From bda28c863aa648480e745b314141fb91e37449db Mon Sep 17 00:00:00 2001 From: Hermann-SW Date: Sat, 12 Oct 2024 19:35:43 +0200 Subject: [PATCH 1/2] add failing is_straight_line_drawing testcase --- test/is_straight_line_draw_test.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/is_straight_line_draw_test.cpp b/test/is_straight_line_draw_test.cpp index 3774ed2fb..17aad9c45 100644 --- a/test/is_straight_line_draw_test.cpp +++ b/test/is_straight_line_draw_test.cpp @@ -192,5 +192,32 @@ int main(int, char*[]) BOOST_TEST(!is_straight_line_drawing(g, drawing)); + + // issue #388 + g.clear(); + add_edge(0, 1, g); + add_edge(2, 0, g); + add_edge(1, 2, g); + + struct coord_t { size_t x, y; }; + std::vector coordinates{ + {4143438, 86426}, + {4064945, 7932}, + {4064944, 7931} + }; +/* + There is a very small angle between edge 0--1 and edge 2--0 at vertex 0, + with slope of edges 78494/78493 != 78495/78494, which cannot be + correctly handled by double type function "intersects()" called + by "is_straight_line_drawing()": + +4143438-4064945 = 78493 +86426-7932 = 78494 + +4143438-4064944 = 78494 +86426-7931 = 78495 +*/ + BOOST_TEST(is_straight_line_drawing(g, coordinates.data())); + return boost::report_errors(); } From 87b862c1911815715e0242daa918caece6cd178a Mon Sep 17 00:00:00 2001 From: "Jeremy W. Murphy" Date: Thu, 19 Dec 2024 08:39:12 +1100 Subject: [PATCH 2/2] Fix #388 by using Boost.Geometry "crosses" fits the requirement as it means that the interior parts of the geometry share some common points, not exterior parts such as end-points, and it means "not within". --- .../boost/graph/is_straight_line_drawing.hpp | 89 ++++--------------- 1 file changed, 19 insertions(+), 70 deletions(-) diff --git a/include/boost/graph/is_straight_line_drawing.hpp b/include/boost/graph/is_straight_line_drawing.hpp index 013f4b400..7330284b1 100644 --- a/include/boost/graph/is_straight_line_drawing.hpp +++ b/include/boost/graph/is_straight_line_drawing.hpp @@ -16,75 +16,16 @@ #include #include +#include +#include + #include #include -#include #include namespace boost { -// Return true exactly when the line segments s1 = ((x1,y1), (x2,y2)) and -// s2 = ((a1,b1), (a2,b2)) intersect in a point other than the endpoints of -// the line segments. The one exception to this rule is when s1 = s2, in -// which case false is returned - this is to accomodate multiple edges -// between the same pair of vertices, which shouldn't invalidate the straight -// line embedding. A tolerance variable epsilon can also be used, which -// defines how far away from the endpoints of s1 and s2 we want to consider -// an intersection. - -inline bool intersects(double x1, double y1, double x2, double y2, double a1, - double b1, double a2, double b2, double epsilon = 0.000001) -{ - - if (x1 - x2 == 0) - { - std::swap(x1, a1); - std::swap(y1, b1); - std::swap(x2, a2); - std::swap(y2, b2); - } - - if (x1 - x2 == 0) - { - BOOST_USING_STD_MAX(); - BOOST_USING_STD_MIN(); - - // two vertical line segments - double min_y = min BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2); - double max_y = max BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2); - double min_b = min BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2); - double max_b = max BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2); - if ((max_y > max_b && max_b > min_y) - || (max_b > max_y && max_y > min_b)) - return true; - else - return false; - } - - double x_diff = x1 - x2; - double y_diff = y1 - y2; - double a_diff = a2 - a1; - double b_diff = b2 - b1; - - double beta_denominator = b_diff - (y_diff / ((double)x_diff)) * a_diff; - - if (beta_denominator == 0) - { - // parallel lines - return false; - } - - double beta = (b2 - y2 - (y_diff / ((double)x_diff)) * (a2 - x2)) - / beta_denominator; - double alpha = (a2 - x2 - beta * (a_diff)) / x_diff; - - double upper_bound = 1 - epsilon; - double lower_bound = 0 + epsilon; - - return (beta < upper_bound && beta > lower_bound && alpha < upper_bound - && alpha > lower_bound); -} template < typename Graph, typename GridPositionMap, typename VertexIndexMap > bool is_straight_line_drawing( @@ -152,6 +93,10 @@ bool is_straight_line_drawing( } else { + using geometry::crosses; + using geometry::model::linestring; + using geometry::model::d2::point_xy; + active_map_iterator_t before, after; if (a_itr == active_edges.begin()) before = active_edges.end(); @@ -168,10 +113,12 @@ bool is_straight_line_drawing( vertex_t f_source(source(f, g)); vertex_t f_target(target(f, g)); - if (intersects(drawing[e_source].x, drawing[e_source].y, - drawing[e_target].x, drawing[e_target].y, - drawing[f_source].x, drawing[f_source].y, - drawing[f_target].x, drawing[f_target].y)) + linestring> source{{drawing[e_source].x, drawing[e_source].y}, + {drawing[e_target].x, drawing[e_target].y}}; + linestring> target{{drawing[f_source].x, drawing[f_source].y}, + {drawing[f_target].x, drawing[f_target].y}}; + + if (crosses(source, target)) return false; } @@ -184,10 +131,12 @@ bool is_straight_line_drawing( vertex_t f_source(source(f, g)); vertex_t f_target(target(f, g)); - if (intersects(drawing[e_source].x, drawing[e_source].y, - drawing[e_target].x, drawing[e_target].y, - drawing[f_source].x, drawing[f_source].y, - drawing[f_target].x, drawing[f_target].y)) + linestring> source{{drawing[e_source].x, drawing[e_source].y}, + {drawing[e_target].x, drawing[e_target].y}}; + linestring> target{{drawing[f_source].x, drawing[f_source].y}, + {drawing[f_target].x, drawing[f_target].y}}; + + if (crosses(source, target)) return false; }