|
BWAPI
|
00001 // Copyright (c) 2005, 2006 Fernando Luis Cacciola Carballal. All rights reserved. 00002 // 00003 // This file is part of CGAL (www.cgal.org); you may redistribute it under 00004 // the terms of the Q Public License version 1.0. 00005 // See the file LICENSE.QPL distributed with CGAL. 00006 // 00007 // Licensees holding a valid commercial license may use this file in 00008 // accordance with the commercial license agreement provided with the software. 00009 // 00010 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00011 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00012 // 00013 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h $ 00014 // $Id: Straight_skeleton_builder_2_impl.h 43611 2008-06-15 16:21:29Z spion $ 00015 // 00016 // Author(s) : Fernando Cacciola <fernando_cacciola@ciudad.com.ar> 00017 // 00018 #ifndef CGAL_STRAIGHT_SKELETON_BUILDER_2_IMPL_H 00019 #define CGAL_STRAIGHT_SKELETON_BUILDER_2_IMPL_H 1 00020 00021 #include <boost/bind.hpp> 00022 #include <boost/utility.hpp> 00023 #include <boost/graph/adjacency_matrix.hpp> 00024 #include <CGAL/Unique_hash_map.h> 00025 00026 #include <CGAL/Real_timer.h> 00027 00028 #if defined(BOOST_MSVC) 00029 # pragma warning(push) 00030 # pragma warning(disable:4355) // complaint about using 'this' to 00031 #endif // initialize a member 00032 00033 CGAL_BEGIN_NAMESPACE 00034 00035 00036 template<class Gt, class Ss, class V> 00037 Straight_skeleton_builder_2<Gt,Ss,V>::Straight_skeleton_builder_2 ( boost::optional<FT> aMaxTime, Traits const& aTraits, Visitor const& aVisitor ) 00038 : 00039 mTraits(aTraits) 00040 ,mVisitor(aVisitor) 00041 ,mEventCompare(this) 00042 ,mVertexID(0) 00043 ,mEdgeID(0) 00044 ,mFaceID(0) 00045 ,mEventID(0) 00046 ,mStepID(0) 00047 ,mMaxTime(aMaxTime) 00048 ,mPQ(mEventCompare) 00049 ,mSSkel( new SSkel() ) 00050 { 00051 } 00052 00053 template<class Gt, class Ss, class V> 00054 typename Straight_skeleton_builder_2<Gt,Ss,V>::Halfedge_handle 00055 Straight_skeleton_builder_2<Gt,Ss,V>::validate( Halfedge_handle aH ) const 00056 { 00057 if ( !handle_assigned(aH) ) 00058 throw std::runtime_error("Incomplete straight skeleton"); 00059 return aH ; 00060 } 00061 00062 template<class Gt, class Ss, class V> 00063 typename Straight_skeleton_builder_2<Gt,Ss,V>::Vertex_handle 00064 Straight_skeleton_builder_2<Gt,Ss,V>::validate( Vertex_handle aH ) const 00065 { 00066 if ( !handle_assigned(aH) ) 00067 throw std::runtime_error("Incomplete straight skeleton"); 00068 return aH ; 00069 } 00070 00071 template<class Gt, class Ss, class V> 00072 void Straight_skeleton_builder_2<Gt,Ss,V>::InsertEventInPQ( EventPtr aEvent ) 00073 { 00074 mPQ.push(aEvent); 00075 CGAL_STSKEL_BUILDER_TRACE(4, "Enque: " << *aEvent); 00076 } 00077 00078 template<class Gt, class Ss, class V> 00079 typename Straight_skeleton_builder_2<Gt,Ss,V>::EventPtr 00080 Straight_skeleton_builder_2<Gt,Ss,V>::PopEventFromPQ() 00081 { 00082 EventPtr rR = mPQ.top(); mPQ.pop(); 00083 return rR ; 00084 } 00085 00086 // Tests whether there is an edge event between the 3 contour edges defining nodes 'aLnode' and 'aRNode'. 00087 // If such event exits and is not in the past, it's returned. Otherwise the result is null 00088 // 00089 template<class Gt, class Ss, class V> 00090 typename Straight_skeleton_builder_2<Gt,Ss,V>::EventPtr 00091 Straight_skeleton_builder_2<Gt,Ss,V>::FindEdgeEvent( Vertex_handle aLNode, Vertex_handle aRNode ) 00092 { 00093 EventPtr rResult ; 00094 00095 Triedge lTriedge = GetVertexTriedge(aLNode) & GetVertexTriedge(aRNode) ; 00096 00097 if ( lTriedge.is_valid() ) 00098 { 00099 Trisegment_2_ptr lTrisegment = CreateTrisegment(lTriedge,aLNode,aRNode); 00100 00101 if ( ExistEvent(lTrisegment) ) 00102 { 00103 Comparison_result lLNodeD = CompareEvents(lTrisegment,aLNode) ; 00104 Comparison_result lRNodeD = CompareEvents(lTrisegment,aRNode) ; 00105 00106 if ( lLNodeD != SMALLER && lRNodeD != SMALLER ) 00107 { 00108 rResult = EventPtr( new EdgeEvent( lTriedge, lTrisegment, aLNode, aRNode ) ) ; 00109 00110 mVisitor.on_edge_event_created(aLNode, aRNode) ; 00111 00112 CGAL_STSKEL_DEBUG_CODE( SetEventTimeAndPoint(*rResult) ); 00113 } 00114 else 00115 { 00116 CGAL_STSKEL_BUILDER_TRACE(4, "Edge event: " << lTriedge << " is in the past. Compared to L=" << lLNodeD << " to R=" << lRNodeD ) ; 00117 } 00118 } 00119 } 00120 return rResult ; 00121 } 00122 00123 00124 template<class Gt, class Ss, class V> 00125 typename Straight_skeleton_builder_2<Gt,Ss,V>::EventPtr 00126 Straight_skeleton_builder_2<Gt,Ss,V>::IsPseudoSplitEvent( EventPtr const& aEvent, Vertex_handle_pair aOpp, Site const& aSite ) 00127 { 00128 EventPtr rPseudoSplitEvent ; 00129 00130 if ( aSite != INSIDE ) 00131 { 00132 SplitEvent& lEvent = dynamic_cast<SplitEvent&>(*aEvent) ; 00133 00134 Triedge const& lEventTriedge = lEvent.triedge(); 00135 Trisegment_2_ptr const& lEventTrisegment = lEvent.trisegment(); 00136 Vertex_handle lSeedN = lEvent.seed0(); 00137 00138 Vertex_handle lOppL = aOpp.first ; 00139 Vertex_handle lOppR = aOpp.second ; 00140 00141 if ( aSite == AT_SOURCE ) 00142 { 00143 Halfedge_handle lOppPrevBorder = GetVertexTriedge(lOppL).e0() ; 00144 00145 if ( lEventTriedge.e0() != lOppPrevBorder && lEventTriedge.e1() != lOppPrevBorder ) 00146 { 00147 rPseudoSplitEvent = EventPtr( new PseudoSplitEvent(lEventTriedge,lEventTrisegment,lOppL,lSeedN,true) ) ; 00148 00149 CGAL_STSKEL_BUILDER_TRACE(1,"Pseudo-split-event found against N" << lOppL->id() ) ; 00150 00151 mVisitor.on_pseudo_split_event_created(lOppL,lSeedN) ; 00152 } 00153 } 00154 else // aSite == AT_TARGET 00155 { 00156 Vertex_handle lOppNextN = GetNextInLAV(lOppR) ; 00157 00158 Halfedge_handle lOppNextBorder = GetVertexTriedge(lOppNextN).e0() ; 00159 00160 if ( lEventTriedge.e0() != lOppNextBorder && lEventTriedge.e1() != lOppNextBorder ) 00161 { 00162 rPseudoSplitEvent = EventPtr( new PseudoSplitEvent(lEventTriedge, lEventTrisegment, lSeedN, lOppR,false) ) ; 00163 00164 CGAL_STSKEL_BUILDER_TRACE(1,"Pseudo-split-event found against N" << lOppR->id() ) ; 00165 00166 mVisitor.on_pseudo_split_event_created(lSeedN,lOppR) ; 00167 } 00168 } 00169 } 00170 00171 if ( rPseudoSplitEvent ) 00172 rPseudoSplitEvent->SetTimeAndPoint(aEvent->time(),aEvent->point()); 00173 00174 return rPseudoSplitEvent ; 00175 } 00176 00177 // Tests whether there is a split event between the contour edges (aReflexLBorder,aReflexRBorder,aOppositeBorder). 00178 // If such event exits and is not in the past, it's returned. Otherwise the result is null 00179 // 'aReflexLBorder' and 'aReflexRBorder' are consecutive contour edges which 'aNode' as the vertex. 00180 // 'aOppositeBorder' is some other edge in the polygon which, if the event exists, is split by the reflex wavefront. 00181 // 00182 // NOTE: 'aNode' can be a skeleton node (an interior split event produced by a previous vertex event). In that case, 00183 // the 'reflex borders' are not consecutive in the input polygon but they are in the corresponding offset polygon that 00184 // contains aNode as a vertex. 00185 // 00186 template<class Gt, class Ss, class V> 00187 void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvent( Vertex_handle aNode, Triedge const& aTriedge ) 00188 { 00189 if ( IsOppositeEdgeFacingTheSplitSeed(aNode,aTriedge.e2()) ) 00190 { 00191 Trisegment_2_ptr lTrisegment = CreateTrisegment(aTriedge,aNode); 00192 00193 if ( lTrisegment->collinearity() != TRISEGMENT_COLLINEARITY_02 && ExistEvent(lTrisegment) ) 00194 { 00195 if ( CompareEvents(lTrisegment,aNode) != SMALLER ) 00196 { 00197 EventPtr lEvent = EventPtr( new SplitEvent (aTriedge,lTrisegment,aNode) ) ; 00198 00199 mVisitor.on_split_event_created(aNode) ; 00200 00201 CGAL_STSKEL_DEBUG_CODE( SetEventTimeAndPoint(*lEvent) ) ; 00202 00203 AddSplitEvent(aNode,lEvent); 00204 } 00205 } 00206 } 00207 } 00208 00209 // Tests the reflex wavefront emerging from 'aNode' against the other contour edges in search for split events. 00210 template<class Gt, class Ss, class V> 00211 void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvents( Vertex_handle aNode ) 00212 { 00213 // lLBorder and lRBorder are the consecutive contour edges forming the reflex wavefront. 00214 Triedge const& lTriedge = GetVertexTriedge(aNode); 00215 00216 Halfedge_handle lLBorder = lTriedge.e0(); 00217 Halfedge_handle lRBorder = lTriedge.e1(); 00218 00219 CGAL_STSKEL_BUILDER_TRACE(3 00220 ,"Finding SplitEvent for N" << aNode->id() 00221 << " LBorder: E" << lLBorder->id() << " RBorder: E" << lRBorder->id() 00222 ); 00223 00224 for ( Halfedge_handle_vector_iterator i = mContourHalfedges.begin(); i != mContourHalfedges.end(); ++ i ) 00225 { 00226 Halfedge_handle lOpposite = *i ; 00227 00228 if ( lOpposite != lLBorder && lOpposite != lRBorder ) 00229 CollectSplitEvent(aNode, Triedge(lLBorder, lRBorder, lOpposite) ) ; 00230 } 00231 } 00232 00233 00234 // Finds and enques all the new potential events produced by the vertex wavefront emerging from 'aNode' (which can be a reflex wavefront). 00235 // This new events are simply stored in the priority queue, not processed. 00236 template<class Gt, class Ss, class V> 00237 void Straight_skeleton_builder_2<Gt,Ss,V>::CollectNewEvents( Vertex_handle aNode ) 00238 { 00239 // A Straight Skeleton is the trace of the 'grassfire propagation' that corresponds to the inward move of all the vertices 00240 // of a polygon along their angular bisectors. 00241 // Since vertices are the common endpoints of contour edges, the propagation corresponds to contour edges moving inward, 00242 // shrinking and expanding as neccesasry to keep the vertices along the angular bisectors. 00243 // At each instant in time the current location of vertices (and edges) describe the current 'Offset polygon' 00244 // (with at time zero corresponds to the input polygon). 00245 // 00246 // An 'edge wavefront' is a moving contour edge. 00247 // A 'vertex wavefront' is the wavefront of two consecutive edge wavefronts (sharing a moving vertex). 00248 // 00249 // An 'Event' is the coallision of 2 wavefronts. 00250 // Each event changes the topology of the shrinking polygon; that is, at the event, the current polygon differs from the 00251 // inmediately previous polygon in the number of vertices. 00252 // 00253 // If 2 vertex wavefronts sharing a common edge collide, the event is called an edge event. At the time of the event, the current 00254 // polygon doex not have the common edge anynmore, and the two vertices become one. This new 'skeleton' vertex generates a new 00255 // vertex wavefront which can further collide with other wavefronts, producing for instance, more edge events. 00256 // 00257 // If a refex vertex wavefront collide with an edge wavefront, the event is called a split event. At the time of the event, the current 00258 // polygon is split in two unconnected polygons, each one containing a portion of the edge hit and split by the reflex wavefront. 00259 // 00260 // If 2 reflex wavefronts collide each other, the event is called a vertex event. At the time of the event, the current polygon 00261 // is split in two unconnected polygons. Each one contains a different combination of the colliding reflex edges. That is, if the 00262 // wavefront (edgea,edgeb) collides with (edgec,edged), the two resulting polygons will contain (edgea,edgec) and (edgeb,edged). 00263 // Furthermore, one of the new vertices can be a reflex vertex generating a reflex wavefront which can further produce more split or 00264 // vertex events (or edge events of course) 00265 // 00266 // Each vertex wavefront (reflex or not) results in one and only one event from a set of possible events. 00267 // It can result in a edge event against the vertex wavefronts emerging from the adjacent vertices (in the current polygon, not 00268 // in the input polygon); or it can result in a split event (or vertex event) against any other wavefront in the rest of 00269 // current polygon. 00270 00271 00272 // Adjacent vertices in the current polygon containing aNode (called LAV) 00273 Vertex_handle lPrev = GetPrevInLAV(aNode) ; 00274 Vertex_handle lNext = GetNextInLAV(aNode) ; 00275 00276 CGAL_STSKEL_BUILDER_TRACE 00277 ( 2 00278 , "Collecting new events generated by N" << aNode->id() << " at " << aNode->point() << " (Prev: N" << lPrev->id() << " Next: N" 00279 << lNext->id() << ")" 00280 ) ; 00281 00282 if ( IsReflex(aNode) ) 00283 CollectSplitEvents(aNode) ; 00284 00285 EventPtr lLEdgeEvent = FindEdgeEvent( lPrev , aNode ) ; 00286 EventPtr lREdgeEvent = FindEdgeEvent( aNode , lNext ) ; 00287 00288 bool lAcceptL = !!lLEdgeEvent ; 00289 bool lAcceptR = !!lREdgeEvent ; 00290 00291 if ( lAcceptL ) 00292 InsertEventInPQ(lLEdgeEvent); 00293 00294 if ( lAcceptR ) 00295 InsertEventInPQ(lREdgeEvent); 00296 } 00297 00298 // Handles the special case of two simultaneous edge events, that is, two edges 00299 // collapsing along the line/point were they meet at the same time. 00300 // This ocurrs when the bisector emerging from vertex 'aA' is defined by the same pair of 00301 // contour edges as the bisector emerging from vertex 'aB' (but in opposite order). 00302 // 00303 template<class Gt, class Ss, class V> 00304 void Straight_skeleton_builder_2<Gt,Ss,V>::HandleSimultaneousEdgeEvent( Vertex_handle aA, Vertex_handle aB ) 00305 { 00306 CGAL_STSKEL_BUILDER_TRACE ( 2, "Handling simultaneous EdgeEvent between N" << aA ->id() << " and N" << aB ->id() ) ; 00307 00308 mVisitor.on_anihiliation_event_processed(aA,aB) ; 00309 00310 Halfedge_handle lOA = aA->primary_bisector() ; 00311 Halfedge_handle lOB = aB->primary_bisector() ; 00312 Halfedge_handle lIA = lOA->opposite(); 00313 Halfedge_handle lIB = lOB->opposite(); 00314 00315 Vertex_handle lOAV = lOA->vertex() ; 00316 Vertex_handle lIAV = lIA->vertex() ; 00317 Vertex_handle lOBV = lOB->vertex() ; 00318 Vertex_handle lIBV = lIB->vertex() ; 00319 00320 CGAL_STSKEL_BUILDER_TRACE ( 2 00321 , "OA: B" << lOA->id() << '\n' 00322 << "IA: B" << lIA->id() << '\n' 00323 << "OB: B" << lOB->id() << '\n' 00324 << "IB: B" << lIB->id() 00325 ) ; 00326 00327 SetIsProcessed(aA) ; 00328 SetIsProcessed(aB) ; 00329 mGLAV.remove(aA); 00330 mGLAV.remove(aB); 00331 00332 CGAL_STSKEL_BUILDER_TRACE ( 3, 'N' << aA->id() << " processed\nN" << aB->id() << " processed" ) ; 00333 00334 Halfedge_handle lOA_Prev = lOA->prev() ; 00335 Halfedge_handle lIA_Next = lIA->next() ; 00336 00337 Halfedge_handle lOB_Prev = lOB->prev() ; 00338 Halfedge_handle lIB_Next = lIB->next() ; 00339 00340 CGAL_STSKEL_BUILDER_TRACE ( 2 00341 , "OA_Prev: B" << lOA_Prev->id() << '\n' 00342 << "IA_Next: B" << lIA_Next->id() << '\n' 00343 << "OB_Prev: B" << lOB_Prev->id() << '\n' 00344 << "IB_Next: B" << lIB_Next->id() 00345 ) ; 00346 00347 CrossLinkFwd(lOB, lIA_Next ); 00348 CrossLinkFwd(lOA_Prev, lIB ); 00349 00350 Link(lOB,aA); 00351 00352 CGAL_STSKEL_BUILDER_TRACE ( 1, "B" << lOA->id() << " and B" << lIA->id() << " erased." ) ; 00353 mDanglingBisectors.push_back(lOA); 00354 00355 // 00356 // The code above corrects the links for vertices aA/aB to the erased halfedges lOA and lIA. 00357 // However, any of these vertices (aA/aB) maybe one of the twin vertices of a split event. 00358 // If that's the case, the erased halfedge maybe be linked to a 'couple' of those vertices. 00359 // This situation is corrected below: 00360 00361 00362 if ( !lOAV->has_infinite_time() && lOAV != aA && lOAV != aB ) 00363 { 00364 Link(lOAV,lIB); 00365 00366 CGAL_STSKEL_BUILDER_TRACE ( 1, "N" << lOAV->id() << " has B" << lOA->id() 00367 << " as it's halfedge. Replacing it with B" << lIB->id() 00368 ) ; 00369 } 00370 if ( !lIAV->has_infinite_time() && lIAV != aA && lIAV != aB ) 00371 { 00372 Link(lIAV,lOB); 00373 00374 CGAL_STSKEL_BUILDER_TRACE ( 1, "N" << lIAV->id() << " has B" << lIA->id() 00375 << " as it's halfedge. Replacing it with B" << lOB->id() 00376 ) ; 00377 } 00378 00379 CGAL_STSKEL_BUILDER_TRACE ( 2, "N" << aA->id() << " halfedge: B" << aA->halfedge()->id() ) ; 00380 CGAL_STSKEL_BUILDER_TRACE ( 2, "N" << aB->id() << " halfedge: B" << aB->halfedge()->id() ) ; 00381 00382 SetBisectorSlope(aA,aB); 00383 00384 CGAL_assertion( aA->primary_bisector() == lIB ) ; 00385 00386 CGAL_STSKEL_BUILDER_TRACE ( 1, "Wavefront: E" << lIB->defining_contour_edge()->id() << " and E" << lIB->opposite()->defining_contour_edge()->id() << " anhiliated each other." ) ; 00387 00388 if ( lOAV->has_infinite_time() ) 00389 { 00390 CGAL_STSKEL_BUILDER_TRACE ( 2, "Ficticius N" << lOAV->id() << " erased." ) ; 00391 EraseNode(lOAV); 00392 } 00393 00394 if ( lOBV->has_infinite_time() ) 00395 { 00396 CGAL_STSKEL_BUILDER_TRACE ( 2, "Ficticius N" << lOBV->id() << " erased." ) ; 00397 EraseNode(lOBV); 00398 } 00399 } 00400 00401 // Returns true if the skeleton edges 'aA' and 'aB' are defined by the same pair of contour edges (but possibly in reverse order) 00402 // 00403 template<class Gt, class Ss, class V> 00404 bool Straight_skeleton_builder_2<Gt,Ss,V>::AreBisectorsCoincident ( Halfedge_const_handle aA, Halfedge_const_handle aB ) const 00405 { 00406 CGAL_STSKEL_BUILDER_TRACE ( 3, "Testing for simultaneous EdgeEvents between B" << aA->id() << " and B" << aB->id() ) ; 00407 00408 Halfedge_const_handle lA_LBorder = aA->defining_contour_edge(); 00409 Halfedge_const_handle lA_RBorder = aA->opposite()->defining_contour_edge(); 00410 Halfedge_const_handle lB_LBorder = aB->defining_contour_edge(); 00411 Halfedge_const_handle lB_RBorder = aB->opposite()->defining_contour_edge(); 00412 00413 return ( lA_LBorder == lB_LBorder && lA_RBorder == lB_RBorder ) 00414 || ( lA_LBorder == lB_RBorder && lA_RBorder == lB_LBorder ) ; 00415 } 00416 00417 template<class Gt, class Ss, class V> 00418 void Straight_skeleton_builder_2<Gt,Ss,V>::UpdatePQ( Vertex_handle aNode ) 00419 { 00420 Vertex_handle lPrev = GetPrevInLAV(aNode) ; 00421 Vertex_handle lNext = GetNextInLAV(aNode) ; 00422 00423 CGAL_STSKEL_BUILDER_TRACE ( 3, "Updating PQ for N" << aNode->id() << " Prev N" << lPrev->id() << " Next N" << lNext->id() ) ; 00424 00425 Halfedge_handle lOBisector_P = lPrev->primary_bisector() ; 00426 Halfedge_handle lOBisector_C = aNode->primary_bisector() ; 00427 Halfedge_handle lOBisector_N = lNext->primary_bisector() ; 00428 00429 if ( AreBisectorsCoincident(lOBisector_C,lOBisector_P) ) 00430 HandleSimultaneousEdgeEvent( aNode, lPrev ) ; 00431 else 00432 if ( AreBisectorsCoincident(lOBisector_C,lOBisector_N) ) 00433 HandleSimultaneousEdgeEvent( aNode, lNext ) ; 00434 else 00435 CollectNewEvents(aNode); 00436 } 00437 template<class Gt, class Ss, class V> 00438 void Straight_skeleton_builder_2<Gt,Ss,V>::CreateInitialEvents() 00439 { 00440 CGAL_STSKEL_BUILDER_TRACE(0, "Creating initial events..."); 00441 for ( Vertex_iterator v = mSSkel->vertices_begin(); v != mSSkel->vertices_end(); ++ v ) 00442 { 00443 if ( ! v->has_infinite_time() ) 00444 { 00445 UpdatePQ(v); 00446 mVisitor.on_initial_events_collected(v,IsReflex(v),IsDegenerate(v)) ; 00447 } 00448 } 00449 } 00450 00451 00452 template<class Gt, class Ss, class V> 00453 void Straight_skeleton_builder_2<Gt,Ss,V>::CreateContourBisectors() 00454 { 00455 CGAL_STSKEL_BUILDER_TRACE(0, "Creating contour bisectors..."); 00456 for ( Vertex_iterator v = mSSkel->vertices_begin(); v != mSSkel->vertices_end(); ++ v ) 00457 { 00458 mGLAV.push_back(static_cast<Vertex_handle>(v)); 00459 Vertex_handle lPrev = GetPrevInLAV(v) ; 00460 Vertex_handle lNext = GetNextInLAV(v) ; 00461 00462 Orientation lOrientation = CGAL::orientation(lPrev->point(),v->point(),lNext->point()); 00463 if ( lOrientation == COLLINEAR ) 00464 { 00465 SetIsDegenerate(v); 00466 CGAL_STSKEL_BUILDER_TRACE(1, "COLLINEAR vertex: N" << v->id() ); 00467 } 00468 else if ( lOrientation == RIGHT_TURN ) 00469 { 00470 mReflexVertices.push_back(v); 00471 SetIsReflex(v); 00472 CGAL_STSKEL_BUILDER_TRACE(1,"Reflex vertex: N" << v->id() ); 00473 } 00474 00475 Halfedge lOB(mEdgeID++), lIB(mEdgeID++); 00476 Halfedge_handle lOBisector = mSSkel->SSkel::Base::edges_push_back (lOB, lIB); 00477 Halfedge_handle lIBisector = lOBisector->opposite(); 00478 lOBisector->HBase_base::set_face(v->halfedge()->face()); 00479 lIBisector->HBase_base::set_face(v->halfedge()->next()->face()); 00480 lIBisector->HBase_base::set_vertex(v); 00481 00482 Halfedge_handle lIBorder = v->halfedge() ; 00483 Halfedge_handle lOBorder = v->halfedge()->next() ; 00484 lIBorder ->HBase_base::set_next(lOBisector); 00485 lOBisector->HBase_base::set_prev(lIBorder); 00486 lOBorder ->HBase_base::set_prev(lIBisector); 00487 lIBisector->HBase_base::set_next(lOBorder); 00488 CGAL_STSKEL_BUILDER_TRACE(3 00489 ,"Adding Contour Bisector at N:" << v->id() << "\n B" << lOBisector->id() 00490 << " (Out)\n B" << lIBisector->id() << " (In)" 00491 ) ; 00492 } 00493 00494 for( Face_iterator fit = mSSkel->SSkel::Base::faces_begin(); fit != mSSkel->SSkel::Base::faces_end(); ++fit) 00495 { 00496 Halfedge_handle lBorder = fit->halfedge(); 00497 Halfedge_handle lLBisector = lBorder->prev(); 00498 Halfedge_handle lRBisector = lBorder->next(); 00499 00500 Vertex_handle lInfNode = mSSkel->SSkel::Base::vertices_push_back( Vertex( mVertexID++ ) ) ; 00501 InitVertexData(lInfNode); 00502 CGAL_assertion(lInfNode->has_null_point()); 00503 00504 lRBisector->HBase_base::set_next( lLBisector ); 00505 lLBisector->HBase_base::set_prev( lRBisector ); 00506 00507 lRBisector->HBase_base::set_vertex(lInfNode); 00508 00509 lInfNode->VBase::set_halfedge(lRBisector); 00510 00511 SetBisectorSlope(lRBisector,POSITIVE); 00512 SetBisectorSlope(lLBisector,NEGATIVE); 00513 00514 CGAL_STSKEL_BUILDER_TRACE(3 00515 ,"Closing face of E" << lBorder->id() 00516 << " with a ficticious vertex. B" << lRBisector->id() 00517 << "->N" << lInfNode->id() 00518 << "->B" << lLBisector->id() 00519 ) ; 00520 } 00521 } 00522 00523 template<class Gt, class Ss, class V> 00524 void Straight_skeleton_builder_2<Gt,Ss,V>::InitPhase() 00525 { 00526 mVisitor.on_initialization_started(mSSkel->size_of_vertices()); 00527 CreateContourBisectors(); 00528 CreateInitialEvents(); 00529 mVisitor.on_initialization_finished(); 00530 } 00531 00532 template<class Gt, class Ss, class V> 00533 typename Straight_skeleton_builder_2<Gt,Ss,V>::Vertex_handle 00534 Straight_skeleton_builder_2<Gt,Ss,V>::ConstructEdgeEventNode( EdgeEvent& aEvent ) 00535 { 00536 CGAL_STSKEL_BUILDER_TRACE ( 2, "Creating EdgeEvent Node" ) ; 00537 00538 Vertex_handle lLSeed = aEvent.seed0() ; 00539 Vertex_handle lRSeed = aEvent.seed1() ; 00540 00541 Vertex_handle lNewNode = mSSkel->SSkel::Base::vertices_push_back( Vertex( mVertexID++, aEvent.point(), aEvent.time(), false, false) ) ; 00542 InitVertexData(lNewNode); 00543 00544 mGLAV.push_back(lNewNode); 00545 00546 SetTrisegment(lNewNode,aEvent.trisegment()); 00547 00548 CGAL_STSKEL_BUILDER_TRACE 00549 ( 3 00550 , "LSeed: N" << lLSeed->id() << " processed\n" 00551 << "RSeed: N" << lRSeed->id() << " processed" 00552 ) ; 00553 00554 SetIsProcessed(lLSeed) ; 00555 SetIsProcessed(lRSeed) ; 00556 mGLAV.remove(lLSeed); 00557 mGLAV.remove(lRSeed); 00558 00559 Vertex_handle lLPrev = GetPrevInLAV(lLSeed) ; 00560 Vertex_handle lRNext = GetNextInLAV(lRSeed) ; 00561 00562 SetPrevInLAV(lNewNode, lLPrev ) ; 00563 SetNextInLAV(lLPrev , lNewNode ) ; 00564 00565 SetNextInLAV(lNewNode, lRNext ) ; 00566 SetPrevInLAV(lRNext , lNewNode ) ; 00567 00568 CGAL_STSKEL_BUILDER_TRACE( 2, "New Node: N" << lNewNode->id() << " at " << lNewNode->point() << '\n' 00569 << 'N' << lLSeed->id() << " removed from LAV\n" 00570 << 'N' << lRSeed->id() << " removed from LAV\n" 00571 ); 00572 00573 return lNewNode ; 00574 } 00575 00576 00577 template<class Gt, class Ss, class V> 00578 typename Straight_skeleton_builder_2<Gt,Ss,V>::Vertex_handle_pair 00579 Straight_skeleton_builder_2<Gt,Ss,V>::LookupOnSLAV ( Halfedge_handle aBorder, EventPtr const& aEvent, Site& rSite ) 00580 { 00581 Vertex_handle_pair rResult ; 00582 00583 CGAL_STSKEL_DEBUG_CODE( bool lFound = false ; ) 00584 00585 Vertex_handle lSeed = aEvent->seed0(); 00586 00587 CGAL_STSKEL_BUILDER_TRACE ( 3, "Looking up for E" << aBorder->id() << ". P=" << aEvent->point() ) ; 00588 00589 for ( typename std::list<Vertex_handle>::const_iterator vi = mGLAV.begin(); vi != mGLAV.end(); ++ vi ) 00590 { 00591 Vertex_handle v = *vi; 00592 00593 Triedge const& lTriedge = GetVertexTriedge(v); 00594 00595 Vertex_handle lPrevN = GetPrevInLAV(v); 00596 Vertex_handle lNextN = GetNextInLAV(v); 00597 00598 if ( lTriedge.e0() == aBorder ) 00599 { 00600 Halfedge_handle lPrevBorder = GetEdgeEndingAt(lPrevN) ; 00601 Halfedge_handle lNextBorder = GetEdgeEndingAt(lNextN) ; 00602 00603 CGAL_STSKEL_DEBUG_CODE( lFound = true ; ) 00604 00605 CGAL_STSKEL_BUILDER_TRACE ( 3 00606 , "Subedge found in SLAV: N" << lPrevN->id() << "->N" << v->id() 00607 << " (E" << lPrevBorder->id() << "->E" << aBorder->id() << "->E" << lNextBorder->id() << ")" 00608 ) ; 00609 00610 Oriented_side lLSide = EventPointOrientedSide(*aEvent, lPrevBorder, aBorder , lPrevN, false ) ; 00611 Oriented_side lRSide = EventPointOrientedSide(*aEvent, aBorder , lNextBorder, v , true ) ; 00612 00613 if ( lLSide != ON_POSITIVE_SIDE && lRSide != ON_NEGATIVE_SIDE ) 00614 { 00615 if ( lLSide != ON_ORIENTED_BOUNDARY || lRSide != ON_ORIENTED_BOUNDARY ) 00616 { 00617 rSite = ( lLSide == ON_ORIENTED_BOUNDARY ? AT_SOURCE : ( lRSide == ON_ORIENTED_BOUNDARY ? AT_TARGET : INSIDE ) ) ; 00618 00619 rResult = std::make_pair(lPrevN,v) ; 00620 00621 CGAL_STSKEL_BUILDER_TRACE ( 3, "Split point found at the " 00622 << ( rSite == AT_SOURCE ? "SOURCE vertex" : ( rSite == AT_TARGET ? "TARGET vertex" : "strict inside" ) ) 00623 << " of the offset edge." 00624 ) ; 00625 break ; 00626 } 00627 else 00628 { 00629 CGAL_STSKEL_BUILDER_TRACE ( 3, "Opposite edge collapsed to a point" ) ; 00630 } 00631 } 00632 } 00633 } 00634 00635 #ifdef CGAL_STRAIGHT_SKELETON_ENABLE_TRACE 00636 if ( !handle_assigned(rResult.first) ) 00637 { 00638 if ( !lFound ) 00639 { 00640 CGAL_STSKEL_BUILDER_TRACE(1,"Split event is no longer valid. Opposite edge vanished."); 00641 } 00642 else 00643 { 00644 CGAL_STSKEL_BUILDER_TRACE(1,"Split event is no longer valid. Point not inside the opposite edge offset zone."); 00645 } 00646 } 00647 #endif 00648 00649 return rResult ; 00650 } 00651 00652 00653 00654 template<class Gt, class Ss, class V> 00655 typename Straight_skeleton_builder_2<Gt,Ss,V>::Vertex_handle_pair 00656 Straight_skeleton_builder_2<Gt,Ss,V>::ConstructSplitEventNodes( SplitEvent& aEvent, Vertex_handle aOppR ) 00657 { 00658 Vertex_handle_pair rResult; 00659 00660 CGAL_STSKEL_BUILDER_TRACE ( 2, "Creating SplitEvent Nodes" ) ; 00661 00662 Vertex_handle lOppL = GetPrevInLAV(aOppR) ; 00663 00664 Vertex_handle lNewNodeA = mSSkel->SSkel::Base::vertices_push_back( Vertex( mVertexID++, aEvent.point(), aEvent.time(), true, false ) ) ; 00665 Vertex_handle lNewNodeB = mSSkel->SSkel::Base::vertices_push_back( Vertex( mVertexID++, aEvent.point(), aEvent.time(), true, false ) ) ; 00666 00667 InitVertexData(lNewNodeA); 00668 InitVertexData(lNewNodeB); 00669 SetTrisegment(lNewNodeA,aEvent.trisegment()); 00670 SetTrisegment(lNewNodeB,aEvent.trisegment()); 00671 00672 mGLAV.push_back(lNewNodeA); 00673 mGLAV.push_back(lNewNodeB); 00674 00675 Vertex_handle lSeed = aEvent.seed0() ; 00676 00677 CGAL_STSKEL_BUILDER_TRACE ( 3, "Seed: N" << lSeed->id() << " processed" ) ; 00678 00679 SetIsProcessed(lSeed) ; 00680 mGLAV.remove(lSeed); 00681 00682 CGAL_STSKEL_BUILDER_TRACE ( 2, 'N' << lNewNodeA->id() << " and N" << lNewNodeB->id() << " inserted into LAV." ) ; 00683 00684 Vertex_handle lPrev = GetPrevInLAV(lSeed) ; 00685 Vertex_handle lNext = GetNextInLAV(lSeed) ; 00686 00687 SetNextInLAV(lPrev , lNewNodeA ) ; 00688 SetPrevInLAV(lNewNodeA, lPrev ) ; 00689 00690 SetNextInLAV(lNewNodeA, aOppR ) ; 00691 SetPrevInLAV(aOppR , lNewNodeA ) ; 00692 00693 SetNextInLAV(lOppL , lNewNodeB ) ; 00694 SetPrevInLAV(lNewNodeB, lOppL ) ; 00695 00696 SetNextInLAV(lNewNodeB, lNext ) ; 00697 SetPrevInLAV(lNext , lNewNodeB ) ; 00698 00699 CGAL_STSKEL_BUILDER_TRACE( 2, 'N' << lSeed->id() << " removed from LAV" ); 00700 00701 rResult = std::make_pair(lNewNodeA,lNewNodeB); 00702 00703 mSplitNodes.push_back(rResult); 00704 00705 return rResult ; 00706 } 00707 00708 template<class Gt, class Ss, class V> 00709 typename Straight_skeleton_builder_2<Gt,Ss,V>::Vertex_handle_pair 00710 Straight_skeleton_builder_2<Gt,Ss,V>::ConstructPseudoSplitEventNodes( PseudoSplitEvent& aEvent ) 00711 { 00712 Vertex_handle_pair rResult; 00713 00714 CGAL_STSKEL_BUILDER_TRACE ( 2, "Creating PseudoSplitEvent Nodes" ) ; 00715 00716 Vertex_handle lLSeed = aEvent.seed0() ; 00717 Vertex_handle lRSeed = aEvent.seed1() ; 00718 00719 Vertex_handle lNewNodeA = mSSkel->SSkel::Base::vertices_push_back( Vertex( mVertexID++, aEvent.point(), aEvent.time(), true, false ) ) ; 00720 Vertex_handle lNewNodeB = mSSkel->SSkel::Base::vertices_push_back( Vertex( mVertexID++, aEvent.point(), aEvent.time(), true, false ) ) ; 00721 00722 mGLAV.push_back(lNewNodeA); 00723 mGLAV.push_back(lNewNodeB); 00724 00725 InitVertexData(lNewNodeA); 00726 InitVertexData(lNewNodeB); 00727 SetTrisegment(lNewNodeA,aEvent.trisegment()); 00728 SetTrisegment(lNewNodeB,aEvent.trisegment()); 00729 00730 CGAL_STSKEL_BUILDER_TRACE 00731 ( 00732 3 00733 , "LSeed: N" << lLSeed->id() << " processed\n" 00734 << "RSeed: N" << lRSeed->id() << " processed" 00735 ) ; 00736 00737 00738 SetIsProcessed(lLSeed) ; 00739 SetIsProcessed(lRSeed) ; 00740 mGLAV.remove(lLSeed); 00741 mGLAV.remove(lRSeed); 00742 00743 Vertex_handle lLPrev = GetPrevInLAV(lLSeed) ; 00744 Vertex_handle lLNext = GetNextInLAV(lLSeed) ; 00745 Vertex_handle lRPrev = GetPrevInLAV(lRSeed) ; 00746 Vertex_handle lRNext = GetNextInLAV(lRSeed) ; 00747 00748 SetPrevInLAV(lNewNodeA, lLPrev ) ; 00749 SetNextInLAV(lLPrev , lNewNodeA ) ; 00750 00751 SetNextInLAV(lNewNodeA, lRNext ) ; 00752 SetPrevInLAV(lRNext , lNewNodeA ) ; 00753 00754 SetPrevInLAV(lNewNodeB, lRPrev ) ; 00755 SetNextInLAV(lRPrev , lNewNodeB ) ; 00756 00757 SetNextInLAV(lNewNodeB, lLNext ) ; 00758 SetPrevInLAV(lLNext , lNewNodeB ) ; 00759 00760 CGAL_STSKEL_BUILDER_TRACE(2, "NewNodeA: N" << lNewNodeA->id() << " at " << lNewNodeA->point() << '\n' 00761 << "NewNodeB: N" << lNewNodeB->id() << " at " << lNewNodeB->point() << '\n' 00762 << 'N' << lLSeed->id() << " removed from LAV\n" 00763 << 'N' << lRSeed->id() << " removed from LAV" 00764 ); 00765 00766 00767 rResult = std::make_pair(lNewNodeA,lNewNodeB); 00768 00769 mSplitNodes.push_back(rResult); 00770 00771 return rResult ; 00772 } 00773 00774 template<class Gt, class Ss, class V> 00775 bool Straight_skeleton_builder_2<Gt,Ss,V>::IsProcessed( EventPtr aEvent ) 00776 { 00777 return IsProcessed(aEvent->seed0()) || IsProcessed(aEvent->seed1()) ; 00778 } 00779 00780 template<class Gt, class Ss, class V> 00781 bool Straight_skeleton_builder_2<Gt,Ss,V>::IsValidEdgeEvent( EdgeEvent const& aEvent ) 00782 { 00783 bool rResult = false ; 00784 00785 Vertex_handle lLSeed = aEvent.seed0() ; 00786 Vertex_handle lRSeed = aEvent.seed1() ; 00787 00788 Vertex_handle lPrevLSeed = GetPrevInLAV(lLSeed) ; 00789 Vertex_handle lNextRSeed = GetNextInLAV(lRSeed) ; 00790 00791 if ( lPrevLSeed != lNextRSeed ) 00792 { 00793 Halfedge_handle lPrevE0 = GetEdgeEndingAt(lPrevLSeed) ; 00794 Halfedge_handle lE0 = aEvent.triedge().e0() ; 00795 Halfedge_handle lE2 = aEvent.triedge().e2() ; 00796 Halfedge_handle lNextE2 = GetEdgeStartingAt(lNextRSeed) ; 00797 00798 CGAL_STSKEL_BUILDER_TRACE(3, "PrevLSeed=N" << lPrevLSeed->id() << " PrevE0=E" << lPrevE0->id() ) ; 00799 CGAL_STSKEL_BUILDER_TRACE(3, "NextRSeed=N" << lNextRSeed->id() << " NextE2=E" << lNextE2->id() ) ; 00800 00801 Oriented_side lLSide = EventPointOrientedSide(aEvent, lPrevE0, lE0 , lPrevLSeed, false ) ; 00802 Oriented_side lRSide = EventPointOrientedSide(aEvent, lE2 , lNextE2, lNextRSeed, true ) ; 00803 00804 bool lLSideOK = ( lLSide != ON_POSITIVE_SIDE ) ; 00805 bool lRSideOK = ( lRSide != ON_NEGATIVE_SIDE ) ; 00806 00807 CGAL_STSKEL_BUILDER_TRACE_IF( !lLSideOK 00808 ,3 00809 ,"Invalid edge event: " << aEvent.triedge() << " NewNode is before E" << lE0->id() 00810 << " source N" << lPrevLSeed->id() 00811 ) ; 00812 00813 CGAL_STSKEL_BUILDER_TRACE_IF( !lRSideOK 00814 ,3 00815 ,"Invalid edge event: " << aEvent.triedge() << " NewNode is past E" << lE2->id() 00816 << " target N" << lNextRSeed->id() 00817 ) ; 00818 00819 rResult = lLSideOK && lRSideOK ; 00820 } 00821 else 00822 { 00823 // Triangle collapse. No need to test explicitely. 00824 rResult = true ; 00825 } 00826 return rResult ; 00827 } 00828 00829 template<class Gt, class Ss, class V> 00830 void Straight_skeleton_builder_2<Gt,Ss,V>::HandleEdgeEvent( EventPtr aEvent ) 00831 { 00832 EdgeEvent& lEvent = dynamic_cast<EdgeEvent&>(*aEvent) ; 00833 00834 if ( IsValidEdgeEvent(lEvent) ) 00835 { 00836 Vertex_handle lLSeed = lEvent.seed0() ; 00837 Vertex_handle lRSeed = lEvent.seed1() ; 00838 00839 Vertex_handle lNewNode = ConstructEdgeEventNode(lEvent); 00840 00841 Halfedge_handle lLOBisector = lLSeed->primary_bisector() ; 00842 Halfedge_handle lROBisector = lRSeed->primary_bisector() ; 00843 Halfedge_handle lLIBisector = lLOBisector->opposite(); 00844 Halfedge_handle lRIBisector = lROBisector->opposite(); 00845 00846 Vertex_handle lRIFicNode = lROBisector->vertex() ; 00847 Vertex_handle lLOFicNode = lLOBisector->vertex() ; 00848 00849 CrossLink(lLOBisector,lNewNode); 00850 00851 Link(lROBisector,lNewNode); 00852 00853 CrossLinkFwd(lROBisector,lLIBisector) ; 00854 00855 Halfedge_handle lDefiningBorderA = lNewNode->halfedge()->defining_contour_edge(); 00856 Halfedge_handle lDefiningBorderB = lNewNode->halfedge()->opposite()->prev()->opposite()->defining_contour_edge(); 00857 Halfedge_handle lDefiningBorderC = lNewNode->halfedge()->opposite()->prev()->defining_contour_edge(); 00858 00859 lNewNode->VBase::set_event_triedge( lEvent.triedge() ) ; 00860 00861 Triedge lTri(lDefiningBorderA,lDefiningBorderB,lDefiningBorderC); 00862 00863 SetVertexTriedge( lNewNode, lTri ) ; 00864 00865 SetBisectorSlope(lLSeed,lNewNode); 00866 SetBisectorSlope(lRSeed,lNewNode); 00867 00868 CGAL_STSKEL_BUILDER_TRACE( 1, "E" << lRSeed->halfedge()->defining_contour_edge()->id() << " collapsed." ); 00869 CGAL_STSKEL_BUILDER_TRACE( 3, "Ficticious node along collapsed face is N" << lRIFicNode->id() << " between B" << lROBisector->id() << " and B" << lLIBisector->id() ) ; 00870 00871 if ( lLOFicNode->has_infinite_time() ) 00872 { 00873 CGAL_STSKEL_BUILDER_TRACE(3,"Creating new Edge Event's Bisector"); 00874 00875 Halfedge_handle lNOBisector = mSSkel->SSkel::Base::edges_push_back ( Halfedge(mEdgeID),Halfedge(mEdgeID+1) ); 00876 00877 Halfedge_handle lNIBisector = lNOBisector->opposite(); 00878 mEdgeID += 2 ; 00879 00880 CrossLinkFwd(lNOBisector , lLOBisector->next()); 00881 CrossLinkFwd(lRIBisector->prev(), lNIBisector ); 00882 00883 CrossLink(lNOBisector,lLOFicNode); 00884 00885 SetBisectorSlope(lNOBisector,POSITIVE); 00886 SetBisectorSlope(lNIBisector,NEGATIVE); 00887 00888 CrossLinkFwd(lNIBisector, lRIBisector); 00889 CrossLinkFwd(lLOBisector, lNOBisector); 00890 00891 Link(lNOBisector,lLOBisector->face()); 00892 Link(lNIBisector,lRIBisector->face()); 00893 00894 Link(lNIBisector,lNewNode); 00895 00896 CGAL_STSKEL_BUILDER_TRACE( 2, newn2str("",lNewNode,lTri) ) ; 00897 CGAL_STSKEL_BUILDER_TRACE( 2, newb2str("O",lNOBisector) ) ; 00898 CGAL_STSKEL_BUILDER_TRACE( 2, newb2str("I",lNIBisector) ) ; 00899 00900 CGAL_STSKEL_BUILDER_TRACE ( 2, "Ficticius N" << lRIFicNode->id() << " erased." ) ; 00901 EraseNode(lRIFicNode); 00902 00903 SetupNewNode(lNewNode) ; 00904 00905 UpdatePQ(lNewNode); 00906 00907 mVisitor.on_edge_event_processed(lLSeed,lRSeed,lNewNode) ; 00908 } 00909 else 00910 { 00911 CGAL_STSKEL_BUILDER_TRACE( 2, newn2str("",lNewNode,lTri) 00912 << ".\nThis is a multiple node (A node with these defining edges already exist in the LAV)" 00913 ); 00914 } 00915 00916 CGAL_STSKEL_BUILDER_TRACE( 1, "Wavefront: " << wavefront2str(lNewNode) ); 00917 } 00918 } 00919 00920 template<class Gt, class Ss, class V> 00921 bool Straight_skeleton_builder_2<Gt,Ss,V>::IsValidSplitEvent( SplitEvent const& aEvent ) 00922 { 00923 return true ; 00924 } 00925 00926 template<class Gt, class Ss, class V> 00927 void Straight_skeleton_builder_2<Gt,Ss,V>::HandleSplitEvent( EventPtr aEvent, Vertex_handle_pair aOpp ) 00928 { 00929 SplitEvent& lEvent = dynamic_cast<SplitEvent&>(*aEvent) ; 00930 00931 if ( IsValidSplitEvent(lEvent) ) 00932 { 00933 Vertex_handle lSeed = lEvent.seed0(); 00934 00935 Vertex_handle lOppL = aOpp.first ; 00936 Vertex_handle lOppR = aOpp.second ; 00937 00938 Halfedge_handle lOppIBisector_L = lOppL->primary_bisector()->opposite(); 00939 Halfedge_handle lOppOBisector_R = lOppR->primary_bisector(); 00940 00941 Vertex_handle lOppFicNode = lOppOBisector_R->vertex() ; 00942 00943 CGAL_assertion(lOppOBisector_R->next() == lOppIBisector_L ) ; 00944 CGAL_assertion(lOppIBisector_L->prev() == lOppOBisector_R ) ; 00945 CGAL_assertion(lOppFicNode->has_infinite_time()); 00946 00947 00948 CGAL_STSKEL_BUILDER_TRACE(2,"Splitted face: N" << lOppR->id() 00949 << "->B" << lOppOBisector_R->id() 00950 << "->N" << lOppFicNode->id() 00951 << "->B" << lOppIBisector_L->id() 00952 << "->N" << lOppL->id() 00953 ) ; 00954 00955 CGAL_STSKEL_BUILDER_TRACE(2,"Ficticious node for right half of opposite edge: N" << lOppFicNode->id() ) ; 00956 00957 Halfedge_handle lOppBorder = lEvent.triedge().e2() ; 00958 00959 Vertex_handle lNewNode_L, lNewNode_R ; 00960 boost::tie(lNewNode_L,lNewNode_R) = ConstructSplitEventNodes(lEvent,lOppR); 00961 00962 Triedge lTriedge = aEvent->triedge(); 00963 00964 Halfedge_handle lReflexLBorder = lTriedge.e0(); 00965 Halfedge_handle lReflexRBorder = lTriedge.e1(); 00966 00967 Halfedge_handle lNOBisector_L = mSSkel->SSkel::Base::edges_push_back ( Halfedge(mEdgeID++),Halfedge(mEdgeID++) ); 00968 Halfedge_handle lNOBisector_R = mSSkel->SSkel::Base::edges_push_back ( Halfedge(mEdgeID++),Halfedge(mEdgeID++) ); 00969 Halfedge_handle lNIBisector_L = lNOBisector_L->opposite(); 00970 Halfedge_handle lNIBisector_R = lNOBisector_R->opposite(); 00971 00972 Halfedge_handle lXOBisector = lSeed->primary_bisector() ; 00973 Halfedge_handle lXIBisector = lXOBisector->opposite(); 00974 00975 Halfedge_handle lXONextBisector = lXOBisector->next(); 00976 Halfedge_handle lXIPrevBisector = lXIBisector->prev(); 00977 00978 Vertex_handle lXOFicNode = lXOBisector->vertex() ; 00979 CGAL_assertion(lXOFicNode->has_infinite_time()); 00980 00981 CGAL_STSKEL_BUILDER_TRACE(2,"Ficticious node for left reflex face: N" << lXOFicNode->id() ) ; 00982 CGAL_STSKEL_BUILDER_TRACE(2,"Ficticious node for right reflex face: N" << lXIPrevBisector->vertex()->id() ) ; 00983 00984 Link(lNewNode_L,lXOBisector); 00985 Link(lNewNode_R,lNIBisector_L) ; 00986 00987 Link(lXOBisector,lNewNode_L); 00988 00989 Link(lNOBisector_L,lXOBisector->face()); 00990 Link(lNIBisector_L,lOppBorder ->face()); 00991 Link(lNOBisector_R,lOppBorder ->face()); 00992 Link(lNIBisector_R,lXIBisector->face()); 00993 00994 Link(lNIBisector_L,lNewNode_R); 00995 Link(lNIBisector_R,lNewNode_R); 00996 00997 Link(lNOBisector_L,lXOFicNode); 00998 00999 01000 CrossLinkFwd(lXOBisector ,lNOBisector_L); 01001 CrossLinkFwd(lNOBisector_L ,lXONextBisector); 01002 CrossLinkFwd(lXIPrevBisector,lNIBisector_R); 01003 CrossLinkFwd(lNIBisector_R ,lXIBisector); 01004 CrossLinkFwd(lOppOBisector_R,lNIBisector_L); 01005 CrossLinkFwd(lNIBisector_L ,lNOBisector_R); 01006 CrossLinkFwd(lNOBisector_R ,lOppIBisector_L); 01007 01008 SetBisectorSlope(lSeed,lNewNode_L); 01009 01010 Vertex_handle lNewFicNode = mSSkel->SSkel::Base::vertices_push_back( Vertex( mVertexID++ ) ) ; 01011 InitVertexData(lNewFicNode); 01012 CGAL_assertion(lNewFicNode->has_null_point()); 01013 CrossLink(lNOBisector_R,lNewFicNode); 01014 01015 SetBisectorSlope(lNOBisector_L,POSITIVE); 01016 SetBisectorSlope(lNIBisector_L,NEGATIVE); 01017 SetBisectorSlope(lNOBisector_R,POSITIVE); 01018 SetBisectorSlope(lNIBisector_R,NEGATIVE); 01019 01020 CGAL_STSKEL_BUILDER_TRACE(2,"(New) ficticious node for left half of opposite edge: N" << lNewFicNode->id() ) ; 01021 01022 Halfedge_handle lNewNode_L_DefiningBorderA = lNewNode_L->halfedge()->defining_contour_edge(); 01023 Halfedge_handle lNewNode_L_DefiningBorderB = lNewNode_L->halfedge()->opposite()->prev()->opposite()->defining_contour_edge(); 01024 Halfedge_handle lNewNode_L_DefiningBorderC = lNewNode_L->halfedge()->opposite()->prev()->defining_contour_edge(); 01025 Halfedge_handle lNewNode_R_DefiningBorderA = lNewNode_R->halfedge()->defining_contour_edge(); 01026 Halfedge_handle lNewNode_R_DefiningBorderB = lNewNode_R->halfedge()->opposite()->prev()->opposite()->defining_contour_edge(); 01027 Halfedge_handle lNewNode_R_DefiningBorderC = lNewNode_R->halfedge()->opposite()->prev()->defining_contour_edge(); 01028 01029 lNewNode_L->VBase::set_event_triedge( lEvent.triedge() ) ; 01030 lNewNode_R->VBase::set_event_triedge( lEvent.triedge() ) ; 01031 01032 Triedge lTriL( lNewNode_L_DefiningBorderA,lNewNode_L_DefiningBorderB,lNewNode_L_DefiningBorderC ) ; 01033 Triedge lTriR( lNewNode_R_DefiningBorderA,lNewNode_R_DefiningBorderB,lNewNode_R_DefiningBorderC ) ; 01034 01035 SetVertexTriedge( lNewNode_L, lTriL ) ; 01036 SetVertexTriedge( lNewNode_R, lTriR ) ; 01037 01038 CGAL_STSKEL_BUILDER_TRACE(2, newn2str("L",lNewNode_L,lTriL) << std::endl 01039 << newn2str("R",lNewNode_R,lTriR) << std::endl 01040 << newb2str("OL",lNOBisector_L) << std::endl 01041 << newb2str("IL",lNIBisector_L) << std::endl 01042 << newb2str("OR",lNOBisector_R) << std::endl 01043 << newb2str("IR",lNIBisector_R) 01044 ) ; 01045 01046 CGAL_STSKEL_BUILDER_TRACE( 1, "Wavefronts:\n " << wavefront2str(lNewNode_L) << "\n " << wavefront2str(lNewNode_R) ); 01047 01048 SetupNewNode(lNewNode_L) ; 01049 SetupNewNode(lNewNode_R) ; 01050 01051 UpdatePQ(lNewNode_L); 01052 UpdatePQ(lNewNode_R); 01053 01054 mVisitor.on_split_event_processed(lSeed,lNewNode_L,lNewNode_R) ; 01055 } 01056 01057 01058 } 01059 01060 template<class Gt, class Ss, class V> 01061 void Straight_skeleton_builder_2<Gt,Ss,V>::SetupNewNode( Vertex_handle aNode ) 01062 { 01063 // In an edge-edge anihiliation the current polygon becomes a two-node degenerate chain collapsed into a single point 01064 if ( GetPrevInLAV(aNode) != GetNextInLAV(aNode) ) 01065 { 01066 Halfedge_handle lLE = GetEdgeEndingAt (aNode); 01067 Halfedge_handle lRE = GetEdgeStartingAt(aNode); 01068 01069 Vector_2 lLV = CreateVector(lLE); 01070 Vector_2 lRV = CreateVector(lRE); 01071 01072 Orientation lOrientation = CGAL::orientation(lLV,lRV) ; 01073 if ( lOrientation == COLLINEAR ) 01074 { 01075 SetIsDegenerate(aNode); 01076 CGAL_STSKEL_BUILDER_TRACE(1, "COLLINEAR *NEW* vertex: N" << aNode->id() << " (E" << lLE->id() << ",E" << lRE->id() << ")" ) ; 01077 } 01078 else if ( lOrientation == RIGHT_TURN ) 01079 { 01080 mReflexVertices.push_back(aNode); 01081 SetIsReflex(aNode); 01082 CGAL_STSKEL_BUILDER_TRACE(1, "Reflex *NEW* vertex: N" << aNode->id() << " (E" << lLE->id() << ",E" << lRE->id() << ")" ); 01083 } 01084 } 01085 } 01086 01087 template<class Direction> 01088 bool counterclockwise_at_or_in_between_2( Direction const& p, Direction const& q, Direction const& r ) 01089 { 01090 typedef typename Kernel_traits<Direction>::Kernel K ; 01091 01092 return p == q || p == r || K().counterclockwise_in_between_2_object()(p,q,r) ; 01093 } 01094 01095 template<class Gt, class Ss, class V> 01096 bool Straight_skeleton_builder_2<Gt,Ss,V>::IsValidPseudoSplitEvent( PseudoSplitEvent const& aEvent ) 01097 { 01098 Vertex_handle lSeed0 = aEvent.seed0(); 01099 Vertex_handle lSeed1 = aEvent.seed1(); 01100 01101 Halfedge_handle lEL0 = GetEdgeEndingAt (lSeed0); 01102 Halfedge_handle lER0 = GetEdgeStartingAt(lSeed0); 01103 01104 Halfedge_handle lEL1 = GetEdgeEndingAt (lSeed1); 01105 Halfedge_handle lER1 = GetEdgeStartingAt(lSeed1); 01106 01107 Direction_2 lDL0 = - CreateDirection(lEL0); 01108 Direction_2 lDL1 = - CreateDirection(lEL1); 01109 Direction_2 lDR0 = CreateDirection(lER0); 01110 Direction_2 lDR1 = CreateDirection(lER1); 01111 01112 bool lV01Degenerate = (lDL0 == lDR1) ; 01113 bool lV10Degenerate = (lDL1 == lDR0) ; 01114 01115 01116 CGAL_STSKEL_BUILDER_TRACE(3, "Validating pseudo-split event. Resulting re-connection: " 01117 << "\nE" << lEL0->id() << " [DL0:" << dir2str(lDL0) << "]" 01118 << "->E" << lER1->id() << " [DR1:" << dir2str(lDR1) << "]" << ( lV01Degenerate ? " (degenerate)" : "" ) 01119 << "\nE" << lEL1->id() << " [DL1:" << dir2str(lDL1) << "]" 01120 << "->E" << lER0->id() << " [DR0:" << dir2str(lDR0) << "]" << ( lV10Degenerate ? " (degenerate)" : "" ) 01121 ) ; 01122 01123 bool lTangled ; 01124 01125 if ( !lV01Degenerate ) 01126 { 01127 bool lEL1V_Tangled = counterclockwise_at_or_in_between_2(lDL1,lDR1,lDL0); 01128 bool lER0V_Tangled = counterclockwise_at_or_in_between_2(lDR0,lDR1,lDL0); 01129 01130 lTangled = lEL1V_Tangled || lER0V_Tangled ; 01131 } 01132 else if ( !lV10Degenerate ) 01133 { 01134 bool lEL0V_Tangled = counterclockwise_at_or_in_between_2(lDL0,lDR0,lDL1); 01135 bool lER1V_Tangled = counterclockwise_at_or_in_between_2(lDR1,lDR0,lDL1); 01136 01137 lTangled = lEL0V_Tangled || lER1V_Tangled ; 01138 } 01139 else 01140 { 01141 lTangled = (lDL0 == lDL1) ; 01142 } 01143 01144 CGAL_STSKEL_BUILDER_TRACE_IF(lTangled, 3, "Tangled profile. Pseudo-split event is invalid"); 01145 01146 return !lTangled ; 01147 } 01148 01149 template<class Gt, class Ss, class V> 01150 void Straight_skeleton_builder_2<Gt,Ss,V>::HandlePseudoSplitEvent( EventPtr aEvent ) 01151 { 01152 PseudoSplitEvent& lEvent = dynamic_cast<PseudoSplitEvent&>(*aEvent) ; 01153 01154 if ( IsValidPseudoSplitEvent(lEvent) ) 01155 { 01156 Vertex_handle lLSeed = lEvent.seed0() ; 01157 Vertex_handle lRSeed = lEvent.seed1() ; 01158 01159 Vertex_handle lNewNode_L, lNewNode_R ; 01160 boost::tie(lNewNode_L,lNewNode_R) = ConstructPseudoSplitEventNodes(lEvent); 01161 01162 Halfedge_handle lNBisector_LO = mSSkel->SSkel::Base::edges_push_back ( Halfedge(mEdgeID++),Halfedge(mEdgeID++) ); 01163 Halfedge_handle lNBisector_RO = mSSkel->SSkel::Base::edges_push_back ( Halfedge(mEdgeID++),Halfedge(mEdgeID++) ); 01164 Halfedge_handle lNBisector_LI = lNBisector_LO->opposite(); 01165 Halfedge_handle lNBisector_RI = lNBisector_RO->opposite(); 01166 01167 Halfedge_handle lSBisector_LO = lLSeed->primary_bisector() ; 01168 Halfedge_handle lSBisector_LI = lSBisector_LO->opposite(); 01169 01170 Halfedge_handle lSBisector_RO = lRSeed->primary_bisector() ; 01171 Halfedge_handle lSBisector_RI = lSBisector_RO->opposite(); 01172 01173 Halfedge_handle lSBisector_LO_Next = lSBisector_LO->next(); 01174 Halfedge_handle lSBisector_RO_Next = lSBisector_RO->next(); 01175 Halfedge_handle lSBisector_LI_Prev = lSBisector_LI->prev(); 01176 Halfedge_handle lSBisector_RI_Prev = lSBisector_RI->prev(); 01177 01178 Vertex_handle lFicNod_SLO = lSBisector_LO->vertex(); 01179 Vertex_handle lFicNod_SLI = lSBisector_LI_Prev->vertex(); 01180 Vertex_handle lFicNod_SRO = lSBisector_RO->vertex(); 01181 Vertex_handle lFicNod_SRI = lSBisector_RI_Prev->vertex(); 01182 01183 CGAL_assertion( lFicNod_SLO->has_infinite_time() ) ; 01184 CGAL_assertion( lFicNod_SLI->has_infinite_time() ) ; 01185 CGAL_assertion( lFicNod_SRO->has_infinite_time() ) ; 01186 CGAL_assertion( lFicNod_SRI->has_infinite_time() ) ; 01187 01188 Link(lNBisector_LO, lSBisector_LO->face()); 01189 Link(lNBisector_LI, lSBisector_RI->face()); 01190 Link(lNBisector_RO, lSBisector_RO->face()); 01191 Link(lNBisector_RI, lSBisector_LI->face()); 01192 01193 CrossLink(lSBisector_LO, lNewNode_L ); 01194 CrossLink(lSBisector_RO, lNewNode_R ); 01195 01196 CrossLink(lNBisector_LO, lFicNod_SLO ); 01197 CrossLink(lNBisector_RO, lFicNod_SRO ); 01198 01199 SetBisectorSlope(lNBisector_LO,POSITIVE); 01200 SetBisectorSlope(lNBisector_LI,NEGATIVE); 01201 SetBisectorSlope(lNBisector_RO,POSITIVE); 01202 SetBisectorSlope(lNBisector_RI,NEGATIVE); 01203 01204 Link(lNBisector_LI, lNewNode_L); 01205 Link(lNBisector_RI, lNewNode_R); 01206 01207 Link(lNewNode_L, lSBisector_LO); 01208 Link(lNewNode_R, lSBisector_RO); 01209 01210 CrossLinkFwd(lSBisector_LO,lNBisector_LO); 01211 CrossLinkFwd(lNBisector_LO,lSBisector_LO_Next); 01212 CrossLinkFwd(lSBisector_LI_Prev,lNBisector_RI); 01213 CrossLinkFwd(lNBisector_RI,lSBisector_LI); 01214 CrossLinkFwd(lSBisector_RI_Prev,lNBisector_LI); 01215 CrossLinkFwd(lNBisector_LI,lSBisector_RI); 01216 CrossLinkFwd(lSBisector_RO,lNBisector_RO); 01217 CrossLinkFwd(lNBisector_RO,lSBisector_RO_Next); 01218 01219 SetBisectorSlope(lLSeed,lNewNode_L); 01220 SetBisectorSlope(lRSeed,lNewNode_R); 01221 01222 Halfedge_handle lNewNode_L_DefiningBorderA = lNewNode_L->halfedge()->defining_contour_edge(); 01223 Halfedge_handle lNewNode_L_DefiningBorderB = lNewNode_L->halfedge()->next()->opposite()->defining_contour_edge(); 01224 Halfedge_handle lNewNode_L_DefiningBorderC = lNewNode_L->halfedge()->opposite()->prev()->defining_contour_edge(); 01225 Halfedge_handle lNewNode_R_DefiningBorderA = lNewNode_R->halfedge()->defining_contour_edge(); 01226 Halfedge_handle lNewNode_R_DefiningBorderB = lNewNode_R->halfedge()->next()->opposite()->defining_contour_edge(); 01227 Halfedge_handle lNewNode_R_DefiningBorderC = lNewNode_R->halfedge()->opposite()->prev()->defining_contour_edge(); 01228 01229 lNewNode_L->VBase::set_event_triedge( lEvent.triedge() ) ; 01230 lNewNode_R->VBase::set_event_triedge( lEvent.triedge() ) ; 01231 01232 Triedge lTriL( lNewNode_L_DefiningBorderA, lNewNode_L_DefiningBorderB, lNewNode_L_DefiningBorderC ) ; 01233 Triedge lTriR( lNewNode_R_DefiningBorderA, lNewNode_R_DefiningBorderB, lNewNode_R_DefiningBorderC ) ; 01234 01235 SetVertexTriedge( lNewNode_L, lTriL ) ; 01236 SetVertexTriedge( lNewNode_R, lTriR ) ; 01237 01238 CGAL_STSKEL_BUILDER_TRACE(2, newn2str("L",lNewNode_L,lTriL) << std::endl 01239 << newn2str("R",lNewNode_R,lTriR) << std::endl 01240 << newb2str("OL",lNBisector_LO) << std::endl 01241 << newb2str("IL",lNBisector_LI) << std::endl 01242 << newb2str("OR",lNBisector_RO) << std::endl 01243 << newb2str("IR",lNBisector_RI) 01244 ) ; 01245 01246 CGAL_STSKEL_BUILDER_TRACE( 1, "Wavefronts:\n " << wavefront2str(lNewNode_L) << "\n " << wavefront2str(lNewNode_R) ); 01247 01248 SetupNewNode(lNewNode_L) ; 01249 SetupNewNode(lNewNode_R) ; 01250 01251 UpdatePQ(lNewNode_L); 01252 UpdatePQ(lNewNode_R); 01253 01254 mVisitor.on_pseudo_split_event_processed(lLSeed,lRSeed,lNewNode_L,lNewNode_R) ; 01255 } 01256 } 01257 01258 template<class Gt, class Ss, class V> 01259 void Straight_skeleton_builder_2<Gt,Ss,V>::HandleSplitOrPseudoSplitEvent( EventPtr aEvent ) 01260 { 01261 Halfedge_handle lOppEdge = aEvent->triedge().e2() ; 01262 01263 Site lSite; 01264 01265 Vertex_handle_pair lOpp = LookupOnSLAV(lOppEdge,aEvent,lSite); 01266 01267 if ( handle_assigned(lOpp.first) ) 01268 { 01269 EventPtr lPseudoSplitEvent = IsPseudoSplitEvent(aEvent,lOpp,lSite); 01270 if ( lPseudoSplitEvent ) 01271 HandlePseudoSplitEvent(lPseudoSplitEvent); 01272 else HandleSplitEvent(aEvent,lOpp); 01273 } 01274 } 01275 01276 template<class Gt, class Ss, class V> 01277 void Straight_skeleton_builder_2<Gt,Ss,V>::InsertNextSplitEventInPQ( Vertex_handle v ) 01278 { 01279 EventPtr lSplitEvent = PopNextSplitEvent(v); 01280 if ( !!lSplitEvent ) 01281 InsertEventInPQ(lSplitEvent); 01282 } 01283 01284 template<class Gt, class Ss, class V> 01285 void Straight_skeleton_builder_2<Gt,Ss,V>::InsertNextSplitEventsInPQ() 01286 { 01287 for ( typename Vertex_handle_vector::iterator v = mReflexVertices.begin(), ev = mReflexVertices.end(); v != ev ; ++ v ) 01288 if ( !IsProcessed(*v) ) 01289 InsertNextSplitEventInPQ(*v); 01290 } 01291 01292 template<class Gt, class Ss, class V> 01293 void Straight_skeleton_builder_2<Gt,Ss,V>::Propagate() 01294 { 01295 CGAL_STSKEL_BUILDER_TRACE(0,"Propagating events..."); 01296 mVisitor.on_propagation_started(); 01297 01298 for (;;) 01299 { 01300 InsertNextSplitEventsInPQ(); 01301 01302 if ( !mPQ.empty() ) 01303 { 01304 EventPtr lEvent = PopEventFromPQ(); 01305 01306 if ( lEvent->type() != Event::cEdgeEvent ) 01307 AllowNextSplitEvent(lEvent->seed0()); 01308 01309 if ( !IsProcessed(lEvent) ) 01310 { 01311 CGAL_STSKEL_BUILDER_TRACE (1,"\nS" << mStepID << " Event: " << *lEvent ) ; 01312 01313 SetEventTimeAndPoint(*lEvent) ; 01314 01315 switch ( lEvent->type() ) 01316 { 01317 case Event::cEdgeEvent : HandleEdgeEvent (lEvent) ; break ; 01318 case Event::cSplitEvent : HandleSplitOrPseudoSplitEvent(lEvent) ; break ; 01319 case Event::cPseudoSplitEvent: HandlePseudoSplitEvent (lEvent) ; break ; 01320 } 01321 01322 ++ mStepID ; 01323 } 01324 } 01325 else break ; 01326 } 01327 01328 mVisitor.on_propagation_finished(); 01329 } 01330 01331 template<class Gt, class Ss, class V> 01332 void Straight_skeleton_builder_2<Gt,Ss,V>::MergeSplitNodes ( Vertex_handle_pair aSplitNodes ) 01333 { 01334 Vertex_handle lLNode, lRNode ; 01335 boost::tie(lLNode,lRNode)=aSplitNodes; 01336 01337 Halfedge_handle lIBisectorL1 = lLNode->primary_bisector()->opposite(); 01338 Halfedge_handle lIBisectorR1 = lRNode->primary_bisector()->opposite(); 01339 Halfedge_handle lIBisectorL2 = lIBisectorL1->next()->opposite(); 01340 Halfedge_handle lIBisectorR2 = lIBisectorR1->next()->opposite(); 01341 01342 CGAL_STSKEL_BUILDER_TRACE(2 01343 ,"Merging SplitNodes: (L) N" << lLNode->id() << " and (R) N" << lRNode->id() << ".\n" 01344 << " LOut: B" << lLNode->primary_bisector()->id() << '\n' 01345 << " ROut: B" << lRNode->primary_bisector()->id() << '\n' 01346 << " LIn1: B" << lIBisectorL1->id() << '\n' 01347 << " RIn1: B" << lIBisectorR1->id() << '\n' 01348 << " LIn2: B" << lIBisectorL2->id() << '\n' 01349 << " RIn2: B" << lIBisectorR2->id() 01350 ); 01351 01352 if ( lIBisectorL1->vertex() == lRNode ) 01353 lIBisectorL1->HBase_base::set_vertex(lLNode); 01354 01355 if ( lIBisectorR1->vertex() == lRNode ) 01356 lIBisectorR1->HBase_base::set_vertex(lLNode); 01357 01358 if ( lIBisectorL2->vertex() == lRNode ) 01359 lIBisectorL2->HBase_base::set_vertex(lLNode); 01360 01361 if ( lIBisectorR2->vertex() == lRNode ) 01362 lIBisectorR2->HBase_base::set_vertex(lLNode); 01363 01364 CGAL_STSKEL_BUILDER_TRACE(2 01365 , " N" << lRNode->id() << " removed.\n" 01366 << " LIn1 B" << lIBisectorL1->id() << " now linked to N" << lIBisectorL1->vertex()->id() << '\n' 01367 << " RIn1 B" << lIBisectorR1->id() << " now linked to N" << lIBisectorR1->vertex()->id() << '\n' 01368 << " LIn2 B" << lIBisectorL2->id() << " now linked to N" << lIBisectorL2->vertex()->id() << '\n' 01369 << " RIn2 B" << lIBisectorR2->id() << " now linked to N" << lIBisectorR2->vertex()->id() 01370 ); 01371 01372 EraseNode(lRNode); 01373 } 01374 01375 01376 template<class Gt, class Ss, class V> 01377 void Straight_skeleton_builder_2<Gt,Ss,V>::EraseNode ( Vertex_handle aNode ) 01378 { 01379 aNode->VBase::reset_id__internal__(-aNode->id()); 01380 mSSkel->SSkel::Base::vertices_erase(aNode); 01381 } 01382 01383 #ifdef CGAL_STRAIGHT_SKELETON_ENABLE_TRACE 01384 template<class Halfedge_handle> 01385 void TraceMultinode( char const* t, Halfedge_handle b, Halfedge_handle e ) 01386 { 01387 std::ostringstream ss ; 01388 ss << t ; 01389 01390 do 01391 { 01392 ss << "B" << b->id() << " N" << b->vertex()->id() << " " ; 01393 } 01394 while ( b = b->next(), b != e ) ; 01395 01396 std::string s = ss.str(); 01397 CGAL_STSKEL_BUILDER_TRACE(0, s); 01398 } 01399 01400 01401 template<class Point> 01402 double angle_wrt_X ( Point const& a, Point const& b ) 01403 { 01404 double dx = to_double(b.x() - a.x() ) ; 01405 double dy = to_double(b.y() - a.y() ) ; 01406 double atan = std::atan2(dy,dx); 01407 double rad = atan >= 0.0 ? atan : 2.0 * 3.141592 + atan ; 01408 double deg = rad * 180.0 / 3.141592 ; 01409 return deg ; 01410 } 01411 01412 template<class Vertex_handle, class Halfedge_around_vertex_circulator> 01413 void TraceFinalBisectors( Vertex_handle v, Halfedge_around_vertex_circulator cb ) 01414 { 01415 Halfedge_around_vertex_circulator c = cb ; 01416 01417 do 01418 { 01419 double phi = angle_wrt_X((*c)->vertex()->point(),(*c)->opposite()->vertex()->point()); 01420 01421 CGAL_STSKEL_BUILDER_TRACE(2, " N" << v->id() << " in=B" << (*c)->id() 01422 << " E" << (*c)->defining_contour_edge()->id() 01423 << " out=B" << (*c)->opposite()->id() 01424 << " E" << (*c)->opposite()->defining_contour_edge()->id() 01425 << " phi=" << phi 01426 ); 01427 01428 ++ c ; 01429 } 01430 while( c != cb ) ; 01431 01432 } 01433 #endif 01434 01435 template<class Vertex_handle, class Halfedge_around_vertex_circulator> 01436 bool ValidateFinalBisectorsAfterMerge( Vertex_handle /* v */, Halfedge_around_vertex_circulator cb ) 01437 { 01438 bool rOK = true ; 01439 01440 Halfedge_around_vertex_circulator c = cb ; 01441 01442 do 01443 { 01444 if ( (*c)->defining_contour_edge() != (*c)->prev()->defining_contour_edge() ) 01445 rOK = false ; 01446 01447 ++ c ; 01448 } 01449 while( rOK && c != cb ) ; 01450 01451 return rOK ; 01452 01453 } 01454 01455 template<class Gt, class Ss, class V> 01456 void Straight_skeleton_builder_2<Gt,Ss,V>::RelinkBisectorsAroundMultinode( Vertex_handle const& v0, Halfedge_handle_vector& aLinks ) 01457 { 01458 CGAL_assertion( aLinks.size() > 0 ) ; 01459 01460 CGAL_STSKEL_BUILDER_TRACE(4, "Relinking " << aLinks.size() << " bisectors around N" << v0->id() ) ; 01461 01462 // Connect the bisectors with each other following the CCW ordering 01463 01464 Halfedge_handle first_he = aLinks.front(); 01465 Halfedge_handle prev_he = first_he ; 01466 01467 first_he->HBase_base::set_vertex(v0); 01468 01469 for ( typename Halfedge_handle_vector::iterator i = successor(aLinks.begin()), ei = aLinks.end(); i != ei ; ++ i ) 01470 { 01471 Halfedge_handle he = *i ; 01472 01473 he->HBase_base::set_vertex(v0); 01474 01475 Halfedge_handle prev_he_opp = prev_he->opposite(); 01476 01477 he ->HBase_base::set_next(prev_he_opp); 01478 prev_he_opp->HBase_base::set_prev(he); 01479 01480 CGAL_STSKEL_BUILDER_TRACE(4, "Relinking B" << he->id() << "->B" << prev_he_opp->id() ) ; 01481 01482 prev_he = he ; 01483 } 01484 01485 Halfedge_handle prev_he_opp = prev_he->opposite(); 01486 01487 first_he ->HBase_base::set_next(prev_he_opp); 01488 prev_he_opp->HBase_base::set_prev(first_he); 01489 01490 CGAL_STSKEL_BUILDER_TRACE(4, "Relinking B" << first_he->id() << "->B" << prev_he_opp->id() ) ; 01491 01492 // Reset the main halfedge for v0 01493 v0->VBase::set_halfedge(first_he) ; 01494 01495 CGAL_STSKEL_DEBUG_CODE( TraceFinalBisectors(v0,v0->halfedge_around_vertex_begin()); ) 01496 01497 CGAL_postcondition( ValidateFinalBisectorsAfterMerge(v0,v0->halfedge_around_vertex_begin()) ) ; 01498 } 01499 01500 01501 template<class Gt, class Ss, class V> 01502 void Straight_skeleton_builder_2<Gt,Ss,V>::PreprocessMultinode( Multinode& aMN ) 01503 { 01504 // 01505 // A Multinode is a run of coincident nodes along a face. 01506 // Its represented by a pair of halfedges describing a linear profile. 01507 // The first halfedge in the pair points to the first node in the multinode. 01508 // Each ->next() halfedge in the profile points to a subsequent node. 01509 // The second halfedge in the pair is past-the-end (it points to the first node around the face that IS NOT part of the multinode) 01510 // 01511 01512 Halfedge_handle oend = validate(aMN.end->opposite()); 01513 01514 Halfedge_handle h = aMN.begin ; 01515 01516 aMN.bisectors_to_relink.push_back(h); 01517 01518 // Traverse the profile collecting: 01519 // The nodes to be removed from the HDS (all but the first) 01520 // The bisectors to be removed from the HDS (each bisector pointing to the next node in the multinode) 01521 // The bisectors around each node that must be relinked to the first node (which will be kept in place of the multinode) 01522 do 01523 { 01524 ++ aMN.size ; 01525 Halfedge_handle nx = validate(h->next()); 01526 if ( nx != aMN.end ) 01527 aMN.bisectors_to_remove.push_back(nx); 01528 01529 // Since each halfedge "h" in this lineal profile corresponds to a single face, all the bisectors around 01530 // each node which must be relinked are those found ccw between h and h->next() 01531 Halfedge_handle ccw = h ; 01532 Halfedge_handle ccw_end = validate(h->next()->opposite()); 01533 for(;;) 01534 { 01535 ccw = validate(ccw->opposite()->prev()) ; 01536 if ( ccw != ccw_end ) 01537 aMN.bisectors_to_relink.push_back(ccw); 01538 else break ; 01539 } 01540 if ( h != aMN.begin ) 01541 { 01542 aMN.nodes_to_remove.push_back(h->vertex()); 01543 } 01544 01545 h = nx; 01546 } 01547 while ( h != aMN.end ) ; 01548 01549 aMN.bisectors_to_relink.push_back(aMN.end->opposite()); 01550 01551 CGAL_STSKEL_DEBUG_CODE( TraceMultinode("Preprocessing multinode: ", aMN.begin,aMN.end) ) ; 01552 } 01553 01554 // 01555 // Replaces a run of coincident nodes with a single one by removing all but the first, remvong node-to-node bisectors and 01556 // relinking the other bisectors. 01557 // 01558 template<class Gt, class Ss, class V> 01559 void Straight_skeleton_builder_2<Gt,Ss,V>::ProcessMultinode( Multinode& aMN 01560 , Halfedge_handle_vector& rBisectorsToRemove 01561 , Vertex_handle_vector& rNodesToRemove 01562 ) 01563 { 01564 bool lDoNotProcess = false ; 01565 01566 Halfedge_handle h = aMN.begin ; 01567 01568 do 01569 { 01570 if ( h->vertex()->has_infinite_time() || IsExcluded(h->vertex())) 01571 lDoNotProcess = true ; 01572 } 01573 while ( h = h->next(), !lDoNotProcess && h != aMN.end ) ; 01574 01575 if ( !lDoNotProcess ) 01576 { 01577 CGAL_STSKEL_DEBUG_CODE( TraceMultinode("Processing multinode: ", aMN.begin,aMN.end) ) ; 01578 01579 Halfedge_handle h = aMN.begin ; 01580 do 01581 { 01582 Exclude(h->vertex()); 01583 } 01584 while ( h = h->next(), h != aMN.end ) ; 01585 01586 std::copy(aMN.bisectors_to_remove.begin(), aMN.bisectors_to_remove.end(), std::back_inserter(rBisectorsToRemove)); 01587 01588 for( Vertex_handle_vector_iterator vi = aMN.nodes_to_remove.begin(), evi = aMN.nodes_to_remove.end() ; vi != evi ; ++ vi ) 01589 rNodesToRemove.push_back(*vi) ; 01590 01591 RelinkBisectorsAroundMultinode(aMN.v,aMN.bisectors_to_relink); 01592 } 01593 } 01594 01595 01596 template<class Gt, class Ss, class V> 01597 typename Straight_skeleton_builder_2<Gt,Ss,V>::MultinodePtr 01598 Straight_skeleton_builder_2<Gt,Ss,V>::CreateMultinode( Halfedge_handle begin, Halfedge_handle end ) 01599 { 01600 return MultinodePtr( new Multinode(begin,end) ); 01601 } 01602 01603 01604 // 01605 // Finds coincident skeleton nodes and merge them 01606 // 01607 // If moving edges Ei,Ej collide with moving edge Ek causing Ej to collapse, Ei and Ek becomes consecutive and a new 01608 // polygon vertex (Ei,Ek) appears in the wavefront. 01609 // If moving edges Ei,Ej collide with moving edge Ek causing Ek to be split in two halves, L(Ek) amd R(Ek) resp, two new 01610 // polygon vertices appears in the wavefront; namely: (Ei,R(Ek)) and (L(Ek),Ej)) 01611 // If moving edge Ei,Ej collide with both Ek,El simultaneously causing the edges to cross-connect, two new vertices 01612 // (Ei,Ek) and (El,Ej) appear in the wavefront. 01613 // 01614 // In all those 3 cases, each new polygon vertex is represented in the straight skeleton as a skeleton node. 01615 // Every skeleton node is describing the coallision of at least 3 edges (called the "defining edges" of the node) 01616 // and it has at least 3 incident bisectors, each one pairing 2 out of the total number of defining egdes. 01617 // 01618 // Any skeleton node has a degree of at least 3, but if more than 3 edges collide simultaneously, the corresponding 01619 // skeleton node has a higher degree. (the degree of the node is exactly the number of colliding edges) 01620 // 01621 // However, the algorithm handles the coallison of 3 edges at a time so each skeleton node initially created 01622 // has degree exactly 3 so this function which detects higher degree nodes and merge them into a single node 01623 // of the proper degree is needed. 01624 // 01625 // Two skeleton nodes are "coincident" IFF they have 2 defining edges in common and each triedge of edges collide 01626 // at the same time and point. IOW, 2 nodes are coincident if they represent the simultaneous 01627 // coallison of exactly 4 edges (the union of 2 triedges with 2 common elements is a set of 4). 01628 // 01629 template<class Gt, class Ss, class V> 01630 void Straight_skeleton_builder_2<Gt,Ss,V>::MergeCoincidentNodes() 01631 { 01632 // 01633 // NOTE: This code might be executed on a topologically incosistent HDS, thus the need to check 01634 // the structure along the way. 01635 // 01636 01637 CGAL_STSKEL_BUILDER_TRACE(0, "Merging coincident nodes..."); 01638 01639 // ALGORITHM DESCRIPTION: 01640 // 01641 // While circulating the bisectors along the face for edge Ei we find all those edges E* which 01642 // are or become consecutive to Ei during the wavefront propagation. Each bisector along the face: 01643 // (Ei,Ea), (Ei,Eb), (Ei,Ec), etcc pairs Ei with such other edge. 01644 // Between one bisector (Ei,Ea) and the next (Ei,Eb) there is skeleton node which represents 01645 // the coallision between the 3 edges (Ei,Ea,Eb). 01646 // It follows from the pairing that any skeleton node Ni, for example (Ei,Ea,Eb), neccesarily 01647 // shares two edges (Ei and Eb precisely) with any next skeleton node Ni+1 around the face. 01648 // That is, the triedge of defining edges that correspond to each skeleton node around the face follow this 01649 // sequence: (Ei,Ea,Eb), (Ei,Eb,Ec), (Ei,Ec,Ed), ... 01650 // 01651 // Any 2_ consecutive_ skeleton nodes around a face share 2 out of the 3 defining edges, which is one of the 01652 // neccesary conditions for "coincidence". Therefore, coincident nodes can only come as consecutive along a face 01653 // 01654 01655 MultinodeVector lMultinodes ; 01656 01657 for( Face_iterator fit = mSSkel->SSkel::Base::faces_begin(); fit != mSSkel->SSkel::Base::faces_end(); ++fit) 01658 { 01659 // 'h' is the first (CCW) skeleton halfedge. 01660 Halfedge_handle h = validate(validate(fit->halfedge())->next()); 01661 01662 CGAL_assertion ( h->is_bisector() ) ; 01663 01664 // 'last' is the last (CCW) skeleton halfedge 01665 Halfedge_handle last = validate(fit->halfedge()->prev()) ; 01666 01667 CGAL_assertion ( last->is_bisector() ) ; 01668 CGAL_assertion ( last->vertex()->is_contour() ) ; 01669 01670 Halfedge_handle h0 = h ; 01671 Vertex_handle v0 = validate(h0->vertex()) ; 01672 01673 if ( ! v0->has_infinite_time() ) 01674 { 01675 CGAL_assertion ( v0->is_skeleton() ) ; 01676 01677 h = validate(h->next()) ; 01678 01679 while ( h != last ) 01680 { 01681 Vertex_handle v = validate(h->vertex()); 01682 01683 if ( ! v->has_infinite_time() ) 01684 { 01685 CGAL_assertion ( v->is_skeleton() ) ; 01686 01687 if ( !AreSkeletonNodesCoincident(v0,v) ) 01688 { 01689 if ( h0->next() != h ) 01690 lMultinodes.push_back( CreateMultinode(h0,h) ); 01691 01692 v0 = v ; 01693 h0 = h ; 01694 } 01695 } 01696 01697 h = validate(h->next()); 01698 } 01699 01700 if ( h0->next() != h ) 01701 lMultinodes.push_back( CreateMultinode(h0,h) ); 01702 } 01703 } 01704 01705 // 01706 // The merging loop removes all but one of the coincident skeleton nodes and the halfedges between them. 01707 // But it can't physically erase those from the HDS while looping, so the nodes/bisector to erase 01708 // are collected in these sequences are erased after the merging loop. 01709 // 01710 Halfedge_handle_vector lBisectorsToRemove ; 01711 Vertex_handle_vector lNodesToRemove ; 01712 01713 for ( typename MultinodeVector::iterator it = lMultinodes.begin(), eit = lMultinodes.end() ; it != eit ; ++ it ) 01714 PreprocessMultinode(**it); 01715 01716 std::sort(lMultinodes.begin(), lMultinodes.end(), MultinodeComparer()); 01717 01718 for ( typename MultinodeVector::iterator it = lMultinodes.begin(), eit = lMultinodes.end() ; it != eit ; ++ it ) 01719 ProcessMultinode(**it,lBisectorsToRemove,lNodesToRemove); 01720 01721 for( Halfedge_handle_vector_iterator hi = lBisectorsToRemove.begin(), ehi = lBisectorsToRemove.end() ; hi != ehi ; ++ hi ) 01722 { 01723 CGAL_STSKEL_BUILDER_TRACE(1, "B" << (*hi)->id() << " removed."); 01724 (*hi)->HBase_base::reset_id(-1); 01725 mSSkel->SSkel::Base::edges_erase(*hi); 01726 } 01727 01728 for( Vertex_handle_vector_iterator vi = lNodesToRemove.begin(), evi = lNodesToRemove.end() ; vi != evi ; ++ vi ) 01729 EraseNode(*vi); 01730 } 01731 01732 template<class Gt, class Ss, class V> 01733 bool Straight_skeleton_builder_2<Gt,Ss,V>::FinishUp() 01734 { 01735 CGAL_STSKEL_BUILDER_TRACE(0, "\n\nFinishing up..."); 01736 01737 mVisitor.on_cleanup_started(); 01738 01739 std::for_each( mSplitNodes.begin() 01740 ,mSplitNodes.end () 01741 ,boost::bind(&Straight_skeleton_builder_2<Gt,Ss,V>::MergeSplitNodes,this,_1) 01742 ) ; 01743 01744 std::for_each( mDanglingBisectors.begin() 01745 ,mDanglingBisectors.end () 01746 ,boost::bind(&Straight_skeleton_builder_2<Gt,Ss,V>::EraseBisector,this,_1) 01747 ) ; 01748 01749 MergeCoincidentNodes(); 01750 01751 mVisitor.on_cleanup_finished(); 01752 01753 return mSSkel->is_valid() ; 01754 } 01755 01756 template<class Gt, class Ss, class V> 01757 bool Straight_skeleton_builder_2<Gt,Ss,V>::Run() 01758 { 01759 InitPhase(); 01760 Propagate(); 01761 return FinishUp(); 01762 } 01763 01764 template<class Gt, class Ss, class V> 01765 typename Straight_skeleton_builder_2<Gt,Ss,V>::SSkelPtr Straight_skeleton_builder_2<Gt,Ss,V>::construct_skeleton( bool aNull_if_failed ) 01766 { 01767 bool ok = false ; 01768 01769 try 01770 { 01771 ok = Run() ; 01772 } 01773 catch( std::exception const& e ) 01774 { 01775 mVisitor.on_error ( e.what() ) ; 01776 CGAL_STSKEL_BUILDER_TRACE(0,"EXCEPTION THROWN (" << e.what() << ") during straight skeleton construction."); 01777 } 01778 catch(...) 01779 { 01780 mVisitor.on_error ( "Unhandled exception" ) ; 01781 CGAL_STSKEL_BUILDER_TRACE(0,"UNHANDLED EXCEPTION during straight skeleton construction."); 01782 } 01783 01784 if ( !ok ) 01785 { 01786 CGAL_STSKEL_BUILDER_TRACE(0,"Invalid result."); 01787 if ( aNull_if_failed ) 01788 mSSkel = SSkelPtr() ; 01789 } 01790 01791 mVisitor.on_algorithm_finished(ok); 01792 01793 return mSSkel ; 01794 } 01795 01796 CGAL_END_NAMESPACE 01797 01798 #if defined(BOOST_MSVC) 01799 # pragma warning(pop) 01800 #endif 01801 01802 #endif // CGAL_STRAIGHT_SKELETON_BUILDER_2_IMPL_H // 01803 // EOF //
1.7.6.1