Skip to content

Commit 3186cf3

Browse files
barendgehrelstinko92
authored andcommitted
[buffer] Fix direction code for some new cases.
The similar_direction function could be erroneous for corner cases, refactored it out. This also makes it a bit less dependent on infinite_line (cartesian)
1 parent fe70a50 commit 3186cf3

File tree

9 files changed

+71
-254
lines changed

9 files changed

+71
-254
lines changed

include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Boost.Geometry (aka GGL, Generic Geometry Library)
22

3-
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
3+
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
44

55
// This file was modified by Oracle on 2017.
66
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
@@ -31,16 +31,13 @@
3131

3232
#include <boost/geometry/strategies/buffer.hpp>
3333
#include <boost/geometry/strategies/side.hpp>
34-
#include <boost/geometry/algorithms/detail/make/make.hpp>
34+
#include <boost/geometry/algorithms/detail/direction_code.hpp>
3535
#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
3636
#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
3737

38-
#include <boost/geometry/algorithms/assign.hpp>
3938
#include <boost/geometry/algorithms/num_interior_rings.hpp>
4039
#include <boost/geometry/algorithms/simplify.hpp>
4140

42-
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
43-
4441
#include <boost/geometry/views/detail/normalized_view.hpp>
4542

4643

@@ -113,23 +110,11 @@ struct buffer_range
113110
JoinStrategy const& join_strategy,
114111
EndStrategy const& end_strategy,
115112
RobustPolicy const& ,
116-
SideStrategy const& side_strategy) // side strategy
113+
SideStrategy const& side_strategy)
117114
{
118-
output_point_type intersection_point;
119-
geometry::assign_zero(intersection_point);
120-
121-
geometry::strategy::buffer::join_selector join
122-
= get_join_type(penultimate_input, previous_input, input, side_strategy);
123-
if (join == geometry::strategy::buffer::join_convex)
124-
{
125-
// Calculate the intersection-point formed by the two sides.
126-
// It might be that the two sides are not convex, but continue
127-
// or spikey, we then change the join-type
128-
join = line_line_intersection::apply(
129-
perp1, perp2, prev_perp1, prev_perp2,
130-
intersection_point);
131-
132-
}
115+
geometry::strategy::buffer::join_selector const join
116+
= get_join_type(penultimate_input, previous_input, input,
117+
side_strategy);
133118

134119
switch(join)
135120
{
@@ -163,6 +148,11 @@ struct buffer_range
163148
{
164149
// The corner is convex, we create a join
165150
// TODO (future) - avoid a separate vector, add the piece directly
151+
output_point_type const
152+
intersection_point
153+
= line_line_intersection::apply(perp1, perp2,
154+
prev_perp1, prev_perp2);
155+
166156
std::vector<output_point_type> range_out;
167157
if (join_strategy.apply(intersection_point,
168158
previous_input, prev_perp2, perp1,
@@ -177,14 +167,14 @@ struct buffer_range
177167
}
178168
}
179169

180-
static inline bool similar_direction(output_point_type const& p0,
170+
// Returns true if collinear point p2 continues after p0 and p1.
171+
// If it turns back (spike), it returns false.
172+
static inline bool same_direction(output_point_type const& p0,
181173
output_point_type const& p1,
182174
output_point_type const& p2)
183175
{
184-
typedef model::infinite_line<coordinate_type> line_type;
185-
line_type const p = detail::make::make_infinite_line<coordinate_type>(p0, p1);
186-
line_type const q = detail::make::make_infinite_line<coordinate_type>(p1, p2);
187-
return arithmetic::similar_direction(p, q);
176+
typedef typename cs_tag<output_point_type>::type cs_tag;
177+
return direction_code<cs_tag>(p0, p1, p2) == 1;
188178
}
189179

190180
template <typename SideStrategy>
@@ -197,8 +187,7 @@ struct buffer_range
197187
int const side = side_strategy.apply(p0, p1, p2);
198188
return side == -1 ? geometry::strategy::buffer::join_convex
199189
: side == 1 ? geometry::strategy::buffer::join_concave
200-
: similar_direction(p0, p1, p2)
201-
? geometry::strategy::buffer::join_continue
190+
: same_direction(p0, p1, p2) ? geometry::strategy::buffer::join_continue
202191
: geometry::strategy::buffer::join_spike;
203192
}
204193

include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Boost.Geometry (aka GGL, Generic Geometry Library)
22

3-
// Copyright (c) 2012-2019 Barend Gehrels, Amsterdam, the Netherlands.
3+
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
44

55
// Use, modification and distribution is subject to the Boost Software License,
66
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -9,10 +9,12 @@
99
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
1010
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
1111

12-
12+
#include <boost/geometry/core/assert.hpp>
1313
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
1414
#include <boost/geometry/algorithms/detail/make/make.hpp>
15-
#include <boost/geometry/strategies/buffer.hpp>
15+
16+
#include <boost/core/ignore_unused.hpp>
17+
1618

1719
namespace boost { namespace geometry
1820
{
@@ -26,29 +28,23 @@ namespace detail { namespace buffer
2628
struct line_line_intersection
2729
{
2830
template <typename Point>
29-
static inline strategy::buffer::join_selector
30-
apply(Point const& pi, Point const& pj,
31-
Point const& qi, Point const& qj,
32-
Point& ip)
31+
static inline Point
32+
apply(Point const& pi, Point const& pj, Point const& qi, Point const& qj)
3333
{
3434
typedef typename coordinate_type<Point>::type ct;
3535
typedef model::infinite_line<ct> line_type;
3636

3737
line_type const p = detail::make::make_infinite_line<ct>(pi, pj);
3838
line_type const q = detail::make::make_infinite_line<ct>(qi, qj);
3939

40-
if (arithmetic::intersection_point(p, q, ip))
41-
{
42-
return strategy::buffer::join_convex;
43-
}
44-
45-
// The lines do not intersect.
46-
// Distinguish between continuing lines (having a similar direction)
47-
// and spikes (having the opposite direction).
48-
return arithmetic::similar_direction(p, q)
49-
? strategy::buffer::join_continue
50-
: strategy::buffer::join_spike
51-
;
40+
// The input lines are not parallel, they intersect, because
41+
// their join type is checked before.
42+
Point ip;
43+
bool const intersecting = arithmetic::intersection_point(p, q, ip);
44+
BOOST_GEOMETRY_ASSERT(intersecting);
45+
boost::ignore_unused(intersecting);
46+
47+
return ip;
5248
}
5349
};
5450

include/boost/geometry/algorithms/detail/direction_code.hpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Boost.Geometry (aka GGL, Generic Geometry Library)
22

3-
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
3+
// Copyright (c) 2015-2020 Barend Gehrels, Amsterdam, the Netherlands.
44

55
// This file was modified by Oracle on 2015, 2017, 2019.
66
// Modifications copyright (c) 2015-2019 Oracle and/or its affiliates.
@@ -54,21 +54,29 @@ struct direction_code_impl<cartesian_tag>
5454

5555
typedef model::infinite_line<calc_t> line_type;
5656

57-
// point b is often equal to the specified point, check that first
58-
line_type const q = detail::make::make_infinite_line<calc_t>(segment_b, point);
59-
if (arithmetic::is_degenerate(q))
57+
// Situation and construction of perpendicular line
58+
//
59+
// P1 a--------------->b P2
60+
// |
61+
// |
62+
// v
63+
//
64+
// P1 is located right of the (directional) perpendicular line
65+
// and therefore gets a negative side_value, and returns -1.
66+
// P2 is to the left of the perpendicular line and returns 1.
67+
// If the specified point is located on top of b, it returns 0.
68+
69+
line_type const line
70+
= detail::make::make_perpendicular_line<calc_t>(segment_a,
71+
segment_b, segment_b);
72+
73+
if (arithmetic::is_degenerate(line))
6074
{
6175
return 0;
6276
}
6377

64-
line_type const p = detail::make::make_infinite_line<calc_t>(segment_a, segment_b);
65-
if (arithmetic::is_degenerate(p))
66-
{
67-
return 0;
68-
}
69-
70-
// p extends a-b if direction is similar
71-
return arithmetic::similar_direction(p, q) ? 1 : -1;
78+
calc_t const sv = arithmetic::side_value(line, point);
79+
return sv == 0 ? 0 : sv > 0 ? 1 : -1;
7280
}
7381
};
7482

include/boost/geometry/arithmetic/infinite_line_functions.hpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,6 @@ side_value(model::infinite_line<Type> const& line, Point const& p)
7676
return side_value(line, geometry::get<0>(p), geometry::get<1>(p));
7777
}
7878

79-
// Returns true for two lines which are supposed to be (close to) collinear
80-
// (which is not checked) and have a similar direction
81-
// (in practice up to 45 degrees, TO BE VERIFIED)
82-
// true: -----------------> p -----------------> q
83-
// false: -----------------> p <----------------- q
84-
template <typename Type>
85-
inline
86-
bool similar_direction(const model::infinite_line<Type>& p,
87-
const model::infinite_line<Type>& q)
88-
{
89-
return p.a * q.a >= 0 && p.b * q.b >= 0;
90-
}
91-
9279
template <typename Type>
9380
inline bool is_degenerate(const model::infinite_line<Type>& line)
9481
{

test/algorithms/buffer/buffer_multi_polygon.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,19 @@ static std::string const rt_u12
281281
static std::string const rt_u13
282282
= "MULTIPOLYGON(((6 4,6 5,7 5,6 4)),((3 2,3 3,4 3,3 2)),((7 8,7 9,8 9,8 8,7 8)),((4 9,4 10,5 10,4 9)),((7 7,7 8,8 7,7 7)),((2 6,2 7,3 7,2 6)),((0 1,1 2,1 1,0 1)),((3 1,4 2,4 1,3 1)),((2 5,2 6,3 6,2 5)),((3 5,4 4,3 4,2 4,3 5)),((4 1,5 2,5 1,4 1)),((2 0,2 1,3 1,2 0)),((5 7,5 8,6 7,5 7)),((0 2,0 3,1 3,0 2)),((9 8,9 9,10 9,10 8,9 8)),((7 5,7 6,8 5,7 5)),((5 6,5 7,6 6,5 6)),((0 6,0 7,1 7,1 6,0 6)),((5 0,5 1,6 1,5 0)),((8 7,8 8,9 8,8 7)),((4.5 4.5,5 4,4 4,4 5,5 5,4.5 4.5)),((6 2,5 2,5 3,6 3,7 3,8 2,7 2,6 2)),((8 6,8 7,9 7,9 6,9 5,8 5,8 6)),((8 1,9 0,8 0,7 0,8 1)))";
283283

284+
static std::string const rt_v1
285+
= "MULTIPOLYGON(((2 8,2 9,3 9,2 8)),((3 6,3 7,4 7,3 6)),((9 9,9 10,10 10,10 9,9 9)),((0 7,1 8,1 7,0 7)))";
286+
287+
static std::string const rt_v2
288+
= "MULTIPOLYGON(((8 4,8 5,9 5,9 4,8 4)),((2 5,2 6,3 5,2 5)),((9 7,9 8,10 8,10 7,9 7)),((2 2,2 3,3 2,2 2)),((6 6,7 5,6 5,6 6)),((6 6,6 7,7 7,7 6,6 6)),((8 9,9 9,8 8,8 9)),((8 9,7 9,8 10,8 9)))";
289+
290+
static std::string const rt_v3
291+
= "MULTIPOLYGON(((7 0,7 1,8 1,8 0,7 0)),((6 2,6 3,7 2,6 2)),((9 3,8 3,8 4,9 3)),((9 3,9 4,10 3,9 3)))";
292+
293+
static std::string const rt_v4
294+
= "MULTIPOLYGON(((5 4,5 5,6 5,6 4,5 4)),((7 1,6 1,7 2,7 1)),((7 1,8 1,8 0,7 0,7 1)),((6 1,5 1,5 2,6 1)))";
295+
296+
284297
static std::string const neighbouring
285298
= "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((10 10,10 20,20 20,20 10,10 10)))";
286299

@@ -502,6 +515,11 @@ void test_all()
502515
test_one<multi_polygon_type, polygon_type>("rt_u12", rt_u12, join_miter, end_flat, 142.1348, 1.0);
503516
test_one<multi_polygon_type, polygon_type>("rt_u13", rt_u13, join_miter, end_flat, 115.4853, 1.0);
504517

518+
test_one<multi_polygon_type, polygon_type>("rt_v1", rt_v1, join_round32, end_flat, 26.9994, 1.0);
519+
test_one<multi_polygon_type, polygon_type>("rt_v2", rt_v2, join_round32, end_flat, 47.3510, 1.0);
520+
test_one<multi_polygon_type, polygon_type>("rt_v3", rt_v3, join_round32, end_flat, 22.9158, 1.0);
521+
test_one<multi_polygon_type, polygon_type>("rt_v4", rt_v4, join_round32, end_flat, 23.4146, 1.0);
522+
505523
test_one<multi_polygon_type, polygon_type>("neighbouring_small",
506524
neighbouring,
507525
join_round32, end_round32, 128.0, -1.0);

test/algorithms/buffer/test_buffer_svg.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,8 @@ private :
157157
<< "/" << it->operations[1].enriched.get_next_turn_index()
158158
//<< " frac " << it->operations[0].fraction
159159

160-
// If you want to see (robust)point coordinates (e.g. to find duplicates)
160+
// If you want to see point coordinates (e.g. to find duplicates)
161161
<< std::endl << std::setprecision(16) << bg::wkt(it->point)
162-
<< std::endl << bg::wkt(it->robust_point)
163162

164163
<< std::endl;
165164
out << " " << bg::method_char(it->method)

test/arithmetic/infinite_line_functions.cpp

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -96,77 +96,6 @@ void test_get_intersection()
9696
verify_point_on_line(q, bg::get<0>(ip), bg::get<1>(ip));
9797
}
9898

99-
template <typename T>
100-
void test_same_direction()
101-
{
102-
bg::model::infinite_line<T> p, q;
103-
104-
// Exactly opposite, diagonal
105-
p = bg::detail::make::make_infinite_line<T>(2, 1, 12, 11);
106-
q = bg::detail::make::make_infinite_line<T>(12, 11, 2, 1);
107-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
108-
109-
// Exactly opposite, horizontal
110-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 0);
111-
q = bg::detail::make::make_infinite_line<T>(10, 0, 0, 0);
112-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
113-
114-
// Exactly opposite, vertical
115-
p = bg::detail::make::make_infinite_line<T>(0, 0, 0, 10);
116-
q = bg::detail::make::make_infinite_line<T>(0, 10, 0, 0);
117-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
118-
119-
// Exactly equal, diagonal
120-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
121-
q = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
122-
BOOST_CHECK(bg::arithmetic::similar_direction(p, q));
123-
124-
// Exactly equal, horizontal
125-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 0);
126-
q = bg::detail::make::make_infinite_line<T>(0, 0, 10, 0);
127-
BOOST_CHECK(bg::arithmetic::similar_direction(p, q));
128-
129-
// Exactly equal, vertical
130-
p = bg::detail::make::make_infinite_line<T>(0, 0, 0, 10);
131-
q = bg::detail::make::make_infinite_line<T>(0, 0, 0, 10);
132-
BOOST_CHECK(bg::arithmetic::similar_direction(p, q));
133-
134-
// Coming together, diagonal
135-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
136-
q = bg::detail::make::make_infinite_line<T>(20, 20, 10, 10);
137-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
138-
139-
// Leaving from common point, diagonal
140-
p = bg::detail::make::make_infinite_line<T>(10, 10, 0, 0);
141-
q = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
142-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
143-
144-
// Continuing each other, diagonal
145-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
146-
q = bg::detail::make::make_infinite_line<T>(10, 10, 20, 20);
147-
BOOST_CHECK(bg::arithmetic::similar_direction(p, q));
148-
149-
// (Nearly) perpendicular
150-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
151-
q = bg::detail::make::make_infinite_line<T>(0, 0, -10, 10);
152-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
153-
154-
// 45 deg
155-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
156-
q = bg::detail::make::make_infinite_line<T>(0, 0, 0, 10);
157-
BOOST_CHECK(bg::arithmetic::similar_direction(p, q));
158-
159-
// a bit more than 45 deg
160-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
161-
q = bg::detail::make::make_infinite_line<T>(0, 0, -1, 10);
162-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
163-
164-
// 135 deg
165-
p = bg::detail::make::make_infinite_line<T>(0, 0, 10, 10);
166-
q = bg::detail::make::make_infinite_line<T>(0, 0, -10, 0);
167-
BOOST_CHECK(! bg::arithmetic::similar_direction(p, q));
168-
}
169-
17099
template <typename T>
171100
void test_degenerate()
172101
{

test/strategies/Jamfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ test-suite boost-geometry-strategies
3535
[ run segment_intersection_collinear.cpp : : : : strategies_segment_intersection_collinear ]
3636
[ run segment_intersection_geo.cpp : : : : strategies_segment_intersection_geo ]
3737
[ run segment_intersection_sph.cpp : : : : strategies_segment_intersection_sph ]
38-
# [ run side_of_intersection.cpp : : : : strategies_side_of_intersection ]
3938
[ run spherical_side.cpp : : : : strategies_spherical_side ]
4039
[ run thomas.cpp : : : : strategies_thomas ]
4140
[ run transform_cs.cpp : : : : strategies_transform_cs ]

0 commit comments

Comments
 (0)