From 3bdefedab16b180841ba5c4b32eaaa494f42d8c8 Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Wed, 19 Mar 2014 21:10:09 +0100 Subject: [PATCH] Polygon: fixing reopend issue #6366: defect in polygon 90 contains. --- include/boost/polygon/polygon_traits.hpp | 34 +++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp index 6055bc7..b03d00f 100644 --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -1129,17 +1129,33 @@ namespace boost { namespace polygon{ template typename enable_if< - typename gtl_and< typename is_polygon_90_type::type, - typename gtl_same_type::type, point_concept>::type>::type, - bool>::type - contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typename gtl_and< + typename is_polygon_90_type::type, + typename gtl_same_type< + typename geometry_concept::type, + point_concept + >::type + >::type, + bool + >::type contains( + const T& polygon, + const input_point_type& point, + bool consider_touch = true) { typedef T polygon_type; typedef typename polygon_traits::coordinate_type coordinate_type; typedef typename polygon_traits::iterator_type iterator; typedef typename std::iterator_traits::value_type point_type; coordinate_type point_x = x(point); coordinate_type point_y = y(point); - bool inside = false; + // Check how many intersections has the ray extended from the given + // point in the x-axis negative direction with the polygon edges. + // If the number is odd the point is within the polygon, otherwise not. + // We can safely ignore horizontal edges, however intersections with + // end points of the vertical edges require special handling. We should + // add one intersection in case horizontal edges that extend vertical edge + // point in the same direction. + int num_full_intersections = 0; + int num_half_intersections = 0; for (iterator iter = begin_points(polygon); iter != end_points(polygon);) { point_type curr_point = *iter; ++iter; @@ -1154,7 +1170,10 @@ namespace boost { namespace polygon{ if (x(curr_point) == point_x) { return consider_touch; } - inside ^= true; + ++num_full_intersections; + } + if (point_y == min_y || point_y == max_y) { + num_half_intersections += (y(curr_point) < y(next_point) ? 1 : -1); } } else { coordinate_type min_x = (std::min)(x(curr_point), x(next_point)); @@ -1166,7 +1185,8 @@ namespace boost { namespace polygon{ } } } - return inside; + int total_intersections = num_full_intersections + (num_half_intersections >> 1); + return total_intersections & 1; } //TODO: refactor to expose as user APIs -- 1.8.3.4 (Apple Git-47)