Fix coverity defect
[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( (xmin+xmax)/2.0, (ymin+ymax)/2.0 ,
60                  (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 fIx(-1),
76 fIy(-1),
77 fStatus(0),
78 fDimensions(),
79 fPosition(),
80 fCharge(0.0),
81 fChargeBackup(0.0)
82 {
83   /// Default ctor
84   Init(-1,-1,-1,-1,TVector2(0,0),TVector2(0,0),0);
85 }
86
87 //_____________________________________________________________________________
88 AliMUONPad::AliMUONPad(Int_t detElemId, Int_t cathode,
89                        Int_t ix, Int_t iy, Double_t x, Double_t y,
90                        Double_t dx, Double_t dy, Double_t charge)
91 :
92 TObject(),
93 fIsSaturated(kFALSE),
94 fIsReal(kFALSE),
95 fClusterId(-1),
96 fCathode(-1),
97 fDetElemId(-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 fIx(-1),
121 fIy(-1),
122 fStatus(0),
123 fDimensions(),
124 fPosition(),
125 fCharge(0.0),
126 fChargeBackup(0.0)
127 {
128   /// Truncated constructor (w/o DE, cath, ix, iy)
129   Init(-1,-1,-1,-1,TVector2(x,y),TVector2(dx,dy),charge);
130 }
131
132 //_____________________________________________________________________________
133 AliMUONPad::AliMUONPad(const TVector2& position, const TVector2& dimensions,
134                        Double_t charge)
135 : TObject(),
136 fIsSaturated(kFALSE),
137 fIsReal(kFALSE),
138 fClusterId(-1),
139 fCathode(-1),
140 fDetElemId(-1),
141 fIx(-1),
142 fIy(-1),
143 fStatus(0),
144 fDimensions(),
145 fPosition(),
146 fCharge(0.0),
147 fChargeBackup(0.0)
148 {
149   /// Alternate ctor
150   Init(-1,-1,-1,-1,position,dimensions,charge);
151 }
152
153 //_____________________________________________________________________________
154 AliMUONPad::~AliMUONPad()
155 {
156 /// Dtor
157 }
158
159 //_____________________________________________________________________________
160 Bool_t 
161 AliMUONPad::AreNeighbours(const AliMUONPad& d1, const AliMUONPad& d2) 
162 {
163   /// Whether 2 pads are neighbours or not
164   if ( d1.DetElemId() != d2.DetElemId() || 
165        d1.Cathode() != d2.Cathode() )
166   {
167     return kFALSE;
168   }
169   else
170   {
171     static Double_t precision = 1E-4; // cm
172     static TVector2 precisionAdjustment(-precision,-precision);    
173     return AreOverlapping(d1,d2,precisionAdjustment);
174   }
175 }
176
177 //_____________________________________________________________________________
178 Bool_t
179 AliMUONPad::AreOverlapping(const AliMUONPad& d1, const AliMUONPad& d2,
180                            const TVector2& precision)
181 {
182   /// Checks the overlap between 2 pads.
183   /// The actual overlap is computed not on d1 and d2, but on d1 and d2
184   /// "re-scaled" using the precision vector (conceptually equivalent to 
185   /// d.Dimensions() += precision)
186   ///
187   /// So, if the elements (x,y) of precision are :
188   ///
189   /// - positive, the overlap is "computed" from smaller d1 and d2  
190   ///   which is, modulo the precision, what you would think as a normal
191   ///   overlap calculation
192   /// - negative, overlap is from "bigger" d1 and d2, which is usefull to "tweek"
193   ///   what we call an overlap, e.g. to consider 2 pads touching only by their
194   ///   corners to be overlapping.
195   
196   AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
197   AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
198   
199   if ( a1.LeftBorder() > a2.RightBorder() - precision.X() ||
200        a1.RightBorder() < a2.LeftBorder() + precision.X() )
201   {
202     return kFALSE;
203   }
204   
205   if ( a1.DownBorder() > a2.UpBorder() - precision.Y() ||
206        a1.UpBorder() < a2.DownBorder() + precision.Y() )
207   {
208     return kFALSE;
209   }
210   return kTRUE;
211 }
212
213 //_____________________________________________________________________________
214 Bool_t
215 AliMUONPad::AreOverlapping(const AliMUONPad& d1, const AliMUONPad& d2,
216                            const TVector2& precision,
217                            AliMpArea& overlapRegion) 
218 {
219   /// Checks the overlap between 2 pads, and returns the overlap area
220   /// 
221   /// See comments on the other AreOverlapping method, too : in this
222   /// method, the overlapRegion does *not* depend on the precision parameter,
223   /// which is only used to decide whether the pads are overlapping, while
224   /// the actual overlap region is computed w/o reference to precision.
225   ///
226   if ( AreOverlapping(d1,d2,precision) )
227   {
228     overlapRegion = Overlap(d1,d2);
229     if ( !overlapRegion.IsValid() )
230     {
231       cerr << "Something is wrong : the 2 pads below are flagged as overlapping"
232       << ", but the overlapRegion is not valid"
233       << endl;
234       d1.Print("corners");
235       d2.Print("corners");
236     }
237     return kTRUE;
238   }
239   return kFALSE;
240 }
241
242 //_____________________________________________________________________________
243 Int_t 
244 AliMUONPad::Compare(const TObject* obj) const
245 {
246   /// Compare 2 pads. 
247   /// Ordering is as complete as possible.
248   
249   const AliMUONPad* pad = static_cast<const AliMUONPad*>(obj);
250     
251   if (DetElemId() < 0)
252   {
253     // AZ - For "pixels" from MLEM cluster finder
254     // we only sort on charge
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               if ( Charge() < pad->Charge() ) 
326               {
327                 return -1;
328               }
329               else if ( Charge() > pad->Charge() )
330               {
331                 return 1;
332               }
333               else
334               {
335                 return 0;
336               }
337             }
338           }          
339         }        
340       }
341     }
342   }
343   return 0;
344 }
345
346 //_____________________________________________________________________________
347 Double_t
348 AliMUONPad::Coord(Int_t ixy) const
349 {
350   /// To be friendly and backward compatible with AZ code, which 
351   /// used that kind of coordinate accessing.
352   
353   if ( ixy == 0 ) 
354   {
355     return X();
356   }
357   else if ( ixy == 1 )
358   {
359     return Y();
360   }
361   AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
362   return 0;
363 }
364
365 //_____________________________________________________________________________
366 void 
367 AliMUONPad::Init(Int_t detElemId, Int_t cathode,
368                  Int_t ix, Int_t iy,
369                  const TVector2& position,
370                  const TVector2& dimensions,
371                  Double_t charge)
372 {
373   /// Called by all the ctors
374   fIsSaturated = kFALSE;
375   fIsReal = kTRUE;
376   fDetElemId = detElemId;
377   fCathode = cathode;
378   fIx = ix;
379   fIy = iy;
380   fPosition = position;
381   fDimensions = dimensions;
382   fCharge = charge;
383   fChargeBackup = fCharge;
384   
385   fClusterId = -1;
386
387   fStatus = 0;
388 }
389
390 //_____________________________________________________________________________
391 AliMpArea
392 AliMUONPad::Overlap(const AliMUONPad& d1, const AliMUONPad& d2)
393 {  
394   /// Return the overlap region between two pads
395   AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
396   AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
397   return Intersect(a1,a2);
398 }
399
400
401 //_____________________________________________________________________________
402 void
403 AliMUONPad::Paint(Option_t*)
404 {
405   /// Paint pad on screen
406   TVector2 ll = Position() - Dimensions();
407   TVector2 ur = Position() + Dimensions();
408
409   gPad->PaintBox(ll.X(),ll.Y(),ur.X(),ur.Y());
410 }
411
412 //_____________________________________________________________________________
413 void
414 AliMUONPad::Print(Option_t* opt) const
415 {
416   /// Printout
417   TString sopt(opt);
418   sopt.ToLower();
419   
420   ios_base::fmtflags oldflags = cout.flags();
421   if ( Cathode() >= 0 )
422   {
423     cout << "DetEle " << setw(5) << DetElemId()
424     << " Cath " << setw(2) << Cathode()
425     << " (Ix,Iy)=(" << setw(3) << Ix() << "," << setw(3) << Iy() << ") ";
426   }
427   cout.setf(ios::fixed);
428   cout.precision(6);
429   cout << " (x,y)=(" << setw(9) << X() << "," << setw(9) << Y() << ") "
430   << " (dx,dy)=(" << setw(9) << DX() << "," << setw(9) << DY() << ") "
431   << " Charge=";
432   cout.precision(2);
433   cout << setw(7) << Charge();
434   if ( sopt.Contains("full") )
435   {
436     cout 
437     << " Used=" << (IsUsed()?Form("YES (ClusterId %d)",fClusterId):"NO")
438     << (IsSaturated()?"(S)":"   ")
439     << (IsReal()?"   ":"(V)")
440     << " Status=" << setw(4) << Status()
441     << " ChargeBackup=" << ChargeBackup();
442   }
443   if ( sopt.Contains("corners") )
444   {
445     cout << Form(" (xmin,xmax)=(%e,%e) (ymin,ymax)=(%e,%e)",
446                  X()-DX(),X()+DX(),
447                  Y()-DY(),Y()+DY()) << endl;
448   }
449   cout << endl;
450   cout.precision(6); // reset to default precision
451   cout.flags(oldflags);
452 }
453
454 //_____________________________________________________________________________
455 void 
456 AliMUONPad::SetCoord(Int_t ixy, Double_t coord)
457 {
458   /// Set the pad coordinate (ixy=0 means x, ixy=1 means y)
459   if ( ixy == 0 ) 
460   {
461     fPosition.Set(coord,Y());
462   }
463   else if ( ixy == 1 )
464   {
465     fPosition.Set(X(),coord);
466   }
467   else
468   {
469     AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
470   }
471 }
472
473 //_____________________________________________________________________________
474 void 
475 AliMUONPad::SetSize(Int_t ixy, Double_t size)
476 {
477   /// Set the pad half size (ixy=0 means x half size, ixy=1 means y half size)
478   if ( ixy == 0 ) 
479   {
480     fDimensions.Set(size,DY());
481   }
482   else if ( ixy == 1 )
483   {
484     fDimensions.Set(DX(),size);
485   }
486   else
487   {
488     AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
489   }
490 }
491
492 //_____________________________________________________________________________
493 void 
494 AliMUONPad::Shift(Int_t ixy, Double_t shift)
495 {
496   /// Shift the position by "shift"
497   SetCoord(ixy,Coord(ixy)+shift);
498 }
499
500 //_____________________________________________________________________________
501 Double_t
502 AliMUONPad::Size(Int_t ixy) const
503 {
504   /// Returns the half size along a direction, given by ixy
505   /// (see SetSize for ixy meaning)
506   
507   if ( ixy == 0 ) 
508   {
509     return DX();
510   }
511   else if ( ixy == 1 )
512   {
513     return DY();
514   }
515   AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
516   return 0;
517 }