// @(#)root/graf:$Name:  $:$Id: TCutG.cxx,v 1.16 2004/06/26 13:38:57 brun Exp $
// Author: Rene Brun   16/05/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.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TCutG                                                                //
//                                                                      //
//  A Graphical cut.                                                    //
//  A TCutG object defines a closed polygon in a x,y plot.              //
//  It can be created via the graphics editor option "CutG"             //
//  or directly by invoking its constructor.                            //
//  To create a TCutG via the graphics editor, use the left button      //
//  to select the points building the contour of the cut. Click on      //
//  the right button to close the TCutG.                                //
//  When it is created via the graphics editor, the TCutG object        //
//  is named "CUTG". It is recommended to immediatly change the name    //
//  by using the context menu item "SetName".                           //                                                                      //
//   When the graphics editor is used, the names of the variables X,Y   //
//   are automatically taken from the current pad title.                //
//  Example:                                                            //
//  Assume a TTree object T and:                                        //
//     Root > T.Draw("abs(fMomemtum)%fEtot")                            //
//  the TCutG members fVarX, fVary will be set to:                      //
//     fVarx = fEtot                                                    //
//     fVary = abs(fMomemtum)                                           //
//                                                                      //
//  A graphical cut can be used in a TTree selection expression:        //
//    Root > T.Draw("fEtot","cutg1")                                    //
//    where "cutg1" is the name of an existing graphical cut.           //
//                                                                      //
//  Note that, as shown in the example above, a graphical cut may be    //
//  used in a selection expression when drawing TTrees expressions      //
//  of 1-d, 2-d or 3-dimensions.                                        //
//  The expressions used in TTree::Draw can reference the variables     //
//  in the fVarX, fVarY of the graphical cut plus other variables.      //
//                                                                      //
//  When the TCutG object is created, it is added to the list of special//
//  objects in the main TROOT object pointed by gROOT. To retrieve a    //
//  pointer to this object from the code or command line, do:           //
//      TCutG *mycutg;                                                  //
//      mycutg = (TCutG*)gROOT->GetListOfSpecials()->FindObject("CUTG") //
//      mycutg->SetName("mycutg");                                      //
//                                                                      //
//  Example of use of a TCutG in TTree::Draw:                           //
//       tree.Draw("x:y","mycutg && z>0 %% sqrt(x)>1")                  //
//                                                                      //
//  A Graphical cut may be drawn via TGraph::Draw.                      //
//  It can be edited like a normal TGraph.                              //
//                                                                      //
//  A Graphical cut may be saved to a file via TCutG::Write.            //                                                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <string.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TCutG.h"
#include "TVirtualPad.h"
#include "TPaveText.h"
#include "TH2.h"

ClassImp(TCutG)

//______________________________________________________________________________
TCutG::TCutG() : TGraph()
{

   fObjectX  = 0;
   fObjectY  = 0;
}

//______________________________________________________________________________
TCutG::TCutG(const TCutG &cutg)
      :TGraph(cutg)
{
   // TCutG copy constructor
   
   fVarX    = cutg.fVarX;
   fVarY    = cutg.fVarY;
   fObjectX = cutg.fObjectX;
   fObjectY = cutg.fObjectY;
}

//______________________________________________________________________________
TCutG::TCutG(const char *name, Int_t n)
      :TGraph(n)
{
   fObjectX  = 0;
   fObjectY  = 0;
   SetName(name);
   delete gROOT->GetListOfSpecials()->FindObject(name);
   gROOT->GetListOfSpecials()->Add(this);

// Take name of cut variables from pad title if title contains ":"
   if (gPad) {
      TPaveText *ptitle = (TPaveText*)gPad->FindObject("title");
      if (!ptitle) return;
      TText *ttitle = ptitle->GetLineWith(":");
      if (!ttitle) ttitle = ptitle->GetLineWith("{");
      if (!ttitle) ttitle = ptitle->GetLine(0);
      if (!ttitle) return;
      const char *title = ttitle->GetTitle();
      Int_t nch = strlen(title);
      char *vars = new char[nch+1];
      strcpy(vars,title);
      char *col = strstr(vars,":");
      if (col) {
         *col = 0;
         col++;
         char *brak = strstr(col," {");
         if (brak) *brak = 0;
         fVarY = vars;
         fVarX = col;
      } else {
         char *brak = strstr(vars," {");
         if (brak) *brak = 0;
         fVarX = vars;
      }        
      delete [] vars;
   }
}

//______________________________________________________________________________
TCutG::TCutG(const char *name, Int_t n, const Float_t *x, const Float_t *y)
      :TGraph(n,x,y)
{
   fObjectX  = 0;
   fObjectY  = 0;
   SetName(name);
   delete gROOT->GetListOfSpecials()->FindObject(name);
   gROOT->GetListOfSpecials()->Add(this);

// Take name of cut variables from pad title if title contains ":"
   if (gPad) {
      TPaveText *ptitle = (TPaveText*)gPad->FindObject("title");
      if (!ptitle) return;
      TText *ttitle = ptitle->GetLineWith(":");
      if (!ttitle) ttitle = ptitle->GetLineWith("{");
      if (!ttitle) ttitle = ptitle->GetLine(0);
      if (!ttitle) return;
      const char *title = ttitle->GetTitle();
      Int_t nch = strlen(title);
      char *vars = new char[nch+1];
      strcpy(vars,title);
      char *col = strstr(vars,":");
      if (col) {
         *col = 0;
         col++;
         char *brak = strstr(col," {");
         if (brak) *brak = 0;
         fVarY = vars;
         fVarX = col;
      } else {
         char *brak = strstr(vars," {");
         if (brak) *brak = 0;
         fVarX = vars;
      }        
      delete [] vars;
   }
}

//______________________________________________________________________________
TCutG::TCutG(const char *name, Int_t n, const Double_t *x, const Double_t *y)
      :TGraph(n,x,y)
{
   fObjectX  = 0;
   fObjectY  = 0;
   SetName(name);
   delete gROOT->GetListOfSpecials()->FindObject(name);
   gROOT->GetListOfSpecials()->Add(this);

// Take name of cut variables from pad title if title contains ":"
   if (gPad) {
      TPaveText *ptitle = (TPaveText*)gPad->FindObject("title");
      if (!ptitle) return;
      TText *ttitle = ptitle->GetLineWith(":");
      if (!ttitle) ttitle = ptitle->GetLineWith("{");
      if (!ttitle) ttitle = ptitle->GetLine(0);
      if (!ttitle) return;
      const char *title = ttitle->GetTitle();
      Int_t nch = strlen(title);
      char *vars = new char[nch+1];
      strcpy(vars,title);
      char *col = strstr(vars,":");
      if (col) {
         *col = 0;
         col++;
         char *brak = strstr(col," {");
         if (brak) *brak = 0;
         fVarY = vars;
         fVarX = col;
      } else {
         char *brak = strstr(vars," {");
         if (brak) *brak = 0;
         fVarX = vars;
      }        
      delete [] vars;
   }
}

//______________________________________________________________________________
TCutG::~TCutG()
{

   delete fObjectX;
   delete fObjectY;
   gROOT->GetListOfSpecials()->Remove(this);
}

//______________________________________________________________________________
Double_t TCutG::Integral(TH2 *h, Option_t *option) const
{
   // Compute the integral of 2-d histogram h for all bins inside the cut
   // if option "width" is specified, the integral is the sum of
   // the bin contents multiplied by the bin width in x and in y.
	
   if (!h) return 0;
   Int_t n = GetN();
   Double_t xmin= 1e200;
   Double_t xmax = -xmin;
   Double_t ymin = xmin;
   Double_t ymax = xmax;
   for (Int_t i=0;i<n;i++) {
      if (fX[i] < xmin) xmin = fX[i];
      if (fX[i] > xmax) xmax = fX[i];
      if (fY[i] < ymin) ymin = fY[i];
      if (fY[i] > ymax) ymax = fY[i];
   }
   TAxis *xaxis = h->GetXaxis();
   TAxis *yaxis = h->GetYaxis();
   Int_t binx1 = xaxis->FindBin(xmin);
   Int_t binx2 = xaxis->FindBin(xmax);
   Int_t biny1 = yaxis->FindBin(ymin);
   Int_t biny2 = yaxis->FindBin(ymax);
   Int_t nbinsx = h->GetNbinsX();
   Stat_t integral = 0;

   // Loop on bins for which the bin center is in the cut 
   TString opt = option;
   opt.ToLower();
   Bool_t width = kFALSE;
   if (opt.Contains("width")) width = kTRUE;
   Int_t bin, binx, biny;
   for (biny=biny1;biny<=biny2;biny++) {
      Double_t y = yaxis->GetBinCenter(biny);
      for (binx=binx1;binx<=binx2;binx++) {
         Double_t x = xaxis->GetBinCenter(binx);
         if (!IsInside(x,y)) continue;
	 bin = binx +(nbinsx+2)*biny;
         if (width) integral += h->GetBinContent(bin)*xaxis->GetBinWidth(binx)*yaxis->GetBinWidth(biny);
         else       integral += h->GetBinContent(bin);
      }
   }
   return integral;
}

//______________________________________________________________________________
Int_t TCutG::IsInside(Double_t x, Double_t y) const
{
//*.         Function which returns 1 if point x,y lies inside the
//*.              polygon defined by the graph points
//*.                                0 otherwise
//*.
//*.     The loop is executed with the end-point coordinates of a
//*.     line segment (X1,Y1)-(X2,Y2) and the Y-coordinate of a
//*.     horizontal line.
//*.     The counter inter is incremented if the line (X1,Y1)-(X2,Y2)
//*.     intersects the horizontal line.
//*.     In this case XINT is set to the X-coordinate of the
//*.     intersection point.
//*.     If inter is an odd number, then the point x,y is within
//*.     the polygon.
//*.
//*.         This routine is based on an original algorithm
//*.         developed by R.Nierhaus.
//*.

   return (Int_t)TMath::IsInside(x,y,fNpoints,fX,fY);
}

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

   char quote = '"';
   out<<"   "<<endl;
   if (gROOT->ClassSaved(TCutG::Class())) {
       out<<"   ";
   } else {
       out<<"   TCutG *";
   }
   out<<"cutg = new TCutG("<<quote<<GetName()<<quote<<","<<fNpoints<<");"<<endl;
   out<<"   cutg->SetVarX("<<quote<<GetVarX()<<quote<<");"<<endl;
   out<<"   cutg->SetVarY("<<quote<<GetVarY()<<quote<<");"<<endl;
   out<<"   cutg->SetTitle("<<quote<<GetTitle()<<quote<<");"<<endl;

   SaveFillAttributes(out,"cutg",0,1001);
   SaveLineAttributes(out,"cutg",1,1,1);
   SaveMarkerAttributes(out,"cutg",1,1,1);

   for (Int_t i=0;i<fNpoints;i++) {
      out<<"   cutg->SetPoint("<<i<<","<<fX[i]<<","<<fY[i]<<");"<<endl;
   }
   out<<"   cutg->Draw("
      <<quote<<option<<quote<<");"<<endl;
}

//______________________________________________________________________________
void TCutG::SetVarX(const char *varx)
{
   fVarX = varx;
   delete fObjectX;
   fObjectX = 0;
}

//______________________________________________________________________________
void TCutG::SetVarY(const char *vary)
{
   fVarY = vary;
   delete fObjectY;
   fObjectY = 0;
}


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

   if (R__b.IsReading()) {
      TCutG::Class()->ReadBuffer(R__b, this);
      gROOT->GetListOfSpecials()->Add(this);
   } else {
      TCutG::Class()->WriteBuffer(R__b, this);
   }
}
