Boost.Geometry Substantial progress on buffer

[SVN r77061]
This commit is contained in:
Barend Gehrels
2012-02-18 10:07:18 +00:00
parent bfda23e1be
commit dffa159cd5
12 changed files with 1265 additions and 1345 deletions

View File

@@ -29,29 +29,15 @@ namespace detail { namespace buffer
// Appends points to an output range (always a ring).
// On the way, special points can be marked, and marked points
// forming a hooklet, loop, curve, curl, or how you call it are checked on intersections.
template
<
typename Range
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
template<typename Range>
class buffer_appender
{
public :
typedef Range range_type;
typedef typename geometry::point_type<Range>::type point_type;
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
Mapper const& m_mapper;
inline buffer_appender(Range& r, Mapper const& mapper)
: m_range(r)
, m_mapper(mapper)
#else
inline buffer_appender(Range& r)
: m_range(r)
#endif
{}
inline void append(point_type const& point)
@@ -83,9 +69,6 @@ public :
inline void append_begin_hooklet(point_type const& point)
{
DEBUG("begin hooklet");
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
const_cast<Mapper&>(m_mapper).map(point, "fill:rgb(0,0,192);", 3);
#endif
check(point);
@@ -99,9 +82,6 @@ public :
inline void append_end_hooklet(point_type const& point)
{
DEBUG("end hooklet");
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
const_cast<Mapper&>(m_mapper).map(point, "fill:rgb(0,0,255);", 4);
#endif
do_append(point);
}
@@ -177,12 +157,6 @@ private :
}
}
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
if (! m_pieces.empty() && m_pieces.back().end > m_pieces.back().begin)
{
const_cast<Mapper&>(m_mapper).map(point, "fill:rgb(0,255,0);", 4);
}
#endif
}
inline bool calculate_ip(point_type const& point, piece const& the_piece)
@@ -193,14 +167,6 @@ private :
return false;
}
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
const_cast<Mapper&>(m_mapper).map(point, "fill:rgb(255,0,0);", 4);
for (int i = the_piece.begin; i <= the_piece.end && i < n; i++)
{
//const_cast<Mapper&>(m_mapper).map(m_range[i], "fill:rgb(0,255,255);", 3);
}
#endif
segment_type segment1(m_previous_point, point);
// Walk backwards through list (chance is higher to have IP at the end)
@@ -215,11 +181,6 @@ private :
if (get_valid_split(is.intersections[0], i + 1, split_off))
{
add_ip(is.intersections[0], i + 1, the_piece, split_off);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
const_cast<Mapper&>(m_mapper).map(is.intersections[0], "fill:rgb(255,0,255);", 4);
const_cast<Mapper&>(m_mapper).map(split_off, "fill:none;stroke:rgb(255,0,0);stroke-width:2");
#endif
}
return true;
@@ -253,11 +214,6 @@ private :
add_ip(is.intersections[0], the_piece.begin + 1, the_piece, split_off);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
const_cast<Mapper&>(m_mapper).map(is.intersections[0], "fill:rgb(255,255,0);", 4);
const_cast<Mapper&>(m_mapper).map(m_range[the_piece.begin], "fill:rgb(255,192,0);", 4);
const_cast<Mapper&>(m_mapper).map(split_off, "fill:none;stroke:rgb(255,192,0);stroke-width:2");
#endif
return true;
}

View File

