1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2014-2015, Oracle and/or its affiliates.
5 // Licensed under the Boost Software License version 1.0.
6 // http://www.boost.org/users/license.html
8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
10 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
11 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
17 #include <boost/range.hpp>
19 #include <boost/geometry/core/assert.hpp>
20 #include <boost/geometry/core/tag.hpp>
21 #include <boost/geometry/core/tags.hpp>
23 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
24 #include <boost/geometry/algorithms/detail/overlay/follow.hpp>
25 #include <boost/geometry/algorithms/detail/overlay/inconsistent_turns_exception.hpp>
26 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
27 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
28 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
30 #include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
32 #include <boost/geometry/algorithms/convert.hpp>
33 #include <boost/geometry/algorithms/not_implemented.hpp>
36 namespace boost { namespace geometry
39 #ifndef DOXYGEN_NO_DETAIL
40 namespace detail { namespace overlay
43 namespace following { namespace linear
49 // follower for linear/linear geometries set operations
51 template <typename Turn, typename Operation>
52 static inline bool is_entering(Turn const& turn,
53 Operation const& operation)
55 if ( turn.method != method_touch && turn.method != method_touch_interior )
59 return operation.operation == operation_intersection;
64 template <typename Turn, typename Operation>
65 static inline bool is_staying_inside(Turn const& turn,
66 Operation const& operation,
74 if ( turn.method != method_equal && turn.method != method_collinear )
78 return operation.operation == operation_continue;
83 template <typename Turn, typename Operation>
84 static inline bool is_leaving(Turn const& turn,
85 Operation const& operation,
93 if ( turn.method != method_touch
94 && turn.method != method_touch_interior
95 && turn.method != method_equal
96 && turn.method != method_collinear )
101 if ( operation.operation == operation_blocked )
106 if ( operation.operation != operation_union )
111 return operation.is_collinear;
116 template <typename Turn, typename Operation>
117 static inline bool is_isolated_point(Turn const& turn,
118 Operation const& operation,
126 if ( turn.method == method_none )
128 BOOST_GEOMETRY_ASSERT( operation.operation == operation_continue );
132 if ( turn.method == method_crosses )
137 if ( turn.method != method_touch && turn.method != method_touch_interior )
142 if ( operation.operation == operation_blocked )
147 if ( operation.operation != operation_union )
152 return !operation.is_collinear;
165 typename LinestringOut,
168 overlay_type OverlayType,
169 bool FollowIsolatedPoints,
170 bool FollowContinueTurns
172 class follow_linestring_linear_linestring
175 // allow spikes (false indicates: do not remove spikes)
176 typedef following::action_selector<OverlayType, false> action;
180 typename TurnIterator,
181 typename TurnOperationIterator,
182 typename SegmentIdentifier,
183 typename OutputIterator
185 static inline OutputIterator
186 process_turn(TurnIterator it,
187 TurnOperationIterator op_it,
189 std::size_t& enter_count,
190 Linestring const& linestring,
191 LinestringOut& current_piece,
192 SegmentIdentifier& current_segment_id,
195 // We don't rescale linear/linear
196 detail::no_rescale_policy robust_policy;
198 if ( is_entering(*it, *op_it) )
200 detail::turns::debug_turn(*it, *op_it, "-> Entering");
203 if ( enter_count == 0 )
205 action::enter(current_piece, linestring,
207 op_it->seg_id.segment_index,
208 it->point, *op_it, robust_policy, oit);
212 else if ( is_leaving(*it, *op_it, entered) )
214 detail::turns::debug_turn(*it, *op_it, "-> Leaving");
217 if ( enter_count == 0 )
220 action::leave(current_piece, linestring,
222 op_it->seg_id.segment_index,
223 it->point, *op_it, robust_policy, oit);
226 else if ( FollowIsolatedPoints
227 && is_isolated_point(*it, *op_it, entered) )
229 detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
231 action::isolated_point(current_piece, linestring,
233 op_it->seg_id.segment_index,
234 it->point, *op_it, oit);
236 else if ( FollowContinueTurns
237 && is_staying_inside(*it, *op_it, entered) )
239 detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
248 typename SegmentIdentifier,
249 typename OutputIterator
251 static inline OutputIterator
252 process_end(bool entered,
253 Linestring const& linestring,
254 SegmentIdentifier const& current_segment_id,
255 LinestringOut& current_piece,
258 if ( action::is_entered(entered) )
260 // We don't rescale linear/linear
261 detail::no_rescale_policy robust_policy;
263 detail::copy_segments::copy_segments_linestring
265 false, false // do not reverse; do not remove spikes
268 static_cast<signed_size_type>(boost::size(linestring) - 1),
273 // Output the last one, if applicable
274 if (::boost::size(current_piece) > 1)
276 *oit++ = current_piece;
283 template <typename TurnIterator, typename OutputIterator>
284 static inline OutputIterator
285 apply(Linestring const& linestring, Linear const&,
286 TurnIterator first, TurnIterator beyond,
289 // Iterate through all intersection points (they are
290 // ordered along the each line)
292 LinestringOut current_piece;
293 geometry::segment_identifier current_segment_id(0, -1, -1, -1);
295 bool entered = false;
296 std::size_t enter_count = 0;
298 for (TurnIterator it = first; it != beyond; ++it)
300 oit = process_turn(it, boost::begin(it->operations),
301 entered, enter_count,
303 current_piece, current_segment_id,
307 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
308 if (enter_count != 0)
310 throw inconsistent_turns_exception();
313 BOOST_GEOMETRY_ASSERT(enter_count == 0);
316 return process_end(entered, linestring,
317 current_segment_id, current_piece,
327 typename LinestringOut,
328 typename MultiLinestring,
330 overlay_type OverlayType,
331 bool FollowIsolatedPoints,
332 bool FollowContinueTurns
334 class follow_multilinestring_linear_linestring
335 : follow_linestring_linear_linestring
338 typename boost::range_value<MultiLinestring>::type,
341 FollowIsolatedPoints,
346 typedef typename boost::range_value<MultiLinestring>::type Linestring;
348 typedef follow_linestring_linear_linestring
350 LinestringOut, Linestring, Linear,
351 OverlayType, FollowIsolatedPoints, FollowContinueTurns
354 typedef following::action_selector<OverlayType> action;
356 typedef typename boost::range_iterator
358 MultiLinestring const
359 >::type linestring_iterator;
362 template <typename OutputIt, overlay_type OT>
363 struct copy_linestrings_in_range
365 static inline OutputIt
366 apply(linestring_iterator, linestring_iterator, OutputIt oit)
372 template <typename OutputIt>
373 struct copy_linestrings_in_range<OutputIt, overlay_difference>
375 static inline OutputIt
376 apply(linestring_iterator first, linestring_iterator beyond,
379 for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
381 LinestringOut line_out;
382 geometry::convert(*ls_it, line_out);
389 template <typename TurnIterator>
390 static inline signed_size_type get_multi_index(TurnIterator it)
392 return boost::begin(it->operations)->seg_id.multi_index;
395 class has_other_multi_id
398 signed_size_type m_multi_id;
401 has_other_multi_id(signed_size_type multi_id)
402 : m_multi_id(multi_id) {}
404 template <typename Turn>
405 bool operator()(Turn const& turn) const
407 return boost::begin(turn.operations)->seg_id.multi_index
413 template <typename TurnIterator, typename OutputIterator>
414 static inline OutputIterator
415 apply(MultiLinestring const& multilinestring, Linear const& linear,
416 TurnIterator first, TurnIterator beyond,
419 BOOST_GEOMETRY_ASSERT( first != beyond );
421 typedef copy_linestrings_in_range
423 OutputIterator, OverlayType
426 linestring_iterator ls_first = boost::begin(multilinestring);
427 linestring_iterator ls_beyond = boost::end(multilinestring);
429 // Iterate through all intersection points (they are
430 // ordered along the each linestring)
432 signed_size_type current_multi_id = get_multi_index(first);
434 oit = copy_linestrings::apply(ls_first,
435 ls_first + current_multi_id,
438 TurnIterator per_ls_next = first;
440 TurnIterator per_ls_current = per_ls_next;
442 // find turn with different multi-index
443 per_ls_next = std::find_if(per_ls_current, beyond,
444 has_other_multi_id(current_multi_id));
446 oit = Base::apply(*(ls_first + current_multi_id),
447 linear, per_ls_current, per_ls_next, oit);
449 signed_size_type next_multi_id = -1;
450 linestring_iterator ls_next = ls_beyond;
451 if ( per_ls_next != beyond )
453 next_multi_id = get_multi_index(per_ls_next);
454 ls_next = ls_first + next_multi_id;
456 oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
460 current_multi_id = next_multi_id;
462 while ( per_ls_next != beyond );
475 typename LinestringOut,
478 overlay_type OverlayType,
479 bool FollowIsolatedPoints,
480 bool FollowContinueTurns,
481 typename TagOut = typename tag<LinestringOut>::type,
482 typename TagIn1 = typename tag<Geometry1>::type
485 : not_implemented<LinestringOut, Geometry1>
492 typename LinestringOut,
495 overlay_type OverlayType,
496 bool FollowIsolatedPoints,
497 bool FollowContinueTurns
501 LinestringOut, Linestring, Linear,
502 OverlayType, FollowIsolatedPoints, FollowContinueTurns,
503 linestring_tag, linestring_tag
504 > : follow_linestring_linear_linestring
506 LinestringOut, Linestring, Linear,
507 OverlayType, FollowIsolatedPoints, FollowContinueTurns
514 typename LinestringOut,
515 typename MultiLinestring,
517 overlay_type OverlayType,
518 bool FollowIsolatedPoints,
519 bool FollowContinueTurns
523 LinestringOut, MultiLinestring, Linear,
524 OverlayType, FollowIsolatedPoints, FollowContinueTurns,
525 linestring_tag, multi_linestring_tag
526 > : follow_multilinestring_linear_linestring
528 LinestringOut, MultiLinestring, Linear,
529 OverlayType, FollowIsolatedPoints, FollowContinueTurns
535 }} // namespace following::linear
537 }} // namespace detail::overlay
538 #endif // DOXYGEN_NO_DETAIL
540 }} // namespace boost::geometry
543 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP