2
0
mirror of https://github.com/boostorg/graph.git synced 2026-01-19 04:12:11 +00:00

Add robust, integer crosses check instead of relying on Boost.Geometry in is_straight_line_drawing.hpp.

This commit is contained in:
Tinko Sebastian Bartels
2025-11-28 23:26:49 +08:00
parent 0cdf8dd014
commit ac16714397
3 changed files with 39 additions and 23 deletions

View File

@@ -37,6 +37,7 @@ target_link_libraries(boost_graph
Boost::move
Boost::mpl
Boost::multi_index
Boost::multiprecision
Boost::optional
Boost::parameter
Boost::preprocessor

View File

@@ -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

View File

@@ -15,11 +15,7 @@
#include <boost/property_map/property_map.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/planar_detail/bucket_sort.hpp>
#include <boost/geometry/algorithms/crosses.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <algorithm>
@@ -28,32 +24,50 @@
namespace boost
{
// Overload of make from Boost.Geometry.
template<typename Geometry, typename Graph, typename GridPositionMap>
Geometry make(typename graph_traits<Graph>::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<Geometry>::type;
return {{numeric_cast<Float>(drawing[e_source].x), numeric_cast<Float>(drawing[e_source].y)},
{numeric_cast<Float>(drawing[e_target].x), numeric_cast<Float>(drawing[e_target].y)}};
template<typename Int128>
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);
}
// Overload of crosses from Boost.Geometry.
template<typename Point>
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));
}
// Crosses in the sense the e and f intersect but are not equal and the
// intersection set is not a shared endpoint.
template<typename Graph, typename GridPositionMap>
bool crosses(typename graph_traits<Graph>::edge_descriptor e,
typename graph_traits<Graph>::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<geometry::model::d2::point_xy<double>>;
return crosses(make<linestring2d>(e, g, drawing),
make<linestring2d>(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<int128_t>(p1.x, p1.y, p2.x, p2.y, q1.x, q1.y);
int o2 = orientation2d<int128_t>(p1.x, p1.y, p2.x, p2.y, q2.x, q2.y);
int o3 = orientation2d<int128_t>(q1.x, q1.y, q2.x, q2.y, p1.x, p1.y);
int o4 = orientation2d<int128_t>(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 >