Refresh priority queues before calling top() if simultaneous events are present

This commit is contained in:
Mael Rouxel-Labbé 2020-11-09 18:22:33 +01:00
parent 770b7f7a28
commit 7385ebb806
2 changed files with 34 additions and 5 deletions

View File

@ -42,7 +42,6 @@ Straight_skeleton_builder_2<Gt,Ss,V>::Straight_skeleton_builder_2 ( boost::optio
: :
mTraits(aTraits) mTraits(aTraits)
,mVisitor(aVisitor) ,mVisitor(aVisitor)
,mSplitEventCompare(this)
,mEventCompare(this) ,mEventCompare(this)
,mVertexID(0) ,mVertexID(0)
,mEdgeID(0) ,mEdgeID(0)

View File

@ -518,7 +518,7 @@ public:
: public CGAL::cpp98::binary_function<bool,EventPtr,EventPtr> : public CGAL::cpp98::binary_function<bool,EventPtr,EventPtr>
{ {
public: public:
Split_event_compare ( Self* aBuilder ) : mBuilder(aBuilder) {} Split_event_compare ( Self* aBuilder, Vertex_handle aV ) : mBuilder(aBuilder), mV(aV) {}
bool operator() ( EventPtr const& aA, EventPtr const& aB ) const bool operator() ( EventPtr const& aA, EventPtr const& aB ) const
{ {
@ -532,6 +532,10 @@ public:
return ( res == LARGER ) ; return ( res == LARGER ) ;
} }
// There are simultaneous events, we will need to refresh the queue before calling top()
// see PopNextSplitEvent()
mBuilder->GetVertexData(mV).mHasSimultaneousEvents = true ;
// Priority queue comparison: `A` has higher priority than `B` if `operator()(A, B)` is `false`. // Priority queue comparison: `A` has higher priority than `B` if `operator()(A, B)` is `false`.
// We want to give priority to smaller angles, so we must return `false` if the angle is smaller // We want to give priority to smaller angles, so we must return `false` if the angle is smaller
// i.e. `true` if the angle is larger // i.e. `true` if the angle is larger
@ -543,6 +547,7 @@ public:
private: private:
Self* mBuilder ; Self* mBuilder ;
const Vertex_handle mV ;
} ; } ;
typedef std::priority_queue<EventPtr,std::vector<EventPtr>,Split_event_compare> SplitPQ ; typedef std::priority_queue<EventPtr,std::vector<EventPtr>,Split_event_compare> SplitPQ ;
@ -559,6 +564,7 @@ public:
, mPrevInLAV(-1) , mPrevInLAV(-1)
, mNextInLAV(-1) , mNextInLAV(-1)
, mNextSplitEventInMainPQ(false) , mNextSplitEventInMainPQ(false)
, mHasSimultaneousEvents(false)
, mSplitEvents(aComparer) , mSplitEvents(aComparer)
{} {}
@ -569,7 +575,8 @@ public:
bool mIsExcluded ; bool mIsExcluded ;
int mPrevInLAV ; int mPrevInLAV ;
int mNextInLAV ; int mNextInLAV ;
bool mNextSplitEventInMainPQ; bool mNextSplitEventInMainPQ ;
bool mHasSimultaneousEvents ;
SplitPQ mSplitEvents ; SplitPQ mSplitEvents ;
Triedge mTriedge ; // Here, E0,E1 corresponds to the vertex (unlike *event* triedges) Triedge mTriedge ; // Here, E0,E1 corresponds to the vertex (unlike *event* triedges)
Trisegment_2_ptr mTrisegment ; // Skeleton nodes cache the full trisegment tree that defines the originating event Trisegment_2_ptr mTrisegment ; // Skeleton nodes cache the full trisegment tree that defines the originating event
@ -597,7 +604,7 @@ private :
void InitVertexData( Vertex_handle aV ) void InitVertexData( Vertex_handle aV )
{ {
mVertexData.push_back( Vertex_data_ptr( new Vertex_data(aV,mSplitEventCompare) ) ) ; mVertexData.push_back( Vertex_data_ptr( new Vertex_data(aV, Split_event_compare(this, aV) ) ) ) ;
} }
Vertex_data const& GetVertexData( Vertex_const_handle aV ) const Vertex_data const& GetVertexData( Vertex_const_handle aV ) const
@ -807,6 +814,30 @@ private :
SplitPQ& lPQ = lData.mSplitEvents ; SplitPQ& lPQ = lData.mSplitEvents ;
if ( !lPQ.empty() ) if ( !lPQ.empty() )
{ {
// When there are simultaneous split events, we sort them to handle nearby pseudo split events
// together as to avoid multiple fronts crossing each other without seeing
// and creating an invalid SLS.
//
// Unfortunately, the way that this sorting is performed requires knowing whether an event
// is a pseudo split, and requires looking into the LAV tree. More annoyingly, whether an event
// exists or not (see calls to handle_assigned(lOpp) and such) can change, which will
// change the position of the item in the split priority queue (as an invalid event is
// at the bottom of the priority queue).
//
// Consequently, when a simultaneous event has been detected, we need to refresh the queue
// to get the real top.
//
// In practice, things are usually fine with a roughly-correct priority queue because an
// invalid event being popped will just be ignored, but MSVC 2015-Debug is a very zealous
// compiler that checks that the full queue is sane when it pops() and will detect this kind
// of unimportant inconsistencies...
if ( lData.mHasSimultaneousEvents )
{
std::make_heap(const_cast<EventPtr*>(&lPQ.top()),
const_cast<EventPtr*>(&lPQ.top()) + lPQ.size(),
Split_event_compare(this, aV));
}
rEvent = lPQ.top(); rEvent = lPQ.top();
lPQ.pop(); lPQ.pop();
lData.mNextSplitEventInMainPQ = true ; lData.mNextSplitEventInMainPQ = true ;
@ -1102,7 +1133,6 @@ private:
Vertex_handle_pair_vector mSplitNodes ; Vertex_handle_pair_vector mSplitNodes ;
Split_event_compare mSplitEventCompare ;
Event_compare mEventCompare ; Event_compare mEventCompare ;
int mVertexID ; int mVertexID ;