diff --git a/CMakeLists.txt b/CMakeLists.txt index db211cc02..df5c57aed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ target_link_libraries(boost_graph Boost::move Boost::mpl Boost::multi_index + Boost::multiprecision Boost::optional Boost::parameter Boost::preprocessor diff --git a/build.jam b/build.jam index 860243297..6b5a46338 100644 --- a/build.jam +++ b/build.jam @@ -27,6 +27,7 @@ constant boost_dependencies : /boost/move//boost_move /boost/mpl//boost_mpl /boost/multi_index//boost_multi_index + /boost/multiprecision//boost_multiprecision /boost/optional//boost_optional /boost/parameter//boost_parameter /boost/preprocessor//boost_preprocessor diff --git a/include/boost/graph/is_straight_line_drawing.hpp b/include/boost/graph/is_straight_line_drawing.hpp index d7701540d..49b522f7f 100644 --- a/include/boost/graph/is_straight_line_drawing.hpp +++ b/include/boost/graph/is_straight_line_drawing.hpp @@ -15,11 +15,7 @@ #include #include #include - -#include -#include -#include - +#include #include #include @@ -28,32 +24,50 @@ namespace boost { -// Overload of make from Boost.Geometry. -template -Geometry make(typename graph_traits::edge_descriptor e, - Graph const &g, - GridPositionMap const &drawing) -{ - auto e_source(source(e, g)); - auto e_target(target(e, g)); - using Float = typename geometry::coordinate_type::type; - return {{numeric_cast(drawing[e_source].x), numeric_cast(drawing[e_source].y)}, - {numeric_cast(drawing[e_target].x), numeric_cast(drawing[e_target].y)}}; + +template +int orientation2d(Int128 ax, Int128 ay, + Int128 bx, Int128 by, + Int128 cx, Int128 cy) { + // If coordinates are in [0, 2^63], this will not overflow. + const Int128 detleft = (bx - ax) * (cy - ay); + const Int128 detright = (by - ay) * (cx - ax); + return detleft > detright ? 1 : (detleft == detright ? 0 : -1); +} + +template +bool between(const Point& a, const Point& b, const Point& c) { + return (b.y == a.y ? + std::min(a.x, b.x) < c.x && c.x < std::max(a.x, b.x) + : std::min(a.y, b.y) < c.y && c.y < std::max(a.y, b.y)); } -// Overload of crosses from Boost.Geometry. +// Crosses in the sense the e and f intersect but are not equal and the +// intersection set is not a shared endpoint. template bool crosses(typename graph_traits::edge_descriptor e, typename graph_traits::edge_descriptor f, Graph const &g, GridPositionMap const &drawing) { - using geometry::crosses; - using geometry::model::linestring; - using geometry::model::d2::point_xy; - using linestring2d = geometry::model::linestring>; - return crosses(make(e, g, drawing), - make(f, g, drawing)); + const auto& p1 = drawing[source(e, g)]; + const auto& p2 = drawing[target(e, g)]; + const auto& q1 = drawing[source(f, g)]; + const auto& q2 = drawing[target(f, g)]; + + using boost::multiprecision::int128_t; + int o1 = orientation2d(p1.x, p1.y, p2.x, p2.y, q1.x, q1.y); + int o2 = orientation2d(p1.x, p1.y, p2.x, p2.y, q2.x, q2.y); + int o3 = orientation2d(q1.x, q1.y, q2.x, q2.y, p1.x, p1.y); + int o4 = orientation2d(q1.x, q1.y, q2.x, q2.y, p2.x, p2.y); + + // X-like crossing of (p1, p2), (q1, q2) + return ((o1 * o2 < 0) && (o3 * o4 < 0)) + // T-like crossing, e.g. q1 in (p1, p2), or partial overlap + || (o1 == 0 && between(p1, p2, q1)) + || (o2 == 0 && between(p1, p2, q2)) + || (o3 == 0 && between(q1, q2, p1)) + || (o4 == 0 && between(q1, q2, p2)); } template < typename Graph, typename GridPositionMap, typename VertexIndexMap >