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