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