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