summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp')
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp954
1 files changed, 954 insertions, 0 deletions
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
new file mode 100644
index 0000000000..558a61fcb4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -0,0 +1,954 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
+
+#include <algorithm>
+#include <cstddef>
+#include <set>
+#include <boost/range.hpp>
+
+
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+
+#include <boost/geometry/strategies/buffer.hpp>
+
+#include <boost/geometry/geometries/ring.hpp>
+#include <boost/geometry/geometries/polygon.hpp>
+
+#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
+#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
+#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
+#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
+#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/occupation_info.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+enum segment_relation_code
+{
+ segment_relation_on_left,
+ segment_relation_on_right,
+ segment_relation_within,
+ segment_relation_disjoint
+};
+
+/*
+ * Terminology
+ *
+ * Suppose we make a buffer (using blocked corners) of this rectangle:
+ *
+ * +-------+
+ * | |
+ * | rect |
+ * | |
+ * +-------+
+ *
+ * For the sides we get these four buffered side-pieces (marked with s)
+ * and four buffered corner pieces (marked with c)
+ *
+ * c---+---s---+---c
+ * | | piece | | <- see below for details of the middle top-side-piece
+ * +---+-------+---+
+ * | | | |
+ * s | rect | s <- two side pieces left/right of rect
+ * | | | |
+ * +---+-------+---+
+ * | | piece | | <- one side-piece below, and two corner pieces
+ * c---+---s---+---c
+ *
+ * The outer part of the picture above, using all pieces,
+ * form together the offsetted ring (marked with o below)
+ * The 8 pieces are part of the piece collection and use for inside-checks
+ * The inner parts form (using 1 or 2 points per piece, often co-located)
+ * form together the robust_ring (marked with r below)
+ * The remaining piece-segments are helper-segments (marked with h)
+ *
+ * ooooooooooooooooo
+ * o h h o
+ * ohhhrrrrrrrrrhhho
+ * o r r o
+ * o r r o
+ * o r r o
+ * ohhhrrrrrrrrrhhho
+ * o h h o
+ * ooooooooooooooooo
+ *
+ */
+
+
+template <typename Ring, typename RobustPolicy>
+struct buffered_piece_collection
+{
+ typedef buffered_piece_collection<Ring, RobustPolicy> this_type;
+
+ typedef typename geometry::point_type<Ring>::type point_type;
+ typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
+ typedef typename geometry::robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // Robust ring/polygon type, always clockwise
+ typedef geometry::model::ring<robust_point_type> robust_ring_type;
+ typedef geometry::model::polygon<robust_point_type> robust_polygon_type;
+
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<point_type>::type
+ >::type side_strategy;
+
+ typedef typename geometry::rescale_policy_type
+ <
+ typename geometry::point_type<Ring>::type
+ >::type rescale_policy_type;
+
+ typedef typename geometry::segment_ratio_type
+ <
+ point_type,
+ RobustPolicy
+ >::type segment_ratio_type;
+
+ typedef buffer_turn_info
+ <
+ point_type,
+ robust_point_type,
+ segment_ratio_type
+ > buffer_turn_info_type;
+
+ typedef buffer_turn_operation
+ <
+ point_type,
+ segment_ratio_type
+ > buffer_turn_operation_type;
+
+ typedef std::vector<buffer_turn_info_type> turn_vector_type;
+
+ struct robust_turn
+ {
+ int turn_index;
+ int operation_index;
+ robust_point_type point;
+ segment_identifier seg_id;
+ segment_ratio_type fraction;
+ };
+
+ struct piece
+ {
+ strategy::buffer::piece_type type;
+ int index;
+
+ int left_index; // points to previous piece of same ring
+ int right_index; // points to next piece of same ring
+
+ // The next two members (1, 2) form together a complete clockwise ring
+ // for each piece (with one dupped point)
+ // The complete clockwise ring is also included as a robust ring (3)
+
+ // 1: half, part of offsetted_rings
+ segment_identifier first_seg_id;
+ int last_segment_index; // no segment-identifier - it is the same as first_seg_id
+ int offsetted_count; // part in robust_ring which is part of offsetted ring
+
+#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
+ // 2: half, not part of offsetted rings - part of robust ring
+ std::vector<point_type> helper_points; // 4 points for segment, 3 points for join - 0 points for flat-end
+#endif
+
+ // Robust representations
+ // 3: complete ring
+ robust_ring_type robust_ring;
+
+ geometry::model::box<robust_point_type> robust_envelope;
+
+ std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead
+ };
+
+ typedef std::vector<piece> piece_vector_type;
+
+ piece_vector_type m_pieces;
+ turn_vector_type m_turns;
+ int m_first_piece_index;
+
+ buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
+ buffered_ring_collection<robust_polygon_type> robust_polygons; // robust representation of the original(s)
+ robust_ring_type current_robust_ring;
+ buffered_ring_collection<Ring> traversed_rings;
+ segment_identifier current_segment_id;
+
+ RobustPolicy const& m_robust_policy;
+
+ struct redundant_turn
+ {
+ inline bool operator()(buffer_turn_info_type const& turn) const
+ {
+ return turn.remove_on_multi;
+ }
+ };
+
+ buffered_piece_collection(RobustPolicy const& robust_policy)
+ : m_first_piece_index(-1)
+ , m_robust_policy(robust_policy)
+ {}
+
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // Will (most probably) be removed later
+ template <typename OccupationMap>
+ inline void adapt_mapped_robust_point(OccupationMap const& map,
+ buffer_turn_info_type& turn, int distance) const
+ {
+ for (int x = -distance; x <= distance; x++)
+ {
+ for (int y = -distance; y <= distance; y++)
+ {
+ robust_point_type rp = turn.robust_point;
+ geometry::set<0>(rp, geometry::get<0>(rp) + x);
+ geometry::set<1>(rp, geometry::get<1>(rp) + y);
+ if (map.find(rp) != map.end())
+ {
+ turn.mapped_robust_point = rp;
+ return;
+ }
+ }
+ }
+ }
+#endif
+
+ inline void get_occupation(
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ int distance = 0
+#endif
+ )
+ {
+ typedef occupation_info<angle_info<robust_point_type, coordinate_type> >
+ buffer_occupation_info;
+
+ typedef std::map
+ <
+ robust_point_type,
+ buffer_occupation_info,
+ geometry::less<robust_point_type>
+ > occupation_map_type;
+
+ occupation_map_type occupation_map;
+
+ // 1: Add all intersection points to occupation map
+ typedef typename boost::range_iterator<turn_vector_type>::type
+ iterator_type;
+
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ if (it->location == location_ok)
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ if (distance > 0 && ! occupation_map.empty())
+ {
+ adapt_mapped_robust_point(occupation_map, *it, distance);
+ }
+#endif
+ occupation_map[it->get_robust_point()].count++;
+ }
+ }
+
+ // Remove all points with one or more u/u points from the map
+ // (Alternatively, we could NOT do this here and change all u/u
+ // behaviour in overlay. Currently nothing is done: each polygon is
+ // just followed there. We could also always switch polygons there. For
+ // buffer behaviour, where 3 pieces might meet of which 2 (or more) form
+ // a u/u turn, this last option would have been better, probably).
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ if (it->both(detail::overlay::operation_union))
+ {
+ typename occupation_map_type::iterator mit =
+ occupation_map.find(it->get_robust_point());
+
+ if (mit != occupation_map.end())
+ {
+ occupation_map.erase(mit);
+ }
+ }
+ }
+
+ // 2: Remove all points from map which has only one
+ typename occupation_map_type::iterator it = occupation_map.begin();
+ while (it != occupation_map.end())
+ {
+ if (it->second.count <= 1)
+ {
+ typename occupation_map_type::iterator to_erase = it;
+ ++it;
+ occupation_map.erase(to_erase);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ if (occupation_map.empty())
+ {
+ return;
+ }
+
+ // 3: Add vectors (incoming->intersection-point,
+ // intersection-point -> outgoing)
+ // for all (co-located) points still present in the map
+
+ for (iterator_type it = boost::begin(m_turns);
+ it != boost::end(m_turns);
+ ++it)
+ {
+ typename occupation_map_type::iterator mit =
+ occupation_map.find(it->get_robust_point());
+
+ if (mit != occupation_map.end())
+ {
+ buffer_occupation_info& info = mit->second;
+ for (int i = 0; i < 2; i++)
+ {
+ add_incoming_and_outgoing_angles(it->get_robust_point(), *it,
+ m_pieces,
+ i, it->operations[i].seg_id,
+ info);
+ }
+
+ it->count_on_multi++;
+ }
+ }
+
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ // X: Check rounding issues
+ if (distance == 0)
+ {
+ for (typename occupation_map_type::const_iterator it = occupation_map.begin();
+ it != occupation_map.end(); ++it)
+ {
+ if (it->second.has_rounding_issues(it->first))
+ {
+ if(distance == 0)
+ {
+ get_occupation(distance + 1);
+ return;
+ }
+ }
+ }
+ }
+#endif
+
+ // Get left turns from all clusters
+ for (typename occupation_map_type::iterator it = occupation_map.begin();
+ it != occupation_map.end(); ++it)
+ {
+ it->second.get_left_turns(it->first, m_turns);
+ }
+ }
+
+ inline void classify_turns()
+ {
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->count_within > 0)
+ {
+ it->location = inside_buffer;
+ }
+ if (it->count_within_near_offsetted > 0)
+ {
+ // Within can have in rare cases a rounding issue. We don't discard this
+ // point, so it can be used to continue started rings in traversal. But
+ // will never start a new ring from this type of points.
+ it->selectable_start = false;
+ }
+
+ }
+ }
+
+ inline void check_remaining_points(int factor)
+ {
+ // TODO: use partition
+
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location == location_ok)
+ {
+ int code = -1;
+ for (std::size_t i = 0; i < robust_polygons.size(); i++)
+ {
+ if (geometry::covered_by(it->robust_point, robust_polygons[i]))
+ {
+ code = 1;
+ break;
+ }
+ }
+ if (code * factor == 1)
+ {
+ it->location = inside_original;
+ }
+ }
+ }
+ }
+
+ inline bool assert_indices_in_robust_rings() const
+ {
+ geometry::equal_to<robust_point_type> comparator;
+ for (typename boost::range_iterator<turn_vector_type const>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ robust_point_type const &p1
+ = m_pieces[it->operations[i].piece_index].robust_ring
+ [it->operations[i].index_in_robust_ring];
+ robust_point_type const &p2 = it->robust_point;
+ if (! comparator(p1, p2))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ inline void insert_rescaled_piece_turns()
+ {
+ // Add rescaled turn points to corresponding pieces
+ // (after this, each turn occurs twice)
+ int index = 0;
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
+ {
+ geometry::recalculate(it->robust_point, it->point, m_robust_policy);
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ it->mapped_robust_point = it->robust_point;
+#endif
+
+ robust_turn turn;
+ it->turn_index = index;
+ turn.turn_index = index;
+ turn.point = it->robust_point;
+ for (int i = 0; i < 2; i++)
+ {
+ turn.operation_index = i;
+ turn.seg_id = it->operations[i].seg_id;
+ turn.fraction = it->operations[i].fraction;
+
+ piece& pc = m_pieces[it->operations[i].piece_index];
+ pc.robust_turns.push_back(turn);
+
+ // Take into account for the box (intersection points should fall inside,
+ // but in theory they can be one off because of rounding
+ geometry::expand(pc.robust_envelope, it->robust_point);
+ }
+ }
+
+ // Insert all rescaled turn-points into these rings, to form a
+ // reliable integer-based ring. All turns can be compared (inside) to this
+ // rings to see if they are inside.
+
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ piece& pc = *it;
+ int piece_segment_index = pc.first_seg_id.segment_index;
+ if (! pc.robust_turns.empty())
+ {
+ if (pc.robust_turns.size() > 1u)
+ {
+ std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
+ }
+ // Walk through them, in reverse to insert at right index
+ int index_offset = pc.robust_turns.size() - 1;
+ for (typename std::vector<robust_turn>::const_reverse_iterator
+ rit = pc.robust_turns.rbegin();
+ rit != pc.robust_turns.rend();
+ ++rit, --index_offset)
+ {
+ int const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
+ BOOST_ASSERT
+ (
+ index_in_vector > 0 && index_in_vector < pc.offsetted_count
+ );
+
+ pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
+ pc.offsetted_count++;
+
+ m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
+ }
+ }
+ }
+
+ BOOST_ASSERT(assert_indices_in_robust_rings());
+ }
+
+ inline void get_turns()
+ {
+ {
+ // Calculate the turns
+ piece_turn_visitor
+ <
+ buffered_ring_collection<buffered_ring<Ring> >,
+ turn_vector_type,
+ RobustPolicy
+ > visitor(offsetted_rings, m_turns, m_robust_policy);
+
+ geometry::partition
+ <
+ model::box<robust_point_type>, piece_get_box, piece_ovelaps_box
+ >::apply(m_pieces, visitor);
+ }
+
+ insert_rescaled_piece_turns();
+
+ {
+ // Check if it is inside any of the pieces
+ turn_in_piece_visitor
+ <
+ turn_vector_type, piece_vector_type
+ > visitor(m_turns, m_pieces);
+
+ geometry::partition
+ <
+ model::box<robust_point_type>,
+ turn_get_box, turn_ovelaps_box,
+ piece_get_box, piece_ovelaps_box
+ >::apply(m_turns, m_pieces, visitor);
+
+ }
+
+ classify_turns();
+
+ //get_occupation();
+ }
+
+ inline void start_new_ring()
+ {
+ 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);
+ current_robust_ring.clear();
+
+ m_first_piece_index = boost::size(m_pieces);
+ }
+
+ inline void finish_ring(bool is_interior = false)
+ {
+ if (m_first_piece_index == -1)
+ {
+ return;
+ }
+
+ if (m_first_piece_index < static_cast<int>(boost::size(m_pieces)))
+ {
+ // If piece was added
+ // Reassign left-of-first and right-of-last
+ geometry::range::at(m_pieces, m_first_piece_index).left_index
+ = boost::size(m_pieces) - 1;
+ geometry::range::back(m_pieces).right_index = m_first_piece_index;
+ }
+ m_first_piece_index = -1;
+
+ if (!current_robust_ring.empty())
+ {
+ BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back()));
+
+ if (is_interior)
+ {
+ if (!robust_polygons.empty())
+ {
+ robust_polygons.back().inners().push_back(current_robust_ring);
+ }
+ }
+ else
+ {
+ robust_polygons.resize(robust_polygons.size() + 1);
+ robust_polygons.back().outer() = current_robust_ring;
+ }
+ }
+ }
+
+ inline int add_point(point_type const& p)
+ {
+ BOOST_ASSERT
+ (
+ boost::size(offsetted_rings) > 0
+ );
+
+ current_segment_id.segment_index++;
+ offsetted_rings.back().push_back(p);
+ return offsetted_rings.back().size();
+ }
+
+ //-------------------------------------------------------------------------
+
+ inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one)
+ {
+ piece pc;
+ pc.type = type;
+ pc.index = boost::size(m_pieces);
+ pc.first_seg_id = current_segment_id;
+
+ // Assign left/right (for first/last piece per ring they will be re-assigned later)
+ pc.left_index = pc.index - 1;
+ pc.right_index = pc.index + 1;
+
+ std::size_t const n = boost::size(offsetted_rings.back());
+ pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
+
+ m_pieces.push_back(pc);
+ return m_pieces.back();
+ }
+
+ inline void init_rescale_piece(piece& pc, std::size_t helper_points_size)
+ {
+ pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index;
+ BOOST_ASSERT(pc.offsetted_count >= 0);
+
+ pc.robust_ring.reserve(pc.offsetted_count + helper_points_size);
+
+ // Add rescaled offsetted segments
+ {
+ buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index];
+
+ typedef typename boost::range_iterator<const buffered_ring<Ring> >::type it_type;
+ for (it_type it = boost::begin(ring) + pc.first_seg_id.segment_index;
+ it != boost::begin(ring) + pc.last_segment_index;
+ ++it)
+ {
+ robust_point_type point;
+ geometry::recalculate(point, *it, m_robust_policy);
+ pc.robust_ring.push_back(point);
+ }
+ }
+ }
+
+ inline robust_point_type add_helper_point(piece& pc, const point_type& point)
+ {
+#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
+ pc.helper_points.push_back(point);
+#endif
+
+ robust_point_type rob_point;
+ geometry::recalculate(rob_point, point, m_robust_policy);
+ pc.robust_ring.push_back(rob_point);
+ return rob_point;
+ }
+
+ inline void calculate_robust_envelope(piece& pc)
+ {
+ geometry::detail::envelope::envelope_range::apply(pc.robust_ring,
+ pc.robust_envelope);
+ }
+
+ inline void finish_piece(piece& pc)
+ {
+ init_rescale_piece(pc, 0u);
+ calculate_robust_envelope(pc);
+ }
+
+ inline void finish_piece(piece& pc,
+ const point_type& point1,
+ const point_type& point2,
+ const point_type& point3)
+ {
+ init_rescale_piece(pc, 3u);
+ add_helper_point(pc, point1);
+ robust_point_type mid_point = add_helper_point(pc, point2);
+ add_helper_point(pc, point3);
+ calculate_robust_envelope(pc);
+
+ current_robust_ring.push_back(mid_point);
+ }
+
+ inline void finish_piece(piece& pc,
+ const point_type& point1,
+ const point_type& point2,
+ const point_type& point3,
+ const point_type& point4)
+ {
+ init_rescale_piece(pc, 4u);
+ add_helper_point(pc, point1);
+ robust_point_type mid_point2 = add_helper_point(pc, point2);
+ robust_point_type mid_point1 = add_helper_point(pc, point3);
+ add_helper_point(pc, point4);
+ calculate_robust_envelope(pc);
+
+ // Add mid-points in other order to current helper_ring
+ current_robust_ring.push_back(mid_point1);
+ current_robust_ring.push_back(mid_point2);
+ }
+
+ inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
+ point_type const& b1, point_type const& b2)
+ {
+ piece& pc = create_piece(type, false);
+ add_point(b1);
+ pc.last_segment_index = add_point(b2);
+ finish_piece(pc, b2, p, b1);
+ }
+
+ template <typename Range>
+ inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
+ {
+ if (boost::size(range) == 0u)
+ {
+ return;
+ }
+
+ typename Range::const_iterator it = boost::begin(range);
+
+ // If it follows a non-join (so basically the same piece-type) point b1 should be added.
+ // There should be two intersections later and it should be discarded.
+ // But for now we need it to calculate intersections
+ if (add_front)
+ {
+ add_point(*it);
+ }
+
+ for (++it; it != boost::end(range); ++it)
+ {
+ pc.last_segment_index = add_point(*it);
+ }
+ }
+
+
+ template <typename Range>
+ inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one)
+ {
+ piece& pc = create_piece(type, decrease_segment_index_by_one);
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ finish_piece(pc);
+ }
+
+ template <typename Range>
+ inline void add_side_piece(point_type const& p1, point_type const& p2,
+ Range const& range, bool first)
+ {
+ BOOST_ASSERT(boost::size(range) >= 2u);
+
+ piece& pc = create_piece(strategy::buffer::buffered_segment, ! first);
+ add_range_to_piece(pc, range, first);
+ finish_piece(pc, range.back(), p2, p1, range.front());
+ }
+
+ template <typename Range>
+ inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& range)
+ {
+ piece& pc = create_piece(type, true);
+
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ if (boost::size(range) > 0)
+ {
+ finish_piece(pc, range.back(), p, range.front());
+ }
+ else
+ {
+ finish_piece(pc);
+ }
+ }
+
+ template <typename EndcapStrategy, typename Range>
+ inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point)
+ {
+ if (range.empty())
+ {
+ return;
+ }
+ strategy::buffer::piece_type pt = strategy.get_piece_type();
+ if (pt == strategy::buffer::buffered_flat_end)
+ {
+ // It is flat, should just be added, without helper segments
+ add_piece(pt, range, true);
+ }
+ else
+ {
+ // Normal case, it has an "inside", helper segments should be added
+ add_piece(pt, end_point, range);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+
+ inline void enrich()
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Ring>::type
+ >::type side_strategy_type;
+
+ enrich_intersection_points<false, false>(m_turns,
+ detail::overlay::operation_union,
+ offsetted_rings, offsetted_rings,
+ m_robust_policy, 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 discard_rings()
+ {
+ for (typename boost::range_iterator<turn_vector_type const>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++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 if (! it->both(detail::overlay::operation_union))
+ {
+ 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 block_turns()
+ {
+ // To fix left-turn issues like #rt_u13
+ // But currently it causes more other issues than it fixes
+// m_turns.erase
+// (
+// std::remove_if(boost::begin(m_turns), boost::end(m_turns),
+// redundant_turn()),
+// boost::end(m_turns)
+// );
+
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ if (it->location != location_ok)
+ {
+ // Set it to blocked. They should not be discarded, to avoid
+ // generating rings over these turns
+ // Performance goes down a tiny bit from 161 s to 173 because there
+ // are sometimes much more turns.
+ // We might speed it up a bit by keeping only one blocked
+ // intersection per segment, but that is complex to program
+ // because each turn involves two segments
+ it->operations[0].operation = detail::overlay::operation_blocked;
+ it->operations[1].operation = detail::overlay::operation_blocked;
+ }
+ }
+ }
+
+ 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,
+ m_robust_policy, m_turns, traversed_rings);
+ }
+
+ inline void reverse()
+ {
+ for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings);
+ it != boost::end(offsetted_rings);
+ ++it)
+ {
+ if (! it->has_intersections())
+ {
+ std::reverse(it->begin(), it->end());
+ }
+ }
+ for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type
+ it = boost::begin(traversed_rings);
+ it != boost::end(traversed_rings);
+ ++it)
+ {
+ std::reverse(it->begin(), it->end());
+ }
+
+ }
+
+ template <typename GeometryOutput, typename OutputIterator>
+ inline OutputIterator assign(OutputIterator out) const
+ {
+ typedef detail::overlay::ring_properties<point_type> 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, true);
+ return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
+ }
+
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP