File indexing completed on 2025-09-18 08:42:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP
0016
0017 #include <cstddef>
0018
0019 #include <boost/range/value_type.hpp>
0020 #include <boost/range/size.hpp>
0021
0022 #include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
0023 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
0024 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
0025 #include <boost/geometry/algorithms/detail/overlay/traversal.hpp>
0026 #include <boost/geometry/algorithms/num_points.hpp>
0027 #include <boost/geometry/core/assert.hpp>
0028 #include <boost/geometry/core/closure.hpp>
0029
0030 namespace boost { namespace geometry
0031 {
0032
0033 #ifndef DOXYGEN_NO_DETAIL
0034 namespace detail { namespace overlay
0035 {
0036
0037
0038 template
0039 <
0040 bool Reverse1,
0041 bool Reverse2,
0042 overlay_type OverlayType,
0043 typename Geometry1,
0044 typename Geometry2,
0045 typename Turns,
0046 typename TurnInfoMap,
0047 typename Clusters,
0048 typename Strategy,
0049 typename Visitor,
0050 typename Backtrack
0051 >
0052 struct traversal_ring_creator
0053 {
0054 using traversal_type = traversal
0055 <
0056 Reverse1, Reverse2, OverlayType,
0057 Geometry1, Geometry2, Turns, Clusters,
0058 Strategy,
0059 Visitor
0060 >;
0061
0062 using turn_type = typename boost::range_value<Turns>::type;
0063 using turn_operation_type = typename turn_type::turn_operation_type;
0064
0065 static const operation_type target_operation
0066 = operation_from_overlay<OverlayType>::value;
0067
0068 inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2,
0069 Turns& turns, TurnInfoMap& turn_info_map,
0070 Clusters const& clusters,
0071 Strategy const& strategy,
0072 Visitor& visitor)
0073 : m_trav(geometry1, geometry2, turns, clusters,
0074 strategy, visitor)
0075 , m_geometry1(geometry1)
0076 , m_geometry2(geometry2)
0077 , m_turns(turns)
0078 , m_turn_info_map(turn_info_map)
0079 , m_clusters(clusters)
0080 , m_strategy(strategy)
0081 , m_visitor(visitor)
0082 {
0083 }
0084
0085 template <typename Ring>
0086 inline traverse_error_type travel_to_next_turn(signed_size_type start_turn_index,
0087 int start_op_index,
0088 signed_size_type& turn_index,
0089 int& op_index,
0090 Ring& current_ring,
0091 bool is_start)
0092 {
0093 int const previous_op_index = op_index;
0094 signed_size_type const previous_turn_index = turn_index;
0095 turn_type& previous_turn = m_turns[turn_index];
0096 turn_operation_type& previous_op = previous_turn.operations[op_index];
0097 segment_identifier previous_seg_id;
0098
0099 signed_size_type to_vertex_index = -1;
0100 if (! m_trav.select_turn_from_enriched(turn_index, previous_seg_id,
0101 to_vertex_index, start_turn_index, start_op_index,
0102 previous_turn, previous_op, is_start))
0103 {
0104 return is_start
0105 ? traverse_error_no_next_ip_at_start
0106 : traverse_error_no_next_ip;
0107 }
0108 if (to_vertex_index >= 0)
0109 {
0110 if (previous_op.seg_id.source_index == 0)
0111 {
0112 geometry::copy_segments<Reverse1>(m_geometry1,
0113 previous_op.seg_id, to_vertex_index,
0114 m_strategy, current_ring);
0115 }
0116 else
0117 {
0118 geometry::copy_segments<Reverse2>(m_geometry2,
0119 previous_op.seg_id, to_vertex_index,
0120 m_strategy, current_ring);
0121 }
0122 }
0123
0124 if (m_turns[turn_index].discarded)
0125 {
0126 return is_start
0127 ? traverse_error_dead_end_at_start
0128 : traverse_error_dead_end;
0129 }
0130
0131 if (is_start)
0132 {
0133
0134 previous_op.visited.set_started();
0135 m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start");
0136 }
0137
0138 if (! m_trav.select_turn(start_turn_index, start_op_index,
0139 turn_index, op_index,
0140 previous_op_index, previous_turn_index, previous_seg_id,
0141 is_start, boost::size(current_ring) > 1))
0142 {
0143 return is_start
0144 ? traverse_error_no_next_ip_at_start
0145 : traverse_error_no_next_ip;
0146 }
0147
0148 {
0149
0150 turn_type const& current_turn = m_turns[turn_index];
0151 turn_operation_type const& op = current_turn.operations[op_index];
0152 if (op.visited.finalized()
0153 || m_trav.is_visited(current_turn, op, turn_index, op_index))
0154 {
0155 return traverse_error_visit_again;
0156 }
0157 }
0158
0159
0160 turn_type& current_turn = m_turns[turn_index];
0161 turn_operation_type& op = current_turn.operations[op_index];
0162 detail::overlay::append_no_collinear(current_ring, current_turn.point,
0163 m_strategy);
0164
0165
0166 m_trav.set_visited(current_turn, op);
0167 m_visitor.visit_traverse(m_turns, current_turn, op, "Visit");
0168
0169 return traverse_error_none;
0170 }
0171
0172 template <typename Ring>
0173 inline traverse_error_type traverse(Ring& ring,
0174 signed_size_type start_turn_index, int start_op_index)
0175 {
0176 turn_type const& start_turn = m_turns[start_turn_index];
0177 turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index];
0178
0179 detail::overlay::append_no_collinear(ring, start_turn.point,
0180 m_strategy);
0181
0182 signed_size_type current_turn_index = start_turn_index;
0183 int current_op_index = start_op_index;
0184
0185 traverse_error_type error = travel_to_next_turn(start_turn_index,
0186 start_op_index,
0187 current_turn_index, current_op_index,
0188 ring, true);
0189
0190 if (error != traverse_error_none)
0191 {
0192
0193
0194 return error;
0195 }
0196
0197 if (current_turn_index == start_turn_index)
0198 {
0199 start_op.visited.set_finished();
0200 m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish");
0201 return traverse_error_none;
0202 }
0203
0204 if (start_turn.is_clustered())
0205 {
0206 turn_type& turn = m_turns[current_turn_index];
0207 turn_operation_type& op = turn.operations[current_op_index];
0208 if (turn.cluster_id == start_turn.cluster_id
0209 && op.enriched.get_next_turn_index() == start_turn_index)
0210 {
0211 op.visited.set_finished();
0212 m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish (cluster)");
0213 return traverse_error_none;
0214 }
0215 }
0216
0217 std::size_t const max_iterations = 2 + 2 * m_turns.size();
0218 for (std::size_t i = 0; i <= max_iterations; i++)
0219 {
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 error = travel_to_next_turn(start_turn_index, start_op_index,
0231 current_turn_index, current_op_index,
0232 ring, false);
0233
0234 if (error != traverse_error_none)
0235 {
0236 return error;
0237 }
0238
0239 if (current_turn_index == start_turn_index
0240 && current_op_index == start_op_index)
0241 {
0242 start_op.visited.set_finished();
0243 m_visitor.visit_traverse(m_turns, start_turn, start_op, "Finish");
0244 return traverse_error_none;
0245 }
0246 }
0247
0248 return traverse_error_endless_loop;
0249 }
0250
0251 template <typename Rings>
0252 void traverse_with_operation(turn_type const& start_turn,
0253 std::size_t turn_index, int op_index,
0254 Rings& rings, std::size_t& finalized_ring_size,
0255 typename Backtrack::state_type& state)
0256 {
0257 using ring_type = typename boost::range_value<Rings>::type;
0258
0259 turn_operation_type const& start_op = start_turn.operations[op_index];
0260
0261 if (! start_op.visited.none()
0262 || ! start_op.enriched.startable
0263 || start_op.visited.rejected()
0264 || ! (start_op.operation == target_operation
0265 || start_op.operation == detail::overlay::operation_continue))
0266 {
0267 return;
0268 }
0269
0270 ring_type ring;
0271 traverse_error_type traverse_error = traverse(ring, turn_index, op_index);
0272
0273 if (traverse_error == traverse_error_none)
0274 {
0275 remove_spikes_at_closure(ring, m_strategy);
0276 fix_closure(ring, m_strategy);
0277
0278 std::size_t const min_num_points
0279 = core_detail::closure::minimum_ring_size
0280 <
0281 geometry::closure<ring_type>::value
0282 >::value;
0283
0284 if (geometry::num_points(ring) >= min_num_points)
0285 {
0286 rings.push_back(ring);
0287
0288 m_trav.finalize_visit_info(m_turn_info_map);
0289 finalized_ring_size++;
0290 }
0291 }
0292 else
0293 {
0294 Backtrack::apply(finalized_ring_size,
0295 rings, ring, m_turns, start_turn,
0296 m_turns[turn_index].operations[op_index],
0297 traverse_error,
0298 m_geometry1, m_geometry2,
0299 m_strategy,
0300 state, m_visitor);
0301 }
0302 }
0303
0304 int get_operation_index(turn_type const& turn) const
0305 {
0306
0307
0308
0309
0310
0311 static const bool is_union
0312 = operation_from_overlay<OverlayType>::value == operation_union;
0313
0314 turn_operation_type const& op0 = turn.operations[0];
0315 turn_operation_type const& op1 = turn.operations[1];
0316 return op0.remaining_distance <= op1.remaining_distance
0317 ? (is_union ? 1 : 0)
0318 : (is_union ? 0 : 1);
0319 }
0320
0321 template <typename Rings>
0322 void iterate(Rings& rings, std::size_t& finalized_ring_size,
0323 typename Backtrack::state_type& state)
0324 {
0325 auto do_iterate = [&](int phase)
0326 {
0327 for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
0328 {
0329 turn_type const& turn = m_turns[turn_index];
0330
0331 if (turn.discarded || turn.blocked() || (phase == 0 && turn.is_clustered()))
0332 {
0333
0334 continue;
0335 }
0336
0337 if (turn.both(operation_continue))
0338 {
0339 traverse_with_operation(turn, turn_index,
0340 get_operation_index(turn),
0341 rings, finalized_ring_size, state);
0342 }
0343 else
0344 {
0345 for (int op_index = 0; op_index < 2; op_index++)
0346 {
0347 traverse_with_operation(turn, turn_index, op_index,
0348 rings, finalized_ring_size, state);
0349 }
0350 }
0351 }
0352 };
0353
0354
0355 do_iterate(0);
0356
0357
0358 do_iterate(1);
0359 }
0360
0361 template <typename Rings>
0362 void iterate_with_preference(std::size_t phase,
0363 Rings& rings, std::size_t& finalized_ring_size,
0364 typename Backtrack::state_type& state)
0365 {
0366 for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
0367 {
0368 turn_type const& turn = m_turns[turn_index];
0369
0370 if (turn.discarded || turn.blocked())
0371 {
0372
0373 continue;
0374 }
0375
0376 turn_operation_type const& op0 = turn.operations[0];
0377 turn_operation_type const& op1 = turn.operations[1];
0378
0379 if (phase == 0)
0380 {
0381 if (! op0.enriched.prefer_start && ! op1.enriched.prefer_start)
0382 {
0383
0384 continue;
0385 }
0386 }
0387
0388 if (turn.both(operation_continue))
0389 {
0390 traverse_with_operation(turn, turn_index,
0391 get_operation_index(turn),
0392 rings, finalized_ring_size, state);
0393 }
0394 else
0395 {
0396 bool const forward = op0.enriched.prefer_start;
0397
0398 int op_index = forward ? 0 : 1;
0399 int const increment = forward ? 1 : -1;
0400
0401 for (int i = 0; i < 2; i++, op_index += increment)
0402 {
0403 traverse_with_operation(turn, turn_index, op_index,
0404 rings, finalized_ring_size, state);
0405 }
0406 }
0407 }
0408 }
0409
0410 private:
0411 traversal_type m_trav;
0412
0413 Geometry1 const& m_geometry1;
0414 Geometry2 const& m_geometry2;
0415 Turns& m_turns;
0416 TurnInfoMap& m_turn_info_map;
0417 Clusters const& m_clusters;
0418 Strategy const& m_strategy;
0419 Visitor& m_visitor;
0420 };
0421
0422 }}
0423 #endif
0424
0425 }}
0426
0427 #endif