BWAPI
SPAR/AIModule/BWTA/vendors/CGAL/CGAL/Straight_skeleton_2/Straight_skeleton_builder_2_impl.h
Go to the documentation of this file.
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 //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines