/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!
!   Author(s): Thomas Bretz, 12/2000 <mailto:tbretz@astro.uni-wuerzburg.de>
!   Author(s): Harald Kornmayer 1/2001
!
!   Copyright: MAGIC Software Development, 2000-2008
!
!
\* ======================================================================== */

//////////////////////////////////////////////////////////////////////////////
//
// MGeomPix
//
// This container stores the geometry (position) information of
// a single pixel together with the information about next neighbors.
//
//
// Version 1:
// ----------
//  - first implementation
//
// Version 2:
// ----------
//  - added fA
//
// Version 3:
// ----------
//  - added fAidx
//
// Version 4:
// ----------
//  - added fUserBits
//
//
// FIXME: According to an agreement we have to change the name 'Id' to 'idx'
//
////////////////////////////////////////////////////////////////////////////
#include "MGeomPix.h"

#include <TMath.h>

#include "MLog.h"
#include "MLogManip.h"

#include "MGeomCam.h"

ClassImp(MGeomPix);

using namespace std;

const Float_t MGeomPix::gsTan30 = tan(30/kRad2Deg);
const Float_t MGeomPix::gsTan60 = tan(60/kRad2Deg);

// --------------------------------------------------------------------------
//
// Initializes one pixel
//
MGeomPix::MGeomPix(Float_t x, Float_t y, Float_t r, UInt_t s, UInt_t a)
{
    //  default constructor
    Set(x, y, r, s, a);
    SetNeighbors();
}

// --------------------------------------------------------------------------
//
// Initializes Next Neighbors.
//
// WARNING: This function is public, but it is not meant for user access.
// It should only be used from geometry classes (like MGeomCam)
//
void MGeomPix::SetNeighbors(Short_t i0, Short_t i1, Short_t i2,
                            Short_t i3, Short_t i4, Short_t i5)
{
    fNeighbors[0] = i0;
    fNeighbors[1] = i1;
    fNeighbors[2] = i2;
    fNeighbors[3] = i3;
    fNeighbors[4] = i4;
    fNeighbors[5] = i5;

    int i;
    for (i=0; i<6; i++)
        if (fNeighbors[i]<0)
            break;

    fNumNeighbors = i;

    fNumNeighbors<5 ? SETBIT(fUserBits, kIsInOutermostRing) : CLRBIT(fUserBits, kIsInOutermostRing);
}

// --------------------------------------------------------------------------
//
//  Set the kIsOuterRing flag if this pixel has a outermost pixel
//  as Next Neighbor and don't have the kIsOutermostRing flag itself.
//
void MGeomPix::CheckOuterRing(const MGeomCam &cam)
{
    if (IsInOutermostRing())
        return;

    CLRBIT(fUserBits, kIsInOuterRing);

    for (int i=0; i<fNumNeighbors; i++)
        if (cam[fNeighbors[i]].IsInOutermostRing())
        {
            SETBIT(fUserBits, kIsInOuterRing);
            return;
        }
}

// --------------------------------------------------------------------------
//
// Print the geometry information of one pixel.
//
void MGeomPix::Print(Option_t *opt) const
{ 
    //   information about a pixel
    *fLog << all << "MPixGeom:  x/y=" << fX << "/" << fY << "mm ";
    *fLog << "d= " << fD << "mm  A= " << fA << "mm˛ (";
    for (int i=0; i<fNumNeighbors; i++)
        *fLog << fNeighbors[i] << (i<fNumNeighbors-1?",":"");
    *fLog << ")" << endl;
}

// ------------------------------------------------------------------------
//
// Return distance of center to coordinate origin: hypot(fX,fY)
//
Float_t MGeomPix::GetDist() const
{
    return TMath::Hypot(fX, fY);
}

// ------------------------------------------------------------------------
//
// Return distance of center to center of pix: hypot(fX-pix.fX,fY-pix.fY)
//
Float_t MGeomPix::GetDist(const MGeomPix &pix) const
{
    return TMath::Hypot(fX-pix.fX, fY-pix.fY);
}

// ------------------------------------------------------------------------
//
// Return angle defined by the center and the center of pix:
//  atan2(fX-pix.fX,fY-pix.fY)
//
Float_t MGeomPix::GetAngle(const MGeomPix &pix) const
{
    return TMath::ATan2(fX - pix.GetX(), fY - pix.GetY());
}

// ------------------------------------------------------------------------
//
// compute the distance of a point (px,py) to the Hexagon center in
// MGeomPix coordinates. Return kTRUE if inside.
//
Bool_t MGeomPix::IsInside(Float_t px, Float_t py) const
{
    //
    //  compute the distance of the Point to the center of the Hexagon
    //
    const Double_t dx = px-fX;

    //
    // Now check if point is outside of hexagon; just check x coordinate
    // in three coordinate systems: the default one, in which two sides of
    // the hexagon are paralel to the y axis (see camera displays) and two 
    // more, rotated with respect to that one by +- 60 degrees.
    //
    if (TMath::Abs(dx)*2>fD)
        return kFALSE;

    const Double_t dy = py-fY;

    const static Double_t cos60 = TMath::Cos(60/kRad2Deg);
    const static Double_t sin60 = TMath::Sin(60/kRad2Deg);

    const Double_t dx2 = dx*cos60 + dy*sin60;
    if  (TMath::Abs(dx2)*2>fD)
        return kFALSE;

    const Double_t dx3 = dx*cos60 - dy*sin60;
    if (TMath::Abs(dx3)*2>fD)
        return kFALSE;

    return kTRUE;
}

// ------------------------------------------------------------------------
//
// Return the direction of the pixel pix w.r.t. this pixel.
// Remark: This function assumes a simple geometry.
//
Int_t MGeomPix::GetDirection(const MGeomPix &pix) const
{
    const Double_t x1 = GetX();
    const Double_t y1 = GetY();

    const Double_t x2 = pix.GetX();
    const Double_t y2 = pix.GetY();

    if (x1>=x2 && y1>y2) return kRightTop;
    if (x1>=x2 && y1<y2) return kRightBottom;
    if (x1<=x2 && y1>y2) return kLeftTop;
    if (x1<=x2 && y1<y2) return kLeftBottom;
    if (x1>x2)           return kRight;
    if (x1<x2)           return kLeft;

    return -1;
}
