1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
5 // Copyright (c) 2014-2017, Oracle and/or its affiliates.
7 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 // Licensed under the Boost Software License version 1.0.
11 // http://www.boost.org/users/license.html
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
21 #include <boost/range.hpp>
22 #include <boost/throw_exception.hpp>
24 #include <boost/geometry/core/assert.hpp>
25 #include <boost/geometry/core/tag.hpp>
26 #include <boost/geometry/core/tags.hpp>
28 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
29 #include <boost/geometry/algorithms/detail/overlay/follow.hpp>
30 #include <boost/geometry/algorithms/detail/overlay/inconsistent_turns_exception.hpp>
31 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
32 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
33 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
35 #include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
37 #include <boost/geometry/algorithms/convert.hpp>
38 #include <boost/geometry/algorithms/not_implemented.hpp>
41 namespace boost { namespace geometry
44 #ifndef DOXYGEN_NO_DETAIL
45 namespace detail { namespace overlay
48 namespace following { namespace linear
54 // follower for linear/linear geometries set operations
56 template <typename Turn, typename Operation>
57 static inline bool is_entering(Turn const& turn,
58 Operation const& operation)
60 if ( turn.method != method_touch && turn.method != method_touch_interior )
64 return operation.operation == operation_intersection;
69 template <typename Turn, typename Operation>
70 static inline bool is_staying_inside(Turn const& turn,
71 Operation const& operation,
79 if ( turn.method != method_equal && turn.method != method_collinear )
83 return operation.operation == operation_continue;
88 template <typename Turn, typename Operation>
89 static inline bool is_leaving(Turn const& turn,
90 Operation const& operation,
98 if ( turn.method != method_touch
99 && turn.method != method_touch_interior
100 && turn.method != method_equal
101 && turn.method != method_collinear )
106 if ( operation.operation == operation_blocked )
111 if ( operation.operation != operation_union )
116 return operation.is_collinear;
121 template <typename Turn, typename Operation>
122 static inline bool is_isolated_point(Turn const& turn,
123 Operation const& operation,
131 if ( turn.method == method_none )
133 BOOST_GEOMETRY_ASSERT( operation.operation == operation_continue );
137 if ( turn.method == method_crosses )
142 if ( turn.method != method_touch && turn.method != method_touch_interior )
147 if ( operation.operation == operation_blocked )
152 if ( operation.operation != operation_union )
157 return !operation.is_collinear;
170 typename LinestringOut,
173 overlay_type OverlayType,
174 bool FollowIsolatedPoints,
175 bool FollowContinueTurns
177 class follow_linestring_linear_linestring
180 // allow spikes (false indicates: do not remove spikes)
181 typedef following::action_selector<OverlayType, false> action;
185 typename TurnIterator,
186 typename TurnOperationIterator,
187 typename SegmentIdentifier,
188 typename OutputIterator,
189 typename SideStrategy
191 static inline OutputIterator
192 process_turn(TurnIterator it,
193 TurnOperationIterator op_it,
195 std::size_t& enter_count,
196 Linestring const& linestring,
197 LinestringOut& current_piece,
198 SegmentIdentifier& current_segment_id,
200 SideStrategy const& strategy)
202 // We don't rescale linear/linear
203 detail::no_rescale_policy robust_policy;
205 if ( is_entering(*it, *op_it) )
207 detail::turns::debug_turn(*it, *op_it, "-> Entering");
210 if ( enter_count == 0 )
212 action::enter(current_piece, linestring,
214 op_it->seg_id.segment_index,
215 it->point, *op_it, strategy, robust_policy, oit);
219 else if ( is_leaving(*it, *op_it, entered) )
221 detail::turns::debug_turn(*it, *op_it, "-> Leaving");
224 if ( enter_count == 0 )
227 action::leave(current_piece, linestring,
229 op_it->seg_id.segment_index,
230 it->point, *op_it, strategy, robust_policy, oit);
233 else if ( FollowIsolatedPoints
234 && is_isolated_point(*it, *op_it, entered) )
236 detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
238 action::isolated_point(current_piece, linestring,
240 op_it->seg_id.segment_index,
241 it->point, *op_it, oit);
243 else if ( FollowContinueTurns
244 && is_staying_inside(*it, *op_it, entered) )
246 detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
255 typename SegmentIdentifier,
256 typename OutputIterator,
257 typename SideStrategy
259 static inline OutputIterator
260 process_end(bool entered,
261 Linestring const& linestring,
262 SegmentIdentifier const& current_segment_id,
263 LinestringOut& current_piece,
265 SideStrategy const& strategy)
267 if ( action::is_entered(entered) )
269 // We don't rescale linear/linear
270 detail::no_rescale_policy robust_policy;
272 detail::copy_segments::copy_segments_linestring
274 false, false // do not reverse; do not remove spikes
277 static_cast<signed_size_type>(boost::size(linestring) - 1),
283 // Output the last one, if applicable
284 if (::boost::size(current_piece) > 1)
286 *oit++ = current_piece;
293 template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
294 static inline OutputIterator
295 apply(Linestring const& linestring, Linear const&,
296 TurnIterator first, TurnIterator beyond,
298 SideStrategy const& strategy)
300 // Iterate through all intersection points (they are
301 // ordered along the each line)
303 LinestringOut current_piece;
304 geometry::segment_identifier current_segment_id(0, -1, -1, -1);
306 bool entered = false;
307 std::size_t enter_count = 0;
309 for (TurnIterator it = first; it != beyond; ++it)
311 oit = process_turn(it, boost::begin(it->operations),
312 entered, enter_count,
314 current_piece, current_segment_id,
319 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
320 if (enter_count != 0)
322 BOOST_THROW_EXCEPTION(inconsistent_turns_exception());
325 BOOST_GEOMETRY_ASSERT(enter_count == 0);
328 return process_end(entered, linestring,
329 current_segment_id, current_piece,
340 typename LinestringOut,
341 typename MultiLinestring,
343 overlay_type OverlayType,
344 bool FollowIsolatedPoints,
345 bool FollowContinueTurns
347 class follow_multilinestring_linear_linestring
348 : follow_linestring_linear_linestring
351 typename boost::range_value<MultiLinestring>::type,
354 FollowIsolatedPoints,
359 typedef typename boost::range_value<MultiLinestring>::type Linestring;
361 typedef follow_linestring_linear_linestring
363 LinestringOut, Linestring, Linear,
364 OverlayType, FollowIsolatedPoints, FollowContinueTurns
367 typedef following::action_selector<OverlayType> action;
369 typedef typename boost::range_iterator
371 MultiLinestring const
372 >::type linestring_iterator;
375 template <typename OutputIt, overlay_type OT>
376 struct copy_linestrings_in_range
378 static inline OutputIt
379 apply(linestring_iterator, linestring_iterator, OutputIt oit)
385 template <typename OutputIt>
386 struct copy_linestrings_in_range<OutputIt, overlay_difference>
388 static inline OutputIt
389 apply(linestring_iterator first, linestring_iterator beyond,
392 for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
394 LinestringOut line_out;
395 geometry::convert(*ls_it, line_out);
402 template <typename TurnIterator>
403 static inline signed_size_type get_multi_index(TurnIterator it)
405 return boost::begin(it->operations)->seg_id.multi_index;
408 class has_other_multi_id
411 signed_size_type m_multi_id;
414 has_other_multi_id(signed_size_type multi_id)
415 : m_multi_id(multi_id) {}
417 template <typename Turn>
418 bool operator()(Turn const& turn) const
420 return boost::begin(turn.operations)->seg_id.multi_index
426 template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
427 static inline OutputIterator
428 apply(MultiLinestring const& multilinestring, Linear const& linear,
429 TurnIterator first, TurnIterator beyond,
431 SideStrategy const& strategy)
433 BOOST_GEOMETRY_ASSERT( first != beyond );
435 typedef copy_linestrings_in_range
437 OutputIterator, OverlayType
440 linestring_iterator ls_first = boost::begin(multilinestring);
441 linestring_iterator ls_beyond = boost::end(multilinestring);
443 // Iterate through all intersection points (they are
444 // ordered along the each linestring)
446 signed_size_type current_multi_id = get_multi_index(first);
448 oit = copy_linestrings::apply(ls_first,
449 ls_first + current_multi_id,
452 TurnIterator per_ls_next = first;
454 TurnIterator per_ls_current = per_ls_next;
456 // find turn with different multi-index
457 per_ls_next = std::find_if(per_ls_current, beyond,
458 has_other_multi_id(current_multi_id));
460 oit = Base::apply(*(ls_first + current_multi_id),
461 linear, per_ls_current, per_ls_next, oit, strategy);
463 signed_size_type next_multi_id = -1;
464 linestring_iterator ls_next = ls_beyond;
465 if ( per_ls_next != beyond )
467 next_multi_id = get_multi_index(per_ls_next);
468 ls_next = ls_first + next_multi_id;
470 oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
474 current_multi_id = next_multi_id;
476 while ( per_ls_next != beyond );
489 typename LinestringOut,
492 overlay_type OverlayType,
493 bool FollowIsolatedPoints,
494 bool FollowContinueTurns,
495 typename TagOut = typename tag<LinestringOut>::type,
496 typename TagIn1 = typename tag<Geometry1>::type
499 : not_implemented<LinestringOut, Geometry1>
506 typename LinestringOut,
509 overlay_type OverlayType,
510 bool FollowIsolatedPoints,
511 bool FollowContinueTurns
515 LinestringOut, Linestring, Linear,
516 OverlayType, FollowIsolatedPoints, FollowContinueTurns,
517 linestring_tag, linestring_tag
518 > : follow_linestring_linear_linestring
520 LinestringOut, Linestring, Linear,
521 OverlayType, FollowIsolatedPoints, FollowContinueTurns
528 typename LinestringOut,
529 typename MultiLinestring,
531 overlay_type OverlayType,
532 bool FollowIsolatedPoints,
533 bool FollowContinueTurns
537 LinestringOut, MultiLinestring, Linear,
538 OverlayType, FollowIsolatedPoints, FollowContinueTurns,
539 linestring_tag, multi_linestring_tag
540 > : follow_multilinestring_linear_linestring
542 LinestringOut, MultiLinestring, Linear,
543 OverlayType, FollowIsolatedPoints, FollowContinueTurns
549 }} // namespace following::linear
551 }} // namespace detail::overlay
552 #endif // DOXYGEN_NO_DETAIL
554 }} // namespace boost::geometry
557 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP