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.hpp503
1 files changed, 434 insertions, 69 deletions
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
index 558a61fcb4..a501e3f197 100644
--- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -12,8 +12,9 @@
#include <algorithm>
#include <cstddef>
#include <set>
-#include <boost/range.hpp>
+#include <boost/core/ignore_unused.hpp>
+#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
@@ -24,13 +25,14 @@
#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/buffer/turn_in_original_visitor.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.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>
@@ -41,6 +43,8 @@
#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/algorithms/detail/sections/sectionalize.hpp>
+#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#include <boost/geometry/util/range.hpp>
@@ -89,7 +93,7 @@ enum segment_relation_code
* 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)
+ * form together the robust_polygons (marked with r below)
* The remaining piece-segments are helper-segments (marked with h)
*
* ooooooooooooooooo
@@ -120,7 +124,7 @@ struct buffered_piece_collection
// 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 geometry::model::box<robust_point_type> robust_box_type;
typedef typename strategy::side::services::default_strategy
<
@@ -164,6 +168,9 @@ struct buffered_piece_collection
struct piece
{
+ typedef robust_ring_type piece_robust_ring_type;
+ typedef geometry::section<robust_box_type, 1> section_type;
+
strategy::buffer::piece_type type;
int index;
@@ -181,18 +188,58 @@ struct buffered_piece_collection
#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
+ std::vector<point_type> helper_points; // 4 points for side, 3 points for join - 0 points for flat-end
#endif
+ bool is_monotonic_increasing[2]; // 0=x, 1=y
+ bool is_monotonic_decreasing[2]; // 0=x, 1=y
+
+ // Monotonic sections of pieces around points
+ std::vector<section_type> sections;
+
+
// Robust representations
// 3: complete ring
robust_ring_type robust_ring;
- geometry::model::box<robust_point_type> robust_envelope;
+ robust_box_type robust_envelope;
+ robust_box_type robust_offsetted_envelope;
std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead
};
+ struct robust_original
+ {
+ typedef robust_ring_type original_robust_ring_type;
+ typedef geometry::sections<robust_box_type, 1> sections_type;
+
+ inline robust_original()
+ : m_is_interior(false)
+ , m_has_interiors(true)
+ {}
+
+ inline robust_original(robust_ring_type const& ring,
+ bool is_interior, bool has_interiors)
+ : m_ring(ring)
+ , m_is_interior(is_interior)
+ , m_has_interiors(has_interiors)
+ {
+ geometry::envelope(m_ring, m_box);
+
+ // create monotonic sections in y-dimension
+ typedef boost::mpl::vector_c<std::size_t, 1> dimensions;
+ geometry::sectionalize<false, dimensions>(m_ring,
+ detail::no_rescale_policy(), m_sections);
+ }
+
+ robust_ring_type m_ring;
+ robust_box_type m_box;
+ sections_type m_sections;
+
+ bool m_is_interior;
+ bool m_has_interiors;
+ };
+
typedef std::vector<piece> piece_vector_type;
piece_vector_type m_pieces;
@@ -200,11 +247,17 @@ struct buffered_piece_collection
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)
+ std::vector<robust_original> robust_originals; // robust representation of the original(s)
robust_ring_type current_robust_ring;
buffered_ring_collection<Ring> traversed_rings;
segment_identifier current_segment_id;
+ // Specificly for offsetted rings around points
+ // but also for large joins with many points
+ typedef geometry::sections<robust_box_type, 2> sections_type;
+ sections_type monotonic_sections;
+
+
RobustPolicy const& m_robust_policy;
struct redundant_turn
@@ -378,7 +431,7 @@ struct buffered_piece_collection
}
}
- inline void classify_turns()
+ inline void classify_turns(bool linear)
{
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
@@ -387,6 +440,10 @@ struct buffered_piece_collection
{
it->location = inside_buffer;
}
+ if (it->count_on_original_boundary > 0 && ! linear)
+ {
+ 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
@@ -394,31 +451,40 @@ struct buffered_piece_collection
// will never start a new ring from this type of points.
it->selectable_start = false;
}
-
}
}
- inline void check_remaining_points(int factor)
+ template <typename DistanceStrategy>
+ inline void check_remaining_points(DistanceStrategy const& distance_strategy)
{
- // TODO: use partition
+ // Check if a turn is inside any of the originals
+
+ turn_in_original_visitor<turn_vector_type> visitor(m_turns);
+ geometry::partition
+ <
+ robust_box_type,
+ turn_get_box, turn_in_original_ovelaps_box,
+ original_get_box, original_ovelaps_box,
+ include_turn_policy, detail::partition::include_all_policy
+ >::apply(m_turns, robust_originals, visitor);
+
+ bool const deflate = distance_strategy.negative();
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)
+ buffer_turn_info_type& turn = *it;
+ if (turn.location == location_ok)
{
- int code = -1;
- for (std::size_t i = 0; i < robust_polygons.size(); i++)
+ if (deflate && turn.count_in_original <= 0)
{
- if (geometry::covered_by(it->robust_point, robust_polygons[i]))
- {
- code = 1;
- break;
- }
+ // For deflate: it is not in original, discard
+ turn.location = location_discard;
}
- if (code * factor == 1)
+ else if (! deflate && turn.count_in_original > 0)
{
- it->location = inside_original;
+ // For inflate: it is in original, discard
+ turn.location = location_discard;
}
}
}
@@ -474,6 +540,7 @@ struct buffered_piece_collection
// 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);
+ geometry::expand(pc.robust_offsetted_envelope, it->robust_point);
}
}
@@ -502,9 +569,10 @@ struct buffered_piece_collection
{
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
- );
+ (
+ 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++;
@@ -517,25 +585,132 @@ struct buffered_piece_collection
BOOST_ASSERT(assert_indices_in_robust_rings());
}
+ template <std::size_t Dimension>
+ static inline void determine_monotonicity(piece& pc,
+ robust_point_type const& current,
+ robust_point_type const& next)
+ {
+ if (geometry::get<Dimension>(current) >= geometry::get<Dimension>(next))
+ {
+ pc.is_monotonic_increasing[Dimension] = false;
+ }
+ if (geometry::get<Dimension>(current) <= geometry::get<Dimension>(next))
+ {
+ pc.is_monotonic_decreasing[Dimension] = false;
+ }
+ }
+
+ static inline void determine_properties(piece& pc)
+ {
+ pc.is_monotonic_increasing[0] = true;
+ pc.is_monotonic_increasing[1] = true;
+ pc.is_monotonic_decreasing[0] = true;
+ pc.is_monotonic_decreasing[1] = true;
+
+ if (pc.offsetted_count < 2)
+ {
+ return;
+ }
+
+ typename robust_ring_type::const_iterator current = pc.robust_ring.begin();
+ typename robust_ring_type::const_iterator next = current + 1;
+
+ for (int i = 1; i < pc.offsetted_count; i++)
+ {
+ determine_monotonicity<0>(pc, *current, *next);
+ determine_monotonicity<1>(pc, *current, *next);
+ current = next;
+ ++next;
+ }
+
+ }
+
+ void determine_properties()
+ {
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ determine_properties(*it);
+ }
+ }
+
+ inline void reverse_negative_robust_rings()
+ {
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ piece& pc = *it;
+ if (geometry::area(pc.robust_ring) < 0)
+ {
+ // Rings can be ccw:
+ // - in a concave piece
+ // - in a line-buffer with a negative buffer-distance
+ std::reverse(pc.robust_ring.begin(), pc.robust_ring.end());
+ }
+ }
+ }
+
+ inline void prepare_buffered_point_piece(piece& pc)
+ {
+ // create monotonic sections in y-dimension
+ typedef boost::mpl::vector_c<std::size_t, 1> dimensions;
+ geometry::sectionalize<false, dimensions>(pc.robust_ring,
+ detail::no_rescale_policy(), pc.sections);
+
+ // TODO (next phase) determine min/max radius
+ }
+
+ inline void prepare_buffered_point_pieces()
+ {
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ if (it->type == geometry::strategy::buffer::buffered_point)
+ {
+ prepare_buffered_point_piece(*it);
+ }
+ }
+ }
+
inline void get_turns()
{
+ for(typename boost::range_iterator<sections_type>::type it
+ = boost::begin(monotonic_sections);
+ it != boost::end(monotonic_sections);
+ ++it)
+ {
+ enlarge_box(it->bounding_box, 1);
+ }
+
{
// Calculate the turns
piece_turn_visitor
<
+ piece_vector_type,
buffered_ring_collection<buffered_ring<Ring> >,
turn_vector_type,
RobustPolicy
- > visitor(offsetted_rings, m_turns, m_robust_policy);
+ > visitor(m_pieces, offsetted_rings, m_turns, m_robust_policy);
geometry::partition
<
- model::box<robust_point_type>, piece_get_box, piece_ovelaps_box
- >::apply(m_pieces, visitor);
+ robust_box_type,
+ detail::section::get_section_box,
+ detail::section::overlaps_section_box
+ >::apply(monotonic_sections, visitor);
}
insert_rescaled_piece_turns();
+ reverse_negative_robust_rings();
+
+ determine_properties();
+
+ prepare_buffered_point_pieces();
+
{
// Check if it is inside any of the pieces
turn_in_piece_visitor
@@ -545,16 +720,12 @@ struct buffered_piece_collection
geometry::partition
<
- model::box<robust_point_type>,
+ robust_box_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()
@@ -571,7 +742,38 @@ struct buffered_piece_collection
m_first_piece_index = boost::size(m_pieces);
}
- inline void finish_ring(bool is_interior = false)
+ inline void update_closing_point()
+ {
+ BOOST_ASSERT(! offsetted_rings.empty());
+ buffered_ring<Ring>& added = offsetted_rings.back();
+ if (! boost::empty(added))
+ {
+ range::back(added) = range::front(added);
+ }
+ }
+
+ inline void update_last_point(point_type const& p,
+ buffered_ring<Ring>& ring)
+ {
+ // For the first point of a new piece, and there were already
+ // points in the offsetted ring, for some piece types the first point
+ // is a duplicate of the last point of the previous piece.
+
+ // TODO: disable that, that point should not be added
+
+ // For now, it is made equal because due to numerical instability,
+ // it can be a tiny bit off, possibly causing a self-intersection
+
+ BOOST_ASSERT(boost::size(m_pieces) > 0);
+ if (! ring.empty()
+ && current_segment_id.segment_index
+ == m_pieces.back().first_seg_id.segment_index)
+ {
+ ring.back() = p;
+ }
+ }
+
+ inline void finish_ring(bool is_interior = false, bool has_interiors = false)
{
if (m_first_piece_index == -1)
{
@@ -588,41 +790,50 @@ struct buffered_piece_collection
}
m_first_piece_index = -1;
- if (!current_robust_ring.empty())
+ update_closing_point();
+
+ if (! current_robust_ring.empty())
{
- BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back()));
+ 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;
- }
+ robust_originals.push_back(
+ robust_original(current_robust_ring,
+ is_interior, has_interiors));
}
}
+ inline void set_current_ring_concave()
+ {
+ BOOST_ASSERT(boost::size(offsetted_rings) > 0);
+ offsetted_rings.back().has_concave = true;
+ }
+
inline int add_point(point_type const& p)
{
- BOOST_ASSERT
- (
- boost::size(offsetted_rings) > 0
- );
+ BOOST_ASSERT(boost::size(offsetted_rings) > 0);
+
+ buffered_ring<Ring>& current_ring = offsetted_rings.back();
+ update_last_point(p, current_ring);
current_segment_id.segment_index++;
- offsetted_rings.back().push_back(p);
- return offsetted_rings.back().size();
+ current_ring.push_back(p);
+ return current_ring.size();
}
//-------------------------------------------------------------------------
- inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one)
+ inline piece& create_piece(strategy::buffer::piece_type type,
+ bool decrease_segment_index_by_one)
{
+ if (type == strategy::buffer::buffered_concave)
+ {
+ offsetted_rings.back().has_concave = true;
+ }
+
piece pc;
pc.type = type;
pc.index = boost::size(m_pieces);
@@ -634,6 +845,7 @@ struct buffered_piece_collection
std::size_t const n = boost::size(offsetted_rings.back());
pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
+ pc.last_segment_index = pc.first_seg_id.segment_index;
m_pieces.push_back(pc);
return m_pieces.back();
@@ -641,6 +853,18 @@ struct buffered_piece_collection
inline void init_rescale_piece(piece& pc, std::size_t helper_points_size)
{
+ if (pc.first_seg_id.segment_index < 0)
+ {
+ // This indicates an error situation: an earlier piece was empty
+ // It currently does not happen
+ // std::cout << "EMPTY " << pc.type << " " << pc.index << " " << pc.first_seg_id.multi_index << std::endl;
+ pc.offsetted_count = 0;
+ return;
+ }
+
+ BOOST_ASSERT(pc.first_seg_id.multi_index >= 0);
+ BOOST_ASSERT(pc.last_segment_index >= 0);
+
pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index;
BOOST_ASSERT(pc.offsetted_count >= 0);
@@ -674,16 +898,65 @@ struct buffered_piece_collection
return rob_point;
}
+ // TODO: this is shared with sectionalize, move to somewhere else (assign?)
+ template <typename Box, typename Value>
+ inline void enlarge_box(Box& box, Value value)
+ {
+ geometry::set<0, 0>(box, geometry::get<0, 0>(box) - value);
+ geometry::set<0, 1>(box, geometry::get<0, 1>(box) - value);
+ geometry::set<1, 0>(box, geometry::get<1, 0>(box) + value);
+ geometry::set<1, 1>(box, geometry::get<1, 1>(box) + value);
+ }
+
inline void calculate_robust_envelope(piece& pc)
{
+ if (pc.offsetted_count == 0)
+ {
+ return;
+ }
+
geometry::detail::envelope::envelope_range::apply(pc.robust_ring,
pc.robust_envelope);
+
+ geometry::assign_inverse(pc.robust_offsetted_envelope);
+ for (int i = 0; i < pc.offsetted_count; i++)
+ {
+ geometry::expand(pc.robust_offsetted_envelope, pc.robust_ring[i]);
+ }
+
+ // Take roundings into account, enlarge boxes with 1 integer
+ enlarge_box(pc.robust_envelope, 1);
+ enlarge_box(pc.robust_offsetted_envelope, 1);
+ }
+
+ inline void sectionalize(piece& pc)
+ {
+
+ buffered_ring<Ring> const& ring = offsetted_rings.back();
+
+ typedef geometry::detail::sectionalize::sectionalize_part
+ <
+ point_type,
+ boost::mpl::vector_c<std::size_t, 0, 1> // x,y dimension
+ > sectionalizer;
+
+ // Create a ring-identifier. The source-index is the piece index
+ // The multi_index is as in this collection (the ring), but not used here
+ // The ring_index is not used
+ ring_identifier ring_id(pc.index, pc.first_seg_id.multi_index, -1);
+
+ sectionalizer::apply(monotonic_sections,
+ boost::begin(ring) + pc.first_seg_id.segment_index,
+ boost::begin(ring) + pc.last_segment_index,
+ m_robust_policy,
+ ring_id, 10);
}
inline void finish_piece(piece& pc)
{
init_rescale_piece(pc, 0u);
calculate_robust_envelope(pc);
+ sectionalize(pc);
}
inline void finish_piece(piece& pc,
@@ -692,10 +965,16 @@ struct buffered_piece_collection
const point_type& point3)
{
init_rescale_piece(pc, 3u);
+ if (pc.offsetted_count == 0)
+ {
+ return;
+ }
+
add_helper_point(pc, point1);
robust_point_type mid_point = add_helper_point(pc, point2);
add_helper_point(pc, point3);
calculate_robust_envelope(pc);
+ sectionalize(pc);
current_robust_ring.push_back(mid_point);
}
@@ -711,6 +990,7 @@ struct buffered_piece_collection
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);
+ sectionalize(pc);
calculate_robust_envelope(pc);
// Add mid-points in other order to current helper_ring
@@ -730,10 +1010,7 @@ struct buffered_piece_collection
template <typename Range>
inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
{
- if (boost::size(range) == 0u)
- {
- return;
- }
+ BOOST_ASSERT(boost::size(range) != 0u);
typename Range::const_iterator it = boost::begin(range);
@@ -753,10 +1030,15 @@ struct buffered_piece_collection
template <typename Range>
- inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one)
+ 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());
+
+ if (boost::size(range) > 0u)
+ {
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ }
finish_piece(pc);
}
@@ -772,13 +1054,14 @@ struct buffered_piece_collection
}
template <typename Range>
- inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& 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)
+ if (boost::size(range) > 0u)
{
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
finish_piece(pc, range.back(), p, range.front());
}
else
@@ -788,8 +1071,11 @@ struct buffered_piece_collection
}
template <typename EndcapStrategy, typename Range>
- inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point)
+ inline void add_endcap(EndcapStrategy const& strategy, Range const& range,
+ point_type const& end_point)
{
+ boost::ignore_unused(strategy);
+
if (range.empty())
{
return;
@@ -842,6 +1128,80 @@ struct buffered_piece_collection
}
}
+ inline bool point_coveredby_original(point_type const& point)
+ {
+ robust_point_type any_point;
+ geometry::recalculate(any_point, point, m_robust_policy);
+
+ int count_in_original = 0;
+
+ // Check of the robust point of this outputted ring is in
+ // any of the robust original rings
+ // This can go quadratic if the input has many rings, and there
+ // are many untouched deflated rings around
+ for (typename std::vector<robust_original>::const_iterator it
+ = robust_originals.begin();
+ it != robust_originals.end();
+ ++it)
+ {
+ robust_original const& original = *it;
+ if (detail::disjoint::disjoint_point_box(any_point,
+ original.m_box))
+ {
+ continue;
+ }
+
+ int const geometry_code
+ = detail::within::point_in_geometry(any_point,
+ original.m_ring);
+
+ if (geometry_code == -1)
+ {
+ // Outside, continue
+ continue;
+ }
+
+ // Apply for possibly nested interior rings
+ if (original.m_is_interior)
+ {
+ count_in_original--;
+ }
+ else if (original.m_has_interiors)
+ {
+ count_in_original++;
+ }
+ else
+ {
+ // Exterior ring without interior rings
+ return true;
+ }
+ }
+ return count_in_original > 0;
+ }
+
+ // For a deflate, all rings around inner rings which are untouched
+ // (no intersections/turns) and which are OUTSIDE the original should
+ // be discarded
+ inline void discard_nonintersecting_deflated_rings()
+ {
+ for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it
+ = boost::begin(offsetted_rings);
+ it != boost::end(offsetted_rings);
+ ++it)
+ {
+ buffered_ring<Ring>& ring = *it;
+ if (! ring.has_intersections()
+ && boost::size(ring) > 0u
+ && geometry::area(ring) < 0)
+ {
+ if (! point_coveredby_original(geometry::range::front(ring)))
+ {
+ ring.is_untouched_outside_original = true;
+ }
+ }
+ }
+ }
+
inline void block_turns()
{
// To fix left-turn issues like #rt_u13
@@ -876,7 +1236,8 @@ struct buffered_piece_collection
typedef detail::overlay::traverse
<
false, false,
- buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >,
+ buffered_ring_collection<buffered_ring<Ring> >,
+ buffered_ring_collection<buffered_ring<Ring > >,
backtrack_for_buffer
> traverser;
@@ -914,16 +1275,20 @@ struct buffered_piece_collection
std::map<ring_identifier, properties> selected;
- // Select all rings which do not have any self-intersection (other ones should be traversed)
+ // Select all rings which do not have any self-intersection
+ // Inner rings, for deflate, which do not have intersections, and
+ // which are outside originals, are skipped
+ // (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())
+ if (! it->has_intersections()
+ && ! it->is_untouched_outside_original)
{
ring_identifier id(0, index, -1);
- selected[id] = properties(*it, true);
+ selected[id] = properties(*it);
}
}
@@ -935,7 +1300,7 @@ struct buffered_piece_collection
++it, ++index)
{
ring_identifier id(2, index, -1);
- selected[id] = properties(*it, true);
+ selected[id] = properties(*it);
}
detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);