Always delete TObjArrays created by TString::Tokenize (Ruben)
[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
cdd730d0 43using std::setw;
44using std::cout;
45using std::endl;
46using std::ios_base;
47using std::cerr;
48using std::ios;
4b6f2cee 49/// \cond CLASSIMP
50ClassImp(AliMUONPad)
51/// \endcond
52
53namespace
54{
55 AliMpArea
56 Intersect(const AliMpArea& a, const AliMpArea& b)
57 {
58 //
59 // Returns the common part of a and b.
60 //
61 Double_t xmin = TMath::Max(a.LeftBorder(),b.LeftBorder());
62 Double_t xmax = TMath::Min(a.RightBorder(),b.RightBorder());
63 Double_t ymin = TMath::Max(a.DownBorder(),b.DownBorder());
64 Double_t ymax = TMath::Min(a.UpBorder(),b.UpBorder());
6e97fbb8 65 AliMpArea c( (xmin+xmax)/2.0, (ymin+ymax)/2.0 ,
66 (xmax-xmin)/2.0, (ymax-ymin)/2.0 );
4b6f2cee 67
68 return c;
69 }
70}
71
72//_____________________________________________________________________________
73AliMUONPad::AliMUONPad()
74:
75TObject(),
76fIsSaturated(kFALSE),
77fIsReal(kFALSE),
78fClusterId(-1),
79fCathode(-1),
80fDetElemId(-1),
4b6f2cee 81fIx(-1),
82fIy(-1),
83fStatus(0),
84fDimensions(),
85fPosition(),
86fCharge(0.0),
87fChargeBackup(0.0)
88{
89 /// Default ctor
90 Init(-1,-1,-1,-1,TVector2(0,0),TVector2(0,0),0);
91}
92
93//_____________________________________________________________________________
94AliMUONPad::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:
98TObject(),
99fIsSaturated(kFALSE),
100fIsReal(kFALSE),
101fClusterId(-1),
102fCathode(-1),
103fDetElemId(-1),
4b6f2cee 104fIx(-1),
105fIy(-1),
106fStatus(0),
107fDimensions(),
108fPosition(),
109fCharge(0.0),
110fChargeBackup(0.0)
111
112{
113 /// Normal ctor, using full information
114 Init(detElemId,cathode,ix,iy,TVector2(x,y),TVector2(dx,dy),charge);
115}
116
117//_____________________________________________________________________________
118AliMUONPad::AliMUONPad(Double_t x, Double_t y,
119 Double_t dx, Double_t dy, Double_t charge)
120: TObject(),
121fIsSaturated(kFALSE),
122fIsReal(kFALSE),
123fClusterId(-1),
124fCathode(-1),
125fDetElemId(-1),
4b6f2cee 126fIx(-1),
127fIy(-1),
128fStatus(0),
129fDimensions(),
130fPosition(),
131fCharge(0.0),
132fChargeBackup(0.0)
133{
134 /// Truncated constructor (w/o DE, cath, ix, iy)
135 Init(-1,-1,-1,-1,TVector2(x,y),TVector2(dx,dy),charge);
136}
137
138//_____________________________________________________________________________
139AliMUONPad::AliMUONPad(const TVector2& position, const TVector2& dimensions,
140 Double_t charge)
141: TObject(),
142fIsSaturated(kFALSE),
143fIsReal(kFALSE),
144fClusterId(-1),
145fCathode(-1),
146fDetElemId(-1),
4b6f2cee 147fIx(-1),
148fIy(-1),
149fStatus(0),
150fDimensions(),
151fPosition(),
152fCharge(0.0),
153fChargeBackup(0.0)
154{
155 /// Alternate ctor
156 Init(-1,-1,-1,-1,position,dimensions,charge);
157}
158
159//_____________________________________________________________________________
71a2d3aa 160AliMUONPad::~AliMUONPad()
161{
162/// Dtor
163}
164
165//_____________________________________________________________________________
4b6f2cee 166Bool_t
167AliMUONPad::AreNeighbours(const AliMUONPad& d1, const AliMUONPad& d2)
168{
169 /// Whether 2 pads are neighbours or not
170 if ( d1.DetElemId() != d2.DetElemId() ||
171 d1.Cathode() != d2.Cathode() )
172 {
173 return kFALSE;
174 }
175 else
176 {
177 static Double_t precision = 1E-4; // cm
178 static TVector2 precisionAdjustment(-precision,-precision);
179 return AreOverlapping(d1,d2,precisionAdjustment);
180 }
181}
182
183//_____________________________________________________________________________
184Bool_t
185AliMUONPad::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
6e97fbb8 202 AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
203 AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
4b6f2cee 204
205 if ( a1.LeftBorder() > a2.RightBorder() - precision.X() ||
206 a1.RightBorder() < a2.LeftBorder() + precision.X() )
207 {
208 return kFALSE;
209 }
210
211 if ( a1.DownBorder() > a2.UpBorder() - precision.Y() ||
212 a1.UpBorder() < a2.DownBorder() + precision.Y() )
213 {
214 return kFALSE;
215 }
216 return kTRUE;
217}
218
219//_____________________________________________________________________________
220Bool_t
221AliMUONPad::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 if ( AreOverlapping(d1,d2,precision) )
233 {
234 overlapRegion = Overlap(d1,d2);
235 if ( !overlapRegion.IsValid() )
236 {
237 cerr << "Something is wrong : the 2 pads below are flagged as overlapping"
238 << ", but the overlapRegion is not valid"
239 << endl;
240 d1.Print("corners");
241 d2.Print("corners");
242 }
243 return kTRUE;
244 }
245 return kFALSE;
246}
247
248//_____________________________________________________________________________
249Int_t
250AliMUONPad::Compare(const TObject* obj) const
251{
252 /// Compare 2 pads.
253 /// Ordering is as complete as possible.
254
255 const AliMUONPad* pad = static_cast<const AliMUONPad*>(obj);
256
8f473fdb 257 if (DetElemId() < 0)
258 {
4bd6a200 259 // AZ - For "pixels" from MLEM cluster finder
8f473fdb 260 // we only sort on charge
4bd6a200 261 if (Charge() == pad->Charge()) return 0;
262 return ( Charge() < pad->Charge() ) ? 1:-1;
263 }
264
4b6f2cee 265 if ( DetElemId() > pad->DetElemId() )
266 {
267 return 1;
268 }
2a055915 269 else if ( DetElemId() < pad->DetElemId() )
4b6f2cee 270 {
8f473fdb 271 return -1;
4b6f2cee 272 }
273 else
274 {
275 // same DetElemId...
276 if ( Cathode() > pad->Cathode() )
277 {
278 return 1;
279 }
280 else if ( Cathode() < pad->Cathode() )
281 {
282 return -1;
283 }
284 else
285 {
286 // same cathode...
287 if ( Ix() > pad->Ix() )
288 {
289 return 1;
290 }
291 else if ( Ix() < pad->Ix() )
292 {
293 return -1;
294 }
295 else
296 {
297 // same ix....
298 if ( Iy() > pad->Iy() )
299 {
300 return 1;
301 }
302 else if ( Iy() < pad->Iy() )
303 {
304 return -1;
305 }
306 else
307 {
308 // same iy....
309 if ( X() > pad->X() )
310 {
311 return 1;
312 }
313 else if ( X() < pad->X() )
314 {
315 return -1;
316 }
317 else
318 {
319 // same X
320 if ( Y() > pad->Y() )
321 {
322 return 1;
323 }
324 else if ( Y() < pad->Y() )
325 {
326 return -1;
327 }
328 else
329 {
330 // same Y
8f473fdb 331 if ( Charge() < pad->Charge() )
332 {
333 return -1;
334 }
335 else if ( Charge() > pad->Charge() )
336 {
337 return 1;
338 }
339 else
340 {
341 return 0;
342 }
343 }
4b6f2cee 344 }
345 }
346 }
347 }
348 }
8f473fdb 349 return 0;
4b6f2cee 350}
351
352//_____________________________________________________________________________
353Double_t
354AliMUONPad::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 if ( ixy == 0 )
360 {
361 return X();
362 }
363 else if ( ixy == 1 )
364 {
365 return Y();
366 }
367 AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
368 return 0;
369}
370
371//_____________________________________________________________________________
372void
373AliMUONPad::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 fIsSaturated = kFALSE;
381 fIsReal = kTRUE;
382 fDetElemId = detElemId;
383 fCathode = cathode;
384 fIx = ix;
385 fIy = iy;
386 fPosition = position;
387 fDimensions = dimensions;
388 fCharge = charge;
389 fChargeBackup = fCharge;
390
391 fClusterId = -1;
4b6f2cee 392
393 fStatus = 0;
394}
395
396//_____________________________________________________________________________
397AliMpArea
398AliMUONPad::Overlap(const AliMUONPad& d1, const AliMUONPad& d2)
399{
400 /// Return the overlap region between two pads
6e97fbb8 401 AliMpArea a1(d1.X(),d1.Y(),d1.DX(),d1.DY());
402 AliMpArea a2(d2.X(),d2.Y(),d2.DX(),d2.DY());
4b6f2cee 403 return Intersect(a1,a2);
404}
405
406
407//_____________________________________________________________________________
408void
409AliMUONPad::Paint(Option_t*)
410{
411 /// Paint pad on screen
412 TVector2 ll = Position() - Dimensions();
413 TVector2 ur = Position() + Dimensions();
414
415 gPad->PaintBox(ll.X(),ll.Y(),ur.X(),ur.Y());
416}
417
418//_____________________________________________________________________________
419void
420AliMUONPad::Print(Option_t* opt) const
421{
422 /// Printout
423 TString sopt(opt);
424 sopt.ToLower();
425
426 ios_base::fmtflags oldflags = cout.flags();
427 if ( Cathode() >= 0 )
428 {
429 cout << "DetEle " << setw(5) << DetElemId()
430 << " Cath " << setw(2) << Cathode()
431 << " (Ix,Iy)=(" << setw(3) << Ix() << "," << setw(3) << Iy() << ") ";
432 }
433 cout.setf(ios::fixed);
434 cout.precision(6);
435 cout << " (x,y)=(" << setw(9) << X() << "," << setw(9) << Y() << ") "
436 << " (dx,dy)=(" << setw(9) << DX() << "," << setw(9) << DY() << ") "
437 << " Charge=";
438 cout.precision(2);
439 cout << setw(7) << Charge();
440 if ( sopt.Contains("full") )
441 {
442 cout
443 << " Used=" << (IsUsed()?Form("YES (ClusterId %d)",fClusterId):"NO")
444 << (IsSaturated()?"(S)":" ")
445 << (IsReal()?" ":"(V)")
446 << " Status=" << setw(4) << Status()
447 << " ChargeBackup=" << ChargeBackup();
448 }
449 if ( sopt.Contains("corners") )
450 {
451 cout << Form(" (xmin,xmax)=(%e,%e) (ymin,ymax)=(%e,%e)",
452 X()-DX(),X()+DX(),
453 Y()-DY(),Y()+DY()) << endl;
454 }
455 cout << endl;
4bd6a200 456 cout.precision(6); // reset to default precision
4b6f2cee 457 cout.flags(oldflags);
458}
459
460//_____________________________________________________________________________
461void
462AliMUONPad::SetCoord(Int_t ixy, Double_t coord)
463{
464 /// Set the pad coordinate (ixy=0 means x, ixy=1 means y)
465 if ( ixy == 0 )
466 {
467 fPosition.Set(coord,Y());
468 }
469 else if ( ixy == 1 )
470 {
471 fPosition.Set(X(),coord);
472 }
473 else
474 {
475 AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
476 }
477}
478
479//_____________________________________________________________________________
480void
481AliMUONPad::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 if ( ixy == 0 )
485 {
486 fDimensions.Set(size,DY());
487 }
488 else if ( ixy == 1 )
489 {
490 fDimensions.Set(DX(),size);
491 }
492 else
493 {
494 AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
495 }
496}
497
498//_____________________________________________________________________________
499void
500AliMUONPad::Shift(Int_t ixy, Double_t shift)
501{
502 /// Shift the position by "shift"
503 SetCoord(ixy,Coord(ixy)+shift);
504}
505
506//_____________________________________________________________________________
507Double_t
508AliMUONPad::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 if ( ixy == 0 )
514 {
515 return DX();
516 }
517 else if ( ixy == 1 )
518 {
519 return DY();
520 }
521 AliError(Form("Incorrect coordinates index %d (only 0,1 are valid)",ixy));
522 return 0;
523}