new functionality and new class added
[u/mrichter/AliRoot.git] / MUON / AliMUONPad.cxx
CommitLineData
4b6f2cee 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
3d1463c8 29//-----------------------------------------------------------------------------
4b6f2cee 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
3d1463c8 41//-----------------------------------------------------------------------------
4b6f2cee 42
43/// \cond CLASSIMP
44ClassImp(AliMUONPad)
45/// \endcond
46
47namespace
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());
6e97fbb8 59 AliMpArea c( (xmin+xmax)/2.0, (ymin+ymax)/2.0 ,
60 (xmax-xmin)/2.0, (ymax-ymin)/2.0 );
4b6f2cee 61
62 return c;
63 }
64}
65
66//_____________________________________________________________________________
67AliMUONPad::AliMUONPad()
68:
69TObject(),
70fIsSaturated(kFALSE),
71fIsReal(kFALSE),
72fClusterId(-1),
73fCathode(-1),
74fDetElemId(-1),
4b6f2cee 75fIx(-1),
76fIy(-1),
77fStatus(0),
78fDimensions(),
79fPosition(),
80fCharge(0.0),
81fChargeBackup(0.0)
82{
83 /// Default ctor
84 Init(-1,-1,-1,-1,TVector2(0,0),TVector2(0,0),0);
85}
86
87//_____________________________________________________________________________
88AliMUONPad::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:
92TObject(),
93fIsSaturated(kFALSE),
94fIsReal(kFALSE),
95fClusterId(-1),
96fCathode(-1),
97fDetElemId(-1),
4b6f2cee 98fIx(-1),
99fIy(-1),
100fStatus(0),
101fDimensions(),
102fPosition(),
103fCharge(0.0),
104fChargeBackup(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//_____________________________________________________________________________
112AliMUONPad::AliMUONPad(Double_t x, Double_t y,
113 Double_t dx, Double_t dy, Double_t charge)
114: TObject(),
115fIsSaturated(kFALSE),
116fIsReal(kFALSE),
117fClusterId(-1),
118fCathode(-1),
119fDetElemId(-1),
4b6f2cee 120fIx(-1),
121fIy(-1),
122fStatus(0),
123fDimensions(),
124fPosition(),
125fCharge(0.0),
126fChargeBackup(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//_____________________________________________________________________________
133AliMUONPad::AliMUONPad(const TVector2& position, const TVector2& dimensions,
134 Double_t charge)
135: TObject(),
136fIsSaturated(kFALSE),
137fIsReal(kFALSE),
138fClusterId(-1),
139fCathode(-1),
140fDetElemId(-1),
4b6f2cee 141fIx(-1),
142fIy(-1),
143fStatus(0),
144fDimensions(),
145fPosition(),
146fCharge(0.0),
147fChargeBackup(0.0)
148{
149 /// Alternate ctor
150 Init(-1,-1,-1,-1,position,dimensions,charge);
151}
152
153//_____________________________________________________________________________
71a2d3aa 154AliMUONPad::~AliMUONPad()
155{
156/// Dtor
157}
158
159//_____________________________________________________________________________
4b6f2cee 160Bool_t
161AliMUONPad::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//_____________________________________________________________________________
178Bool_t
179AliMUONPad::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
6e97fbb8 196 AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
197 AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
4b6f2cee 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//_____________________________________________________________________________
214Bool_t
215AliMUONPad::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//_____________________________________________________________________________
243Int_t
244AliMUONPad::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
8f473fdb 251 if (DetElemId() < 0)
252 {
4bd6a200 253 // AZ - For "pixels" from MLEM cluster finder
8f473fdb 254 // we only sort on charge
4bd6a200 255 if (Charge() == pad->Charge()) return 0;
256 return ( Charge() < pad->Charge() ) ? 1:-1;
257 }
258
4b6f2cee 259 if ( DetElemId() > pad->DetElemId() )
260 {
261 return 1;
262 }
2a055915 263 else if ( DetElemId() < pad->DetElemId() )
4b6f2cee 264 {
8f473fdb 265 return -1;
4b6f2cee 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
8f473fdb 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 }
4b6f2cee 338 }
339 }
340 }
341 }
342 }
8f473fdb 343 return 0;
4b6f2cee 344}
345
346//_____________________________________________________________________________
347Double_t
348AliMUONPad::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//_____________________________________________________________________________
366void
367AliMUONPad::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;
4b6f2cee 386
387 fStatus = 0;
388}
389
390//_____________________________________________________________________________
391AliMpArea
392AliMUONPad::Overlap(const AliMUONPad& d1, const AliMUONPad& d2)
393{
394 /// Return the overlap region between two pads
6e97fbb8 395 AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
396 AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
4b6f2cee 397 return Intersect(a1,a2);
398}
399
400
401//_____________________________________________________________________________
402void
403AliMUONPad::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//_____________________________________________________________________________
413void
414AliMUONPad::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;
4bd6a200 450 cout.precision(6); // reset to default precision
4b6f2cee 451 cout.flags(oldflags);
452}
453
454//_____________________________________________________________________________
455void
456AliMUONPad::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//_____________________________________________________________________________
474void
475AliMUONPad::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//_____________________________________________________________________________
493void
494AliMUONPad::Shift(Int_t ixy, Double_t shift)
495{
496 /// Shift the position by "shift"
497 SetCoord(ixy,Coord(ixy)+shift);
498}
499
500//_____________________________________________________________________________
501Double_t
502AliMUONPad::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}