@@ -0,0 +1,324 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp>
#include <boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename RingOutput,
typename Tag
>
struct buffer_range
{
typedef typename point_type<RingOutput>::type output_point_type;
typedef typename coordinate_type<RingOutput>::type coordinate_type;
typedef model::referring_segment<output_point_type const> segment_type;
template
<
typename Collection,
typename Iterator,
typename DistanceStrategy,
typename JoinStrategy
>
static inline void iterate(Collection& collection,
Iterator begin, Iterator end,
buffer_side_selector side,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy
)
{
output_point_type previous_p1, previous_p2;
output_point_type first_p1, first_p2;
bool first = true;
Iterator it = begin;
for (Iterator prev = it++; it != end; ++it)
{
if (! detail::equals::equals_point_point(*prev, *it))
{
// Generate a block along (left or right of) the segment
// Simulate a vector d (dx,dy)
coordinate_type dx = get<0>(*it) - get<0>(*prev);
coordinate_type dy = get<1>(*it) - get<1>(*prev);
// For normalization [0,1] (=dot product d.d, sqrt)
coordinate_type length = 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 px = -dy / length;
coordinate_type py = dx / length;
output_point_type p1, p2;
coordinate_type d = distance.apply(*prev, *it, side);
set<0>(p2, get<0>(*it) + px * d);
set<1>(p2, get<1>(*it) + py * d);
set<0>(p1, get<0>(*prev) + px * d);
set<1>(p1, get<1>(*prev) + py * d);
std::vector<output_point_type> range_out;
if (! first)
{
output_point_type p;
segment_type s1(p1, p2);
segment_type s2(previous_p1, previous_p2);
if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p))
{
join_strategy.apply(p, *prev, previous_p2, p1,
distance.apply(*prev, *it, side),
range_out);
}
}
else
{
first = false;
first_p1 = p1;
first_p2 = p2;
}
if (! range_out.empty())
{
collection.add_piece(*prev, range_out);
range_out.clear();
}
collection.add_piece(*prev, *it, p1, p2);
previous_p1 = p1;
previous_p2 = p2;
prev = it;
}
}
// Might be replaced by specialization
if(boost::is_same<Tag, ring_tag>::value)
{
// Generate closing corner
output_point_type p;
segment_type s1(previous_p1, previous_p2);
segment_type s2(first_p1, first_p2);
line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p);
std::vector<output_point_type> range_out;
join_strategy.apply(p, *begin, previous_p2, first_p1,
distance.apply(*(end - 1), *begin, side),
range_out);
if (! range_out.empty())
{
collection.add_piece(*begin, range_out);
}
// Buffer is closed automatically by last closing corner (NOT FOR OPEN POLYGONS - TODO)
}
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
typename RingInput,
typename RingOutput
>
struct buffer_inserter
{};
template
<
typename RingInput,
typename RingOutput
>
struct buffer_inserter<ring_tag, RingInput, RingOutput>
: public detail::buffer::buffer_range
<
RingOutput,
ring_tag
>
{
template
<
typename Collection, typename DistanceStrategy, typename JoinStrategy
>
static inline void apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy)
{
iterate(collection, boost::begin(ring), boost::end(ring),
buffer_side_left,
distance, join_strategy);
}
};
template
<
typename Linestring,
typename Polygon
>
struct buffer_inserter<linestring_tag, Linestring, Polygon>
: public detail::buffer::buffer_range
<
typename ring_type<Polygon>::type,
linestring_tag
>
{
template<typename Collection, typename DistanceStrategy, typename JoinStrategy>
static inline void apply(Linestring const& linestring, Collection& collection,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy)
{
collection.add_input();
iterate(collection, boost::begin(linestring), boost::end(linestring),
buffer_side_left,
distance, join_strategy);
iterate(collection, boost::rbegin(linestring), boost::rend(linestring),
buffer_side_right,
distance, join_strategy);
}
};
template
<
typename PolygonInput,
typename PolygonOutput
>
struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
{
template <typename Collection, typename DistanceStrategy, typename JoinStrategy>
static inline void apply(PolygonInput const& polygon, Collection& collection,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy)
{
typedef typename ring_type<PolygonInput>::type input_ring_type;
typedef typename ring_type<PolygonOutput>::type output_ring_type;
typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy;
{
collection.add_input();
policy::apply(exterior_ring(polygon), collection,
distance, join_strategy);
}
typename interior_return_type<PolygonInput const>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
output_ring_type ring;
collection.add_input();
policy::apply(*it, collection, distance, join_strategy);
}
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
template
<
typename GeometryOutput,
typename GeometryInput,
typename OutputIterator,
typename DistanceStrategy,
typename JoinStrategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
DistanceStrategy const& distance_strategy, JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
detail::buffer::buffered_piece_collection<typename geometry::ring_type<GeometryOutput>::type> collection;
dispatch::buffer_inserter
<
typename tag<GeometryInput>::type,
GeometryInput,
GeometryOutput
>::apply(geometry_input, collection, distance_strategy, join_strategy);
collection.get_turns(geometry_input);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
collection.map_offsetted(mapper);
#endif
collection.discard_points();
collection.enrich();
collection.traverse();
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
//collection.map<geometry::polygon_tag>(mapper);
collection.map_turns(mapper);
collection.map_traverse(mapper);
#endif
collection.assign<GeometryOutput>(out);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP

View File

@@ -0,0 +1,657 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012 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_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
class backtrack_for_buffer
{
public :
typedef detail::overlay::backtrack_state state_type;
template <typename Operation, typename Rings, typename Turns, typename Geometry>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& reason,
Geometry const& ,
Geometry const& ,
state_type& state
)
{
std::cout << "WARNING " << reason << std::endl;
// TODO this is a copy of dissolve, check this for buffer
state.m_good = false;
// Make bad output clean
rings.resize(size_at_start);
ring.clear();
// Reject this as a starting point
operation.visited.set_rejected();
// And clear all visit info
clear_visit_info(turns);
}
};
enum intersection_location_type
{
location_ok, inside_buffer, inside_original
};
// Shoould follow traversal-turn-concept (enrichment, visit structure)
// and adds index in piece vector to find it back
template <typename Point>
struct buffer_turn_operation : public detail::overlay::traversal_turn_operation<Point>
{
int piece_index;
inline buffer_turn_operation()
: piece_index(-1)
{}
};
// Add an "intersection_location_type" which gets true for all intersection points lying inside the buffer or original polygon
template <typename Point>
struct buffer_turn_info : public detail::overlay::turn_info<Point, buffer_turn_operation<Point> >
{
intersection_location_type location;
inline buffer_turn_info()
: location(location_ok)
{}
};
template <typename Ring>
struct buffered_piece_collection
{
typedef typename geometry::point_type<Ring>::type Point;
typedef typename strategy::side::services::default_strategy<typename cs_tag<Point>::type>::type side;
enum piece_type
{
buffered_segment, buffered_join
};
template <typename Turn>
struct redundant_turn
{
inline bool operator()(Turn const& turn) const
{
return turn.location != location_ok;
}
};
struct piece
{
piece_type type;
int index;
segment_identifier seg_id;
// -----------------------------------------------------------------
// type=buffered_segment:
// This buffered_segment (2 points of the original)
Point p1, p2;
// The buffered buffered_segment (offsetted with certain distance to left/right)
Point b1, b2;
// -----------------------------------------------------------------
// type=buffered_join
Point p;
// Corner next to this buffered_segment (so connected to p2 and b2).
// In case p2 is a concave point, corner is empty
Ring corner; // TODO redundant
// Filled for both:
typedef geometry::model::linestring<Point> buffered_vector_type;
buffered_vector_type offseted_segment;
};
typedef std::vector<piece> piece_vector;
piece_vector all_pieces;
buffered_ring_collection<buffered_ring<Ring> > offsetted_rings;
buffered_ring_collection<Ring> traversed_rings;
segment_identifier current_segment_id;
typedef std::vector<buffer_turn_info<Point> > turn_vector_type;
typedef detail::overlay::get_turn_info
<
Point, Point, buffer_turn_info<Point>,
detail::overlay::calculate_distance_policy
> turn_policy;
turn_vector_type turn_vector;
inline buffered_piece_collection()
{}
inline bool within_piece(buffer_turn_info<Point> const& turn, piece const& pc) const
{
bool const collinear =
turn.operations[0].operation == detail::overlay::operation_continue
&& turn.operations[0].operation == detail::overlay::operation_continue;
// For now: use within, using built-up corner (which will be redundant later)
// Because pieces are always concave we only have to verify if it is left of all segments.
// As soon as it is right of one, we can quit. This is faster than the normal within,
// and we don't have to build up the polygon.
if (collinear)
{
// ONLY for the outer-boundary: return within
return geometry::within(turn.point, pc.corner);
}
return geometry::covered_by(turn.point, pc.corner);
}
// Checks if an intersection point is within one of all pieces
// (but skip the pieces of which this intersection point is the result
inline bool is_wrong(buffer_turn_info<Point> const& turn, piece const& piece1, piece const& piece2) const
{
// We might do this using partition.
typename std::vector<piece>::const_iterator it;
for (it = boost::begin(all_pieces);
it != boost::end(all_pieces);
++it)
{
if (it->index != piece1.index && it->index != piece2.index)
{
if (within_piece(turn, *it))
{
return true;
}
}
}
return false;
}
inline bool is_neighbor(piece const& piece1, piece const& piece2) const
{
if (std::abs(piece1.index - piece2.index) == 1)
{
return true;
}
int const b = boost::size(all_pieces) - 1; // back
return (piece1.index == 0 && piece2.index == b)
|| (piece1.index == b && piece2.index == 0)
;
}
inline bool skip_neighbor(piece const& piece1, piece const& piece2) const
{
return piece1.type != piece2.type && is_neighbor(piece1, piece2);
}
template <typename Iterator>
inline Point next_point(piece const& piece, Iterator it) const
{
// Next point in current offseted:
Iterator next = it;
++next;
if (next != boost::end(piece.offseted_segment))
{
return *next;
}
// TODO: check if there is a second point (there should be one)
// Second point from next piece:
int next_index = piece.index + 1;
if (next_index >= boost::size(all_pieces))
{
next_index = 0;
}
return piece.offseted_segment[1];
}
inline void calculate_turns(piece const& piece1, piece const& piece2)
{
buffer_turn_info<Point> the_model;
the_model.operations[0].piece_index = piece1.index;
the_model.operations[0].seg_id = piece1.seg_id;
// TODO use partition
typedef typename boost::range_iterator<typename piece::buffered_vector_type const>::type iterator;
iterator it1 = boost::begin(piece1.offseted_segment);
for (iterator prev1 = it1++;
it1 != boost::end(piece1.offseted_segment);
prev1 = it1++, the_model.operations[0].seg_id.segment_index++)
{
the_model.operations[1].piece_index = piece2.index;
the_model.operations[1].seg_id = piece2.seg_id;
iterator it2 = boost::begin(piece2.offseted_segment);
for (iterator prev2 = it2++;
it2 != boost::end(piece2.offseted_segment);
prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
{
// Revert (this is used more often - should be common function TODO)
the_model.operations[0].other_id = the_model.operations[1].seg_id;
the_model.operations[1].other_id = the_model.operations[0].seg_id;
turn_vector_type turns; // TEMPORARY in the end we can add directly to turn_vector
turn_policy::apply(*prev1, *it1, next_point(piece1, it1),
*prev2, *it2, next_point(piece2, it2),
the_model, std::back_inserter(turns));
// Add buffered_segment identifier info
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(turns); it != boost::end(turns); ++it)
{
// TODO: much later in partition.
if (is_wrong(*it, piece1, piece2))
{
it->location = inside_buffer;
}
turn_vector.push_back(*it);
}
}
}
}
template <typename Geometry>
inline void check_remaining_points(Geometry const& input_geometry)
{
// TODO: this should be done as a collection-of-points, for performance
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(turn_vector); it != boost::end(turn_vector); ++it)
{
if (it->location == location_ok)
{
if (geometry::covered_by(it->point, input_geometry))
{
it->location = inside_original;
}
}
}
}
template <typename Geometry>
inline void get_turns(Geometry const& input_geometry)
{
for(typename piece_vector::const_iterator it1 = boost::begin(all_pieces);
it1 != boost::end(all_pieces);
++it1)
{
for(typename piece_vector::const_iterator it2 = it1 + 1;
it2 != boost::end(all_pieces);
++it2)
{
if (! skip_neighbor(*it1, *it2))
{
calculate_turns(*it1, *it2);
}
}
}
if (boost::is_same<typename tag_cast<typename tag<Geometry>::type, areal_tag>::type, areal_tag>())
{
check_remaining_points(input_geometry);
}
calculate_discarded();
}
inline void add_input()
{
int const n = offsetted_rings.size();
current_segment_id.source_index = 0;
current_segment_id.multi_index = n;
current_segment_id.ring_index = -1;
current_segment_id.segment_index = 0;
offsetted_rings.resize(n + 1);
}
inline void add_point(Point const& p)
{
BOOST_ASSERT
(
boost::size(offsetted_rings) > 0
);
current_segment_id.segment_index++;
offsetted_rings.back().push_back(p);
}
inline piece& add_piece(piece_type type, bool decrease_by_one)
{
piece pc;
pc.type = type;
pc.index = boost::size(all_pieces);
pc.seg_id = current_segment_id;
std::size_t const n = boost::size(offsetted_rings.back());
pc.seg_id.segment_index = decrease_by_one ? n - 1 : n;
all_pieces.push_back(pc);
return all_pieces.back();
}
inline void add_piece(Point const& p1, Point const& p2,
Point const& b1, Point const& b2)
{
bool const last_type_join = ! all_pieces.empty()
&& all_pieces.back().type != buffered_segment;
piece& pc = add_piece(buffered_segment, last_type_join);
pc.p1 = p1;
pc.p2 = p2;
pc.b1 = b1;
pc.b2 = b2;
// If it follows the same piece-type point both should be added.
// There should be two intersections later and it should be discarded.
// But for need it to calculate intersections
if (! last_type_join)
{
add_point(b1);
}
add_point(b2);
// TEMPORARY
pc.corner.push_back(p1);
pc.corner.push_back(b1);
pc.corner.push_back(b2);
pc.corner.push_back(p2);
pc.corner.push_back(p1);
// END TEMPORARY
pc.offseted_segment.push_back(b1);
pc.offseted_segment.push_back(b2);
}
template <typename Corner>
inline void add_piece(Point const& p, Corner const& corner)
{
piece& pc = add_piece(buffered_join, true);
pc.p = p;
pc.corner.push_back(p);// TEMPORARY
bool first = true;
for (typename Corner::const_iterator it = boost::begin(corner);
it != boost::end(corner);
++it)
{
bool add = true;
if (first)
{
// Only for very first one, add first. In all other cases it is shared with previous.
add = offsetted_rings.back().empty();
first = false;
}
if (add)
{
add_point(*it);
}
pc.corner.push_back(*it); // TEMPORARY
pc.offseted_segment.push_back(*it); // REDUNDANT
}
pc.corner.push_back(p);// TEMPORARY
}
inline void enrich()
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Ring>::type
>::type side_strategy_type;
enrich_intersection_points<false, false>(turn_vector,
detail::overlay::operation_union,
offsetted_rings, offsetted_rings,
side_strategy_type());
}
// Discards all rings which do have not-OK intersection points only.
// Those can never be traversed and should not be part of the output.
inline void calculate_discarded()
{
for (typename boost::range_iterator<turn_vector_type const>::type it =
boost::begin(turn_vector); it != boost::end(turn_vector); ++it)
{
if (it->location != location_ok)
{
offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true;
offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true;
}
else
{
offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true;
offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true;
}
}
}
inline void discard_points()
{
// Erase all points being inside
turn_vector.erase(
std::remove_if(boost::begin(turn_vector), boost::end(turn_vector), redundant_turn<buffer_turn_info<Point> >()),
boost::end(turn_vector));
}
inline void traverse()
{
typedef detail::overlay::traverse
<
false, false,
buffered_ring_collection<buffered_ring<Ring > >, buffered_ring_collection<buffered_ring<Ring > >,
backtrack_for_buffer
> traverser;
traversed_rings.clear();
traverser::apply(offsetted_rings, offsetted_rings,
detail::overlay::operation_union,
turn_vector, traversed_rings);
}
template <typename GeometryOutput, typename OutputIterator>
inline OutputIterator assign(OutputIterator out)
{
typedef detail::overlay::ring_properties<Point> properties;
std::map<ring_identifier, properties> selected;
// Select all rings which do not have any self-intersection (other ones should be traversed)
int index = 0;
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
it != boost::end(offsetted_rings);
++it, ++index)
{
if (! it->has_intersections())
{
ring_identifier id(0, index, -1);
selected[id] = properties(*it, true);
}
}
// Select all created rings
index = 0;
for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type
it = boost::begin(traversed_rings);
it != boost::end(traversed_rings);
++it, ++index)
{
ring_identifier id(2, index, -1);
selected[id] = properties(*it, true);
}
detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
}
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
template <typename Mapper>
inline void map_turns(Mapper& mapper)
{
int index = 0;
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(turn_vector); it != boost::end(turn_vector); ++it)
{
std::string fill = "fill:rgb(0,255,0);";
switch(it->location)
{
case inside_buffer : fill = "fill:rgb(255,0,0);"; break;
case inside_original : fill = "fill:rgb(0,0,255);"; break;
}
mapper.map(it->point, fill, 6);
std::ostringstream out;
//out << it->operations[0].piece_index << "/" << it->operations[1].piece_index;
out << " " << all_pieces[it->operations[0].piece_index].seg_id.segment_index
<< "+" << all_pieces[it->operations[1].piece_index].seg_id.segment_index;
//out << " " << all_pieces[it->operations[0].piece_index].index_in_all_points
// << "," << all_pieces[it->operations[1].piece_index].index_in_all_points;
//out << " " << it->operations[0].seg_id.segment_index
// << "|" << it->operations[1].seg_id.segment_index;
out << ":" << operation_char(it->operations[0].operation);
mapper.text(it->point, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
}
}
template <typename Tag, typename Mapper>
inline void map(Mapper& mapper)
{
for(typename piece_vector::const_iterator it = boost::begin(all_pieces);
it != boost::end(all_pieces);
++it)
{
if (it->type == buffered_segment)
{
geometry::model::ring<Point> ring;
ring.push_back(it->p1);
ring.push_back(it->b1);
ring.push_back(it->b2);
ring.push_back(it->p2);
ring.push_back(it->p1);
if(boost::is_same<Tag, ring_tag>::value || boost::is_same<Tag, polygon_tag>::value)
{
mapper.map(ring, "opacity:0.3;fill:rgb(255,128,0);stroke:rgb(0,0,0);stroke-width:1");
}
else if(boost::is_same<Tag, linestring_tag>::value)
{
mapper.map(ring, "opacity:0.3;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
}
}
else
{
mapper.map(it->corner, "opacity:0.3;fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1");
}
// Put starting segment_index in centroid
Point centroid;
geometry::centroid(it->corner, centroid);
std::ostringstream out;
out << it->seg_id.segment_index;
mapper.text(centroid, out.str(), "fill:rgb(255,0,0);font-family='Arial';", 5, 5);
}
int index = 0;
for (typename boost::range_iterator<std::vector<Point> >::type it =
boost::begin(offsetted_rings.front()); it != boost::end(offsetted_rings.front()); ++it)
{
mapper.map(*it, "fill:rgb(0,0,0);", 2);
std::ostringstream out;
out << index++;
mapper.text(*it, out.str(), "fill:rgb(0,0,255);font-family='Arial';", -5, -5);
}
}
template <typename Mapper>
inline void map_traverse(Mapper& mapper)
{
for(typename buffered_ring_collection<Ring>::const_iterator it = boost::begin(traversed_rings);
it != boost::end(traversed_rings);
++it)
{
mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(0,255,0);stroke-width:8");
}
}
template <typename Mapper>
inline void map_offsetted(Mapper& mapper)
{
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
it != boost::end(offsetted_rings);
++it)
{
if (it->discarded())
{
mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(255,0,0);stroke-width:8");
}
else
{
mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(0,0,255);stroke-width:8");
}
}
}
#endif
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP

View File

@@ -0,0 +1,260 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012 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_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/multi/algorithms/within.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
struct buffered_ring_collection_tag : polygonal_tag, multi_tag
{};
template <typename Ring>
struct buffered_ring : public Ring
{
bool has_discarded_intersections;
bool has_accepted_intersections;
inline buffered_ring()
: has_accepted_intersections(false)
, has_discarded_intersections(false)
{}
inline bool discarded() const
{
return has_discarded_intersections && ! has_accepted_intersections;
}
inline bool has_intersections() const
{
return has_discarded_intersections || has_accepted_intersections;
}
};
// This is a collection now special for overlay (needs vector of rings)
template <typename Ring>
struct buffered_ring_collection : public std::vector<Ring>
{
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
// Register the types
namespace traits
{
template <typename Ring>
struct tag<detail::buffer::buffered_ring<Ring> >
{
typedef ring_tag type;
};
template <typename Ring>
struct point_order<detail::buffer::buffered_ring<Ring> >
{
static const order_selector value = geometry::point_order<Ring>::value;
};
template <typename Ring>
struct closure<detail::buffer::buffered_ring<Ring> >
{
static const closure_selector value = geometry::closure<Ring>::value;
};
template <typename Ring>
struct point_type<detail::buffer::buffered_ring_collection<Ring> >
{
typedef typename geometry::point_type<Ring>::type type;
};
template <typename Ring>
struct tag<detail::buffer::buffered_ring_collection<Ring> >
{
typedef detail::buffer::buffered_ring_collection_tag type;
};
} // namespace traits
namespace core_dispatch
{
template <typename Ring>
struct ring_type
<
detail::buffer::buffered_ring_collection_tag,
detail::buffer::buffered_ring_collection<Ring>
>
{
typedef Ring type;
};
}
namespace dispatch
{
template
<
typename MultiRing,
bool Reverse,
typename SegmentIdentifier,
typename PointOut
>
struct copy_segment_point
<
detail::buffer::buffered_ring_collection_tag,
MultiRing,
Reverse,
SegmentIdentifier,
PointOut
>
: detail::copy_segments::copy_segment_point_multi
<
MultiRing,
SegmentIdentifier,
PointOut,
detail::copy_segments::copy_segment_point_range
<
typename boost::range_value<MultiRing>::type,
Reverse,
SegmentIdentifier,
PointOut
>
>
{};
template
<
typename MultiRing,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments
<
detail::buffer::buffered_ring_collection_tag,
MultiRing,
Reverse,
SegmentIdentifier,
RangeOut
>
: detail::copy_segments::copy_segments_multi
<
MultiRing,
SegmentIdentifier,
RangeOut,
detail::copy_segments::copy_segments_ring
<
typename boost::range_value<MultiRing>::type,
Reverse,
SegmentIdentifier,
RangeOut
>
>
{};
template <typename Point, typename MultiGeometry>
struct within
<
Point,
MultiGeometry,
point_tag,
detail::buffer::buffered_ring_collection_tag
>
{
template <typename Strategy>
static inline bool apply(Point const& point,
MultiGeometry const& multi, Strategy const& strategy)
{
return detail::within::geometry_multi_within_code
<
Point,
MultiGeometry,
Strategy,
detail::within::point_in_ring
<
Point,
typename boost::range_value<MultiGeometry>::type,
//iterate_forward,
//closed,
order_as_direction
<
geometry::point_order<MultiGeometry>::value
>::value,
geometry::closure<MultiGeometry>::value,
Strategy
>
>::apply(point, multi, strategy) == 1;
}
};
} // namespace dispatch
namespace detail { namespace overlay
{
template<>
struct get_ring<detail::buffer::buffered_ring_collection_tag>
{
template<typename MultiGeometry>
static inline typename ring_type<MultiGeometry>::type const& apply(
ring_identifier const& id,
MultiGeometry const& multi_ring)
{
BOOST_ASSERT
(
id.multi_index >= 0
&& id.multi_index < boost::size(multi_ring)
);
return get_ring<ring_tag>::apply(id, multi_ring[id.multi_index]);
}
};
}}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING

View File

@@ -1,100 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_LINESTRING_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINESTRING_BUFFER_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp>
#include <boost/geometry/extensions/algorithms/buffer/range_buffer.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename Linestring,
typename Polygon,
typename DistanceStrategy,
typename JoinStrategy
>
struct linestring_buffer
: public range_buffer
<
typename ring_type<Polygon>::type,
DistanceStrategy,
JoinStrategy,
linestring_tag
>
{
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
template<typename Mapper>
#endif
static inline void apply(Linestring const& linestring, Polygon& buffered,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
buffer_appender
<
typename geometry::ring_type<Polygon>::type
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper
#endif
> appender
(
geometry::exterior_ring(buffered)
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
iterate(appender, boost::begin(linestring), boost::end(linestring),
buffer_side_left,
distance, join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
iterate(appender, boost::rbegin(linestring), boost::rend(linestring),
buffer_side_right,
distance, join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINESTRING_BUFFER_HPP

View File

@@ -1,159 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_POLYGON_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_POLYGON_BUFFER_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp>
#include <boost/geometry/extensions/algorithms/buffer/range_buffer.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename RingInput,
typename RingOutput,
typename DistanceStrategy,
typename JoinStrategy
>
struct ring_buffer
: public range_buffer
<
RingOutput,
DistanceStrategy,
JoinStrategy,
ring_tag
>
{
template
<
typename BufferAppender
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
static inline void apply(RingInput const& ring,
BufferAppender& appender,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
iterate(appender, boost::begin(ring), boost::end(ring),
buffer_side_left,
distance, join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
}
};
template
<
typename PolygonInput,
typename PolygonOutput,
typename DistanceStrategy,
typename JoinStrategy
>
struct polygon_buffer
{
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
template <typename Mapper>
#endif
static inline void apply(PolygonInput const& polygon, PolygonOutput& buffered,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
geometry::clear(buffered);
typedef typename ring_type<PolygonInput>::type input_ring_type;
typedef typename ring_type<PolygonOutput>::type output_ring_type;
typedef buffer_appender
<
output_ring_type
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper
#endif
> appender_type;
typedef ring_buffer<input_ring_type, output_ring_type, DistanceStrategy, JoinStrategy> policy;
{
appender_type appender(geometry::exterior_ring(buffered)
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
policy::apply(exterior_ring(polygon), appender,
distance, join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
}
typename interior_return_type<PolygonInput const>::type rings
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
output_ring_type ring;
appender_type appender(ring
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
policy::apply(*it, appender, distance, join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
interior_rings(buffered).push_back(ring);
}
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_POLYGON_BUFFER_HPP

View File

@@ -1,199 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_RANGE_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_RANGE_BUFFER_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp>
#include <boost/geometry/geometries/segment.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename RingOutput,
typename DistanceStrategy,
typename JoinStrategy,
typename Tag
>
struct range_buffer
{
typedef typename point_type<RingOutput>::type output_point_type;
typedef typename coordinate_type<RingOutput>::type coordinate_type;
typedef model::referring_segment<output_point_type const> segment_type;
template
<
typename BufferAppender,
typename Iterator
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
static inline void iterate(BufferAppender& appender,
Iterator begin, Iterator end,
buffer_side_selector side,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
)
{
output_point_type previous_p1, previous_p2;
output_point_type first_p1, first_p2;
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
int index = 0;
#endif
bool first = true;
Iterator it = begin;
for (Iterator prev = it++; it != end; ++it)
{
if (! detail::equals::equals_point_point(*prev, *it))
{
// Generate a block along (left or right of) the segment
// Simulate a vector d (dx,dy)
coordinate_type dx = get<0>(*it) - get<0>(*prev);
coordinate_type dy = get<1>(*it) - get<1>(*prev);
// For normalization [0,1] (=dot product d.d, sqrt)
coordinate_type length = 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 px = -dy / length;
coordinate_type py = dx / length;
output_point_type p1, p2;
coordinate_type d = distance.apply(*prev, *it, side);
set<0>(p2, get<0>(*it) + px * d);
set<1>(p2, get<1>(*it) + py * d);
set<0>(p1, get<0>(*prev) + px * d);
set<1>(p1, get<1>(*prev) + py * d);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
{
RingOutput block;
block.push_back(*prev);
block.push_back(*it);
block.push_back(p2);
block.push_back(p1);
block.push_back(*prev);
if(boost::is_same<Tag, ring_tag>::value)
{
mapper.map(block, "opacity:0.4;fill:rgb(255,128,0);stroke:rgb(0,0,0);stroke-width:1");
}
else if(boost::is_same<Tag, linestring_tag>::value)
{
mapper.map(block, "opacity:0.4;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
}
}
#endif
if (! first)
{
output_point_type p;
segment_type s1(p1, p2);
segment_type s2(previous_p1, previous_p2);
if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p))
{
join_strategy.apply(p, *prev, previous_p2, p1,
distance.apply(*prev, *it, side),
appender);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
{
//mapper.map(p, "fill:rgb(0,0,0);", 3);
//std::ostringstream out;
//out << index++;
//mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
}
#endif
}
}
else
{
first = false;
first_p1 = p1;
first_p2 = p2;
appender.append(p1);
}
previous_p1 = p1;
previous_p2 = p2;
prev = it;
}
}
// Might be replaced by specialization
if(boost::is_same<Tag, linestring_tag>::value)
{
appender.append(previous_p2);
}
else if(boost::is_same<Tag, ring_tag>::value)
{
// Generate closing corner
output_point_type p;
segment_type s1(previous_p1, previous_p2);
segment_type s2(first_p1, first_p2);
line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p);
join_strategy.apply(p, *begin, previous_p2, first_p1,
distance.apply(*(end - 1), *begin, side),
appender);
// Buffer is closed automatically by last closing corner (NOT FOR OPEN POLYGONS - TODO)
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
{
//mapper.map(p, "fill:rgb(0,0,0);", 3);
//std::ostringstream out;
//out << index++;
//mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
}
#endif
}
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_RANGE_BUFFER_HPP

View File

@@ -1,167 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_SECTIONALIZING_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SECTIONALIZING_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/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/algorithms/detail/buffer/intersecting_inserter.hpp>
#include <boost/geometry/extensions/algorithms/detail/buffer/linestring_buffer.hpp>
#include <boost/geometry/extensions/algorithms/detail/buffer/line_line_intersection.hpp>
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/extensions/algorithms/dissolve.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename GeometryOut, typename Geometry,
typename DistanceStrategy,
typename JoinStrategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
void sectionalizing_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
)
{
typedef typename point_type<Geometry>::type point_type;
typedef geometry::box<point_type> box_type;
typedef geometry::sections<box_type, 2> sections_type;
typedef typename geometry::ring_type<GeometryOut>::type ring_type;
// TEMPORARY
typedef intersecting_inserter
<
std::vector<GeometryOut>
> inserter_type;
sections_type sections;
geometry::sectionalize(geometry, sections);
// Buffer all sections separately, and put them in a temporary vector
std::vector<GeometryOut> buffered_sections;
BOOST_FOREACH(typename sections_type::value_type const& section, sections)
{
if (! section.duplicate)
{
typedef typename boost::range_iterator
<
typename geometry::detail::range_type<Geometry>::type const
>::type iterator_type;
inserter_type inserter(buffered_sections);
iterator_type begin, end;
typedef std::pair<iterator_type, iterator_type> section_range;
TODO: UPDATE: get _ section IS OBSOLETE NOW AND DISCARDED.
TAKE range_by_section AND ADD section.begin_index/section.end_index
geometry::get _ section(geometry, section, begin, end); // get_section is DISCARDED
geometry::detail::buffer::linestring_buffer
<
section_range, ring_type, DistanceStrategy, JoinStrategy
>::apply(std::make_pair(begin, end), inserter,
distance_strategy,
join_strategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
);
}
}
// IF there are bowl-like shapes, there can still be self-intersections
std::vector<GeometryOut> dissolved;
BOOST_FOREACH(GeometryOut const& p, buffered_sections)
{
geometry::dissolve(p, dissolved);
}
/*BOOST_FOREACH(GeometryOut const& p, buffered_sections)
{
if (geometry::intersects(p))
{
//std::cout << ".";
}
}*/
// TEMP
//buffered.swap(dissolved);
//return;
// END TEMP
BOOST_FOREACH(GeometryOut const& p, dissolved)
{
if (buffered.empty())
{
buffered.push_back(p);
//geometry::union_inserter<GeometryOut>(geometry, p, std::back_inserter(buffered));
}
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);*/
}
}
// Output
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SECTIONALIZING_BUFFER_HPP

View File

@@ -1,350 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP
#include <cstddef>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/strategies/buffer_join_round.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/disjoint.hpp>
#include <boost/geometry/extensions/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 model::segment<point_type const> segment_type;
typedef typename geometry::ring_type<GeometryOut>::type ring_type;
typedef typename strategy::side::services::default_strategy<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 < geometry::math::abs(distance_left))
{
distance_left = buffered_length * distance_left < 0 ? -1.0 : 1.0;
}
if (buffered_length < geometry::math::abs(distance_right))
{
distance_right = buffered_length * distance_right < 0 ? -1.0 : 1.0;
}
distance_type prop_left = geometry::math::abs(distance_left) / segment_length;
distance_type prop_right = geometry::math::abs(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, uncomment to see what was actually generated
//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

View File

@@ -1,116 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_SPLITTING_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SPLITTING_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/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/algorithms/detail/buffer/intersecting_inserter.hpp>
#include <boost/geometry/extensions/algorithms/detail/buffer/linestring_buffer.hpp>
#include <boost/geometry/extensions/algorithms/detail/buffer/line_line_intersection.hpp>
#include <boost/geometry/extensions/algorithms/detail/overlay/dissolver.hpp>
#include <boost/geometry/extensions/algorithms/detail/overlay/split_rings.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename GeometryOut, typename Geometry,
typename DistanceStrategy,
typename JoinStrategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
inline void splitting_buffer(Geometry const& geometry,
std::vector<GeometryOut>& buffered,
DistanceStrategy const& distance_strategy,
JoinStrategy const& join_strategy
, int option
)
{
typedef typename ring_type<GeometryOut>::type ring_type;
typedef detail::buffer::intersecting_inserter
<
std::vector<GeometryOut>
> inserter_type;
inserter_type inserter(buffered);
detail::buffer::linestring_buffer
<
Geometry, GeometryOut, DistanceStrategy, JoinStrategy
>::apply(geometry, inserter, distance_strategy, join_strategy);
if (option == 0)
{
return;
}
std::vector<ring_type> rings;
BOOST_FOREACH(GeometryOut const& polygon, buffered)
{
//std::cout << geometry::wkt(polygon) << " ; POLYGON" << std::endl;
geometry::split_rings(polygon, rings);
}
if (option == 1)
{
buffered.resize(rings.size());
int i = 0;
BOOST_FOREACH(ring_type const& ring, rings)
{
exterior_ring(buffered[i++]) = ring;
}
return;
}
std::vector<GeometryOut> buffered_and_unioned;
geometry::dissolver(rings, buffered_and_unioned);
std::vector<GeometryOut> buffered_and_assembled;
detail::overlay::assemble<GeometryOut>(buffered_and_unioned,
std::map<ring_identifier, int>(),
buffered_and_unioned[0], buffered_and_unioned[0], 1, true, true,
std::back_inserter(buffered_and_assembled));
buffered = buffered_and_assembled;
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SPLITTING_BUFFER_HPP

View File

@@ -1,89 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 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_ALGORITHMS_DETAIL_BUFFER_TRAVERSING_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TRAVERSING_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/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/extensions/algorithms/buffer/intersecting_inserter.hpp>
#include <boost/geometry/extensions/algorithms/buffer/linestring_buffer.hpp>
#include <boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp>
#include <boost/geometry/extensions/algorithms/dissolve.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename GeometryOut, typename Geometry,
typename DistanceStrategy,
typename JoinStrategy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
>
inline void traversing_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
)
{
typedef typename ring_type<GeometryOut>::type ring_type;
typedef detail::buffer::intersecting_inserter
<
std::vector<GeometryOut>
> inserter_type;
inserter_type inserter(buffered);
detail::buffer::linestring_buffer
<
Geometry, GeometryOut, DistanceStrategy, JoinStrategy
>::apply(geometry, inserter, distance_strategy, join_strategy);
std::vector<GeometryOut> buffered_and_assembled;
detail::overlay::assemble<GeometryOut>(buffered,
std::map<ring_identifier, int>(),
buffered[0], buffered[0], 1, true, true,
std::back_inserter(buffered_and_assembled));
buffered = buffered_and_assembled;
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TRAVERSING_BUFFER_HPP

View File

@@ -59,65 +59,25 @@ namespace strategy { namespace buffer
*/
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
template
<
typename PointIn, typename Mapper
>
struct join_mapper
{
Mapper const& m_mapper;
join_mapper(Mapper const& mapper)
: m_mapper(mapper)
{}
template <typename BufferAppender>
inline void map(PointIn const& ip, PointIn const& vertex,
PointIn const& perp1, PointIn const& perp2) const
{
typename BufferAppender::range_type corner;
corner.push_back(vertex);
corner.push_back(perp1);
corner.push_back(ip);
corner.push_back(perp2);
corner.push_back(vertex);
const_cast<Mapper&>(m_mapper).map(corner,
"opacity:0.4;fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1");
}
};
#endif
// TODO: merge join_miter with join_round, lot of duplicate code
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
// Forget this, it will go
template<typename PointIn, typename PointOut, bool AddHooklets, typename Mapper>
struct join_miter : public join_mapper<PointIn, Mapper>
{
join_miter(Mapper const& mapper) : join_mapper(mapper) {}
#else
template
<
typename PointIn,
typename PointOut,
bool AddHooklets = true
typename PointOut
>
struct join_miter
{
#endif
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
typedef typename coordinate_type<PointIn>::type coordinate_type;
template <typename BufferAppender>
template <typename RangeOut>
inline void apply(PointIn const& ip, PointIn const& vertex,
PointIn const& perp1, PointIn const& perp2,
coordinate_type const& buffer_distance,
BufferAppender& appender) const
RangeOut& range_out) const
{
coordinate_type zero = 0;
int signum = buffer_distance > zero ? 1
@@ -126,15 +86,6 @@ struct join_miter
if (side::apply(perp1, ip, perp2) == signum)
{
if (AddHooklets)
{
appender.append_begin_hooklet(perp1);
appender.append_end_hooklet(perp2);
}
else
{
appender.append(ip);
}
}
else
{
@@ -165,26 +116,15 @@ struct join_miter
#endif
}
appender.append_begin_join(p);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
map<BufferAppender>(ip, vertex, perp1, perp2);
#endif
range_out.push_back(perp1);
range_out.push_back(p);
range_out.push_back(perp2);
}
}
};
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
// Forget this, it will go
template<typename PointIn, typename PointOut, typename Mapper>
struct join_bevel : public join_mapper<PointIn, Mapper>
{
join_bevel(Mapper const& mapper) : join_mapper(mapper) {}
#else
template
<
typename PointIn,
@@ -192,62 +132,39 @@ template
>
struct join_bevel
{
#endif
typedef typename coordinate_type<PointIn>::type coordinate_type;
template <typename BufferAppender>
template <typename RangeOut>
inline void apply(PointIn const& ip, PointIn const& vertex,
PointIn const& perp1, PointIn const& perp2,
coordinate_type const& buffer_distance,
BufferAppender& appender) const
RangeOut& range_out) const
{
appender.append(perp1);
appender.append(perp2);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
map<BufferAppender>(ip, vertex, perp1, perp2);
#endif
}
};
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
// Forget this, it will go
template<typename PointIn, typename PointOut, bool AddHooklets, typename Mapper>
struct join_round : public join_mapper<PointIn, Mapper>
{
join_round(Mapper const& mapper, int max_level = 4)
: join_mapper(mapper)
, m_max_level(max_level)
{}
#else
template
<
typename PointIn,
typename PointOut,
bool AddHooklets = true
typename PointOut
>
struct join_round
{
inline join_round(int max_level = 4)
inline join_round(int max_level = 6)
: m_max_level(max_level)
{}
#endif
typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
typedef typename coordinate_type<PointOut>::type coordinate_type;
int m_max_level;
template <typename BufferAppender>
template <typename RangeOut>
inline void mid_points(PointIn const& vertex,
PointIn const& p1, PointIn const& p2,
coordinate_type const& buffer_distance,
BufferAppender& appender,
RangeOut& range_out,
int level = 1) const
{
// Generate 'vectors'
@@ -272,22 +189,22 @@ struct join_round
if (level < m_max_level)
{
mid_points(vertex, p1, mid_point, buffer_distance, appender, level + 1);
mid_points(vertex, p1, mid_point, buffer_distance, range_out, level + 1);
}
appender.append(mid_point);
range_out.push_back(mid_point);
if (level < m_max_level)
{
mid_points(vertex, mid_point, p2, buffer_distance, appender, level + 1);
mid_points(vertex, mid_point, p2, buffer_distance, range_out, level + 1);
}
}
template <typename BufferAppender>
template <typename RangeOut>
inline void apply(PointIn const& ip, PointIn const& vertex,
PointIn const& perp1, PointIn const& perp2,
coordinate_type const& buffer_distance,
BufferAppender& appender) const
RangeOut& range_out) const
{
coordinate_type zero = 0;
int signum = buffer_distance > zero ? 1
@@ -296,16 +213,6 @@ struct join_round
if (side::apply(perp1, ip, perp2) == signum)
{
// If it is concave (corner to left), add helperline
if (AddHooklets)
{
appender.append_begin_hooklet(perp1);
appender.append_end_hooklet(perp2);
}
else
{
appender.append(ip);
}
}
else
{
@@ -323,25 +230,21 @@ struct join_round
set<0>(bp, get<0>(vertex) + vix * prop);
set<1>(bp, get<1>(vertex) + viy * prop);
appender.append_begin_join(perp1);
range_out.push_back(perp1);
if (m_max_level <= 1)
{
if (m_max_level == 1)
{
appender.append(bp);
range_out.push_back(bp);
}
}
else
{
mid_points(vertex, perp1, bp, bd, appender);
appender.append(bp);
mid_points(vertex, bp, perp2, bd, appender);
mid_points(vertex, perp1, bp, bd, range_out);
range_out.push_back(bp);
mid_points(vertex, bp, perp2, bd, range_out);
}
appender.append_end_join(perp2);
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
map<BufferAppender>(bp, vertex, perp1, perp2);
#endif
range_out.push_back(perp2);
}
}
};