Separating run-dependent mapping data from data, which are not
[u/mrichter/AliRoot.git] / MUON / AliMUONPainterContourMaker.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 "AliMUONPainterContourMaker.h"
19
20 #include "AliMUONPainterContour.h"
21 #include "AliMUONPainterHelper.h"
22 #include "AliMUONVCalibParam.h"
23 #include "AliMUONVDigit.h"
24 #include "AliMpConnection.h"
25 #include "AliMpConstants.h"
26 #include "AliMpDEManager.h"
27 #include "AliMpExMap.h"
28 #include "AliMpMotifMap.h"
29 #include "AliMpMotifPosition.h"
30 #include "AliMpMotifType.h"
31 #include "AliMpSector.h"
32 #include "AliMpSectorSegmentation.h"
33 #include "AliMpSegmentation.h"
34 #include "AliMpSlat.h"
35 #include "AliMpSlatSegmentation.h"
36 #include "AliMpStationType.h"
37 #include "AliMpVMotif.h"
38 #include "AliCodeTimer.h"
39 #include "AliLog.h"
40 #include <Riostream.h>
41 #include <TArrayI.h>
42 #include <TGeoMatrix.h>
43 #include <TLine.h>
44 #include <TMap.h>
45 #include <TMath.h>
46 #include <TMathBase.h>
47 #include <TObjArray.h>
48 #include <TPolyLine.h>
49 #include <cassert>
50 #include <float.h>
51
52 /// \class AliMUONPainterContourMaker
53 ///
54 /// A class to build painter contours. 
55 ///
56 /// The basics are to build one manu contour, and then to merge contours
57 /// to build higher order objects, like PCBS, DEs, etc...
58 ///
59 /// \author Laurent Aphecetche, Subatech
60
61 ///\cond CLASSIMP
62 ClassImp(AliMUONPainterContourMaker)
63 ClassImp(AliMUONPainterContourMaker::AliMUONNeighbour)
64 ///\endcond
65
66 //_____________________________________________________________________________
67 Int_t
68 AliMUONPainterContourMaker::AliMUONNeighbour::Compare(const TObject* obj) const
69 {
70   /// Compare two neighbours objects
71   
72   const AliMUONNeighbour* n = static_cast<const AliMUONNeighbour*>(obj);
73   
74   if ( Position().X() < n->Position().X() )
75   {
76     return -1;
77   }
78   else if ( Position().X() > n->Position().X() )
79   {
80     return 1;
81   }
82   else
83   {
84     // same X
85     if ( Position().Y() < n->Position().Y() )
86     {
87       return -1;
88     }
89     else if ( Position().Y() > n->Position().Y() )
90     {
91       return 1;
92     }
93   }
94   return 0;
95 }
96
97 //_____________________________________________________________________________
98 void
99 AliMUONPainterContourMaker::AliMUONNeighbour::Print(Option_t*) const
100 {
101   /// Printout
102   cout << Form("ID %10d DE %4d Manu %4d Channel %2d "
103                "(X,Y)=(%7.3f,%7.3f) L,R,T,B=%1d,%1d,%1d,%1d",
104                ID(),
105                AliMUONVDigit::DetElemId(ID()),
106                AliMUONVDigit::ManuId(ID()),
107                AliMUONVDigit::ManuChannel(ID()),
108                Position().X(),Position().Y(),
109                HasLeftNeighbour(),HasRightNeighbour(),
110                HasTopNeighbour(),HasBottomNeighbour())
111   << endl;
112 }
113
114 //_____________________________________________________________________________
115 AliMUONPainterContourMaker::AliMUONPainterContourMaker(AliMpExMap* globalTransformations)
116 : TObject(), 
117   fGlobalTransformations(globalTransformations),
118   fLocalManuContours(new TMap),
119   fContours(new TMap)
120 {
121     /// ctor
122     fContours->SetOwner(kTRUE);
123 }
124
125 //_____________________________________________________________________________
126 AliMUONPainterContourMaker::~AliMUONPainterContourMaker()
127 {
128   /// dtor
129   fLocalManuContours->DeleteAll();
130   delete fLocalManuContours;
131   fContours->DeleteAll();
132   delete fContours;
133 }
134
135 //_____________________________________________________________________________
136 void
137 AliMUONPainterContourMaker::Add(AliMUONPainterContour* contour)
138 {
139   /// Add a contour to our store of contours
140   fContours->Add(new TObjString(contour->GetName()),contour);
141 }
142
143 //_____________________________________________________________________________
144 void 
145 AliMUONPainterContourMaker::AddSegment(TObjArray& segments, Double_t x1, Double_t y1,
146                                        Double_t x2, Double_t y2, Int_t id) const
147 {
148   /// Add one segment defined by (x1,y1,x2,y2) to the array of segments
149   AliCodeTimerAuto("")
150   AliDebug(1,Form("AddSegment %7.3f,%7.3f -> %7.3f,%7.3f",x1,y1,x2,y2));
151   TLine* line = new TLine(x1,y1,x2,y2);
152   line->SetUniqueID(id);
153   segments.Add(line);
154 }
155
156 //_____________________________________________________________________________
157 Bool_t
158 AliMUONPainterContourMaker::HasLine(const TObjArray& segments,
159                                     const TLine& line) const
160 {
161   /// Check whether line is already part of segments array
162   
163   TIter next(&segments);
164   TLine* l;
165   
166   while ( ( l = static_cast<TLine*>(next()) ) )
167   {
168     if ( IsEqual(line,*l) ) return kTRUE;
169   }
170   
171   return kFALSE;
172 }
173
174 //_____________________________________________________________________________
175 void 
176 AliMUONPainterContourMaker::AddSegments(TObjArray& segments, 
177                                         const AliMUONPainterContour& contour) const
178
179 {
180   /// Add all the segments (that are not already there) 
181   /// of contour to the segments array
182   
183   AliCodeTimerAuto("")
184   
185   const TObjArray* pl = contour.AsPolyLines();
186
187   TIter next(pl);
188
189   Int_t n(0);
190   
191   TPolyLine* line;
192   
193   while ( ( line = static_cast<TPolyLine*>(next()) ) )
194   {
195     n += line->GetLastPoint();
196   }  
197   
198   AliDebug(1,Form("Adding %d groups (%d lines) from contour %s ",pl->GetLast()+1,n,contour.GetName()));
199
200   next.Reset();
201   
202   while ( ( line = static_cast<TPolyLine*>(next()) ) )    
203   {
204     AliDebug(1,"line=");
205 //    StdoutToAliDebug(1,line->Print(););
206     for ( Int_t i = 0; i < line->GetLastPoint(); ++i ) 
207     {
208       Double_t x1 = line->GetX()[i];
209       Double_t y1 = line->GetY()[i];
210       Double_t x2 = line->GetX()[i+1];
211       Double_t y2 = line->GetY()[i+1];
212       
213       TLine* l = new TLine(x1,y1,x2,y2);
214       
215       if ( !HasLine(segments,*l) )
216       {
217         segments.Add(l);      
218         AliDebug(1,Form("Adding line %s",LineAsString(*l).Data()));
219       }
220       else
221       {
222         AliDebug(1,Form("Line %s is already there",LineAsString(*l).Data()));
223       }      
224     }
225   }
226 }
227
228 //_____________________________________________________________________________
229 AliMUONPainterContour*
230 AliMUONPainterContourMaker::ConvertEdgePadsToContour(TObjArray& ePads, 
231                                                      const char* name) const
232 {
233   /// Convert an array of edge pads into a contour of a given name
234   
235   AliCodeTimerAuto("")
236   
237   ePads.Sort();
238   
239   AliDebug(1,Form("%d pads to convert:",ePads.GetEntries()));
240 //  StdoutToAliDebug(1,ePads.Print();)
241     
242   TObjArray segments;
243   segments.SetOwner(kTRUE);
244   
245   TIter nextPad(&ePads);
246   AliMUONNeighbour* ne;
247   
248   while ( ( ne = static_cast<AliMUONNeighbour*>(nextPad()) ) )
249   {
250     Int_t id = ne->ID();
251     
252     if ( ! ne->HasLeftNeighbour() )
253     {
254       AddSegment(segments,ne->LowerLeft().X(),ne->LowerLeft().Y(),
255                  ne->LowerLeft().X(),ne->UpperRight().Y(),id);
256     }
257     if ( ! ne->HasRightNeighbour() )
258     {
259       AddSegment(segments,ne->UpperRight().X(),ne->LowerLeft().Y(),
260                  ne->UpperRight().X(),ne->UpperRight().Y(),id);
261     }
262     if ( ! ne->HasTopNeighbour() )
263     {
264       AddSegment(segments,ne->LowerLeft().X(),ne->UpperRight().Y(),
265                  ne->UpperRight().X(),ne->UpperRight().Y(),id);
266     }
267     if ( ! ne->HasBottomNeighbour() )
268     {
269       AddSegment(segments,ne->LowerLeft().X(),ne->LowerLeft().Y(),
270                  ne->UpperRight().X(),ne->LowerLeft().Y(),id);
271     }    
272   }
273   
274   return ConvertSegmentsToContour(segments,name);
275 }
276
277 //_____________________________________________________________________________
278 void 
279 AliMUONPainterContourMaker::PrintLine(const TLine& line, const char* msg) const
280 {
281   /// Printout of a line
282   cout << Form("%10s %s",
283                msg,LineAsString(line).Data()) << endl;   
284 }
285
286 //_____________________________________________________________________________
287 TString 
288 AliMUONPainterContourMaker::LineAsString(const TLine& line, Bool_t slope) const
289 {
290   /// Return a string representation of the line
291   
292   TString rv(Form("%7.3f,%7.3f -> %7.3f,%7.3f",
293                   line.GetX1(),line.GetY1(),
294                   line.GetX2(),line.GetY2()));
295              
296   if ( slope ) 
297   {
298     if ( IsHorizontal(line) ) rv += " H";
299     else if ( IsVertical(line) ) rv += " V";
300     else rv += Form(" (slope %e)",Slope(line));
301   }
302   
303   return rv;
304 }
305
306 //_____________________________________________________________________________
307 void 
308 AliMUONPainterContourMaker::PrintSegments(const TObjArray& segments) const
309 {
310   /// Printout of segment arrays (debug)
311   
312   for ( Int_t i = 0; i <= segments.GetLast(); ++i )
313   {
314     TLine* l = static_cast<TLine*>(segments.UncheckedAt(i));
315     
316     cout << Form("***--- i %4d",i);
317     if ( l ) 
318     {
319       PrintLine(*l);
320     }
321     else
322     {
323       cout << " line is null ?" << endl;
324     }
325   }
326 }
327
328 //_____________________________________________________________________________
329 TLine* 
330 AliMUONPainterContourMaker::AddToLine(TPolyLine& line, TObjArray& segments, Int_t i) const
331 {
332   /// Add one segment (taken from position i in array) into polyline
333   
334   AliDebug(1,Form("i=%d",i));
335   TLine* l = static_cast<TLine*>(segments.UncheckedAt(i));
336   if (l)
337   {
338     line.SetNextPoint(l->GetX1(),l->GetY1());
339     line.SetNextPoint(l->GetX2(),l->GetY2());
340   }
341   else
342   {
343     AliError(Form("Did not find the line at i=%d",i));
344     PrintSegments(segments);
345   }
346   return l;
347 }
348
349 //_____________________________________________________________________________
350 Int_t 
351 AliMUONPainterContourMaker::FindPoint(Double_t x, Double_t y, 
352                                       TObjArray& segments) const
353 {
354   /// Find if point (x,y) is in segments array, and return
355   /// its index (=position within array)
356   
357   TIter next(&segments);
358   TLine* l;
359   
360   while ( ( l = static_cast<TLine*>(next()) ) )
361   {
362     if ( IsEqual(l->GetX1(),x) && IsEqual(l->GetY1(),y) )
363     {
364       return segments.IndexOf(l);
365     }
366   }
367   AliError(Form("Did not find point %7.3f %7.3f in those segments:",x,y));
368 //  StdoutToAliDebug(1,PrintSegments(segments););
369   return -1;
370 }
371
372 //_____________________________________________________________________________
373 AliMUONPainterContour*
374 AliMUONPainterContourMaker::ConvertSegmentsToContour(TObjArray& segments, 
375                                                      const char* name) const
376 {
377   /// Convert an array of segments into a contour
378   
379   AliDebug(1,"");
380   AliCodeTimerAuto("");
381   
382   AliMUONPainterContour* contour = new AliMUONPainterContour(name);
383
384   Int_t n(0); // this is a protection against infinite loop (used for debug only)
385   
386   while ( segments.GetLast() >= 0 && n < 100 ) 
387   {
388     TPolyLine lines;
389     TIter next(&segments);
390     TLine* l;
391     
392     while ( ( l = static_cast<TLine*>(next() ) ) )
393     {
394       TLine* inserted = InsertSegment(lines,*l);
395       if ( inserted ) 
396       {
397         segments.Remove(inserted);
398         next.Reset();
399       }
400       
401       // check for closure
402       if ( IsLineClosed(lines) ) 
403       {
404         AliDebug(1,"Line closed. Starting a new one");
405         break;
406       }
407     }
408     
409     TPolyLine* sl = Simplify(lines);
410     
411     contour->AdoptPolyLine(sl);
412     ++n;
413   }
414   
415   if ( segments.GetLast() >= 0 ) 
416   {
417     AliError("segment should be empty by now");
418 //    StdoutToAliError(PrintSegments(segments););
419   }
420   
421   return contour;
422 }
423
424 //_____________________________________________________________________________
425 Int_t 
426 AliMUONPainterContourMaker::FindPoint(const TPolyLine& lines, Double_t x, Double_t y) const
427 {
428   /// Return position of (x,y) within the polyline
429   
430   AliCodeTimerAuto("")
431   
432   for ( Int_t i = 0; i < lines.Size(); ++i ) 
433   {
434     if ( IsEqual(lines.GetX()[i],x) && IsEqual(lines.GetY()[i],y) ) 
435     {
436       return i;
437     }
438   }
439   return -1;
440 }
441
442 //_____________________________________________________________________________
443 void
444 AliMUONPainterContourMaker::CleanSegments(TObjArray& segments,
445                                           const TArrayI& toBeRemoved) const
446 {
447   /// Remove segments at indices stored in toBeRemoved array
448   for ( Int_t i = 0; i < toBeRemoved.GetSize(); ++i ) 
449   {
450     if ( toBeRemoved[i] )
451     {
452       segments.RemoveAt(i);
453     }
454   }
455   segments.Compress();
456 }
457
458 //_____________________________________________________________________________
459 Int_t
460 AliMUONPainterContourMaker::SplitSegments(TObjArray& segments) const
461 {
462   /// Split segments that have partial overlap 
463   
464   AliCodeTimerAuto("")
465   
466   TArrayI toBeRemoved(segments.GetLast()+1);
467   toBeRemoved.Reset(0);
468   Bool_t added(kFALSE);
469   
470   for ( Int_t i = 0; i <= segments.GetLast() && !added; ++i ) 
471   {
472     if ( toBeRemoved[i] ) continue;
473     
474     TLine* li = static_cast<TLine*>(segments.UncheckedAt(i));
475     
476     for ( Int_t j = i+1; j <= segments.GetLast() && !added; ++j ) 
477     {
478       if ( toBeRemoved[j] ) continue;
479       
480       TLine* lj = static_cast<TLine*>(segments.UncheckedAt(j));
481       
482       Int_t o = Overlap(*li,*lj);
483
484       if ( o ) 
485       {
486         toBeRemoved[i] = toBeRemoved[j] = 1;
487         
488         Double_t x[] = { li->GetX1(), lj->GetX1(), li->GetX2(), lj->GetX2() };
489         Double_t y[] = { li->GetY1(), lj->GetY1(), li->GetY2(), lj->GetY2() };
490         
491         Double_t xmin(FLT_MAX), ymin(FLT_MAX);
492         Double_t xmax(-FLT_MAX), ymax(-FLT_MAX);
493
494         for ( Int_t k = 0; k < 4; ++k )
495         {
496           xmin = TMath::Min(x[k],xmin);
497           ymin = TMath::Min(y[k],ymin);
498           xmax = TMath::Max(x[k],xmax);
499           ymax = TMath::Max(y[k],ymax);
500         }
501         
502         TLine fullLine(xmin,ymin,xmax,ymax);
503         
504         for ( Int_t i1 = 0; i1 < 4; ++i1 )
505         {
506           for ( Int_t j1 = i1+1; j1 < 4; ++j1 )
507           {
508             if ( TMath::Abs(i1-j1) != 2 ) 
509             {
510               TLine test(x[i1],y[i1],x[j1],y[j1]);
511
512               Bool_t isFullLine = IsEqual(test,fullLine);
513               
514               if ( !IsPoint(test) && !isFullLine ) 
515               {
516                 segments.Add(new TLine(test));
517                 added = kTRUE;
518               }              
519             }
520           }
521         }
522       }
523     }
524   }
525   
526   CleanSegments(segments,toBeRemoved);
527   
528   return added;
529 }
530
531 //_____________________________________________________________________________
532 Bool_t
533 AliMUONPainterContourMaker::ShouldBeRemoved(const TObjArray& contours,
534                                             Double_t x, Double_t y) const
535 {
536   /// Tells whether or not a point can be removed, because it lies
537   /// inside the global contour
538   
539   const Double_t kPrecision(AliMpConstants::LengthTolerance());
540   const Double_t kShiftX[] = { kPrecision,kPrecision,-kPrecision,-kPrecision };
541   const Double_t kShiftY[] = { kPrecision,-kPrecision,kPrecision,-kPrecision };
542   
543   TIter next(&contours);
544   AliMUONPainterContour* contour;
545
546   Int_t n(0);
547
548   while ( ( contour = static_cast<AliMUONPainterContour*>(next()) ) )
549   {
550     for ( Int_t i = 0; i < 4; ++i )
551     {
552       if ( contour->IsInside( x + kShiftX[i], y + kShiftY[i]) )
553       {
554         ++n;
555       }
556     }
557   }
558   
559   return (n>=4);
560 }
561
562 //_____________________________________________________________________________
563 Int_t
564 AliMUONPainterContourMaker::RemoveInsideSegments(const TObjArray& contours,
565                                                  TObjArray& segments) const
566 {
567   /// Remove segments that have 2 triple points
568
569   AliCodeTimerAuto("")
570   
571   TArrayI toBeRemoved(segments.GetLast()+1);
572   toBeRemoved.Reset(0);
573   
574   for ( Int_t i = 0; i <= segments.GetLast(); ++i ) 
575   {
576     TLine* line = static_cast<TLine*>(segments.UncheckedAt(i)); 
577     
578     Double_t x = (line->GetX1() + line->GetX2())/2.0;
579     Double_t y = (line->GetY1() + line->GetY2())/2.0;
580     
581     if ( ShouldBeRemoved(contours,x,y) )
582     {
583       toBeRemoved[i] = 1;
584     }
585   }
586     
587   Int_t before = segments.GetLast()+1;
588   
589   CleanSegments(segments,toBeRemoved);
590   
591   Int_t after = segments.GetLast()+1;
592   
593   AliDebug(1,Form("# of segments before = %d after = %d",before,after));  
594   
595   return after-before;
596 }
597
598 //_____________________________________________________________________________
599 AliMUONPainterContour* 
600 AliMUONPainterContourMaker::MergeContours(const TObjArray& contours,
601                                           const char* contourName) const
602 {
603   /// Merge an array of contours into a single contour, with a given name
604   
605   AliCodeTimerAuto("");
606   
607   AliDebug(1,Form("Merging %d contours into %s",contours.GetLast()+1,contourName));
608   
609   if ( contours.GetSize() == 0 ) return 0x0;
610   
611   TIter next(&contours);
612   AliMUONPainterContour* contour;
613   
614   TObjArray segments;
615   segments.SetOwner(kTRUE);
616   
617   while ( ( contour = static_cast<AliMUONPainterContour*>(next()) ) )
618   {
619     AddSegments(segments,*contour);
620   }
621   
622 //  AliDebug(1,"After AddSegments");
623 //  StdoutToAliDebug(1,PrintSegments(segments));
624   
625   while (SplitSegments(segments));
626
627 //  AliDebug(1,"After SplitSegments");
628 //  StdoutToAliDebug(1,PrintSegments(segments));
629
630 //  if (!SanityCheck(contours,segments))
631 //  {
632 //    return 0x0;
633 //  }
634
635   RemoveInsideSegments(contours,segments);
636   
637 //  if (!SanityCheck(contours,segments))
638 //  {
639 //    return 0x0;
640 //  }
641     
642 //  AliDebug(1,"After RemoveInsideSegments");
643 //  StdoutToAliDebug(1,PrintSegments(segments););
644     
645 //  if (!SanityCheck(contours,segments))
646 //  {
647 //    return 0x0;
648 //  }
649   
650   return ConvertSegmentsToContour(segments,contourName);
651 }
652
653 //_____________________________________________________________________________
654 TString
655 AliMUONPainterContourMaker::NameIt(const AliMpMotifPosition& motifPosition) const
656 {
657   /// Get the name of an AliMpMotifPosition
658   
659   AliMpVMotif* motif = motifPosition.GetMotif();
660   TString name(Form("%s",motif->GetID().Data()));
661   
662   for ( Int_t i = 0; i < motif->GetNofPadDimensions(); ++i )
663   {
664     TVector2 padDim = motif->GetPadDimensions(i);
665     name += Form("/%7.3f-%7.3f:",padDim.X(),padDim.Y());
666   }
667   return name;
668 }
669
670 //_____________________________________________________________________________
671 AliMUONPainterContour*
672 AliMUONPainterContourMaker::FindLocalManuContour(Int_t detElemId, Int_t manuId) const
673 {
674   /// Get a pre-computed manu contour (in local coordinates)
675   AliCodeTimerAuto("")
676   
677   AliMpMotifPosition* motifPos = FindMotifPosition(detElemId,manuId);
678   
679   TObject* o = fLocalManuContours->GetValue(NameIt(*motifPos));
680   
681   if (o) return static_cast<AliMUONPainterContour*>(o);
682   return 0x0;
683 }
684
685 //_____________________________________________________________________________
686 AliMpMotifPosition*
687 AliMUONPainterContourMaker::FindMotifPosition(Int_t detElemId, Int_t manuId) const
688 {
689   /// Find a given motifPosition object
690   
691   AliCodeTimerAuto("")
692   
693   const AliMpVSegmentation* vseg = AliMpSegmentation::Instance()->GetMpSegmentationByElectronics(detElemId,manuId);
694   if (!vseg)
695   {
696     AliFatal(Form("Could not find motif for DE %d manu %d",detElemId,manuId));
697   }
698   
699   AliMp::StationType stationType = AliMpDEManager::GetStationType(detElemId);
700   
701   if ( stationType == AliMp::kStation345 ) 
702   {
703     const AliMpSlatSegmentation* seg = static_cast<const AliMpSlatSegmentation*>(vseg);
704     const AliMpSlat* slat = seg->Slat();
705     return slat->FindMotifPosition(manuId);
706   }
707   else
708   {
709     const AliMpSectorSegmentation* seg = static_cast<const AliMpSectorSegmentation*>(vseg);
710     const AliMpSector* sector = seg->GetSector();
711     return sector->GetMotifMap()->FindMotifPosition(manuId);
712   }
713   return 0x0;
714 }
715
716 //_____________________________________________________________________________
717 AliMUONPainterContour* 
718 AliMUONPainterContourMaker::GenerateManuContour(const char* name, 
719                                                 Int_t detElemId, Int_t manuId,
720                                                 AliMUONAttPainter viewType) const
721 {  
722   /// Generate the contour for a given manu
723   
724   AliDebug(3,Form("DE %04d ManuID %04d Name %s",detElemId,manuId,name));
725   
726   AliCodeTimerAuto("")
727   
728   AliMpMotifPosition* motifPosition = FindMotifPosition(detElemId,manuId);
729   AliMpVMotif* motif = motifPosition->GetMotif();
730   
731   AliMUONPainterContour* contour = FindLocalManuContour(detElemId,manuId); 
732   // do we already have the local contour for that manu ?
733   
734   // no : build it
735   if  (!contour)
736   {
737     AliCodeTimerAuto("Generation of local contour");
738     TObjArray ePads;
739     ePads.SetOwner(kTRUE);
740     AliMpMotifType* motifType = motif->GetMotifType();
741     AliDebug(3,Form("motifType %s",motifType->GetID().Data()));
742     
743 //    for ( Int_t i = 0; i <= motifType->GetNofPads(); ++i ) 
744     for ( Int_t i = 0; i <= AliMpConstants::ManuNofChannels(); ++i ) 
745     {
746 //      AliMpConnection* connection = motifType->FindConnectionByPadNum(i);
747       AliMpConnection* connection = motifType->FindConnectionByGassiNum(i);
748
749       AliDebug(3,Form("connection i =%d",i));
750       
751       if ( connection ) 
752       {
753         AliMpIntPair indices = connection->LocalIndices();
754         Bool_t left(kTRUE);
755         Bool_t right(kTRUE);
756         Bool_t top(kTRUE);
757         Bool_t bottom(kTRUE);
758         
759         if ( !motifType->FindConnectionByLocalIndices(indices+AliMpIntPair(1,0)) )
760         {
761           right = kFALSE;
762         }
763         if ( !motifType->FindConnectionByLocalIndices(indices+AliMpIntPair(-1,0)) )
764         {
765           left = kFALSE;
766         }
767         if ( !motifType->FindConnectionByLocalIndices(indices+AliMpIntPair(0,1)) )
768         {
769           top = kFALSE;
770         }
771         if ( !motifType->FindConnectionByLocalIndices(indices+AliMpIntPair(0,-1)) )
772         {
773           bottom = kFALSE;
774         }
775         
776         AliDebug(3,Form("indices=(%3d,%3d) L %d R %d T %d B %d",
777                         indices.GetFirst(),indices.GetSecond(),
778                         left,right,top,bottom));
779         
780         TVector2 position = motif->PadPositionLocal(indices);
781         TVector2 dimensions = motif->GetPadDimensions(indices);
782
783         if ( !left  || !right || !top  || !bottom )
784         {
785           // the pad is on the edge
786           Int_t id = AliMUONVDigit::BuildUniqueID(detElemId,manuId,
787                                                   connection->GetGassiNum(),0);
788           ePads.AddLast(new AliMUONNeighbour(id,position,dimensions,left,right,top,bottom));
789         }
790       }
791     }
792     
793     contour = ConvertEdgePadsToContour(ePads,NameIt(*motifPosition));
794     
795     AliDebug(1,Form("localContour:"));
796 //    StdoutToAliDebug(1,contour->Print("full"));
797     // register the local contour
798     fLocalManuContours->Add(new TObjString(contour->GetName()),contour);
799   }
800   
801   AliMUONPainterContour* globalContour = static_cast<AliMUONPainterContour*>(contour->Clone(name));
802   
803   // once we have the local contour, convert it to global
804   
805   TVector2 pos(motifPosition->Position());
806
807   if ( AliMpDEManager::GetStationType(detElemId) == AliMp::kStation345 ) 
808   {
809     const AliMpSlat* slat = AliMUONPainterHelper::Instance()->GetSlat(detElemId,manuId);
810     pos -= slat->Position();
811   }
812   globalContour->Offset(pos);
813   TGeoHMatrix* matrix = static_cast<TGeoHMatrix*>(fGlobalTransformations->GetValue(detElemId));
814   globalContour->Transform(*matrix);
815
816   if ( viewType.IsBackView() )
817   {
818     AliWarning("Got a back view : will rotate ! This has not been really tested. Please do so now !");
819     TGeoRotation rot;
820     rot.RotateZ(180);
821     globalContour->Transform(rot);
822   }
823   
824   return globalContour;
825 }
826
827 //_____________________________________________________________________________
828 AliMUONPainterContour*
829 AliMUONPainterContourMaker::GetContour(const char* name) const
830 {
831   /// Get contour by name
832   
833   TObject* o = fContours->GetValue(name);
834   return static_cast<AliMUONPainterContour*>(o);
835 }
836
837 //_____________________________________________________________________________
838 Bool_t
839 AliMUONPainterContourMaker::HasContour(const char* name) const
840 {
841   /// Whether contour named "name" exists
842   TObject* o = fContours->GetValue(name);
843   if (o) return kTRUE;
844   return kFALSE;
845 }
846
847 //_____________________________________________________________________________
848 TLine* 
849 AliMUONPainterContourMaker::InsertSegment(TPolyLine& lines, TLine& l) const
850 {
851   /// Insert line into polyline, at the correct position
852   
853   AliCodeTimerAuto("")
854 //  AliDebug(2,Form("Trying to insert %7.3f,%7.3f -> %7.3f,%7.3f from "
855 //                  "(DE,manu,ch)=(%d,%d,%d) into",
856 //                  l.GetX1(),l.GetY1(),l.GetX2(),l.GetY2(),
857 //                  AliMUONVDigit::DetElemId(l.GetUniqueID()),
858 //                  AliMUONVDigit::ManuId(l.GetUniqueID()),
859 //                  AliMUONVDigit::ManuChannel(l.GetUniqueID())));
860   
861   if ( lines.Size()==0 ) 
862   {
863 //    AliDebug(2,"Starting line");
864 //    
865     lines.SetNextPoint(l.GetX1(),l.GetY1());
866     lines.SetNextPoint(l.GetX2(),l.GetY2());
867     return &l;
868   }
869   
870   Int_t i1 = FindPoint(lines,l.GetX1(),l.GetY1());
871   Int_t i2 = FindPoint(lines,l.GetX2(),l.GetY2());
872   
873   if ( i1 < 0 && i2 < 0 ) 
874   {
875 //    AliDebug(2,"Not yet");
876     return 0x0;
877   }
878   
879   if ( i1 >= 0 && i2 >= 0 )
880   {
881     if ( i1==0 )
882     {
883       lines.SetNextPoint(l.GetX1(),l.GetY1());
884     }
885     else if ( i2==0 )
886     {
887       lines.SetNextPoint(l.GetX2(),l.GetY2());
888     }
889     else
890     {
891       AliError("Segment already there but does not correspond to ending the polyline !");
892       AliError(Form("Segment is %7.3f,%7.3f -> %7.3f,%7.3f and existing points are : ",
893                     l.GetX1(),l.GetY1(),l.GetX2(),l.GetY2()));
894                       
895       for ( Int_t i = 0; i < lines.Size(); ++i ) 
896       {
897         AliError(Form("Point %2d X %7.3f Y %7.3f",i,lines.GetX()[i],lines.GetY()[i]));
898       }
899 //      TObject* o(0x0);
900 //      o->Print(); // to crash and throw gdb...
901     }
902     return &l;
903   }
904   
905   Double_t x = (i1>=0) ? l.GetX2() : l.GetX1();
906   Double_t y = (i1>=0) ? l.GetY2() : l.GetY1();
907   
908   Int_t iref = ( i1 >= 0 ? i1 : i2 ) ;
909   
910   Bool_t firstPoint = ( iref == 0 );
911   
912   if ( firstPoint ) 
913   {
914     // must insert segment before
915     lines.SetPolyLine(lines.Size()+1);
916 //    AliDebug(2,Form("Inserting %7.3f,%7.3f",x,y));
917     for ( Int_t i = lines.Size()-1; i > 0; --i ) 
918     {
919       lines.SetPoint(i,lines.GetX()[i-1],lines.GetY()[i-1]);
920     }
921     lines.SetPoint(0,x,y);
922   }
923   else
924   {
925 //    AliDebug(2,Form("Appending %7.3f,%7.3f",x,y));
926     lines.SetNextPoint(x,y);
927   }
928   
929   return &l;
930 }
931
932 //_____________________________________________________________________________
933 Bool_t 
934 AliMUONPainterContourMaker::IsEqual(Double_t x, Double_t y) const
935 {
936   /// Whether x==y
937   
938   if ( TMath::Abs(x-y) < AliMpConstants::LengthTolerance() ) return kTRUE;
939   else return kFALSE;      
940 }
941
942 //_____________________________________________________________________________
943 Bool_t 
944 AliMUONPainterContourMaker::IsEqual(const TLine& line1,
945                                     const TLine& line2) const
946 {
947   /// Whether line1 == line2
948   
949   Bool_t check1 =  
950     IsEqual(line1.GetX1(),line2.GetX1()) && 
951     IsEqual(line1.GetY1(),line2.GetY1()) &&
952     IsEqual(line1.GetX2(),line2.GetX2()) &&
953     IsEqual(line1.GetY2(),line2.GetY2());
954   
955   Bool_t check2 =  
956     IsEqual(line1.GetX1(),line2.GetX2()) && 
957     IsEqual(line1.GetY1(),line2.GetY2()) &&
958     IsEqual(line1.GetX2(),line2.GetX1()) &&
959     IsEqual(line1.GetY2(),line2.GetY1());
960   
961   return (check1 || check2);
962 }
963
964 //_____________________________________________________________________________
965 Double_t 
966 AliMUONPainterContourMaker::Slope(const TLine& line) const
967 {
968   /// Get the slope of line
969   
970   Double_t x = TMath::Abs(line.GetX2() - line.GetX1());
971   
972   if ( x  < AliMpConstants::LengthTolerance() ) return FLT_MAX;
973   
974   return TMath::Abs(line.GetY2() - line.GetY1())/x;
975 }
976
977 //_____________________________________________________________________________
978 Bool_t 
979 AliMUONPainterContourMaker::IsPoint(const TLine& line) const
980 {
981   /// Whether the line is a point (sic ;-) )
982   return 
983   IsEqual(line.GetX1(),line.GetX2()) && 
984   IsEqual(line.GetY1(),line.GetY2());
985 }
986
987 //_____________________________________________________________________________
988 TLine
989 AliMUONPainterContourMaker::Shift(const TLine& line, Double_t x, Double_t y) const
990 {
991   /// Shift the line by a given offset
992   
993   return TLine(line.GetX1()-x,line.GetY1()-y,line.GetX2()-x,line.GetY2()-y);
994 }
995
996 //_____________________________________________________________________________
997 Bool_t
998 AliMUONPainterContourMaker::SameDirection(const TLine& line1, const TLine& line2) const
999 {
1000   /// Whether both lines have the same direction.
1001   
1002   TLine l1 = Shift(line1,line1.GetX1(),line1.GetY1());
1003   TLine l2 = Shift(line2,line2.GetX1(),line2.GetY1());
1004   
1005   Double_t v = l1.GetX2()*l2.GetX2() + l1.GetY2()*l2.GetY2();
1006   
1007   return v > 0 ;
1008 }
1009
1010 //_____________________________________________________________________________
1011 void 
1012 AliMUONPainterContourMaker::Swap(TLine& line) const
1013 {
1014   /// Swap both points of the line
1015   
1016   Double_t x = line.GetX1();
1017   Double_t y = line.GetY1();
1018   
1019   line.SetX1(line.GetX2());
1020   line.SetY1(line.GetY2());
1021   line.SetX2(x);
1022   line.SetY2(y);
1023 }
1024
1025 //_____________________________________________________________________________
1026 Int_t
1027 AliMUONPainterContourMaker::IsInRange(Double_t x, Double_t a, Double_t b,
1028                                       Bool_t strict) const
1029 {
1030   /// Whether w is in [a,b] (if strict=kFALSE) or in ]a,b[ (if strict=kTRUE)
1031   
1032   if ( a > b ) 
1033   {
1034     Double_t tmp(b);
1035     b = a;
1036     a = tmp;
1037   }
1038   
1039   Bool_t rv(kFALSE);
1040   
1041   if ( strict )  
1042   {
1043     rv = ( x > a && x < b );
1044   }
1045   else
1046   {
1047     rv = ( x >= a && x <= b);
1048   }
1049
1050   AliDebug(4,Form("x = %7.3f a = %7.3f b = %7.3f strict = %d IsInRange = %d",x,a,b,strict,rv));
1051   
1052   return rv;
1053 }
1054
1055 //_____________________________________________________________________________
1056 Int_t 
1057 AliMUONPainterContourMaker::IsInLine(const TLine& line,
1058                                      Double_t x,
1059                                      Double_t y,
1060                                      Bool_t strict) const
1061 {
1062   /// Check whether point (x,y) is belonging to the line segment
1063   /// by computing the distance point to line
1064   /// line1 must not be a single point.
1065   /// Returns the number of *coordinates* that matches, for a point
1066   /// that lies on line (if point is not on the line, returns 0 always).
1067   /// For instance, if (x,y) is on the line (and strict=kFALSE), 
1068   /// it will return 1 if x *or* y corresponds to line.GetX1() or X2 or Y1 or Y2,
1069   /// and 2 if the pair (x,y) corresponds to one of the line points.
1070   
1071   Double_t x1 = line.GetX1();
1072   Double_t x2 = line.GetX2();
1073   Double_t y1 = line.GetY1();
1074   Double_t y2 = line.GetY2();
1075   
1076   Double_t distance = TMath::Abs( (x2-x1)*(y1-y) - (x1-x)*(y2-y1) );
1077   
1078   distance /= TMath::Sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
1079   
1080   Bool_t online = ( distance < AliMpConstants::LengthTolerance() ) ;
1081   
1082   Int_t rv(0);
1083   
1084   if (online)
1085   {
1086     // point is on the line, 
1087     // check in addition that it's within the segment
1088     
1089     rv = IsInRange(x,x1,x2,strict) + IsInRange(y,y1,y2,strict);
1090   }
1091   else
1092   {
1093     rv = 0;
1094   }
1095   
1096   AliDebug(4,Form("Point (%7.3f,%7.3f) isinline=%d in line %s",
1097                   x,y,rv,LineAsString(line).Data()));
1098   
1099   return rv;
1100 }
1101
1102 //_____________________________________________________________________________
1103 Int_t 
1104 AliMUONPainterContourMaker::IsInside(const TLine& line1,
1105                                      const TLine& line2,
1106                                      Bool_t useEndPoints) const
1107 {
1108   /// Check whether one or both points of line2 are within line1.
1109   /// Both line1 and line2 must have the same slope 
1110   /// and the same direction
1111
1112   if (!IsEqual(Slope(line1),Slope(line2))) return 0;
1113   
1114   TLine l2(line2);
1115   
1116   if (!SameDirection(line1,line2)) 
1117   {
1118     Swap(l2);
1119   }
1120       
1121   Int_t rv = 
1122     IsInLine(line1,l2.GetX1(),l2.GetY1(),!useEndPoints) +
1123     IsInLine(line1,l2.GetX2(),l2.GetY2(),!useEndPoints);
1124   
1125   assert(rv<=4);
1126   
1127   return rv;
1128 }
1129
1130 //_____________________________________________________________________________
1131 Bool_t 
1132 AliMUONPainterContourMaker::IsInside(const TObjArray& segments, 
1133                                      const TLine& line) const
1134 {
1135   /// Whether the segment (line) is contained inside the contour defined
1136   /// by all the segments (i.e. is it on the boundary or not)
1137   /// Basic (and dirty) implementation only working with horizontal and vertical lines.
1138   /// I know there must be a better way to do it, but it took me way too long
1139   /// to get this stuff working, so I'm giving up on the optimisation/cleaning,
1140   /// at least for now...
1141   /// If you'd like to clean this (while keeping it working in all cases), be
1142   /// my guest and do it ;-) )
1143   
1144   Int_t p1 = CountPoint(segments,line.GetX1(),line.GetY1());
1145   Int_t p2 = CountPoint(segments,line.GetX2(),line.GetY2());
1146   
1147   Bool_t triplet = ( p1 >= 3 || p2 >= 3 );
1148   
1149   AliDebug(4,Form("IsInside(segments,%s) triplet=%d",
1150                   LineAsString(line).Data(),triplet));
1151   
1152   if (!triplet) return kFALSE;
1153     
1154   Bool_t top(kFALSE), bottom(kFALSE), left(kFALSE), right(kFALSE);
1155   
1156   Bool_t vertical(IsVertical(line));
1157   Bool_t horizontal(IsHorizontal(line));
1158   
1159   if (!vertical && !horizontal ) 
1160   {
1161     AliFatal("Only working with horizontal and vertical lines");
1162   }
1163   
1164   for ( Int_t i = 0; i <= segments.GetLast(); ++i ) 
1165   {
1166     TLine* l = static_cast<TLine*>(segments.UncheckedAt(i));
1167     
1168     if ( IsEqual(*l,line) ) continue;
1169     
1170     if ( vertical && IsVertical(*l) )
1171     {
1172       TLine tmpLine(l->GetX1(),line.GetY1(),
1173                     l->GetX1(),line.GetY2());
1174       
1175       AliDebug(4,Form("i=%2d VV\nIsInside(l=%s,%s)=%d\nIsInside(%s,l=%s)=%d",
1176                       i,
1177                       LineAsString(*l).Data(),LineAsString(tmpLine).Data(),
1178                       IsInside(*l,tmpLine,kTRUE),
1179                       LineAsString(tmpLine).Data(),LineAsString(*l).Data(),
1180                       IsInside(tmpLine,*l,kTRUE)));
1181                       
1182       if ( IsInside(*l,tmpLine,kTRUE) == 4 || IsInside(tmpLine,*l,kTRUE) == 4 ) 
1183       {
1184         if ( l->GetX1() > line.GetX1() ) 
1185         {
1186           right = kTRUE;
1187         }
1188         else
1189         {
1190           left = kTRUE;
1191         }
1192       }
1193     }
1194     
1195     if ( vertical && IsHorizontal(*l) )
1196     {
1197       if ( !IsEqual(l->GetY1(),line.GetX1()) && 
1198            !IsEqual(l->GetY1(),line.GetY2()) &&
1199            IsInLine(*l,line.GetX1(),l->GetY1(),kFALSE)==2 )
1200         {
1201         if ( line.GetY2() < l->GetY1() ) 
1202         {
1203           top = kTRUE;
1204         }
1205         else if ( line.GetY2() > l->GetY1() )
1206         {
1207           bottom = kTRUE;
1208         }
1209       }
1210     }
1211     
1212     if ( horizontal && IsHorizontal(*l) )
1213     {
1214       TLine tmpLine(line.GetX1(),l->GetY1(),
1215                     line.GetX2(),l->GetY1());
1216       
1217       AliDebug(4,Form("i=%2d HH\nIsInside(%s,%s)=%d\nIsInside(%s,%s)=%d",
1218                       i,
1219                       LineAsString(*l).Data(),LineAsString(tmpLine).Data(),
1220                       IsInside(*l,tmpLine),
1221                       LineAsString(tmpLine).Data(),LineAsString(*l).Data(),
1222                       IsInside(tmpLine,*l)));
1223       
1224       if ( IsInside(*l,tmpLine) == 4 || IsInside(tmpLine,*l) == 4 ) 
1225       {
1226         if ( l->GetY1() > line.GetY1() ) 
1227         {
1228           top = kTRUE;
1229         }
1230         else
1231         {
1232           bottom = kTRUE;
1233         }
1234       }
1235     }
1236     
1237     if ( horizontal && IsVertical(*l) )
1238     {
1239       if ( !IsEqual(l->GetX1(),line.GetX1()) && 
1240            !IsEqual(l->GetX1(),line.GetX2()) &&
1241            IsInLine(*l,l->GetX1(),line.GetY1(),kFALSE)==2 )
1242         {
1243         if ( line.GetX2() < l->GetX1() ) 
1244         {
1245           right = kTRUE;
1246         }
1247         else if ( line.GetX2() > l->GetX1() )
1248         {
1249           left = kTRUE;
1250         }
1251       }
1252     }
1253     
1254   }
1255   
1256   Bool_t rv(kFALSE);
1257
1258   AliDebug(3,Form("%s %s R %d L %d T %d B% d IsInside %d",
1259                   IsVertical(line) ? 
1260                   "Vertical  " : 
1261                   "Horizontal",
1262                   LineAsString(line,kFALSE).Data(),right,left,top,bottom,rv));
1263
1264   if ( vertical ) 
1265   {
1266     rv = (right && left) && ( top || bottom );
1267   }
1268   
1269   if ( horizontal ) 
1270   {
1271     rv = (top && bottom) && ( right || left );
1272   }
1273   
1274   return rv;
1275 }
1276
1277 //_____________________________________________________________________________
1278 Bool_t 
1279 AliMUONPainterContourMaker::IsHorizontal(const TLine& line) const
1280 {
1281   /// whether line is horizontal
1282   
1283   static Double_t l2 = AliMpConstants::LengthTolerance()*AliMpConstants::LengthTolerance();
1284   
1285   return ( Slope(line) < l2 );
1286 }
1287
1288 //_____________________________________________________________________________
1289 Bool_t 
1290 AliMUONPainterContourMaker::IsVertical(const TLine& line) const
1291 {
1292   /// whether line is vertical
1293   
1294   return ( TMath::Abs(Slope(line)) == FLT_MAX );
1295 }
1296
1297 //_____________________________________________________________________________
1298 Int_t
1299 AliMUONPainterContourMaker::Overlap(const TLine& line1,
1300                                     const TLine& line2) const
1301 {
1302   /// Whether line1 and line2 overlap
1303   
1304   Int_t rv(0);
1305   
1306   if ( IsEqual(line1,line2) ) 
1307   {
1308     // First things first. If both lines are the same one, 
1309     // they for sure overlap ;-)
1310     rv = 4;
1311   }
1312   else
1313   {
1314     rv = IsInside(line1,line2) + IsInside(line2,line1);
1315   }
1316   
1317   AliDebug(3,Form("%s and %s : overlap=%d",
1318                   LineAsString(line1).Data(),
1319                   LineAsString(line2).Data(),
1320                   rv));
1321   
1322   return rv;
1323 }
1324
1325 //_____________________________________________________________________________
1326 Bool_t 
1327 AliMUONPainterContourMaker::IsLineClosed(const TPolyLine& line) const
1328 {
1329   /// check if polyline is already closed (i.e. last point = first point)
1330   
1331   Double_t* x = line.GetX();
1332   Double_t* y = line.GetY();
1333   
1334   if ( IsEqual(x[line.GetLastPoint()],x[0]) &&
1335        IsEqual(y[line.GetLastPoint()],y[0]) )
1336   {
1337     return kTRUE;
1338   }
1339   else
1340   {
1341     return kFALSE;
1342   }
1343 }  
1344
1345 //_____________________________________________________________________________
1346 void 
1347 AliMUONPainterContourMaker::Local2Global(Int_t detElemId, 
1348                                          Double_t xl, Double_t yl, Double_t zl,
1349                                          Double_t& xg, Double_t& yg, Double_t& zg) const
1350 {
1351   /// Convert local coordinates to global ones
1352   TGeoHMatrix* matrix = static_cast<TGeoHMatrix*>(fGlobalTransformations->GetValue(detElemId));
1353   Double_t pl[3] = { xl, yl, zl };
1354   Double_t pg[3] = { 0., 0., 0. };
1355   matrix->LocalToMaster(pl, pg);
1356   xg = pg[0];
1357   yg = pg[1];
1358   zg = pg[2];
1359 }
1360
1361 //_____________________________________________________________________________
1362 void
1363 AliMUONPainterContourMaker::Print(Option_t* opt) const
1364 {
1365   /// Printout
1366   
1367   cout << "Local Contours" << endl;
1368   
1369   TIter next(fLocalManuContours);
1370   TObjString* key;
1371   
1372   while ( ( key = static_cast<TObjString*>(next()) ) )
1373   {
1374     cout << key->String().Data() << endl;
1375     AliMUONPainterContour* contour = static_cast<AliMUONPainterContour*>(fLocalManuContours->GetValue(key));
1376     contour->Print(opt);
1377   }
1378
1379   cout << "Global Contours" << endl;
1380   
1381   TIter nextC(fContours);
1382   
1383   while ( ( key = static_cast<TObjString*>(nextC()) ) )
1384   {
1385     AliMUONPainterContour* contour = static_cast<AliMUONPainterContour*>(fContours->GetValue(key));
1386     contour->Print(opt);
1387   }
1388 }
1389
1390 //_____________________________________________________________________________
1391 Int_t
1392 AliMUONPainterContourMaker::CountPoint(const TObjArray& segments, 
1393                                        Double_t x, Double_t y) const
1394 {
1395   /// Count the number of times the point (x,y) appears in the segment array
1396   
1397   Int_t n(0);
1398   
1399   for ( Int_t i = 0; i <= segments.GetLast(); ++i ) 
1400   {
1401     TLine* line = static_cast<TLine*>(segments.UncheckedAt(i));
1402       
1403     if ( IsEqual(x,line->GetX1()) &&
1404          IsEqual(y,line->GetY1()) )
1405     {
1406       ++n;
1407     }
1408   
1409     if ( IsEqual(x,line->GetX2()) &&
1410          IsEqual(y,line->GetY2()) )
1411     {
1412       ++n;
1413     }
1414   }
1415   
1416   return n;
1417 }
1418
1419 //_____________________________________________________________________________
1420 Bool_t
1421 AliMUONPainterContourMaker::SanityCheck(const TObjArray& contours,
1422                                         const TObjArray& segments, Bool_t check) const
1423 {
1424   /// (debug) check 
1425   
1426   Bool_t ok(kTRUE);
1427
1428   // cross-check that we have no more complete duplicates
1429   // and that we have no orphan point
1430
1431   Double_t xmin(FLT_MAX), xmax(-FLT_MAX);
1432   Double_t ymin(FLT_MAX), ymax(-FLT_MAX);
1433   
1434   for ( Int_t i = 0; i <= segments.GetLast(); ++i ) 
1435   {
1436     TLine* li = static_cast<TLine*>(segments.UncheckedAt(i));
1437   
1438     if (!IsHorizontal(*li) && !IsVertical(*li))
1439     {
1440       AliError("Got an oblique line !");
1441       return kFALSE;
1442     }
1443     
1444     xmin = TMath::Min(xmin,li->GetX1());
1445     xmin = TMath::Min(xmin,li->GetX2());
1446
1447     xmax = TMath::Max(xmax,li->GetX1());
1448     xmax = TMath::Max(xmax,li->GetX2());
1449
1450     ymin = TMath::Min(ymin,li->GetY1());
1451     ymin = TMath::Min(ymin,li->GetY2());
1452     
1453     ymax = TMath::Max(ymax,li->GetY1());
1454     ymax = TMath::Max(ymax,li->GetY2());
1455     
1456   }
1457   
1458   AliDebug(1,Form("xmin=%7.3f ymin=%7.3f xmax=%7.3f ymax=%7.3f",
1459                   xmin,ymin,xmax,ymax));
1460   
1461   for ( Int_t i = 0; i <= segments.GetLast(); ++i ) 
1462   {
1463     TLine* li = static_cast<TLine*>(segments.UncheckedAt(i));
1464
1465     if (!check) 
1466     {
1467       for ( Int_t j = 0; j <= segments.GetLast(); ++j ) 
1468       {
1469         TLine* lj = static_cast<TLine*>(segments.UncheckedAt(j));
1470
1471         if ( i != j && IsEqual(*li,*lj) )
1472         {
1473           ok = kFALSE;
1474           PrintLine(*li);
1475           PrintLine(*lj);
1476           AliFatal("");
1477         }      
1478       }
1479     }
1480     
1481
1482     Int_t rv(0);
1483     
1484     Double_t x = (li->GetX1()+li->GetX2())/2.0;
1485     Double_t y = (li->GetY1()+li->GetY2())/2.0;
1486     
1487     if ( ShouldBeRemoved(contours,x,y) ) rv = 1;
1488     
1489     AliDebug(1,Form("Line %4d %7.3f,%7.3f -> %7.3f,%7.3f [ %d ]",
1490                     i,
1491                     li->GetX1(),li->GetY1(),
1492                     li->GetX2(),li->GetY2(),
1493                     rv));
1494   }
1495   
1496   return kTRUE;
1497 }
1498
1499 //_____________________________________________________________________________
1500 TPolyLine*
1501 AliMUONPainterContourMaker::Simplify(const TPolyLine& lines) const
1502 {
1503   /// try to simplify the polyline, by minimizing the number of points
1504
1505   if ( lines.Size() < 3 ) 
1506   {
1507     AliError("Cannot simplify lines with less that 3 points !");
1508     return 0x0;
1509   }
1510   
1511   AliCodeTimerAuto("")
1512   
1513 //  cout << "Before simplify" << endl;
1514 //  
1515 //  for ( Int_t i = 0; i < lines.Size(); ++i ) 
1516 //  {
1517 //    cout << Form("Point %3d %7.3f %7.3f",i,lines.GetX()[i],lines.GetY()[i]) << endl;
1518 //  }
1519   
1520   TPolyLine* l = new TPolyLine;
1521
1522   Double_t* x = lines.GetX();
1523   Double_t* y = lines.GetY();
1524
1525   l->SetNextPoint(x[0],y[0]);
1526
1527   Bool_t verticalCurrent = IsEqual(x[1],x[0]);
1528   Bool_t horizontalCurrent = IsEqual(y[1],y[0]);
1529
1530   Int_t i(2);
1531
1532   while ( i < lines.Size() )
1533   {
1534     Bool_t vertical = IsEqual(x[i],x[i-1]);
1535     Bool_t horizontal = IsEqual(y[i],y[i-1]);
1536     
1537 //    cout << Form("i %3d %7.3f %7.3f vert %d horiz %d (current vert %d horiz %d)",
1538 //                 i,x[i],y[i],vertical,horizontal,verticalCurrent,horizontalCurrent)
1539 //      << endl;
1540     
1541     if ( ( vertical != verticalCurrent ) || 
1542          ( horizontal != horizontalCurrent ) )
1543     {
1544 //      cout << Form("Changing direction : adding point %7.3f %7.3f",x[i-1],y[i-1]) << endl;
1545       l->SetNextPoint(x[i-1],y[i-1]);
1546       verticalCurrent = vertical;
1547       horizontalCurrent = horizontal;
1548     }
1549     ++i;
1550   }
1551   
1552   l->SetNextPoint(l->GetX()[0],l->GetY()[0]);
1553   
1554 //  cout << "After simplify" << endl;
1555 //  
1556 //  for ( Int_t i = 0; i < l->Size(); ++i ) 
1557 //  {
1558 //    cout << Form("Point %3d %7.3f %7.3f",i,l->GetX()[i],l->GetY()[i]) << endl;
1559 //  }
1560   
1561   return l;
1562 }
1563
1564 //_____________________________________________________________________________
1565 Int_t
1566 AliMUONPainterContourMaker::Size() const
1567 {
1568   /// Number of contours we have already
1569   
1570   return fContours->GetSize();
1571 }
1572