f70f507e301573a2653bbc57552d035c9c296a5c
[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     name += Form("/%7.3f-%7.3f:",motif->GetPadDimensionX(i),motif->GetPadDimensionY(i));
663   }
664   return name;
665 }
666
667 //_____________________________________________________________________________
668 AliMUONPainterContour*
669 AliMUONPainterContourMaker::FindLocalManuContour(Int_t detElemId, Int_t manuId) const
670 {
671   /// Get a pre-computed manu contour (in local coordinates)
672   AliCodeTimerAuto("")
673   
674   AliMpMotifPosition* motifPos = FindMotifPosition(detElemId,manuId);
675   
676   TObject* o = fLocalManuContours->GetValue(NameIt(*motifPos));
677   
678   if (o) return static_cast<AliMUONPainterContour*>(o);
679   return 0x0;
680 }
681
682 //_____________________________________________________________________________
683 AliMpMotifPosition*
684 AliMUONPainterContourMaker::FindMotifPosition(Int_t detElemId, Int_t manuId) const
685 {
686   /// Find a given motifPosition object
687   
688   AliCodeTimerAuto("")
689   
690   AliMp::StationType stationType = AliMpDEManager::GetStationType(detElemId);
691   
692   if ( stationType == AliMp::kStation345 ) 
693   {
694     const AliMpSlat* kSlat 
695       = AliMpSegmentation::Instance()->GetSlatByElectronics(detElemId,manuId);
696     if ( ! kSlat ) {
697       AliFatal(Form("Could not find motif for DE %d manu %d",detElemId,manuId));
698     }
699     return kSlat->FindMotifPosition(manuId);
700   }
701   else
702   {
703     const AliMpSector* kSector 
704       = AliMpSegmentation::Instance()->GetSectorByElectronics(detElemId,manuId);
705     if ( ! kSector ) {
706       AliFatal(Form("Could not find motif for DE %d manu %d",detElemId,manuId));
707     }
708     return kSector->GetMotifMap()->FindMotifPosition(manuId);
709   }
710   return 0x0;
711 }
712
713 //_____________________________________________________________________________
714 AliMUONPainterContour* 
715 AliMUONPainterContourMaker::GenerateManuContour(const char* name, 
716                                                 Int_t detElemId, Int_t manuId,
717                                                 AliMUONAttPainter viewType) const
718 {  
719   /// Generate the contour for a given manu
720   
721   AliDebug(3,Form("DE %04d ManuID %04d Name %s",detElemId,manuId,name));
722   
723   AliCodeTimerAuto("")
724   
725   AliMpMotifPosition* motifPosition = FindMotifPosition(detElemId,manuId);
726   AliMpVMotif* motif = motifPosition->GetMotif();
727   
728   AliMUONPainterContour* contour = FindLocalManuContour(detElemId,manuId); 
729   // do we already have the local contour for that manu ?
730   
731   // no : build it
732   if  (!contour)
733   {
734     AliCodeTimerAuto("Generation of local contour");
735     TObjArray ePads;
736     ePads.SetOwner(kTRUE);
737     AliMpMotifType* motifType = motif->GetMotifType();
738     AliDebug(3,Form("motifType %s",motifType->GetID().Data()));
739     
740 //    for ( Int_t i = 0; i <= motifType->GetNofPads(); ++i ) 
741     for ( Int_t i = 0; i <= AliMpConstants::ManuNofChannels(); ++i ) 
742     {
743 //      AliMpConnection* connection = motifType->FindConnectionByPadNum(i);
744       AliMpConnection* connection = motifType->FindConnectionByGassiNum(i);
745
746       AliDebug(3,Form("connection i =%d",i));
747       
748       if ( connection ) 
749       {
750         Int_t ix = connection->GetLocalIx();
751         Int_t iy = connection->GetLocalIy();
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(ix+1, iy) )
758         {
759           right = kFALSE;
760         }
761         if ( ! motifType->FindConnectionByLocalIndices(ix-1, iy) )
762         {
763           left = kFALSE;
764         }
765         if ( ! motifType->FindConnectionByLocalIndices(ix, iy+1) )
766         {
767           top = kFALSE;
768         }
769         if ( ! motifType->FindConnectionByLocalIndices(ix, iy-1) )
770         {
771           bottom = kFALSE;
772         }
773         
774         AliDebug(3,Form("indices=(%3d,%3d) L %d R %d T %d B %d",
775                         ix,iy, left,right,top,bottom));
776         
777         Double_t posx, posy;
778         motif->PadPositionLocal(ix, iy, posx, posy);
779         
780         Double_t dx, dy;
781         motif->GetPadDimensionsByIndices(ix, iy, dx, dy);
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->GetManuChannel(),0);
788           ePads.AddLast(new AliMUONNeighbour(id,TVector2(posx, posy),TVector2(dx, dy),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->GetPositionX(), motifPosition->GetPositionY());
806
807   if ( AliMpDEManager::GetStationType(detElemId) == AliMp::kStation345 ) 
808   {
809     const AliMpSlat* slat = AliMUONPainterHelper::Instance()->GetSlat(detElemId,manuId);
810     pos -= TVector2(slat->GetPositionX(),slat->GetPositionY()) ;
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