File indexing completed on 2025-09-16 08:34:09
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
0016 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP
0017
0018 #include <algorithm>
0019 #include <cstddef>
0020 #include <set>
0021
0022 #include <boost/core/ignore_unused.hpp>
0023 #include <boost/range/begin.hpp>
0024 #include <boost/range/empty.hpp>
0025 #include <boost/range/end.hpp>
0026 #include <boost/range/size.hpp>
0027 #include <boost/range/value_type.hpp>
0028
0029 #include <boost/geometry/core/assert.hpp>
0030 #include <boost/geometry/core/coordinate_type.hpp>
0031 #include <boost/geometry/core/point_type.hpp>
0032
0033 #include <boost/geometry/algorithms/covered_by.hpp>
0034 #include <boost/geometry/algorithms/envelope.hpp>
0035
0036 #include <boost/geometry/strategies/buffer.hpp>
0037
0038 #include <boost/geometry/geometries/ring.hpp>
0039
0040 #include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
0041 #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
0042 #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
0043 #include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
0044 #include <boost/geometry/algorithms/detail/buffer/piece_border.hpp>
0045 #include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
0046 #include <boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp>
0047
0048 #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
0049 #include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
0050 #include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
0051 #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
0052 #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
0053 #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
0054 #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
0055 #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
0056 #include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
0057 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
0058 #include <boost/geometry/algorithms/detail/partition.hpp>
0059 #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
0060 #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
0061
0062 #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
0063 #include <boost/geometry/views/enumerate_view.hpp>
0064 #include <boost/geometry/util/range.hpp>
0065
0066
0067 namespace boost { namespace geometry
0068 {
0069
0070
0071 #ifndef DOXYGEN_NO_DETAIL
0072 namespace detail { namespace buffer
0073 {
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119 template
0120 <
0121 typename Ring,
0122 typename Strategy,
0123 typename DistanceStrategy
0124 >
0125 struct buffered_piece_collection
0126 {
0127 using point_type = geometry::point_type_t<Ring>;
0128 using coordinate_type = geometry::coordinate_type_t<Ring>;
0129
0130
0131 using clockwise_ring_type = geometry::model::ring<point_type>;
0132
0133 using box_type = geometry::model::box<point_type>;
0134
0135 using buffer_turn_info_type = buffer_turn_info
0136 <
0137 point_type,
0138 typename segment_ratio_type<point_type>::type
0139 >;
0140
0141 using buffer_turn_operation_type = buffer_turn_operation
0142 <
0143 point_type,
0144 typename segment_ratio_type<point_type>::type
0145 >;
0146
0147 using turn_vector_type = std::vector<buffer_turn_info_type>;
0148
0149 using piece_border_type = piece_border<Ring, point_type> ;
0150
0151 struct piece
0152 {
0153 strategy::buffer::piece_type type;
0154 signed_size_type index;
0155
0156 signed_size_type left_index;
0157 signed_size_type right_index;
0158
0159
0160
0161
0162
0163
0164
0165
0166 segment_identifier first_seg_id;
0167
0168
0169
0170
0171
0172 signed_size_type beyond_last_segment_index;
0173
0174
0175 signed_size_type offsetted_count;
0176
0177 bool is_flat_start;
0178 bool is_flat_end;
0179
0180 bool is_deflated;
0181
0182
0183 piece_border_type m_piece_border;
0184
0185 point_type m_label_point;
0186
0187
0188 point_type m_center;
0189
0190 piece()
0191 : type(strategy::buffer::piece_type_unknown)
0192 , index(-1)
0193 , left_index(-1)
0194 , right_index(-1)
0195 , beyond_last_segment_index(-1)
0196 , offsetted_count(-1)
0197 , is_flat_start(false)
0198 , is_flat_end(false)
0199 , is_deflated(false)
0200 {
0201 }
0202 };
0203
0204 struct original_ring
0205 {
0206 using sections_type = geometry::sections<box_type, 1>;
0207
0208
0209 inline original_ring()
0210 : m_is_interior(false)
0211 , m_has_interiors(false)
0212 {}
0213
0214 inline original_ring(clockwise_ring_type const& ring,
0215 bool is_interior, bool has_interiors,
0216 Strategy const& strategy)
0217 : m_ring(ring)
0218 , m_is_interior(is_interior)
0219 , m_has_interiors(has_interiors)
0220 {
0221 geometry::envelope(m_ring, m_box, strategy);
0222
0223
0224
0225
0226
0227 using dimensions = std::integer_sequence<std::size_t, 0>;
0228 geometry::sectionalize
0229 <
0230 false, dimensions
0231 >(m_ring, m_sections, strategy);
0232 }
0233
0234 clockwise_ring_type m_ring;
0235 box_type m_box;
0236 sections_type m_sections;
0237
0238 bool m_is_interior;
0239 bool m_has_interiors;
0240 };
0241
0242 using piece_vector_type = std::vector<piece>;
0243
0244 piece_vector_type m_pieces;
0245 turn_vector_type m_turns;
0246 signed_size_type m_first_piece_index;
0247 bool m_deflate;
0248 bool m_has_deflated;
0249
0250
0251
0252 using ring_collection_t = buffered_ring_collection<buffered_ring<Ring>>;
0253 ring_collection_t offsetted_rings;
0254 std::vector<original_ring> original_rings;
0255 std::vector<point_type> m_linear_end_points;
0256
0257 buffered_ring_collection<Ring> traversed_rings;
0258 segment_identifier current_segment_id;
0259
0260
0261 using sections_type = geometry::sections<box_type, 2>;
0262 sections_type monotonic_sections;
0263
0264
0265 using cluster_type = std::map
0266 <
0267 signed_size_type,
0268 detail::overlay::cluster_info
0269 >;
0270
0271 cluster_type m_clusters;
0272
0273 Strategy m_strategy;
0274 DistanceStrategy m_distance_strategy;
0275
0276 buffered_piece_collection(Strategy const& strategy,
0277 DistanceStrategy const& distance_strategy)
0278 : m_first_piece_index(-1)
0279 , m_deflate(false)
0280 , m_has_deflated(false)
0281 , m_strategy(strategy)
0282 , m_distance_strategy(distance_strategy)
0283 {}
0284
0285 inline void check_linear_endpoints(buffer_turn_info_type& turn) const
0286 {
0287
0288
0289
0290
0291 for (auto const& p : m_linear_end_points)
0292 {
0293 if (detail::equals::equals_point_point(turn.point, p, m_strategy))
0294 {
0295 turn.is_linear_end_point = true;
0296 }
0297 }
0298 }
0299
0300 inline void deflate_check_turns()
0301 {
0302 if (! m_has_deflated)
0303 {
0304 return;
0305 }
0306
0307
0308
0309 for (auto& turn : m_turns)
0310 {
0311 if (! turn.is_turn_traversable)
0312 {
0313 continue;
0314 }
0315 for (auto& op : turn.operations)
0316 {
0317 if (op.enriched.get_next_turn_index() == static_cast<signed_size_type>(turn.turn_index)
0318 && m_pieces[op.seg_id.piece_index].is_deflated)
0319 {
0320
0321 op.enriched.startable = false;
0322 }
0323 }
0324 }
0325 }
0326
0327
0328 inline void check_turn_in_original()
0329 {
0330 turn_in_original_visitor
0331 <
0332 turn_vector_type,
0333 Strategy
0334 > visitor(m_turns, m_strategy);
0335
0336 geometry::partition
0337 <
0338 box_type,
0339 include_turn_policy,
0340 detail::partition::include_all_policy
0341 >::apply(m_turns, original_rings, visitor,
0342 turn_get_box<Strategy>(m_strategy),
0343 turn_in_original_overlaps_box<Strategy>(m_strategy),
0344 original_get_box<Strategy>(m_strategy),
0345 original_overlaps_box<Strategy>(m_strategy));
0346
0347 bool const deflate = m_distance_strategy.negative();
0348
0349 for (auto& turn : m_turns)
0350 {
0351 if (turn.is_turn_traversable)
0352 {
0353 if (deflate && turn.count_in_original <= 0)
0354 {
0355
0356
0357 turn.is_turn_traversable = false;
0358 }
0359 else if (! deflate && turn.count_in_original > 0)
0360 {
0361
0362 turn.is_turn_traversable = false;
0363 }
0364 }
0365 }
0366 }
0367
0368 inline void update_turn_administration()
0369 {
0370 for (auto const& enumerated : util::enumerate(m_turns))
0371 {
0372
0373 auto& turn = enumerated.value;
0374 turn.turn_index = enumerated.index;
0375
0376
0377 if (! turn.is_linear_end_point)
0378 {
0379 this->check_linear_endpoints(turn);
0380 }
0381 }
0382 }
0383
0384
0385
0386
0387
0388
0389
0390
0391 inline void update_piece_administration()
0392 {
0393 for (auto& pc : m_pieces)
0394 {
0395 piece_border_type& border = pc.m_piece_border;
0396 buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index];
0397
0398 if (pc.offsetted_count > 0)
0399 {
0400 if (pc.type != strategy::buffer::buffered_concave)
0401 {
0402 border.set_offsetted(ring, pc.first_seg_id.segment_index,
0403 pc.beyond_last_segment_index);
0404 }
0405
0406
0407 border.get_properties_of_border(pc.type == geometry::strategy::buffer::buffered_point,
0408 pc.m_center, m_strategy);
0409 if (! pc.is_flat_end && ! pc.is_flat_start)
0410 {
0411 border.get_properties_of_offsetted_ring_part(m_strategy);
0412 }
0413 }
0414 }
0415 }
0416
0417 inline void get_turns()
0418 {
0419 update_piece_administration();
0420
0421 {
0422
0423 piece_turn_visitor
0424 <
0425 piece_vector_type,
0426 buffered_ring_collection<buffered_ring<Ring> >,
0427 turn_vector_type,
0428 Strategy
0429 > visitor(m_pieces, offsetted_rings, m_turns,
0430 m_strategy);
0431
0432 detail::sectionalize::enlarge_sections(monotonic_sections, m_strategy);
0433
0434 geometry::partition
0435 <
0436 box_type
0437 >::apply(monotonic_sections, visitor,
0438 detail::section::get_section_box<Strategy>(m_strategy),
0439 detail::section::overlaps_section_box<Strategy>(m_strategy));
0440 }
0441
0442 update_turn_administration();
0443 }
0444
0445 inline void check_turn_in_pieces()
0446 {
0447
0448 turn_in_piece_visitor
0449 <
0450 geometry::cs_tag_t<point_type>,
0451 turn_vector_type, piece_vector_type, DistanceStrategy, Strategy
0452 > visitor(m_turns, m_pieces, m_distance_strategy, m_strategy);
0453
0454 geometry::partition
0455 <
0456 box_type
0457 >::apply(m_turns, m_pieces, visitor,
0458 turn_get_box<Strategy>(m_strategy),
0459 turn_overlaps_box<Strategy>(m_strategy),
0460 piece_get_box<Strategy>(m_strategy),
0461 piece_overlaps_box<Strategy>(m_strategy));
0462 }
0463
0464 inline void start_new_ring(bool deflate)
0465 {
0466 std::size_t const n = offsetted_rings.size();
0467 current_segment_id.source_index = 0;
0468 current_segment_id.multi_index = static_cast<signed_size_type>(n);
0469 current_segment_id.ring_index = -1;
0470 current_segment_id.segment_index = 0;
0471
0472 offsetted_rings.resize(n + 1);
0473 original_rings.resize(n + 1);
0474
0475 m_first_piece_index = static_cast<signed_size_type>(boost::size(m_pieces));
0476 m_deflate = deflate;
0477 if (deflate)
0478 {
0479
0480
0481 m_has_deflated = true;
0482 }
0483 }
0484
0485 inline void abort_ring()
0486 {
0487
0488 while (! m_pieces.empty()
0489 && m_pieces.back().first_seg_id.multi_index
0490 == current_segment_id.multi_index)
0491 {
0492 m_pieces.pop_back();
0493 }
0494
0495 offsetted_rings.pop_back();
0496 original_rings.pop_back();
0497
0498 m_first_piece_index = -1;
0499 }
0500
0501 inline void update_last_point(point_type const& p,
0502 buffered_ring<Ring>& ring)
0503 {
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513 BOOST_GEOMETRY_ASSERT(boost::size(m_pieces) > 0);
0514 if (! ring.empty()
0515 && current_segment_id.segment_index
0516 == m_pieces.back().first_seg_id.segment_index)
0517 {
0518 ring.back() = p;
0519 }
0520 }
0521
0522 inline void set_piece_center(point_type const& center)
0523 {
0524 BOOST_GEOMETRY_ASSERT(! m_pieces.empty());
0525 m_pieces.back().m_center = center;
0526 }
0527
0528 inline bool finish_ring(strategy::buffer::result_code code)
0529 {
0530 if (code == strategy::buffer::result_error_numerical)
0531 {
0532 abort_ring();
0533 return false;
0534 }
0535
0536 if (m_first_piece_index == -1)
0537 {
0538 return false;
0539 }
0540
0541
0542 std::size_t const first_piece_index
0543 = static_cast<std::size_t>(m_first_piece_index);
0544 signed_size_type const last_piece_index
0545 = static_cast<signed_size_type>(boost::size(m_pieces)) - 1;
0546
0547 if (first_piece_index < boost::size(m_pieces))
0548 {
0549
0550
0551 geometry::range::at(m_pieces, first_piece_index).left_index
0552 = last_piece_index;
0553 geometry::range::back(m_pieces).right_index = m_first_piece_index;
0554 }
0555
0556 buffered_ring<Ring>& added = offsetted_rings.back();
0557 if (! boost::empty(added))
0558 {
0559
0560
0561 range::back(added) = range::front(added);
0562 }
0563
0564 for (std::size_t i = first_piece_index; i < boost::size(m_pieces); i++)
0565 {
0566 sectionalize(m_pieces[i], added);
0567 }
0568
0569 m_first_piece_index = -1;
0570 return true;
0571 }
0572
0573 template <typename InputRing>
0574 inline void finish_ring(strategy::buffer::result_code code,
0575 InputRing const& input_ring,
0576 bool is_interior, bool has_interiors)
0577 {
0578 if (! finish_ring(code))
0579 {
0580 return;
0581 }
0582
0583 if (! boost::empty(input_ring))
0584 {
0585
0586
0587
0588 clockwise_ring_type clockwise_ring;
0589
0590 using view_type = detail::closed_clockwise_view<InputRing const>;
0591 view_type const view(input_ring);
0592
0593 for (auto it = boost::begin(view); it != boost::end(view); ++it)
0594 {
0595 clockwise_ring.push_back(*it);
0596 }
0597
0598 original_rings.back()
0599 = original_ring(clockwise_ring,
0600 is_interior, has_interiors,
0601 m_strategy);
0602 }
0603 }
0604
0605 inline void set_current_ring_concave()
0606 {
0607 BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0);
0608 offsetted_rings.back().has_concave = true;
0609 }
0610
0611 inline signed_size_type add_point(point_type const& p)
0612 {
0613 BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0);
0614
0615 buffered_ring<Ring>& current_ring = offsetted_rings.back();
0616 update_last_point(p, current_ring);
0617
0618 current_segment_id.segment_index++;
0619 current_ring.push_back(p);
0620 return static_cast<signed_size_type>(current_ring.size());
0621 }
0622
0623
0624
0625 inline piece& create_piece(strategy::buffer::piece_type type,
0626 bool decrease_segment_index_by_one)
0627 {
0628 if (type == strategy::buffer::buffered_concave)
0629 {
0630 offsetted_rings.back().has_concave = true;
0631 }
0632
0633 piece pc;
0634 pc.type = type;
0635 pc.index = static_cast<signed_size_type>(boost::size(m_pieces));
0636 pc.is_deflated = m_deflate;
0637
0638 current_segment_id.piece_index = pc.index;
0639
0640 pc.first_seg_id = current_segment_id;
0641
0642
0643 pc.left_index = pc.index - 1;
0644 pc.right_index = pc.index + 1;
0645
0646 std::size_t const n = boost::size(offsetted_rings.back());
0647 pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
0648 pc.beyond_last_segment_index = pc.first_seg_id.segment_index;
0649
0650 m_pieces.push_back(pc);
0651 return m_pieces.back();
0652 }
0653
0654 inline void init_rescale_piece(piece& pc)
0655 {
0656 if (pc.first_seg_id.segment_index < 0)
0657 {
0658
0659
0660 pc.offsetted_count = 0;
0661 return;
0662 }
0663
0664 BOOST_GEOMETRY_ASSERT(pc.first_seg_id.multi_index >= 0);
0665 BOOST_GEOMETRY_ASSERT(pc.beyond_last_segment_index >= 0);
0666
0667 pc.offsetted_count = pc.beyond_last_segment_index - pc.first_seg_id.segment_index;
0668 BOOST_GEOMETRY_ASSERT(pc.offsetted_count >= 0);
0669 }
0670
0671 inline void add_piece_point(piece& pc, point_type const& point, bool add_to_original)
0672 {
0673 if (add_to_original && pc.type != strategy::buffer::buffered_concave)
0674 {
0675 pc.m_piece_border.add_original_point(point);
0676 }
0677 else
0678 {
0679 pc.m_label_point = point;
0680 }
0681 }
0682
0683 inline void sectionalize(piece const& pc, buffered_ring<Ring> const& ring)
0684 {
0685 using sectionalizer = geometry::detail::sectionalize::sectionalize_part
0686 <
0687 std::integer_sequence<std::size_t, 0, 1>
0688 >;
0689
0690
0691
0692
0693 ring_identifier const ring_id(pc.index, pc.first_seg_id.multi_index, -1);
0694
0695 sectionalizer::apply(monotonic_sections,
0696 boost::begin(ring) + pc.first_seg_id.segment_index,
0697 boost::begin(ring) + pc.beyond_last_segment_index,
0698 m_strategy,
0699 ring_id, 10);
0700 }
0701
0702 inline void finish_piece(piece& pc)
0703 {
0704 init_rescale_piece(pc);
0705 }
0706
0707 inline void finish_piece(piece& pc,
0708 point_type const& point1,
0709 point_type const& point2,
0710 point_type const& point3)
0711 {
0712 init_rescale_piece(pc);
0713 if (pc.offsetted_count == 0)
0714 {
0715 return;
0716 }
0717
0718 add_piece_point(pc, point1, false);
0719 add_piece_point(pc, point2, true);
0720 add_piece_point(pc, point3, false);
0721 }
0722
0723 inline void finish_piece(piece& pc,
0724 point_type const& point1,
0725 point_type const& point2,
0726 point_type const& point3,
0727 point_type const& point4)
0728 {
0729 init_rescale_piece(pc);
0730
0731
0732
0733
0734 add_piece_point(pc, point1, false);
0735 add_piece_point(pc, point2, true);
0736 add_piece_point(pc, point3, true);
0737 add_piece_point(pc, point4, false);
0738 }
0739
0740 template <typename Range>
0741 inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
0742 {
0743 BOOST_GEOMETRY_ASSERT(boost::size(range) != 0u);
0744
0745 auto it = boost::begin(range);
0746
0747
0748
0749
0750 if (add_front)
0751 {
0752 add_point(*it);
0753 }
0754
0755 for (++it; it != boost::end(range); ++it)
0756 {
0757 pc.beyond_last_segment_index = add_point(*it);
0758 }
0759 }
0760
0761 inline void add_piece(strategy::buffer::piece_type type, point_type const& p,
0762 point_type const& b1, point_type const& b2)
0763 {
0764 piece& pc = create_piece(type, false);
0765 add_point(b1);
0766 pc.beyond_last_segment_index = add_point(b2);
0767 finish_piece(pc, b2, p, b1);
0768 }
0769
0770 template <typename Range>
0771 inline void add_piece(strategy::buffer::piece_type type, Range const& range,
0772 bool decrease_segment_index_by_one)
0773 {
0774 piece& pc = create_piece(type, decrease_segment_index_by_one);
0775
0776 if (boost::size(range) > 0u)
0777 {
0778 add_range_to_piece(pc, range, offsetted_rings.back().empty());
0779 }
0780 finish_piece(pc);
0781 }
0782
0783 template <typename Range>
0784 inline void add_piece(strategy::buffer::piece_type type,
0785 point_type const& p, Range const& range)
0786 {
0787 piece& pc = create_piece(type, true);
0788
0789 if (boost::size(range) > 0u)
0790 {
0791 add_range_to_piece(pc, range, offsetted_rings.back().empty());
0792 finish_piece(pc, range.back(), p, range.front());
0793 }
0794 else
0795 {
0796 finish_piece(pc);
0797 }
0798 }
0799
0800 template <typename Range>
0801 inline void add_side_piece(point_type const& original_point1,
0802 point_type const& original_point2,
0803 Range const& range, bool is_first, bool is_empty)
0804 {
0805 BOOST_GEOMETRY_ASSERT(boost::size(range) >= 2u);
0806
0807 auto const piece_type = is_empty
0808 ? strategy::buffer::buffered_empty_side
0809 : strategy::buffer::buffered_segment;
0810
0811 piece& pc = create_piece(piece_type, ! is_first);
0812 add_range_to_piece(pc, range, is_first);
0813
0814
0815
0816 finish_piece(pc, range.back(), original_point2, original_point1, range.front());
0817 }
0818
0819 template <typename EndcapStrategy, typename Range>
0820 inline void add_endcap(EndcapStrategy const& strategy, Range const& range,
0821 point_type const& end_point)
0822 {
0823 boost::ignore_unused(strategy);
0824
0825 if (range.empty())
0826 {
0827 return;
0828 }
0829 strategy::buffer::piece_type pt = strategy.get_piece_type();
0830 if (pt == strategy::buffer::buffered_flat_end)
0831 {
0832
0833 add_piece(pt, range, true);
0834 }
0835 else
0836 {
0837
0838 add_piece(pt, end_point, range);
0839 }
0840 }
0841
0842 inline void mark_flat_start(point_type const& point)
0843 {
0844 if (! m_pieces.empty())
0845 {
0846 piece& back = m_pieces.back();
0847 back.is_flat_start = true;
0848
0849
0850
0851
0852
0853
0854 m_linear_end_points.push_back(point);
0855 }
0856 }
0857
0858 inline void mark_flat_end(point_type const& point)
0859 {
0860 if (! m_pieces.empty())
0861 {
0862 piece& back = m_pieces.back();
0863 back.is_flat_end = true;
0864 m_linear_end_points.push_back(point);
0865 }
0866 }
0867
0868
0869
0870 inline void handle_colocations()
0871 {
0872 if (! detail::overlay::handle_colocations
0873 <
0874 false, false, overlay_buffer,
0875 ring_collection_t, ring_collection_t
0876 >(m_turns, m_clusters))
0877 {
0878 return;
0879 }
0880
0881 detail::overlay::gather_cluster_properties
0882 <
0883 false, false, overlay_buffer
0884 >(m_clusters, m_turns, detail::overlay::operation_union,
0885 offsetted_rings, offsetted_rings, m_strategy);
0886
0887 for (auto const& cluster : m_clusters)
0888 {
0889 if (cluster.second.open_count == 0 && cluster.second.spike_count == 0)
0890 {
0891
0892 for (auto const& index : cluster.second.turn_indices)
0893 {
0894 m_turns[index].is_turn_traversable = false;
0895 }
0896 }
0897 }
0898 }
0899
0900 inline void make_traversable_consistent_per_cluster()
0901 {
0902 for (auto const& cluster : m_clusters)
0903 {
0904 bool is_traversable = false;
0905 for (auto const& index : cluster.second.turn_indices)
0906 {
0907 if (m_turns[index].is_turn_traversable)
0908 {
0909
0910
0911 is_traversable = true;
0912 break;
0913 }
0914 }
0915 if (is_traversable)
0916 {
0917 for (auto const& index : cluster.second.turn_indices)
0918 {
0919 m_turns[index].is_turn_traversable = true;
0920 }
0921 }
0922 }
0923 }
0924
0925 inline void enrich()
0926 {
0927 enrich_intersection_points<false, false, overlay_buffer>(m_turns,
0928 m_clusters, offsetted_rings, offsetted_rings,
0929 m_strategy);
0930 }
0931
0932
0933
0934 inline void discard_rings()
0935 {
0936 for (auto const& turn : m_turns)
0937 {
0938 if (turn.is_turn_traversable)
0939 {
0940 offsetted_rings[turn.operations[0].seg_id.multi_index].has_accepted_intersections = true;
0941 offsetted_rings[turn.operations[1].seg_id.multi_index].has_accepted_intersections = true;
0942 }
0943 else
0944 {
0945 offsetted_rings[turn.operations[0].seg_id.multi_index].has_discarded_intersections = true;
0946 offsetted_rings[turn.operations[1].seg_id.multi_index].has_discarded_intersections = true;
0947 }
0948 }
0949 }
0950
0951 inline bool point_coveredby_original(point_type const& point)
0952 {
0953 signed_size_type count_in_original = 0;
0954
0955
0956
0957
0958
0959 for (auto const& original : original_rings)
0960 {
0961 if (original.m_ring.empty())
0962 {
0963 continue;
0964 }
0965 if (detail::disjoint::disjoint_point_box(point, original.m_box,m_strategy))
0966 {
0967 continue;
0968 }
0969
0970 int const geometry_code
0971 = detail::within::point_in_geometry(point, original.m_ring, m_strategy);
0972
0973 if (geometry_code == -1)
0974 {
0975
0976 continue;
0977 }
0978
0979
0980 if (original.m_is_interior)
0981 {
0982 count_in_original--;
0983 }
0984 else if (original.m_has_interiors)
0985 {
0986 count_in_original++;
0987 }
0988 else
0989 {
0990
0991 return true;
0992 }
0993 }
0994 return count_in_original > 0;
0995 }
0996
0997
0998
0999
1000 inline void discard_nonintersecting_deflated_rings()
1001 {
1002 for (auto& ring : offsetted_rings)
1003 {
1004 if (! ring.has_intersections()
1005 && boost::size(ring) > 0u
1006 && geometry::area(ring, m_strategy) < 0)
1007 {
1008 if (! point_coveredby_original(geometry::range::front(ring)))
1009 {
1010 ring.is_untouched_outside_original = true;
1011 }
1012 }
1013 }
1014 }
1015
1016 inline void block_turns()
1017 {
1018 for (auto& turn : m_turns)
1019 {
1020 if (! turn.is_turn_traversable)
1021 {
1022
1023
1024 turn.discarded = true;
1025 }
1026 }
1027 }
1028
1029 inline void traverse()
1030 {
1031 using traverser = detail::overlay::traverse
1032 <
1033 false, false,
1034 buffered_ring_collection<buffered_ring<Ring> >,
1035 buffered_ring_collection<buffered_ring<Ring > >,
1036 overlay_buffer,
1037 backtrack_for_buffer
1038 >;
1039 std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
1040
1041 traversed_rings.clear();
1042 buffer_overlay_visitor visitor;
1043 traverser::apply(offsetted_rings, offsetted_rings,
1044 m_strategy,
1045 m_turns, traversed_rings,
1046 turn_info_per_ring,
1047 m_clusters, visitor);
1048 }
1049
1050 inline void reverse()
1051 {
1052 for (auto& ring : offsetted_rings)
1053 {
1054 if (! ring.has_intersections())
1055 {
1056 std::reverse(ring.begin(), ring.end());
1057 }
1058 }
1059 for (auto& ring : traversed_rings)
1060 {
1061 std::reverse(ring.begin(), ring.end());
1062 }
1063 }
1064
1065 template <typename GeometryOutput, typename OutputIterator>
1066 inline OutputIterator assign(OutputIterator out) const
1067 {
1068 using area_result_type = typename geometry::area_result
1069 <
1070 buffered_ring<Ring>, Strategy
1071 >::type;
1072 using properties = detail::overlay::ring_properties
1073 <
1074 point_type, area_result_type
1075 >;
1076
1077 std::map<ring_identifier, properties> selected;
1078
1079
1080
1081
1082
1083 for (auto const& enumerated : util::enumerate(offsetted_rings))
1084 {
1085 auto const& ring = enumerated.value;
1086 if (! ring.has_intersections()
1087 && ! ring.is_untouched_outside_original)
1088 {
1089 properties const p = properties(ring, m_strategy);
1090 if (p.valid)
1091 {
1092 ring_identifier id(0, enumerated.index, -1);
1093 selected[id] = p;
1094 }
1095 }
1096 }
1097
1098
1099 for (auto const& enumerated : util::enumerate(traversed_rings))
1100 {
1101 auto const& ring = enumerated.value;
1102 properties p = properties(ring, m_strategy);
1103 if (p.valid)
1104 {
1105 ring_identifier id(2, enumerated.index, -1);
1106 selected[id] = p;
1107 }
1108 }
1109
1110 detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings,
1111 selected, m_strategy);
1112 return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out,
1113 m_strategy);
1114 }
1115
1116 };
1117
1118
1119 }}
1120 #endif
1121
1122
1123 }}
1124
1125 #endif