From e35a3b1610d61c184bbf810f8d73449d92870957 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 11 Feb 2012 14:24:42 +0000 Subject: [PATCH] Boost.Geometry line/poly overlay (new for 1.49), bugfix (take point-in-between instead of first point) [SVN r76975] --- .../algorithms/detail/overlay/follow.hpp | 52 ++++++++++++++----- .../detail/overlay/intersection_insert.hpp | 13 ++++- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/follow.hpp b/include/boost/geometry/algorithms/detail/overlay/follow.hpp index 274cc47b8..ac8af1c6c 100644 --- a/include/boost/geometry/algorithms/detail/overlay/follow.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/follow.hpp @@ -14,11 +14,12 @@ #include #include +#include #include #include #include -#include +#include namespace boost { namespace geometry @@ -43,6 +44,29 @@ static inline bool is_entering(Turn const& /* TODO remove this parameter */, Ope ; } +template +< + typename Turn, + typename Operation, + typename LineString, + typename Polygon +> +static inline bool last_covered_by(Turn const& turn, Operation const& op, + LineString const& linestring, Polygon const& polygon) +{ + // Check any point between the this one and the first IP + typedef typename geometry::point_type::type point_type; + point_type point_in_between; + detail::point_on_border::midpoint_helper + < + point_type, + 0, dimension::value + >::apply(point_in_between, linestring[op.seg_id.segment_index], turn.point); + + return geometry::covered_by(point_in_between, polygon); +} + + template < typename Turn, @@ -58,7 +82,7 @@ static inline bool is_leaving(Turn const& turn, Operation const& op, { return entered || turn.method == method_crosses - || (first && geometry::within(linestring[0], polygon)) + || (first && last_covered_by(turn, op, linestring, polygon)) ; } return false; @@ -79,27 +103,31 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op, if (turn.method == method_crosses) { // The normal case, this is completely covered with entering/leaving - // so stay out of this time consuming "within" + // so stay out of this time consuming "covered_by" return false; } if (is_entering(turn, op)) { - return entered || (first && geometry::within(linestring[0], polygon)); + return entered || (first && last_covered_by(turn, op, linestring, polygon)); } return false; } -template -static inline bool was_entered(Turn const& turn, bool first) +template +< + typename Turn, + typename Operation, + typename Linestring, + typename Polygon +> +static inline bool was_entered(Turn const& turn, Operation const& op, bool first, + Linestring const& linestring, Polygon const& polygon) { if (first && (turn.method == method_collinear || turn.method == method_equal)) { - // If it is the very first point, and either equal or collinear, there is only one - // IP generated (on purpose). So consider this as having entered. - // Maybe it will leave immediately after that (u/i) but that is checked later. - return true; + return last_covered_by(turn, op, linestring, polygon); } return false; } @@ -169,7 +197,7 @@ struct action_selector template static inline bool included(Point const& point, Geometry const& geometry) { - return geometry::within(point, geometry); + return geometry::covered_by(point, geometry); } }; @@ -299,7 +327,7 @@ public : { turn_operation_iterator_type iit = boost::begin(it->operations); - if (following::was_entered(*it, first)) + if (following::was_entered(*it, *iit, first, linestring, polygon)) { debug_traverse(*it, *iit, "-> Was entered"); entered = true; diff --git a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index 45324fc79..8bca790d7 100644 --- a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -171,7 +172,17 @@ struct intersection_of_linestring_with_areal // No intersection points, it is either completely // inside (interior + borders) // or completely outside - if (follower::included(*boost::begin(linestring), areal)) + + // Use border point (on a segment) to check this + // (because turn points might skip some cases) + point_type border_point; + if (! geometry::point_on_border(border_point, linestring, true)) + { + return out; + } + + + if (follower::included(border_point, areal)) { LineStringOut copy; geometry::convert(linestring, copy);