// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP #include <cstddef> #include <deque> #include <type_traits> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/overlay/clip_linestring.hpp> #include <boost/geometry/algorithms/detail/overlay/follow.hpp> #include <boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp> #include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp> #include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/policies/robustness/rescale_policy_tags.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> #include <boost/geometry/strategies/relate/services.hpp> #include <boost/geometry/views/segment_view.hpp> #include <boost/geometry/views/detail/boundary_view.hpp> #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> #include <boost/geometry/io/wkt/wkt.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { template <typename PointOut> struct intersection_segment_segment_point { template < typename Segment1, typename Segment2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Segment1 const& segment1, Segment2 const& segment2, RobustPolicy const& , OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); typedef typename point_type<PointOut>::type point_type; // Get the intersection point (or two points) typedef segment_intersection_points<point_type> intersection_return_type; typedef policies::relate::segments_intersection_points < intersection_return_type > policy_type; detail::segment_as_subrange<Segment1> sub_range1(segment1); detail::segment_as_subrange<Segment2> sub_range2(segment2); intersection_return_type is = strategy.relate().apply(sub_range1, sub_range2, policy_type()); for (std::size_t i = 0; i < is.count; i++) { PointOut p; geometry::convert(is.intersections[i], p); *out++ = p; } return out; } }; template <typename PointOut> struct intersection_linestring_linestring_point { template < typename Linestring1, typename Linestring2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linestring1 const& linestring1, Linestring2 const& linestring2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); typedef detail::overlay::turn_info<PointOut> turn_info; std::deque<turn_info> turns; geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns, strategy); for (typename boost::range_iterator<std::deque<turn_info> const>::type it = boost::begin(turns); it != boost::end(turns); ++it) { PointOut p; geometry::convert(it->point, p); *out++ = p; } return out; } }; /*! \brief Version of linestring with an areal feature (polygon or multipolygon) */ template < bool ReverseAreal, typename GeometryOut, overlay_type OverlayType, bool FollowIsolatedPoints > struct intersection_of_linestring_with_areal { #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) template <typename Turn, typename Operation> static inline void debug_follow(Turn const& turn, Operation op, int index) { std::cout << index << " at " << op.seg_id << " meth: " << method_char(turn.method) << " op: " << operation_char(op.operation) << " vis: " << visited_char(op.visited) << " of: " << operation_char(turn.operations[0].operation) << operation_char(turn.operations[1].operation) << " " << geometry::wkt(turn.point) << std::endl; } template <typename Turn> static inline void debug_turn(Turn const& t, bool non_crossing) { std::cout << "checking turn @" << geometry::wkt(t.point) << "; " << method_char(t.method) << ":" << operation_char(t.operations[0].operation) << "/" << operation_char(t.operations[1].operation) << "; non-crossing? " << std::boolalpha << non_crossing << std::noboolalpha << std::endl; } #endif template <typename Linestring, typename Areal, typename Strategy, typename Turns> static inline bool simple_turns_analysis(Linestring const& linestring, Areal const& areal, Strategy const& strategy, Turns const& turns, int & inside_value) { using namespace overlay; bool found_continue = false; bool found_intersection = false; bool found_union = false; bool found_front = false; for (typename Turns::const_iterator it = turns.begin(); it != turns.end(); ++it) { method_type const method = it->method; operation_type const op = it->operations[0].operation; if (method == method_crosses) { return false; } else if (op == operation_intersection) { found_intersection = true; } else if (op == operation_union) { found_union = true; } else if (op == operation_continue) { found_continue = true; } if ((found_intersection || found_continue) && found_union) { return false; } if (it->operations[0].position == position_front) { found_front = true; } } if (found_front) { if (found_intersection) { inside_value = 1; // inside } else if (found_union) { inside_value = -1; // outside } else // continue and blocked { inside_value = 0; } return true; } // if needed analyse points of a linestring // NOTE: range_in_geometry checks points of a linestring // until a point inside/outside areal is found // TODO: Could be replaced with point_in_geometry() because found_front is false inside_value = range_in_geometry(linestring, areal, strategy); if ( (found_intersection && inside_value == -1) // going in from outside || (found_continue && inside_value == -1) // going on boundary from outside || (found_union && inside_value == 1) ) // going out from inside { return false; } return true; } template < typename LineString, typename Areal, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(LineString const& linestring, Areal const& areal, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); if (boost::size(linestring) == 0) { return out; } typedef detail::overlay::follow < GeometryOut, LineString, Areal, OverlayType, false, // do not remove spikes for linear geometries FollowIsolatedPoints > follower; typedef typename geometry::detail::output_geometry_access < GeometryOut, linestring_tag, linestring_tag > linear; typedef typename point_type < typename linear::type >::type point_type; typedef geometry::segment_ratio < typename coordinate_type<point_type>::type > ratio_type; typedef detail::overlay::turn_info < point_type, ratio_type, detail::overlay::turn_operation_linear < point_type, ratio_type > > turn_info; std::deque<turn_info> turns; detail::get_turns::no_interrupt_policy policy; typedef detail::overlay::get_turn_info_linear_areal < detail::overlay::assign_null_policy > turn_policy; dispatch::get_turns < typename geometry::tag<LineString>::type, typename geometry::tag<Areal>::type, LineString, Areal, false, (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal), turn_policy >::apply(0, linestring, 1, areal, strategy, robust_policy, turns, policy); int inside_value = 0; if (simple_turns_analysis(linestring, areal, strategy, turns, inside_value)) { // No crossing the boundary, it is either // inside (interior + borders) // or outside (exterior + borders) // or on boundary // add linestring to the output if conditions are met if (follower::included(inside_value)) { typename linear::type copy; geometry::convert(linestring, copy); *linear::get(out)++ = copy; } return out; } #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) int index = 0; for(typename std::deque<turn_info>::const_iterator it = turns.begin(); it != turns.end(); ++it) { debug_follow(*it, it->operations[0], index++); } #endif return follower::apply ( linestring, areal, geometry::detail::overlay::operation_intersection, turns, robust_policy, out, strategy ); } }; template <typename Turns, typename OutputIterator> inline OutputIterator intersection_output_turn_points(Turns const& turns, OutputIterator out) { for (typename Turns::const_iterator it = turns.begin(); it != turns.end(); ++it) { *out++ = it->point; } return out; } template <typename PointOut> struct intersection_areal_areal_point { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { typedef detail::overlay::turn_info < PointOut, typename segment_ratio_type<PointOut, RobustPolicy>::type > turn_info; std::vector<turn_info> turns; detail::get_turns::no_interrupt_policy policy; geometry::get_turns < false, false, detail::overlay::assign_null_policy >(geometry1, geometry2, strategy, robust_policy, turns, policy); return intersection_output_turn_points(turns, out); } }; template <typename PointOut> struct intersection_linear_areal_point { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); typedef geometry::segment_ratio<typename geometry::coordinate_type<PointOut>::type> ratio_type; typedef detail::overlay::turn_info < PointOut, ratio_type, detail::overlay::turn_operation_linear < PointOut, ratio_type > > turn_info; typedef detail::overlay::get_turn_info_linear_areal < detail::overlay::assign_null_policy > turn_policy; std::vector<turn_info> turns; detail::get_turns::no_interrupt_policy interrupt_policy; dispatch::get_turns < typename geometry::tag<Geometry1>::type, typename geometry::tag<Geometry2>::type, Geometry1, Geometry2, false, false, turn_policy >::apply(0, geometry1, 1, geometry2, strategy, robust_policy, turns, interrupt_policy); return intersection_output_turn_points(turns, out); } }; template <typename PointOut> struct intersection_areal_linear_point { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return intersection_linear_areal_point < PointOut >::apply(geometry2, geometry1, robust_policy, out, strategy); } }; }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < // real types typename Geometry1, typename Geometry2, typename GeometryOut, overlay_type OverlayType, // orientation bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, // tag dispatching: typename TagIn1 = typename geometry::tag<Geometry1>::type, typename TagIn2 = typename geometry::tag<Geometry2>::type, typename TagOut = typename detail::setop_insert_output_tag<GeometryOut>::type, // metafunction finetuning helpers: typename CastedTagIn1 = typename geometry::tag_cast<TagIn1, areal_tag, linear_tag, pointlike_tag>::type, typename CastedTagIn2 = typename geometry::tag_cast<TagIn2, areal_tag, linear_tag, pointlike_tag>::type, typename CastedTagOut = typename geometry::tag_cast<TagOut, areal_tag, linear_tag, pointlike_tag>::type > struct intersection_insert { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for these Geometry types or their order.", Geometry1, Geometry2, GeometryOut, std::integral_constant<overlay_type, OverlayType>); }; template < typename Geometry1, typename Geometry2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2, typename TagOut > struct intersection_insert < Geometry1, Geometry2, GeometryOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, TagOut, areal_tag, areal_tag, areal_tag > : detail::overlay::overlay < Geometry1, Geometry2, Reverse1, Reverse2, detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, GeometryOut, OverlayType > {}; // Any areal type with box: template < typename Geometry, typename Box, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn, typename TagOut > struct intersection_insert < Geometry, Box, GeometryOut, OverlayType, Reverse1, Reverse2, TagIn, box_tag, TagOut, areal_tag, areal_tag, areal_tag > : detail::overlay::overlay < Geometry, Box, Reverse1, Reverse2, detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, GeometryOut, OverlayType > {}; template < typename Segment1, typename Segment2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Segment1, Segment2, GeometryOut, OverlayType, Reverse1, Reverse2, segment_tag, segment_tag, point_tag, linear_tag, linear_tag, pointlike_tag > : detail::intersection::intersection_segment_segment_point<GeometryOut> {}; template < typename Linestring1, typename Linestring2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring1, Linestring2, GeometryOut, OverlayType, Reverse1, Reverse2, linestring_tag, linestring_tag, point_tag, linear_tag, linear_tag, pointlike_tag > : detail::intersection::intersection_linestring_linestring_point<GeometryOut> {}; template < typename Linestring, typename Box, typename GeometryOut, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring, Box, GeometryOut, overlay_intersection, Reverse1, Reverse2, linestring_tag, box_tag, linestring_tag, linear_tag, areal_tag, linear_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Linestring const& linestring, Box const& box, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { typedef typename point_type<GeometryOut>::type point_type; strategy::intersection::liang_barsky<Box, point_type> lb_strategy; return detail::intersection::clip_range_with_box <GeometryOut>(box, linestring, robust_policy, out, lb_strategy); } }; template < typename Linestring, typename Polygon, typename GeometryOut, overlay_type OverlayType, bool ReverseLinestring, bool ReversePolygon > struct intersection_insert < Linestring, Polygon, GeometryOut, OverlayType, ReverseLinestring, ReversePolygon, linestring_tag, polygon_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_linestring_with_areal < ReversePolygon, GeometryOut, OverlayType, false > {}; template < typename Linestring, typename Ring, typename GeometryOut, overlay_type OverlayType, bool ReverseLinestring, bool ReverseRing > struct intersection_insert < Linestring, Ring, GeometryOut, OverlayType, ReverseLinestring, ReverseRing, linestring_tag, ring_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_linestring_with_areal < ReverseRing, GeometryOut, OverlayType, false > {}; template < typename Segment, typename Box, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Segment, Box, GeometryOut, OverlayType, Reverse1, Reverse2, segment_tag, box_tag, linestring_tag, linear_tag, areal_tag, linear_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Segment const& segment, Box const& box, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { geometry::segment_view<Segment> range(segment); typedef typename point_type<GeometryOut>::type point_type; strategy::intersection::liang_barsky<Box, point_type> lb_strategy; return detail::intersection::clip_range_with_box <GeometryOut>(box, range, robust_policy, out, lb_strategy); } }; template < typename Geometry1, typename Geometry2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, PointOut, OverlayType, Reverse1, Reverse2, Tag1, Tag2, point_tag, areal_tag, areal_tag, pointlike_tag > : public detail::intersection::intersection_areal_areal_point < PointOut > {}; template < typename Geometry1, typename Geometry2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, PointOut, OverlayType, Reverse1, Reverse2, Tag1, Tag2, point_tag, linear_tag, areal_tag, pointlike_tag > : public detail::intersection::intersection_linear_areal_point < PointOut > {}; template < typename Geometry1, typename Geometry2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, PointOut, OverlayType, Reverse1, Reverse2, Tag1, Tag2, point_tag, areal_tag, linear_tag, pointlike_tag > : public detail::intersection::intersection_areal_linear_point < PointOut > {}; template < typename Geometry1, typename Geometry2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert_reversed { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return intersection_insert < Geometry2, Geometry1, GeometryOut, OverlayType, Reverse2, Reverse1 >::apply(g2, g1, robust_policy, out, strategy); } }; // dispatch for intersection(areal, areal, linear) template < typename Geometry1, typename Geometry2, typename LinestringOut, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, LinestringOut, overlay_intersection, Reverse1, Reverse2, Tag1, Tag2, linestring_tag, areal_tag, areal_tag, linear_tag > { template < typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { detail::boundary_view<Geometry1 const> view1(geometry1); detail::boundary_view<Geometry2 const> view2(geometry2); return detail::overlay::linear_linear_linestring < detail::boundary_view<Geometry1 const>, detail::boundary_view<Geometry2 const>, LinestringOut, overlay_intersection >::apply(view1, view2, robust_policy, oit, strategy); } }; // dispatch for difference/intersection of linear geometries template < typename Linear1, typename Linear2, typename LineStringOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < Linear1, Linear2, LineStringOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, linestring_tag, linear_tag, linear_tag, linear_tag > : detail::overlay::linear_linear_linestring < Linear1, Linear2, LineStringOut, OverlayType > {}; template < typename Linear1, typename Linear2, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < Linear1, Linear2, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, linear_tag, linear_tag, detail::tupled_output_tag > : detail::expect_output < Linear1, Linear2, TupledOut, // NOTE: points can be the result only in case of intersection. std::conditional_t < (OverlayType == overlay_intersection), point_tag, void >, linestring_tag > { // NOTE: The order of geometries in TupledOut tuple/pair must correspond to the order // iterators in OutputIterators tuple/pair. template < typename RobustPolicy, typename OutputIterators, typename Strategy > static inline OutputIterators apply(Linear1 const& linear1, Linear2 const& linear2, RobustPolicy const& robust_policy, OutputIterators oit, Strategy const& strategy) { return detail::overlay::linear_linear_linestring < Linear1, Linear2, TupledOut, OverlayType >::apply(linear1, linear2, robust_policy, oit, strategy); } }; // dispatch for difference/intersection of point-like geometries template < typename Point1, typename Point2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Point1, Point2, PointOut, OverlayType, Reverse1, Reverse2, point_tag, point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::point_point_point < Point1, Point2, PointOut, OverlayType > {}; template < typename MultiPoint, typename Point, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < MultiPoint, Point, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::multipoint_point_point < MultiPoint, Point, PointOut, OverlayType > {}; template < typename Point, typename MultiPoint, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Point, MultiPoint, PointOut, OverlayType, Reverse1, Reverse2, point_tag, multi_point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::point_multipoint_point < Point, MultiPoint, PointOut, OverlayType > {}; template < typename MultiPoint1, typename MultiPoint2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < MultiPoint1, MultiPoint2, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, multi_point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::multipoint_multipoint_point < MultiPoint1, MultiPoint2, PointOut, OverlayType > {}; template < typename PointLike1, typename PointLike2, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < PointLike1, PointLike2, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, pointlike_tag, detail::tupled_output_tag > : detail::expect_output<PointLike1, PointLike2, TupledOut, point_tag> { // NOTE: The order of geometries in TupledOut tuple/pair must correspond to the order // of iterators in OutputIterators tuple/pair. template < typename RobustPolicy, typename OutputIterators, typename Strategy > static inline OutputIterators apply(PointLike1 const& pointlike1, PointLike2 const& pointlike2, RobustPolicy const& robust_policy, OutputIterators oits, Strategy const& strategy) { namespace bgt = boost::geometry::tuples; static const bool out_point_index = bgt::find_index_if < TupledOut, geometry::detail::is_tag_same_as_pred<point_tag>::template pred >::value; bgt::get<out_point_index>(oits) = intersection_insert < PointLike1, PointLike2, typename bgt::element < out_point_index, TupledOut >::type, OverlayType >::apply(pointlike1, pointlike2, robust_policy, bgt::get<out_point_index>(oits), strategy); return oits; } }; // dispatch for difference/intersection of pointlike-linear geometries template < typename Point, typename Linear, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag > struct intersection_insert < Point, Linear, PointOut, OverlayType, Reverse1, Reverse2, point_tag, Tag, point_tag, pointlike_tag, linear_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_linear_point < Point, Linear, PointOut, OverlayType, point_tag, typename tag_cast<Tag, segment_tag, linear_tag>::type > {}; template < typename MultiPoint, typename Linear, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag > struct intersection_insert < MultiPoint, Linear, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, Tag, point_tag, pointlike_tag, linear_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_linear_point < MultiPoint, Linear, PointOut, OverlayType, multi_point_tag, typename tag_cast<Tag, segment_tag, linear_tag>::type > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Linestring combination. template < typename Linestring, typename MultiPoint, typename PointOut, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring, MultiPoint, PointOut, overlay_intersection, Reverse1, Reverse2, linestring_tag, multi_point_tag, point_tag, linear_tag, pointlike_tag, pointlike_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Linestring const& linestring, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return detail_dispatch::overlay::pointlike_linear_point < MultiPoint, Linestring, PointOut, overlay_intersection, multi_point_tag, linear_tag >::apply(multipoint, linestring, robust_policy, out, strategy); } }; template < typename PointLike, typename Linear, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < PointLike, Linear, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, linear_tag, detail::tupled_output_tag > // Reuse the implementation for PointLike/PointLike. : intersection_insert < PointLike, Linear, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, pointlike_tag, detail::tupled_output_tag > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Linestring combination. template < typename Linestring, typename MultiPoint, typename TupledOut, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring, MultiPoint, TupledOut, overlay_intersection, Reverse1, Reverse2, linestring_tag, multi_point_tag, detail::tupled_output_tag, linear_tag, pointlike_tag, detail::tupled_output_tag > { template <typename RobustPolicy, typename OutputIterators, typename Strategy> static inline OutputIterators apply(Linestring const& linestring, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterators out, Strategy const& strategy) { return intersection_insert < MultiPoint, Linestring, TupledOut, overlay_intersection >::apply(multipoint, linestring, robust_policy, out, strategy); } }; // dispatch for difference/intersection of pointlike-areal geometries template < typename Point, typename Areal, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename ArealTag > struct intersection_insert < Point, Areal, PointOut, OverlayType, Reverse1, Reverse2, point_tag, ArealTag, point_tag, pointlike_tag, areal_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_areal_point < Point, Areal, PointOut, OverlayType, point_tag, ArealTag > {}; template < typename MultiPoint, typename Areal, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename ArealTag > struct intersection_insert < MultiPoint, Areal, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, ArealTag, point_tag, pointlike_tag, areal_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_areal_point < MultiPoint, Areal, PointOut, OverlayType, multi_point_tag, ArealTag > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Ring and MultiPoint/Polygon combinations. template < typename Areal, typename MultiPoint, typename PointOut, bool Reverse1, bool Reverse2, typename ArealTag > struct intersection_insert < Areal, MultiPoint, PointOut, overlay_intersection, Reverse1, Reverse2, ArealTag, multi_point_tag, point_tag, areal_tag, pointlike_tag, pointlike_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Areal const& areal, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return detail_dispatch::overlay::pointlike_areal_point < MultiPoint, Areal, PointOut, overlay_intersection, multi_point_tag, ArealTag >::apply(multipoint, areal, robust_policy, out, strategy); } }; template < typename PointLike, typename Areal, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < PointLike, Areal, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, areal_tag, detail::tupled_output_tag > // Reuse the implementation for PointLike/PointLike. : intersection_insert < PointLike, Areal, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, pointlike_tag, detail::tupled_output_tag > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Ring and MultiPoint/Polygon combinations. template < typename Areal, typename MultiPoint, typename TupledOut, bool Reverse1, bool Reverse2, typename TagIn1 > struct intersection_insert < Areal, MultiPoint, TupledOut, overlay_intersection, Reverse1, Reverse2, TagIn1, multi_point_tag, detail::tupled_output_tag, areal_tag, pointlike_tag, detail::tupled_output_tag > { template <typename RobustPolicy, typename OutputIterators, typename Strategy> static inline OutputIterators apply(Areal const& areal, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterators out, Strategy const& strategy) { return intersection_insert < MultiPoint, Areal, TupledOut, overlay_intersection >::apply(multipoint, areal, robust_policy, out, strategy); } }; template < typename Linestring, typename Polygon, typename TupledOut, overlay_type OverlayType, bool ReverseLinestring, bool ReversePolygon > struct intersection_insert < Linestring, Polygon, TupledOut, OverlayType, ReverseLinestring, ReversePolygon, linestring_tag, polygon_tag, detail::tupled_output_tag, linear_tag, areal_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_linestring_with_areal < ReversePolygon, TupledOut, OverlayType, true > {}; template < typename Linestring, typename Ring, typename TupledOut, overlay_type OverlayType, bool ReverseLinestring, bool ReverseRing > struct intersection_insert < Linestring, Ring, TupledOut, OverlayType, ReverseLinestring, ReverseRing, linestring_tag, ring_tag, detail::tupled_output_tag, linear_tag, areal_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_linestring_with_areal < ReverseRing, TupledOut, OverlayType, true > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { template < typename GeometryOut, bool ReverseSecond, overlay_type OverlayType, typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator insert(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy robust_policy, OutputIterator out, Strategy const& strategy) { return std::conditional_t < geometry::reverse_dispatch<Geometry1, Geometry2>::type::value, geometry::dispatch::intersection_insert_reversed < Geometry1, Geometry2, GeometryOut, OverlayType, overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value >, geometry::dispatch::intersection_insert < Geometry1, Geometry2, GeometryOut, OverlayType, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value > >::apply(geometry1, geometry2, robust_policy, out, strategy); } /*! \brief \brief_calc2{intersection} \brief_strategy \ingroup intersection \details \details_calc2{intersection_insert, spatial set theoretic intersection} \brief_strategy. \details_insert{intersection} \tparam GeometryOut \tparam_geometry{\p_l_or_c} \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam OutputIterator \tparam_out{\p_l_or_c} \tparam Strategy \tparam_strategy_overlay \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{intersection} \param strategy \param_strategy{intersection} \return \return_out \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/intersection.qbk]} */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator, typename Strategy > inline OutputIterator intersection_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); return detail::intersection::insert < GeometryOut, false, overlay_intersection >(geometry1, geometry2, robust_policy, out, strategy); } /*! \brief \brief_calc2{intersection} \ingroup intersection \details \details_calc2{intersection_insert, spatial set theoretic intersection}. \details_insert{intersection} \tparam GeometryOut \tparam_geometry{\p_l_or_c} \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam OutputIterator \tparam_out{\p_l_or_c} \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{intersection} \return \return_out \qbk{[include reference/algorithms/intersection.qbk]} */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator > inline OutputIterator intersection_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); typedef typename strategies::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return intersection_insert<GeometryOut>(geometry1, geometry2, out, strategy_type()); } }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP