]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONPad.cxx
Correct function Compare() for "pixels" from MLEM cluster finder.
[u/mrichter/AliRoot.git] / MUON / AliMUONPad.cxx
1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 *                                                                        *
4 * Author: The ALICE Off-line Project.                                    *
5 * Contributors are mentioned in the code where appropriate.              *
6 *                                                                        *
7 * Permission to use, copy, modify and distribute this software and its   *
8 * documentation strictly for non-commercial purposes is hereby granted   *
9 * without fee, provided that the above copyright notice appears in all   *
10 * copies and that both the copyright notice and this permission notice   *
11 * appear in the supporting documentation. The authors make no claims     *
12 * about the suitability of this software for any purpose. It is          *
13 * provided "as is" without express or implied warranty.                  *
14 **************************************************************************/
15
16 // $Id$
17
18 #include "AliMUONPad.h"
19
20 #include "AliLog.h"
21 #include "AliMpArea.h"
22
23 #include "Riostream.h"
24 #include "TVirtualPad.h"
25 #include "TVirtualX.h"
26 #include "TVector2.h"
27 #include "TMath.h"
28
29 /// \class AliMUONPad
30 ///
31 /// Object gathering information about a hit pad.
32 /// 
33 /// Can be seen as a combination of a Digit (which brings the charge) 
34 /// and an MpPad (which brings location and position)
35 ///
36 /// Also provided are some static functions to compute overlap and
37 /// get neighboring information.
38 ///
39 /// \author Laurent Aphecetche
40
41 /// \cond CLASSIMP
42 ClassImp(AliMUONPad)
43 /// \endcond
44
45 namespace
46 {
47   AliMpArea
48   Intersect(const AliMpArea& a, const AliMpArea& b)
49   { 
50     //
51     // Returns the common part of a and b.
52     //
53     Double_t xmin = TMath::Max(a.LeftBorder(),b.LeftBorder());
54     Double_t xmax = TMath::Min(a.RightBorder(),b.RightBorder());
55     Double_t ymin = TMath::Max(a.DownBorder(),b.DownBorder());
56     Double_t ymax = TMath::Min(a.UpBorder(),b.UpBorder());
57     AliMpArea c( TVector2( (xmin+xmax)/2.0, (ymin+ymax)/2.0 ),
58                  TVector2( (xmax-xmin)/2.0, (ymax-ymin)/2.0 ) );
59         
60     return c;
61   }
62 }
63
64 //_____________________________________________________________________________
65 AliMUONPad::AliMUONPad()
66 :
67 TObject(),
68 fIsSaturated(kFALSE),
69 fIsReal(kFALSE),
70 fClusterId(-1),
71 fCathode(-1),
72 fDetElemId(-1),
73 fDigitIndex(-1),
74 fIx(-1),
75 fIy(-1),
76 fStatus(0),
77 fDimensions(),
78 fPosition(),
79 fCharge(0.0),
80 fChargeBackup(0.0)
81 {
82   /// Default ctor
83   Init(-1,-1,-1,-1,TVector2(0,0),TVector2(0,0),0);
84 }
85
86 //_____________________________________________________________________________
87 AliMUONPad::AliMUONPad(Int_t detElemId, Int_t cathode,
88                        Int_t ix, Int_t iy, Double_t x, Double_t y,
89                        Double_t dx, Double_t dy, Double_t charge)
90 :
91 TObject(),
92 fIsSaturated(kFALSE),
93 fIsReal(kFALSE),
94 fClusterId(-1),
95 fCathode(-1),
96 fDetElemId(-1),
97 fDigitIndex(-1),
98 fIx(-1),
99 fIy(-1),
100 fStatus(0),
101 fDimensions(),
102 fPosition(),
103 fCharge(0.0),
104 fChargeBackup(0.0)
105
106 {
107   /// Normal ctor, using full information
108   Init(detElemId,cathode,ix,iy,TVector2(x,y),TVector2(dx,dy),charge);
109 }
110
111 //_____________________________________________________________________________
112 AliMUONPad::AliMUONPad(Double_t x, Double_t y,
113                        Double_t dx, Double_t dy, Double_t charge)
114 : TObject(),
115 fIsSaturated(kFALSE),
116 fIsReal(kFALSE),
117 fClusterId(-1),
118 fCathode(-1),
119 fDetElemId(-1),
120 fDigitIndex(-1),
121 fIx(-1),
122 fIy(-1),
123 fStatus(0),
124 fDimensions(),
125 fPosition(),
126 fCharge(0.0),
127 fChargeBackup(0.0)
128 {
129   /// Truncated constructor (w/o DE, cath, ix, iy)
130   Init(-1,-1,-1,-1,TVector2(x,y),TVector2(dx,dy),charge);
131 }
132
133 //_____________________________________________________________________________
134 AliMUONPad::AliMUONPad(const TVector2& position, const TVector2& dimensions,
135                        Double_t charge)
136 : TObject(),
137 fIsSaturated(kFALSE),
138 fIsReal(kFALSE),
139 fClusterId(-1),
140 fCathode(-1),
141 fDetElemId(-1),
142 fDigitIndex(-1),
143 fIx(-1),
144 fIy(-1),
145 fStatus(0),
146 fDimensions(),
147 fPosition(),
148 fCharge(0.0),
149 fChargeBackup(0.0)
150 {
151   /// Alternate ctor
152   Init(-1,-1,-1,-1,position,dimensions,charge);
153 }
154
155 //_____________________________________________________________________________
156 AliMUONPad::~AliMUONPad()
157 {
158 /// Dtor
159 }
160
161 //_____________________________________________________________________________
162 Bool_t 
163 AliMUONPad::AreNeighbours(const AliMUONPad& d1, const AliMUONPad& d2) 
164 {
165   /// Whether 2 pads are neighbours or not
166   if ( d1.DetElemId() != d2.DetElemId() || 
167        d1.Cathode() != d2.Cathode() )
168   {
169     return kFALSE;
170   }
171   else
172   {
173     static Double_t precision = 1E-4; // cm
174     static TVector2 precisionAdjustment(-precision,-precision);    
175     return AreOverlapping(d1,d2,precisionAdjustment);
176   }
177 }
178
179 //_____________________________________________________________________________
180 Bool_t
181 AliMUONPad::AreOverlapping(const AliMUONPad& d1, const AliMUONPad& d2,
182                            const TVector2& precision)
183 {
184   /// Checks the overlap between 2 pads.
185   /// The actual overlap is computed not on d1 and d2, but on d1 and d2
186   /// "re-scaled" using the precision vector (conceptually equivalent to 
187   /// d.Dimensions() += precision)
188   ///
189   /// So, if the elements (x,y) of precision are :
190   ///
191   /// - positive, the overlap is "computed" from smaller d1 and d2  
192   ///   which is, modulo the precision, what you would think as a normal
193   ///   overlap calculation
194   /// - negative, overlap is from "bigger" d1 and d2, which is usefull to "tweek"
195   ///   what we call an overlap, e.g. to consider 2 pads touching only by their
196   ///   corners to be overlapping.
197   
198   AliMpArea a1(d1.Position(),d1.Dimensions());
199   AliMpArea a2(d2.Position(),d2.Dimensions());
200   
201   if ( a1.LeftBorder() > a2.RightBorder() - precision.X() ||
202        a1.RightBorder() < a2.LeftBorder() + precision.X() )
203   {
204     return kFALSE;
205   }
206   
207   if ( a1.DownBorder() > a2.UpBorder() - precision.Y() ||
208        a1.UpBorder() < a2.DownBorder() + precision.Y() )
209   {
210     return kFALSE;
211   }
212   return kTRUE;
213 }
214
215 //_____________________________________________________________________________
216 Bool_t
217 AliMUONPad::AreOverlapping(const AliMUONPad& d1, const AliMUONPad& d2,
218                            const TVector2& precision,
219                            AliMpArea& overlapRegion) 
220 {
221   /// Checks the overlap between 2 pads, and returns the overlap area
222   /// 
223   /// See comments on the other AreOverlapping method, too : in this
224   /// method, the overlapRegion does *not* depend on the precision parameter,
225   /// which is only used to decide whether the pads are overlapping, while
226   /// the actual overlap region is computed w/o reference to precision.
227   ///
228   if ( AreOverlapping(d1,d2,precision) )
229   {
230     overlapRegion = Overlap(d1,d2);
231     if ( !overlapRegion.IsValid() )
232     {
233       cerr << "Something is wrong : the 2 pads below are flagged as overlapping"
234       << ", but the overlapRegion is not valid"
235       << endl;
236       d1.Print("corners");
237       d2.Print("corners");
238     }
239     return kTRUE;
240   }
241   return kFALSE;
242 }
243
244 //_____________________________________________________________________________
245 Int_t 
246 AliMUONPad::Compare(const TObject* obj) const
247 {
248   /// Compare 2 pads. 
249   /// Ordering is as complete as possible.
250   
251   const AliMUONPad* pad = static_cast<const AliMUONPad*>(obj);
252     
253   if (DetElemId() < 0) {
254     // AZ - For "pixels" from MLEM cluster finder
255     if (Charge() == pad->Charge()) return 0;
256     return ( Charge() < pad->Charge() ) ? 1:-1;
257   }
258
259   if ( DetElemId() > pad->DetElemId() )
260   {
261     return 1;
262   }
263   else if ( DetElemId() > pad->DetElemId() )
264   {
265     return 1;
266   }
267   else
268   {
269     // same DetElemId...
270     if ( Cathode() > pad->Cathode() )
271     {
272       return 1;
273     }
274     else if ( Cathode() < pad->Cathode() ) 
275     {
276       return -1;
277     }
278     else
279     {
280       // same cathode...
281       if ( Ix() > pad->Ix() )
282       {
283         return 1;
284       }
285       else if ( Ix() < pad->Ix() ) 
286       {
287         return -1;
288       }
289       else
290       {
291         // same ix....
292         if ( Iy() > pad->Iy() )
293         {
294           return 1;
295         }
296         else if ( Iy() < pad->Iy() ) 
297         {
298           return -1;
299         }
300         else
301         {
302           // same iy....
303           if ( X() > pad->X() )
304           {
305             return 1;
306           }
307           else if ( X() < pad->X() )
308           {
309             return -1;
310           }
311           else
312           {
313             // same X
314             if ( Y() > pad->Y() )
315             {
316               return 1;
317             }
318             else if ( Y() < pad->Y() )
319             {
320               return -1;
321             }
322             else
323             {
324               // same Y
325               return ( Charge() < pad->Charge() ) ? -1:1;              
326             }            
327           }          
328         }        
329       }
330     }
331   }
332 }
333
334 //_____________________________________________________________________________
335 Double_t
336 AliMUONPad::Coord(Int_t ixy) const
337 {
338   /// To be friendly and backward compatible with AZ code, which 
339   /// used that kind of coordinate accessing.
340   
341   if ( ixy == 0 ) 
342   {
343     return X();
344   }
345   else if ( ixy == 1 )
346   {
347     return Y();
348   }
349   AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
350   return 0;
351 }
352
353 //_____________________________________________________________________________
354 void 
355 AliMUONPad::Init(Int_t detElemId, Int_t cathode,
356                  Int_t ix, Int_t iy,
357                  const TVector2& position,
358                  const TVector2& dimensions,
359                  Double_t charge)
360 {
361   /// Called by all the ctors
362   fIsSaturated = kFALSE;
363   fIsReal = kTRUE;
364   fDetElemId = detElemId;
365   fCathode = cathode;
366   fIx = ix;
367   fIy = iy;
368   fPosition = position;
369   fDimensions = dimensions;
370   fCharge = charge;
371   fChargeBackup = fCharge;
372   
373   fClusterId = -1;
374   fDigitIndex = -1;
375
376   fStatus = 0;
377 }
378
379 //_____________________________________________________________________________
380 AliMpArea
381 AliMUONPad::Overlap(const AliMUONPad& d1, const AliMUONPad& d2)
382 {  
383   /// Return the overlap region between two pads
384   AliMpArea a1(d1.Position(),d1.Dimensions());
385   AliMpArea a2(d2.Position(),d2.Dimensions());
386   return Intersect(a1,a2);
387 }
388
389
390 //_____________________________________________________________________________
391 void
392 AliMUONPad::Paint(Option_t*)
393 {
394   /// Paint pad on screen
395   TVector2 ll = Position() - Dimensions();
396   TVector2 ur = Position() + Dimensions();
397
398   gPad->PaintBox(ll.X(),ll.Y(),ur.X(),ur.Y());
399 }
400
401 //_____________________________________________________________________________
402 void
403 AliMUONPad::Print(Option_t* opt) const
404 {
405   /// Printout
406   TString sopt(opt);
407   sopt.ToLower();
408   
409   ios_base::fmtflags oldflags = cout.flags();
410   if ( Cathode() >= 0 )
411   {
412     cout << "DetEle " << setw(5) << DetElemId()
413     << " Cath " << setw(2) << Cathode()
414     << " (Ix,Iy)=(" << setw(3) << Ix() << "," << setw(3) << Iy() << ") ";
415   }
416   cout.setf(ios::fixed);
417   cout.precision(6);
418   cout << " (x,y)=(" << setw(9) << X() << "," << setw(9) << Y() << ") "
419   << " (dx,dy)=(" << setw(9) << DX() << "," << setw(9) << DY() << ") "
420   << " Charge=";
421   cout.precision(2);
422   cout << setw(7) << Charge();
423   if ( sopt.Contains("full") )
424   {
425     cout 
426     << " Used=" << (IsUsed()?Form("YES (ClusterId %d)",fClusterId):"NO")
427     << (IsSaturated()?"(S)":"   ")
428     << (IsReal()?"   ":"(V)")
429     << " Status=" << setw(4) << Status()
430     << " ChargeBackup=" << ChargeBackup();
431   }
432   if ( sopt.Contains("corners") )
433   {
434     cout << Form(" (xmin,xmax)=(%e,%e) (ymin,ymax)=(%e,%e)",
435                  X()-DX(),X()+DX(),
436                  Y()-DY(),Y()+DY()) << endl;
437   }
438   cout << endl;
439   cout.precision(6); // reset to default precision
440   cout.flags(oldflags);
441 }
442
443 //_____________________________________________________________________________
444 void 
445 AliMUONPad::SetCoord(Int_t ixy, Double_t coord)
446 {
447   /// Set the pad coordinate (ixy=0 means x, ixy=1 means y)
448   if ( ixy == 0 ) 
449   {
450     fPosition.Set(coord,Y());
451   }
452   else if ( ixy == 1 )
453   {
454     fPosition.Set(X(),coord);
455   }
456   else
457   {
458     AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
459   }
460 }
461
462 //_____________________________________________________________________________
463 void 
464 AliMUONPad::SetSize(Int_t ixy, Double_t size)
465 {
466   /// Set the pad half size (ixy=0 means x half size, ixy=1 means y half size)
467   if ( ixy == 0 ) 
468   {
469     fDimensions.Set(size,DY());
470   }
471   else if ( ixy == 1 )
472   {
473     fDimensions.Set(DX(),size);
474   }
475   else
476   {
477     AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
478   }
479 }
480
481 //_____________________________________________________________________________
482 void 
483 AliMUONPad::Shift(Int_t ixy, Double_t shift)
484 {
485   /// Shift the position by "shift"
486   SetCoord(ixy,Coord(ixy)+shift);
487 }
488
489 //_____________________________________________________________________________
490 Double_t
491 AliMUONPad::Size(Int_t ixy) const
492 {
493   /// Returns the half size along a direction, given by ixy
494   /// (see SetSize for ixy meaning)
495   
496   if ( ixy == 0 ) 
497   {
498     return DX();
499   }
500   else if ( ixy == 1 )
501   {
502     return DY();
503   }
504   AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
505   return 0;
506 }