Updated buffer / double->coordinate_type

Added buffering new approach (per segment), do not use this yet.

[SVN r61227]
This commit is contained in:
Barend Gehrels
2010-04-12 16:19:51 +00:00
parent 305df85138
commit d800cfd056
2 changed files with 351 additions and 5 deletions

View File

@@ -35,20 +35,20 @@ namespace detail { namespace buffer
template <typename RingInput, typename RingOutput, typename JoinStrategy>
struct ring_buffer
{
typedef typename point_type<RingOutput>::type output_point_type;
typedef typename coordinate_type<output_point_type>::type coordinate_type;
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
template <typename Mapper>
#endif
static inline void apply(RingInput const& ring, RingOutput& buffered,
double distance, // TODO: change coordinate type
coordinate_type distance,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
typedef typename point_type<RingOutput>::type output_point_type;
typedef segment<output_point_type const> segment_type;
typedef typename boost::range_iterator
<
@@ -72,7 +72,6 @@ struct ring_buffer
bool skip = false;
// Generate a block along (int most cases to the left of) the segment
typedef typename coordinate_type<output_point_type>::type coordinate_type;
// Simulate a vector d (dx,dy)
coordinate_type dx = get<0>(*it) - get<0>(*prev);
@@ -185,7 +184,8 @@ struct polygon_buffer
template <typename Mapper>
#endif
static inline void apply(PolygonInput const& polygon, PolygonOutput& buffered,
double distance, JoinStrategy const& join_strategy
typename coordinate_type<PolygonOutput>::type distance,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif

View File

@@ -0,0 +1,346 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
//
// Copyright Barend Gehrels 2010, Geodan, 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_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP
#include <cstddef>
#include <boost/foreach.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range/functions.hpp>
#include <boost/range/metafunctions.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/strategies/buffer_side.hpp>
#include <boost/geometry/strategies/buffer_join_round.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
#include <boost/geometry/algorithms/dissolve.hpp>
// TEMPORARY do not use yet.
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <typename Point, typename PointOut, typename DistanceType>
inline bool calculate_parallels(Point const& point1, Point const& point2,
PointOut& p1, PointOut& p2, DistanceType const& distance)
{
typedef typename coordinate_type<Point>::type coordinate_type;
// Simulate a vector d (dx,dy)
coordinate_type dx = get<0>(point2) - get<0>(point1);
coordinate_type dy = get<1>(point2) - get<1>(point1);
// For normalization [0,1] (=dot product d.d, sqrt)
// TODO: promote to non-integer
coordinate_type length = sqrt(dx * dx + dy * dy);
// Because coordinates are not equal, should been checked before, length should not be zero
if(geometry::math::equals(length, 0))
{
return false;
}
// Generate the normalized perpendicular p, to the left (ccw)
coordinate_type px = -dy / length;
coordinate_type py = dx / length;
set<0>(p1, get<0>(point1) + px * distance);
set<1>(p1, get<1>(point1) + py * distance);
set<0>(p2, get<0>(point2) + px * distance);
set<1>(p2, get<1>(point2) + py * distance);
return true;
}
template
<
typename GeometryOut, typename Range,
typename DistanceStrategy,
typename JoinStrategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
struct per_segment_buffer
{
typedef typename point_type<Range>::type input_point_type;
typedef typename point_type<GeometryOut>::type point_type;
typedef typename coordinate_type<point_type>::type coordinate_type;
typedef coordinate_type distance_type; // TODO promote to FP
typedef segment<point_type const> segment_type;
typedef typename geometry::ring_type<GeometryOut>::type ring_type;
typedef typename strategy_side<typename cs_tag<point_type>::type>::type side;
typedef typename boost::range_iterator<Range const>::type iterator_type;
static inline void calculate_tail(input_point_type const& tail, input_point_type const& head,
point_type& tail_left, point_type& tail_right,
distance_type& distance_left,
distance_type& distance_right,
distance_type& buffered_length)
{
coordinate_type ext_x = get<0>(head) - get<0>(tail);
coordinate_type ext_y = get<1>(head) - get<1>(tail);
distance_type segment_length = sqrt(ext_x * ext_x + ext_y * ext_y);
if (buffered_length < distance_left)
{
distance_left = buffered_length;
}
if (buffered_length < distance_right)
{
distance_right = buffered_length;
}
distance_type prop_left = distance_left / segment_length;
distance_type prop_right = distance_right / segment_length;
set<0>(tail_left, get<0>(tail) - ext_x * prop_left);
set<1>(tail_left, get<1>(tail) - ext_y * prop_left);
set<0>(tail_right, get<0>(tail) - ext_x * prop_right);
set<1>(tail_right, get<1>(tail) - ext_y * prop_right);
buffered_length += segment_length;
}
static inline void calculate_head(input_point_type const& tail, input_point_type const& head,
point_type& head_left, point_type& head_right,
distance_type& distance_left,
distance_type& distance_right,
distance_type const& rest_length)
{
coordinate_type ext_x = get<0>(head) - get<0>(tail);
coordinate_type ext_y = get<1>(head) - get<1>(tail);
distance_type segment_length = sqrt(ext_x * ext_x + ext_y * ext_y);
if (rest_length < distance_left)
{
distance_left = rest_length;
}
if (rest_length < distance_right)
{
distance_right = rest_length;
}
distance_type prop_left = distance_left / segment_length;
distance_type prop_right = distance_right / segment_length;
set<0>(head_left, get<0>(head) + ext_x * prop_left);
set<1>(head_left, get<1>(head) + ext_y * prop_left);
set<0>(head_right, get<0>(head) + ext_x * prop_right);
set<1>(head_right, get<1>(head) + ext_y * prop_right);
}
static inline void apply(Range const& range,
std::vector<GeometryOut>& buffered,
DistanceStrategy const& distance_strategy,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
// Buffer all segments separately, and put them in a temporary vector
std::vector<GeometryOut> buffered_pieces;
bool first = true;
strategy::buffer::join_round2<point_type> new_join;
//strategy::buffer::join_none<point_type> new_join;
distance_type range_length = geometry::length(range);
distance_type buffered_length = coordinate_type();
iterator_type it = boost::begin(range);
//iterator_type it_c = boost::end(range);
for (iterator_type previous = it++;
it != boost::end(range);
++it)
{
bool const last = it + 1 == boost::end(range);
distance_type distance_left = distance_strategy.apply(
*previous, *it, buffer_side_left);
distance_type distance_right = distance_strategy.apply(
*previous, *it, buffer_side_right);
point_type left_ab_p1, left_ab_p2, right_ab_p1, right_ab_p2;
if (detail::disjoint::disjoint_point_point(*previous, *it)
&& calculate_parallels(*previous, *it, left_ab_p1, left_ab_p2,
distance_left)
&& calculate_parallels(*previous, *it, right_ab_p1, right_ab_p2,
-distance_right)
)
{
{
point_type tail_left, tail_right, head_left, head_right;
// For flat buffers, generate corners only if outside range of buffer_distance
distance_type distance_tail_left = distance_left;
distance_type distance_tail_right = distance_right;
distance_type distance_head_left = distance_left;
distance_type distance_head_right = distance_right;
calculate_tail(*previous, *it,
tail_left, tail_right,
distance_tail_left, distance_tail_right,
buffered_length);
distance_type const rest_length = range_length - buffered_length;
calculate_head(*previous, *it,
head_left, head_right,
distance_head_left, distance_head_right,
rest_length);
// Add non-axis aligned rectangle
buffered_pieces.resize(buffered_pieces.size() + 1);
ring_type& ring = exterior_ring(buffered_pieces.back());
ring.push_back(left_ab_p1);
ring.push_back(left_ab_p2);
if (! last)
{
new_join.apply(*it, left_ab_p2, left_ab_p2, head_left,
distance_left, distance_head_left,
std::back_inserter(ring));
ring.push_back(head_left);
ring.push_back(head_right);
new_join.apply(*it, right_ab_p2, head_right, right_ab_p2,
distance_right, distance_head_right,
std::back_inserter(ring));
}
ring.push_back(right_ab_p2);
ring.push_back(right_ab_p1);
if (! first)
{
new_join.apply(*previous, right_ab_p1, right_ab_p1, tail_right,
distance_right, distance_tail_right,
std::back_inserter(ring));
ring.push_back(tail_right);
ring.push_back(tail_left);
new_join.apply(*previous, left_ab_p1, tail_left, left_ab_p1,
distance_left, distance_tail_left,
std::back_inserter(ring));
}
ring.push_back(left_ab_p1);
}
previous = it;
first = false;
}
}
// TEMP
buffered.swap(buffered_pieces);
return;
// END TEMP
BOOST_FOREACH(GeometryOut const& p, buffered_pieces)
{
if (buffered.empty())
{
buffered.push_back(p);
}
else if (boost::size(buffered) == 1)
{
std::vector<GeometryOut> unioned;
geometry::union_inserter<GeometryOut>(buffered.front(), p, std::back_inserter(unioned));
buffered.swap(unioned);
}
else
{
std::cerr << " D " << buffered.size();
/*std::vector<GeometryOut> dissolved;
dissolved.push_back(p);
geometry::dissolver(buffered, dissolved);
dissolved.swap(buffered);*/
}
}
/***
std::vector<GeometryOut> dissolved;
BOOST_FOREACH(GeometryOut const& p, buffered)
{
geometry::dissolve(p, dissolved);
}
dissolved.swap(buffered);
***/
// Output
}
};
template
<
typename GeometryOut, typename Geometry,
typename DistanceStrategy,
typename JoinStrategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
inline void segmenting_buffer(Geometry const& geometry,
std::vector<GeometryOut>& buffered,
DistanceStrategy const& distance_strategy,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
per_segment_buffer
<
GeometryOut, Geometry,
DistanceStrategy, JoinStrategy
>::apply(geometry, buffered, distance_strategy, join_strategy);
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP