KaliVeda
Toolkit for HIC analysis
KVIDLine.cpp
1 /***************************************************************************
2 $Id: KVIDLine.cpp,v 1.22 2009/05/05 15:57:52 franklan Exp $
3  KVIDLine.cpp - description
4  -------------------
5  begin : Nov 10 2004
6  copyright : (C) 2004 by J.D. Frankland
7  email : frankland@ganil.fr
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "KVIDLine.h"
20 #include "Riostream.h"
21 #include "TF1.h"
22 #include "TProfile.h"
23 #include "TH2.h"
24 #include "TCutG.h"
25 #include "TPad.h"
26 #include "TList.h"
27 #include "TROOT.h"
28 #include "TVirtualX.h"
29 
30 using namespace std;
31 
33 
34 
35 
39 {
40  //Default ctor
41 }
42 
43 
44 
47 
48 KVIDLine::~KVIDLine()
49 {
50  //Default dtor
51 }
52 
53 
54 
57 
59  : KVIDentifier(obj)
60 {
61  // copy constructor
62 }
63 
64 
65 
68 
70 {
71  //initialize KVIDLine using TGraph copy ctor
72 }
73 
74 
75 
76 
87 
89 {
90  // create an IDLine from different objects (Inherited from TProfile, TGraph, TF1)
91  // - "xdeb" and "xfin" stand for the delimitation of the line - dafault values are -1
92  // in this case range is the one of the considered object
93  // if the choosen range is greater than the object one, one point for each limit is added with the value
94  // corresponding to the first and/or last of the object
95  // - "np" is in the TF1 case the number point (default value 20), in the TProfile case is the minimum threshold
96  // for the bin entries (default value is one); for the TGraph case it has no effect;
97  // In the TProfile and TGraph cases the number of points are determined by the object considering the interval
98  // - "save" allow to save the TF1 or TProfile object which can be recall with the GetListofFunction() method
99  Double_t xdeb_bis = xdeb, xfin_bis = xfin, np_bis = np;
100  if (obj) {
101  KVIDLine* line = new KVIDLine();
102  if (obj->InheritsFrom("TF1")) {
103  Double_t xmin, xmax;
104  dynamic_cast<TF1*>(obj)->GetRange(xmin, xmax);
105  if (xdeb_bis == -1) xdeb_bis = xmin;
106  if (xfin_bis == -1) xfin_bis = xmax;
107  if (np_bis == 1) np_bis = Double_t(dynamic_cast<TF1*>(obj)->GetNpx());
108  Double_t inter = (xfin_bis - xdeb_bis) / (np_bis);
109  Int_t pp = 0;
110  for (Double_t xx = xdeb_bis; xx <= xfin_bis; xx += inter) {
111  line->SetPoint(pp++, xx, dynamic_cast<TF1*>(obj)->Eval(xx));
112  }
113  if (save) line->Fit(dynamic_cast<TF1*>(obj), "0+", "", xdeb_bis, xfin_bis);
114  }
115  else if (obj->InheritsFrom("TGraph")) { // np has no effect in this case
116  Int_t nx = dynamic_cast<TGraph*>(obj)->GetN(), np2 = 0;
117  Double_t* xtab = dynamic_cast<TGraph*>(obj)->GetX();
118  Double_t* ytab = dynamic_cast<TGraph*>(obj)->GetY();
119  if (xdeb_bis == -1) xdeb_bis = xtab[0];
120  if (xfin_bis == -1) xfin_bis = xtab[nx - 1];
121  if (xdeb_bis < xtab[0]) line->SetPoint(np2++, xdeb_bis, ytab[0]);
122  for (Int_t pp = 0; pp < nx; pp += 1) if (xdeb_bis <= xtab[pp] && xtab[pp] <= xfin_bis) line->SetPoint(np2++, xtab[pp], ytab[pp]);
123  if (xfin_bis > xtab[nx - 1]) line->SetPoint(np2, xfin_bis, ytab[nx - 1]);
124  }
125  else if (obj->InheritsFrom("TProfile")) {
126  TProfile* pf = dynamic_cast<TProfile*>(obj);
127  Int_t nx = pf->GetNbinsX(), np2 = 0;
128  Int_t pp = 1;
129  while (pf->GetBinEntries(pp) < np && pp < nx) pp += 1;
130  Int_t xmin = pp;
131  pp = nx;
132  while (pf->GetBinEntries(pp) < np && pp > xmin) pp -= 1;
133  Int_t xmax = pp;
134  if (xdeb_bis == -1) xdeb_bis = pf->GetBinCenter(xmin);
135  if (xfin_bis == -1) xfin_bis = pf->GetBinCenter(xmax);
136  if (xdeb_bis < pf->GetBinCenter(xmin)) line->SetPoint(np2++, xdeb_bis, pf->GetBinContent(xmin));
137  for (pp = xmin; pp <= xmax; pp += 1) {
138  Double_t xx = pf->GetBinCenter(pp);
139  if (xdeb_bis <= xx && xx <= xfin_bis && pf->GetBinEntries(pp) >= np) line->SetPoint(np2++, xx, pf->GetBinContent(pp));
140  }
141  if (xfin_bis > pf->GetBinCenter(xmax)) line->SetPoint(np2, xfin_bis, pf->GetBinContent(xmax));
142  if (save) line->GetListOfFunctions()->Add(pf);
143  }
144  else cout << "le type ne correspond pas " << endl;
145  line->SetName(Form("from_%s", obj->GetName()));
146  return line;
147  }
148  else return NULL;
149 }
150 
151 
152 
159 
160 Bool_t KVIDLine::WhereAmI(const KVIDLine& other, const TString& tested_direction) const
161 {
162  // Test the relative position of this line compared to another
163  //
164  // \param[in] tested_direction is one of `"above"`, `"below"`, `"left"`, `"right"`
165  //
166  // \returns true if the tested relative displacement is true for all points of this line
167 
168  int npoints = GetN();
169  double X,Y;
170  for(int i=0; i<npoints; ++i)
171  {
172  GetPoint(i,X,Y);
173  if(other.IsBetweenEndPoints(X,Y,"x"))
174  if(!other.WhereAmI(X,Y,tested_direction))
175  return false;
176  }
177  return true;
178 }
179 
180 
181 
182 /*
183 KVIDLine *KVIDLine::MakeIDLine(TH2 *hh,TCutG *cut,Double_t xdeb,Double_t xfin,Double_t np,Bool_t save)
184 {
185  if (hh){
186  TProfile *gg = NULL;
187  if (cut){
188  if (cut->InheritsFrom("TCutG")){
189  Double_t xmin=1e6,xmax=-1e6;
190  Double_t ymin=1e6,ymax=-1e6;
191  for (Int_t pp=0;pp<cut->GetN();pp+=1){
192  Double_t xx,yy; cut->GetPoint(pp,xx,yy);
193  if (xx<xmin) xmin=xx; if (xx>xmax) xmax=xx;
194  if (yy<ymin) ymin=yy; if (yy>ymax) ymax=yy;
195  }
196 
197  Int_t bxmin = hh->GetXaxis()->FindBin(xmin); xmin = hh->GetXaxis()->GetBinLowEdge(bxmin);
198  Int_t bxmax = hh->GetXaxis()->FindBin(xmax); xmax = hh->GetXaxis()->GetBinUpEdge(bxmax);
199  Int_t bymin = hh->GetYaxis()->FindBin(ymin); ymin = hh->GetYaxis()->GetBinLowEdge(bymin);
200  Int_t bymax = hh->GetYaxis()->FindBin(ymax); ymax = hh->GetYaxis()->GetBinUpEdge(bymax);
201 
202  Int_t dx = bxmax - bxmin +1;
203  gg = new TProfile(Form("%s_%s",hh->GetName(),cut->GetName()),"prof",dx,xmin,xmax,ymin,ymax);
204  for (Int_t xx=bxmin;xx<=bxmax;xx+=1)
205  for (Int_t yy=bymin;yy<=bymax;yy+=1)
206  if ( cut->IsInside(hh->GetXaxis()->GetBinCenter(xx),hh->GetYaxis()->GetBinCenter(yy)) )
207  gg->Fill(hh->GetXaxis()->GetBinCenter(xx),hh->GetYaxis()->GetBinCenter(yy),hh->GetBinContent(xx,yy));
208  }
209  }
210  else { gg = hh->ProfileX(); }
211  return KVIDLine::MakeIDLine(gg,xdeb,xfin,np,save);
212  }
213  else return NULL;
214 }
215 */
216 
217 
218 
222 
224 {
225  // Method used to draw a new identifier in the active pad
226  // Override in child classes so that gPad->WaitPrimitive has correct arguments
227 
228  if (!gPad) return;
229  TGraph* gr = (TGraph*) gPad->WaitPrimitive("Graph", "PolyLine");
230  //copy coordinates of user's line
231  CopyGraph(gr);
232  //remove TGraph and draw the KVIDLine in its place
233  gPad->GetListOfPrimitives()->Remove(gr);
234  delete gr;
235  Draw("PL");
236 }
237 
238 
239 
254 
256 {
257  // We override the TGraph::ExecuteEvent which contains a TCutG-specific part
258  // making sure that the first and last point are the same. This is a copy
259  // of that method with the "if(InheritsFrom("TCutG"))" part commented out.
260  //
261  // Execute action corresponding to one event.
262  //
263  // This member function is called when a graph is clicked with the locator
264  //
265  // If Left button clicked on one of the line end points, this point
266  // follows the cursor until button is released.
267  //
268  // if Middle button clicked, the line is moved parallel to itself
269  // until the button is released.
270 
271  Int_t i, d;
272  Double_t xmin, xmax, ymin, ymax, dx, dy, dxr, dyr;
273  const Int_t kMaxDiff = 10;
274  static Bool_t middle, badcase;
275  static Int_t ipoint, pxp, pyp;
276  static Int_t px1, px2, py1, py2;
277  static Int_t pxold, pyold, px1old, py1old, px2old, py2old;
278  static Int_t dpx, dpy;
279  static Int_t* x = 0, *y = 0;
280 
281  if (!IsEditable()) {
282  gPad->SetCursor(kHand);
283  return;
284  }
285  if (!gPad->IsEditable()) return;
286 
287  switch (event) {
288 
289  case kButton1Down:
290  badcase = kFALSE;
291  gVirtualX->SetLineColor(-1);
292  TAttLine::Modify(); //Change line attributes only if necessary
293  px1 = gPad->XtoAbsPixel(gPad->GetX1());
294  py1 = gPad->YtoAbsPixel(gPad->GetY1());
295  px2 = gPad->XtoAbsPixel(gPad->GetX2());
296  py2 = gPad->YtoAbsPixel(gPad->GetY2());
297  ipoint = -1;
298 
299 
300  if (x || y) break;
301  x = new Int_t[fNpoints + 1];
302  y = new Int_t[fNpoints + 1];
303  for (i = 0; i < fNpoints; i++) {
304  pxp = gPad->XtoAbsPixel(gPad->XtoPad(fX[i]));
305  pyp = gPad->YtoAbsPixel(gPad->YtoPad(fY[i]));
306  if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
307  pyp < -kMaxPixel || pyp >= kMaxPixel) {
308  badcase = kTRUE;
309  continue;
310  }
311  gVirtualX->DrawLine(pxp - 4, pyp - 4, pxp + 4, pyp - 4);
312  gVirtualX->DrawLine(pxp + 4, pyp - 4, pxp + 4, pyp + 4);
313  gVirtualX->DrawLine(pxp + 4, pyp + 4, pxp - 4, pyp + 4);
314  gVirtualX->DrawLine(pxp - 4, pyp + 4, pxp - 4, pyp - 4);
315  x[i] = pxp;
316  y[i] = pyp;
317  d = TMath::Abs(pxp - px) + TMath::Abs(pyp - py);
318  if (d < kMaxDiff) ipoint = i;
319  }
320  dpx = 0;
321  dpy = 0;
322  pxold = px;
323  pyold = py;
324  if (ipoint < 0) return;
325  if (ipoint == 0) {
326  px1old = 0;
327  py1old = 0;
328  px2old = gPad->XtoAbsPixel(fX[1]);
329  py2old = gPad->YtoAbsPixel(fY[1]);
330  }
331  else if (ipoint == fNpoints - 1) {
332  px1old = gPad->XtoAbsPixel(gPad->XtoPad(fX[fNpoints - 2]));
333  py1old = gPad->YtoAbsPixel(gPad->YtoPad(fY[fNpoints - 2]));
334  px2old = 0;
335  py2old = 0;
336  }
337  else {
338  px1old = gPad->XtoAbsPixel(gPad->XtoPad(fX[ipoint - 1]));
339  py1old = gPad->YtoAbsPixel(gPad->YtoPad(fY[ipoint - 1]));
340  px2old = gPad->XtoAbsPixel(gPad->XtoPad(fX[ipoint + 1]));
341  py2old = gPad->YtoAbsPixel(gPad->YtoPad(fY[ipoint + 1]));
342  }
343  pxold = gPad->XtoAbsPixel(gPad->XtoPad(fX[ipoint]));
344  pyold = gPad->YtoAbsPixel(gPad->YtoPad(fY[ipoint]));
345 
346  break;
347 
348 
349  case kMouseMotion:
350 
351  middle = kTRUE;
352  for (i = 0; i < fNpoints; i++) {
353  pxp = gPad->XtoAbsPixel(gPad->XtoPad(fX[i]));
354  pyp = gPad->YtoAbsPixel(gPad->YtoPad(fY[i]));
355  d = TMath::Abs(pxp - px) + TMath::Abs(pyp - py);
356  if (d < kMaxDiff) middle = kFALSE;
357  }
358 
359 
360  // check if point is close to an axis
361  if (middle) gPad->SetCursor(kMove);
362  else gPad->SetCursor(kHand);
363  break;
364 
365  case kButton1Motion:
366  if (middle) {
367  for (i = 0; i < fNpoints - 1; i++) {
368  gVirtualX->DrawLine(x[i] + dpx, y[i] + dpy, x[i + 1] + dpx, y[i + 1] + dpy);
369  pxp = x[i] + dpx;
370  pyp = y[i] + dpy;
371  if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
372  pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
373  gVirtualX->DrawLine(pxp - 4, pyp - 4, pxp + 4, pyp - 4);
374  gVirtualX->DrawLine(pxp + 4, pyp - 4, pxp + 4, pyp + 4);
375  gVirtualX->DrawLine(pxp + 4, pyp + 4, pxp - 4, pyp + 4);
376  gVirtualX->DrawLine(pxp - 4, pyp + 4, pxp - 4, pyp - 4);
377  }
378  pxp = x[fNpoints - 1] + dpx;
379  pyp = y[fNpoints - 1] + dpy;
380  gVirtualX->DrawLine(pxp - 4, pyp - 4, pxp + 4, pyp - 4);
381  gVirtualX->DrawLine(pxp + 4, pyp - 4, pxp + 4, pyp + 4);
382  gVirtualX->DrawLine(pxp + 4, pyp + 4, pxp - 4, pyp + 4);
383  gVirtualX->DrawLine(pxp - 4, pyp + 4, pxp - 4, pyp - 4);
384  dpx += px - pxold;
385  dpy += py - pyold;
386  pxold = px;
387  pyold = py;
388  for (i = 0; i < fNpoints - 1; i++) {
389  gVirtualX->DrawLine(x[i] + dpx, y[i] + dpy, x[i + 1] + dpx, y[i + 1] + dpy);
390  pxp = x[i] + dpx;
391  pyp = y[i] + dpy;
392  if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
393  pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
394  gVirtualX->DrawLine(pxp - 4, pyp - 4, pxp + 4, pyp - 4);
395  gVirtualX->DrawLine(pxp + 4, pyp - 4, pxp + 4, pyp + 4);
396  gVirtualX->DrawLine(pxp + 4, pyp + 4, pxp - 4, pyp + 4);
397  gVirtualX->DrawLine(pxp - 4, pyp + 4, pxp - 4, pyp - 4);
398  }
399  pxp = x[fNpoints - 1] + dpx;
400  pyp = y[fNpoints - 1] + dpy;
401  gVirtualX->DrawLine(pxp - 4, pyp - 4, pxp + 4, pyp - 4);
402  gVirtualX->DrawLine(pxp + 4, pyp - 4, pxp + 4, pyp + 4);
403  gVirtualX->DrawLine(pxp + 4, pyp + 4, pxp - 4, pyp + 4);
404  gVirtualX->DrawLine(pxp - 4, pyp + 4, pxp - 4, pyp - 4);
405  }
406  else {
407  if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold, pyold);
408  if (px2old) gVirtualX->DrawLine(pxold, pyold, px2old, py2old);
409  gVirtualX->DrawLine(pxold - 4, pyold - 4, pxold + 4, pyold - 4);
410  gVirtualX->DrawLine(pxold + 4, pyold - 4, pxold + 4, pyold + 4);
411  gVirtualX->DrawLine(pxold + 4, pyold + 4, pxold - 4, pyold + 4);
412  gVirtualX->DrawLine(pxold - 4, pyold + 4, pxold - 4, pyold - 4);
413  pxold = px;
414  pxold = TMath::Max(pxold, px1);
415  pxold = TMath::Min(pxold, px2);
416  pyold = py;
417  pyold = TMath::Max(pyold, py2);
418  pyold = TMath::Min(pyold, py1);
419  if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold, pyold);
420  if (px2old) gVirtualX->DrawLine(pxold, pyold, px2old, py2old);
421  gVirtualX->DrawLine(pxold - 4, pyold - 4, pxold + 4, pyold - 4);
422  gVirtualX->DrawLine(pxold + 4, pyold - 4, pxold + 4, pyold + 4);
423  gVirtualX->DrawLine(pxold + 4, pyold + 4, pxold - 4, pyold + 4);
424  gVirtualX->DrawLine(pxold - 4, pyold + 4, pxold - 4, pyold - 4);
425  }
426  break;
427 
428  case kButton1Up:
429 
430  if (gROOT->IsEscaped()) {
431  gROOT->SetEscape(kFALSE);
432  delete [] x;
433  x = 0;
434  delete [] y;
435  y = 0;
436  break;
437  }
438 
439  // Compute x,y range
440  xmin = gPad->GetUxmin();
441  xmax = gPad->GetUxmax();
442  ymin = gPad->GetUymin();
443  ymax = gPad->GetUymax();
444  dx = xmax - xmin;
445  dy = ymax - ymin;
446  dxr = dx / (1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
447  dyr = dy / (1 - gPad->GetBottomMargin() - gPad->GetTopMargin());
448 
449  if (fHistogram) {
450  // Range() could change the size of the pad pixmap and therefore should
451  // be called before the other paint routines
452  gPad->Range(xmin - dxr * gPad->GetLeftMargin(),
453  ymin - dyr * gPad->GetBottomMargin(),
454  xmax + dxr * gPad->GetRightMargin(),
455  ymax + dyr * gPad->GetTopMargin());
456  gPad->RangeAxis(xmin, ymin, xmax, ymax);
457  }
458  if (middle) {
459  for (i = 0; i < fNpoints; i++) {
460  if (badcase) continue; //do not update if big zoom and points moved
461  if (x) fX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i] + dpx));
462  if (y) fY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i] + dpy));
463  }
464  }
465  else {
466  fX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
467  fY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
468 // if (InheritsFrom("TCutG")) {
469 // //make sure first and last point are the same
470 // if (ipoint == 0) {
471 // fX[fNpoints-1] = fX[0];
472 // fY[fNpoints-1] = fY[0];
473 // }
474 // if (ipoint == fNpoints-1) {
475 // fX[0] = fX[fNpoints-1];
476 // fY[0] = fY[fNpoints-1];
477 // }
478 // }
479  }
480  badcase = kFALSE;
481  delete [] x;
482  x = 0;
483  delete [] y;
484  y = 0;
485  gPad->Modified(kTRUE);
486  gVirtualX->SetLineColor(-1);
487 
488  }
489 
490 }
491 
492 
493 
494 
497 
498 void KVIDLine::Streamer(TBuffer& R__b)
499 {
500  // Stream an object of class KVIDLine
501 
502  UInt_t R__s, R__c;
503  if (R__b.IsReading()) {
504  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
505  if (R__v < 2) {
506  TGraph::Streamer(R__b);
507  }
508  else {
509  R__b.ReadClassBuffer(KVIDLine::Class(), this, R__v, R__s, R__c);
510  }
511  }
512  else {
513  R__b.WriteClassBuffer(KVIDLine::Class(), this);
514  }
515 }
516 
517 
kMouseMotion
kButton1Motion
kButton1Up
kButton1Down
int Int_t
unsigned int UInt_t
kMove
kHand
const Int_t kMaxPixel
#define d(i)
bool Bool_t
short Version_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
#define X(type, name)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t np
float xmin
float ymin
float xmax
float ymax
#define gROOT
char * Form(const char *fmt,...)
#define gPad
#define gVirtualX
Base class for lines/cuts used for particle identification in 2D data maps.
Definition: KVIDLine.h:143
static KVIDLine * MakeIDLine(TObject *obj, Double_t xdeb=-1., Double_t xfin=-1., Double_t np=1., Bool_t save=kFALSE)
Definition: KVIDLine.cpp:88
Bool_t WhereAmI(Double_t px, Double_t py, Option_t *opt) const
void ExecuteEvent(Int_t event, Int_t px, Int_t py) override
Definition: KVIDLine.cpp:255
Bool_t IsBetweenEndPoints(Double_t x, Double_t y, std::optional< TString > axis={}) const
KVIDLine()
Default ctor.
Definition: KVIDLine.cpp:38
void WaitForPrimitive() override
Definition: KVIDLine.cpp:223
Base class for graphical cuts used in particle identification.
Definition: KVIDentifier.h:28
void CopyGraph(TGraph *)
Copy coordinates of points from the TGraph.
virtual void Modify()
virtual Version_t ReadVersion(UInt_t *start=nullptr, UInt_t *bcnt=nullptr, const TClass *cl=nullptr)=0
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=nullptr)=0
Bool_t IsReading() const
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
void Streamer(TBuffer &) override
static TClass * Class()
virtual Double_t Eval(Double_t x, Double_t y=0, Double_t z=0, Double_t t=0) const
Int_t fNpoints
Double_t * GetY() const
virtual Bool_t IsEditable() const
TH1F * fHistogram
Int_t GetN() const
Double_t * fY
void Streamer(TBuffer &) override
Double_t * GetX() const
void Draw(Option_t *chopt="") override
Double_t * fX
virtual Int_t GetPoint(Int_t i, Double_t &x, Double_t &y) const
virtual Double_t GetBinCenter(Int_t bin) const
virtual Int_t GetNbinsX() const
virtual const char * GetName() const
virtual Bool_t InheritsFrom(const char *classname) const
Double_t GetBinContent(Int_t bin) const override
virtual Double_t GetBinEntries(Int_t bin) const
TLine * line
Double_t y[n]
Double_t x[n]
TGraphErrors * gr
Double_t Min(Double_t a, Double_t b)
Double_t Abs(Double_t d)
Double_t Max(Double_t a, Double_t b)
ClassImp(TPyArg)