]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/mapping/AliMpSlatZonePadIterator.cxx
Presenting to the outside world a (x,y) reference located at the center of the slat...
[u/mrichter/AliRoot.git] / MUON / mapping / AliMpSlatZonePadIterator.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 // $MpId: AliMpSlatZonePadIterator.cxx,v 1.4 2005/09/19 19:01:31 ivana Exp $
18
19 #include "AliMpSlatZonePadIterator.h"
20
21 #include "AliLog.h"
22 #include "AliMpPCB.h"
23 #include "AliMpSlat.h"
24 #include "AliMpSlatSegmentation.h"
25
26 #include <algorithm>
27 #include <limits>
28 #include <cassert>
29
30 ClassImp(AliMpSlatZonePadIterator)
31
32 // This iterator only works within a region of constant density.
33
34 namespace 
35 {
36   const Double_t epsilon = 1E-9; // mm
37   Double_t DMAX(std::numeric_limits<Double_t>::max());
38 }
39
40 //_____________________________________________________________________________
41 AliMpSlatZonePadIterator::AliMpSlatZonePadIterator(const AliMpSlat* slat,
42                                                    const AliMpArea& area)
43 : AliMpVPadIterator(),
44 fkSlat(slat),
45 fSlatSegmentation(new AliMpSlatSegmentation(slat)),
46 fArea(area),
47 fOffset(0.0,0.0),
48 fStep(0.0,0.0),
49 fIsDone(kTRUE)
50 {
51   //
52   // Normal ctor.
53   // Iteration will be done on the slat, over the crop of (area,slat_area)
54   //
55   if (!CropArea()) 
56     {
57       AliFatal(Form("Could not crop area : (x,y)min=(%e,%e) ; max=(%e,%e) for slat %s",
58                     area.LeftBorder(),area.DownBorder(),
59                     area.RightBorder(),area.UpBorder(),fkSlat->GetID()));
60     }
61   Invalidate();
62 }
63
64 //_____________________________________________________________________________
65 AliMpSlatZonePadIterator::~AliMpSlatZonePadIterator()
66 {
67   //
68   // Dtor.
69   //
70   delete fSlatSegmentation;
71 }
72
73 //_____________________________________________________________________________
74 Bool_t
75 AliMpSlatZonePadIterator::CropArea()
76 {
77   //
78   // Checks the area is correct, and truncate it
79   // if it goes outside the slat.
80
81   AliDebug(3,Form("Input area (%7.2f,%7.2f)->(%7.2f,%7.2f)",
82                   fArea.LeftBorder(),fArea.DownBorder(),
83                   fArea.RightBorder(),fArea.UpBorder()));
84
85   // Left and right x-limits have to come from first and last pcbs
86   // to deal with short and rounded pcbs cases.
87   AliMpPCB* first = fkSlat->FindPCB(fArea.LeftBorder(),fArea.DownBorder());
88   AliMpPCB* last = fkSlat->FindPCB(fArea.RightBorder()-epsilon,
89                                  fArea.DownBorder());
90
91   AliDebug(3,Form("First PCB %s Ixmin %2d Last PCB %s Ixmax %2d",
92                   first->GetID(),first->Ixmin(),
93                   last->GetID(),last->Ixmax()));
94
95   Double_t xleft = first->ActiveXmin();
96   Double_t xright = last->ActiveXmax() - epsilon;
97
98   AliDebug(3,Form("xleft,xright=%7.2f,%7.2f",xleft,xright));
99
100   Double_t xmin = std::max(fArea.LeftBorder(),xleft);
101   Double_t xmax = std::min(fArea.RightBorder(),xright);
102   Double_t ymin = std::max(fArea.DownBorder(),0.0);
103   Double_t ymax = std::min(fArea.UpBorder(),fkSlat->DY()*2.0-epsilon);
104
105   AliDebug(3,Form("Cropped area (%7.2f,%7.2f)->(%7.2f,%7.2f)",
106                   xmin,ymin,xmax,ymax));
107   
108   // At this point (xmin,ymin)->(xmax,ymax) should be a zone completely included
109   // inside the slat.
110   // But there's so far no guarantee that it is "filling" an integer number
111   // of pads. The following lines solve this, by expanding the area up to 
112   // the bottomLeft and topRight limits of the pads sitting at (xmin,ymin)
113   // and (xmax,ymax).
114
115   AliMpPad bottomLeft 
116     = fSlatSegmentation->PadByPosition(TVector2(xmin,ymin)-fkSlat->Position(),
117                                        kFALSE);
118   if ( bottomLeft.IsValid() )
119     {
120       xmin = std::min(xmin,fkSlat->DX() + 
121                       bottomLeft.Position().X() - bottomLeft.Dimensions().X());
122       ymin = std::min(ymin,fkSlat->DY() + 
123                       bottomLeft.Position().Y() - bottomLeft.Dimensions().Y());
124     }
125
126   AliMpPad topRight 
127     = fSlatSegmentation->PadByPosition(TVector2(xmax,ymax)-fkSlat->Position(),
128                                        kFALSE);
129   if ( topRight.IsValid() )
130     {
131       xmax = std::max(xmax,fkSlat->DX() + 
132                       topRight.Position().X() + topRight.Dimensions().X());
133       ymax = std::max(ymax,fkSlat->DY() + 
134                       topRight.Position().Y() + topRight.Dimensions().Y());
135     }
136
137   fArea = AliMpArea(TVector2((xmin+xmax)/2.0,(ymin+ymax)/2.0),
138                     TVector2((xmax-xmin)/2.0,(ymax-ymin)/2.0));
139  
140   AliDebug(3,Form("Paddified cropped area (%7.2f,%7.2f)->(%7.2f,%7.2f)",
141                   fArea.LeftBorder(),fArea.DownBorder(),
142                   fArea.RightBorder(),fArea.UpBorder())); 
143
144   // Finally set the step sizes equal to the smallest pad sizes (which is
145   // hereby assumed to be that of the first pcb).
146   fStep.Set(first->PadSizeX(),first->PadSizeY());
147
148   AliDebug(3,Form("Step Sizes (%7.2f,%7.2f)",fStep.X(),fStep.Y()));
149
150   return fArea.IsValid();
151 }
152
153 //_____________________________________________________________________________
154 AliMpPad
155 AliMpSlatZonePadIterator::CurrentItem() const
156 {
157   //
158   // Returns the current iteration position (i.e. a pad)
159   //
160   return fCurrentPad;
161 }
162
163 //_____________________________________________________________________________
164 Bool_t
165 AliMpSlatZonePadIterator::GetNextPosition(Double_t& x, Double_t& y)
166 {
167   // Get the next iteration position. 
168   // On input, fOffset must be a valid position (i.e. within iteration
169   // area already).
170
171   AliDebug(3,Form("input (x,y)=(%7.2f,%7.2f)",x,y));
172
173   x += fStep.X();
174
175   if ( x > fArea.Dimensions().X() ) 
176     {
177       AliDebug(3,"Going back left and one step upper");
178       // Go back leftmost position...
179       x = -1.0*fArea.Dimensions().X();
180       // ... and up
181       y += fStep.Y();
182       // Update y offset
183       fOffset.Set(fOffset.X(),y);
184       if ( y > fArea.Dimensions().Y() )
185       {
186         return false;
187       }
188     }
189   AliDebug(3,Form("output (x,y)=(%7.2f,%7.2f",x,y));
190   return true;
191 }
192
193 //_____________________________________________________________________________
194 void
195 AliMpSlatZonePadIterator::First()
196 {
197   //
198   // (re)Starts the iteration.
199   //
200   
201   fOffset = fArea.Dimensions()*(-1.0);
202   fIsDone = kFALSE;
203   SetPad(fCurrentPad,fArea.Position()+fOffset);
204   if (!fCurrentPad.IsValid()) Next();
205   AliDebug(3,Form("fOffset after Next=%7.2f,%7.2f",fOffset.X(),fOffset.Y()));
206   if ( !fCurrentPad.IsValid() ) 
207     {
208       // did not find any valid pad in there, bailing out.
209       fIsDone = kTRUE;
210       AliError(Form("Could not initiate iterator for slat %s. "
211                     " Please check the area you gave : %e,%e +- %e,%e",
212                     fkSlat->GetName(),
213                     fArea.Position().X(),
214                     fArea.Position().Y(),
215                     fArea.Dimensions().X(),
216                     fArea.Dimensions().Y()));
217       return;
218     }
219   else
220     {
221       // Reposition to pad center (both in x and y).
222       // Please note that repositionning y is valid here, and only here
223       // (i.e. do *not* do this in Next() for instance).
224       fOffset.Set(fCurrentPad.Position().X()+fkSlat->DX()-fArea.Position().X(),
225                   fCurrentPad.Position().Y()+fkSlat->DY()-fArea.Position().Y());
226       fIsDone = kFALSE;
227     }
228   AliDebug(3,Form("fOffset repositionned=%7.2f,%7.2f",fOffset.X(),fOffset.Y()));
229 }
230
231 //_____________________________________________________________________________
232 void
233 AliMpSlatZonePadIterator::Invalidate()
234 {
235   //
236   // Invalidate the iterator.
237   //
238   
239   fOffset = TVector2(DMAX,DMAX);
240   fCurrentPad = AliMpPad::Invalid();
241   fIsDone = kTRUE;
242 }
243
244 //_____________________________________________________________________________
245 Bool_t
246 AliMpSlatZonePadIterator::IsDone() const
247 {
248   //
249   // Whether the iteration is finished or not.
250   //
251   return fIsDone;
252 }
253
254 //_____________________________________________________________________________
255 void
256 AliMpSlatZonePadIterator::Next()
257 {
258   // This one is the meat of the class.
259   // We're iterating in x-direction mainly, starting from 
260   // lower-left of the iteration area, and proceeding right,
261   // until we reach right border, in which case we increment y
262   // and go back to leftmost position.
263   // Put otherwise, here's basically how it should work:
264   // try to do x+=xstep. If outside the area, get back to xmin
265   // and try y+=ystep. If outside of the window end-of-game.
266   // When new x,y known, get the corresponding pad.
267   // If same pad as before (should not happen if step sizes are
268   // well chosen) or not valid pad (might happen for e.g. rounded pcbs), 
269   // restart.
270   // End of iteration occurs when both x and y are outside the iteration
271   // window.
272   
273   if (IsDone()) return;
274
275   AliMpPad pad(fCurrentPad);
276   int n = 0;
277   Double_t x(fOffset.X());
278   Double_t y(fOffset.Y());
279
280   while ( ( pad == fCurrentPad || !pad.IsValid() ) && n<100 )
281   {
282     ++n;
283     if (GetNextPosition(x,y)==kFALSE) 
284     {
285       Invalidate();
286       return;
287     } 
288     SetPad(pad,fArea.Position()+TVector2(x,y));
289   }
290   fCurrentPad = pad;
291 }
292
293 //_____________________________________________________________________________
294 void
295 AliMpSlatZonePadIterator::SetPad(AliMpPad& pad, const TVector2& pos)
296 {
297   //
298   // Sets the current pad.
299   //
300   pad = fSlatSegmentation->PadByPosition(pos-fkSlat->Position(),kFALSE);
301   if ( pad.IsValid() )
302     {
303       // Reposition fOffset to pad center (only in x-direction).
304       fOffset.Set(pad.Position().X()+fkSlat->DX()-fArea.Position().X(),
305                   fOffset.Y());
306     }
307   else
308   {
309     AliDebug(3,Form("No pad at pos=%e,%e",pos.X(),pos.Y()));
310   }
311 }