Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:50:00

0001 // Boost.Geometry
0002 
0003 // Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland.
0004 
0005 // Copyright (c) 2022 Oracle and/or its affiliates.
0006 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0007 
0008 // Use, modification and distribution is subject to the Boost Software License,
0009 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0010 // http://www.boost.org/LICENSE_1_0.txt)
0011 
0012 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP
0013 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP
0014 
0015 
0016 #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
0017 #include <boost/geometry/algorithms/detail/relate/interface.hpp>
0018 #include <boost/geometry/algorithms/difference.hpp>
0019 #include <boost/geometry/algorithms/intersection.hpp>
0020 #include <boost/geometry/algorithms/is_empty.hpp>
0021 #include <boost/geometry/algorithms/union.hpp>
0022 #include <boost/geometry/geometries/linestring.hpp>
0023 #include <boost/geometry/geometries/multi_linestring.hpp>
0024 #include <boost/geometry/geometries/multi_point.hpp>
0025 #include <boost/geometry/geometries/multi_polygon.hpp>
0026 #include <boost/geometry/geometries/polygon.hpp>
0027 #include <boost/geometry/util/condition.hpp>
0028 #include <boost/geometry/views/detail/geometry_collection_view.hpp>
0029 
0030 
0031 namespace boost { namespace geometry
0032 {
0033 
0034 #ifndef DOXYGEN_NO_DETAIL
0035 namespace detail { namespace relate
0036 {
0037 
0038 // For fields II IE and EI this handler behaves like matrix_handler.
0039 // It has to be created at the beginning of processing because it relies on the
0040 //   fact that all of the fields are set to F and no geometry was handled yet.
0041 //   This way it can check which fields are required for any mask and matrix
0042 //   without accessing the internals.
0043 // An alternative would be to remove this wrapper and always set the matrix
0044 //   in static_mask_handler even if this is not required.
0045 template <typename Handler>
0046 struct aa_handler_wrapper
0047 {
0048     bool interrupt = false;
0049 
0050     explicit aa_handler_wrapper(Handler& handler)
0051         : m_handler(handler)
0052         , m_overwrite_ii(! handler.template may_update<interior, interior, '2'>())
0053         , m_overwrite_ie(! handler.template may_update<interior, exterior, '2'>())
0054         , m_overwrite_ei(! handler.template may_update<exterior, interior, '2'>())
0055     {}
0056 
0057     template <field F1, field F2, char D>
0058     inline bool may_update() const
0059     {
0060         if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii)
0061             || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie)
0062             || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei))
0063         {
0064             char const c = m_handler.template get<F1, F2>();
0065             return D > c || c > '9';
0066         }
0067         else
0068         {
0069             return m_handler.template may_update<F1, F2, D>();
0070         }
0071     }
0072 
0073     template <field F1, field F2, char V>
0074     inline void update()
0075     {
0076         if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii)
0077             || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie)
0078             || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei))
0079         {
0080             // NOTE: Other handlers first check for potential interruption
0081             //   and only after that checks update condition.
0082             char const c = m_handler.template get<F1, F2>();
0083             // If c == T and V == T it will be set anyway but that's fine.
0084             if (V > c || c > '9')
0085             {
0086                 // set may set interrupt flag
0087                 m_handler.template set<F1, F2, V>();
0088             }
0089         }
0090         else
0091         {
0092             m_handler.template update<F1, F2, V>();
0093         }
0094         interrupt = interrupt || m_handler.interrupt;
0095     }
0096 
0097 private:
0098     Handler & m_handler;
0099     bool const m_overwrite_ii;
0100     bool const m_overwrite_ie;
0101     bool const m_overwrite_ei;
0102 };
0103 
0104 
0105 template <typename Geometry1, typename Geometry2>
0106 struct gc_gc
0107 {
0108     static const bool interruption_enabled = true;
0109 
0110     using mpt1_found_t = typename util::sequence_find_if
0111         <
0112             typename traits::geometry_types<Geometry1>::type,
0113             util::is_multi_point
0114         >::type;
0115     using mls1_found_t = typename util::sequence_find_if
0116         <
0117             typename traits::geometry_types<Geometry1>::type,
0118             util::is_multi_linestring
0119         >::type;
0120     using mpo1_found_t = typename util::sequence_find_if
0121         <
0122             typename traits::geometry_types<Geometry1>::type,
0123             util::is_multi_polygon
0124         >::type;
0125     using pt1_t = geometry::point_type_t<Geometry1>;
0126     using mpt1_t = std::conditional_t
0127         <
0128             std::is_void<mpt1_found_t>::value,
0129             geometry::model::multi_point<pt1_t>,
0130             mpt1_found_t
0131         >;
0132     using mls1_t = std::conditional_t
0133         <
0134             std::is_void<mls1_found_t>::value,
0135             geometry::model::multi_linestring<geometry::model::linestring<pt1_t>>,
0136             mls1_found_t
0137         >;
0138     using mpo1_t = std::conditional_t
0139         <
0140             std::is_void<mpo1_found_t>::value,
0141             geometry::model::multi_polygon<geometry::model::polygon<pt1_t>>,
0142             mpo1_found_t
0143         >;
0144     using tuple1_t = boost::tuple<mpt1_t, mls1_t, mpo1_t>;
0145 
0146     using mpt2_found_t = typename util::sequence_find_if
0147         <
0148             typename traits::geometry_types<Geometry2>::type,
0149             util::is_multi_point
0150         >::type;
0151     using mls2_found_t = typename util::sequence_find_if
0152         <
0153             typename traits::geometry_types<Geometry2>::type,
0154             util::is_multi_linestring
0155         >::type;
0156     using mpo2_found_t = typename util::sequence_find_if
0157         <
0158             typename traits::geometry_types<Geometry2>::type,
0159             util::is_multi_polygon
0160         >::type;
0161     using pt2_t = geometry::point_type_t<Geometry2>;
0162     using mpt2_t = std::conditional_t
0163         <
0164             std::is_void<mpt2_found_t>::value,
0165             geometry::model::multi_point<pt2_t>,
0166             mpt2_found_t
0167         >;
0168     using mls2_t = std::conditional_t
0169         <
0170             std::is_void<mls2_found_t>::value,
0171             geometry::model::multi_linestring<geometry::model::linestring<pt2_t>>,
0172             mls2_found_t
0173         >;
0174     using mpo2_t = std::conditional_t
0175         <
0176             std::is_void<mpo2_found_t>::value,
0177             geometry::model::multi_polygon<geometry::model::polygon<pt2_t>>,
0178             mpo2_found_t
0179         >;
0180     using tuple2_t = boost::tuple<mpt2_t, mls2_t, mpo2_t>;
0181 
0182     template <typename Geometry>
0183     using kind_id = util::index_constant
0184         <
0185             util::is_areal<Geometry>::value ? 2
0186           : util::is_linear<Geometry>::value ? 1
0187           : 0
0188         >;
0189 
0190     template <typename Result, typename Strategy>
0191     static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
0192                              Result & result,
0193                              Strategy const& strategy)
0194     {
0195         using gc1_view_t = random_access_view<Geometry1 const>;
0196         using gc2_view_t = random_access_view<Geometry2 const>;
0197         gc1_view_t const gc1_view(geometry1);
0198         gc2_view_t const gc2_view(geometry2);
0199 
0200         bool inters_found[2][3] = {{false, false, false}, {false, false, false}};
0201         bool disjoint_found[2][3] = {{false, false, false}, {false, false, false}};
0202         bool disjoint_linear_boundary_found[2] = {false, false};
0203         bool has_disjoint = false;
0204 
0205         gc_group_elements(gc1_view, gc2_view, strategy,
0206             [&](auto const& inters_group)
0207             {
0208                 tuple1_t tuple1;
0209                 tuple2_t tuple2;
0210 
0211                 // Create MPts, MLss and MPos containing all gc elements from this group
0212                 // They may potentially intersect each other
0213                 for (auto const& id : inters_group)
0214                 {
0215                     BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1);
0216                     if (id.source_id == 0)
0217                     {
0218                         traits::iter_visit<gc1_view_t>::apply([&](auto const& g1)
0219                         {
0220                             merge_geometry(tuple1, g1, strategy);
0221                         }, boost::begin(gc1_view) + id.gc_id);
0222                     }
0223                     else
0224                     {
0225                         traits::iter_visit<gc2_view_t>::apply([&](auto const& g2)
0226                         {
0227                             merge_geometry(tuple2, g2, strategy);
0228                         }, boost::begin(gc2_view) + id.gc_id);
0229                     }
0230                 }
0231 
0232                 // Subtract higher topo-dim elements from elements of lower topo-dim
0233                 // MPts do not intersect other geometries, MLss and MPos may touch
0234                 subtract_elements(tuple1, strategy);
0235                 subtract_elements(tuple2, strategy);
0236 
0237                 // Helpers
0238                 auto const& mpt1 = boost::get<0>(tuple1);
0239                 auto const& mls1 = boost::get<1>(tuple1);
0240                 auto const& mpo1 = boost::get<2>(tuple1);
0241                 auto const& mpt2 = boost::get<0>(tuple2);
0242                 auto const& mls2 = boost::get<1>(tuple2);
0243                 auto const& mpo2 = boost::get<2>(tuple2);
0244 
0245                 // A/A
0246                 if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpo2))
0247                 {
0248                     inters_found[0][2] = true;
0249                     inters_found[1][2] = true;
0250                     aa_handler_wrapper<Result> wrapper(result);
0251                     call_relate(mpo1, mpo2, wrapper, strategy);
0252                 }
0253 
0254                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0255                 {
0256                     return false;
0257                 }
0258 
0259                 bool is_aa_ii = result.template get<interior, interior>() != 'F';
0260                 bool is_aa_ie = result.template get<interior, exterior>() != 'F';
0261                 bool is_aa_ei = result.template get<exterior, interior>() != 'F';
0262                 // is_aa_ii implies is_aa_checked and non-empty Areal geometries
0263                 bool are_aa_equal = is_aa_ii && ! is_aa_ie && ! is_aa_ei;
0264 
0265                 // Boundary checkers are internally initialized lazily later if a point has to be checked
0266                 boundary_checker<mls1_t, Strategy> mls1_boundary(mls1, strategy);
0267                 boundary_checker<mls2_t, Strategy> mls2_boundary(mls2, strategy);
0268 
0269                 // If needed divide MLss into two parts:
0270                 // - inside Areal of other GC
0271                 // - outside of other GC Areal to check WRT Linear of other GC
0272                 mls2_t mls2_diff_mpo1, mls2_inters_mpo1;
0273                 bool is_mls2_divided = false;
0274                 mls1_t mls1_diff_mpo2, mls1_inters_mpo2;
0275                 bool is_mls1_divided = false;
0276                 // If Areal are equal then Linear are outside of both so there is no need to divide
0277                 if (! are_aa_equal && ! geometry::is_empty(mls1) && ! geometry::is_empty(mls2))
0278                 {
0279                     // LA/L
0280                     if (! geometry::is_empty(mpo1))
0281                     {
0282                         geometry::difference(mls2, mpo1, mls2_diff_mpo1);
0283                         geometry::intersection(mls2, mpo1, mls2_inters_mpo1);
0284                         is_mls2_divided = true;
0285                     }
0286                     // L/LA
0287                     if (! geometry::is_empty(mpo2))
0288                     {
0289                         geometry::difference(mls1, mpo2, mls1_diff_mpo2);
0290                         geometry::intersection(mls1, mpo2, mls1_inters_mpo2);
0291                         is_mls1_divided = true;
0292                     }
0293                 }
0294 
0295                 // A/L
0296                 if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mls2))
0297                 {
0298                     inters_found[0][2] = true;
0299                     inters_found[1][1] = true;
0300                     if (is_aa_ii && ! is_aa_ie && ! is_aa_ei && ! geometry::is_empty(mls1))
0301                     {
0302                         // Equal Areal and both Linear non-empty, calculate only L/L below
0303                     }
0304                     else if (is_aa_ii && ! is_aa_ie && geometry::is_empty(mls1))
0305                     {
0306                         // An alternative would be to calculate L/L with one empty below
0307                         mpo1_t empty;
0308                         call_relate_al(empty, mls2, mls2_boundary, result, strategy);
0309                     }
0310                     else
0311                     {
0312                         if (is_mls2_divided)
0313                         {
0314                             if (! geometry::is_empty(mls2_inters_mpo1))
0315                             {
0316                                 call_relate_al(mpo1, mls2_inters_mpo1, mls2_boundary, result, strategy);
0317                             }
0318                         }
0319                         else
0320                         {
0321                             call_relate_al(mpo1, mls2, mls2_boundary, result, strategy);
0322                         }
0323                     }
0324                 }
0325 
0326                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0327                 {
0328                     return false;
0329                 }
0330 
0331                 // L/A
0332                 if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpo2))
0333                 {
0334                     inters_found[0][1] = true;
0335                     inters_found[1][2] = true;
0336                     if (is_aa_ii && ! is_aa_ei && ! is_aa_ie && ! geometry::is_empty(mls2))
0337                     {
0338                         // Equal Areal and both Linear non-empty, calculate only L/L below
0339                     }
0340                     else if (is_aa_ii && ! is_aa_ei && geometry::is_empty(mls2))
0341                     {
0342                         // An alternative would be to calculate L/L with one empty below
0343                         mpo2_t empty;
0344                         call_relate_la(mls1, empty, mls1_boundary, result, strategy);
0345                     }
0346                     else
0347                     {
0348                         if (is_mls1_divided)
0349                         {
0350                             if (! geometry::is_empty(mls1_inters_mpo2))
0351                             {
0352                                 call_relate_la(mls1_inters_mpo2, mpo2, mls1_boundary, result, strategy);
0353                             }
0354                         }
0355                         else
0356                         {
0357                             call_relate_la(mls1, mpo2, mls1_boundary, result, strategy);
0358                         }
0359                     }
0360                 }
0361 
0362                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0363                 {
0364                     return false;
0365                 }
0366 
0367                 // L/L
0368                 if (! geometry::is_empty(mls1) && ! geometry::is_empty(mls2))
0369                 {
0370                     inters_found[0][1] = true;
0371                     inters_found[1][1] = true;
0372                     if (is_mls1_divided && is_mls2_divided)
0373                     {
0374                         if (! geometry::is_empty(mls1_diff_mpo2) && ! geometry::is_empty(mls2_diff_mpo1))
0375                         {
0376                             call_relate_ll(mls1_diff_mpo2, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy);
0377                         }
0378                     }
0379                     else if (is_mls1_divided)
0380                     {
0381                         if (! geometry::is_empty(mls1_diff_mpo2))
0382                         {
0383                             call_relate_ll(mls1_diff_mpo2, mls2, mls1_boundary, mls2_boundary, result, strategy);
0384                         }
0385                     }
0386                     else if (is_mls2_divided)
0387                     {
0388                         if (! geometry::is_empty(mls2_diff_mpo1))
0389                         {
0390                             call_relate_ll(mls1, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy);
0391                         }
0392                     }
0393                     else
0394                     {
0395                         call_relate_ll(mls1, mls2, mls1_boundary, mls2_boundary, result, strategy);
0396                     }
0397                 }
0398 
0399                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0400                 {
0401                     return false;
0402                 }
0403 
0404                 // A/P
0405                 if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpt2))
0406                 {
0407                     inters_found[0][2] = true;
0408                     inters_found[1][0] = true;
0409                     call_relate(mpo1, mpt2, result, strategy);
0410                 }
0411 
0412                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0413                 {
0414                     return false;
0415                 }
0416 
0417                 // P/A
0418                 if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpo2))
0419                 {
0420                     inters_found[0][0] = true;
0421                     inters_found[1][2] = true;
0422                     call_relate(mpt1, mpo2, result, strategy);
0423                 }
0424 
0425                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0426                 {
0427                     return false;
0428                 }
0429 
0430                 // L/P
0431                 if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpt2))
0432                 {
0433                     inters_found[0][1] = true;
0434                     inters_found[1][0] = true;
0435                     call_relate(mls1, mpt2, result, strategy);
0436                 }
0437 
0438                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0439                 {
0440                     return false;
0441                 }
0442 
0443                 // P/L
0444                 if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mls2))
0445                 {
0446                     inters_found[0][0] = true;
0447                     inters_found[1][1] = true;
0448                     call_relate(mpt1, mls2, result, strategy);
0449                 }
0450 
0451                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0452                 {
0453                     return false;
0454                 }
0455 
0456                 // P/P
0457                 if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpt2))
0458                 {
0459                     inters_found[0][0] = true;
0460                     inters_found[1][0] = true;
0461                     call_relate(mpt1, mpt2, result, strategy);
0462                 }
0463 
0464                 if (BOOST_GEOMETRY_CONDITION(result.interrupt))
0465                 {
0466                     return false;
0467                 }
0468 
0469                 return true;
0470             },
0471             [&](auto const& disjoint_group)
0472             {
0473                 for (auto const& id : disjoint_group)
0474                 {
0475                     BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1);
0476                     if (id.source_id == 0)
0477                     {
0478                         traits::iter_visit<gc1_view_t>::apply([&](auto const& g1)
0479                         {
0480                             if (! geometry::is_empty(g1))
0481                             {
0482                                 static const std::size_t index = kind_id<util::remove_cref_t<decltype(g1)>>::value;
0483                                 disjoint_found[0][index] = true;
0484                                 disjoint_linear_boundary_found[0] = has_linear_boundary(g1, strategy);
0485                                 has_disjoint = true;
0486                             }
0487                         }, boost::begin(gc1_view) + id.gc_id);
0488                     }
0489                     else
0490                     {
0491                         traits::iter_visit<gc2_view_t>::apply([&](auto const& g2)
0492                         {
0493                             if (! geometry::is_empty(g2))
0494                             {
0495                                 static const std::size_t index = kind_id<util::remove_cref_t<decltype(g2)>>::value;
0496                                 disjoint_found[1][index] = true;
0497                                 disjoint_linear_boundary_found[1] = has_linear_boundary(g2, strategy);
0498                                 has_disjoint = true;
0499                             }
0500                         }, boost::begin(gc2_view) + id.gc_id);
0501                     }
0502                 }
0503             }, true);
0504 
0505         // Based on found disjoint geometries as well as those intersecting set exteriors
0506         if (has_disjoint)
0507         {
0508             if (disjoint_found[0][2] == true)
0509             {
0510                 update<interior, exterior, '2'>(result);
0511                 update<boundary, exterior, '1'>(result);
0512             }
0513             else if (disjoint_found[0][1] == true)
0514             {
0515                 update<interior, exterior, '1'>(result);
0516                 if (disjoint_linear_boundary_found[0])
0517                 {
0518                     update<boundary, exterior, '0'>(result);
0519                 }
0520             }
0521             else if (disjoint_found[0][0] == true)
0522             {
0523                 update<interior, exterior, '0'>(result);
0524             }
0525 
0526             if (disjoint_found[1][2] == true)
0527             {
0528                 update<exterior, interior, '2'>(result);
0529                 update<exterior, boundary, '1'>(result);
0530             }
0531             else if (disjoint_found[1][1] == true)
0532             {
0533                 update<exterior, interior, '1'>(result);
0534                 if (disjoint_linear_boundary_found[1])
0535                 {
0536                     update<exterior, boundary, '0'>(result);
0537                 }
0538             }
0539             else if (disjoint_found[1][0] == true)
0540             {
0541                 update<exterior, interior, '0'>(result);
0542             }
0543         }
0544     }
0545 
0546 private:
0547     template <typename Tuple, typename Geometry, typename Strategy>
0548     static inline void merge_geometry(Tuple& tuple, Geometry const& geometry, Strategy const& strategy)
0549     {
0550         static const std::size_t index = kind_id<Geometry>::value;
0551         typename boost::tuples::element<index, Tuple>::type temp_out;
0552         geometry::union_(boost::get<index>(tuple), geometry, temp_out, strategy);
0553         boost::get<index>(tuple) = std::move(temp_out);
0554     }
0555 
0556     template <typename Tuple, typename Strategy>
0557     static inline void subtract_elements(Tuple& tuple, Strategy const& strategy)
0558     {
0559         if (! geometry::is_empty(boost::get<1>(tuple)))
0560         {
0561             if (! geometry::is_empty(boost::get<2>(tuple)))
0562             {
0563                 typename boost::tuples::element<1, Tuple>::type mls;
0564                 geometry::difference(boost::get<1>(tuple), boost::get<2>(tuple), mls, strategy);
0565                 boost::get<1>(tuple) = std::move(mls);
0566             }
0567         }
0568         if (! geometry::is_empty(boost::get<0>(tuple)))
0569         {
0570             if (! geometry::is_empty(boost::get<2>(tuple)))
0571             {
0572                 typename boost::tuples::element<0, Tuple>::type mpt;
0573                 geometry::difference(boost::get<0>(tuple), boost::get<2>(tuple), mpt, strategy);
0574                 boost::get<0>(tuple) = std::move(mpt);
0575             }
0576             if (! geometry::is_empty(boost::get<1>(tuple)))
0577             {
0578                 typename boost::tuples::element<0, Tuple>::type mpt;
0579                 geometry::difference(boost::get<0>(tuple), boost::get<1>(tuple), mpt, strategy);
0580                 boost::get<0>(tuple) = std::move(mpt);
0581             }
0582         }
0583     }
0584 
0585     template
0586     <
0587         typename Geometry, typename Strategy,
0588         std::enable_if_t<util::is_linear<Geometry>::value, int> = 0
0589     >
0590     static inline bool has_linear_boundary(Geometry const& geometry, Strategy const& strategy)
0591     {
0592         topology_check<Geometry, Strategy> tc(geometry, strategy);
0593         return tc.has_boundary();
0594     }
0595 
0596     template
0597     <
0598         typename Geometry, typename Strategy,
0599         std::enable_if_t<! util::is_linear<Geometry>::value, int> = 0
0600     >
0601     static inline bool has_linear_boundary(Geometry const& , Strategy const& )
0602     {
0603         return false;
0604     }
0605 
0606 
0607     template <typename Multi1, typename Multi2, typename Result, typename Strategy>
0608     static inline void call_relate(Multi1 const& multi1, Multi2 const& multi2,
0609                                    Result& result, Strategy const& strategy)
0610     {
0611         dispatch::relate
0612             <
0613                 Multi1, Multi2
0614             >::apply(multi1, multi2, result, strategy);
0615     }
0616 
0617     template <typename MLs, typename MPo, typename MLsBoundary, typename Result, typename Strategy>
0618     static inline void call_relate_la(MLs const& mls, MPo const& mpo,
0619                                       MLsBoundary const& mls_boundary,
0620                                       Result& result, Strategy const& strategy)
0621     {
0622         linear_areal<MLs, MPo>::apply(mls, mpo, mls_boundary, result, strategy);
0623     }
0624 
0625     template <typename MPo, typename MLs, typename MLsBoundary, typename Result, typename Strategy>
0626     static inline void call_relate_al(MPo const& mls, MLs const& mpo,
0627                                       MLsBoundary const& mls_boundary,
0628                                       Result& result, Strategy const& strategy)
0629     {
0630         areal_linear<MPo, MLs>::apply(mls, mpo, mls_boundary, result, strategy);
0631     }
0632 
0633     template <typename MLs1, typename MLs2, typename MLs1Boundary, typename MLs2Boundary, typename Result, typename Strategy>
0634     static inline void call_relate_ll(MLs1 const& mls1, MLs2 const& mls2,
0635                                       MLs1Boundary const& mls1_boundary,
0636                                       MLs2Boundary const& mls2_boundary,
0637                                       Result& result, Strategy const& strategy)
0638     {
0639         linear_linear<MLs1, MLs2>::apply(mls1, mls2, mls1_boundary, mls2_boundary,
0640                                                          result, strategy);
0641     }
0642 
0643 
0644 };
0645 
0646 
0647 }} // namespace detail::relate
0648 #endif // DOXYGEN_NO_DETAIL
0649 
0650 
0651 #ifndef DOXYGEN_NO_DISPATCH
0652 namespace dispatch {
0653 
0654 template <typename Geometry1, typename Geometry2>
0655 struct relate<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag, -1, -1, false>
0656     : detail::relate::gc_gc<Geometry1, Geometry2>
0657 {};
0658 
0659 
0660 template <typename Geometry1, typename Geometry2, typename Tag1, int TopDim1>
0661 struct relate<Geometry1, Geometry2, Tag1, geometry_collection_tag, TopDim1, -1, false>
0662 {
0663     static const bool interruption_enabled = true;
0664 
0665     template <typename Result, typename Strategy>
0666     static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
0667                              Result & result,
0668                              Strategy const& strategy)
0669     {
0670         using gc1_view_t = detail::geometry_collection_view<Geometry1>;
0671         relate<gc1_view_t, Geometry2>::apply(gc1_view_t(geometry1), geometry2, result, strategy);
0672     }
0673 };
0674 
0675 template <typename Geometry1, typename Geometry2, typename Tag2, int TopDim2>
0676 struct relate<Geometry1, Geometry2, geometry_collection_tag, Tag2, -1, TopDim2, false>
0677 {
0678     static const bool interruption_enabled = true;
0679 
0680     template <typename Result, typename Strategy>
0681     static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
0682                              Result & result,
0683                              Strategy const& strategy)
0684     {
0685         using gc2_view_t = detail::geometry_collection_view<Geometry2>;
0686         relate<Geometry1, gc2_view_t>::apply(geometry1, gc2_view_t(geometry2), result, strategy);
0687     }
0688 };
0689 
0690 } // namespace dispatch
0691 #endif // DOXYGEN_NO_DISPATCH
0692 
0693 
0694 }} // namespace boost::geometry
0695 
0696 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP