From dffa159cd546bfb4b8fac66e0791baa248f3c81a Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 18 Feb 2012 10:07:18 +0000 Subject: [PATCH] Boost.Geometry Substantial progress on buffer [SVN r77061] --- .../algorithms/buffer/buffer_appender.hpp | 46 +- .../algorithms/buffer/buffer_inserter.hpp | 324 +++++++++ .../buffer/buffered_piece_collection.hpp | 657 ++++++++++++++++++ .../algorithms/buffer/buffered_ring.hpp | 260 +++++++ .../algorithms/buffer/linestring_buffer.hpp | 100 --- .../algorithms/buffer/polygon_buffer.hpp | 159 ----- .../algorithms/buffer/range_buffer.hpp | 199 ------ .../buffer/sectionalizing_buffer.hpp | 167 ----- .../algorithms/buffer/segmenting_buffer.hpp | 350 ---------- .../algorithms/buffer/splitting_buffer.hpp | 116 ---- .../algorithms/buffer/traversing_buffer.hpp | 89 --- .../geometry/extensions/strategies/buffer.hpp | 143 +--- 12 files changed, 1265 insertions(+), 1345 deletions(-) create mode 100644 include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp create mode 100644 include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp create mode 100644 include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp delete mode 100644 include/boost/geometry/extensions/algorithms/buffer/linestring_buffer.hpp delete mode 100644 include/boost/geometry/extensions/algorithms/buffer/polygon_buffer.hpp delete mode 100644 include/boost/geometry/extensions/algorithms/buffer/range_buffer.hpp delete mode 100644 include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp delete mode 100644 include/boost/geometry/extensions/algorithms/buffer/segmenting_buffer.hpp delete mode 100644 include/boost/geometry/extensions/algorithms/buffer/splitting_buffer.hpp delete mode 100644 include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp index 977ca9d49..67a0aad73 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_appender.hpp @@ -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 class buffer_appender { public : typedef Range range_type; typedef typename geometry::point_type::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(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(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(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(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(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(m_mapper).map(is.intersections[0], "fill:rgb(255,0,255);", 4); - const_cast(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(m_mapper).map(is.intersections[0], "fill:rgb(255,255,0);", 4); - const_cast(m_mapper).map(m_range[the_piece.begin], "fill:rgb(255,192,0);", 4); - const_cast(m_mapper).map(split_off, "fill:none;stroke:rgb(255,192,0);stroke-width:2"); -#endif return true; } diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp new file mode 100644 index 000000000..4b25e72da --- /dev/null +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp @@ -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 + +#include + +#include +#include + +#include +#include + +#include +#include +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + + +template +< + typename RingOutput, + typename Tag +> +struct buffer_range +{ + typedef typename point_type::type output_point_type; + typedef typename coordinate_type::type coordinate_type; + typedef model::referring_segment 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 range_out; + if (! first) + { + output_point_type p; + segment_type s1(p1, p2); + segment_type s2(previous_p1, previous_p2); + + if (line_line_intersection::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::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::apply(s1, s2, p); + + std::vector 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 + : 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 + : public detail::buffer::buffer_range + < + typename ring_type::type, + linestring_tag + > +{ + + template + 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 +{ + + template + static inline void apply(PolygonInput const& polygon, Collection& collection, + DistanceStrategy const& distance, + JoinStrategy const& join_strategy) + { + + typedef typename ring_type::type input_ring_type; + typedef typename ring_type::type output_ring_type; + + typedef buffer_inserter policy; + + { + collection.add_input(); + + policy::apply(exterior_ring(polygon), collection, + distance, join_strategy); + } + + typename interior_return_type::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::type> collection; + + dispatch::buffer_inserter + < + typename tag::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(mapper); + collection.map_turns(mapper); + collection.map_traverse(mapper); +#endif + + collection.assign(out); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp new file mode 100644 index 000000000..e54b93f62 --- /dev/null +++ b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp @@ -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 + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + + + + +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 + static inline void apply(std::size_t size_at_start, + Rings& rings, typename boost::range_value::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 +struct buffer_turn_operation : public detail::overlay::traversal_turn_operation +{ + 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 +struct buffer_turn_info : public detail::overlay::turn_info > +{ + intersection_location_type location; + + inline buffer_turn_info() + : location(location_ok) + {} +}; + + +template +struct buffered_piece_collection +{ + typedef typename geometry::point_type::type Point; + typedef typename strategy::side::services::default_strategy::type>::type side; + + enum piece_type + { + buffered_segment, buffered_join + }; + + template + 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 buffered_vector_type; + + buffered_vector_type offseted_segment; + }; + + typedef std::vector piece_vector; + piece_vector all_pieces; + buffered_ring_collection > offsetted_rings; + buffered_ring_collection traversed_rings; + segment_identifier current_segment_id; + + typedef std::vector > turn_vector_type; + typedef detail::overlay::get_turn_info + < + Point, Point, buffer_turn_info, + detail::overlay::calculate_distance_policy + > turn_policy; + turn_vector_type turn_vector; + + + + inline buffered_piece_collection() + {} + + + inline bool within_piece(buffer_turn_info 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 const& turn, piece const& piece1, piece const& piece2) const + { + // We might do this using partition. + typename std::vector::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 + 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 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::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::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 + 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::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 + 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::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 + 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::type + >::type side_strategy_type; + + enrich_intersection_points(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::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 >()), + boost::end(turn_vector)); + + } + + inline void traverse() + { + typedef detail::overlay::traverse + < + false, false, + buffered_ring_collection >, buffered_ring_collection >, + backtrack_for_buffer + > traverser; + + traversed_rings.clear(); + traverser::apply(offsetted_rings, offsetted_rings, + detail::overlay::operation_union, + turn_vector, traversed_rings); + } + + template + inline OutputIterator assign(OutputIterator out) + { + typedef detail::overlay::ring_properties properties; + + std::map selected; + + // Select all rings which do not have any self-intersection (other ones should be traversed) + int index = 0; + for(typename buffered_ring_collection >::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 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(selected, offsetted_rings, traversed_rings, out); + } + +#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + + template + inline void map_turns(Mapper& mapper) + { + int index = 0; + for (typename boost::range_iterator::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 + 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 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::value || boost::is_same::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::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 >::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 + inline void map_traverse(Mapper& mapper) + { + for(typename buffered_ring_collection::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 + inline void map_offsetted(Mapper& mapper) + { + for(typename buffered_ring_collection >::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 diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp new file mode 100644 index 000000000..6a9367642 --- /dev/null +++ b/include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp @@ -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 + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +struct buffered_ring_collection_tag : polygonal_tag, multi_tag +{}; + + +template +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 +struct buffered_ring_collection : public std::vector +{ +}; + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + + +// Register the types +namespace traits +{ + + +template +struct tag > +{ + typedef ring_tag type; +}; + + +template +struct point_order > +{ + static const order_selector value = geometry::point_order::value; +}; + + +template +struct closure > +{ + static const closure_selector value = geometry::closure::value; +}; + + +template +struct point_type > +{ + typedef typename geometry::point_type::type type; +}; + +template +struct tag > +{ + typedef detail::buffer::buffered_ring_collection_tag type; +}; + + +} // namespace traits + +namespace core_dispatch +{ + +template +struct ring_type +< + detail::buffer::buffered_ring_collection_tag, + detail::buffer::buffered_ring_collection +> +{ + 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::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::type, + Reverse, + SegmentIdentifier, + RangeOut + > + > +{}; + + + +template +struct within +< + Point, + MultiGeometry, + point_tag, + detail::buffer::buffered_ring_collection_tag +> +{ + template + 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::type, + //iterate_forward, + //closed, + order_as_direction + < + geometry::point_order::value + >::value, + geometry::closure::value, + Strategy + > + >::apply(point, multi, strategy) == 1; + } +}; + + +} // namespace dispatch + +namespace detail { namespace overlay +{ + +template<> +struct get_ring +{ + template + static inline typename ring_type::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::apply(id, multi_ring[id.multi_index]); + } +}; + +}} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING diff --git a/include/boost/geometry/extensions/algorithms/buffer/linestring_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/linestring_buffer.hpp deleted file mode 100644 index db52bfaea..000000000 --- a/include/boost/geometry/extensions/algorithms/buffer/linestring_buffer.hpp +++ /dev/null @@ -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 - -#include - -#include - -#include - -#include -#include - - -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::type, - DistanceStrategy, - JoinStrategy, - linestring_tag - > -{ - -#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER - template -#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::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 diff --git a/include/boost/geometry/extensions/algorithms/buffer/polygon_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/polygon_buffer.hpp deleted file mode 100644 index 1ef7df08a..000000000 --- a/include/boost/geometry/extensions/algorithms/buffer/polygon_buffer.hpp +++ /dev/null @@ -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 - -#include - -#include -#include - -#include -#include - -#include -#include -#include - - -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 -#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::type input_ring_type; - typedef typename ring_type::type output_ring_type; - - typedef buffer_appender - < - output_ring_type -#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER - , Mapper -#endif - > appender_type; - - typedef ring_buffer 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::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 diff --git a/include/boost/geometry/extensions/algorithms/buffer/range_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/range_buffer.hpp deleted file mode 100644 index b9c358f6d..000000000 --- a/include/boost/geometry/extensions/algorithms/buffer/range_buffer.hpp +++ /dev/null @@ -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 - -#include - -#include -#include - -#include - -#include - -#include - - -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::type output_point_type; - typedef typename coordinate_type::type coordinate_type; - typedef model::referring_segment 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::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::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::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::value) - { - appender.append(previous_p2); - } - else if(boost::is_same::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::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 diff --git a/include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp deleted file mode 100644 index 7e7d3a5e1..000000000 --- a/include/boost/geometry/extensions/algorithms/buffer/sectionalizing_buffer.hpp +++ /dev/null @@ -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 - -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include - - - -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& buffered, - DistanceStrategy const& distance_strategy, - JoinStrategy const& join_strategy -#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER - , Mapper& mapper -#endif - ) -{ - typedef typename point_type::type point_type; - typedef geometry::box box_type; - typedef geometry::sections sections_type; - typedef typename geometry::ring_type::type ring_type; - - // TEMPORARY - typedef intersecting_inserter - < - std::vector - > inserter_type; - - - sections_type sections; - geometry::sectionalize(geometry, sections); - - - - // Buffer all sections separately, and put them in a temporary vector - std::vector 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::type const - >::type iterator_type; - - - inserter_type inserter(buffered_sections); - - iterator_type begin, end; - typedef std::pair 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 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(geometry, p, std::back_inserter(buffered)); - } - else if (boost::size(buffered) == 1) - { - std::vector unioned; - geometry::union_inserter(buffered.front(), p, std::back_inserter(unioned)); - buffered.swap(unioned); - } - else - { - std::cerr << " D " << buffered.size(); - /*std::vector 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 diff --git a/include/boost/geometry/extensions/algorithms/buffer/segmenting_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/segmenting_buffer.hpp deleted file mode 100644 index 7b99a749e..000000000 --- a/include/boost/geometry/extensions/algorithms/buffer/segmenting_buffer.hpp +++ /dev/null @@ -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 -#include - -#include -#include - -#include - -#include -#include - -#include -#include -#include - -#include - - -#include - - -// TEMPORARY do not use yet. - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace buffer -{ - - -template -inline bool calculate_parallels(Point const& point1, Point const& point2, - PointOut& p1, PointOut& p2, DistanceType const& distance) -{ - typedef typename coordinate_type::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::type input_point_type; - typedef typename point_type::type point_type; - typedef typename coordinate_type::type coordinate_type; - typedef coordinate_type distance_type; // TODO promote to FP - typedef model::segment segment_type; - typedef typename geometry::ring_type::type ring_type; - typedef typename strategy::side::services::default_strategy::type>::type side; - - typedef typename boost::range_iterator::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& 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 buffered_pieces; - - bool first = true; - - strategy::buffer::join_round2 new_join; - //strategy::buffer::join_none 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 unioned; - geometry::union_inserter(buffered.front(), p, std::back_inserter(unioned)); - buffered.swap(unioned); - } - else - { - std::cerr << " D " << buffered.size(); - /*std::vector dissolved; - dissolved.push_back(p); - geometry::dissolver(buffered, dissolved); - dissolved.swap(buffered);*/ - } - } - - /*** - std::vector 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& 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 diff --git a/include/boost/geometry/extensions/algorithms/buffer/splitting_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/splitting_buffer.hpp deleted file mode 100644 index 9514b22b2..000000000 --- a/include/boost/geometry/extensions/algorithms/buffer/splitting_buffer.hpp +++ /dev/null @@ -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 - -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - - -#include -#include - - - -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& buffered, - DistanceStrategy const& distance_strategy, - JoinStrategy const& join_strategy - - , int option - ) -{ - typedef typename ring_type::type ring_type; - typedef detail::buffer::intersecting_inserter - < - std::vector - > 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 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 buffered_and_unioned; - geometry::dissolver(rings, buffered_and_unioned); - - std::vector buffered_and_assembled; - detail::overlay::assemble(buffered_and_unioned, - std::map(), - 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 diff --git a/include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp b/include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp deleted file mode 100644 index b64129c29..000000000 --- a/include/boost/geometry/extensions/algorithms/buffer/traversing_buffer.hpp +++ /dev/null @@ -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 - -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - - -#include - - - -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& buffered, - DistanceStrategy const& distance_strategy, - JoinStrategy const& join_strategy -#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER - , Mapper& mapper -#endif - ) -{ - typedef typename ring_type::type ring_type; - typedef detail::buffer::intersecting_inserter - < - std::vector - > inserter_type; - - - inserter_type inserter(buffered); - - detail::buffer::linestring_buffer - < - Geometry, GeometryOut, DistanceStrategy, JoinStrategy - >::apply(geometry, inserter, distance_strategy, join_strategy); - - std::vector buffered_and_assembled; - detail::overlay::assemble(buffered, - std::map(), - 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 diff --git a/include/boost/geometry/extensions/strategies/buffer.hpp b/include/boost/geometry/extensions/strategies/buffer.hpp index 455110369..5c8a67804 100644 --- a/include/boost/geometry/extensions/strategies/buffer.hpp +++ b/include/boost/geometry/extensions/strategies/buffer.hpp @@ -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 - 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(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 -struct join_miter : public join_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::type>::type side; typedef typename coordinate_type::type coordinate_type; - template + template 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(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 -struct join_bevel : public join_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::type coordinate_type; - template + template 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(ip, vertex, perp1, perp2); -#endif } }; -#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER -// Forget this, it will go -template -struct join_round : public join_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::type>::type side; typedef typename coordinate_type::type coordinate_type; int m_max_level; - template + template 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 + template 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(bp, vertex, perp1, perp2); -#endif + range_out.push_back(perp2); } } };