mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-20 14:52:10 +00:00
[winding] Add winding_side_equal optimized for cartesian CS.
This commit is contained in:
@@ -33,6 +33,78 @@ namespace boost { namespace geometry
|
||||
namespace strategy { namespace within
|
||||
{
|
||||
|
||||
|
||||
// Fix for https://svn.boost.org/trac/boost/ticket/9628
|
||||
// For floating point coordinates, the <1> coordinate of a point is compared
|
||||
// with the segment's points using some EPS. If the coordinates are "equal"
|
||||
// the sides are calculated. Therefore we can treat a segment as a long areal
|
||||
// geometry having some width. There is a small ~triangular area somewhere
|
||||
// between the segment's effective area and a segment's line used in sides
|
||||
// calculation where the segment is on the one side of the line but on the
|
||||
// other side of a segment (due to the width).
|
||||
// For the s1 of a segment going NE the real side is RIGHT but the point may
|
||||
// be detected as LEFT, like this:
|
||||
// RIGHT
|
||||
// ___----->
|
||||
// ^ O Pt __ __
|
||||
// EPS __ __
|
||||
// v__ __ BUT DETECTED AS LEFT OF THIS LINE
|
||||
// _____7
|
||||
// _____/
|
||||
// _____/
|
||||
template <typename CSTag>
|
||||
struct winding_side_equal
|
||||
{
|
||||
typedef typename strategy::side::services::default_strategy
|
||||
<
|
||||
CSTag
|
||||
>::type strategy_side_type;
|
||||
|
||||
template <size_t D, typename Point, typename PointOfSegment>
|
||||
static inline int apply(Point const& point,
|
||||
PointOfSegment const& se,
|
||||
int count)
|
||||
{
|
||||
// Create a vertical segment intersecting the original segment's endpoint
|
||||
// equal to the point, with the derived direction (UP/DOWN).
|
||||
// Set only the 2 first coordinates, the other ones are ignored
|
||||
PointOfSegment ss1, ss2;
|
||||
set<1-D>(ss1, get<1-D>(se));
|
||||
set<1-D>(ss2, get<1-D>(se));
|
||||
if ( count > 0 ) // UP
|
||||
{
|
||||
set<D>(ss1, 0);
|
||||
set<D>(ss2, 1);
|
||||
}
|
||||
else // DOWN
|
||||
{
|
||||
set<D>(ss1, 1);
|
||||
set<D>(ss2, 0);
|
||||
}
|
||||
// Check the side using this vertical segment
|
||||
return strategy_side_type::apply(ss1, ss2, point);
|
||||
}
|
||||
};
|
||||
|
||||
// The optimization for cartesian
|
||||
template <>
|
||||
struct winding_side_equal<cartesian_tag>
|
||||
{
|
||||
template <size_t D, typename Point, typename PointOfSegment>
|
||||
static inline int apply(Point const& point,
|
||||
PointOfSegment const& se,
|
||||
int count)
|
||||
{
|
||||
return math::equals(get<1-D>(point), get<1-D>(se)) ?
|
||||
0 :
|
||||
get<1-D>(point) < get<1-D>(se) ?
|
||||
// assuming count is equal to 1 or -1
|
||||
count : // ( count > 0 ? 1 : -1) :
|
||||
-count; // ( count > 0 ? -1 : 1) ;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
\brief Within detection using winding rule
|
||||
\ingroup strategies
|
||||
@@ -137,56 +209,6 @@ class winding
|
||||
: 0;
|
||||
}
|
||||
|
||||
// Fix for https://svn.boost.org/trac/boost/ticket/9628
|
||||
// For floating point coordinates, the <1> coordinate of a point is compared
|
||||
// with the segment's points using some EPS. If the coordinates are "equal"
|
||||
// the sides are calculated. Therefore we can treat a segment as a long areal
|
||||
// geometry having some width. There is a small ~triangular area somewhere
|
||||
// between the segment's effective area and a segment's line used in sides
|
||||
// calculation where the segment is on the one side of the line but on the
|
||||
// other side of a segment (due to the width).
|
||||
// For the s1 of a segment going NE the real side is RIGHT but the point may
|
||||
// be detected as LEFT, like this:
|
||||
// RIGHT
|
||||
// ___----->
|
||||
// ^ O Pt __ __
|
||||
// EPS __ __
|
||||
// v__ __ BUT DETECTED AS LEFT OF THIS LINE
|
||||
// _____7
|
||||
// _____/
|
||||
// _____/
|
||||
template <size_t D>
|
||||
static inline int side_equal(Point const& point,
|
||||
PointOfSegment const& se,
|
||||
int count)
|
||||
{
|
||||
// TODO: possible optimization of cartesian CS
|
||||
// math::equals(p<1-D>, se<1-D>) ?
|
||||
// 0 :
|
||||
// p<1-D> < se<1-D> ?
|
||||
// (UP ? LEFT : RIGHT) :
|
||||
// (UP ? RIGHT : LEFT) ;
|
||||
|
||||
// Create a vertical segment intersecting the original segment's endpoint
|
||||
// equal to the point, with the derived direction (UP/DOWN).
|
||||
// Set only the 2 first coordinates, the other ones are ignored
|
||||
PointOfSegment ss1, ss2;
|
||||
set<1-D>(ss1, get<1-D>(se));
|
||||
set<1-D>(ss2, get<1-D>(se));
|
||||
if ( count > 0 ) // UP
|
||||
{
|
||||
set<D>(ss1, 0);
|
||||
set<D>(ss2, 1);
|
||||
}
|
||||
else // DOWN
|
||||
{
|
||||
set<D>(ss1, 1);
|
||||
set<D>(ss2, 0);
|
||||
}
|
||||
// Check the side using this vertical segment
|
||||
return strategy_side_type::apply(ss1, ss2, point);
|
||||
}
|
||||
|
||||
|
||||
public :
|
||||
|
||||
@@ -209,7 +231,8 @@ public :
|
||||
int side = 0;
|
||||
if ( count == 1 || count == -1 )
|
||||
{
|
||||
side = side_equal<1>(point, eq1 ? s1 : s2, count);
|
||||
side = winding_side_equal<typename cs_tag<Point>::type>
|
||||
::template apply<1>(point, eq1 ? s1 : s2, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user