1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2014.
6 // Modifications copyright (c) 2014 Oracle and/or its affiliates.
8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
19 #include <boost/range.hpp>
20 #include <boost/mpl/assert.hpp>
22 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
23 #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
24 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
25 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
27 #include <boost/geometry/algorithms/covered_by.hpp>
28 #include <boost/geometry/algorithms/clear.hpp>
31 namespace boost { namespace geometry
35 #ifndef DOXYGEN_NO_DETAIL
36 namespace detail { namespace overlay
42 template <typename Turn, typename Operation>
43 static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
45 // (Blocked means: blocked for polygon/polygon intersection, because
46 // they are reversed. But for polygon/line it is similar to continue)
47 return op.operation == operation_intersection
48 || op.operation == operation_continue
49 || op.operation == operation_blocked
60 static inline bool last_covered_by(Turn const& turn, Operation const& op,
61 LineString const& linestring, Polygon const& polygon)
63 // Check any point between the this one and the first IP
64 typedef typename geometry::point_type<LineString>::type point_type;
65 point_type point_in_between;
66 detail::point_on_border::midpoint_helper
69 0, dimension<point_type>::value
70 >::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
72 return geometry::covered_by(point_in_between, polygon);
83 static inline bool is_leaving(Turn const& turn, Operation const& op,
84 bool entered, bool first,
85 LineString const& linestring, Polygon const& polygon)
87 if (op.operation == operation_union)
90 || turn.method == method_crosses
91 || (first && last_covered_by(turn, op, linestring, polygon))
105 static inline bool is_staying_inside(Turn const& turn, Operation const& op,
106 bool entered, bool first,
107 LineString const& linestring, Polygon const& polygon)
109 if (turn.method == method_crosses)
111 // The normal case, this is completely covered with entering/leaving
112 // so stay out of this time consuming "covered_by"
116 if (is_entering(turn, op))
118 return entered || (first && last_covered_by(turn, op, linestring, polygon));
131 static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
132 Linestring const& linestring, Polygon const& polygon)
134 if (first && (turn.method == method_collinear || turn.method == method_equal))
136 return last_covered_by(turn, op, linestring, polygon);
142 // Template specialization structure to call the right actions for the right type
143 template <overlay_type OverlayType, bool RemoveSpikes = true>
144 struct action_selector
146 // If you get here the overlay type is not intersection or difference
147 // BOOST_MPL_ASSERT(false);
150 // Specialization for intersection, containing the implementation
151 template <bool RemoveSpikes>
152 struct action_selector<overlay_intersection, RemoveSpikes>
156 typename OutputIterator,
157 typename LineStringOut,
161 typename RobustPolicy
163 static inline void enter(LineStringOut& current_piece,
165 segment_identifier& segment_id,
166 signed_size_type , Point const& point,
167 Operation const& operation,
168 RobustPolicy const& ,
171 // On enter, append the intersection point and remember starting point
172 // TODO: we don't check on spikes for linestrings (?). Consider this.
173 detail::overlay::append_no_duplicates(current_piece, point);
174 segment_id = operation.seg_id;
179 typename OutputIterator,
180 typename LineStringOut,
184 typename RobustPolicy
186 static inline void leave(LineStringOut& current_piece,
187 LineString const& linestring,
188 segment_identifier& segment_id,
189 signed_size_type index, Point const& point,
191 RobustPolicy const& robust_policy,
194 // On leave, copy all segments from starting point, append the intersection point
195 // and add the output piece
196 detail::copy_segments::copy_segments_linestring
199 >::apply(linestring, segment_id, index, robust_policy, current_piece);
200 detail::overlay::append_no_duplicates(current_piece, point);
201 if (::boost::size(current_piece) > 1)
203 *out++ = current_piece;
206 geometry::clear(current_piece);
211 typename OutputIterator,
212 typename LineStringOut,
217 static inline void isolated_point(LineStringOut&,
220 signed_size_type, Point const& point,
221 Operation const& , OutputIterator& out)
223 LineStringOut isolated_point_ls;
224 geometry::append(isolated_point_ls, point);
226 #ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
227 geometry::append(isolated_point_ls, point);
228 #endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
230 *out++ = isolated_point_ls;
233 static inline bool is_entered(bool entered)
242 typename RobustPolicy
244 static inline bool included(Point const& point,
245 Geometry const& geometry,
246 RobustPolicy const& )
248 return geometry::covered_by(point, geometry);
253 // Specialization for difference, which reverses these actions
254 template <bool RemoveSpikes>
255 struct action_selector<overlay_difference, RemoveSpikes>
257 typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
261 typename OutputIterator,
262 typename LineStringOut,
266 typename RobustPolicy
268 static inline void enter(LineStringOut& current_piece,
269 LineString const& linestring,
270 segment_identifier& segment_id,
271 signed_size_type index, Point const& point,
272 Operation const& operation,
273 RobustPolicy const& robust_policy,
276 normal_action::leave(current_piece, linestring, segment_id, index,
277 point, operation, robust_policy, out);
282 typename OutputIterator,
283 typename LineStringOut,
287 typename RobustPolicy
289 static inline void leave(LineStringOut& current_piece,
290 LineString const& linestring,
291 segment_identifier& segment_id,
292 signed_size_type index, Point const& point,
293 Operation const& operation,
294 RobustPolicy const& robust_policy,
297 normal_action::enter(current_piece, linestring, segment_id, index,
298 point, operation, robust_policy, out);
303 typename OutputIterator,
304 typename LineStringOut,
309 static inline void isolated_point(LineStringOut&,
312 signed_size_type, Point const&,
313 Operation const&, OutputIterator&)
317 static inline bool is_entered(bool entered)
319 return ! normal_action::is_entered(entered);
326 typename RobustPolicy
328 static inline bool included(Point const& point,
329 Geometry const& geometry,
330 RobustPolicy const& robust_policy)
332 return ! normal_action::included(point, geometry, robust_policy);
340 \brief Follows a linestring from intersection point to intersection point, outputting which
341 is inside, or outside, a ring or polygon
346 typename LineStringOut,
349 overlay_type OverlayType,
350 bool RemoveSpikes = true
355 template <typename Turn>
356 struct sort_on_segment
358 // In case of turn point at the same location, we want to have continue/blocked LAST
359 // because that should be followed (intersection) or skipped (difference).
360 inline int operation_order(Turn const& turn) const
362 operation_type const& operation = turn.operations[0].operation;
365 case operation_opposite : return 0;
366 case operation_none : return 0;
367 case operation_union : return 1;
368 case operation_intersection : return 2;
369 case operation_blocked : return 3;
370 case operation_continue : return 4;
375 inline bool use_operation(Turn const& left, Turn const& right) const
377 // If they are the same, OK.
378 return operation_order(left) < operation_order(right);
381 inline bool use_distance(Turn const& left, Turn const& right) const
383 return left.operations[0].fraction == right.operations[0].fraction
384 ? use_operation(left, right)
385 : left.operations[0].fraction < right.operations[0].fraction
389 inline bool operator()(Turn const& left, Turn const& right) const
391 segment_identifier const& sl = left.operations[0].seg_id;
392 segment_identifier const& sr = right.operations[0].seg_id;
395 ? use_distance(left, right)
410 typename RobustPolicy
412 static inline bool included(Point const& point,
413 Geometry const& geometry,
414 RobustPolicy const& robust_policy)
416 return following::action_selector
418 OverlayType, RemoveSpikes
419 >::included(point, geometry, robust_policy);
425 typename OutputIterator,
426 typename RobustPolicy
428 static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
429 detail::overlay::operation_type , // TODO: this parameter might be redundant
431 RobustPolicy const& robust_policy,
434 typedef typename boost::range_iterator<Turns>::type turn_iterator;
435 typedef typename boost::range_value<Turns>::type turn_type;
436 typedef typename boost::range_iterator
438 typename turn_type::container_type
439 >::type turn_operation_iterator_type;
441 typedef following::action_selector<OverlayType, RemoveSpikes> action;
443 // Sort intersection points on segments-along-linestring, and distance
444 // (like in enrich is done for poly/poly)
445 std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
447 LineStringOut current_piece;
448 geometry::segment_identifier current_segment_id(0, -1, -1, -1);
450 // Iterate through all intersection points (they are ordered along the line)
451 bool entered = false;
453 for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
455 turn_operation_iterator_type iit = boost::begin(it->operations);
457 if (following::was_entered(*it, *iit, first, linestring, polygon))
459 debug_traverse(*it, *iit, "-> Was entered");
463 if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon))
465 debug_traverse(*it, *iit, "-> Staying inside");
469 else if (following::is_entering(*it, *iit))
471 debug_traverse(*it, *iit, "-> Entering");
474 action::enter(current_piece, linestring, current_segment_id,
475 iit->seg_id.segment_index, it->point, *iit,
479 else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
481 debug_traverse(*it, *iit, "-> Leaving");
484 action::leave(current_piece, linestring, current_segment_id,
485 iit->seg_id.segment_index, it->point, *iit,
492 if (action::is_entered(entered))
494 detail::copy_segments::copy_segments_linestring
499 static_cast<signed_size_type>(boost::size(linestring) - 1),
504 // Output the last one, if applicable
505 if (::boost::size(current_piece) > 1)
507 *out++ = current_piece;
515 }} // namespace detail::overlay
516 #endif // DOXYGEN_NO_DETAIL
519 }} // namespace boost::geometry
522 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP