mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-10 15:44:07 +00:00
[buffer] add join_selector and use it before generating the join.
This moves responsibility of generation to the calling code, removes it from the join strategies. It also enables using the end-strategy for the spikes
This commit is contained in:
parent
d8a4d12c8e
commit
aa307b5ad2
@ -22,6 +22,7 @@
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
|
||||
|
||||
@ -44,7 +45,6 @@ struct buffer_range
|
||||
typedef typename point_type<RingOutput>::type output_point_type;
|
||||
typedef typename coordinate_type<RingOutput>::type coordinate_type;
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename Point,
|
||||
@ -90,6 +90,7 @@ struct buffer_range
|
||||
typename RobustPolicy
|
||||
>
|
||||
static inline void add_join(Collection& collection,
|
||||
strategy::buffer::join_selector join,
|
||||
Point const& previous_input,
|
||||
output_point_type const& prev_perp1,
|
||||
output_point_type const& prev_perp2,
|
||||
@ -101,26 +102,67 @@ struct buffer_range
|
||||
JoinStrategy const& join_strategy,
|
||||
RobustPolicy const& )
|
||||
{
|
||||
|
||||
output_point_type intersection_point;
|
||||
if (line_line_intersection::apply(
|
||||
perp1, perp2, prev_perp1, prev_perp2, intersection_point))
|
||||
switch(join)
|
||||
{
|
||||
std::vector<output_point_type> range_out;
|
||||
if (join_strategy.apply(intersection_point,
|
||||
previous_input, prev_perp2, perp1,
|
||||
distance.apply(previous_input, input, side),
|
||||
range_out))
|
||||
{
|
||||
collection.add_piece(strategy::buffer::buffered_join,
|
||||
previous_input, range_out);
|
||||
}
|
||||
else
|
||||
{
|
||||
case strategy::buffer::join_continue :
|
||||
// No join, we get two consecutive sides
|
||||
return;
|
||||
case strategy::buffer::join_convex :
|
||||
break; // All code below handles this
|
||||
case strategy::buffer::join_concave :
|
||||
collection.add_piece(strategy::buffer::buffered_concave,
|
||||
previous_input, prev_perp2, perp1);
|
||||
}
|
||||
return;
|
||||
case strategy::buffer::join_spike :
|
||||
// TODO use end strategy
|
||||
// For now: use join strategy
|
||||
//return;
|
||||
break;
|
||||
}
|
||||
|
||||
output_point_type intersection_point;
|
||||
line_line_intersection::apply(
|
||||
perp1, perp2, prev_perp1, prev_perp2,
|
||||
intersection_point);
|
||||
std::vector<output_point_type> range_out;
|
||||
if (join_strategy.apply(intersection_point,
|
||||
previous_input, prev_perp2, perp1,
|
||||
distance.apply(previous_input, input, side),
|
||||
range_out))
|
||||
{
|
||||
collection.add_piece(strategy::buffer::buffered_join,
|
||||
previous_input, range_out);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2)
|
||||
{
|
||||
return math::sign(dx1) == math::sign(dx2)
|
||||
&& math::sign(dy1) == math::sign(dy2);
|
||||
}
|
||||
|
||||
static inline strategy::buffer::join_selector get_join_type(
|
||||
output_point_type const& p0,
|
||||
output_point_type const& p1,
|
||||
output_point_type const& p2)
|
||||
{
|
||||
typedef typename strategy::side::services::default_strategy
|
||||
<
|
||||
typename cs_tag<output_point_type>::type
|
||||
>::type side_strategy;
|
||||
|
||||
int const side = side_strategy::apply(p0, p1, p2);
|
||||
return side == -1 ? strategy::buffer::join_convex
|
||||
: side == 1 ? strategy::buffer::join_concave
|
||||
: parallel_continue
|
||||
(
|
||||
get<0>(p2) - get<0>(p1),
|
||||
get<1>(p2) - get<1>(p1),
|
||||
get<0>(p1) - get<0>(p0),
|
||||
get<1>(p1) - get<1>(p0)
|
||||
) ? strategy::buffer::join_continue
|
||||
: strategy::buffer::join_spike;
|
||||
}
|
||||
|
||||
template
|
||||
@ -155,7 +197,7 @@ struct buffer_range
|
||||
robust_point_type previous_robust_input;
|
||||
output_point_type previous_p1, previous_p2;
|
||||
output_point_type first_p1, first_p2;
|
||||
point_type penultimate_point, ultimate_point; // last two points from begin/end
|
||||
point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
|
||||
|
||||
bool first = true;
|
||||
|
||||
@ -175,6 +217,7 @@ struct buffer_range
|
||||
if (! first)
|
||||
{
|
||||
add_join(collection,
|
||||
get_join_type(penultimate_point, *prev, *it),
|
||||
*prev, previous_p1, previous_p2,
|
||||
*it, p1, p2,
|
||||
side,
|
||||
@ -191,6 +234,7 @@ struct buffer_range
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
second_point = *it;
|
||||
first_p1 = p1;
|
||||
first_p2 = p2;
|
||||
}
|
||||
@ -205,6 +249,7 @@ struct buffer_range
|
||||
{
|
||||
// Generate closing corner
|
||||
add_join(collection,
|
||||
get_join_type(penultimate_point, ultimate_point, second_point),
|
||||
*(end - 1), previous_p1, previous_p2,
|
||||
*begin, first_p1, first_p2,
|
||||
side,
|
||||
|
@ -32,15 +32,6 @@ struct line_line_intersection
|
||||
return a * d - b * c;
|
||||
}
|
||||
|
||||
// Returns true if two parallel segments (vectors dx1,dy1 and dx2,dy2)
|
||||
// move forward (one continues each other - they have the same signs)
|
||||
template <typename T>
|
||||
static inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2)
|
||||
{
|
||||
return math::sign(dx1) == math::sign(dx2)
|
||||
&& math::sign(dy1) == math::sign(dy2);
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
static inline bool apply(Point const& pi, Point const& pj,
|
||||
Point const& qi, Point const& qj, Point& ip)
|
||||
@ -50,7 +41,7 @@ struct line_line_intersection
|
||||
|
||||
coordinate_type denominator = det(get<0>(pi) - get<0>(pj), get<1>(pi) - get<1>(pj), get<0>(qi) - get<0>(qj), get<1>(qi) - get<1>(qj));
|
||||
|
||||
// TODO: maybe use something else then denominator (sides?) to determine this.
|
||||
// TODO: code below will be removed - curve type is now checked before
|
||||
|
||||
// The limit is arbitrary. If it is small, the IP will be far far away.
|
||||
// For round joins, it will not be used at all.
|
||||
@ -59,28 +50,9 @@ struct line_line_intersection
|
||||
coordinate_type const limit = 1.0e-9;
|
||||
if (geometry::math::abs(denominator) < limit)
|
||||
{
|
||||
// If denominator is small or zero, segments are (nearly) parallel
|
||||
// Either they continue each other
|
||||
// +---------------+--------------+
|
||||
// x1,y1 x2,y2=x3,y3 x4,y4
|
||||
// We then return false
|
||||
|
||||
// Or they form a spikey feature
|
||||
// x1,y1
|
||||
// +---------------+ x2,y2
|
||||
// +---------------/ x3,y4
|
||||
// x4,y4
|
||||
// We then calculate the IP from one of the segments up to a certain distance
|
||||
if (parallel_continue(get<0>(qj) - get<0>(qi),
|
||||
get<1>(qj) - get<1>(qi),
|
||||
get<0>(pj) - get<0>(pi),
|
||||
get<1>(pj) - get<1>(pi)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Spikey, set something arbitrary and calculate px,py far away
|
||||
denominator = limit;
|
||||
}
|
||||
// END TODO
|
||||
|
||||
coordinate_type d1 = det(get<0>(pi), get<1>(pi), get<0>(pj), get<1>(pj));
|
||||
coordinate_type d2 = det(get<0>(qi), get<1>(qi), get<0>(qj), get<1>(qj));
|
||||
|
@ -70,6 +70,19 @@ enum piece_type
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
\brief Enumerates types of joins
|
||||
\ingroup enum
|
||||
*/
|
||||
enum join_selector
|
||||
{
|
||||
join_convex,
|
||||
join_concave,
|
||||
join_continue, // collinear, next segment touches previous segment
|
||||
join_spike // collinear, with overlap, next segment goes back
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include <boost/geometry/core/cs.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
@ -33,7 +32,6 @@ template
|
||||
>
|
||||
struct join_miter
|
||||
{
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointIn>::type coordinate_type;
|
||||
|
||||
// Constructor compatible with other join strategies:
|
||||
@ -46,16 +44,6 @@ struct join_miter
|
||||
coordinate_type const& buffer_distance,
|
||||
RangeOut& range_out) const
|
||||
{
|
||||
coordinate_type const zero = 0;
|
||||
int const signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PointIn p = ip;
|
||||
|
||||
// Normalize it and give it X*dist.
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <boost/geometry/policies/compare.hpp>
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
@ -42,7 +41,6 @@ public :
|
||||
: m_steps_per_circle(steps_per_circle)
|
||||
{}
|
||||
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointOut>::type coordinate_type;
|
||||
|
||||
typedef typename geometry::select_most_precise
|
||||
@ -121,16 +119,6 @@ public :
|
||||
return false;
|
||||
}
|
||||
|
||||
coordinate_type const zero = 0;
|
||||
int const signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate 'vectors'
|
||||
coordinate_type vix = (get<0>(ip) - get<0>(vertex));
|
||||
coordinate_type viy = (get<1>(ip) - get<1>(vertex));
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <boost/geometry/policies/compare.hpp>
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/select_most_precise.hpp>
|
||||
|
||||
@ -42,7 +41,6 @@ public :
|
||||
: m_max_level(max_level)
|
||||
{}
|
||||
|
||||
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
|
||||
typedef typename coordinate_type<PointOut>::type coordinate_type;
|
||||
|
||||
typedef typename geometry::select_most_precise
|
||||
@ -110,16 +108,6 @@ public :
|
||||
return false;
|
||||
}
|
||||
|
||||
coordinate_type const zero = 0;
|
||||
int const signum = buffer_distance > zero ? 1
|
||||
: buffer_distance < zero ? -1
|
||||
: 0;
|
||||
|
||||
if (side::apply(perp1, ip, perp2) == signum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate 'vectors'
|
||||
coordinate_type vix = (get<0>(ip) - get<0>(vertex));
|
||||
coordinate_type viy = (get<1>(ip) - get<1>(vertex));
|
||||
|
@ -28,6 +28,7 @@ static std::string const one_bend = "LINESTRING(0 0,4 5,7 4)";
|
||||
static std::string const two_bends = "LINESTRING(0 0,4 5,7 4,10 6)";
|
||||
static std::string const overlapping = "LINESTRING(0 0,4 5,7 4,10 6, 10 2,2 2)";
|
||||
static std::string const curve = "LINESTRING(2 7,3 5,5 4,7 5,8 7)";
|
||||
static std::string const tripod = "LINESTRING(5 0,5 5,1 8,5 5,9 8)"; // with spike
|
||||
|
||||
static std::string const for_collinear = "LINESTRING(2 0,0 0,0 4,6 4,6 0,4 0)";
|
||||
static std::string const for_collinear2 = "LINESTRING(2 1,2 0,0 0,0 4,6 4,6 0,4 0,4 1)";
|
||||
@ -116,6 +117,9 @@ void test_all()
|
||||
test_one<linestring, buf::join_miter, buf::end_flat, polygon>("curve", curve, 55.3875, 5.0, 3.0);
|
||||
#endif
|
||||
|
||||
test_one<linestring, buf::join_miter, buf::end_flat, polygon>("tripod", tripod, 89.55, 3.0);
|
||||
test_one<linestring, buf::join_miter, buf::end_round, polygon>("tripod", tripod, 117.806, 3.0);
|
||||
|
||||
test_one<linestring, buf::join_round, buf::end_flat, polygon>("chained2", chained2, 11.3137, 2.5, 1.5);
|
||||
test_one<linestring, buf::join_round, buf::end_flat, polygon>("chained3", chained3, 16.9706, 2.5, 1.5);
|
||||
test_one<linestring, buf::join_round, buf::end_flat, polygon>("chained4", chained4, 22.6274, 2.5, 1.5);
|
||||
|
@ -24,6 +24,9 @@ static std::string const spike_simplex
|
||||
static std::string const chained_box
|
||||
= "POLYGON((0 0,0 4,4 4,8 4,12 4,12 0,8 0,4 0,0 0))";
|
||||
|
||||
static std::string const join_types
|
||||
= "POLYGON ((0 0,0 4,4 4,2 6,0 8,2 6,4 8,8 4,4 0,0 0))"; // first 4 join types are all different: convex, concave, continue, spike
|
||||
|
||||
static std::string const donut_simplex
|
||||
= "POLYGON ((0 0,1 9,8 1,0 0),(1 1,4 1,1 4,1 1))";
|
||||
static std::string const donut_diamond
|
||||
@ -99,6 +102,8 @@ void test_all()
|
||||
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("spike_simplex150", spike_simplex, 998.9530, 15.0);
|
||||
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("spike_simplex150", spike_simplex, 1532.6543, 15.0);
|
||||
|
||||
test_one<polygon_type, buf::join_round, buf::end_flat, polygon_type>("join_types", join_types, 91.7379, 1.5);
|
||||
|
||||
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("chained_box", chained_box, 83.1403, 1.0);
|
||||
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("chained_box", chained_box, 84, 1.0);
|
||||
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("L", letter_L, 13.7314, 0.5);
|
||||
@ -275,12 +280,16 @@ void test_all()
|
||||
|
||||
#if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS)
|
||||
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("parcel3_10", parcel3, 99, 10.0);
|
||||
#endif
|
||||
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("parcel3_10", parcel3, 20022.4271087646484, 10.0);
|
||||
#endif
|
||||
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("parcel3_20", parcel3, 34504.8032569885254, 20.0, -999, false);
|
||||
#if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS)
|
||||
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("parcel3_20", parcel3, 34615.6553726196289, 20.0);
|
||||
#endif
|
||||
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("parcel3_30", parcel3, 45263.0166702270508, 30.0, -999, false);
|
||||
#if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS)
|
||||
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("parcel3_30", parcel3, 45506.1910133361816, 30.0);
|
||||
#endif
|
||||
|
||||
// Negative buffers making polygons smaller
|
||||
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("simplex", simplex, 7.04043, -0.5);
|
||||
|
Loading…
x
Reference in New Issue
Block a user