1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
19 /// Maker/merger of contours. Can create contour from a set polygons or
20 /// merger a set of contours into a single one.
22 /// This is based on (one of the) algorithm found in
23 /// Diane L. Souvaine and Iliana Bjorling-Sachs,
24 /// Proceedings of the IEEE, Vol. 80, No. 9, September 1992, p. 1449
26 /// Note that besides the AliMUON prefix, nothing is really MUON specific
29 /// \author Laurent Aphecetche, Subatech
32 #include "AliMUONContourMaker.h"
34 #include "AliCodeTimer.h"
36 #include "AliMUONContour.h"
37 #include "AliMUONPointWithRef.h"
38 #include "AliMUONPolygon.h"
39 #include "AliMUONSegment.h"
40 #include "AliMUONSegmentTree.h"
41 #include "Riostream.h"
48 ClassImp(AliMUONContourMaker)
53 void PrintSegments(const TObjArray& array)
58 while ( ( s = static_cast<AliMUONSegment*>(next()) ) )
60 cout << Form("i=%d %s",i,s->AsString()) << endl;
66 //_____________________________________________________________________________
67 AliMUONContourMaker::AliMUONContourMaker()
69 /// Default constructor
73 //_____________________________________________________________________________
74 AliMUONContourMaker::~AliMUONContourMaker()
79 //_____________________________________________________________________________
81 AliMUONContourMaker::CreateContour(const TObjArray& polygons, const char* name) const
83 /// Create the contour of the polygon array
84 /// and get back the intermediate verticals and horizontal segments
85 /// both arrays are arrays of AliMUONSegment objects.
87 AliCodeTimerAuto("",0);
89 if ( polygons.IsEmpty() ) return 0x0; // protection against user error...
91 // Sanity check : insure that all polygons are oriented counter-clockwise
92 TIter next(&polygons);
94 while ( ( pol = static_cast<AliMUONPolygon*>(next()) ) )
96 if ( !pol->IsCounterClockwiseOriented() )
98 AliError(Form("Got a clockwise oriented polygon in CreateContour(%s). That's not OK !",name));
99 StdoutToAliError(polygons.Print());
104 AliMUONContour* contour(0x0);
106 if ( polygons.GetLast() == 0 )
108 AliCodeTimerAuto("Trivial case",1);
109 contour = new AliMUONContour(name);
110 pol = static_cast<AliMUONPolygon*>(polygons.First());
112 contour->AssertOrientation();
116 TObjArray polygonVerticalEdges; // arrray of AliMUONSegment objects
117 polygonVerticalEdges.SetOwner(kTRUE);
118 // get vertical edges of input polygons
119 GetVerticalEdges(polygons,polygonVerticalEdges);
121 // sort them in ascending x order
122 // if same x, insure that left edges are before right edges
123 // within same x, order by increasing bottommost y (see AliMUONSegment::Compare method)
124 polygonVerticalEdges.Sort();
126 if ( polygonVerticalEdges.GetLast()+1 < 2 )
129 AliFatal(Form("Got too few edges here for createContour %s",name));
132 // Find the vertical edges of the merged contour. This is the meat of the algorithm...
133 TObjArray contourVerticalEdges;
134 contourVerticalEdges.SetOwner(kTRUE);
135 Sweep(polygonVerticalEdges,contourVerticalEdges);
137 TObjArray horizontals;
138 horizontals.SetOwner(kTRUE);
139 VerticalToHorizontal(contourVerticalEdges,horizontals);
141 contour = FinalizeContour(contourVerticalEdges,horizontals);
143 if ( contour && name ) contour->SetName(name);
148 //_____________________________________________________________________________
150 AliMUONContourMaker::FinalizeContour(const TObjArray& verticals,
151 const TObjArray& horizontals) const
153 /// For a list of vertical and horizontal edges, we build the final
156 AliCodeTimerAuto("",0);
158 TObjArray all; // array of AliMUONSegment
159 TObjArray inorder; // array of AliMUONSegment
161 all.SetOwner(kFALSE);
162 inorder.SetOwner(kFALSE);
164 for ( Int_t i = 0; i <= verticals.GetLast(); ++i )
166 all.Add(verticals.UncheckedAt(i));
167 all.Add(horizontals.UncheckedAt(i));
170 TArrayI alreadyAdded(all.GetLast()+1);
171 alreadyAdded.Reset();
175 AliMUONContour* contour = new AliMUONContour;
179 while ( !all.IsEmpty() )
185 AliError("Total 1000 reached !!!!");
189 AliMUONSegment* si = static_cast<AliMUONSegment*>(all.UncheckedAt(i));
192 const AliMUONSegment* all0 = static_cast<const AliMUONSegment*>(all.First());
193 if ( i != 0 && AliMUONSegment::AreEqual(si->EndX(),all0->StartX()) && AliMUONSegment::AreEqual(si->EndY(),all0->StartY()) )
197 AliMUONPolygon polygon(inorder.GetLast()+2);
199 // we got a cycle. Add it to the contour
200 for ( Int_t j = 0; j <= inorder.GetLast(); ++j )
202 AliMUONSegment* s = static_cast<AliMUONSegment*>(inorder.UncheckedAt(j));
203 polygon.SetVertex(++n,s->StartX(),s->StartY());
211 contour->Add(polygon);
213 if ( ! all.IsEmpty() )
217 alreadyAdded.Set(all.GetLast()+1);
218 alreadyAdded.Reset();
223 for ( Int_t j = 0; j <= all.GetLast(); ++j)
225 if ( j != i && alreadyAdded[j] == 0 )
227 const AliMUONSegment* sj = static_cast<const AliMUONSegment*>(all.UncheckedAt(j));
228 if ( AliMUONSegment::AreEqual(si->EndX(),sj->StartX()) && AliMUONSegment::AreEqual(si->EndY(),sj->StartY()))
237 contour->AssertOrientation(kTRUE);
242 //_____________________________________________________________________________
244 AliMUONContourMaker::GetVerticalEdges(const TObjArray& polygons, TObjArray& polygonVerticalEdges) const
246 /// From an array of polygons, extract the list of vertical edges.
247 /// Output array polygonVerticalEdges should be empty before calling.
249 AliCodeTimerAuto("",0);
251 for ( Int_t i = 0; i <= polygons.GetLast(); ++i )
253 const AliMUONPolygon* g = static_cast<const AliMUONPolygon*>(polygons.UncheckedAt(i));
254 for ( Int_t j = 0; j < g->NumberOfVertices()-1; ++j )
256 if ( AliMUONSegment::AreEqual(g->X(j),g->X(j+1)) ) // segment is vertical
258 polygonVerticalEdges.Add(new AliMUONSegment(g->X(j),g->Y(j),g->X(j+1),g->Y(j+1)));
265 //_____________________________________________________________________________
267 AliMUONContourMaker::GetYPositions(const TObjArray& polygonVerticalEdges,
268 TArrayD& yPositions) const
270 /// Fill the array yPositions with the different y positions found in
271 /// polygonVerticalEdges
273 AliCodeTimerAuto("",0);
275 Double_t* y = new Double_t[polygonVerticalEdges.GetSize()*2];
278 for ( Int_t i = 0; i < polygonVerticalEdges.GetLast(); ++i )
280 AliMUONSegment* s = static_cast<AliMUONSegment*>(polygonVerticalEdges.UncheckedAt(i));
285 Int_t* ix = new Int_t[n+1];
287 TMath::Sort(n,y,ix,kFALSE);
294 for ( Int_t i = 0; i < n; ++i )
298 yPositions[u] = y[ix[i]];
311 //_____________________________________________________________________________
313 AliMUONContourMaker::MergeContour(const TObjArray& contours, const char* name) const
315 /// Merge all the polygons of all contours into a single contour
317 AliCodeTimerAuto("",0);
320 polygons.SetOwner(kTRUE);
322 TIter next(&contours);
323 AliMUONContour* contour;
324 while ( ( contour = static_cast<AliMUONContour*>(next()) ) )
326 const TObjArray* contourPolygons = contour->Polygons();
327 TIter nextPol(contourPolygons);
329 while ( ( pol = static_cast<AliMUONPolygon*>(nextPol()) ) )
331 polygons.Add(new AliMUONPolygon(*pol));
335 if ( polygons.IsEmpty() ) return 0x0;
337 contour = CreateContour(polygons,name);
342 //_____________________________________________________________________________
344 AliMUONContourMaker::SortPoints(const TObjArray& polygonVerticalEdges,
345 TObjArray& sortedPoints) const
347 /// Sort the point of the vertical edges in ascending order, first on ordinate,
348 /// then on abcissa, and put them in output vector sortedPoints.
349 /// Output array sortedPoints should be empty before calling this method.
351 AliCodeTimerAuto("",0);
353 for ( Int_t i = 0; i <= polygonVerticalEdges.GetLast(); ++i )
355 const AliMUONSegment* e = static_cast<const AliMUONSegment*>(polygonVerticalEdges.UncheckedAt(i));
356 sortedPoints.Add(new AliMUONPointWithRef(e->StartX(),e->StartY(),i));
357 sortedPoints.Add(new AliMUONPointWithRef(e->EndX(),e->EndY(),i));
358 // note that we keep track of the original edge, which is used
359 // later on to deduce orientation of horizontal edges.
365 //_____________________________________________________________________________
367 AliMUONContourMaker::Sweep(const TObjArray& polygonVerticalEdges,
368 TObjArray& contourVerticalEdges) const
370 /// This is the meat of the algorithm of the contour merging...
372 AliCodeTimerAuto("",0);
375 GetYPositions(polygonVerticalEdges,yPositions);
377 AliMUONSegmentTree segmentTree(yPositions);
379 for ( Int_t i = 0; i <= polygonVerticalEdges.GetLast(); ++i )
381 const AliMUONSegment* edge = static_cast<const AliMUONSegment*>(polygonVerticalEdges.UncheckedAt(i));
385 if ( edge->IsLeftEdge() )
387 segmentTree.Contribution(edge->Bottom(),edge->Top());
388 segmentTree.InsertInterval(edge->Bottom(),edge->Top());
392 segmentTree.DeleteInterval(edge->Bottom(),edge->Top());
393 segmentTree.Contribution(edge->Bottom(),edge->Top());
396 AliMUONSegment e1(*edge);
398 if ( i < polygonVerticalEdges.GetLast() )
400 const AliMUONSegment* next = static_cast<const AliMUONSegment*>(polygonVerticalEdges.UncheckedAt(i+1));
404 if ( ( edge->IsLeftEdge() != e1.IsLeftEdge() ) ||
405 ( !AliMUONSegment::AreEqual(edge->StartX(),e1.StartX() ) ) ||
406 ( i == polygonVerticalEdges.GetLast() ) )
408 const TObjArray& stack = segmentTree.Stack();
410 double x = edge->StartX();
412 for ( Int_t j = 0; j <= stack.GetLast(); ++j )
414 AliMUONSegment* sj = static_cast<AliMUONSegment*>(stack.UncheckedAt(j));
415 AliMUONSegment* s = new AliMUONSegment(x,sj->StartY(),x,sj->EndY());
423 if ( edge->IsLeftEdge() != s->IsLeftEdge() )
425 s->Set(x,sj->EndY(),x,sj->StartY());
427 contourVerticalEdges.Add(s);
429 segmentTree.ResetStack();
434 //_____________________________________________________________________________
436 AliMUONContourMaker::VerticalToHorizontal(const TObjArray& polygonVerticalEdges,
437 TObjArray& horizontalEdges) const
439 /// Deduce the set of horizontal edges from the vertical edges
440 /// Output array horizontalEdges should be empty before calling this method
442 AliCodeTimerAuto("",0);
444 TObjArray points; // array of AliMUONPointWithRef
445 points.SetOwner(kTRUE);
447 SortPoints(polygonVerticalEdges,points);
449 for ( Int_t k = 0; k < (points.GetLast()+1)/2; ++k )
451 const AliMUONPointWithRef* p1 = static_cast<AliMUONPointWithRef*>(points.UncheckedAt(k*2));
452 const AliMUONPointWithRef* p2 = static_cast<AliMUONPointWithRef*>(points.UncheckedAt(k*2+1));
454 const AliMUONSegment* refEdge = static_cast<const AliMUONSegment*>(polygonVerticalEdges.UncheckedAt(p1->Ref()));
456 // (p1,p2) is the horizontal edge.
457 // refEdge is used to deduce the orientation of (p1,p2)
459 if ( AliMUONSegment::AreEqual(p1->X(),refEdge->EndX()) && AliMUONSegment::AreEqual(p1->Y(),refEdge->EndY()) )
460 // if ( AreEqual(p1,refEdge->End()) )
462 horizontalEdges.Add(new AliMUONSegment(p1->X(),p1->Y(),p2->X(),p2->Y()));
466 horizontalEdges.Add(new AliMUONSegment(p2->X(),p2->Y(),p1->X(),p1->Y()));