Merge branch 'develop' of https://github.com/boostorg/geometry into feature/distance

This commit is contained in:
Menelaos Karavelas
2014-07-02 23:44:23 +03:00
3 changed files with 222 additions and 118 deletions

View File

@@ -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);
}
}

View File

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

View 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