diff --git a/include/boost/geometry/algorithms/detail/overlay/follow.hpp b/include/boost/geometry/algorithms/detail/overlay/follow.hpp index 6d65dab81..6062cfaab 100644 --- a/include/boost/geometry/algorithms/detail/overlay/follow.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/follow.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -28,7 +29,7 @@ namespace boost { namespace geometry namespace detail { namespace overlay { - + /*! \brief Follows a linestring from intersection point to intersection point, outputting which @@ -39,7 +40,8 @@ template < typename LineStringOut, typename LineString, - typename Polygon + typename Polygon, + overlay_type OverlayType > class follow { @@ -119,7 +121,94 @@ class follow return false; } + // Template specialization structure to call the right actions for the right type + template + struct action_selector + { + // If you get here the overlay type is not intersection or difference + BOOST_MPL_ASSERT(false); + }; + + // Specialization for intersection, containing the implementation + template<> + struct action_selector + { + template + static inline void enter(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, int index, Point const& point, Operation const& operation, OutputIterator& out) + { + // On enter, append the intersection point and remember starting point + detail::overlay::append_no_duplicates(current_piece, point); + segment_id = operation.seg_id; + } + + template + static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, int index, Point const& point, Operation const& operation, OutputIterator& out) + { + // On leave, copy all segments from starting point, append the intersection point + // and add the output piece + geometry::copy_segments(linestring, segment_id, index, current_piece); + detail::overlay::append_no_duplicates(current_piece, point); + if (! current_piece.empty()) + { + *out++ = current_piece; + current_piece.clear(); + } + } + + static inline bool is_entered(bool entered) + { + return entered; + } + + template + static inline bool included(Point const& point, Geometry const& geometry) + { + return geometry::within(point, geometry); + } + + }; + + // Specialization for difference, which reverses these actions + template<> + struct action_selector + { + typedef action_selector normal_action; + + template + static inline void enter(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, int index, Point const& point, Operation const& operation, OutputIterator& out) + { + normal_action::leave(current_piece, linestring, segment_id, index, point, operation, out); + } + + template + static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, int index, Point const& point, Operation const& operation, OutputIterator& out) + { + normal_action::enter(current_piece, linestring, segment_id, index, point, operation, out); + } + + static inline bool is_entered(bool entered) + { + return ! normal_action::is_entered(entered); + } + + template + static inline bool included(Point const& point, Geometry const& geometry) + { + return ! normal_action::included(point, geometry); + } + + }; + + + public : + + template + static inline bool included(Point const& point, Geometry const& geometry) + { + return action_selector::included(point, geometry); + } + template static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon, detail::overlay::operation_type operation, @@ -132,7 +221,6 @@ public : typename turn_type::container_type >::type turn_operation_iterator_type; - // Sort intersection points on segments-along-linestring, and distance // (like in enrich is done for poly/poly) std::sort(boost::begin(turns), boost::end(turns), sort_on_segment()); @@ -164,42 +252,33 @@ public : debug_traverse(*it, *iit, "-> Entering"); entered = true; - detail::overlay::append_no_duplicates(current_piece, it->point); - current_segment_id = iit->seg_id; + action_selector::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out); } else if (is_leaving(*it, *iit, entered, first, linestring, polygon)) { debug_traverse(*it, *iit, "-> Leaving"); entered = false; - geometry::copy_segments(linestring, current_segment_id, - iit->seg_id.segment_index, - current_piece); - detail::overlay::append_no_duplicates(current_piece, it->point); - - if (! current_piece.empty()) - { - *out++ = current_piece; - current_piece.clear(); - } + action_selector::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out); } first = false; } - if (entered) + if (action_selector::is_entered(entered)) { - geometry::copy_segments(linestring, current_segment_id, + geometry::copy_segments(linestring, current_segment_id, boost::size(linestring) - 1, current_piece); } - // Add the last one, if applicable + // Output the last one, if applicable if (! current_piece.empty()) { *out++ = current_piece; } return out; } + }; diff --git a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index c16cc1e36..644e09140 100644 --- a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -29,6 +29,9 @@ #include #include +#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) +#include +#endif namespace boost { namespace geometry { @@ -111,10 +114,18 @@ template typename LineString, typename Areal, bool ReverseAreal, typename OutputIterator, typename LineStringOut, + overlay_type OverlayType, typename Strategy > struct intersection_of_linestring_with_areal { + typedef detail::overlay::follow + < + LineStringOut, + LineString, + Areal, + OverlayType + > follower; #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) template @@ -150,14 +161,17 @@ struct intersection_of_linestring_with_areal detail::get_turns::no_interrupt_policy policy; geometry::get_turns < - false, ReverseAreal, detail::overlay::calculate_distance_policy + false, + (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal), + detail::overlay::calculate_distance_policy >(linestring, areal, turns, policy); if (turns.empty()) { - // No intersection points, it is either completely inside + // No intersection points, it is either completely + // inside (interior + borders) // or completely outside - if (geometry::within(linestring[0], areal)) + if (follower::included(*boost::begin(linestring), areal)) { LineStringOut copy; geometry::convert(linestring, copy); @@ -174,12 +188,7 @@ struct intersection_of_linestring_with_areal } #endif - return detail::overlay::follow - < - LineStringOut, - LineString, - Areal - >::apply + return follower::apply ( linestring, areal, geometry::detail::overlay::operation_intersection, @@ -374,6 +383,7 @@ struct intersection_insert Linestring, Polygon, ReversePolygon, OutputIterator, GeometryOut, + OverlayType, Strategy > {}; @@ -401,6 +411,7 @@ struct intersection_insert Linestring, Ring, ReverseRing, OutputIterator, GeometryOut, + OverlayType, Strategy > {}; diff --git a/include/boost/geometry/multi/algorithms/intersection.hpp b/include/boost/geometry/multi/algorithms/intersection.hpp index 5198535aa..a9e7ce6a2 100644 --- a/include/boost/geometry/multi/algorithms/intersection.hpp +++ b/include/boost/geometry/multi/algorithms/intersection.hpp @@ -116,6 +116,7 @@ template typename MultiLinestring, typename Areal, bool ReverseAreal, typename OutputIterator, typename LineStringOut, + overlay_type OverlayType, typename Strategy > struct intersection_of_multi_linestring_with_areal @@ -135,7 +136,7 @@ struct intersection_of_multi_linestring_with_areal < typename boost::range_value::type, Areal, ReverseAreal, - OutputIterator, LineStringOut, Strategy + OutputIterator, LineStringOut, OverlayType, Strategy >::apply(*it, areal, out, strategy); } @@ -150,6 +151,7 @@ template typename Areal, typename MultiLinestring, bool ReverseAreal, typename OutputIterator, typename LineStringOut, + overlay_type OverlayType, typename Strategy > struct intersection_of_areal_with_multi_linestring @@ -162,6 +164,7 @@ struct intersection_of_areal_with_multi_linestring < MultiLinestring, Areal, ReverseAreal, OutputIterator, LineStringOut, + OverlayType, Strategy >::apply(ml, areal, out, strategy); } @@ -304,6 +307,7 @@ struct intersection_insert Linestring, MultiPolygon, ReverseMultiPolygon, OutputIterator, GeometryOut, + OverlayType, Strategy > {}; @@ -333,6 +337,7 @@ struct intersection_insert Polygon, MultiLinestring, ReversePolygon, OutputIterator, GeometryOut, + OverlayType, Strategy > {}; @@ -360,6 +365,7 @@ struct intersection_insert MultiLinestring, Ring, ReverseRing, OutputIterator, GeometryOut, + OverlayType, Strategy > {}; @@ -389,6 +395,7 @@ struct intersection_insert MultiLinestring, MultiPolygon, ReverseMultiPolygon, OutputIterator, GeometryOut, + OverlayType, Strategy > {};