File indexing completed on 2025-09-18 08:42:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
0016
0017 #include <cstddef>
0018 #include <algorithm>
0019 #include <iterator>
0020
0021 #include <boost/range/begin.hpp>
0022 #include <boost/range/end.hpp>
0023 #include <boost/range/size.hpp>
0024 #include <boost/range/value_type.hpp>
0025 #include <boost/throw_exception.hpp>
0026
0027 #include <boost/geometry/core/assert.hpp>
0028 #include <boost/geometry/core/tag.hpp>
0029 #include <boost/geometry/core/tags.hpp>
0030
0031 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
0032 #include <boost/geometry/algorithms/detail/overlay/follow.hpp>
0033 #include <boost/geometry/algorithms/detail/overlay/inconsistent_turns_exception.hpp>
0034 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
0035 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
0036 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
0037
0038 #include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
0039
0040 #include <boost/geometry/algorithms/detail/tupled_output.hpp>
0041
0042 #include <boost/geometry/algorithms/convert.hpp>
0043 #include <boost/geometry/algorithms/not_implemented.hpp>
0044
0045 #include <boost/geometry/util/condition.hpp>
0046
0047 namespace boost { namespace geometry
0048 {
0049
0050 #ifndef DOXYGEN_NO_DETAIL
0051 namespace detail { namespace overlay
0052 {
0053
0054 namespace following { namespace linear
0055 {
0056
0057
0058
0059
0060
0061
0062 template <typename Turn, typename Operation>
0063 static inline bool is_entering(Turn const& turn,
0064 Operation const& operation)
0065 {
0066 if ( turn.method != method_touch && turn.method != method_touch_interior )
0067 {
0068 return false;
0069 }
0070 return operation.operation == operation_intersection;
0071 }
0072
0073
0074
0075 template <typename Turn, typename Operation>
0076 static inline bool is_staying_inside(Turn const& turn,
0077 Operation const& operation,
0078 bool entered)
0079 {
0080 if ( !entered )
0081 {
0082 return false;
0083 }
0084
0085 if ( turn.method != method_equal && turn.method != method_collinear )
0086 {
0087 return false;
0088 }
0089 return operation.operation == operation_continue;
0090 }
0091
0092
0093
0094 template <typename Turn, typename Operation>
0095 static inline bool is_leaving(Turn const& turn,
0096 Operation const& operation,
0097 bool entered)
0098 {
0099 if ( !entered )
0100 {
0101 return false;
0102 }
0103
0104 if ( turn.method != method_touch
0105 && turn.method != method_touch_interior
0106 && turn.method != method_equal
0107 && turn.method != method_collinear )
0108 {
0109 return false;
0110 }
0111
0112 if ( operation.operation == operation_blocked )
0113 {
0114 return true;
0115 }
0116
0117 if ( operation.operation != operation_union )
0118 {
0119 return false;
0120 }
0121
0122 return operation.is_collinear;
0123 }
0124
0125
0126
0127 template <typename Turn, typename Operation>
0128 static inline bool is_isolated_point(Turn const& turn,
0129 Operation const& operation,
0130 bool entered)
0131 {
0132 if ( entered )
0133 {
0134 return false;
0135 }
0136
0137 if ( turn.method == method_none )
0138 {
0139 BOOST_GEOMETRY_ASSERT( operation.operation == operation_continue );
0140 return true;
0141 }
0142
0143 if ( turn.method == method_crosses )
0144 {
0145 return true;
0146 }
0147
0148 if ( turn.method != method_touch && turn.method != method_touch_interior )
0149 {
0150 return false;
0151 }
0152
0153 if ( operation.operation == operation_blocked )
0154 {
0155 return true;
0156 }
0157
0158 if ( operation.operation != operation_union )
0159 {
0160 return false;
0161 }
0162
0163 return !operation.is_collinear;
0164 }
0165
0166
0167
0168
0169
0170
0171 template
0172 <
0173 typename GeometryOut,
0174 typename Linestring,
0175 typename Linear,
0176 overlay_type OverlayType,
0177 bool FollowIsolatedPoints,
0178 bool FollowContinueTurns
0179 >
0180 class follow_linestring_linear
0181 {
0182 protected:
0183
0184 using action = following::action_selector<OverlayType, false>;
0185
0186 using linear = geometry::detail::output_geometry_access
0187 <
0188 GeometryOut, linestring_tag, linestring_tag
0189 >;
0190 using pointlike = geometry::detail::output_geometry_access
0191 <
0192 GeometryOut, point_tag, linestring_tag
0193 >;
0194
0195 template
0196 <
0197 typename TurnIterator,
0198 typename TurnOperationIterator,
0199 typename LinestringOut,
0200 typename SegmentIdentifier,
0201 typename OutputIterator,
0202 typename SideStrategy
0203 >
0204 static inline OutputIterator
0205 process_turn(TurnIterator it,
0206 TurnOperationIterator op_it,
0207 bool& entered,
0208 std::size_t& enter_count,
0209 Linestring const& linestring,
0210 LinestringOut& current_piece,
0211 SegmentIdentifier& current_segment_id,
0212 OutputIterator oit,
0213 SideStrategy const& strategy)
0214 {
0215 if ( is_entering(*it, *op_it) )
0216 {
0217 detail::turns::debug_turn(*it, *op_it, "-> Entering");
0218
0219 entered = true;
0220 if ( enter_count == 0 )
0221 {
0222 action::enter(current_piece,
0223 linestring,
0224 current_segment_id,
0225 op_it->seg_id.segment_index,
0226 it->point, *op_it, strategy,
0227 linear::get(oit));
0228 }
0229 ++enter_count;
0230 }
0231 else if ( is_leaving(*it, *op_it, entered) )
0232 {
0233 detail::turns::debug_turn(*it, *op_it, "-> Leaving");
0234
0235 --enter_count;
0236 if ( enter_count == 0 )
0237 {
0238 entered = false;
0239 action::leave(current_piece,
0240 linestring,
0241 current_segment_id,
0242 op_it->seg_id.segment_index,
0243 it->point, *op_it, strategy,
0244 linear::get(oit));
0245 }
0246 }
0247 else if ( BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints)
0248 && is_isolated_point(*it, *op_it, entered) )
0249 {
0250 detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
0251
0252 action::template isolated_point
0253 <
0254 typename pointlike::type
0255 >(it->point, pointlike::get(oit));
0256 }
0257 else if ( BOOST_GEOMETRY_CONDITION(FollowContinueTurns)
0258 && is_staying_inside(*it, *op_it, entered) )
0259 {
0260 detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
0261
0262 entered = true;
0263 }
0264 return oit;
0265 }
0266
0267 template
0268 <
0269 typename SegmentIdentifier,
0270 typename LinestringOut,
0271 typename OutputIterator,
0272 typename SideStrategy
0273 >
0274 static inline OutputIterator
0275 process_end(bool entered,
0276 Linestring const& linestring,
0277 SegmentIdentifier const& current_segment_id,
0278 LinestringOut& current_piece,
0279 OutputIterator oit,
0280 SideStrategy const& strategy)
0281 {
0282 if ( action::is_entered(entered) )
0283 {
0284 detail::copy_segments::copy_segments_linestring
0285 <
0286 false, false
0287 >::apply(linestring,
0288 current_segment_id,
0289 static_cast<signed_size_type>(boost::size(linestring) - 1),
0290 strategy,
0291 current_piece);
0292 }
0293
0294
0295 if (::boost::size(current_piece) > 1)
0296 {
0297 *linear::get(oit)++ = current_piece;
0298 }
0299
0300 return oit;
0301 }
0302
0303 public:
0304 template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
0305 static inline OutputIterator
0306 apply(Linestring const& linestring, Linear const&,
0307 TurnIterator first, TurnIterator beyond,
0308 OutputIterator oit,
0309 SideStrategy const& strategy)
0310 {
0311
0312
0313
0314 typename linear::type current_piece;
0315 geometry::segment_identifier current_segment_id(0, -1, -1, -1);
0316
0317 bool entered = false;
0318 std::size_t enter_count = 0;
0319
0320 for (TurnIterator it = first; it != beyond; ++it)
0321 {
0322 oit = process_turn(it, boost::begin(it->operations),
0323 entered, enter_count,
0324 linestring,
0325 current_piece, current_segment_id,
0326 oit,
0327 strategy);
0328 }
0329
0330 if (enter_count != 0)
0331 {
0332 return oit;
0333 }
0334
0335 return process_end(entered, linestring,
0336 current_segment_id, current_piece,
0337 oit,
0338 strategy);
0339 }
0340 };
0341
0342
0343
0344
0345 template
0346 <
0347 typename LinestringOut,
0348 typename MultiLinestring,
0349 typename Linear,
0350 overlay_type OverlayType,
0351 bool FollowIsolatedPoints,
0352 bool FollowContinueTurns
0353 >
0354 class follow_multilinestring_linear
0355 : follow_linestring_linear
0356 <
0357 LinestringOut,
0358 typename boost::range_value<MultiLinestring>::type,
0359 Linear,
0360 OverlayType,
0361 FollowIsolatedPoints,
0362 FollowContinueTurns
0363 >
0364 {
0365 protected:
0366 using linestring_t = typename boost::range_value<MultiLinestring>::type;
0367
0368 using base_t = follow_linestring_linear
0369 <
0370 LinestringOut, linestring_t, Linear,
0371 OverlayType, FollowIsolatedPoints, FollowContinueTurns
0372 >;
0373
0374 using action = following::action_selector<OverlayType>;
0375
0376 using linestring_iterator = typename boost::range_iterator
0377 <
0378 MultiLinestring const
0379 >::type;
0380
0381
0382 template <typename OutputIt, overlay_type OT>
0383 struct copy_linestrings_in_range
0384 {
0385 static inline OutputIt
0386 apply(linestring_iterator, linestring_iterator, OutputIt oit)
0387 {
0388 return oit;
0389 }
0390 };
0391
0392 template <typename OutputIt>
0393 struct copy_linestrings_in_range<OutputIt, overlay_difference>
0394 {
0395 static inline OutputIt
0396 apply(linestring_iterator first, linestring_iterator beyond,
0397 OutputIt oit)
0398 {
0399 for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
0400 {
0401 LinestringOut line_out;
0402 geometry::convert(*ls_it, line_out);
0403 *oit++ = line_out;
0404 }
0405 return oit;
0406 }
0407 };
0408
0409 template <typename TurnIterator>
0410 static inline signed_size_type get_multi_index(TurnIterator it)
0411 {
0412 return boost::begin(it->operations)->seg_id.multi_index;
0413 }
0414
0415 class has_other_multi_id
0416 {
0417 private:
0418 signed_size_type m_multi_id;
0419
0420 public:
0421 has_other_multi_id(signed_size_type multi_id)
0422 : m_multi_id(multi_id) {}
0423
0424 template <typename Turn>
0425 bool operator()(Turn const& turn) const
0426 {
0427 return boost::begin(turn.operations)->seg_id.multi_index
0428 != m_multi_id;
0429 }
0430 };
0431
0432 public:
0433 template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
0434 static inline OutputIterator
0435 apply(MultiLinestring const& multilinestring, Linear const& linear,
0436 TurnIterator first, TurnIterator beyond,
0437 OutputIterator oit,
0438 SideStrategy const& strategy)
0439 {
0440 BOOST_GEOMETRY_ASSERT( first != beyond );
0441
0442 using copy_linestrings = copy_linestrings_in_range
0443 <
0444 OutputIterator, OverlayType
0445 >;
0446
0447 linestring_iterator ls_first = boost::begin(multilinestring);
0448 linestring_iterator ls_beyond = boost::end(multilinestring);
0449
0450
0451
0452
0453 signed_size_type current_multi_id = get_multi_index(first);
0454
0455 oit = copy_linestrings::apply(ls_first,
0456 ls_first + current_multi_id,
0457 oit);
0458
0459 TurnIterator per_ls_next = first;
0460 do {
0461 TurnIterator per_ls_current = per_ls_next;
0462
0463
0464 per_ls_next = std::find_if(per_ls_current, beyond,
0465 has_other_multi_id(current_multi_id));
0466
0467 oit = base_t::apply(*(ls_first + current_multi_id),
0468 linear, per_ls_current, per_ls_next, oit, strategy);
0469
0470 signed_size_type next_multi_id = -1;
0471 linestring_iterator ls_next = ls_beyond;
0472 if ( per_ls_next != beyond )
0473 {
0474 next_multi_id = get_multi_index(per_ls_next);
0475 ls_next = ls_first + next_multi_id;
0476 }
0477 oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
0478 ls_next,
0479 oit);
0480
0481 current_multi_id = next_multi_id;
0482 }
0483 while ( per_ls_next != beyond );
0484
0485 return oit;
0486 }
0487 };
0488
0489
0490
0491
0492
0493
0494 template
0495 <
0496 typename LinestringOut,
0497 typename Geometry1,
0498 typename Geometry2,
0499 overlay_type OverlayType,
0500 bool FollowIsolatedPoints,
0501 bool FollowContinueTurns,
0502 typename TagIn1 = tag_t<Geometry1>
0503 >
0504 struct follow
0505 : not_implemented<Geometry1>
0506 {};
0507
0508
0509
0510 template
0511 <
0512 typename LinestringOut,
0513 typename Linestring,
0514 typename Linear,
0515 overlay_type OverlayType,
0516 bool FollowIsolatedPoints,
0517 bool FollowContinueTurns
0518 >
0519 struct follow
0520 <
0521 LinestringOut, Linestring, Linear,
0522 OverlayType, FollowIsolatedPoints, FollowContinueTurns,
0523 linestring_tag
0524 > : follow_linestring_linear
0525 <
0526 LinestringOut, Linestring, Linear,
0527 OverlayType, FollowIsolatedPoints, FollowContinueTurns
0528 >
0529 {};
0530
0531
0532 template
0533 <
0534 typename LinestringOut,
0535 typename MultiLinestring,
0536 typename Linear,
0537 overlay_type OverlayType,
0538 bool FollowIsolatedPoints,
0539 bool FollowContinueTurns
0540 >
0541 struct follow
0542 <
0543 LinestringOut, MultiLinestring, Linear,
0544 OverlayType, FollowIsolatedPoints, FollowContinueTurns,
0545 multi_linestring_tag
0546 > : follow_multilinestring_linear
0547 <
0548 LinestringOut, MultiLinestring, Linear,
0549 OverlayType, FollowIsolatedPoints, FollowContinueTurns
0550 >
0551 {};
0552
0553
0554
0555 }}
0556
0557 }}
0558 #endif
0559
0560 }}
0561
0562
0563 #endif