1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
6 // This file was modified by Oracle on 2014, 2017, 2018, 2019, 2020.
7 // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates.
8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
20 #include <boost/range.hpp>
21 #include <boost/mpl/assert.hpp>
23 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
24 #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
25 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
26 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
28 #include <boost/geometry/algorithms/covered_by.hpp>
29 #include <boost/geometry/algorithms/clear.hpp>
30 #include <boost/geometry/algorithms/detail/relate/turns.hpp>
31 #include <boost/geometry/algorithms/detail/tupled_output.hpp>
33 namespace boost { namespace geometry
37 #ifndef DOXYGEN_NO_DETAIL
38 namespace detail { namespace overlay
44 template <typename Turn, typename Operation>
45 inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
47 // (Blocked means: blocked for polygon/polygon intersection, because
48 // they are reversed. But for polygon/line it is similar to continue)
49 return op.operation == operation_intersection
50 || op.operation == operation_continue
51 || op.operation == operation_blocked
61 typename PtInPolyStrategy
63 inline bool last_covered_by(Turn const& /*turn*/, Operation const& op,
64 LineString const& linestring, Polygon const& polygon,
65 PtInPolyStrategy const& strategy)
67 return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy);
77 typename PtInPolyStrategy
79 inline bool is_leaving(Turn const& turn, Operation const& op,
80 bool entered, bool first,
81 LineString const& linestring, Polygon const& polygon,
82 PtInPolyStrategy const& strategy)
84 if (op.operation == operation_union)
87 || turn.method == method_crosses
89 && op.position != position_front
90 && last_covered_by(turn, op, linestring, polygon, strategy))
103 typename PtInPolyStrategy
105 inline bool is_staying_inside(Turn const& turn, Operation const& op,
106 bool entered, bool first,
107 LineString const& linestring, Polygon const& polygon,
108 PtInPolyStrategy const& strategy)
110 if (turn.method == method_crosses)
112 // The normal case, this is completely covered with entering/leaving
113 // so stay out of this time consuming "covered_by"
117 if (is_entering(turn, op))
119 return entered || (first && last_covered_by(turn, op, linestring, polygon, strategy));
131 typename PtInPolyStrategy
133 inline bool was_entered(Turn const& turn, Operation const& op, bool first,
134 Linestring const& linestring, Polygon const& polygon,
135 PtInPolyStrategy const& strategy)
137 if (first && (turn.method == method_collinear || turn.method == method_equal))
139 return last_covered_by(turn, op, linestring, polygon, strategy);
149 inline bool is_touching(Turn const& turn, Operation const& op,
152 return (op.operation == operation_union || op.operation == operation_blocked)
153 && (turn.method == method_touch || turn.method == method_touch_interior)
161 typename GeometryOut,
162 typename Tag = typename geometry::tag<GeometryOut>::type
164 struct add_isolated_point
167 template <typename LineStringOut>
168 struct add_isolated_point<LineStringOut, linestring_tag>
170 template <typename Point, typename OutputIterator>
171 static inline void apply(Point const& point, OutputIterator& out)
173 LineStringOut isolated_point_ls;
174 geometry::append(isolated_point_ls, point);
176 #ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
177 geometry::append(isolated_point_ls, point);
178 #endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
180 *out++ = isolated_point_ls;
184 template <typename PointOut>
185 struct add_isolated_point<PointOut, point_tag>
187 template <typename Point, typename OutputIterator>
188 static inline void apply(Point const& point, OutputIterator& out)
190 PointOut isolated_point;
192 geometry::detail::conversion::convert_point_to_point(point, isolated_point);
194 *out++ = isolated_point;
199 // Template specialization structure to call the right actions for the right type
200 template <overlay_type OverlayType, bool RemoveSpikes = true>
201 struct action_selector
203 // If you get here the overlay type is not intersection or difference
204 // BOOST_MPL_ASSERT(false);
207 // Specialization for intersection, containing the implementation
208 template <bool RemoveSpikes>
209 struct action_selector<overlay_intersection, RemoveSpikes>
213 typename OutputIterator,
214 typename LineStringOut,
219 typename RobustPolicy
221 static inline void enter(LineStringOut& current_piece,
223 segment_identifier& segment_id,
224 signed_size_type , Point const& point,
225 Operation const& operation,
226 Strategy const& strategy,
227 RobustPolicy const& ,
230 // On enter, append the intersection point and remember starting point
231 // TODO: we don't check on spikes for linestrings (?). Consider this.
232 detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
233 segment_id = operation.seg_id;
238 typename OutputIterator,
239 typename LineStringOut,
244 typename RobustPolicy
246 static inline void leave(LineStringOut& current_piece,
247 LineString const& linestring,
248 segment_identifier& segment_id,
249 signed_size_type index, Point const& point,
251 Strategy const& strategy,
252 RobustPolicy const& robust_policy,
255 // On leave, copy all segments from starting point, append the intersection point
256 // and add the output piece
257 detail::copy_segments::copy_segments_linestring
260 >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
261 detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
262 if (::boost::size(current_piece) > 1)
264 *out++ = current_piece;
267 geometry::clear(current_piece);
272 typename LineStringOrPointOut,
274 typename OutputIterator
276 static inline void isolated_point(Point const& point,
279 add_isolated_point<LineStringOrPointOut>::apply(point, out);
282 static inline bool is_entered(bool entered)
287 static inline bool included(int inside_value)
289 return inside_value >= 0; // covered_by
294 // Specialization for difference, which reverses these actions
295 template <bool RemoveSpikes>
296 struct action_selector<overlay_difference, RemoveSpikes>
298 typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
302 typename OutputIterator,
303 typename LineStringOut,
308 typename RobustPolicy
310 static inline void enter(LineStringOut& current_piece,
311 LineString const& linestring,
312 segment_identifier& segment_id,
313 signed_size_type index, Point const& point,
314 Operation const& operation,
315 Strategy const& strategy,
316 RobustPolicy const& robust_policy,
319 normal_action::leave(current_piece, linestring, segment_id, index,
320 point, operation, strategy, robust_policy, out);
325 typename OutputIterator,
326 typename LineStringOut,
331 typename RobustPolicy
333 static inline void leave(LineStringOut& current_piece,
334 LineString const& linestring,
335 segment_identifier& segment_id,
336 signed_size_type index, Point const& point,
337 Operation const& operation,
338 Strategy const& strategy,
339 RobustPolicy const& robust_policy,
342 normal_action::enter(current_piece, linestring, segment_id, index,
343 point, operation, strategy, robust_policy, out);
348 typename LineStringOrPointOut,
350 typename OutputIterator
352 static inline void isolated_point(Point const&,
353 OutputIterator const&)
357 static inline bool is_entered(bool entered)
359 return ! normal_action::is_entered(entered);
362 static inline bool included(int inside_value)
364 return ! normal_action::included(inside_value);
369 } // namespace following
372 \brief Follows a linestring from intersection point to intersection point, outputting which
373 is inside, or outside, a ring or polygon
378 typename GeometryOut,
381 overlay_type OverlayType,
383 bool FollowIsolatedPoints
387 typedef geometry::detail::output_geometry_access
389 GeometryOut, linestring_tag, linestring_tag
391 typedef geometry::detail::output_geometry_access
393 GeometryOut, point_tag, linestring_tag
398 static inline bool included(int inside_value)
400 return following::action_selector
402 OverlayType, RemoveSpikes
403 >::included(inside_value);
409 typename OutputIterator,
410 typename RobustPolicy,
413 static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
414 detail::overlay::operation_type , // TODO: this parameter might be redundant
416 RobustPolicy const& robust_policy,
418 Strategy const& strategy)
420 typedef typename boost::range_iterator<Turns>::type turn_iterator;
421 typedef typename boost::range_value<Turns>::type turn_type;
422 typedef typename boost::range_iterator
424 typename turn_type::container_type
425 >::type turn_operation_iterator_type;
427 typedef following::action_selector<OverlayType, RemoveSpikes> action;
429 typedef typename Strategy::cs_tag cs_tag;
431 typename Strategy::template point_in_geometry_strategy
434 >::type const pt_in_poly_strategy
435 = strategy.template get_point_in_geometry_strategy<LineString, Polygon>();
437 // Sort intersection points on segments-along-linestring, and distance
438 // (like in enrich is done for poly/poly)
439 // sort turns by Linear seg_id, then by fraction, then
440 // for same ring id: x, u, i, c
441 // for different ring id: c, i, u, x
442 typedef relate::turns::less
444 0, relate::turns::less_op_linear_areal_single<0>, cs_tag
446 std::sort(boost::begin(turns), boost::end(turns), turn_less());
448 typename linear::type current_piece;
449 geometry::segment_identifier current_segment_id(0, -1, -1, -1);
451 // Iterate through all intersection points (they are ordered along the line)
452 bool entered = false;
454 for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
456 turn_operation_iterator_type iit = boost::begin(it->operations);
458 if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy))
460 debug_traverse(*it, *iit, "-> Was entered");
464 if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
466 debug_traverse(*it, *iit, "-> Staying inside");
470 else if (following::is_entering(*it, *iit))
472 debug_traverse(*it, *iit, "-> Entering");
475 action::enter(current_piece, linestring, current_segment_id,
476 iit->seg_id.segment_index, it->point, *iit,
477 strategy, robust_policy,
480 else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
482 debug_traverse(*it, *iit, "-> Leaving");
485 action::leave(current_piece, linestring, current_segment_id,
486 iit->seg_id.segment_index, it->point, *iit,
487 strategy, robust_policy,
490 else if (FollowIsolatedPoints
491 && following::is_touching(*it, *iit, entered))
493 debug_traverse(*it, *iit, "-> Isolated point");
495 action::template isolated_point
497 typename pointlike::type
498 >(it->point, pointlike::get(out));
504 if (action::is_entered(entered))
506 detail::copy_segments::copy_segments_linestring
511 static_cast<signed_size_type>(boost::size(linestring) - 1),
512 strategy, robust_policy,
516 // Output the last one, if applicable
517 std::size_t current_piece_size = ::boost::size(current_piece);
518 if (current_piece_size > 1)
520 *linear::get(out)++ = current_piece;
522 else if (FollowIsolatedPoints
523 && current_piece_size == 1)
525 action::template isolated_point
527 typename pointlike::type
528 >(range::front(current_piece), pointlike::get(out));
537 }} // namespace detail::overlay
538 #endif // DOXYGEN_NO_DETAIL
541 }} // namespace boost::geometry
544 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP