Skip to content

Commit 84c36ca

Browse files
Merge pull request #412 from jeremy-murphy/388_is_straight_line_drawing
Fix geometry bug in is_straight_line_drawing
2 parents 80e00c3 + 9176040 commit 84c36ca

File tree

2 files changed

+59
-80
lines changed

2 files changed

+59
-80
lines changed

include/boost/graph/is_straight_line_drawing.hpp

Lines changed: 32 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,74 +16,44 @@
1616
#include <boost/graph/properties.hpp>
1717
#include <boost/graph/planar_detail/bucket_sort.hpp>
1818

19+
#include <boost/geometry/algorithms/crosses.hpp>
20+
#include <boost/geometry/geometries/linestring.hpp>
21+
#include <boost/geometry/core/coordinate_type.hpp>
22+
23+
#include <boost/numeric/conversion/cast.hpp>
24+
1925
#include <algorithm>
2026
#include <vector>
21-
#include <set>
2227
#include <map>
2328

2429
namespace boost
2530
{
26-
27-
// Return true exactly when the line segments s1 = ((x1,y1), (x2,y2)) and
28-
// s2 = ((a1,b1), (a2,b2)) intersect in a point other than the endpoints of
29-
// the line segments. The one exception to this rule is when s1 = s2, in
30-
// which case false is returned - this is to accomodate multiple edges
31-
// between the same pair of vertices, which shouldn't invalidate the straight
32-
// line embedding. A tolerance variable epsilon can also be used, which
33-
// defines how far away from the endpoints of s1 and s2 we want to consider
34-
// an intersection.
35-
36-
inline bool intersects(double x1, double y1, double x2, double y2, double a1,
37-
double b1, double a2, double b2, double epsilon = 0.000001)
31+
// Overload of make from Boost.Geometry.
32+
template<typename Geometry, typename Graph, typename GridPositionMap>
33+
Geometry make(typename graph_traits<Graph>::edge_descriptor e,
34+
Graph const &g,
35+
GridPositionMap const &drawing)
3836
{
37+
auto e_source(source(e, g));
38+
auto e_target(target(e, g));
39+
using Float = typename geometry::coordinate_type<Geometry>::type;
40+
return {{numeric_cast<Float>(drawing[e_source].x), numeric_cast<Float>(drawing[e_source].y)},
41+
{numeric_cast<Float>(drawing[e_target].x), numeric_cast<Float>(drawing[e_target].y)}};
42+
}
3943

40-
if (x1 - x2 == 0)
41-
{
42-
std::swap(x1, a1);
43-
std::swap(y1, b1);
44-
std::swap(x2, a2);
45-
std::swap(y2, b2);
46-
}
47-
48-
if (x1 - x2 == 0)
49-
{
50-
BOOST_USING_STD_MAX();
51-
BOOST_USING_STD_MIN();
52-
53-
// two vertical line segments
54-
double min_y = min BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2);
55-
double max_y = max BOOST_PREVENT_MACRO_SUBSTITUTION(y1, y2);
56-
double min_b = min BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2);
57-
double max_b = max BOOST_PREVENT_MACRO_SUBSTITUTION(b1, b2);
58-
if ((max_y > max_b && max_b > min_y)
59-
|| (max_b > max_y && max_y > min_b))
60-
return true;
61-
else
62-
return false;
63-
}
64-
65-
double x_diff = x1 - x2;
66-
double y_diff = y1 - y2;
67-
double a_diff = a2 - a1;
68-
double b_diff = b2 - b1;
69-
70-
double beta_denominator = b_diff - (y_diff / ((double)x_diff)) * a_diff;
71-
72-
if (beta_denominator == 0)
73-
{
74-
// parallel lines
75-
return false;
76-
}
77-
78-
double beta = (b2 - y2 - (y_diff / ((double)x_diff)) * (a2 - x2))
79-
/ beta_denominator;
80-
double alpha = (a2 - x2 - beta * (a_diff)) / x_diff;
81-
82-
double upper_bound = 1 - epsilon;
83-
double lower_bound = 0 + epsilon;
84-
85-
return (beta < upper_bound && beta > lower_bound && alpha < upper_bound
86-
&& alpha > lower_bound);
44+
// Overload of crosses from Boost.Geometry.
45+
template<typename Graph, typename GridPositionMap>
46+
bool crosses(typename graph_traits<Graph>::edge_descriptor e,
47+
typename graph_traits<Graph>::edge_descriptor f,
48+
Graph const &g,
49+
GridPositionMap const &drawing)
50+
{
51+
using geometry::crosses;
52+
using geometry::model::linestring;
53+
using geometry::model::d2::point_xy;
54+
using linestring2d = geometry::model::linestring<geometry::model::d2::point_xy<double>>;
55+
return crosses(make<linestring2d>(e, g, drawing),
56+
make<linestring2d>(f, g, drawing));
8757
}
8858

8959
template < typename Graph, typename GridPositionMap, typename VertexIndexMap >
@@ -161,33 +131,15 @@ bool is_straight_line_drawing(
161131

162132
if (before != active_edges.end())
163133
{
164-
165134
edge_t f = before->second;
166-
vertex_t e_source(source(e, g));
167-
vertex_t e_target(target(e, g));
168-
vertex_t f_source(source(f, g));
169-
vertex_t f_target(target(f, g));
170-
171-
if (intersects(drawing[e_source].x, drawing[e_source].y,
172-
drawing[e_target].x, drawing[e_target].y,
173-
drawing[f_source].x, drawing[f_source].y,
174-
drawing[f_target].x, drawing[f_target].y))
135+
if (crosses(e, f, g, drawing))
175136
return false;
176137
}
177138

178139
if (after != active_edges.end())
179140
{
180-
181141
edge_t f = after->second;
182-
vertex_t e_source(source(e, g));
183-
vertex_t e_target(target(e, g));
184-
vertex_t f_source(source(f, g));
185-
vertex_t f_target(target(f, g));
186-
187-
if (intersects(drawing[e_source].x, drawing[e_source].y,
188-
drawing[e_target].x, drawing[e_target].y,
189-
drawing[f_source].x, drawing[f_source].y,
190-
drawing[f_target].x, drawing[f_target].y))
142+
if (crosses(e, f, g, drawing))
191143
return false;
192144
}
193145

test/is_straight_line_draw_test.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,5 +192,32 @@ int main(int, char*[])
192192

193193
BOOST_TEST(!is_straight_line_drawing(g, drawing));
194194

195+
196+
// issue #388
197+
g.clear();
198+
add_edge(0, 1, g);
199+
add_edge(2, 0, g);
200+
add_edge(1, 2, g);
201+
202+
struct coord_t { size_t x, y; };
203+
std::vector<coord_t> coordinates{
204+
{4143438, 86426},
205+
{4064945, 7932},
206+
{4064944, 7931}
207+
};
208+
/*
209+
There is a very small angle between edge 0--1 and edge 2--0 at vertex 0,
210+
with slope of edges 78494/78493 != 78495/78494, which cannot be
211+
correctly handled by double type function "intersects()" called
212+
by "is_straight_line_drawing()":
213+
214+
4143438-4064945 = 78493
215+
86426-7932 = 78494
216+
217+
4143438-4064944 = 78494
218+
86426-7931 = 78495
219+
*/
220+
BOOST_TEST(is_straight_line_drawing(g, coordinates.data()));
221+
195222
return boost::report_errors();
196223
}

0 commit comments

Comments
 (0)