mirror of https://github.com/CGAL/cgal
Harmonize speeds of collinear input segments + caching for non-filtered kernels
This commit is contained in:
parent
07750bd638
commit
b6333ed459
|
|
@ -189,7 +189,7 @@ Straight_skeleton_builder_2<Gt,Ss,V>::IsPseudoSplitEvent( EventPtr const& aEvent
|
|||
// contains aNode as a vertex.
|
||||
//
|
||||
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);
|
||||
|
||||
|
|
@ -204,7 +204,8 @@ void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvent( Vertex_handle aNod
|
|||
EventPtr lEvent = EventPtr( new SplitEvent (aTriedge,lTrisegment,aNode) ) ;
|
||||
|
||||
// filter split event
|
||||
if (CanSafelyIgnoreSplitEvent(lEvent, bound)) return;
|
||||
if (CanSafelyIgnoreSplitEvent(lEvent))
|
||||
return;
|
||||
|
||||
mVisitor.on_split_event_created(aNode) ;
|
||||
|
||||
|
|
@ -218,7 +219,7 @@ void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvent( Vertex_handle aNod
|
|||
|
||||
// Tests the reflex wavefront emerging from 'aNode' against the other contour edges in search for split events.
|
||||
template<class Gt, class Ss, class V>
|
||||
void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvents( Vertex_handle aNode, Triedge const& aPrevEventTriedge )
|
||||
void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvents( Vertex_handle aNode, Triedge const& aPrevEventTriedge )
|
||||
{
|
||||
// lLBorder and lRBorder are the consecutive contour edges forming the reflex wavefront.
|
||||
Triedge const& lTriedge = GetVertexTriedge(aNode);
|
||||
|
|
@ -231,9 +232,8 @@ void Straight_skeleton_builder_2<Gt,Ss,V>::CollectSplitEvents( Vertex_handle aNo
|
|||
<< " LBorder: E" << lLBorder->id() << " RBorder: E" << lRBorder->id()
|
||||
);
|
||||
|
||||
boost::optional<FT> bound =
|
||||
UpperBoundForValidSplitEvents(GetPrevInLAV(aNode), aNode, GetNextInLAV(aNode),
|
||||
mContourHalfedges.begin(), mContourHalfedges.end());
|
||||
ComputeUpperBoundForValidSplitEvents(GetPrevInLAV(aNode), aNode, GetNextInLAV(aNode),
|
||||
mContourHalfedges.begin(), mContourHalfedges.end());
|
||||
|
||||
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 )
|
||||
{
|
||||
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>
|
||||
void Straight_skeleton_builder_2<Gt,Ss,V>::InitPhase()
|
||||
{
|
||||
mVisitor.on_initialization_started(static_cast<int>(mSSkel->size_of_vertices()));
|
||||
CreateContourBisectors();
|
||||
HarmonizeSpeeds();
|
||||
CreateInitialEvents();
|
||||
mVisitor.on_initialization_finished();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,7 +186,24 @@ class Rational
|
|||
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
|
||||
// e0*,e1*,e2* [e* denotes an _offseted_ edge].
|
||||
|
|
@ -211,21 +228,19 @@ class Rational
|
|||
template<class K>
|
||||
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:
|
||||
|
||||
typedef typename K::Segment_2 Segment_2 ;
|
||||
|
||||
typedef boost::intrusive_ptr<Trisegment_2> Self_ptr ;
|
||||
|
||||
public:
|
||||
|
||||
Trisegment_2 ( Segment_2 const& aE0
|
||||
, Segment_2 const& aE1
|
||||
, Segment_2 const& aE2
|
||||
Trisegment_2 ( Segment_2_with_ID const& aE0
|
||||
, Segment_2_with_ID const& aE1
|
||||
, Segment_2_with_ID const& aE2
|
||||
, Trisegment_collinearity aCollinearity
|
||||
, std::size_t id
|
||||
, std::size_t aID
|
||||
)
|
||||
: id(id)
|
||||
: mID(aID)
|
||||
{
|
||||
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() ; }
|
||||
|
||||
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 const& e1() const { return e(1) ; }
|
||||
Segment_2 const& e2() const { return e(2) ; }
|
||||
Segment_2_with_ID const& e0() const { return e(0) ; }
|
||||
Segment_2_with_ID const& e1() const { return e(1) ; }
|
||||
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.
|
||||
// These methods returns the edges according to that classification.
|
||||
// PRECONDITION: Exactly 2 out of 3 edges are collinear
|
||||
Segment_2 const& collinear_edge () const { return e(mCSIdx) ; }
|
||||
Segment_2 const& non_collinear_edge() const { return e(mNCSIdx) ; }
|
||||
Segment_2 const& other_collinear_edge() const
|
||||
Segment_2_with_ID const& collinear_edge () const { return e(mCSIdx) ; }
|
||||
Segment_2_with_ID const& non_collinear_edge() const { return e(mNCSIdx) ; }
|
||||
Segment_2_with_ID const& other_collinear_edge() const
|
||||
{
|
||||
switch ( mCollinearity )
|
||||
{
|
||||
|
|
@ -297,7 +315,7 @@ public:
|
|||
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())
|
||||
<< " " << s2str(aTrisegment.e1())
|
||||
|
|
@ -335,11 +353,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::size_t id;
|
||||
std::size_t mID;
|
||||
|
||||
private :
|
||||
|
||||
Segment_2 mE[3];
|
||||
Segment_2_with_ID mE[3];
|
||||
Trisegment_collinearity mCollinearity ;
|
||||
unsigned mCSIdx, mNCSIdx ;
|
||||
|
||||
|
|
@ -347,13 +365,72 @@ private :
|
|||
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>
|
||||
struct Functor_base_2
|
||||
{
|
||||
typedef typename K::FT FT ;
|
||||
typedef typename K::Point_2 Point_2 ;
|
||||
typedef typename K::Vector_2 Vector_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 ;
|
||||
|
||||
|
|
@ -378,6 +455,9 @@ struct SS_converter : Converter
|
|||
typedef typename Source_kernel::Segment_2 Source_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<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) ) ;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
|
@ -434,7 +520,7 @@ struct SS_converter : Converter
|
|||
,cvt_s(tri->e1())
|
||||
,cvt_s(tri->e2())
|
||||
,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_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
|
||||
{
|
||||
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(Segment_2_with_ID)
|
||||
|
||||
} // namespace CGAL_SS_i
|
||||
|
||||
|
|
|
|||
|
|
@ -251,10 +251,6 @@ private :
|
|||
Vector_2 lV1 ( aEvent->point(), lEvent.seed0()->point() ); // @fixme ? is this correct?
|
||||
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) ;
|
||||
}
|
||||
|
||||
|
|
@ -268,21 +264,15 @@ private :
|
|||
if(lEvent.is_at_source_vertex())
|
||||
{
|
||||
// is_at_source_vertex <=> opposite node is seed0
|
||||
// std::cout << "seed1: " << lEvent.seed1()->point() << std::endl;
|
||||
lV1 = Vector_2( aEvent->point(), lEvent.seed1()->point() );
|
||||
lV2 = Vector_2( aEvent->point(), aEvent->point() + CreateVector(aEvent->triedge().e2()) ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "seed0: " << lEvent.seed0()->point() << std::endl;
|
||||
lV1 = Vector_2( aEvent->point(), lEvent.seed0()->point() );
|
||||
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) ;
|
||||
}
|
||||
|
||||
|
|
@ -535,10 +525,6 @@ public:
|
|||
{
|
||||
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) )
|
||||
return ( mBuilder->CompareEvents(aA,aB) == LARGER ) ;
|
||||
|
||||
|
|
@ -661,13 +647,30 @@ private :
|
|||
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 t = aH->vertex()->point() ;
|
||||
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
|
||||
{
|
||||
Point_2 s = aH->opposite()->vertex()->point() ;
|
||||
|
|
@ -684,9 +687,9 @@ private :
|
|||
{
|
||||
CGAL_precondition(aTriedge.is_valid() && aTriedge.is_skeleton());
|
||||
|
||||
Trisegment_2_ptr r = Construct_ss_trisegment_2(mTraits)(CreateSegment(aTriedge.e0())
|
||||
,CreateSegment(aTriedge.e1())
|
||||
,CreateSegment(aTriedge.e2())
|
||||
Trisegment_2_ptr r = Construct_ss_trisegment_2(mTraits)(CreateSegment<Traits>(aTriedge.e0())
|
||||
,CreateSegment<Traits>(aTriedge.e1())
|
||||
,CreateSegment<Traits>(aTriedge.e2())
|
||||
);
|
||||
|
||||
CGAL_STSKEL_BUILDER_TRACE(5,"Trisegment for " << aTriedge << ":" << r ) ;
|
||||
|
|
@ -828,8 +831,8 @@ private :
|
|||
bool IsOppositeEdgeFacingTheSplitSeed( Vertex_handle aSeed, Halfedge_handle aOpposite ) const
|
||||
{
|
||||
if ( aSeed->is_skeleton() )
|
||||
return Is_edge_facing_ss_node_2(mTraits)( GetTrisegment(aSeed), CreateSegment(aOpposite) ) ;
|
||||
else return Is_edge_facing_ss_node_2(mTraits)( aSeed->point() , 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<Traits>(aOpposite) ) ;
|
||||
}
|
||||
|
||||
Oriented_side EventPointOrientedSide( Event const& aEvent
|
||||
|
|
@ -840,8 +843,8 @@ private :
|
|||
) const
|
||||
{
|
||||
return Oriented_side_of_event_point_wrt_bisector_2(mTraits)( aEvent.trisegment()
|
||||
, CreateSegment(aE0)
|
||||
, CreateSegment(aE1)
|
||||
, CreateSegment<Traits>(aE0)
|
||||
, CreateSegment<Traits>(aE1)
|
||||
, GetTrisegment(aV01) // Can be null
|
||||
, aE0isPrimary
|
||||
) ;
|
||||
|
|
@ -1012,9 +1015,9 @@ private :
|
|||
|
||||
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 ) ;
|
||||
|
||||
EventPtr FindEdgeEvent( Vertex_handle aLNode, Vertex_handle aRNode, Triedge const& aPrevEventTriedge ) ;
|
||||
|
||||
|
|
@ -1024,6 +1027,9 @@ private :
|
|||
void UpdatePQ( Vertex_handle aV, Triedge const& aPrevEventTriedge ) ;
|
||||
void CreateInitialEvents();
|
||||
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 SetupNewNode( Vertex_handle aNode );
|
||||
|
|
@ -1206,43 +1212,41 @@ private :
|
|||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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,
|
||||
Halfedge_handle_vector_iterator , Halfedge_handle_vector_iterator,
|
||||
boost::mpl::bool_<false>)
|
||||
void ComputeUpperBoundForValidSplitEventsImpl(Vertex_handle, Vertex_handle, Vertex_handle,
|
||||
Halfedge_handle_vector_iterator, Halfedge_handle_vector_iterator,
|
||||
boost::mpl::bool_<false>)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<FT> UpperBoundForValidSplitEventsImpl(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_begin,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_end,
|
||||
boost::mpl::bool_<true>)
|
||||
void ComputeUpperBoundForValidSplitEventsImpl(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_begin,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_end,
|
||||
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>
|
||||
UpperBoundForValidSplitEvents(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_begin,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_end)
|
||||
void ComputeUpperBoundForValidSplitEvents(Vertex_handle lPrev, Vertex_handle aNode, Vertex_handle lNext,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_begin,
|
||||
Halfedge_handle_vector_iterator contour_halfedges_end)
|
||||
{
|
||||
return UpperBoundForValidSplitEventsImpl(lPrev, aNode, lNext, contour_halfedges_begin, contour_halfedges_end,
|
||||
typename CGAL_SS_i::has_Filters_split_events_tag<Traits>::type());
|
||||
return ComputeUpperBoundForValidSplitEventsImpl(lPrev, aNode, lNext, contour_halfedges_begin, contour_halfedges_end,
|
||||
typename CGAL_SS_i::has_Filters_split_events_tag<Traits>::type());
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -31,64 +31,27 @@ namespace CGAL {
|
|||
|
||||
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>
|
||||
struct Construct_ss_trisegment_2 : Functor_base_2<K>
|
||||
{
|
||||
typedef Functor_base_2<K> Base ;
|
||||
|
||||
typedef typename Base::Segment_2 Segment_2 ;
|
||||
typedef typename Base::Trisegment_2 Trisegment_2 ;
|
||||
typedef typename Base::Segment_2_with_ID Segment_2_with_ID ;
|
||||
typedef typename Base::Trisegment_2_ptr Trisegment_2_ptr ;
|
||||
|
||||
typedef Trisegment_2_ptr result_type ;
|
||||
|
||||
template <class 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>
|
||||
|
|
@ -101,20 +64,22 @@ struct Do_ss_event_exist_2 : Functor_base_2<K>
|
|||
|
||||
typedef Uncertain<bool> result_type ;
|
||||
|
||||
Do_ss_event_exist_2(Time_cache<K>& time_cache)
|
||||
: mTime_cache(time_cache)
|
||||
Do_ss_event_exist_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_cache)
|
||||
: mTime_cache(aTime_cache), mCoeff_cache(aCoeff_cache)
|
||||
{}
|
||||
|
||||
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);
|
||||
|
||||
return rResult ;
|
||||
}
|
||||
|
||||
Time_cache<K>& mTime_cache;
|
||||
private:
|
||||
Time_cache<K>& mTime_cache ;
|
||||
Coeff_cache<K>& mCoeff_cache ;
|
||||
};
|
||||
|
||||
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 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 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) ;
|
||||
}
|
||||
|
||||
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>
|
||||
|
|
@ -148,20 +120,22 @@ struct Compare_ss_event_times_2 : Functor_base_2<K>
|
|||
|
||||
typedef Uncertain<Comparison_result> result_type ;
|
||||
|
||||
Compare_ss_event_times_2(Time_cache<K>& time_cache)
|
||||
: mTime_cache(time_cache)
|
||||
Compare_ss_event_times_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_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> 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 );
|
||||
|
||||
return rResult ;
|
||||
}
|
||||
|
||||
Time_cache<K>& mTime_cache;
|
||||
private:
|
||||
Time_cache<K>& mTime_cache ;
|
||||
Coeff_cache<K>& mCoeff_cache ;
|
||||
};
|
||||
|
||||
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 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::Point_2 Point_2 ;
|
||||
|
||||
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
|
||||
, Segment_2 const& aE0
|
||||
, Segment_2 const& aE1
|
||||
, Segment_2_with_ID const& aE0
|
||||
, Segment_2_with_ID const& aE1
|
||||
, Trisegment_2_ptr const& aE01Event
|
||||
, bool aE0isPrimary
|
||||
) 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 );
|
||||
|
||||
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 ;
|
||||
|
||||
|
||||
Are_ss_events_simultaneous_2(Time_cache<K>& time_cache)
|
||||
: mTime_cache(time_cache)
|
||||
Are_ss_events_simultaneous_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_cache)
|
||||
: mTime_cache(aTime_cache), mCoeff_cache(aCoeff_cache)
|
||||
{}
|
||||
|
||||
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);
|
||||
|
||||
return rResult ;
|
||||
}
|
||||
|
||||
Time_cache<K>& mTime_cache;
|
||||
private:
|
||||
Time_cache<K>& mTime_cache ;
|
||||
Coeff_cache<K>& mCoeff_cache ;
|
||||
};
|
||||
|
||||
template<class K>
|
||||
|
|
@ -245,11 +227,11 @@ struct Are_ss_edges_collinear_2 : Functor_base_2<K>
|
|||
{
|
||||
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 ;
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -264,11 +246,11 @@ struct Are_ss_edges_parallel_2 : Functor_base_2<K>
|
|||
{
|
||||
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 ;
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -286,15 +268,15 @@ struct Construct_ss_event_time_and_point_2 : Functor_base_2<K>
|
|||
|
||||
typedef typename Base::FT FT ;
|
||||
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 boost::tuple<FT,Point_2> rtype ;
|
||||
|
||||
typedef boost::optional<rtype> result_type ;
|
||||
|
||||
Construct_ss_event_time_and_point_2(Time_cache<K>& time_cache)
|
||||
:mTime_cache(time_cache)
|
||||
Construct_ss_event_time_and_point_2(Time_cache<K>& aTime_cache, Coeff_cache<K>& aCoeff_cache)
|
||||
: mTime_cache(aTime_cache), mCoeff_cache(aCoeff_cache)
|
||||
{}
|
||||
|
||||
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) ;
|
||||
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()) ) )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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) )
|
||||
{
|
||||
Segment_2 const& e0 = aTrisegment->e0() ;
|
||||
Segment_2 const& e1 = aTrisegment->e1() ;
|
||||
Segment_2 const& e2 = aTrisegment->e2() ;
|
||||
Segment_2_with_ID const& e0 = aTrisegment->e0() ;
|
||||
Segment_2_with_ID const& e1 = aTrisegment->e1() ;
|
||||
Segment_2_with_ID const& e2 = aTrisegment->e2() ;
|
||||
|
||||
Point_2 const& e0s = e0.source();
|
||||
Point_2 const& e0t = e0.target();
|
||||
|
|
@ -376,7 +358,9 @@ struct Construct_ss_event_time_and_point_2 : Functor_base_2<K>
|
|||
return rR ;
|
||||
}
|
||||
|
||||
Time_cache<K>& mTime_cache;
|
||||
private:
|
||||
Time_cache<K>& mTime_cache ;
|
||||
Coeff_cache<K>& mCoeff_cache ;
|
||||
};
|
||||
|
||||
} // 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::Vector_2 Vector_2 ;
|
||||
typedef typename K::Direction_2 Direction_2 ;
|
||||
typedef typename K::Segment_2 Segment_2 ;
|
||||
|
||||
typedef CGAL_SS_i::Trisegment_2<K> Trisegment_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 typename Trisegment_2::Self_ptr Trisegment_2_ptr ;
|
||||
|
||||
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>
|
||||
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_base<K> Base ;
|
||||
|
||||
public:
|
||||
|
||||
mutable std::size_t trisegment_id = 0;
|
||||
|
||||
typedef Unfiltered_predicate_adaptor<typename Unfiltering::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_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;
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
|
@ -498,10 +482,124 @@ public:
|
|||
{
|
||||
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>
|
||||
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::Approximate_kernel FK ;
|
||||
|
|
@ -598,36 +696,53 @@ public:
|
|||
Compare_ss_event_times_2
|
||||
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)),
|
||||
typename Filtering::Compare_ss_event_times_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) );
|
||||
return Compare_ss_event_times_2( typename Exact::Compare_ss_event_times_2(
|
||||
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
|
||||
get(Compare_ss_event_angles_2 const* = 0 ) const
|
||||
Is_edge_facing_ss_node_2
|
||||
get(Is_edge_facing_ss_node_2 const* = 0 ) const
|
||||
{
|
||||
return Compare_ss_event_angles_2( typename Exact::Compare_ss_event_angles_2(),
|
||||
typename Filtering::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::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
|
||||
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)),
|
||||
typename Filtering::Do_ss_event_exist_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) );
|
||||
return Do_ss_event_exist_2( typename Exact::Do_ss_event_exist_2(
|
||||
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
|
||||
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)),
|
||||
typename Filtering::Are_ss_events_simultaneous_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) );
|
||||
return Are_ss_events_simultaneous_2( typename Exact::Are_ss_events_simultaneous_2(
|
||||
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
|
||||
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)),
|
||||
typename Filtering::Construct_ss_event_time_and_point_2(const_cast<CGAL_SS_i::Time_cache<FK>&>(mApproximate_traits.time_cache)) );
|
||||
return Construct_ss_event_time_and_point_2( typename Exact::Construct_ss_event_time_and_point_2(
|
||||
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
|
||||
Construct_ss_trisegment_2
|
||||
|
|
@ -636,121 +751,165 @@ public:
|
|||
return Construct_ss_trisegment_2(*this);
|
||||
}
|
||||
|
||||
// functions and tag for filtering split events
|
||||
struct Filters_split_events_tag{};
|
||||
|
||||
template <class EventPtr>
|
||||
bool
|
||||
can_safely_ignore_split_event(const EventPtr& lEvent, const boost::optional<double>& bound)
|
||||
{
|
||||
// filter event
|
||||
if (bound)
|
||||
{
|
||||
typedef FK Interval_kernel;
|
||||
typename Interval_kernel::FT::Protector p;
|
||||
Cartesian_converter<K, Interval_kernel> to_interval;
|
||||
typedef CGAL_SS_i::Trisegment_2<Interval_kernel> Target_trisegment_2 ;
|
||||
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())
|
||||
,to_interval(lEvent->trisegment()->e2())
|
||||
,lEvent->trisegment()->collinearity()
|
||||
,lEvent->trisegment()->id
|
||||
);
|
||||
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));
|
||||
|
||||
if (opt_time && opt_time->to_nt().inf() > *bound)
|
||||
{
|
||||
reset_trisegment(tri->id); // avoid filling the cache vectors with times of trisegments that will be removed
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(Uncertain_conversion_exception&)
|
||||
{}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Vertex_handle, class Halfedge_handle_vector_iterator>
|
||||
boost::optional<double>
|
||||
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_end)
|
||||
{
|
||||
boost::optional<double> bound;
|
||||
if ( aNode->is_contour())
|
||||
{
|
||||
|
||||
typedef FK Interval_kernel;
|
||||
Cartesian_converter<K, Interval_kernel> to_interval;
|
||||
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;
|
||||
|
||||
Segment_2 s1(to_interval(lPrev->point()), to_interval(aNode->point()));
|
||||
Segment_2 s2(to_interval(aNode->point()), to_interval(lNext->point()));
|
||||
|
||||
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 v1(l1->a(), l1->b());
|
||||
Vector_2 v2(l2->a(), l2->b());
|
||||
Ray_2 bisect_ray(to_interval(aNode->point()), v1+v2);
|
||||
|
||||
// Cartesian_converter<Interval_kernel, K> to_input;
|
||||
// std::cout << "bisect " << aNode->point() << " " << aNode->point() + to_input(v1+v2) << "\n";
|
||||
|
||||
for ( Halfedge_handle_vector_iterator i = contour_halfedges_begin; i != contour_halfedges_end; ++ i )
|
||||
{
|
||||
try{
|
||||
CGAL_assertion((*i)->vertex()->is_contour() && (*i)->opposite()->vertex()->is_contour() );
|
||||
Segment_2 s_h(to_interval((*i)->opposite()->vertex()->point()),
|
||||
to_interval((*i)->vertex()->point()));
|
||||
|
||||
Uncertain<bool> inter = do_intersect(s_h, bisect_ray);
|
||||
Uncertain<Oriented_side> orient = orientation(s_h[0], s_h[1], to_interval(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;
|
||||
|
||||
boost::optional< Line_2 > lh = CGAL_SS_i::compute_normalized_line_ceoffC2(s_h); // Note that we don't need the normalization
|
||||
|
||||
typename Interval_kernel::FT h_bound =
|
||||
( - lh->c() -lh->a() * to_interval(aNode->point().x()) - lh->b() * to_interval(aNode->point().y()) ) /
|
||||
(lh->a() * ( (v1+v2).x() ) + lh->b() * ( (v1+v2).y() ));
|
||||
|
||||
if (!bound || *bound>h_bound.sup())
|
||||
bound=h_bound.sup();
|
||||
}
|
||||
catch(CGAL::Uncertain_conversion_exception&)
|
||||
{}
|
||||
}
|
||||
}
|
||||
// if (bound) std::cout << "bound is " << *bound << "\n";
|
||||
return bound;
|
||||
}
|
||||
|
||||
// TODO: as soon as an exact value we could refine the interval one. Not sure if it is worth it
|
||||
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;
|
||||
// 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)
|
||||
if ( i+1 == trisegment_ID() )
|
||||
{
|
||||
--trisegment_id;
|
||||
mExact_traits.time_cache.reset(i);
|
||||
mApproximate_traits.time_cache.reset(i);
|
||||
--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
|
||||
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>
|
||||
bool CanSafelyIgnoreSplitEvent(const EventPtr& lEvent)
|
||||
{
|
||||
// filter event
|
||||
if ( ! mApproximate_traits.mFilteringBound )
|
||||
return false;
|
||||
|
||||
typename FK::FT::Protector p;
|
||||
|
||||
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;
|
||||
|
||||
C2F to_FK ;
|
||||
Source_trisegment_2_ptr src_tri = lEvent->trisegment() ;
|
||||
CGAL_assertion( src_tri != nullptr ) ;
|
||||
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
|
||||
{
|
||||
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 ( lOptTime && lOptTime->to_nt() > *mApproximate_traits.mFilteringBound )
|
||||
{
|
||||
// avoid filling the cache vectors with times of trisegments that will be removed
|
||||
reset_trisegment(tri->id());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(Uncertain_conversion_exception&)
|
||||
{}
|
||||
|
||||
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)
|
||||
{
|
||||
mApproximate_traits.mFilteringBound = boost::none;
|
||||
|
||||
if ( ! aNode->is_contour() )
|
||||
return ;
|
||||
|
||||
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;
|
||||
|
||||
typename FK::FT::Protector protector;
|
||||
|
||||
C2F to_FK;
|
||||
|
||||
Target_Point_2 laP = to_FK(aNode->point());
|
||||
Target_Segment_2 s1(to_FK(lPrev->point()), laP);
|
||||
Target_Segment_2 s2(laP, to_FK(lNext->point()));
|
||||
|
||||
// @todo? These are not input segments, but it might still worth caching (just gotta assign them an ID)
|
||||
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 )
|
||||
{
|
||||
try
|
||||
{
|
||||
CGAL_assertion((*i)->vertex()->is_contour() && (*i)->opposite()->vertex()->is_contour() );
|
||||
Target_Segment_2 s_h(to_FK((*i)->opposite()->vertex()->point()), to_FK((*i)->vertex()->point()));
|
||||
|
||||
Uncertain<bool> inter = FK().do_intersect_2_object()(s_h, bisect_ray);
|
||||
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
|
||||
// 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< Target_Line_2 > lh = CGAL_SS_i::compute_normalized_line_ceoffC2(s_h);
|
||||
|
||||
typename FK::FT lBound = ( - lh->c() - lh->a()*laP.x() - lh->b()*laP.y() ) /
|
||||
( lh->a()*lV12.x() + lh->b()*lV12.y() );
|
||||
|
||||
if ( ! is_finite(lBound) )
|
||||
continue;
|
||||
|
||||
if ( ! mApproximate_traits.mFilteringBound || *mApproximate_traits.mFilteringBound > lBound )
|
||||
mApproximate_traits.mFilteringBound = lBound ;
|
||||
}
|
||||
catch(CGAL::Uncertain_conversion_exception&)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// TODO: as soon as an exact value we could refine the interval one. Not sure if it is worth it
|
||||
Exact mExact_traits ;
|
||||
|
||||
// Below is only used for the cached variables not the functor types
|
||||
Straight_skeleton_builder_traits_2_impl<Tag_false, FK> mApproximate_traits ;
|
||||
} ;
|
||||
|
||||
template<class K>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
namespace CGAL {
|
||||
|
||||
template < class Refs, class S >
|
||||
template < class Refs >
|
||||
class Straight_skeleton_halfedge_base_base_2
|
||||
{
|
||||
public:
|
||||
|
|
@ -38,9 +38,7 @@ public:
|
|||
typedef typename Refs::Vertex Vertex;
|
||||
typedef typename Refs::Face Face;
|
||||
|
||||
typedef Straight_skeleton_halfedge_base_base_2<Refs,S> Base_base ;
|
||||
|
||||
typedef S Segment_2;
|
||||
typedef Straight_skeleton_halfedge_base_base_2<Refs> Base_base ;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
@ -107,8 +105,8 @@ private:
|
|||
Sign mSlope ;
|
||||
};
|
||||
|
||||
template < class Refs, class S >
|
||||
class Straight_skeleton_halfedge_base_2 : public Straight_skeleton_halfedge_base_base_2<Refs,S>
|
||||
template < class Refs >
|
||||
class Straight_skeleton_halfedge_base_2 : public Straight_skeleton_halfedge_base_base_2<Refs>
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
@ -116,8 +114,8 @@ public:
|
|||
typedef typename Refs::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Refs::Face_handle Face_handle;
|
||||
|
||||
typedef Straight_skeleton_halfedge_base_base_2<Refs,S> Base_base ;
|
||||
typedef Straight_skeleton_halfedge_base_2<Refs,S> Base ;
|
||||
typedef Straight_skeleton_halfedge_base_base_2<Refs> Base_base ;
|
||||
typedef Straight_skeleton_halfedge_base_2<Refs> Base ;
|
||||
|
||||
Straight_skeleton_halfedge_base_2() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ public:
|
|||
template<class Refs, class Traits>
|
||||
struct Halfedge_wrapper
|
||||
{
|
||||
typedef typename Traits::Segment_2 Segment ;
|
||||
typedef Straight_skeleton_halfedge_base_2 < Refs, Segment > Halfedge;
|
||||
typedef Straight_skeleton_halfedge_base_2 < Refs > Halfedge;
|
||||
};
|
||||
|
||||
template<class Refs, class Traits>
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@ namespace CGAL_SS_i {
|
|||
//
|
||||
// POSTCONDITION: In case of overflow an empty optional is returned.
|
||||
//
|
||||
template<class K>
|
||||
boost::optional< Point_2<K> > construct_offset_pointC2 ( typename K::FT const& t
|
||||
, Segment_2<K> const& e0
|
||||
, Segment_2<K> const& e1
|
||||
, boost::intrusive_ptr< Trisegment_2<K> > const& tri)
|
||||
template<class K, class CoeffCache>
|
||||
boost::optional< Point_2<K> > construct_offset_pointC2 ( typename K::FT const& t
|
||||
, Segment_2_with_ID<K> const& e0
|
||||
, Segment_2_with_ID<K> const& e1
|
||||
, boost::intrusive_ptr< Trisegment_2<K> > const& tri
|
||||
, CoeffCache& aCoeff_cache)
|
||||
{
|
||||
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 ) ;
|
||||
|
||||
Optional_line_2 l0 = compute_normalized_line_ceoffC2(e0) ;
|
||||
Optional_line_2 l1 = compute_normalized_line_ceoffC2(e1) ;
|
||||
Optional_line_2 l0 = compute_normalized_line_ceoffC2(e0, aCoeff_cache) ;
|
||||
Optional_line_2 l1 = compute_normalized_line_ceoffC2(e1, aCoeff_cache) ;
|
||||
|
||||
bool ok = false ;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace CGAL {
|
|||
namespace CGAL_SS_i {
|
||||
|
||||
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()))
|
||||
&& ( (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>
|
||||
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(),
|
||||
e1.source(), e1.target()) == ACUTE;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
template<class K>
|
||||
Trisegment_collinearity trisegment_collinearity_no_exact_constructions ( Segment_2<K> const& e0
|
||||
, Segment_2<K> const& e1
|
||||
, Segment_2<K> const& e2)
|
||||
Trisegment_collinearity trisegment_collinearity_no_exact_constructions ( Segment_2_with_ID<K> const& e0
|
||||
, Segment_2_with_ID<K> const& e1
|
||||
, Segment_2_with_ID<K> const& e2)
|
||||
{
|
||||
bool is_01 = are_edges_orderly_collinear(e0,e1);
|
||||
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 ;
|
||||
|
||||
FT a (0.0),b (0.0) ,c(0.0) ;
|
||||
FT a(0), b(0), c(0) ;
|
||||
|
||||
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) ) ;
|
||||
}
|
||||
|
||||
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>
|
||||
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,11 +235,11 @@ 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.
|
||||
//
|
||||
template<class K>
|
||||
boost::intrusive_ptr< Trisegment_2<K> > construct_trisegment ( Segment_2<K> const& e0
|
||||
, Segment_2<K> const& e1
|
||||
, Segment_2<K> const& e2
|
||||
, std::size_t id
|
||||
)
|
||||
boost::intrusive_ptr< Trisegment_2<K> > construct_trisegment ( Segment_2_with_ID<K> const& e0
|
||||
, Segment_2_with_ID<K> const& e1
|
||||
, Segment_2_with_ID<K> const& e2
|
||||
, std::size_t id
|
||||
)
|
||||
{
|
||||
typedef Trisegment_2<K> Trisegment_2 ;
|
||||
typedef typename Trisegment_2::Self_ptr Trisegment_2_ptr ;
|
||||
|
|
@ -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()
|
||||
//
|
||||
template<class K>
|
||||
boost::optional< Rational< typename K::FT> > compute_normal_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri )
|
||||
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,
|
||||
CoeffCache& aCoeff_cache )
|
||||
{
|
||||
typedef typename K::FT FT ;
|
||||
|
||||
|
|
@ -280,9 +298,9 @@ boost::optional< Rational< typename K::FT> > compute_normal_offset_lines_isec_ti
|
|||
|
||||
bool ok = false ;
|
||||
|
||||
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->e0()) ;
|
||||
Optional_line_2 l1 = compute_normalized_line_ceoffC2(tri->e1()) ;
|
||||
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2()) ;
|
||||
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->e0(), aCoeff_cache) ;
|
||||
Optional_line_2 l1 = compute_normalized_line_ceoffC2(tri->e1(), aCoeff_cache) ;
|
||||
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2(), aCoeff_cache) ;
|
||||
|
||||
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.
|
||||
//
|
||||
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 ;
|
||||
|
||||
|
|
@ -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.
|
||||
// If you request the point of such degenerate pseudo seed the oriented midpoint bettwen e0 and e2 is returned.
|
||||
//
|
||||
template<class K>
|
||||
boost::optional< Point_2<K> > compute_seed_pointC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri, typename Trisegment_2<K>::SEED_ID sid )
|
||||
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,
|
||||
CoeffCache& aCoeff_cache)
|
||||
{
|
||||
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 :
|
||||
|
||||
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()) ;
|
||||
break ;
|
||||
|
||||
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()) ;
|
||||
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
|
||||
// of the degenerate seed.
|
||||
// A normal collinearity occurs when e0,e1 or e1,e2 are collinear.
|
||||
template<class K>
|
||||
boost::optional< Point_2<K> > compute_degenerate_seed_pointC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri )
|
||||
template <class K, class CoeffCache>
|
||||
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
|
||||
|
|
@ -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.
|
||||
//
|
||||
template<class K>
|
||||
boost::optional< Rational< typename K::FT> > compute_degenerate_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri )
|
||||
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,
|
||||
CoeffCache& aCoeff_cache )
|
||||
{
|
||||
typedef typename K::FT FT ;
|
||||
|
||||
|
|
@ -473,12 +497,13 @@ boost::optional< Rational< typename K::FT> > compute_degenerate_offset_lines_ise
|
|||
//
|
||||
bool ok = false ;
|
||||
|
||||
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->collinear_edge ()) ;
|
||||
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->non_collinear_edge()) ;
|
||||
const Segment_2_with_ID<K>& ce = tri->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 )
|
||||
{
|
||||
|
|
@ -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.
|
||||
//
|
||||
template<class K, class TimeCache>
|
||||
boost::optional< Rational< typename K::FT > > compute_offset_lines_isec_timeC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri, TimeCache& cache)
|
||||
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& aTime_cache,
|
||||
CoeffCache& aCoeff_cache)
|
||||
{
|
||||
if (cache.is_time_cached(tri->id))
|
||||
return cache.time(tri->id);
|
||||
if ( aTime_cache.IsCached(tri->id()) )
|
||||
return aTime_cache.Get(tri->id()) ;
|
||||
|
||||
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)
|
||||
: compute_degenerate_offset_lines_isec_timeC2(tri);
|
||||
cache.set_time(tri->id, res);
|
||||
return res;
|
||||
boost::optional< Rational< typename K::FT > > rRes =
|
||||
tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? compute_normal_offset_lines_isec_timeC2 (tri, aCoeff_cache)
|
||||
: compute_degenerate_offset_lines_isec_timeC2(tri, aCoeff_cache);
|
||||
|
||||
aTime_cache.Set(tri->id(), rRes) ;
|
||||
|
||||
return rRes ;
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
template<class K>
|
||||
boost::optional< Point_2<K> > construct_normal_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri )
|
||||
template<class K, class CoeffCache>
|
||||
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 ;
|
||||
|
||||
|
|
@ -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 ) ;
|
||||
|
||||
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 l1 = compute_normalized_line_ceoffC2(tri->e1()) ;
|
||||
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2()) ;
|
||||
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->e0(), aCoeff_cache) ;
|
||||
Optional_line_2 l1 = compute_normalized_line_ceoffC2(tri->e1(), aCoeff_cache) ;
|
||||
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->e2(), aCoeff_cache) ;
|
||||
|
||||
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.
|
||||
//
|
||||
template<class K>
|
||||
boost::optional< Point_2<K> > construct_degenerate_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri )
|
||||
template <class K, class CoeffCache>
|
||||
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 ;
|
||||
|
||||
|
|
@ -610,10 +643,10 @@ boost::optional< Point_2<K> > construct_degenerate_offset_lines_isecC2 ( boost::
|
|||
|
||||
FT x(0.0),y(0.0) ;
|
||||
|
||||
Optional_line_2 l0 = compute_normalized_line_ceoffC2(tri->collinear_edge ()) ;
|
||||
Optional_line_2 l2 = compute_normalized_line_ceoffC2(tri->non_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(), 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 ;
|
||||
|
||||
|
|
@ -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.
|
||||
//
|
||||
template<class K>
|
||||
boost::optional< Point_2<K> > construct_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri )
|
||||
template <class K, class CoeffCache>
|
||||
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 ) ;
|
||||
|
||||
return tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? construct_normal_offset_lines_isecC2 (tri)
|
||||
: construct_degenerate_offset_lines_isecC2(tri) ;
|
||||
return tri->collinearity() == TRISEGMENT_COLLINEARITY_NONE ? construct_normal_offset_lines_isecC2 (tri, aCoeff_cache)
|
||||
: construct_degenerate_offset_lines_isecC2(tri, aCoeff_cache) ;
|
||||
}
|
||||
|
||||
} // namespace CGAL_SS_i
|
||||
|
|
|
|||
|
|
@ -24,29 +24,6 @@ namespace CGAL {
|
|||
|
||||
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
|
||||
// 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'.
|
||||
|
|
@ -64,7 +41,9 @@ Uncertain<Comparison_result> compare_offset_against_isec_timeC2 ( typename K::FT
|
|||
|
||||
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);
|
||||
if ( et_ )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include <CGAL/Point_2.h>
|
||||
#include <CGAL/Quotient.h>
|
||||
#include <CGAL/Segment_2.h>
|
||||
#include <CGAL/Uncertain.h>
|
||||
|
||||
#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
|
||||
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())
|
||||
& 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)
|
||||
template<class K>
|
||||
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()
|
||||
,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.
|
||||
template<class K>
|
||||
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;
|
||||
}
|
||||
|
|
@ -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.
|
||||
// NOTE: If e1 goes back over e0 (a degenerate antenna or alley) this returns false.
|
||||
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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
//
|
||||
template<class K>
|
||||
Uncertain<Trisegment_collinearity> certified_trisegment_collinearity ( Segment_2<K> const& e0
|
||||
, Segment_2<K> const& e1
|
||||
, Segment_2<K> const& e2
|
||||
Uncertain<Trisegment_collinearity> certified_trisegment_collinearity ( Segment_2_with_ID<K> const& e0
|
||||
, Segment_2_with_ID<K> const& e1
|
||||
, Segment_2_with_ID<K> const& e2
|
||||
)
|
||||
{
|
||||
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
|
||||
// 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
|
||||
, boost::optional<FT> const& aMaxTime
|
||||
, TimeCache& time_cache )
|
||||
, TimeCache& aTime_cache
|
||||
, CoeffCache& aCoeff_cache
|
||||
)
|
||||
{
|
||||
|
||||
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" ) ) ;
|
||||
|
||||
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 )
|
||||
{
|
||||
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.
|
||||
// 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.
|
||||
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
|
||||
, boost::intrusive_ptr< Trisegment_2<K> > const& n
|
||||
, TimeCache& time_cache
|
||||
, TimeCache& aTime_cache
|
||||
, CoeffCache& aCoeff_cache
|
||||
)
|
||||
{
|
||||
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();
|
||||
|
||||
Optional_rational mt_ = compute_offset_lines_isec_timeC2(m, time_cache);
|
||||
Optional_rational nt_ = compute_offset_lines_isec_timeC2(n, time_cache);
|
||||
Optional_rational mt_ = compute_offset_lines_isec_timeC2(m, aTime_cache, aCoeff_cache);
|
||||
Optional_rational nt_ = compute_offset_lines_isec_timeC2(n, aTime_cache, aCoeff_cache);
|
||||
|
||||
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
|
||||
//
|
||||
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 ;
|
||||
|
||||
|
|
@ -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
|
||||
// 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>
|
||||
inline Uncertain<bool> is_edge_facing_offset_lines_isecC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& tri, Segment_2<K> const& aEdge )
|
||||
template<class K, class CoeffCache>
|
||||
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
|
||||
|
|
@ -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 consecutive, v01_event is null.
|
||||
//
|
||||
template<class K>
|
||||
template<class K, class CoeffCache>
|
||||
Uncertain<Oriented_side>
|
||||
oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2<K> > const& event
|
||||
, Segment_2<K> const& e0
|
||||
, Segment_2<K> const& e1
|
||||
, Segment_2_with_ID<K> const& e0
|
||||
, Segment_2_with_ID<K> const& e1
|
||||
, boost::intrusive_ptr< Trisegment_2<K> > const& v01_event // can be null
|
||||
, bool primary_is_0
|
||||
, CoeffCache& aCoeff_cache
|
||||
)
|
||||
{
|
||||
typedef typename K::FT FT ;
|
||||
|
|
@ -408,10 +414,10 @@ oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2
|
|||
|
||||
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 l1 = validate(compute_normalized_line_ceoffC2(e1)) ;
|
||||
Line_2 l0 = validate(compute_normalized_line_ceoffC2(e0, aCoeff_cache)) ;
|
||||
Line_2 l1 = validate(compute_normalized_line_ceoffC2(e1, aCoeff_cache)) ;
|
||||
|
||||
CGAL_STSKEL_TRAITS_TRACE("Getting oriented side of point " << p2str(p)
|
||||
<< " 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.
|
||||
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)" : "" ) ) ;
|
||||
|
||||
|
|
@ -515,10 +521,11 @@ oriented_side_of_event_point_wrt_bisectorC2 ( boost::intrusive_ptr< Trisegment_2
|
|||
// PRECONDITIONS:
|
||||
// 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,
|
||||
boost::intrusive_ptr< Trisegment_2<K> > const& r,
|
||||
TimeCache& time_cache )
|
||||
TimeCache& aTime_cache,
|
||||
CoeffCache& aCoeff_cache )
|
||||
{
|
||||
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();
|
||||
|
||||
Optional_rational lt_ = compute_offset_lines_isec_timeC2(l, time_cache);
|
||||
Optional_rational rt_ = compute_offset_lines_isec_timeC2(r, time_cache);
|
||||
Optional_rational lt_ = compute_offset_lines_isec_timeC2(l, aTime_cache, aCoeff_cache);
|
||||
Optional_rational rt_ = compute_offset_lines_isec_timeC2(r, aTime_cache, aCoeff_cache);
|
||||
|
||||
if ( lt_ && rt_ )
|
||||
{
|
||||
|
|
@ -548,8 +555,8 @@ Uncertain<bool> are_events_simultaneousC2 ( boost::intrusive_ptr< Trisegment_2<K
|
|||
{
|
||||
if ( equal_times )
|
||||
{
|
||||
Optional_point_2 li = construct_offset_lines_isecC2(l);
|
||||
Optional_point_2 ri = construct_offset_lines_isecC2(r);
|
||||
Optional_point_2 li = construct_offset_lines_isecC2(l, aCoeff_cache);
|
||||
Optional_point_2 ri = construct_offset_lines_isecC2(r, aCoeff_cache);
|
||||
|
||||
if ( li && ri )
|
||||
rResult = CGAL_NTS logical_and( CGAL_NTS certified_is_equal(li->x(),ri->x())
|
||||
|
|
|
|||
Loading…
Reference in New Issue