Harmonize speeds of collinear input segments + caching for non-filtered kernels

This commit is contained in:
Mael Rouxel-Labbé 2020-10-05 18:29:34 +02:00
parent 07750bd638
commit b6333ed459
10 changed files with 735 additions and 421 deletions

View File

@ -189,7 +189,7 @@ Straight_skeleton_builder_2<Gt,Ss,V>::IsPseudoSplitEvent( EventPtr const& aEvent
// contains aNode as a vertex. // contains aNode as a vertex.
// //
template<class Gt, class Ss, class V> template<class Gt, class Ss, class V>
void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvent( Vertex_handle aNode, Triedge const& aTriedge, boost::optional<FT> bound) void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvent( Vertex_handle aNode, Triedge const& aTriedge )
{ {
CGAL_STSKEL_BUILDER_TRACE(3, "Collect SplitEvent for N" << aNode->id() << " triedge: " << aTriedge); CGAL_STSKEL_BUILDER_TRACE(3, "Collect SplitEvent for N" << aNode->id() << " triedge: " << aTriedge);
@ -204,7 +204,8 @@ void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvent( Vertex_handle aNod
EventPtr lEvent = EventPtr( new SplitEvent (aTriedge,lTrisegment,aNode) ) ; EventPtr lEvent = EventPtr( new SplitEvent (aTriedge,lTrisegment,aNode) ) ;
// filter split event // filter split event
if (CanSafelyIgnoreSplitEvent(lEvent, bound)) return; if (CanSafelyIgnoreSplitEvent(lEvent))
return;
mVisitor.on_split_event_created(aNode) ; mVisitor.on_split_event_created(aNode) ;
@ -231,8 +232,7 @@ void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvents( Vertex_handle aNo
<< " LBorder: E" << lLBorder->id() << " RBorder: E" << lRBorder->id() << " LBorder: E" << lLBorder->id() << " RBorder: E" << lRBorder->id()
); );
boost::optional<FT> bound = ComputeUpperBoundForValidSplitEvents(GetPrevInLAV(aNode), aNode, GetNextInLAV(aNode),
UpperBoundForValidSplitEvents(GetPrevInLAV(aNode), aNode, GetNextInLAV(aNode),
mContourHalfedges.begin(), mContourHalfedges.end()); mContourHalfedges.begin(), mContourHalfedges.end());
for ( Halfedge_handle_vector_iterator i = mContourHalfedges.begin(); i != mContourHalfedges.end(); ++ i ) for ( Halfedge_handle_vector_iterator i = mContourHalfedges.begin(); i != mContourHalfedges.end(); ++ i )
@ -245,7 +245,7 @@ void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvents( Vertex_handle aNo
if ( lEventTriedge != aPrevEventTriedge ) if ( lEventTriedge != aPrevEventTriedge )
{ {
CollectSplitEvent(aNode, lEventTriedge, bound ) ; CollectSplitEvent(aNode, lEventTriedge) ;
} }
} }
} }
@ -556,11 +556,55 @@ void Straight_skeleton_builder_2<Gt,Ss,V>::CreateContourBisectors()
} }
} }
// @todo certify calls to K() instead of supposing exact predicates from K
template<class Gt, class Ss, class V>
void Straight_skeleton_builder_2<Gt,Ss,V>::HarmonizeSpeeds(boost::mpl::bool_<true>)
{
auto comparer = [&](Halfedge_handle lLH, Halfedge_handle lRH) -> bool
{
const Direction_2 lLD = CreateDirection(lLH) ;
const Direction_2 lRD = CreateDirection(lRH) ;
Comparison_result rRes = K().compare_angle_with_x_axis_2_object()(lLD, lRD) ;
if ( rRes == EQUAL )
{
if ( K().orientation_2_object()(lLH->vertex()->point(),
lLH->opposite()->vertex()->point(),
lRH->vertex()->point()) == EQUAL )
return false; // collinear
// parallel but not collinear, order arbitrarily (but consistently)
return K().less_xy_2_object()(lLH->vertex()->point(), lRH->vertex()->point()) ;
}
else
{
// not parallel
return ( rRes == SMALLER ) ;
}
} ;
typedef std::set<Halfedge_handle, decltype(comparer)> Ordered_halfedges;
Ordered_halfedges lOrdered_halfedges(comparer);
for( Face_iterator fit = mSSkel->SSkel::Base::faces_begin(); fit != mSSkel->SSkel::Base::faces_end(); ++fit)
{
Halfedge_handle lBorder = fit->halfedge() ;
Segment_2 lS = CreateSegment<Traits> ( lBorder ) ;
std::pair<typename Ordered_halfedges::iterator, bool> rRes = lOrdered_halfedges.insert ( lBorder ) ;
if ( ! rRes.second ) // some collinear edge is already in the set
mTraits.InitializeLineCoeffs ( lBorder->id(), (*rRes.first)->id() );
else
mTraits.InitializeLineCoeffs ( lS );
}
}
template<class Gt, class Ss, class V> template<class Gt, class Ss, class V>
void Straight_skeleton_builder_2<Gt,Ss,V>::InitPhase() void Straight_skeleton_builder_2<Gt,Ss,V>::InitPhase()
{ {
mVisitor.on_initialization_started(static_cast<int>(mSSkel->size_of_vertices())); mVisitor.on_initialization_started(static_cast<int>(mSSkel->size_of_vertices()));
CreateContourBisectors(); CreateContourBisectors();
HarmonizeSpeeds();
CreateInitialEvents(); CreateInitialEvents();
mVisitor.on_initialization_finished(); mVisitor.on_initialization_finished();
} }

View File

@ -186,7 +186,24 @@ class Rational
NT mN, mD ; NT mN, mD ;
} ; } ;
template <class K>
struct Segment_2_with_ID
: public Segment_2<K>
{
typedef Segment_2<K> Base;
typedef typename K::Point_2 Point_2;
public:
Segment_2_with_ID() : Base(), mID(-1) { }
Segment_2_with_ID(Base const& aS) : Base(aS), mID(-1) { }
Segment_2_with_ID(Base const& aS, const std::size_t aID) : Base(aS), mID(aID) { }
Segment_2_with_ID(Point_2 const& aP, Point_2 const& aQ, const std::size_t aID) : Base(aP, aQ), mID(aID) { }
public:
std::size_t mID;
};
// @fixme this has to somehow be documented for the traits concept to make sense
// //
// A straight skeleton event is the simultaneous collision of 3 offseted oriented straight line segments // A straight skeleton event is the simultaneous collision of 3 offseted oriented straight line segments
// e0*,e1*,e2* [e* denotes an _offseted_ edge]. // e0*,e1*,e2* [e* denotes an _offseted_ edge].
@ -211,21 +228,19 @@ class Rational
template<class K> template<class K>
class Trisegment_2 : public Ref_counted_base class Trisegment_2 : public Ref_counted_base
{ {
typedef CGAL_SS_i::Segment_2_with_ID<K> Segment_2_with_ID;
typedef Trisegment_2<K> Self;
public: public:
typedef typename K::Segment_2 Segment_2 ;
typedef boost::intrusive_ptr<Trisegment_2> Self_ptr ; typedef boost::intrusive_ptr<Trisegment_2> Self_ptr ;
public: Trisegment_2 ( Segment_2_with_ID const& aE0
, Segment_2_with_ID const& aE1
Trisegment_2 ( Segment_2 const& aE0 , Segment_2_with_ID const& aE2
, Segment_2 const& aE1
, Segment_2 const& aE2
, Trisegment_collinearity aCollinearity , Trisegment_collinearity aCollinearity
, std::size_t id , std::size_t aID
) )
: id(id) : mID(aID)
{ {
mCollinearity = aCollinearity ; mCollinearity = aCollinearity ;
@ -252,22 +267,25 @@ public:
} }
} }
std::size_t& id() { return mID; }
const std::size_t& id() const { return mID; }
static Trisegment_2 null() { return Self_ptr() ; } static Trisegment_2 null() { return Self_ptr() ; }
Trisegment_collinearity collinearity() const { return mCollinearity ; } Trisegment_collinearity collinearity() const { return mCollinearity ; }
Segment_2 const& e( unsigned idx ) const { CGAL_precondition(idx<3) ; return mE[idx] ; } Segment_2_with_ID const& e( unsigned idx ) const { CGAL_precondition(idx<3) ; return mE[idx] ; }
Segment_2 const& e0() const { return e(0) ; } Segment_2_with_ID const& e0() const { return e(0) ; }
Segment_2 const& e1() const { return e(1) ; } Segment_2_with_ID const& e1() const { return e(1) ; }
Segment_2 const& e2() const { return e(2) ; } Segment_2_with_ID const& e2() const { return e(2) ; }
// If 2 out of the 3 edges are collinear they can be reclassified as 1 collinear edge (any of the 2) and 1 non-collinear. // If 2 out of the 3 edges are collinear they can be reclassified as 1 collinear edge (any of the 2) and 1 non-collinear.
// These methods returns the edges according to that classification. // These methods returns the edges according to that classification.
// PRECONDITION: Exactly 2 out of 3 edges are collinear // PRECONDITION: Exactly 2 out of 3 edges are collinear
Segment_2 const& collinear_edge () const { return e(mCSIdx) ; } Segment_2_with_ID const& collinear_edge () const { return e(mCSIdx) ; }
Segment_2 const& non_collinear_edge() const { return e(mNCSIdx) ; } Segment_2_with_ID const& non_collinear_edge() const { return e(mNCSIdx) ; }
Segment_2 const& other_collinear_edge() const Segment_2_with_ID const& other_collinear_edge() const
{ {
switch ( mCollinearity ) switch ( mCollinearity )
{ {
@ -297,7 +315,7 @@ public:
return c == TRISEGMENT_COLLINEARITY_01 ? LEFT : c == TRISEGMENT_COLLINEARITY_12 ? RIGHT : UNKNOWN ; return c == TRISEGMENT_COLLINEARITY_01 ? LEFT : c == TRISEGMENT_COLLINEARITY_12 ? RIGHT : UNKNOWN ;
} }
friend std::ostream& operator << ( std::ostream& os, Trisegment_2<K> const& aTrisegment ) friend std::ostream& operator << ( std::ostream& os, Self const& aTrisegment )
{ {
return os << "[" << s2str(aTrisegment.e0()) return os << "[" << s2str(aTrisegment.e0())
<< " " << s2str(aTrisegment.e1()) << " " << s2str(aTrisegment.e1())
@ -335,11 +353,11 @@ public:
} }
} }
std::size_t id; std::size_t mID;
private : private :
Segment_2 mE[3]; Segment_2_with_ID mE[3];
Trisegment_collinearity mCollinearity ; Trisegment_collinearity mCollinearity ;
unsigned mCSIdx, mNCSIdx ; unsigned mCSIdx, mNCSIdx ;
@ -347,13 +365,72 @@ private :
Self_ptr mChildR ; Self_ptr mChildR ;
} ; } ;
template <class Info>
struct No_cache
{
bool IsCached ( std::size_t ) { return false; }
Info const& Get ( std::size_t )
{
CGAL_error();
return Info();
}
void Set ( std::size_t, Info const& ) { }
void Reset ( std::size_t ) { }
};
//TODO: call reserve, but how? #input vertices + n*m estimation?
template <class Info>
struct Info_cache
{
std::vector<Info> mValues ;
std::vector<bool> mAlreadyComputed ;
bool IsCached ( std::size_t i )
{
return ( (mAlreadyComputed.size() > i) && mAlreadyComputed[i] ) ;
}
Info const& Get(std::size_t i)
{
CGAL_precondition ( IsCached(i) ) ;
return mValues[i] ;
}
void Set ( std::size_t i, Info const& aValue)
{
if (mValues.size() <= i )
{
mValues.resize(i+1) ;
mAlreadyComputed.resize(i+1, false) ;
}
mAlreadyComputed[i] = true ;
mValues[i] = aValue ;
}
void Reset ( std::size_t i )
{
if ( IsCached(i) ) // needed if approx info is set but not exact info
mAlreadyComputed[i] = false ;
}
};
template <typename K>
using Time_cache = Info_cache< boost::optional< CGAL_SS_i::Rational< typename K::FT > > > ;
template <typename K>
using Coeff_cache = Info_cache< boost::optional< Line_2<K> > > ;
template<class K> template<class K>
struct Functor_base_2 struct Functor_base_2
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
typedef typename K::Point_2 Point_2 ; typedef typename K::Point_2 Point_2 ;
typedef typename K::Vector_2 Vector_2 ;
typedef typename K::Segment_2 Segment_2 ; typedef typename K::Segment_2 Segment_2 ;
typedef typename K::Vector_2 Vector_2 ;
typedef CGAL_SS_i::Segment_2_with_ID<K> Segment_2_with_ID ;
typedef CGAL_SS_i::Trisegment_2<K> Trisegment_2 ; typedef CGAL_SS_i::Trisegment_2<K> Trisegment_2 ;
@ -378,6 +455,9 @@ struct SS_converter : Converter
typedef typename Source_kernel::Segment_2 Source_segment_2 ; typedef typename Source_kernel::Segment_2 Source_segment_2 ;
typedef typename Target_kernel::Segment_2 Target_segment_2 ; typedef typename Target_kernel::Segment_2 Target_segment_2 ;
typedef Segment_2_with_ID<Source_kernel> Source_segment_2_with_ID ;
typedef Segment_2_with_ID<Target_kernel> Target_segment_2_with_ID ;
typedef Trisegment_2<Source_kernel> Source_trisegment_2 ; typedef Trisegment_2<Source_kernel> Source_trisegment_2 ;
typedef Trisegment_2<Target_kernel> Target_trisegment_2 ; typedef Trisegment_2<Target_kernel> Target_trisegment_2 ;
@ -416,7 +496,13 @@ struct SS_converter : Converter
return Target_vector_2(cvt_p(Source_point_2(CGAL::ORIGIN)), cvt_p(Source_point_2(CGAL::ORIGIN) + v) ) ; return Target_vector_2(cvt_p(Source_point_2(CGAL::ORIGIN)), cvt_p(Source_point_2(CGAL::ORIGIN) + v) ) ;
} }
Target_segment_2 cvt_s( Source_segment_2 const& e) const { return Target_segment_2(cvt_p(e.source()), cvt_p(e.target()) ) ; } Target_segment_2 cvt_s( Source_segment_2 const& e) const {
return Target_segment_2(cvt_p(e.source()), cvt_p(e.target())) ;
}
Target_segment_2_with_ID cvt_s( Source_segment_2_with_ID const& e) const {
return Target_segment_2_with_ID(cvt_p(e.source()), cvt_p(e.target()), e.mID) ;
}
Target_time_and_point_2 cvt_t_p( Source_time_and_point_2 const& v ) const Target_time_and_point_2 cvt_t_p( Source_time_and_point_2 const& v ) const
{ {
@ -434,7 +520,7 @@ struct SS_converter : Converter
,cvt_s(tri->e1()) ,cvt_s(tri->e1())
,cvt_s(tri->e2()) ,cvt_s(tri->e2())
,tri->collinearity() ,tri->collinearity()
,tri->id ,tri->id()
) )
) ; ) ;
} }
@ -473,6 +559,8 @@ struct SS_converter : Converter
Target_segment_2 operator()( Source_segment_2 const& s) const { return cvt_s(s); } Target_segment_2 operator()( Source_segment_2 const& s) const { return cvt_s(s); }
Target_segment_2_with_ID operator()( Source_segment_2_with_ID const& s) const { return cvt_s(s); }
Target_trisegment_2_ptr operator()( Source_trisegment_2_ptr const& tri ) const Target_trisegment_2_ptr operator()( Source_trisegment_2_ptr const& tri ) const
{ {
return cvt_trisegment(tri); return cvt_trisegment(tri);
@ -507,6 +595,7 @@ struct SS_converter : Converter
}; };
BOOST_MPL_HAS_XXX_TRAIT_DEF(Filters_split_events_tag) BOOST_MPL_HAS_XXX_TRAIT_DEF(Filters_split_events_tag)
BOOST_MPL_HAS_XXX_TRAIT_DEF(Segment_2_with_ID)
} // namespace CGAL_SS_i } // namespace CGAL_SS_i

