Fix taking the middle of the gap between e2 and e0 as seed of the bissector

See code for more information.
This commit is contained in:
Mael Rouxel-Labbé 2020-11-27 13:54:22 +01:00
parent c502e935f9
commit 7d311d3ad5
5 changed files with 99 additions and 5 deletions

View File

@ -96,12 +96,66 @@ Straight_skeleton_builder_2<Gt,Ss,V>::FindEdgeEvent( Vertex_handle aLNode, Verte
{
EventPtr rResult ;
CGAL_STSKEL_BUILDER_TRACE(4, "FindEdgeEvent(), Left/Right Nodes: N" << aLNode->id() << " N" << aRNode->id() ) ;
Triedge lTriedge = GetVertexTriedge(aLNode) & GetVertexTriedge(aRNode) ;
if ( lTriedge.is_valid() && lTriedge != aPrevEventTriedge )
{
Trisegment_2_ptr lTrisegment = CreateTrisegment(lTriedge,aLNode,aRNode);
// The 02 collinearity configuration is problematic: 01 or 12 collinearity has a seed position
// giving the point through which the bissector passes. However, for 02, it is not a given.
//
// If the seed exists, the information is passed to the traits as the "third" child of the trisegment.
// Otherwise, ignore this as it should re-appear when the seed of 02 is created.
if ( lTrisegment->collinearity() == TRISEGMENT_COLLINEARITY_02 )
{
// Check in the SLAV if the seed corresponding to 02 exists
std::cout << "EdgeEvent 02" << std::endl ;
// Note that this is only for edge events; (pseudo-)split events are not concerned.
Vertex_handle lPrevNode = GetPrevInLAV(aLNode) ;
CGAL_assertion( GetEdgeStartingAt(lPrevNode) == lTriedge.e0() ) ;
if ( GetEdgeEndingAt(lPrevNode) == lTriedge.e2() )
{
// Note that this can be a contour node and in that case GetTrisegment is null and we get
// the middle point, but in that case e2 and e0 are consecutive in the input
// and the middle point is the common extremity and things are fine.
lTrisegment->set_child_t( GetTrisegment(lPrevNode) ) ;
}
else
{
Orientation lOrientationS = CGAL::orientation( lTrisegment->e0().source(), lTrisegment->e0().target(), lTrisegment->e1().source() ) ;
Orientation lOrientationT = CGAL::orientation( lTrisegment->e0().source(), lTrisegment->e0().target(), lTrisegment->e1().target() ) ;
if ( lOrientationS != LEFT_TURN && lOrientationT != LEFT_TURN )
{
// Reasonning is: if the middle halfedge (e1) is "below" e0 and e2, then there is some
// kind of concavity in between e0 and e2. This concavity will resolve itself and either:
// - e0 and e2 will never meet, but in that case we would not be here
// - e0 and e2 will meet. In that case, we can ignore all the details of the concavity
// and simply consider that in the end, all that matters is the e0, e2, next(e0),
// and prev(e2). In that case, we get two bisectors issued from e0 and e2, and one
// bissector issued from some seed S and splitting next(e0) and prev(e2). This can also
// be seen as two exterior bissectors and one interior bissector of a triangle
// target(e0) -- S - source(e2). It is a known result that these three bissectors
// meet in a single point. Thus, when we get here e0-e1-e2, we know that
// these will meet in a single, existing point, either the left or the right child (the oldest).
if ( CompareEvents(aLNode, aRNode) == SMALLER )
lTrisegment->set_child_t( GetTrisegment(aRNode) ) ;
else
lTrisegment->set_child_t( GetTrisegment(aLNode) ) ;
}
else
{
return rResult;
}
}
}
if ( ExistEvent(lTrisegment) )
{
Comparison_result lLNodeD = CompareEvents(lTrisegment,aLNode) ;

View File

@ -403,6 +403,9 @@ struct SS_converter : Converter
if ( tri->child_r() )
res->set_child_r( cvt_trisegment(tri->child_r() ) ) ;
if ( tri->child_t() )
res->set_child_t( cvt_trisegment(tri->child_t() ) ) ;
}
return res ;

View File

@ -899,6 +899,35 @@ private :
: LARGER ;
}
Comparison_result CompareEvents( Vertex_handle aLNode, Vertex_handle aRNode ) const
{
if ( aLNode->is_skeleton() )
{
if ( aRNode->is_skeleton() )
{
if ( aLNode->has_infinite_time() && aRNode->has_infinite_time() )
return EQUAL ;
else if ( aLNode->has_infinite_time() )
return LARGER ;
else if ( aRNode->has_infinite_time() )
return SMALLER ;
else
return CompareEvents ( GetTrisegment(aLNode), GetTrisegment(aRNode) ) ;
}
else // left skeleton, right not skeleton
{
return LARGER ;
}
}
else // left not skeleton
{
if ( aRNode->is_skeleton() )
return SMALLER ;
else // both not skeleton
return EQUAL ;
}
}
bool AreEventsSimultaneous( Trisegment_2_ptr const& x, Trisegment_2_ptr const& y ) const
{
return Are_ss_events_simultaneous_2(mTraits)(x,y) ;

View File

@ -137,11 +137,13 @@ public:
Self_ptr child_l() const { return mChildL ; }
Self_ptr child_r() const { return mChildR ; }
Self_ptr child_t() const { return mChildT ; }
void set_child_l( Self_ptr const& aChild ) { mChildL = aChild ; }
void set_child_r( Self_ptr const& aChild ) { mChildR = aChild ; }
void set_child_t( Self_ptr const& aChild ) { mChildT = aChild ; }
enum SEED_ID { LEFT, RIGHT, UNKNOWN } ;
enum SEED_ID { LEFT, RIGHT, THIRD } ;
// Indicates which of the seeds is collinear for a normal collinearity case.
// PRECONDITION: The collinearity is normal.
@ -149,7 +151,7 @@ public:
{
Trisegment_collinearity c = collinearity();
return c == TRISEGMENT_COLLINEARITY_01 ? LEFT : c == TRISEGMENT_COLLINEARITY_12 ? RIGHT : UNKNOWN ;
return c == TRISEGMENT_COLLINEARITY_01 ? LEFT : c == TRISEGMENT_COLLINEARITY_12 ? RIGHT : THIRD ;
}
friend std::ostream& operator << ( std::ostream& os, Self const& aTrisegment )
@ -198,6 +200,11 @@ private :
Self_ptr mChildL ;
Self_ptr mChildR ;
// this is the potential child of e2-e0, if it exists. It is used only in the configuration
// of e0 and e2 collinear as the common child gives where the bissector starts (as it is not
// necessarily the middle of the gap between e2 and e0).
Self_ptr mChildT ;
} ;
} // end namespace CGAL

View File

@ -414,9 +414,10 @@ compute_seed_pointC2 ( boost::intrusive_ptr< Trisegment_2<K, Segment_2_with_ID<K
: compute_oriented_midpoint(tri->e1(),tri->e2()) ;
break ;
case Trisegment_2::UNKNOWN :
case Trisegment_2::THIRD :
p = compute_oriented_midpoint(tri->e0(),tri->e2());
p = tri->child_t() ? construct_offset_lines_isecC2(tri->child_t(), aCoeff_cache) // this can recurse
: compute_oriented_midpoint(tri->e0(),tri->e2()) ;
break ;
}