    // @(#)root/g3d:$Name:  $:$Id: TMarker3DBox.cxx,v 1.7 2002/02/02 11:56:14 brun Exp $
    // Author: "Valery fine"   31/10/97

    /*************************************************************************
     * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    #include "Riostream.h"
    #include "TROOT.h"
    #include "TView.h"
    #include "TMarker3DBox.h"
    #include "TVirtualPad.h"
    #include "TVirtualGL.h"
    #include "TPadView3D.h"
    #include "TH1.h"
    #include "TH3.h"
    #include "TFile.h"

    ClassImp(TMarker3DBox)

    //______________________________________________________________________________
    // Marker3DBox is a special 3-D marker designed for event display.
    // It has the following parameters:
    //    fX;               X coordinate of the center of the box
    //    fY;               Y coordinate of the center of the box
    //    fZ;               Z coordinate of the center of the box
    //    fDx;              half length in X
    //    fDy;              half length in Y
    //    fDz;              half length in Z
    //    fTheta;           Angle of box z axis with respect to main Z axis
    //    fPhi;             Angle of box x axis with respect to main Xaxis
    //    fRefObject;       A reference to an object
    //

    //______________________________________________________________________________
     TMarker3DBox::TMarker3DBox()
    {
    //*-*-*-*-*-*-*-*-*-*-*-*-*Marker3DBox  default constructor*-*-*-*-*-*-*-*-*-*
    //*-*                      ================================

       fRefObject = 0;
       //just in case of a stupid call to this constructor
       fDx = 1;
       fDy = 1;
       fDz = 1;

       fX  = 0;
       fY  = 0;
       fZ  = 0;

       fTheta = 0;
       fPhi   = 0;
    }

    //______________________________________________________________________________
     TMarker3DBox::TMarker3DBox( Float_t x, Float_t y, Float_t z,
                                Float_t dx, Float_t dy, Float_t dz,
                                Float_t theta, Float_t phi)
                  :TAttLine(1,1,1), TAttFill(1,0)
    {
    //*-*-*-*-*-*-*-*-*-*-*-*-*Marker3DBox normal constructor*-*-*-*-*-*-*-*-*-*-*-*-*
    //*-*                      =============================

        fDx = dx;
        fDy = dy;
        fDz = dz;

        fX  = x;
        fY  = y;
        fZ  = z;

        fTheta = theta;
        fPhi   = phi;
        fRefObject = 0;
    }

    //______________________________________________________________________________
     TMarker3DBox::~TMarker3DBox()
    {
    //*-*-*-*-*-*-*-*-*-*-*-*-*Marker3DBox shape default destructor*-*-*-*-*-*-*-*-*-*-*-*-*
    //*-*                      =============================

    }

    //______________________________________________________________________________
     Int_t TMarker3DBox::DistancetoPrimitive(Int_t px, Int_t py)
    {
    //*-*-*-*-*-*-*-*Compute distance from point px,py to a Marker3DBox*-*-*-*-*
    //*-*            ==================================================
    //*-*
    //*-*  Compute the closest distance of approach from point px,py to each corner
    //*-*  point of the Marker3DBox.
    //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

       const Int_t numPoints = 8;
       Int_t dist = 9999;
       Float_t points[3*numPoints];

       TView *view = gPad->GetView();
       if (!view) return dist;
       const Int_t seg1[12] = {0,1,2,3,4,5,6,7,0,1,2,3};
       const Int_t seg2[12] = {1,2,3,0,5,6,7,4,4,5,6,7};

       SetPoints(points);

       Int_t i, i1, i2, dsegment;
       Double_t x1,y1,x2,y2;
       Float_t xndc[3];
       for (i = 0; i < 12; i++) {
          i1 = 3*seg1[i];
          view->WCtoNDC(&points[i1], xndc);
          x1 = xndc[0];
          y1 = xndc[1];

          i2 = 3*seg2[i];
          view->WCtoNDC(&points[i2], xndc);
          x2 = xndc[0];
          y2 = xndc[1];
          dsegment = DistancetoLine(px,py,x1,y1,x2,y2);
          if (dsegment < dist) dist = dsegment;
       }
       if (dist < 5) {
          gPad->SetCursor(kCross);
          if (fRefObject) {gPad->SetSelected(fRefObject); return 0;}
       }
       return dist;
    }

    //______________________________________________________________________________
     void TMarker3DBox::ExecuteEvent(Int_t event, Int_t px, Int_t py)
    {
    //*-*-*-*-*-*-*-*-*-*Execute action corresponding to one event*-*-*-*-*-*-*-*-*-*
    //*-*                =========================================
    //*-*
    //*-*  This member function must be implemented to realize the action
    //*-*  corresponding to the mouse click on the object in the window
    //*-*
    //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

            if (gPad->GetView())
                    gPad->GetView()->ExecuteRotateView(event, px, py);

    }

    //______________________________________________________________________________
     void TMarker3DBox::Paint(Option_t *option)
    {
    //*-*-*-*-*-*-*-*Paint this 3-D box marker with its current attributes*-*-*-*
    //*-*            =====================================================

       const Int_t numpoints = 8;

    //*-* Allocate memory for points *-*

       Float_t *points = new Float_t[3*numpoints];
       if (!points) return;

       SetPoints(points);

       TPadView3D *view3D = (TPadView3D*)gPad->GetView3D();
       Bool_t rangeView = option && *option && strcmp(option,"range")==0 ? kTRUE : kFALSE;
       if (view3D && !rangeView) {
         gVirtualGL->SetLineAttr(GetLineColor(),GetLineWidth());
         PaintGLPoints(points);
       }

       Int_t c = ((GetLineColor() % 8) - 1) * 4;  // Basic colors: 0, 1, ... 7
       if (c < 0) c = 0;

    //*-* Allocate memory for segments *-*

        X3DBuffer *buff = new X3DBuffer;
        if (buff) {
            buff->numPoints = 8;
            buff->numSegs   = 12;
            buff->numPolys  = 6;
        }

    //*-* Allocate memory for points *-*

        buff->points = points;
        buff->segs = new Int_t[buff->numSegs*3];
        if (buff->segs) {
            buff->segs[ 0] = c;    buff->segs[ 1] = 0;    buff->segs[ 2] = 1;
            buff->segs[ 3] = c+1;  buff->segs[ 4] = 1;    buff->segs[ 5] = 2;
            buff->segs[ 6] = c+1;  buff->segs[ 7] = 2;    buff->segs[ 8] = 3;
            buff->segs[ 9] = c;    buff->segs[10] = 3;    buff->segs[11] = 0;
            buff->segs[12] = c+2;  buff->segs[13] = 4;    buff->segs[14] = 5;
            buff->segs[15] = c+2;  buff->segs[16] = 5;    buff->segs[17] = 6;
            buff->segs[18] = c+3;  buff->segs[19] = 6;    buff->segs[20] = 7;
            buff->segs[21] = c+3;  buff->segs[22] = 7;    buff->segs[23] = 4;
            buff->segs[24] = c;    buff->segs[25] = 0;    buff->segs[26] = 4;
            buff->segs[27] = c+2;  buff->segs[28] = 1;    buff->segs[29] = 5;
            buff->segs[30] = c+1;  buff->segs[31] = 2;    buff->segs[32] = 6;
            buff->segs[33] = c+3;  buff->segs[34] = 3;    buff->segs[35] = 7;
        }

    //*-* Allocate memory for polygons *-*

        buff->polys = new Int_t[buff->numPolys*6];
        if (buff->polys) {
            buff->polys[ 0] = c;   buff->polys[ 1] = 4;  buff->polys[ 2] = 0;
            buff->polys[ 3] = 9;   buff->polys[ 4] = 4;  buff->polys[ 5] = 8;
            buff->polys[ 6] = c+1; buff->polys[ 7] = 4;  buff->polys[ 8] = 1;
            buff->polys[ 9] = 10;  buff->polys[10] = 5;  buff->polys[11] = 9;
            buff->polys[12] = c;   buff->polys[13] = 4;  buff->polys[14] = 2;
            buff->polys[15] = 11;  buff->polys[16] = 6;  buff->polys[17] = 10;
            buff->polys[18] = c+1; buff->polys[19] = 4;  buff->polys[20] = 3;
            buff->polys[21] = 8;   buff->polys[22] = 7;  buff->polys[23] = 11;
            buff->polys[24] = c+2; buff->polys[25] = 4;  buff->polys[26] = 0;
            buff->polys[27] = 3;   buff->polys[28] = 2;  buff->polys[29] = 1;
            buff->polys[30] = c+3; buff->polys[31] = 4;  buff->polys[32] = 4;
            buff->polys[33] = 5;   buff->polys[34] = 6;  buff->polys[35] = 7;
        }

        //*-* Paint in the pad
        PaintShape(buff,rangeView);

        if (strstr(option, "x3d")) {
            if(buff && buff->points && buff->segs)
                FillX3DBuffer(buff);
            else {
                gSize3D.numPoints -= buff->numPoints;
                gSize3D.numSegs   -= buff->numSegs;
                gSize3D.numPolys  -= buff->numPolys;
            }
        }

        delete [] points;
        if (buff->segs)     delete [] buff->segs;
        if (buff->polys)    delete [] buff->polys;
        if (buff)           delete    buff;

    }

    //______________________________________________________________________________
     void TMarker3DBox::PaintGLPoints(Float_t *vertex)
    {
    //*-*-*-*-*-*-*-*-*-*-*Direct copy of TBRIK::PaintGLPoints*-*-*-*-*-*-*-*-*-*
    //*-*                  ===================================
        gVirtualGL->PaintBrik(vertex);
    }

    //______________________________________________________________________________
     void TMarker3DBox::PaintH3(TH1 *h, Option_t *option)
    {
    //*-*-*-*-*-*-*-*Paint 3-d histogram h with marker3dboxes*-*-*-*
    //*-*            ========================================

       Int_t bin,ix,iy,iz;
       Double_t xmin,xmax,ymin,ymax,zmin,zmax,wmin,wmax,w;
       TAxis *xaxis = h->GetXaxis();
       TAxis *yaxis = h->GetYaxis();
       TAxis *zaxis = h->GetZaxis();

       //compute min and max of all cells
       wmin = wmax = 0;
       for (iz=zaxis->GetFirst();iz<=zaxis->GetLast();iz++) {
          for (iy=yaxis->GetFirst();iy<=yaxis->GetLast();iy++) {
             for (ix=xaxis->GetFirst();ix<=xaxis->GetLast();ix++) {
                bin = h->GetBin(ix,iy,iz);
                w = h->GetBinContent(bin);
                if (w > wmax) wmax = w;
                if (w < wmin) wmin = w;
             }
          }
       }

       //Create or modify 3-d view object
       TView *view = gPad->GetView();
       if (!view) {
          gPad->Range(-1,-1,1,1);
          view = new TView(1);
       }
       view->SetRange(xaxis->GetBinLowEdge(xaxis->GetFirst()),
                      yaxis->GetBinLowEdge(yaxis->GetFirst()),
                      zaxis->GetBinLowEdge(zaxis->GetFirst()),
                      xaxis->GetBinUpEdge(xaxis->GetLast()),
                      yaxis->GetBinUpEdge(yaxis->GetLast()),
                      zaxis->GetBinUpEdge(zaxis->GetLast()));

       //Draw TMarker3DBox with size proportional to cell content
       TMarker3DBox m3;
       m3.SetRefObject(h);
       m3.SetDirection(0,0);
       m3.SetLineColor(h->GetMarkerColor());
       Double_t scale;
       for (ix=xaxis->GetFirst();ix<=xaxis->GetLast();ix++) {
          xmin = h->GetXaxis()->GetBinLowEdge(ix);
          xmax = xmin + h->GetXaxis()->GetBinWidth(ix);
          for (iy=yaxis->GetFirst();iy<=yaxis->GetLast();iy++) {
             ymin = h->GetYaxis()->GetBinLowEdge(iy);
             ymax = ymin + h->GetYaxis()->GetBinWidth(iy);
             for (iz=zaxis->GetFirst();iz<=zaxis->GetLast();iz++) {
                zmin = h->GetZaxis()->GetBinLowEdge(iz);
                zmax = zmin + h->GetZaxis()->GetBinWidth(iz);
                bin = h->GetBin(ix,iy,iz);
                w = h->GetBinContent(bin);
                if (w == 0) continue;
                scale = (w-wmin)/(wmax-wmin);
                m3.SetPosition(0.5*(xmin+xmax),0.5*(ymin+ymax),0.5*(zmin+zmax));
                m3.SetSize(scale*(xmax-xmin),scale*(ymax-ymin),scale*(zmax-zmin));
                m3.Paint(option);
             }
          }
       }
    }

    //______________________________________________________________________________
     void TMarker3DBox::PaintShape(X3DBuffer *buff, Bool_t rangeView)
    {
    //*-*-*-*-*Paint 3-D marker in current pad with its current attributes*-*-*-*-*
    //*-*      ==========================================================

        //*-* Paint in the pad

        Double_t points[6], x0, y0, z0, x1, y1, z1;
        const Int_t kExpandView = 2;
        int i0;

        x0 = y0 = z0 = x1 = y1 = z1 = buff->points[0];

        TAttLine::Modify();  //Change line attributes only if necessary
        TAttFill::Modify();  //Change fill area attributes only if necessary

        for (Int_t i = 0; i < buff->numSegs; i++) {
            i0 = 3*buff->segs[3*i+1];
            points[0] = buff->points[i0++];
            points[1] = buff->points[i0++];
            points[2] = buff->points[i0];

            i0 = 3*buff->segs[3*i+2];
            points[3] = buff->points[i0++];
            points[4] = buff->points[i0++];
            points[5] = buff->points[i0];

            x0 = points[0] < x0 ? points[0] : x0;
            y0 = points[1] < y0 ? points[1] : y0;
            z0 = points[2] < z0 ? points[2] : z0;
            x1 = points[0] > x1 ? points[0] : x1;
            y1 = points[1] > y1 ? points[1] : y1;
            z1 = points[2] > z1 ? points[2] : z1;

           if (!rangeView) gPad->PaintLine3D(&points[0], &points[3]);
        }
        if (rangeView){
          TView *view = gPad->GetView();
          if (view->GetAutoRange()) view->SetRange(x0,y0,z0,x1,y1,z1,kExpandView);
        }

    }

    //______________________________________________________________________________
     void TMarker3DBox::SavePrimitive(ofstream &out, Option_t *)
    {
        // Save primitive as a C++ statement(s) on output stream out

       out<<"   "<<endl;
       if (gROOT->ClassSaved(TMarker3DBox::Class())) {
           out<<"   ";
       } else {
           out<<"   TMarker3DBox *";
       }
       out<<"marker3DBox = new TMarker3DBox("<<fX<<","
                                             <<fY<<","
                                             <<fZ<<","
                                             <<fDx<<","
                                             <<fDy<<","
                                             <<fDz<<","
                                             <<fTheta<<","
                                             <<fPhi<<");"<<endl;

       SaveLineAttributes(out,"marker3DBox",1,1,1);
       SaveFillAttributes(out,"marker3DBox",1,0);

       out<<"   marker3DBox->Draw();"<<endl;
    }

    //______________________________________________________________________________
     void TMarker3DBox::SetDirection(Float_t theta, Float_t phi)
    {
      fTheta = theta;
      fPhi   = phi;
    }

    //______________________________________________________________________________
     void TMarker3DBox::SetSize(Float_t dx, Float_t dy, Float_t dz)
    {
      fDx = dx;
      fDy = dy;
      fDz = dz;
    }

    //______________________________________________________________________________
     void TMarker3DBox::SetPosition(Float_t x, Float_t y, Float_t z)
    {
      fX  = x;
      fY  = y;
      fZ  = z;
    }

    //______________________________________________________________________________
     void TMarker3DBox::SetPoints(Float_t *buff)
    {
    //*-*-*-*-*-*-*-*-*-*-*Direct copy of TBRIK::SetPoints *-*-*-*-*-*-*-*-*-*-*
    //*-*                  ===============================

        if (buff) {
            buff[ 0] = -fDx;    buff[ 1] = -fDy;    buff[ 2] = -fDz;
            buff[ 3] =  fDx;    buff[ 4] = -fDy;    buff[ 5] = -fDz;
            buff[ 6] =  fDx;    buff[ 7] =  fDy;    buff[ 8] = -fDz;
            buff[ 9] = -fDx;    buff[10] =  fDy;    buff[11] = -fDz;
            buff[12] = -fDx;    buff[13] = -fDy;    buff[14] =  fDz;
            buff[15] =  fDx;    buff[16] = -fDy;    buff[17] =  fDz;
            buff[18] =  fDx;    buff[19] =  fDy;    buff[20] =  fDz;
            buff[21] = -fDx;    buff[22] =  fDy;    buff[23] =  fDz;
        }

       Double_t x, y, z;
       const Double_t kPI = TMath::Pi();
       Double_t theta  = fTheta*kPI/180;
       Double_t phi    = fPhi*kPI/180;
       Double_t sinth = TMath::Sin(theta);
       Double_t costh = TMath::Cos(theta);
       Double_t sinfi = TMath::Sin(phi);
       Double_t cosfi = TMath::Cos(phi);

       //
       // Matrix to convert from fruit frame to master frame
       //

       Double_t M[9];
       M[0] =  costh * cosfi;       M[1] = -sinfi;          M[2] = sinth*cosfi;
       M[3] =  costh * sinfi;       M[4] =  cosfi;          M[5] = sinth*sinfi;
       M[6] = -sinth;               M[7] =  0;              M[8] = costh;
       for (Int_t i = 0; i < 8; i++) {
          x = buff[3*i];
          y = buff[3*i+1];
          z = buff[3*i+2];

          buff[3*i]   = fX + M[0] * x + M[1] * y + M[2] * z;
          buff[3*i+1] = fY + M[3] * x + M[4] * y + M[5] * z;
          buff[3*i+2] = fZ + M[6] * x + M[7] * y + M[8] * z;
       }

    }

    //______________________________________________________________________________
     void TMarker3DBox::Sizeof3D() const
    {
    //*-*-*-*-*-*-*Return total X3D size of this marker*-*-*-*-*-*-*-*
    //*-*          ====================================

        gSize3D.numPoints += 8;
        gSize3D.numSegs   += 12;
        gSize3D.numPolys  += 6;
    }

    //______________________________________________________________________________
     void TMarker3DBox::SizeofH3(TH1 *h)
    {
    //*-*-*-*-*-*-*Return total X3D size of 3-D histogram h*-*-*-*-*-*-*-*
    //*-*          ========================================

       // take into account the 4 polylines of the OutlinetoCube
       gSize3D.numSegs   += 4*3;
       gSize3D.numPoints += 4*4;

       Int_t ix,iy,iz;
       Int_t nbinsx = h->GetXaxis()->GetNbins();
       Int_t nbinsy = h->GetYaxis()->GetNbins();
       Int_t nbinsz = h->GetZaxis()->GetNbins();
       Int_t ncells = 0;
       for (ix=1;ix<=nbinsx;ix++) {
          for (iy=1;iy<=nbinsy;iy++) {
             for (iz=1;iz<=nbinsz;iz++) {
                if (((TH3F*)h)->GetBinContent(((TH3F*)h)->GetBin(ix,iy,iz)) != 0)
                    ncells++;
             }
          }
       }
       gSize3D.numPoints += 8*ncells;
       gSize3D.numSegs   += 12*ncells;
       gSize3D.numPolys  += 6*ncells;
    }

    //______________________________________________________________________________
     void TMarker3DBox::Streamer(TBuffer &R__b)
    {
       // Stream an object of class TMarker3DBox.

       if (R__b.IsReading()) {
          UInt_t R__s, R__c;
          Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
          if (R__v > 1) {
             TMarker3DBox::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
             return;
          }
          //====process old versions before automatic schema evolution
          TObject::Streamer(R__b);
          TAttLine::Streamer(R__b);
          TAttFill::Streamer(R__b);
          TFile *file = (TFile*)R__b.GetParent();
          if (file) {
             if (file->GetVersion() > 22300) TAtt3D::Streamer(R__b);
          } else {
             TAtt3D::Streamer(R__b);
           }
          R__b >> fX;
          R__b >> fY;
          R__b >> fZ;
          R__b >> fDx;
          R__b >> fDy;
          R__b >> fDz;
          R__b >> fTheta;
          R__b >> fPhi;
          R__b >> fRefObject;
          R__b.CheckByteCount(R__s, R__c, TMarker3DBox::IsA());
          //====end of old versions

       } else {
          TMarker3DBox::Class()->WriteBuffer(R__b,this);
       }
    }