View File

@ -251,10 +251,6 @@ private :
Vector_2 lV1 ( aEvent->point(), lEvent.seed0()->point() ); // @fixme ? is this correct? Vector_2 lV1 ( aEvent->point(), lEvent.seed0()->point() ); // @fixme ? is this correct?
Vector_2 lV2 ( aEvent->point(), aEvent->point() + CreateVector(aEvent->triedge().e2()) ) ; Vector_2 lV2 ( aEvent->point(), aEvent->point() + CreateVector(aEvent->triedge().e2()) ) ;
// std::cout << "aEvent->point(): " << aEvent->point() << std::endl;
// std::cout << "S LV1: " << lV1 << std::endl;
// std::cout << "S LV2: " << lV2 << std::endl;
return ComputeApproximateAngle(lV1, lV2) ; return ComputeApproximateAngle(lV1, lV2) ;
} }
@ -268,21 +264,15 @@ private :
if(lEvent.is_at_source_vertex()) if(lEvent.is_at_source_vertex())
{ {
// is_at_source_vertex <=> opposite node is seed0 // is_at_source_vertex <=> opposite node is seed0
// std::cout << "seed1: " << lEvent.seed1()->point() << std::endl;
lV1 = Vector_2( aEvent->point(), lEvent.seed1()->point() ); lV1 = Vector_2( aEvent->point(), lEvent.seed1()->point() );
lV2 = Vector_2( aEvent->point(), aEvent->point() + CreateVector(aEvent->triedge().e2()) ) ; lV2 = Vector_2( aEvent->point(), aEvent->point() + CreateVector(aEvent->triedge().e2()) ) ;
} }
else else
{ {
// std::cout << "seed0: " << lEvent.seed0()->point() << std::endl;
lV1 = Vector_2( aEvent->point(), lEvent.seed0()->point() ); lV1 = Vector_2( aEvent->point(), lEvent.seed0()->point() );
lV2 = Vector_2( aEvent->point(), aEvent->point() - CreateVector(aEvent->triedge().e2()) ) ; lV2 = Vector_2( aEvent->point(), aEvent->point() - CreateVector(aEvent->triedge().e2()) ) ;
} }
// std::cout << "aEvent->point(): " << aEvent->point() << std::endl;
// std::cout << "PS LV1: " << lV1 << std::endl;
// std::cout << "PS LV2: " << lV2 << std::endl;
return ComputeApproximateAngle(lV1, lV2) ; return ComputeApproximateAngle(lV1, lV2) ;
} }
@ -535,10 +525,6 @@ public:
{ {
CGAL_precondition( aA->type() != Event::cEdgeEvent || aB->type() != Event::cEdgeEvent ) ; CGAL_precondition( aA->type() != Event::cEdgeEvent || aB->type() != Event::cEdgeEvent ) ;
mBuilder->SetEventTimeAndPoint(*aA); // @fixme cache this
mBuilder->SetEventTimeAndPoint(*aB);
// Below is a bit redundant since we recompute (certified) times if events are not simultaneous
if ( ! mBuilder->AreEventsSimultaneous(aA,aB) ) if ( ! mBuilder->AreEventsSimultaneous(aA,aB) )
return ( mBuilder->CompareEvents(aA,aB) == LARGER ) ; return ( mBuilder->CompareEvents(aA,aB) == LARGER ) ;
@ -661,13 +647,30 @@ private :
GetHalfedgeLAVList(GetVertexData(aV).mTriedge.e0()).remove(aV); GetHalfedgeLAVList(GetVertexData(aV).mTriedge.e0()).remove(aV);
} }
Segment_2 CreateSegment ( Halfedge_const_handle aH ) const typename K::Segment_2 CreateRawSegment ( Halfedge_const_handle aH ) const
{ {
Point_2 s = aH->opposite()->vertex()->point() ; Point_2 s = aH->opposite()->vertex()->point() ;
Point_2 t = aH->vertex()->point() ; Point_2 t = aH->vertex()->point() ;
return K().construct_segment_2_object()(s,t); return K().construct_segment_2_object()(s,t);
} }
template <typename GT> // actually just equal to 'Traits', but gotta template for SFINAE to work
Segment_2 CreateSegment ( Halfedge_const_handle aH,
typename std::enable_if<
! CGAL_SS_i::has_Segment_2_with_ID<GT>::value>::type* = nullptr ) const
{
CGAL_assertion(false);
return Segment_2(CreateRawSegment(aH)) ;
}
template <typename GT> // actually just equal to 'Traits', but gotta template for SFINAE to work
Segment_2 CreateSegment ( Halfedge_const_handle aH,
typename std::enable_if<
CGAL_SS_i::has_Segment_2_with_ID<GT>::value>::type* = nullptr ) const
{
return Segment_2(CreateRawSegment(aH), aH->id());
}
Vector_2 CreateVector ( Halfedge_const_handle aH ) const Vector_2 CreateVector ( Halfedge_const_handle aH ) const
{ {
Point_2 s = aH->opposite()->vertex()->point() ; Point_2 s = aH->opposite()->vertex()->point() ;
@ -684,9 +687,9 @@ private :
{ {
CGAL_precondition(aTriedge.is_valid() && aTriedge.is_skeleton()); CGAL_precondition(aTriedge.is_valid() && aTriedge.is_skeleton());
Trisegment_2_ptr r = Construct_ss_trisegment_2(mTraits)(CreateSegment(aTriedge.e0()) Trisegment_2_ptr r = Construct_ss_trisegment_2(mTraits)(CreateSegment<Traits>(aTriedge.e0())
,CreateSegment(aTriedge.e1()) ,CreateSegment<Traits>(aTriedge.e1())
,CreateSegment(aTriedge.e2()) ,CreateSegment<Traits>(aTriedge.e2())
); );
CGAL_STSKEL_BUILDER_TRACE(5,"Trisegment for " << aTriedge << ":" << r ) ; CGAL_STSKEL_BUILDER_TRACE(5,"Trisegment for " << aTriedge << ":" << r ) ;
@ -828,8 +831,8 @@ private :
bool IsOppositeEdgeFacingTheSplitSeed( Vertex_handle aSeed, Halfedge_handle aOpposite ) const bool IsOppositeEdgeFacingTheSplitSeed( Vertex_handle aSeed, Halfedge_handle aOpposite ) const
{ {
if ( aSeed->is_skeleton() ) if ( aSeed->is_skeleton() )
return Is_edge_facing_ss_node_2(mTraits)( GetTrisegment(aSeed), CreateSegment(aOpposite) ) ; return Is_edge_facing_ss_node_2(mTraits)( GetTrisegment(aSeed), CreateSegment<Traits>(aOpposite) ) ;
else return Is_edge_facing_ss_node_2(mTraits)( aSeed->point() , CreateSegment(aOpposite) ) ; else return Is_edge_facing_ss_node_2(mTraits)( aSeed->point() , CreateSegment<Traits>(aOpposite) ) ;
} }
Oriented_side EventPointOrientedSide( Event const& aEvent Oriented_side EventPointOrientedSide( Event const& aEvent
@ -840,8 +843,8 @@ private :
) const ) const
{ {
return Oriented_side_of_event_point_wrt_bisector_2(mTraits)( aEvent.trisegment() return Oriented_side_of_event_point_wrt_bisector_2(mTraits)( aEvent.trisegment()
, CreateSegment(aE0) , CreateSegment<Traits>(aE0)
, CreateSegment(aE1) , CreateSegment<Traits>(aE1)
, GetTrisegment(aV01) // Can be null , GetTrisegment(aV01) // Can be null
, aE0isPrimary , aE0isPrimary
) ; ) ;
@ -1012,7 +1015,7 @@ private :
EventPtr IsPseudoSplitEvent( EventPtr const& aEvent, Vertex_handle_pair aOpp, Site const& aSite ) ; EventPtr IsPseudoSplitEvent( EventPtr const& aEvent, Vertex_handle_pair aOpp, Site const& aSite ) ;
void CollectSplitEvent( Vertex_handle aNode, Triedge const& aTriedge, boost::optional<FT> bound=boost::none) ; void CollectSplitEvent( Vertex_handle aNode, Triedge const& aTriedge ) ;
void CollectSplitEvents( Vertex_handle aNode, Triedge const& aPrevEventTriedge ) ; void CollectSplitEvents( Vertex_handle aNode, Triedge const& aPrevEventTriedge ) ;
@ -1024,6 +1027,9 @@ private :
void UpdatePQ( Vertex_handle aV, Triedge const& aPrevEventTriedge ) ; void UpdatePQ( Vertex_handle aV, Triedge const& aPrevEventTriedge ) ;
void CreateInitialEvents(); void CreateInitialEvents();
void CreateContourBisectors(); void CreateContourBisectors();
void HarmonizeSpeeds(boost::mpl::bool_<false>) { }
void HarmonizeSpeeds(boost::mpl::bool_<true>);
void HarmonizeSpeeds() { return HarmonizeSpeeds(typename CGAL_SS_i::has_Segment_2_with_ID<Traits>::type()); }
void InitPhase(); void InitPhase();
void SetupNewNode( Vertex_handle aNode ); void SetupNewNode( Vertex_handle aNode );
@ -1206,42 +1212,40 @@ private :
} }
// internal function to filter split event in case the traits is Filtered // internal function to filter split event in case the traits is Filtered
bool CanSafelyIgnoreSplitEventImpl(const EventPtr& lEvent, const boost::optional<FT>& bound, boost::mpl::bool_<false>) bool CanSafelyIgnoreSplitEventImpl(const EventPtr&, boost::mpl::bool_<false>)
{ {
return false; return false;
} }
bool CanSafelyIgnoreSplitEventImpl(const EventPtr& lEvent, const boost::optional<FT>& bound, boost::mpl::bool_<true>) bool CanSafelyIgnoreSplitEventImpl(const EventPtr& lEvent, boost::mpl::bool_<true>)
{ {
return mTraits.can_safely_ignore_split_event(lEvent, bound); return mTraits.CanSafelyIgnoreSplitEvent(lEvent);
} }
bool CanSafelyIgnoreSplitEvent(const EventPtr& lEvent, const boost::optional<FT>& bound) bool CanSafelyIgnoreSplitEvent(const EventPtr& lEvent)
{ {
return CanSafelyIgnoreSplitEventImpl(lEvent, bound, typename CGAL_SS_i::has_Filters_split_events_tag<Traits>::type()); return CanSafelyIgnoreSplitEventImpl(lEvent, typename CGAL_SS_i::has_Filters_split_events_tag<Traits>::type());
} }
boost::optional<FT> UpperBoundForValidSplitEventsImpl(Vertex_handle, Vertex_handle, Vertex_handle, void ComputeUpperBoundForValidSplitEventsImpl(Vertex_handle, Vertex_handle, Vertex_handle,
Halfedge_handle_vector_iterator, Halfedge_handle_vector_iterator, Halfedge_handle_vector_iterator, Halfedge_handle_vector_iterator,
boost::mpl::bool_<false>) boost::mpl::bool_<false>)
{ {
return boost::none;
} }
boost::optional<FT> UpperBoundForValidSplitEventsImpl(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext, void ComputeUpperBoundForValidSplitEventsImpl(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
Halfedge_handle_vector_iterator contour_halfedges_begin, Halfedge_handle_vector_iterator contour_halfedges_begin,
Halfedge_handle_vector_iterator contour_halfedges_end, Halfedge_handle_vector_iterator contour_halfedges_end,
boost::mpl::bool_<true>) boost::mpl::bool_<true>)
{ {
return mTraits.upper_bound_for_valid_split_events(lPrev, aNode, lNext, contour_halfedges_begin, contour_halfedges_end); return mTraits.ComputeFilteringBound(lPrev, aNode, lNext, contour_halfedges_begin, contour_halfedges_end);
} }
boost::optional<FT> void ComputeUpperBoundForValidSplitEvents(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
UpperBoundForValidSplitEvents(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
Halfedge_handle_vector_iterator contour_halfedges_begin, Halfedge_handle_vector_iterator contour_halfedges_begin,
Halfedge_handle_vector_iterator contour_halfedges_end) Halfedge_handle_vector_iterator contour_halfedges_end)
{ {
return UpperBoundForValidSplitEventsImpl(lPrev, aNode, lNext, contour_halfedges_begin, contour_halfedges_end, return ComputeUpperBoundForValidSplitEventsImpl(lPrev, aNode, lNext, contour_halfedges_begin, contour_halfedges_end,
typename CGAL_SS_i::has_Filters_split_events_tag<Traits>::type()); typename CGAL_SS_i::has_Filters_split_events_tag<Traits>::type());
} }

View File

@ -31,64 +31,27 @@ namespace CGAL {
namespace CGAL_SS_i { namespace CGAL_SS_i {
//TODO: call reserve, but how? #input vertices + n*m estimation?
template <class K>
struct Time_cache
{
typedef boost::optional< Rational< typename K::FT > > Event_time;
std::vector<Event_time> event_times;
std::vector<bool> already_computed;
bool is_time_cached(std::size_t i)
{
return already_computed.size()>i && already_computed[i];
}
const Event_time& time(std::size_t i)
{
CGAL_assertion(is_time_cached(i));
return event_times[i];
}
void set_time(std::size_t i, const Event_time& time)
{
if (event_times.size()<=i){
event_times.resize(i+1);
already_computed.resize(i+1, false);
}
already_computed[i]=true;
event_times[i]=time;
}
void reset(std::size_t i)
{
if (is_time_cached(i)) // needed if approx time is set but not exact time
already_computed[i]=false;
}
};
template<class K> template<class K>
struct Construct_ss_trisegment_2 : Functor_base_2<K> struct Construct_ss_trisegment_2 : Functor_base_2<K>
{ {
typedef Functor_base_2<K> Base ; typedef Functor_base_2<K> Base ;
typedef typename Base::Segment_2 Segment_2 ; typedef typename Base::Segment_2_with_ID Segment_2_with_ID ;
typedef typename Base::Trisegment_2 Trisegment_2 ;
typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ; typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ;
typedef Trisegment_2_ptr result_type ; typedef Trisegment_2_ptr result_type ;
template <class Traits> template <class Traits>
Construct_ss_trisegment_2(const Traits& traits) Construct_ss_trisegment_2(const Traits& traits)
: nextID(traits.trisegment_id) : mNext_ID(traits.trisegment_ID())
{} {}
result_type operator() ( Segment_2 const& aS0, Segment_2 const& aS1, Segment_2 const& aS2 ) const result_type operator() ( Segment_2_with_ID const& aS0, Segment_2_with_ID const& aS1, Segment_2_with_ID const& aS2 ) const
{ {
return construct_trisegment(aS0,aS1,aS2,nextID++); return construct_trisegment(aS0,aS1,aS2,mNext_ID++) ;
} }
std::size_t& nextID; std::size_t& mNext_ID ;
}; };
template<class K> template<class K>
@ -101,20 +64,22 @@ struct Do_ss_event_exist_2 : Functor_base_2<K>
typedef Uncertain<bool> result_type ; typedef Uncertain<bool> result_type ;
Do_ss_event_exist_2(Time_cache<K>& time_cache) Do_ss_event_exist_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_cache)
: mTime_cache(time_cache) : mTime_cache(aTime_cache), mCoeff_cache(aCoeff_cache)
{} {}
Uncertain<bool> operator() ( Trisegment_2_ptr const& aTrisegment, boost::optional<FT> aMaxTime ) const Uncertain<bool> operator() ( Trisegment_2_ptr const& aTrisegment, boost::optional<FT> aMaxTime ) const
{ {
Uncertain<bool> rResult = exist_offset_lines_isec2(aTrisegment,aMaxTime, mTime_cache) ; Uncertain<bool> rResult = exist_offset_lines_isec2(aTrisegment,aMaxTime,mTime_cache,mCoeff_cache) ;
CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Exist_event",aTrisegment); CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Exist_event",aTrisegment);
return rResult ; return rResult ;
} }
private:
Time_cache<K>& mTime_cache ; Time_cache<K>& mTime_cache ;
Coeff_cache<K>& mCoeff_cache ;
}; };
template<class K> template<class K>
@ -123,20 +88,27 @@ struct Is_edge_facing_ss_node_2 : Functor_base_2<K>
typedef Functor_base_2<K> Base ; typedef Functor_base_2<K> Base ;
typedef typename Base::Point_2 Point_2 ; typedef typename Base::Point_2 Point_2 ;
typedef typename Base::Segment_2 Segment_2 ; typedef typename Base::Segment_2_with_ID Segment_2_with_ID ;
typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ; typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ;
typedef Uncertain<bool> result_type ; typedef Uncertain<bool> result_type ;
Uncertain<bool> operator() ( Point_2 const& aContourNode, Segment_2 const& aEdge ) const Is_edge_facing_ss_node_2(Coeff_cache<K>& aCoeff_cache)
: mCoeff_cache(aCoeff_cache)
{ }
Uncertain<bool> operator() ( Point_2 const& aContourNode, Segment_2_with_ID const& aEdge ) const
{ {
return is_edge_facing_pointC2(cgal_make_optional(aContourNode),aEdge) ; return is_edge_facing_pointC2(cgal_make_optional(aContourNode),aEdge) ;
} }
Uncertain<bool> operator() ( Trisegment_2_ptr const& aSkeletonNode, Segment_2 const& aEdge ) const Uncertain<bool> operator() ( Trisegment_2_ptr const& aSkeletonNode, Segment_2_with_ID const& aEdge ) const
{ {
return is_edge_facing_offset_lines_isecC2(aSkeletonNode,aEdge) ; return is_edge_facing_offset_lines_isecC2(aSkeletonNode,aEdge,mCoeff_cache) ;
} }
private:
Coeff_cache<K>& mCoeff_cache ;
}; };
template<class K> template<class K>
@ -148,20 +120,22 @@ struct Compare_ss_event_times_2 : Functor_base_2<K>
typedef Uncertain<Comparison_result> result_type ; typedef Uncertain<Comparison_result> result_type ;
Compare_ss_event_times_2(Time_cache<K>& time_cache) Compare_ss_event_times_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_cache)
: mTime_cache(time_cache) : mTime_cache(aTime_cache), mCoeff_cache(aCoeff_cache)
{} {}
Uncertain<Comparison_result> operator() ( Trisegment_2_ptr const& aL, Trisegment_2_ptr const& aR ) const Uncertain<Comparison_result> operator() ( Trisegment_2_ptr const& aL, Trisegment_2_ptr const& aR ) const
{ {
Uncertain<Comparison_result> rResult = compare_offset_lines_isec_timesC2(aL,aR, mTime_cache) ; Uncertain<Comparison_result> rResult = compare_offset_lines_isec_timesC2(aL,aR,mTime_cache,mCoeff_cache) ;
CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Compare_event_times","L: " << aL << "\nR:" << aR ); CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Compare_event_times","L: " << aL << "\nR:" << aR );
return rResult ; return rResult ;
} }
private:
Time_cache<K>& mTime_cache ; Time_cache<K>& mTime_cache ;
Coeff_cache<K>& mCoeff_cache ;
}; };
template<class K> template<class K>
@ -192,25 +166,32 @@ struct Oriented_side_of_event_point_wrt_bisector_2 : Functor_base_2<K>
{ {
typedef Functor_base_2<K> Base ; typedef Functor_base_2<K> Base ;
typedef typename Base::Segment_2 Segment_2 ; typedef typename Base::Segment_2_with_ID Segment_2_with_ID ;
typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ; typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ;
typedef typename Base::Point_2 Point_2 ; typedef typename Base::Point_2 Point_2 ;
typedef Uncertain<Oriented_side> result_type ; typedef Uncertain<Oriented_side> result_type ;
Oriented_side_of_event_point_wrt_bisector_2(Coeff_cache<K>& aCoeff_cache)
: mCoeff_cache(aCoeff_cache)
{}
Uncertain<Oriented_side> operator() ( Trisegment_2_ptr const& aEvent Uncertain<Oriented_side> operator() ( Trisegment_2_ptr const& aEvent
, Segment_2 const& aE0 , Segment_2_with_ID const& aE0
, Segment_2 const& aE1 , Segment_2_with_ID const& aE1
, Trisegment_2_ptr const& aE01Event , Trisegment_2_ptr const& aE01Event
, bool aE0isPrimary , bool aE0isPrimary
) const ) const
{ {
Uncertain<Oriented_side> rResult = oriented_side_of_event_point_wrt_bisectorC2(aEvent,aE0,aE1,aE01Event,aE0isPrimary) ; Uncertain<Oriented_side> rResult = oriented_side_of_event_point_wrt_bisectorC2(aEvent,aE0,aE1,aE01Event,aE0isPrimary,mCoeff_cache) ;
CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Oriented_side_of_event_point_wrt_bisector_2","Event=" << aEvent << " E0=" << aE0 << " E1=" << aE1 ); CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Oriented_side_of_event_point_wrt_bisector_2","Event=" << aEvent << " E0=" << aE0 << " E1=" << aE1 );
return rResult ; return rResult ;
} }
private:
Coeff_cache<K>& mCoeff_cache ;
}; };
@ -223,21 +204,22 @@ struct Are_ss_events_simultaneous_2 : Functor_base_2<K>
typedef Uncertain<bool> result_type ; typedef Uncertain<bool> result_type ;
Are_ss_events_simultaneous_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_cache)
Are_ss_events_simultaneous_2(Time_cache<K>& time_cache) : mTime_cache(aTime_cache), mCoeff_cache(aCoeff_cache)
: mTime_cache(time_cache)
{} {}
Uncertain<bool> operator() ( Trisegment_2_ptr const& aA, Trisegment_2_ptr const& aB ) const Uncertain<bool> operator() ( Trisegment_2_ptr const& aA, Trisegment_2_ptr const& aB ) const
{ {
Uncertain<bool> rResult = are_events_simultaneousC2(aA,aB,mTime_cache); Uncertain<bool> rResult = are_events_simultaneousC2(aA,aB,mTime_cache,mCoeff_cache);
CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Are_events_simultaneous","A=" << aA << "\nB=" << aB); CGAL_STSKEL_ASSERT_PREDICATE_RESULT(rResult,K,"Are_events_simultaneous","A=" << aA << "\nB=" << aB);
return rResult ; return rResult ;
} }
private:
Time_cache<K>& mTime_cache ; Time_cache<K>& mTime_cache ;
Coeff_cache<K>& mCoeff_cache ;
}; };
template<class K> template<class K>
@ -245,11 +227,11 @@ struct Are_ss_edges_collinear_2 : Functor_base_2<K>
{ {
typedef Functor_base_2<K> Base ; typedef Functor_base_2<K> Base ;
typedef typename Base::Segment_2 Segment_2 ; typedef typename Base::Segment_2_with_ID Segment_2_with_ID ;
typedef Uncertain<bool> result_type ; typedef Uncertain<bool> result_type ;
Uncertain<bool> operator() ( Segment_2 const& aA, Segment_2 const& aB ) const Uncertain<bool> operator() ( Segment_2_with_ID const& aA, Segment_2_with_ID const& aB ) const
{ {
Uncertain<bool> rResult = are_edges_collinearC2(aA,aB); Uncertain<bool> rResult = are_edges_collinearC2(aA,aB);
@ -264,11 +246,11 @@ struct Are_ss_edges_parallel_2 : Functor_base_2<K>
{ {
typedef Functor_base_2<K> Base ; typedef Functor_base_2<K> Base ;
typedef typename Base::Segment_2 Segment_2 ; typedef typename Base::Segment_2_with_ID Segment_2_with_ID ;
typedef Uncertain<bool> result_type ; typedef Uncertain<bool> result_type ;
Uncertain<bool> operator() ( Segment_2 const& aA, Segment_2 const& aB ) const Uncertain<bool> operator() ( Segment_2_with_ID const& aA, Segment_2_with_ID const& aB ) const
{ {
Uncertain<bool> rResult = are_edges_parallelC2(aA,aB); Uncertain<bool> rResult = are_edges_parallelC2(aA,aB);
@ -286,15 +268,15 @@ struct Construct_ss_event_time_and_point_2 : Functor_base_2<K>
typedef typename Base::FT FT ; typedef typename Base::FT FT ;
typedef typename Base::Point_2 Point_2 ; typedef typename Base::Point_2 Point_2 ;
typedef typename Base::Segment_2 Segment_2 ; typedef typename Base::Segment_2_with_ID Segment_2_with_ID ;
typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ; typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ;
typedef boost::tuple<FT,Point_2> rtype ; typedef boost::tuple<FT,Point_2> rtype ;
typedef boost::optional<rtype> result_type ; typedef boost::optional<rtype> result_type ;
Construct_ss_event_time_and_point_2(Time_cache<K>& time_cache) Construct_ss_event_time_and_point_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_cache)
:mTime_cache(time_cache) : mTime_cache(aTime_cache), mCoeff_cache(aCoeff_cache)
{} {}
result_type operator() ( Trisegment_2_ptr const& aTrisegment ) const result_type operator() ( Trisegment_2_ptr const& aTrisegment ) const
@ -304,13 +286,13 @@ struct Construct_ss_event_time_and_point_2 : Functor_base_2<K>
FT t(0) ; FT t(0) ;
Point_2 i = ORIGIN ; Point_2 i = ORIGIN ;
boost::optional< Rational<FT> > ot = compute_offset_lines_isec_timeC2(aTrisegment, mTime_cache); boost::optional< Rational<FT> > ot = compute_offset_lines_isec_timeC2(aTrisegment,mTime_cache,mCoeff_cache);
if ( !!ot && certainly( CGAL_NTS certified_is_not_zero(ot->d()) ) ) if ( !!ot && certainly( CGAL_NTS certified_is_not_zero(ot->d()) ) )
{ {
t = ot->n() / ot->d(); t = ot->n() / ot->d();
boost::optional<Point_2> oi = construct_offset_lines_isecC2(aTrisegment); boost::optional<Point_2> oi = construct_offset_lines_isecC2(aTrisegment,mCoeff_cache);
if ( oi ) if ( oi )
{ {
i = *oi ; i = *oi ;
@ -329,9 +311,9 @@ struct Construct_ss_event_time_and_point_2 : Functor_base_2<K>
if ( is_possibly_inexact_time_clearly_not_zero(t) ) if ( is_possibly_inexact_time_clearly_not_zero(t) )
{ {
Segment_2 const& e0 = aTrisegment->e0() ; Segment_2_with_ID const& e0 = aTrisegment->e0() ;
Segment_2 const& e1 = aTrisegment->e1() ; Segment_2_with_ID const& e1 = aTrisegment->e1() ;
Segment_2 const& e2 = aTrisegment->e2() ; Segment_2_with_ID const& e2 = aTrisegment->e2() ;
Point_2 const& e0s = e0.source(); Point_2 const& e0s = e0.source();
Point_2 const& e0t = e0.target(); Point_2 const& e0t = e0.target();
@ -376,7 +358,9 @@ struct Construct_ss_event_time_and_point_2 : Functor_base_2<K>
return rR ; return rR ;
} }
private:
Time_cache<K>& mTime_cache ; Time_cache<K>& mTime_cache ;
Coeff_cache<K>& mCoeff_cache ;
}; };
} // namespace CGAL_SS_i } // namespace CGAL_SS_i
@ -405,10 +389,10 @@ struct Straight_skeleton_builder_traits_2_base
typedef typename K::Point_2 Point_2 ; typedef typename K::Point_2 Point_2 ;
typedef typename K::Vector_2 Vector_2 ; typedef typename K::Vector_2 Vector_2 ;
typedef typename K::Direction_2 Direction_2 ; typedef typename K::Direction_2 Direction_2 ;
typedef typename K::Segment_2 Segment_2 ;
typedef CGAL_SS_i::Segment_2_with_ID<K> Segment_2 ;
typedef CGAL_SS_i::Segment_2_with_ID<K> Segment_2_with_ID ; // used in BOOST_MPL_HAS_XXX_TRAIT_DEF
typedef CGAL_SS_i::Trisegment_2<K> Trisegment_2 ; typedef CGAL_SS_i::Trisegment_2<K> Trisegment_2 ;
typedef typename Trisegment_2::Self_ptr Trisegment_2_ptr ; typedef typename Trisegment_2::Self_ptr Trisegment_2_ptr ;
template<class F> F get( F const* = 0 ) const { return F(); } template<class F> F get( F const* = 0 ) const { return F(); }
@ -416,17 +400,17 @@ struct Straight_skeleton_builder_traits_2_base
} ; } ;
template<class Is_filtered_kernel, class K> class Straight_skeleton_builder_traits_2_impl ; template<class Is_filtered_kernel, class K>
class Straight_skeleton_builder_traits_2_impl ;
template<class K> template<class K>
class Straight_skeleton_builder_traits_2_impl<Tag_false,K> : public Straight_skeleton_builder_traits_2_base<K> class Straight_skeleton_builder_traits_2_impl<Tag_false /*Is_filtered_kernel*/, K>
: public Straight_skeleton_builder_traits_2_base<K>
{ {
typedef Straight_skeleton_builder_traits_2_functors<K> Unfiltering ; typedef Straight_skeleton_builder_traits_2_functors<K> Unfiltering ;
typedef Straight_skeleton_builder_traits_2_base<K> Base ;
public: public:
mutable std::size_t trisegment_id = 0;
typedef Unfiltered_predicate_adaptor<typename Unfiltering::Do_ss_event_exist_2> typedef Unfiltered_predicate_adaptor<typename Unfiltering::Do_ss_event_exist_2>
Do_ss_event_exist_2 ; Do_ss_event_exist_2 ;
@ -454,43 +438,43 @@ public:
typedef typename Unfiltering::Construct_ss_event_time_and_point_2 Construct_ss_event_time_and_point_2 ; typedef typename Unfiltering::Construct_ss_event_time_and_point_2 Construct_ss_event_time_and_point_2 ;
typedef typename Unfiltering::Construct_ss_trisegment_2 Construct_ss_trisegment_2 ; typedef typename Unfiltering::Construct_ss_trisegment_2 Construct_ss_trisegment_2 ;
mutable CGAL_SS_i::Time_cache<K> time_cache;
void reset_trisegment(std::size_t i) const
{
time_cache.reset(i);
}
using Straight_skeleton_builder_traits_2_base<K>::get; using Straight_skeleton_builder_traits_2_base<K>::get;
Is_edge_facing_ss_node_2
get(Is_edge_facing_ss_node_2 const* = 0 ) const
{
return Is_edge_facing_ss_node_2(mCoeff_cache);
}
Compare_ss_event_times_2 Compare_ss_event_times_2
get(Compare_ss_event_times_2 const* = 0 ) const get(Compare_ss_event_times_2 const* = 0 ) const
{ {
return Compare_ss_event_times_2(const_cast<CGAL_SS_i::Time_cache<K>&>(time_cache)); return Compare_ss_event_times_2(mTime_cache, mCoeff_cache);
} }
Compare_ss_event_angles_2
get(Compare_ss_event_angles_2 const* = 0 ) const Oriented_side_of_event_point_wrt_bisector_2
get(Oriented_side_of_event_point_wrt_bisector_2 const* = 0 ) const
{ {
return Compare_ss_event_angles_2(); return Oriented_side_of_event_point_wrt_bisector_2(mCoeff_cache);
} }
Do_ss_event_exist_2 Do_ss_event_exist_2
get(Do_ss_event_exist_2 const* = 0 ) const get(Do_ss_event_exist_2 const* = 0 ) const
{ {
return Do_ss_event_exist_2(const_cast<CGAL_SS_i::Time_cache<K>&>(time_cache)); return Do_ss_event_exist_2(mTime_cache, mCoeff_cache);
} }
Are_ss_events_simultaneous_2 Are_ss_events_simultaneous_2
get(Are_ss_events_simultaneous_2 const* = 0 ) const get(Are_ss_events_simultaneous_2 const* = 0 ) const
{ {
return Are_ss_events_simultaneous_2(const_cast<CGAL_SS_i::Time_cache<K>&>(time_cache)); return Are_ss_events_simultaneous_2(mTime_cache, mCoeff_cache);
} }
Construct_ss_event_time_and_point_2 Construct_ss_event_time_and_point_2
get(Construct_ss_event_time_and_point_2 const* = 0 ) const get(Construct_ss_event_time_and_point_2 const* = 0 ) const
{ {
return Construct_ss_event_time_and_point_2(const_cast<CGAL_SS_i::Time_cache<K>&>(time_cache)); return Construct_ss_event_time_and_point_2(mTime_cache, mCoeff_cache);
} }
Construct_ss_trisegment_2 Construct_ss_trisegment_2
@ -498,10 +482,124 @@ public:
{ {
return Construct_ss_trisegment_2(*this); return Construct_ss_trisegment_2(*this);
} }
// ID functions
std::size_t& trisegment_ID() const { return mTrisegment_ID ; }
void reset_trisegment(std::size_t i) const
{
--mTrisegment_ID ;
mTime_cache.Reset(i) ;
}
// functions to initialize (and harmonize) and cache speeds
void InitializeLineCoeffs ( CGAL_SS_i::Segment_2_with_ID<K> const& aBorderS )
{
CGAL_SS_i::compute_normalized_line_ceoffC2 ( aBorderS, mCoeff_cache ) ;
}
void InitializeLineCoeffs ( std::size_t aID, std::size_t aOtherID )
{
if ( mCoeff_cache.Get( aOtherID ) )
mCoeff_cache.Set( aID, CGAL_SS_i::cgal_make_optional(*(mCoeff_cache.Get(aOtherID))) ) ;
else
mCoeff_cache.Set( aID, boost::none ) ;
}
// functions and tag for filtering split events
struct Filters_split_events_tag{};
template <class EventPtr>
bool CanSafelyIgnoreSplitEvent(const EventPtr& lEvent)
{
return false;
// filter event
if ( ! mFilteringBound )
return false;
typename Base::Trisegment_2_ptr tri = lEvent->trisegment() ;
boost::optional<CGAL_SS_i::Rational<typename K::FT> > lOptTime =
CGAL_SS_i::compute_offset_lines_isec_timeC2(tri, mTime_cache, mCoeff_cache);
if ( lOptTime && lOptTime->to_nt() > *mFilteringBound )
{
// avoid filling the cache vectors with times of trisegments that will be removed
reset_trisegment(tri->id());
return true;
}
return false;
}
// @todo there shouldn't be any combinatorial structures such as vertices in the traits
template <class Vertex_handle, class Halfedge_handle_vector_iterator>
void ComputeFilteringBound(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
Halfedge_handle_vector_iterator contour_halfedges_begin,
Halfedge_handle_vector_iterator contour_halfedges_end)
{
mFilteringBound = boost::none;
if ( ! aNode->is_contour() )
return ;
typedef typename K::Vector_2 Vector_2;
typedef typename K::Segment_2 Segment_2;
typedef typename K::Ray_2 Ray_2;
typedef typename K::Line_2 Line_2;
Segment_2 s1(lPrev->point(), aNode->point());
Segment_2 s2(aNode->point(), lNext->point());
// @todo? These are not input segments, but it might still worth caching (just gotta assign them an ID)
boost::optional< Line_2 > l1 = CGAL_SS_i::compute_normalized_line_ceoffC2(s1);
boost::optional< Line_2 > l2 = CGAL_SS_i::compute_normalized_line_ceoffC2(s2);
Vector_2 lV1(l1->a(), l1->b()) ;
Vector_2 lV2(l2->a(), l2->b()) ;
Vector_2 lV12 = lV1 + lV2 ;
Ray_2 bisect_ray(aNode->point(), lV12) ;
// F2C to_input;
// std::cout << "bisect " << aNode->point() << " " << aNode->point() + to_input(lV12) << "\n";
for ( Halfedge_handle_vector_iterator i = contour_halfedges_begin; i != contour_halfedges_end; ++ i )
{
CGAL_assertion((*i)->vertex()->is_contour() && (*i)->opposite()->vertex()->is_contour() );
Segment_2 s_h((*i)->opposite()->vertex()->point(), (*i)->vertex()->point());
auto inter = K().do_intersect_2_object()(s_h, bisect_ray);
auto orient = K().orientation_2_object()(s_h[0], s_h[1], aNode->point());
// we use segments of the input polygon intersected by the bisector and such that
// they are oriented such that the reflex vertex is on the left side of the segment
if (!is_certain(inter) || !is_certain(orient) || !inter || orient != LEFT_TURN)
continue;
// Note that we don't need the normalization
boost::optional< Line_2 > lh = CGAL_SS_i::compute_normalized_line_ceoffC2(s_h);
typename K::FT lBound = ( - lh->c() - lh->a()*aNode->point().x() - lh->b()*aNode->point().y() ) /
( lh->a()*lV12.x() + lh->b()*lV12.y() );
if( ! is_finite(lBound) )
continue;
if ( ! mFilteringBound || *mFilteringBound > lBound )
mFilteringBound = lBound;
}
}
public:
mutable std::size_t mTrisegment_ID = 0 ;
mutable CGAL_SS_i::Time_cache<K> mTime_cache ;
mutable CGAL_SS_i::Coeff_cache<K> mCoeff_cache ;
boost::optional< typename K::FT > mFilteringBound ;
} ; } ;
template<class K> template<class K>
class Straight_skeleton_builder_traits_2_impl<Tag_true,K> : public Straight_skeleton_builder_traits_2_base<K> class Straight_skeleton_builder_traits_2_impl<Tag_true /*Is_filtered_kernel*/, K>
: public Straight_skeleton_builder_traits_2_base<K>
{ {
typedef typename K::Exact_kernel EK ; typedef typename K::Exact_kernel EK ;
typedef typename K::Approximate_kernel FK ; typedef typename K::Approximate_kernel FK ;
@ -598,36 +696,53 @@ public:
Compare_ss_event_times_2 Compare_ss_event_times_2
get(Compare_ss_event_times_2 const* = 0 ) const get(Compare_ss_event_times_2 const* = 0 ) const
{ {
return Compare_ss_event_times_2( typename Exact::Compare_ss_event_times_2(const_cast<CGAL_SS_i::Time_cache<EK>&>(mExact_traits.time_cache)), return Compare_ss_event_times_2( typename Exact::Compare_ss_event_times_2(
typename Filtering::Compare_ss_event_times_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) ); mExact_traits.mTime_cache, mExact_traits.mCoeff_cache),
typename Filtering::Compare_ss_event_times_2(
mApproximate_traits.mTime_cache, mApproximate_traits.mCoeff_cache) );
} }
Compare_ss_event_angles_2 Is_edge_facing_ss_node_2
get(Compare_ss_event_angles_2 const* = 0 ) const get(Is_edge_facing_ss_node_2 const* = 0 ) const
{ {
return Compare_ss_event_angles_2( typename Exact::Compare_ss_event_angles_2(), return Is_edge_facing_ss_node_2( typename Exact::Is_edge_facing_ss_node_2(mExact_traits.mCoeff_cache),
typename Filtering::Compare_ss_event_angles_2() ); typename Filtering::Is_edge_facing_ss_node_2(mApproximate_traits.mCoeff_cache) );
}
Oriented_side_of_event_point_wrt_bisector_2
get(Oriented_side_of_event_point_wrt_bisector_2 const* = 0 ) const
{
return Oriented_side_of_event_point_wrt_bisector_2( typename Exact::Oriented_side_of_event_point_wrt_bisector_2(
mExact_traits.mCoeff_cache),
typename Filtering::Oriented_side_of_event_point_wrt_bisector_2(
mApproximate_traits.mCoeff_cache) );
} }
Do_ss_event_exist_2 Do_ss_event_exist_2
get(Do_ss_event_exist_2 const* = 0 ) const get(Do_ss_event_exist_2 const* = 0 ) const
{ {
return Do_ss_event_exist_2( typename Exact::Do_ss_event_exist_2(const_cast<CGAL_SS_i::Time_cache<EK>&>(mExact_traits.time_cache)), return Do_ss_event_exist_2( typename Exact::Do_ss_event_exist_2(
typename Filtering::Do_ss_event_exist_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) ); mExact_traits.mTime_cache, mExact_traits.mCoeff_cache),
typename Filtering::Do_ss_event_exist_2(
mApproximate_traits.mTime_cache, mApproximate_traits.mCoeff_cache) );
} }
Are_ss_events_simultaneous_2 Are_ss_events_simultaneous_2
get(Are_ss_events_simultaneous_2 const* = 0 ) const get(Are_ss_events_simultaneous_2 const* = 0 ) const
{ {
return Are_ss_events_simultaneous_2( typename Exact::Are_ss_events_simultaneous_2(const_cast<CGAL_SS_i::Time_cache<EK>&>(mExact_traits.time_cache)), return Are_ss_events_simultaneous_2( typename Exact::Are_ss_events_simultaneous_2(
typename Filtering::Are_ss_events_simultaneous_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) ); mExact_traits.mTime_cache, mExact_traits.mCoeff_cache),
typename Filtering::Are_ss_events_simultaneous_2(
mApproximate_traits.mTime_cache, mApproximate_traits.mCoeff_cache) );
} }
Construct_ss_event_time_and_point_2 Construct_ss_event_time_and_point_2
get(Construct_ss_event_time_and_point_2 const* = 0 ) const get(Construct_ss_event_time_and_point_2 const* = 0 ) const
{ {
return Construct_ss_event_time_and_point_2( typename Exact::Construct_ss_event_time_and_point_2(const_cast<CGAL_SS_i::Time_cache<EK>&>(mExact_traits.time_cache)), return Construct_ss_event_time_and_point_2( typename Exact::Construct_ss_event_time_and_point_2(
typename Filtering::Construct_ss_event_time_and_point_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) ); mExact_traits.mTime_cache, mExact_traits.mCoeff_cache),
typename Filtering::Construct_ss_event_time_and_point_2(
mApproximate_traits.mTime_cache, mApproximate_traits.mCoeff_cache) );
} }
// constructor of trisegments using global id stored in the traits // constructor of trisegments using global id stored in the traits
Construct_ss_trisegment_2 Construct_ss_trisegment_2
@ -636,121 +751,165 @@ public:
return Construct_ss_trisegment_2(*this); return Construct_ss_trisegment_2(*this);
} }
// ID functions
std::size_t& trisegment_ID() const { return mApproximate_traits.mTrisegment_ID ; }
void reset_trisegment(std::size_t i) const
{
if ( i+1 == trisegment_ID() )
{
--trisegment_ID() ;
mExact_traits.mTime_cache.Reset(i) ;
mApproximate_traits.mTime_cache.Reset(i) ;
}
}
// functions to initialize (and harmonize) and cache speeds
void InitializeLineCoeffs ( CGAL_SS_i::Segment_2_with_ID<K> const& aBorderS )
{
// std::cout << "Initialize " << aBorderS.mID << std::endl;
C2E lToExact ;
C2F lToFiltered ;
mApproximate_traits.InitializeLineCoeffs( lToFiltered(aBorderS) );
// if ( mApproximate_traits.mCoeff_cache.Get ( aBorderS.mID ) )
// std::cout << "Initialized (F) to: " << *(mApproximate_traits.mCoeff_cache.Get ( aBorderS.mID ) ) << std::endl;
mExact_traits.InitializeLineCoeffs( lToExact(aBorderS) );
// if ( mExact_traits.mCoeff_cache.Get ( aBorderS.mID ) )
// std::cout << "Initialized (E) to: " << *(mExact_traits.mCoeff_cache.Get ( aBorderS.mID ) ) << std::endl;
}
// This overload copies the coefficients from the halfedge `aOtherID` and caches them for the halfedge `aID`
void InitializeLineCoeffs ( std::size_t aID, std::size_t aOtherID )
{
// std::cout << "Initialize (copy) " << aBorderS.mID << " using " << aOtherID << std::endl;
mApproximate_traits.InitializeLineCoeffs(aID, aOtherID) ;
mExact_traits.InitializeLineCoeffs(aID, aOtherID) ;
}
// functions and tag for filtering split events // functions and tag for filtering split events
struct Filters_split_events_tag{}; struct Filters_split_events_tag{};
// The kernel is filtered, and only the filtered part is used in the check (to avoid computing
// exact stuff and losing time in a check that is there to gain speed)
template <class EventPtr> template <class EventPtr>
bool bool CanSafelyIgnoreSplitEvent(const EventPtr& lEvent)
can_safely_ignore_split_event(const EventPtr& lEvent, const boost::optional<double>& bound)
{ {
// filter event // filter event
if (bound) if ( ! mApproximate_traits.mFilteringBound )
{ return false;
typedef FK Interval_kernel;
typename Interval_kernel::FT::Protector p; typename FK::FT::Protector p;
Cartesian_converter<K, Interval_kernel> to_interval;
typedef CGAL_SS_i::Trisegment_2<Interval_kernel> Target_trisegment_2 ; typedef CGAL_SS_i::Trisegment_2<K> Source_trisegment_2 ;
typedef typename Source_trisegment_2::Self_ptr Source_trisegment_2_ptr;
typedef CGAL_SS_i::Trisegment_2<FK> Target_trisegment_2 ;
typedef typename Target_trisegment_2::Self_ptr Target_trisegment_2_ptr; typedef typename Target_trisegment_2::Self_ptr Target_trisegment_2_ptr;
Target_trisegment_2_ptr tri = new Target_trisegment_2(to_interval(lEvent->trisegment()->e0())
,to_interval(lEvent->trisegment()->e1()) C2F to_FK ;
,to_interval(lEvent->trisegment()->e2()) Source_trisegment_2_ptr src_tri = lEvent->trisegment() ;
,lEvent->trisegment()->collinearity() CGAL_assertion( src_tri != nullptr ) ;
,lEvent->trisegment()->id Target_trisegment_2_ptr tri = to_FK.cvt_single_trisegment(src_tri) ;
);
CGAL_postcondition( src_tri->collinearity() == tri->collinearity() ) ;
CGAL_postcondition( src_tri->id() == tri->id() ) ;
try try
{ {
boost::optional<CGAL_SS_i::Rational<typename FK::FT> > opt_time = CGAL_SS_i::compute_offset_lines_isec_timeC2(tri, const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)); boost::optional<CGAL_SS_i::Rational<typename FK::FT> > lOptTime =
CGAL_SS_i::compute_offset_lines_isec_timeC2(
tri, mApproximate_traits.mTime_cache, mApproximate_traits.mCoeff_cache);
if (opt_time && opt_time->to_nt().inf() > *bound) if ( lOptTime && lOptTime->to_nt() > *mApproximate_traits.mFilteringBound )
{ {
reset_trisegment(tri->id); // avoid filling the cache vectors with times of trisegments that will be removed // avoid filling the cache vectors with times of trisegments that will be removed
reset_trisegment(tri->id());
return true; return true;
} }
} }
catch(Uncertain_conversion_exception&) catch(Uncertain_conversion_exception&)
{} {}
}
return false; return false;
} }
// @todo there shouldn't be any combinatorial structures such as vertices in the traits
template <class Vertex_handle, class Halfedge_handle_vector_iterator> template <class Vertex_handle, class Halfedge_handle_vector_iterator>
boost::optional<double> void ComputeFilteringBound(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
upper_bound_for_valid_split_events(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
Halfedge_handle_vector_iterator contour_halfedges_begin, Halfedge_handle_vector_iterator contour_halfedges_begin,
Halfedge_handle_vector_iterator contour_halfedges_end) Halfedge_handle_vector_iterator contour_halfedges_end)
{ {
boost::optional<double> bound; mApproximate_traits.mFilteringBound = boost::none;
if ( aNode->is_contour())
{
typedef FK Interval_kernel; if ( ! aNode->is_contour() )
Cartesian_converter<K, Interval_kernel> to_interval; return ;
typedef typename Interval_kernel::Line_2 Line_2;
typedef typename Interval_kernel::Ray_2 Ray_2;
typedef typename Interval_kernel::Vector_2 Vector_2;
typedef typename Interval_kernel::Segment_2 Segment_2;
typename Interval_kernel::FT::Protector protector; typedef typename FK::Point_2 Target_Point_2;
typedef typename FK::Vector_2 Target_Vector_2;
typedef typename FK::Segment_2 Target_Segment_2;
typedef typename FK::Ray_2 Target_Ray_2;
typedef typename FK::Line_2 Target_Line_2;
Segment_2 s1(to_interval(lPrev->point()), to_interval(aNode->point())); typename FK::FT::Protector protector;
Segment_2 s2(to_interval(aNode->point()), to_interval(lNext->point()));
boost::optional< Line_2 > l1 = CGAL_SS_i::compute_normalized_line_ceoffC2(s1); C2F to_FK;
boost::optional< Line_2 > l2 = CGAL_SS_i::compute_normalized_line_ceoffC2(s2);
Vector_2 v1(l1->a(), l1->b()); Target_Point_2 laP = to_FK(aNode->point());
Vector_2 v2(l2->a(), l2->b()); Target_Segment_2 s1(to_FK(lPrev->point()), laP);
Ray_2 bisect_ray(to_interval(aNode->point()), v1+v2); Target_Segment_2 s2(laP, to_FK(lNext->point()));
// Cartesian_converter<Interval_kernel, K> to_input; // @todo? These are not input segments, but it might still worth caching (just gotta assign them an ID)
// std::cout << "bisect " << aNode->point() << " " << aNode->point() + to_input(v1+v2) << "\n"; boost::optional< Target_Line_2 > l1 = CGAL_SS_i::compute_normalized_line_ceoffC2(s1);
boost::optional< Target_Line_2 > l2 = CGAL_SS_i::compute_normalized_line_ceoffC2(s2);
Target_Vector_2 lV1(l1->a(), l1->b()) ;
Target_Vector_2 lV2(l2->a(), l2->b()) ;
Target_Vector_2 lV12 = lV1 + lV2 ;
Target_Ray_2 bisect_ray(laP, lV12) ;
// F2C to_input;
// std::cout << "bisect " << aNode->point() << " " << aNode->point() + to_input(lV12) << "\n";
for ( Halfedge_handle_vector_iterator i = contour_halfedges_begin; i != contour_halfedges_end; ++ i ) for ( Halfedge_handle_vector_iterator i = contour_halfedges_begin; i != contour_halfedges_end; ++ i )
{ {
try{ try
{
CGAL_assertion((*i)->vertex()->is_contour() && (*i)->opposite()->vertex()->is_contour() ); CGAL_assertion((*i)->vertex()->is_contour() && (*i)->opposite()->vertex()->is_contour() );
Segment_2 s_h(to_interval((*i)->opposite()->vertex()->point()), Target_Segment_2 s_h(to_FK((*i)->opposite()->vertex()->point()), to_FK((*i)->vertex()->point()));
to_interval((*i)->vertex()->point()));
Uncertain<bool> inter = do_intersect(s_h, bisect_ray); Uncertain<bool> inter = FK().do_intersect_2_object()(s_h, bisect_ray);
Uncertain<Oriented_side> orient = orientation(s_h[0], s_h[1], to_interval(aNode->point())); Uncertain<Oriented_side> orient = FK().orientation_2_object()(s_h[0], s_h[1], laP);
// we use segments of the input polygon intersected by the bisector and such that // we use segments of the input polygon intersected by the bisector and such that
// they are oriented such that the reflex vertex is on the left side of the segment // they are oriented such that the reflex vertex is on the left side of the segment
if (!is_certain(inter) || !is_certain(orient) || !inter || orient!=LEFT_TURN) continue; if (!is_certain(inter) || !is_certain(orient) || !inter || orient != LEFT_TURN)
continue;
boost::optional< Line_2 > lh = CGAL_SS_i::compute_normalized_line_ceoffC2(s_h); // Note that we don't need the normalization // Note that we don't need the normalization
boost::optional< Target_Line_2 > lh = CGAL_SS_i::compute_normalized_line_ceoffC2(s_h);
typename Interval_kernel::FT h_bound = typename FK::FT lBound = ( - lh->c() - lh->a()*laP.x() - lh->b()*laP.y() ) /
( - lh->c() -lh->a() * to_interval(aNode->point().x()) - lh->b() * to_interval(aNode->point().y()) ) / ( lh->a()*lV12.x() + lh->b()*lV12.y() );
(lh->a() * ( (v1+v2).x() ) + lh->b() * ( (v1+v2).y() ));
if (!bound || *bound>h_bound.sup()) if ( ! is_finite(lBound) )
bound=h_bound.sup(); continue;
if ( ! mApproximate_traits.mFilteringBound || *mApproximate_traits.mFilteringBound > lBound )
mApproximate_traits.mFilteringBound = lBound ;
} }
catch(CGAL::Uncertain_conversion_exception&) catch(CGAL::Uncertain_conversion_exception&)
{} {}
} }
} }
// if (bound) std::cout << "bound is " << *bound << "\n";
return bound;
}
public:
// TODO: as soon as an exact value we could refine the interval one. Not sure if it is worth it // TODO: as soon as an exact value we could refine the interval one. Not sure if it is worth it
Exact mExact_traits ; Exact mExact_traits ;
Straight_skeleton_builder_traits_2_impl<Tag_false, FK> mApproximate_traits; // only used for the time_cache variable not the functor types
mutable std::size_t trisegment_id = 0; // Below is only used for the cached variables not the functor types
Straight_skeleton_builder_traits_2_impl<Tag_false, FK> mApproximate_traits ;
void reset_trisegment(std::size_t i) const
{
if (i+1==trisegment_id)
{
--trisegment_id;
mExact_traits.time_cache.reset(i);
mApproximate_traits.time_cache.reset(i);
}
}
} ; } ;
template<class K> template<class K>

View File

@ -19,7 +19,7 @@
namespace CGAL { namespace CGAL {
template < class Refs, class S > template < class Refs >
class Straight_skeleton_halfedge_base_base_2 class Straight_skeleton_halfedge_base_base_2
{ {
public: public:
@ -38,9 +38,7 @@ public:
typedef typename Refs::Vertex Vertex; typedef typename Refs::Vertex Vertex;
typedef typename Refs::Face Face; typedef typename Refs::Face Face;
typedef Straight_skeleton_halfedge_base_base_2<Refs,S> Base_base ; typedef Straight_skeleton_halfedge_base_base_2<Refs> Base_base ;
typedef S Segment_2;
protected: protected:
@ -107,8 +105,8 @@ private:
Sign mSlope ; Sign mSlope ;
}; };
template < class Refs, class S > template < class Refs >
class Straight_skeleton_halfedge_base_2 : public Straight_skeleton_halfedge_base_base_2<Refs,S> class Straight_skeleton_halfedge_base_2 : public Straight_skeleton_halfedge_base_base_2<Refs>
{ {
public: public:
@ -116,8 +114,8 @@ public:
typedef typename Refs::Halfedge_handle Halfedge_handle; typedef typename Refs::Halfedge_handle Halfedge_handle;
typedef typename Refs::Face_handle Face_handle; typedef typename Refs::Face_handle Face_handle;
typedef Straight_skeleton_halfedge_base_base_2<Refs,S> Base_base ; typedef Straight_skeleton_halfedge_base_base_2<Refs> Base_base ;
typedef Straight_skeleton_halfedge_base_2<Refs,S> Base ; typedef Straight_skeleton_halfedge_base_2<Refs> Base ;
Straight_skeleton_halfedge_base_2() {} Straight_skeleton_halfedge_base_2() {}

View File

@ -35,8 +35,7 @@ public:
template<class Refs, class Traits> template<class Refs, class Traits>
struct Halfedge_wrapper struct Halfedge_wrapper
{ {
typedef typename Traits::Segment_2 Segment ; typedef Straight_skeleton_halfedge_base_2 < Refs > Halfedge;
typedef Straight_skeleton_halfedge_base_2 < Refs, Segment > Halfedge;
}; };
template<class Refs, class Traits> template<class Refs, class Traits>

View File

@ -31,11 +31,12 @@ namespace CGAL_SS_i {
// //
// POSTCONDITION: In case of overflow an empty optional is returned. // POSTCONDITION: In case of overflow an empty optional is returned.
// //
template<class K> template<class K, class CoeffCache>
boost::optional< Point_2<K> > construct_offset_pointC2 ( typename K::FT const& t boost::optional< Point_2<K> > construct_offset_pointC2 ( typename K::FT const& t
, Segment_2<K> const& e0 , Segment_2_with_ID<K> const& e0
, Segment_2<K> const& e1 , Segment_2_with_ID<K> const& e1
, boost::intrusive_ptr< Trisegment_2<K> > const& tri) , boost::intrusive_ptr< Trisegment_2<K> > const& tri
, CoeffCache& aCoeff_cache)
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -49,8 +50,8 @@ boost::optional< Point_2<K> > construct_offset_pointC2 ( typename K::FT const&
CGAL_STSKEL_TRAITS_TRACE("Constructing offset point for t=" << t << " e0=" << s2str(e0) << " e1=" << s2str(e1) << " tri=" << tri ) ; CGAL_STSKEL_TRAITS_TRACE("Constructing offset point for t=" << t << " e0=" << s2str(e0) << " e1=" << s2str(e1) << " tri=" << tri ) ;
Optional_line_2 l0 = compute_normalized_line_ceoffC2(e0) ; Optional_line_2 l0 = compute_normalized_line_ceoffC2(e0, aCoeff_cache) ;
Optional_line_2 l1 = compute_normalized_line_ceoffC2(e1) ; Optional_line_2 l1 = compute_normalized_line_ceoffC2(e1, aCoeff_cache) ;
bool ok = false ; bool ok = false ;

View File

@ -28,7 +28,7 @@ namespace CGAL {
namespace CGAL_SS_i { namespace CGAL_SS_i {
template<class K> template<class K>
bool are_edges_collinear( Segment_2<K> const& e0, Segment_2<K> const& e1 ) bool are_edges_collinear( Segment_2_with_ID<K> const& e0, Segment_2_with_ID<K> const& e1 )
{ {
return ((e1.source() == e0.source()) || (e1.source() == e0.target()) || collinear(e0.source(),e0.target(),e1.source())) return ((e1.source() == e0.source()) || (e1.source() == e0.target()) || collinear(e0.source(),e0.target(),e1.source()))
&& ( (e1.target() == e0.source()) || (e1.target() == e0.target()) || (collinear(e0.source(),e0.target(),e1.target()))) ; && ( (e1.target() == e0.source()) || (e1.target() == e0.target()) || (collinear(e0.source(),e0.target(),e1.target()))) ;
@ -36,23 +36,23 @@ bool are_edges_collinear( Segment_2<K> const& e0, Segment_2<K> const& e1 )
template<class K> template<class K>
inline inline
bool are_parallel_edges_equally_oriented( Segment_2<K> const& e0, Segment_2<K> const& e1 ) bool are_parallel_edges_equally_oriented( Segment_2_with_ID<K> const& e0, Segment_2_with_ID<K> const& e1 )
{ {
return angle(e0.source(), e0.target(), return angle(e0.source(), e0.target(),
e1.source(), e1.target()) == ACUTE; e1.source(), e1.target()) == ACUTE;
} }
template<class K> template<class K>
bool are_edges_orderly_collinear( Segment_2<K> const& e0, Segment_2<K> const& e1 ) bool are_edges_orderly_collinear( Segment_2_with_ID<K> const& e0, Segment_2_with_ID<K> const& e1 )
{ {
return are_edges_collinear(e0,e1) & are_parallel_edges_equally_oriented(e0,e1); return are_edges_collinear(e0,e1) & are_parallel_edges_equally_oriented(e0,e1);
} }
template<class K> template<class K>
Trisegment_collinearity trisegment_collinearity_no_exact_constructions ( Segment_2<K> const& e0 Trisegment_collinearity trisegment_collinearity_no_exact_constructions ( Segment_2_with_ID<K> const& e0
, Segment_2<K> const& e1 , Segment_2_with_ID<K> const& e1
, Segment_2<K> const& e2) , Segment_2_with_ID<K> const& e2)
{ {
bool is_01 = are_edges_orderly_collinear(e0,e1); bool is_01 = are_edges_orderly_collinear(e0,e1);
bool is_02 = are_edges_orderly_collinear(e0,e2); bool is_02 = are_edges_orderly_collinear(e0,e2);
@ -117,7 +117,7 @@ boost::optional< Line_2<K> > compute_normalized_line_ceoffC2( Segment_2<K> const
typedef typename K::FT FT ; typedef typename K::FT FT ;
FT a (0.0),b (0.0) ,c(0.0) ; FT a(0), b(0), c(0) ;
if(e.source().y() == e.target().y()) if(e.source().y() == e.target().y())
{ {
@ -199,6 +199,22 @@ boost::optional< Line_2<K> > compute_normalized_line_ceoffC2( Segment_2<K> const
return cgal_make_optional( finite, K().construct_line_2_object()(a,b,c) ) ; return cgal_make_optional( finite, K().construct_line_2_object()(a,b,c) ) ;
} }
template<class K, class CoeffCache>
boost::optional< Line_2<K> > compute_normalized_line_ceoffC2( Segment_2_with_ID<K> const& e,
CoeffCache& aCoeff_cache )
{
CGAL_precondition ( e.mID != std::size_t(-1) ) ;
if ( aCoeff_cache.IsCached(e.mID) )
return aCoeff_cache.Get(e.mID) ;
boost::optional< Line_2<K> > rRes = compute_normalized_line_ceoffC2 ( static_cast<Segment_2<K> const&>(e) ) ;
aCoeff_cache.Set(e.mID, rRes) ;
return rRes ;
}
template<class FT> template<class FT>
Rational<FT> squared_distance_from_point_to_lineC2( FT const& px, FT const& py, FT const& sx, FT const& sy, FT const& tx, FT const& ty ) Rational<FT> squared_distance_from_point_to_lineC2( FT const& px, FT const& py, FT const& sx, FT const& sy, FT const& tx, FT const& ty )
{ {
@ -219,9 +235,9 @@ Rational<FT> squared_distance_from_point_to_lineC2( FT const& px, FT const& py,
// NOTE: If the collinearity cannot be determined reliably, a null trisegment is returned. // NOTE: If the collinearity cannot be determined reliably, a null trisegment is returned.
// //
template<class K> template<class K>
boost::intrusive_ptr< Trisegment_2<K> > construct_trisegment ( Segment_2<K> const& e0 boost::intrusive_ptr< Trisegment_2<K> > construct_trisegment ( Segment_2_with_ID<K> const& e0
, Segment_2<K> const& e1 , Segment_2_with_ID<K> const& e1
, Segment_2<K> const& e2 , Segment_2_with_ID<K> const& e2
, std::size_t id , std::size_t id
) )
{ {
@ -250,8 +266,10 @@ boost::intrusive_ptr< Trisegment_2<K> > construct_trisegment ( Segment_2<K> cons
// //
// NOTE: The segments (e0,e1,e2) are stored in the argument as the trisegment st.event() // NOTE: The segments (e0,e1,e2) are stored in the argument as the trisegment st.event()
// //
template<class K> template <class K, class CoeffCache>
boost::optional< Rational< typename K::FT> > compute_normal_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri ) boost::optional< Rational< typename K::FT> >
compute_normal_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
CoeffCache& aCoeff_cache )
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -280,9 +298,9 @@ boost::optional< Rational< typename K::FT> > compute_normal_offset_lines_isec_ti
bool ok = false ; bool ok = false ;
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->e0()) ; Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->e0(), aCoeff_cache) ;
Optional_line_2 l1 = compute_normalized_line_ceoffC2(tri->e1()) ; Optional_line_2 l1 = compute_normalized_line_ceoffC2(tri->e1(), aCoeff_cache) ;
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2()) ; Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2(), aCoeff_cache) ;
if ( l0 && l1 && l2 ) if ( l0 && l1 && l2 )
{ {
@ -315,7 +333,8 @@ boost::optional< Rational< typename K::FT> > compute_normal_offset_lines_isec_ti
// POSTCONDITION: In case of overflow an empty optional is returned. // POSTCONDITION: In case of overflow an empty optional is returned.
// //
template<class K> template<class K>
boost::optional< Point_2<K> > compute_oriented_midpoint ( Segment_2<K> const& e0, Segment_2<K> const& e1 ) boost::optional< Point_2<K> > compute_oriented_midpoint ( Segment_2_with_ID<K> const& e0,
Segment_2_with_ID<K> const& e1 )
{ {
bool ok = false ; bool ok = false ;
@ -372,8 +391,10 @@ boost::optional< Point_2<K> > compute_oriented_midpoint ( Segment_2<K> const& e0
// so the degenerate seed is neither the left or the right seed. In this case, the SEED ID for the degenerate pseudo seed is UNKOWN. // so the degenerate seed is neither the left or the right seed. In this case, the SEED ID for the degenerate pseudo seed is UNKOWN.
// If you request the point of such degenerate pseudo seed the oriented midpoint bettwen e0 and e2 is returned. // If you request the point of such degenerate pseudo seed the oriented midpoint bettwen e0 and e2 is returned.
// //
template<class K> template <class K, class CoeffCache>
boost::optional< Point_2<K> > compute_seed_pointC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri, typename Trisegment_2<K>::SEED_ID sid ) boost::optional< Point_2<K> > compute_seed_pointC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
typename Trisegment_2<K>::SEED_ID sid,
CoeffCache& aCoeff_cache)
{ {
boost::optional< Point_2<K> > p ; boost::optional< Point_2<K> > p ;
@ -383,13 +404,13 @@ boost::optional< Point_2<K> > compute_seed_pointC2 ( boost::intrusive_ptr< Trise
{ {
case Trisegment_2::LEFT : case Trisegment_2::LEFT :
p = tri->child_l() ? construct_offset_lines_isecC2(tri->child_l()) // this can recurse p = tri->child_l() ? construct_offset_lines_isecC2(tri->child_l(), aCoeff_cache) // this can recurse
: compute_oriented_midpoint(tri->e0(),tri->e1()) ; : compute_oriented_midpoint(tri->e0(),tri->e1()) ;
break ; break ;
case Trisegment_2::RIGHT : case Trisegment_2::RIGHT :
p = tri->child_r() ? construct_offset_lines_isecC2(tri->child_r()) // this can recurse p = tri->child_r() ? construct_offset_lines_isecC2(tri->child_r(), aCoeff_cache) // this can recurse
: compute_oriented_midpoint(tri->e1(),tri->e2()) ; : compute_oriented_midpoint(tri->e1(),tri->e2()) ;
break ; break ;
@ -407,10 +428,11 @@ boost::optional< Point_2<K> > compute_seed_pointC2 ( boost::intrusive_ptr< Trise
// Given the trisegment tree for an event which is known to have a normal collinearity returns the seed point // Given the trisegment tree for an event which is known to have a normal collinearity returns the seed point
// of the degenerate seed. // of the degenerate seed.
// A normal collinearity occurs when e0,e1 or e1,e2 are collinear. // A normal collinearity occurs when e0,e1 or e1,e2 are collinear.
template<class K> template <class K, class CoeffCache>
boost::optional< Point_2<K> > compute_degenerate_seed_pointC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri ) boost::optional< Point_2<K> > compute_degenerate_seed_pointC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
CoeffCache& aCoeff_cache )
{ {
return compute_seed_pointC2( tri, tri->degenerate_seed_id() ) ; return compute_seed_pointC2( tri, tri->degenerate_seed_id(), aCoeff_cache ) ;
} }
// Given 3 oriented straight line segments: e0, e1, e2 // Given 3 oriented straight line segments: e0, e1, e2
@ -423,8 +445,10 @@ boost::optional< Point_2<K> > compute_degenerate_seed_pointC2 ( boost::intrusive
// //
// POSTCONDITION: In case of overflow an empty optional is returned. // POSTCONDITION: In case of overflow an empty optional is returned.
// //
template<class K> template <class K, class CoeffCache>
boost::optional< Rational< typename K::FT> > compute_degenerate_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri ) boost::optional< Rational< typename K::FT> >
compute_degenerate_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
CoeffCache& aCoeff_cache )
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -473,12 +497,13 @@ boost::optional< Rational< typename K::FT> > compute_degenerate_offset_lines_ise
// //
bool ok = false ; bool ok = false ;
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->collinear_edge ()) ; const Segment_2_with_ID<K>& ce = tri->collinear_edge();
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->non_collinear_edge()) ; Optional_line_2 l0 = compute_normalized_line_ceoffC2(ce, aCoeff_cache) ;
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->non_collinear_edge(), aCoeff_cache) ;
Optional_point_2 q = compute_degenerate_seed_pointC2(tri); Optional_point_2 q = compute_degenerate_seed_pointC2(tri, aCoeff_cache);
FT num(0.0), den(0.0) ; FT num(0), den(0) ;
if ( l0 && l2 && q ) if ( l0 && l2 && q )
{ {
@ -512,17 +537,23 @@ boost::optional< Rational< typename K::FT> > compute_degenerate_offset_lines_ise
// //
// Calls the appropiate function depending on the collinearity of the edges. // Calls the appropiate function depending on the collinearity of the edges.
// //
template<class K, class TimeCache> template<class K, class TimeCache, class CoeffCache>
boost::optional< Rational< typename K::FT > > compute_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri, TimeCache& cache) boost::optional< Rational< typename K::FT > > compute_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
TimeCache& aTime_cache,
CoeffCache& aCoeff_cache)
{ {
if (cache.is_time_cached(tri->id)) if ( aTime_cache.IsCached(tri->id()) )
return cache.time(tri->id); return aTime_cache.Get(tri->id()) ;
CGAL_precondition ( tri->collinearity() != TRISEGMENT_COLLINEARITY_ALL ) ; CGAL_precondition ( tri->collinearity() != TRISEGMENT_COLLINEARITY_ALL ) ;
boost::optional< Rational< typename K::FT > > res = tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? compute_normal_offset_lines_isec_timeC2 (tri) boost::optional< Rational< typename K::FT > > rRes =
: compute_degenerate_offset_lines_isec_timeC2(tri); tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? compute_normal_offset_lines_isec_timeC2 (tri, aCoeff_cache)
cache.set_time(tri->id, res); : compute_degenerate_offset_lines_isec_timeC2(tri, aCoeff_cache);
return res;
aTime_cache.Set(tri->id(), rRes) ;
return rRes ;
} }
// Given 3 oriented line segments e0, e1 and e2 // Given 3 oriented line segments e0, e1 and e2
@ -536,8 +567,9 @@ boost::optional< Rational< typename K::FT > > compute_offset_lines_isec_timeC2 (
// //
// POSTCONDITION: In case of overflow an empty optional is returned. // POSTCONDITION: In case of overflow an empty optional is returned.
// //
template<class K> template<class K, class CoeffCache>
boost::optional< Point_2<K> > construct_normal_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri ) boost::optional< Point_2<K> > construct_normal_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
CoeffCache& aCoeff_cache)
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -547,11 +579,11 @@ boost::optional< Point_2<K> > construct_normal_offset_lines_isecC2 ( boost::intr
CGAL_STSKEL_TRAITS_TRACE("Computing normal offset lines isec point for: " << tri ) ; CGAL_STSKEL_TRAITS_TRACE("Computing normal offset lines isec point for: " << tri ) ;
FT x(0.0),y(0.0) ; FT x(0), y(0) ;
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->e0()) ; Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->e0(), aCoeff_cache) ;
Optional_line_2 l1 = compute_normalized_line_ceoffC2(tri->e1()) ; Optional_line_2 l1 = compute_normalized_line_ceoffC2(tri->e1(), aCoeff_cache) ;
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2()) ; Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2(), aCoeff_cache) ;
bool ok = false ; bool ok = false ;
@ -595,8 +627,9 @@ boost::optional< Point_2<K> > construct_normal_offset_lines_isecC2 ( boost::intr
// //
// POSTCONDITION: In case of overflow an empty optional is returned. // POSTCONDITION: In case of overflow an empty optional is returned.
// //
template<class K> template <class K, class CoeffCache>
boost::optional< Point_2<K> > construct_degenerate_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri ) boost::optional< Point_2<K> > construct_degenerate_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
CoeffCache& aCoeff_cache)
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -610,10 +643,10 @@ boost::optional< Point_2<K> > construct_degenerate_offset_lines_isecC2 ( boost::
FT x(0.0),y(0.0) ; FT x(0.0),y(0.0) ;
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->collinear_edge ()) ; Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->collinear_edge (), aCoeff_cache) ;
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->non_collinear_edge()) ; Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->non_collinear_edge(), aCoeff_cache) ;
Optional_point_2 q = compute_degenerate_seed_pointC2(tri); Optional_point_2 q = compute_degenerate_seed_pointC2(tri, aCoeff_cache);
bool ok = false ; bool ok = false ;
@ -655,13 +688,14 @@ boost::optional< Point_2<K> > construct_degenerate_offset_lines_isecC2 ( boost::
// //
// Calls the appropiate function depending on the collinearity of the edges. // Calls the appropiate function depending on the collinearity of the edges.
// //
template<class K> template <class K, class CoeffCache>
boost::optional< Point_2<K> > construct_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri ) boost::optional< Point_2<K> > construct_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
CoeffCache& aCoeff_cache)
{ {
CGAL_precondition ( tri->collinearity() != TRISEGMENT_COLLINEARITY_ALL ) ; CGAL_precondition ( tri->collinearity() != TRISEGMENT_COLLINEARITY_ALL ) ;
return tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? construct_normal_offset_lines_isecC2 (tri) return tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? construct_normal_offset_lines_isecC2 (tri, aCoeff_cache)
: construct_degenerate_offset_lines_isecC2(tri) ; : construct_degenerate_offset_lines_isecC2(tri, aCoeff_cache) ;
} }
} // namespace CGAL_SS_i } // namespace CGAL_SS_i

View File

@ -24,29 +24,6 @@ namespace CGAL {
namespace CGAL_SS_i { namespace CGAL_SS_i {
template <class K>
struct No_cache
{
typedef boost::optional< Rational< typename K::FT > > Event_time;
bool is_time_cached(std::size_t)
{
return false;
}
Event_time time(std::size_t)
{
CGAL_error();
return Event_time();
}
void set_time(std::size_t, const Event_time&)
{}
void reset(std::size_t)
{}
};
// Given a triple of oriented straight line segments: (e0,e1,e2) such that // Given a triple of oriented straight line segments: (e0,e1,e2) such that
// there exists a distance 'et' for which the offsets lines at 'et' (e0',e1',e2') intersect in a single point; // there exists a distance 'et' for which the offsets lines at 'et' (e0',e1',e2') intersect in a single point;
// returns the relative order of 't' w.r.t 'et'. // returns the relative order of 't' w.r.t 'et'.
@ -64,7 +41,9 @@ Uncertain<Comparison_result> compare_offset_against_isec_timeC2 ( typename K::FT
Uncertain<Comparison_result> rResult = Uncertain<Comparison_result>::indeterminate(); Uncertain<Comparison_result> rResult = Uncertain<Comparison_result>::indeterminate();
No_cache<K> time_cache; typedef boost::optional< CGAL_SS_i::Rational< typename K::FT > > Event_time;
No_cache<Event_time> time_cache;
Optional_rational et_ = compute_offset_lines_isec_timeC2(tri, time_cache); Optional_rational et_ = compute_offset_lines_isec_timeC2(tri, time_cache);
if ( et_ ) if ( et_ )
{ {

View File

@ -21,7 +21,6 @@
#include <CGAL/Point_2.h> #include <CGAL/Point_2.h>
#include <CGAL/Quotient.h> #include <CGAL/Quotient.h>
#include <CGAL/Segment_2.h>
#include <CGAL/Uncertain.h> #include <CGAL/Uncertain.h>
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
@ -70,7 +69,7 @@ Uncertain<bool> certified_collinear_are_ordered_along_lineC2( Point_2<K> const&
// Returns true IFF segments e0,e1 share the same supporting line // Returns true IFF segments e0,e1 share the same supporting line
template<class K> template<class K>
Uncertain<bool> are_edges_collinearC2( Segment_2<K> const& e0, Segment_2<K> const& e1 ) Uncertain<bool> are_edges_collinearC2( Segment_2_with_ID<K> const& e0, Segment_2_with_ID<K> const& e1 )
{ {
return certified_collinearC2(e0.source(),e0.target(),e1.source()) return certified_collinearC2(e0.source(),e0.target(),e1.source())
& certified_collinearC2(e0.source(),e0.target(),e1.target()) ; & certified_collinearC2(e0.source(),e0.target(),e1.target()) ;
@ -79,7 +78,7 @@ Uncertain<bool> are_edges_collinearC2( Segment_2<K> const& e0, Segment_2<K> cons
// Returns true IFF the supporting lines for segments e0,e1 are parallel (or the same) // Returns true IFF the supporting lines for segments e0,e1 are parallel (or the same)
template<class K> template<class K>
inline inline
Uncertain<bool> are_edges_parallelC2( Segment_2<K> const& e0, Segment_2<K> const& e1 ) Uncertain<bool> are_edges_parallelC2( Segment_2_with_ID<K> const& e0, Segment_2_with_ID<K> const& e1 )
{ {
Uncertain<Sign> s = certified_sign_of_determinant2x2(e0.target().x() - e0.source().x() Uncertain<Sign> s = certified_sign_of_determinant2x2(e0.target().x() - e0.source().x()
,e0.target().y() - e0.source().y() ,e0.target().y() - e0.source().y()
@ -96,7 +95,7 @@ Uncertain<bool> are_edges_parallelC2( Segment_2<K> const& e0, Segment_2<K> const
// the three points are along the same line, in any order. // the three points are along the same line, in any order.
template<class K> template<class K>
inline inline
Uncertain<bool> are_parallel_edges_equally_orientedC2( Segment_2<K> const& e0, Segment_2<K> const& e1 ) Uncertain<bool> are_parallel_edges_equally_orientedC2( Segment_2_with_ID<K> const& e0, Segment_2_with_ID<K> const& e1 )
{ {
return CGAL_NTS certified_sign( (e0.target() - e0.source()) * (e1.target() - e1.source()) ) == POSITIVE; return CGAL_NTS certified_sign( (e0.target() - e0.source()) * (e1.target() - e1.source()) ) == POSITIVE;
} }
@ -105,7 +104,7 @@ Uncertain<bool> are_parallel_edges_equally_orientedC2( Segment_2<K> const& e0, S
// Returns true IFF segments e0,e1 share the same supporting line but do not overlap except at the vetices, and have the same orientation. // Returns true IFF segments e0,e1 share the same supporting line but do not overlap except at the vetices, and have the same orientation.
// NOTE: If e1 goes back over e0 (a degenerate antenna or alley) this returns false. // NOTE: If e1 goes back over e0 (a degenerate antenna or alley) this returns false.
template<class K> template<class K>
Uncertain<bool> are_edges_orderly_collinearC2( Segment_2<K> const& e0, Segment_2<K> const& e1 ) Uncertain<bool> are_edges_orderly_collinearC2( Segment_2_with_ID<K> const& e0, Segment_2_with_ID<K> const& e1 )
{ {
return are_edges_collinearC2(e0,e1) & are_parallel_edges_equally_orientedC2(e0,e1); return are_edges_collinearC2(e0,e1) & are_parallel_edges_equally_orientedC2(e0,e1);
} }
@ -128,9 +127,9 @@ Uncertain<Sign> certified_side_of_oriented_lineC2(const FT &a, const FT &b, cons
// (encoded as a collinear count of -1) // (encoded as a collinear count of -1)
// //
template<class K> template<class K>
Uncertain<Trisegment_collinearity> certified_trisegment_collinearity ( Segment_2<K> const& e0 Uncertain<Trisegment_collinearity> certified_trisegment_collinearity ( Segment_2_with_ID<K> const& e0
, Segment_2<K> const& e1 , Segment_2_with_ID<K> const& e1
, Segment_2<K> const& e2 , Segment_2_with_ID<K> const& e2
) )
{ {
Uncertain<bool> is_01 = are_edges_orderly_collinearC2(e0,e1); Uncertain<bool> is_01 = are_edges_orderly_collinearC2(e0,e1);
@ -175,10 +174,12 @@ Uncertain<Trisegment_collinearity> certified_trisegment_collinearity ( Segment_2
// Those seeds are used to determine the actual position of the degenerate vertex in case of collinear edges (since that point is // Those seeds are used to determine the actual position of the degenerate vertex in case of collinear edges (since that point is
// not given by the collinear edges alone) // not given by the collinear edges alone)
// //
template<class K, class FT, class TimeCache> template<class K, class FT, class TimeCache, class CoeffCache>
Uncertain<bool> exist_offset_lines_isec2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri Uncertain<bool> exist_offset_lines_isec2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri
, boost::optional<FT> const& aMaxTime , boost::optional<FT> const& aMaxTime
, TimeCache& time_cache ) , TimeCache& aTime_cache
, CoeffCache& aCoeff_cache
)
{ {
typedef Rational<FT> Rational ; typedef Rational<FT> Rational ;
@ -191,7 +192,7 @@ Uncertain<bool> exist_offset_lines_isec2 ( boost::intrusive_ptr< Trisegment_2<K>
{ {
CGAL_STSKEL_TRAITS_TRACE( ( tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? " normal edges" : " collinear edges" ) ) ; CGAL_STSKEL_TRAITS_TRACE( ( tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? " normal edges" : " collinear edges" ) ) ;
Optional_rational t = compute_offset_lines_isec_timeC2(tri, time_cache) ; Optional_rational t = compute_offset_lines_isec_timeC2(tri, aTime_cache, aCoeff_cache) ;
if ( t ) if ( t )
{ {
Uncertain<bool> d_is_zero = CGAL_NTS certified_is_zero(t->d()) ; Uncertain<bool> d_is_zero = CGAL_NTS certified_is_zero(t->d()) ;
@ -236,10 +237,11 @@ Uncertain<bool> exist_offset_lines_isec2 ( boost::intrusive_ptr< Trisegment_2<K>
// (m0',m1',m2') and (n0',n1',n2') intersect each in a single point; returns the relative order of mt w.r.t nt. // (m0',m1',m2') and (n0',n1',n2') intersect each in a single point; returns the relative order of mt w.r.t nt.
// That is, indicates which offset triple intersects first (closer to the source lines) // That is, indicates which offset triple intersects first (closer to the source lines)
// PRECONDITION: There exist distances mt and nt for which each offset triple intersect at a single point. // PRECONDITION: There exist distances mt and nt for which each offset triple intersect at a single point.
template<class K, class TimeCache> template<class K, class TimeCache, class CoeffCache>
Uncertain<Comparison_result> compare_offset_lines_isec_timesC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& m Uncertain<Comparison_result> compare_offset_lines_isec_timesC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& m
, boost::intrusive_ptr< Trisegment_2<K> > const& n , boost::intrusive_ptr< Trisegment_2<K> > const& n
, TimeCache& time_cache , TimeCache& aTime_cache
, CoeffCache& aCoeff_cache
) )
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -250,8 +252,8 @@ Uncertain<Comparison_result> compare_offset_lines_isec_timesC2 ( boost::intrusiv
Uncertain<Comparison_result> rResult = Uncertain<Comparison_result>::indeterminate(); Uncertain<Comparison_result> rResult = Uncertain<Comparison_result>::indeterminate();
Optional_rational mt_ = compute_offset_lines_isec_timeC2(m, time_cache); Optional_rational mt_ = compute_offset_lines_isec_timeC2(m, aTime_cache, aCoeff_cache);
Optional_rational nt_ = compute_offset_lines_isec_timeC2(n, time_cache); Optional_rational nt_ = compute_offset_lines_isec_timeC2(n, aTime_cache, aCoeff_cache);
if ( mt_ && nt_ ) if ( mt_ && nt_ )
{ {
@ -306,7 +308,8 @@ Uncertain<Comparison_result> compare_isec_anglesC2 ( Vector_2<K> const& aBV1
// Returns true if the point aP is on the positive side of the line supporting the edge // Returns true if the point aP is on the positive side of the line supporting the edge
// //
template<class K> template<class K>
Uncertain<bool> is_edge_facing_pointC2 ( boost::optional< Point_2<K> > const& aP, Segment_2<K> const& aEdge ) Uncertain<bool> is_edge_facing_pointC2 ( boost::optional< Point_2<K> > const& aP,
Segment_2_with_ID<K> const& aEdge )
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -323,10 +326,12 @@ Uncertain<bool> is_edge_facing_pointC2 ( boost::optional< Point_2<K> > const& aP
// Given a triple of oriented straight line segments: (e0,e1,e2) such that their offsets // Given a triple of oriented straight line segments: (e0,e1,e2) such that their offsets
// at some distance intersects in a point (x,y), returns true if (x,y) is on the positive side of the line supporting aEdge // at some distance intersects in a point (x,y), returns true if (x,y) is on the positive side of the line supporting aEdge
// //
template<class K> template<class K, class CoeffCache>
inline Uncertain<bool> is_edge_facing_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri, Segment_2<K> const& aEdge ) inline Uncertain<bool> is_edge_facing_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri,
Segment_2_with_ID<K> const& aEdge,
CoeffCache& aCoeff_cache)
{ {
return is_edge_facing_pointC2(construct_offset_lines_isecC2(tri),aEdge); return is_edge_facing_pointC2(construct_offset_lines_isecC2(tri, aCoeff_cache), aEdge);
} }
// Given an event trisegment and two oriented straight line segments e0 and e1, returns the oriented side of the event point // Given an event trisegment and two oriented straight line segments e0 and e1, returns the oriented side of the event point
@ -390,13 +395,14 @@ inline Uncertain<bool> is_edge_facing_offset_lines_isecC2 ( boost::intrusive_ptr
// If e0 and e1 are not consecutive in the input, v01_event is the event that defined they very first offset vertex. // If e0 and e1 are not consecutive in the input, v01_event is the event that defined they very first offset vertex.
// If e0 and e1 are consecutive, v01_event is null. // If e0 and e1 are consecutive, v01_event is null.
// //
template<class K> template<class K, class CoeffCache>
Uncertain<Oriented_side> Uncertain<Oriented_side>
oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& event oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& event
, Segment_2<K> const& e0 , Segment_2_with_ID<K> const& e0
, Segment_2<K> const& e1 , Segment_2_with_ID<K> const& e1
, boost::intrusive_ptr< Trisegment_2<K> > const& v01_event // can be null , boost::intrusive_ptr< Trisegment_2<K> > const& v01_event // can be null
, bool primary_is_0 , bool primary_is_0
, CoeffCache& aCoeff_cache
) )
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -408,10 +414,10 @@ oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2
try try
{ {
Point_2 p = validate(construct_offset_lines_isecC2(event)); Point_2 p = validate(construct_offset_lines_isecC2(event, aCoeff_cache));
Line_2 l0 = validate(compute_normalized_line_ceoffC2(e0)) ; Line_2 l0 = validate(compute_normalized_line_ceoffC2(e0, aCoeff_cache)) ;
Line_2 l1 = validate(compute_normalized_line_ceoffC2(e1)) ; Line_2 l1 = validate(compute_normalized_line_ceoffC2(e1, aCoeff_cache)) ;
CGAL_STSKEL_TRAITS_TRACE("Getting oriented side of point " << p2str(p) CGAL_STSKEL_TRAITS_TRACE("Getting oriented side of point " << p2str(p)
<< " w.r.t bisector [" << " w.r.t bisector ["
@ -430,7 +436,7 @@ oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2
// We need to compute the actual bisector line. // We need to compute the actual bisector line.
CGAL_assertion( v01_event || ( !v01_event && e0.target() == e1.source() ) ) ; CGAL_assertion( v01_event || ( !v01_event && e0.target() == e1.source() ) ) ;
Point_2 v01 = v01_event ? validate( construct_offset_lines_isecC2(v01_event) ) : e1.source() ; Point_2 v01 = v01_event ? validate( construct_offset_lines_isecC2(v01_event, aCoeff_cache) ) : e1.source() ;
CGAL_STSKEL_TRAITS_TRACE("v01=" << p2str(v01) << ( v01_event ? " (from skelton node)" : "" ) ) ; CGAL_STSKEL_TRAITS_TRACE("v01=" << p2str(v01) << ( v01_event ? " (from skelton node)" : "" ) ) ;
@ -515,10 +521,11 @@ oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2
// PRECONDITIONS: // PRECONDITIONS:
// There exist single points at which the offset lines for 'l' and 'r' at 'tl', 'tr' intersect. // There exist single points at which the offset lines for 'l' and 'r' at 'tl', 'tr' intersect.
// //
template<class K, class TimeCache> template<class K, class TimeCache, class CoeffCache>
Uncertain<bool> are_events_simultaneousC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& l, Uncertain<bool> are_events_simultaneousC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& l,
boost::intrusive_ptr< Trisegment_2<K> > const& r, boost::intrusive_ptr< Trisegment_2<K> > const& r,
TimeCache& time_cache ) TimeCache& aTime_cache,
CoeffCache& aCoeff_cache )
{ {
typedef typename K::FT FT ; typedef typename K::FT FT ;
@ -532,8 +539,8 @@ Uncertain<bool> are_events_simultaneousC2 ( boost::intrusive_ptr< Trisegment_2<K
Uncertain<bool> rResult = Uncertain<bool>::indeterminate(); Uncertain<bool> rResult = Uncertain<bool>::indeterminate();
Optional_rational lt_ = compute_offset_lines_isec_timeC2(l, time_cache); Optional_rational lt_ = compute_offset_lines_isec_timeC2(l, aTime_cache, aCoeff_cache);
Optional_rational rt_ = compute_offset_lines_isec_timeC2(r, time_cache); Optional_rational rt_ = compute_offset_lines_isec_timeC2(r, aTime_cache, aCoeff_cache);
if ( lt_ && rt_ ) if ( lt_ && rt_ )
{ {
@ -548,8 +555,8 @@ Uncertain<bool> are_events_simultaneousC2 ( boost::intrusive_ptr< Trisegment_2<K
{ {
if ( equal_times ) if ( equal_times )
{ {
Optional_point_2 li = construct_offset_lines_isecC2(l); Optional_point_2 li = construct_offset_lines_isecC2(l, aCoeff_cache);
Optional_point_2 ri = construct_offset_lines_isecC2(r); Optional_point_2 ri = construct_offset_lines_isecC2(r, aCoeff_cache);
if ( li && ri ) if ( li && ri )
rResult = CGAL_NTS logical_and( CGAL_NTS certified_is_equal(li->x(),ri->x()) rResult = CGAL_NTS logical_and( CGAL_NTS certified_is_equal(li->x(),ri->x())