mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-09 11:12:21 +00:00
Merge branch 'develop' of https://github.com/boostorg/geometry into feature/distance
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
#include <boost/geometry/strategies/cartesian/buffer_side.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>
|
||||
@@ -38,52 +39,12 @@ namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename RingOutput,
|
||||
typename Tag
|
||||
>
|
||||
template <typename RingOutput>
|
||||
struct buffer_range
|
||||
{
|
||||
typedef typename point_type<RingOutput>::type output_point_type;
|
||||
typedef typename coordinate_type<RingOutput>::type coordinate_type;
|
||||
|
||||
template
|
||||
<
|
||||
typename Point,
|
||||
typename DistanceStrategy
|
||||
>
|
||||
static inline void generate_side(
|
||||
Point const& input_p1, Point const& input_p2,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
DistanceStrategy const& distance,
|
||||
output_point_type& side_p1, output_point_type& side_p2)
|
||||
{
|
||||
// Generate a block along (left or right of) the segment
|
||||
|
||||
// Simulate a vector d (dx,dy)
|
||||
coordinate_type dx = get<0>(input_p2) - get<0>(input_p1);
|
||||
coordinate_type dy = get<1>(input_p2) - get<1>(input_p1);
|
||||
|
||||
// For normalization [0,1] (=dot product d.d, sqrt)
|
||||
// TODO promoted_type
|
||||
coordinate_type const length = geometry::math::sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Because coordinates are not equal, length should not be zero
|
||||
BOOST_ASSERT((! geometry::math::equals(length, 0)));
|
||||
|
||||
// Generate the normalized perpendicular p, to the left (ccw)
|
||||
coordinate_type const px = -dy / length;
|
||||
coordinate_type const py = dx / length;
|
||||
|
||||
coordinate_type const d = distance.apply(input_p1, input_p2, side);
|
||||
|
||||
set<0>(side_p1, get<0>(input_p1) + px * d);
|
||||
set<1>(side_p1, get<1>(input_p1) + py * d);
|
||||
set<0>(side_p2, get<0>(input_p2) + px * d);
|
||||
set<1>(side_p2, get<1>(input_p2) + py * d);
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename Collection,
|
||||
@@ -197,7 +158,10 @@ struct buffer_range
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
RobustPolicy const& robust_policy,
|
||||
bool /*close*/ = false)
|
||||
output_point_type& first_p1,
|
||||
output_point_type& first_p2,
|
||||
output_point_type& last_p1,
|
||||
output_point_type& last_p2)
|
||||
{
|
||||
typedef typename std::iterator_traits
|
||||
<
|
||||
@@ -211,16 +175,14 @@ struct buffer_range
|
||||
>::type robust_point_type;
|
||||
|
||||
robust_point_type previous_robust_input;
|
||||
output_point_type previous_p1, previous_p2;
|
||||
output_point_type first_p1, first_p2;
|
||||
point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
|
||||
|
||||
/*
|
||||
* prev.p1 prev.p2 these are the "previous perpendicular points"
|
||||
* last.p1 last.p2 these are the "previous (last) perpendicular points"
|
||||
* --------------
|
||||
* | |
|
||||
* *------------*____ <- *prev
|
||||
* pup | | p1 "current perpendiculat point 1"
|
||||
* pup | | p1 "current perpendicular point 1"
|
||||
* | |
|
||||
* | | this forms a "side", a side is a piece
|
||||
* | |
|
||||
@@ -238,6 +200,9 @@ struct buffer_range
|
||||
|
||||
geometry::recalculate(previous_robust_input, *begin, robust_policy);
|
||||
|
||||
std::vector<output_point_type> generated_side;
|
||||
generated_side.reserve(2);
|
||||
|
||||
for (Iterator prev = it++; it != end; ++it)
|
||||
{
|
||||
robust_point_type robust_input;
|
||||
@@ -246,69 +211,39 @@ struct buffer_range
|
||||
// unlikely (though possible by rescaling)
|
||||
if (! detail::equals::equals_point_point(previous_robust_input, robust_input))
|
||||
{
|
||||
output_point_type p1, p2;
|
||||
generate_side(*prev, *it, side, distance_strategy, p1, p2);
|
||||
generated_side.clear();
|
||||
strategy::buffer::buffer_side::apply(*prev,
|
||||
*it, side, distance_strategy, generated_side);
|
||||
|
||||
if (! first)
|
||||
{
|
||||
add_join(collection, phase,
|
||||
penultimate_point,
|
||||
*prev, previous_p1, previous_p2,
|
||||
*it, p1, p2,
|
||||
*prev, last_p1, last_p2,
|
||||
*it, generated_side.front(), generated_side.back(),
|
||||
side,
|
||||
distance_strategy, join_strategy, end_strategy,
|
||||
robust_policy);
|
||||
}
|
||||
|
||||
collection.add_piece(strategy::buffer::buffered_segment,
|
||||
*prev, *it, p1, p2, first);
|
||||
*prev, *it, generated_side, first);
|
||||
|
||||
penultimate_point = *prev;
|
||||
ultimate_point = *it;
|
||||
previous_p1 = p1;
|
||||
previous_p2 = p2;
|
||||
last_p1 = generated_side.front();
|
||||
last_p2 = generated_side.back();
|
||||
prev = it;
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
second_point = *it;
|
||||
first_p1 = p1;
|
||||
first_p2 = p2;
|
||||
first_p1 = generated_side.front();
|
||||
first_p2 = generated_side.back();
|
||||
}
|
||||
}
|
||||
previous_robust_input = robust_input;
|
||||
}
|
||||
|
||||
// Might be replaced by specialization
|
||||
if(boost::is_same<Tag, ring_tag>::value)
|
||||
{
|
||||
// Generate closing corner
|
||||
add_join(collection, phase,
|
||||
penultimate_point,
|
||||
*(end - 1), previous_p1, previous_p2,
|
||||
*(begin + 1), first_p1, first_p2,
|
||||
side,
|
||||
distance_strategy, join_strategy, end_strategy,
|
||||
robust_policy);
|
||||
|
||||
// Buffer is closed automatically by last closing corner (NOT FOR OPEN POLYGONS - TODO)
|
||||
}
|
||||
else if (boost::is_same<Tag, linestring_tag>::value)
|
||||
{
|
||||
|
||||
// Generate perpendicular points to the reverse side,
|
||||
// these points are necessary for all end-cap strategies
|
||||
// TODO fix this (approach) for one-side buffer (1.5 - -1.0)
|
||||
output_point_type rp1, rp2;
|
||||
generate_side(ultimate_point, penultimate_point,
|
||||
side == strategy::buffer::buffer_side_left
|
||||
? strategy::buffer::buffer_side_right
|
||||
: strategy::buffer::buffer_side_left,
|
||||
distance_strategy, rp2, rp1);
|
||||
|
||||
std::vector<output_point_type> range_out;
|
||||
end_strategy.apply(penultimate_point, previous_p2, ultimate_point, rp2, side, distance_strategy, range_out);
|
||||
collection.add_endcap(end_strategy, range_out, ultimate_point);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -485,17 +420,47 @@ template
|
||||
typename RingOutput
|
||||
>
|
||||
struct buffer_inserter<ring_tag, RingInput, RingOutput>
|
||||
: public detail::buffer::buffer_range
|
||||
<
|
||||
RingOutput,
|
||||
ring_tag
|
||||
>
|
||||
{
|
||||
typedef detail::buffer::buffer_range
|
||||
<
|
||||
RingOutput,
|
||||
ring_tag
|
||||
> base;
|
||||
typedef typename point_type<RingOutput>::type output_point_type;
|
||||
|
||||
template
|
||||
<
|
||||
typename Collection,
|
||||
typename Iterator,
|
||||
typename DistanceStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename RobustPolicy
|
||||
>
|
||||
static inline void iterate(Collection& collection,
|
||||
Iterator begin, Iterator end,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
RobustPolicy const& robust_policy)
|
||||
{
|
||||
output_point_type first_p1, first_p2, last_p1, last_p2;
|
||||
|
||||
typedef detail::buffer::buffer_range<RingOutput> buffer_range;
|
||||
|
||||
buffer_range::iterate(collection, 0, begin, end,
|
||||
side,
|
||||
distance_strategy, join_strategy, end_strategy, robust_policy,
|
||||
first_p1, first_p2, last_p1, last_p2);
|
||||
|
||||
// Generate closing join
|
||||
buffer_range::add_join(collection, 0,
|
||||
*(end - 2),
|
||||
*(end - 1), last_p1, last_p2,
|
||||
*(begin + 1), first_p1, first_p2,
|
||||
side,
|
||||
distance_strategy, join_strategy, end_strategy,
|
||||
robust_policy);
|
||||
|
||||
// Buffer is closed automatically by last closing corner
|
||||
// (OPEN IT FOR OPEN POLYGONS - TODO)
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
@@ -531,16 +496,17 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
|
||||
// Walk backwards (rings will be reversed afterwards)
|
||||
// It might be that this will be changed later.
|
||||
// TODO: decide this.
|
||||
base::iterate(collection, 0, boost::rbegin(simplified), boost::rend(simplified),
|
||||
iterate(collection, boost::rbegin(simplified), boost::rend(simplified),
|
||||
strategy::buffer::buffer_side_right,
|
||||
distance, join_strategy, end_strategy, robust_policy);
|
||||
}
|
||||
else
|
||||
{
|
||||
base::iterate(collection, 0, boost::begin(simplified), boost::end(simplified),
|
||||
iterate(collection, boost::begin(simplified), boost::end(simplified),
|
||||
strategy::buffer::buffer_side_left,
|
||||
distance, join_strategy, end_strategy, robust_policy);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -552,17 +518,64 @@ template
|
||||
typename Polygon
|
||||
>
|
||||
struct buffer_inserter<linestring_tag, Linestring, Polygon>
|
||||
: public detail::buffer::buffer_range
|
||||
<
|
||||
typename ring_type<Polygon>::type,
|
||||
linestring_tag
|
||||
>
|
||||
{
|
||||
typedef detail::buffer::buffer_range
|
||||
<
|
||||
typename ring_type<Polygon>::type,
|
||||
linestring_tag
|
||||
> base;
|
||||
typedef typename ring_type<Polygon>::type output_ring_type;
|
||||
typedef typename point_type<output_ring_type>::type output_point_type;
|
||||
typedef typename point_type<Linestring>::type input_point_type;
|
||||
|
||||
template <typename DistanceStrategy>
|
||||
static inline output_point_type first_perpendicular_point(
|
||||
input_point_type const& p1, input_point_type const& p2,
|
||||
DistanceStrategy const& distance_strategy)
|
||||
{
|
||||
std::vector<output_point_type> generated_side;
|
||||
strategy::buffer::buffer_side::apply(p1, p2,
|
||||
strategy::buffer::buffer_side_right,
|
||||
distance_strategy, generated_side);
|
||||
return generated_side.front();
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename Collection,
|
||||
typename Iterator,
|
||||
typename DistanceStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename RobustPolicy
|
||||
>
|
||||
static inline void iterate(Collection& collection, int phase,
|
||||
Iterator begin, Iterator end,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
RobustPolicy const& robust_policy,
|
||||
output_point_type& first_p1)
|
||||
{
|
||||
input_point_type const& ultimate_point = *(end - 1);
|
||||
input_point_type const& penultimate_point = *(end - 2);
|
||||
|
||||
// For the end-cap, we need to have the last perpendicular point on the
|
||||
// other side of the linestring. If it is the second pass (right),
|
||||
// we have it already from the first phase (left).
|
||||
// But for the first pass, we have to generate it
|
||||
output_point_type reverse_p1
|
||||
= side == strategy::buffer::buffer_side_right
|
||||
? first_p1
|
||||
: first_perpendicular_point(ultimate_point, penultimate_point, distance_strategy);
|
||||
|
||||
output_point_type first_p2, last_p1, last_p2;
|
||||
|
||||
detail::buffer::buffer_range<output_ring_type>::iterate(collection,
|
||||
phase, begin, end, side,
|
||||
distance_strategy, join_strategy, end_strategy, robust_policy,
|
||||
first_p1, first_p2, last_p1, last_p2);
|
||||
|
||||
std::vector<output_point_type> range_out;
|
||||
end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
|
||||
collection.add_endcap(end_strategy, range_out, ultimate_point);
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
@@ -584,13 +597,16 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
|
||||
geometry::simplify(linestring, simplified, distance.simplify_distance());
|
||||
|
||||
collection.start_new_ring();
|
||||
base::iterate(collection, 0, boost::begin(simplified), boost::end(simplified),
|
||||
output_point_type first_p1;
|
||||
iterate(collection, 0, boost::begin(simplified), boost::end(simplified),
|
||||
strategy::buffer::buffer_side_left,
|
||||
distance, join_strategy, end_strategy, robust_policy);
|
||||
distance, join_strategy, end_strategy, robust_policy,
|
||||
first_p1);
|
||||
|
||||
base::iterate(collection, 1, boost::rbegin(simplified), boost::rend(simplified),
|
||||
iterate(collection, 1, boost::rbegin(simplified), boost::rend(simplified),
|
||||
strategy::buffer::buffer_side_right,
|
||||
distance, join_strategy, end_strategy, robust_policy, true);
|
||||
distance, join_strategy, end_strategy, robust_policy,
|
||||
first_p1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -589,8 +589,9 @@ struct buffered_piece_collection
|
||||
return m_pieces.back();
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
inline void add_piece(strategy::buffer::piece_type type, point_type const& p1, point_type const& p2,
|
||||
point_type const& b1, point_type const& b2, bool first)
|
||||
Range const& range, bool first)
|
||||
{
|
||||
piece& pc = add_piece(type, ! first);
|
||||
|
||||
@@ -599,14 +600,14 @@ struct buffered_piece_collection
|
||||
// But for now we need it to calculate intersections
|
||||
if (first)
|
||||
{
|
||||
add_point(b1);
|
||||
add_point(range.front());
|
||||
}
|
||||
pc.last_segment_index = add_point(b2);
|
||||
pc.last_segment_index = add_point(range.back());
|
||||
|
||||
pc.helper_segments.push_back(b2);
|
||||
pc.helper_segments.push_back(range.back());
|
||||
pc.helper_segments.push_back(p2);
|
||||
pc.helper_segments.push_back(p1);
|
||||
pc.helper_segments.push_back(b1);
|
||||
pc.helper_segments.push_back(range.front());
|
||||
}
|
||||
|
||||
inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
|
||||
|
||||
87
include/boost/geometry/strategies/cartesian/buffer_side.hpp
Normal file
87
include/boost/geometry/strategies/cartesian/buffer_side.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_HPP
|
||||
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/exterior_ring.hpp>
|
||||
#include <boost/geometry/core/interior_rings.hpp>
|
||||
|
||||
#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>
|
||||
#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/simplify.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
namespace strategy { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
struct buffer_side
|
||||
{
|
||||
|
||||
template
|
||||
<
|
||||
typename Point,
|
||||
typename OutputRange,
|
||||
typename DistanceStrategy
|
||||
>
|
||||
static inline void apply(
|
||||
Point const& input_p1, Point const& input_p2,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
DistanceStrategy const& distance,
|
||||
OutputRange& output_range)
|
||||
{
|
||||
typedef typename coordinate_type<Point>::type coordinate_type;
|
||||
// Generate a block along (left or right of) the segment
|
||||
|
||||
// Simulate a vector d (dx,dy)
|
||||
coordinate_type dx = get<0>(input_p2) - get<0>(input_p1);
|
||||
coordinate_type dy = get<1>(input_p2) - get<1>(input_p1);
|
||||
|
||||
// For normalization [0,1] (=dot product d.d, sqrt)
|
||||
// TODO promoted_type
|
||||
coordinate_type const length = geometry::math::sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Because coordinates are not equal, length should not be zero
|
||||
BOOST_ASSERT((! geometry::math::equals(length, 0)));
|
||||
|
||||
// Generate the normalized perpendicular p, to the left (ccw)
|
||||
coordinate_type const px = -dy / length;
|
||||
coordinate_type const py = dx / length;
|
||||
|
||||
coordinate_type const d = distance.apply(input_p1, input_p2, side);
|
||||
|
||||
output_range.resize(2);
|
||||
|
||||
set<0>(output_range.front(), get<0>(input_p1) + px * d);
|
||||
set<1>(output_range.front(), get<1>(input_p1) + py * d);
|
||||
set<0>(output_range.back(), get<0>(input_p2) + px * d);
|
||||
set<1>(output_range.back(), get<1>(input_p2) + py * d);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_HPP
|
||||
Reference in New Issue
Block a user