Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:42:44

0001 // Boost.Geometry
0002 
0003 // Copyright (c) 2022-2024, Oracle and/or its affiliates.
0004 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
0005 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0006 
0007 // Licensed under the Boost Software License version 1.0.
0008 // http://www.boost.org/users/license.html
0009 
0010 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_GC_HPP
0011 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_GC_HPP
0012 
0013 
0014 #include <tuple>
0015 
0016 #include <boost/range/size.hpp>
0017 
0018 #include <boost/geometry/algorithms/detail/gc_make_rtree.hpp>
0019 #include <boost/geometry/algorithms/detail/intersection/interface.hpp>
0020 #include <boost/geometry/views/detail/geometry_collection_view.hpp>
0021 
0022 
0023 namespace boost { namespace geometry
0024 {
0025 
0026 #ifndef DOXYGEN_NO_DETAIL
0027 namespace detail { namespace intersection
0028 {
0029 
0030 
0031 template <typename GC, typename Multi>
0032 struct gc_can_move_element
0033 {
0034     template <typename G>
0035     using is_same_as_single = std::is_same<G, typename boost::range_value<Multi>::type>;
0036     using gc_types = typename traits::geometry_types<GC>::type;
0037     using found_type = typename util::sequence_find_if<gc_types, is_same_as_single>::type;
0038     static const bool value = ! std::is_void<found_type>::value;
0039 };
0040 
0041 template <typename GC, typename Multi>
0042 struct gc_can_convert_element
0043 {
0044     template <typename G>
0045     using has_same_tag_as_single = std::is_same
0046         <
0047             geometry::tag_t<G>,
0048             geometry::tag_t<typename boost::range_value<Multi>::type>
0049         >;
0050     using gc_types = typename traits::geometry_types<GC>::type;
0051     using found_type = typename util::sequence_find_if<gc_types, has_same_tag_as_single>::type;
0052     static const bool value = ! std::is_void<found_type>::value;
0053 };
0054 
0055 template
0056 <
0057     typename GC, typename Multi,
0058     std::enable_if_t<gc_can_move_element<GC, Multi>::value, int> = 0
0059 >
0060 inline void gc_move_one_elem_multi_back(GC& gc, Multi&& multi)
0061 {
0062     range::emplace_back(gc, std::move(*boost::begin(multi)));
0063 }
0064 
0065 template
0066 <
0067     typename GC, typename Multi,
0068     std::enable_if_t<! gc_can_move_element<GC, Multi>::value && gc_can_convert_element<GC, Multi>::value, int> = 0
0069 >
0070 inline void gc_move_one_elem_multi_back(GC& gc, Multi&& multi)
0071 {
0072     typename gc_can_convert_element<GC, Multi>::found_type single_out;
0073     geometry::convert(*boost::begin(multi), single_out);
0074     range::emplace_back(gc, std::move(single_out));
0075 }
0076 
0077 template
0078 <
0079     typename GC, typename Multi,
0080     std::enable_if_t<! gc_can_move_element<GC, Multi>::value && ! gc_can_convert_element<GC, Multi>::value, int> = 0
0081 >
0082 inline void gc_move_one_elem_multi_back(GC& gc, Multi&& multi)
0083 {
0084     range::emplace_back(gc, std::move(multi));
0085 }
0086 
0087 template <typename GC, typename Multi>
0088 inline void gc_move_multi_back(GC& gc, Multi&& multi)
0089 {
0090     if (! boost::empty(multi))
0091     {
0092         if (boost::size(multi) == 1)
0093         {
0094             gc_move_one_elem_multi_back(gc, std::move(multi));
0095         }
0096         else
0097         {
0098             range::emplace_back(gc, std::move(multi));
0099         }
0100     }
0101 }
0102 
0103 
0104 }} // namespace detail::intersection
0105 #endif // DOXYGEN_NO_DETAIL
0106 
0107 
0108 namespace resolve_collection
0109 {
0110 
0111 
0112 template
0113 <
0114     typename Geometry1, typename Geometry2, typename GeometryOut
0115 >
0116 struct intersection
0117     <
0118         Geometry1, Geometry2, GeometryOut,
0119         geometry_collection_tag, geometry_collection_tag, geometry_collection_tag
0120     >
0121 {
0122     // NOTE: for now require all of the possible output types
0123     //       technically only a subset could be needed.
0124     using multi_point_t = typename util::sequence_find_if
0125         <
0126             typename traits::geometry_types<GeometryOut>::type,
0127             util::is_multi_point
0128         >::type;
0129     using multi_linestring_t = typename util::sequence_find_if
0130         <
0131             typename traits::geometry_types<GeometryOut>::type,
0132             util::is_multi_linestring
0133         >::type;
0134     using multi_polygon_t = typename util::sequence_find_if
0135         <
0136             typename traits::geometry_types<GeometryOut>::type,
0137             util::is_multi_polygon
0138         >::type;
0139     using tuple_out_t = boost::tuple<multi_point_t, multi_linestring_t, multi_polygon_t>;
0140 
0141     template <typename Strategy>
0142     static inline bool apply(Geometry1 const& geometry1,
0143                              Geometry2 const& geometry2,
0144                              GeometryOut& geometry_out,
0145                              Strategy const& strategy)
0146     {
0147         bool result = false;
0148         tuple_out_t out;
0149 
0150         auto const rtree2 = detail::gc_make_rtree_iterators(geometry2, strategy);
0151         detail::visit_breadth_first([&](auto const& g1)
0152         {
0153             bool r = g1_prod_gc2(g1, rtree2, out, strategy);
0154             result = result || r;
0155             return true;
0156         }, geometry1);
0157 
0158         detail::intersection::gc_move_multi_back(geometry_out, boost::get<0>(out));
0159         detail::intersection::gc_move_multi_back(geometry_out, boost::get<1>(out));
0160         detail::intersection::gc_move_multi_back(geometry_out, boost::get<2>(out));
0161 
0162         return result;
0163     }
0164 
0165 private:
0166     // Implemented as separate function because msvc is unable to do nested lambda capture
0167     template <typename G1, typename Rtree2, typename TupleOut, typename Strategy>
0168     static bool g1_prod_gc2(G1 const& g1, Rtree2 const& rtree2, TupleOut& out, Strategy const& strategy)
0169     {
0170         bool result = false;
0171 
0172         using box1_t = detail::gc_make_rtree_box_t<G1>;
0173         box1_t b1 = geometry::return_envelope<box1_t>(g1, strategy);
0174         detail::expand_by_epsilon(b1);
0175 
0176         for (auto qit = rtree2.qbegin(index::intersects(b1)); qit != rtree2.qend(); ++qit)
0177         {
0178             traits::iter_visit<Geometry2>::apply([&](auto const& g2)
0179             {
0180                 TupleOut inters_result;
0181                 using g2_t = util::remove_cref_t<decltype(g2)>;
0182                 intersection<G1, g2_t, TupleOut>::apply(g1, g2, inters_result, strategy);
0183 
0184                 // TODO: If possible merge based on adjacency lists, i.e. merge
0185                 //       only the intersections of elements that intersect each other
0186                 //       as subgroups. So the result could contain merged intersections
0187                 //       of several groups, not only one.
0188                 // TODO: It'd probably be better to gather all of the parts first
0189                 //       and then merge them with merge_elements.
0190                 // NOTE: template explicitly called because gcc-6 doesn't compile it
0191                 //       otherwise.
0192                 bool const r0 = intersection::template merge_result<0>(inters_result, out, strategy);
0193                 bool const r1 = intersection::template merge_result<1>(inters_result, out, strategy);
0194                 bool const r2 = intersection::template merge_result<2>(inters_result, out, strategy);
0195                 result = result || r0 || r1 || r2;
0196             }, qit->second);
0197         }
0198 
0199         return result;
0200     }
0201 
0202     template <std::size_t Index, typename Out, typename Strategy>
0203     static bool merge_result(Out const& inters_result, Out& out, Strategy const& strategy)
0204     {
0205         auto const& multi_result = boost::get<Index>(inters_result);
0206         auto& multi_out = boost::get<Index>(out);
0207         if (! boost::empty(multi_result))
0208         {
0209             std::remove_reference_t<decltype(multi_out)> temp_result;
0210             merge_two(multi_out, multi_result, temp_result, strategy);
0211             multi_out = std::move(temp_result);
0212             return true;
0213         }
0214         return false;
0215     }
0216 
0217     template <typename Out, typename Strategy, std::enable_if_t<! util::is_pointlike<Out>::value, int> = 0>
0218     static void merge_two(Out const& g1, Out const& g2, Out& out, Strategy const& strategy)
0219     {
0220         geometry::dispatch::intersection_insert
0221             <
0222                 Out, Out, typename boost::range_value<Out>::type,
0223                 overlay_union
0224             >::apply(g1,
0225                      g2,
0226                      geometry::range::back_inserter(out),
0227                      strategy);
0228     }
0229 
0230     template <typename Out, typename Strategy, std::enable_if_t<util::is_pointlike<Out>::value, int> = 0>
0231     static void merge_two(Out const& g1, Out const& g2, Out& out, Strategy const& strategy)
0232     {
0233         detail::overlay::union_pointlike_pointlike_point
0234             <
0235                 Out, Out, typename boost::range_value<Out>::type
0236             >::apply(g1,
0237                      g2,
0238                      geometry::range::back_inserter(out),
0239                      strategy);
0240     }
0241 };
0242 
0243 template
0244 <
0245     typename Geometry1, typename Geometry2, typename GeometryOut, typename Tag1
0246 >
0247 struct intersection
0248     <
0249         Geometry1, Geometry2, GeometryOut,
0250         Tag1, geometry_collection_tag, geometry_collection_tag
0251     >
0252 {
0253     template <typename Strategy>
0254     static inline bool apply(Geometry1 const& geometry1,
0255                              Geometry2 const& geometry2,
0256                              GeometryOut& geometry_out,
0257                              Strategy const& strategy)
0258     {
0259         using gc_view_t = geometry::detail::geometry_collection_view<Geometry1>;
0260         return intersection
0261             <
0262                 gc_view_t, Geometry2, GeometryOut
0263             >::apply(gc_view_t(geometry1), geometry2, geometry_out, strategy);
0264     }
0265 };
0266 
0267 template
0268 <
0269     typename Geometry1, typename Geometry2, typename GeometryOut, typename Tag2
0270 >
0271 struct intersection
0272     <
0273         Geometry1, Geometry2, GeometryOut,
0274         geometry_collection_tag, Tag2, geometry_collection_tag
0275     >
0276 {
0277     template <typename Strategy>
0278     static inline bool apply(Geometry1 const& geometry1,
0279                              Geometry2 const& geometry2,
0280                              GeometryOut& geometry_out,
0281                              Strategy const& strategy)
0282     {
0283         using gc_view_t = geometry::detail::geometry_collection_view<Geometry2>;
0284         return intersection
0285             <
0286                 Geometry1, gc_view_t, GeometryOut
0287             >::apply(geometry1, gc_view_t(geometry2), geometry_out, strategy);
0288     }
0289 };
0290 
0291 template
0292 <
0293     typename Geometry1, typename Geometry2, typename GeometryOut, typename Tag1, typename Tag2
0294 >
0295 struct intersection
0296     <
0297         Geometry1, Geometry2, GeometryOut,
0298         Tag1, Tag2, geometry_collection_tag
0299     >
0300 {
0301     template <typename Strategy>
0302     static inline bool apply(Geometry1 const& geometry1,
0303                              Geometry2 const& geometry2,
0304                              GeometryOut& geometry_out,
0305                              Strategy const& strategy)
0306     {
0307         using gc1_view_t = geometry::detail::geometry_collection_view<Geometry1>;
0308         using gc2_view_t = geometry::detail::geometry_collection_view<Geometry2>;
0309         return intersection
0310             <
0311                 gc1_view_t, gc2_view_t, GeometryOut
0312             >::apply(gc1_view_t(geometry1), gc2_view_t(geometry2), geometry_out, strategy);
0313     }
0314 };
0315 
0316 
0317 } // namespace resolve_collection
0318 
0319 }} // namespace boost::geometry
0320 
0321 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_GC_HPP