implementation_gc.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. // Boost.Geometry
  2. // Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland.
  3. // Copyright (c) 2022 Oracle and/or its affiliates.
  4. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP
  10. #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
  11. #include <boost/geometry/algorithms/detail/relate/interface.hpp>
  12. #include <boost/geometry/algorithms/difference.hpp>
  13. #include <boost/geometry/algorithms/intersection.hpp>
  14. #include <boost/geometry/algorithms/is_empty.hpp>
  15. #include <boost/geometry/algorithms/union.hpp>
  16. #include <boost/geometry/geometries/linestring.hpp>
  17. #include <boost/geometry/geometries/multi_linestring.hpp>
  18. #include <boost/geometry/geometries/multi_point.hpp>
  19. #include <boost/geometry/geometries/multi_polygon.hpp>
  20. #include <boost/geometry/geometries/polygon.hpp>
  21. #include <boost/geometry/util/condition.hpp>
  22. #include <boost/geometry/views/detail/geometry_collection_view.hpp>
  23. namespace boost { namespace geometry
  24. {
  25. #ifndef DOXYGEN_NO_DETAIL
  26. namespace detail { namespace relate
  27. {
  28. // For fields II IE and EI this handler behaves like matrix_handler.
  29. // It has to be created at the beginning of processing because it relies on the
  30. // fact that all of the fields are set to F and no geometry was handled yet.
  31. // This way it can check which fields are required for any mask and matrix
  32. // without accessing the internals.
  33. // An alternative would be to remove this wrapper and always set the matrix
  34. // in static_mask_handler even if this is not required.
  35. template <typename Handler>
  36. struct aa_handler_wrapper
  37. {
  38. bool interrupt = false;
  39. explicit aa_handler_wrapper(Handler& handler)
  40. : m_handler(handler)
  41. , m_overwrite_ii(! handler.template may_update<interior, interior, '2'>())
  42. , m_overwrite_ie(! handler.template may_update<interior, exterior, '2'>())
  43. , m_overwrite_ei(! handler.template may_update<exterior, interior, '2'>())
  44. {}
  45. template <field F1, field F2, char D>
  46. inline bool may_update() const
  47. {
  48. if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii)
  49. || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie)
  50. || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei))
  51. {
  52. char const c = m_handler.template get<F1, F2>();
  53. return D > c || c > '9';
  54. }
  55. else
  56. {
  57. return m_handler.template may_update<F1, F2, D>();
  58. }
  59. }
  60. template <field F1, field F2, char V>
  61. inline void update()
  62. {
  63. if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii)
  64. || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie)
  65. || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei))
  66. {
  67. // NOTE: Other handlers first check for potential interruption
  68. // and only after that checks update condition.
  69. char const c = m_handler.template get<F1, F2>();
  70. // If c == T and V == T it will be set anyway but that's fine.
  71. if (V > c || c > '9')
  72. {
  73. // set may set interrupt flag
  74. m_handler.template set<F1, F2, V>();
  75. }
  76. }
  77. else
  78. {
  79. m_handler.template update<F1, F2, V>();
  80. }
  81. interrupt = interrupt || m_handler.interrupt;
  82. }
  83. private:
  84. Handler & m_handler;
  85. bool const m_overwrite_ii;
  86. bool const m_overwrite_ie;
  87. bool const m_overwrite_ei;
  88. };
  89. template <typename Geometry1, typename Geometry2>
  90. struct gc_gc
  91. {
  92. static const bool interruption_enabled = true;
  93. using mpt1_found_t = typename util::sequence_find_if
  94. <
  95. typename traits::geometry_types<Geometry1>::type,
  96. util::is_multi_point
  97. >::type;
  98. using mls1_found_t = typename util::sequence_find_if
  99. <
  100. typename traits::geometry_types<Geometry1>::type,
  101. util::is_multi_linestring
  102. >::type;
  103. using mpo1_found_t = typename util::sequence_find_if
  104. <
  105. typename traits::geometry_types<Geometry1>::type,
  106. util::is_multi_polygon
  107. >::type;
  108. using pt1_t = typename geometry::point_type<Geometry1>::type;
  109. using mpt1_t = std::conditional_t
  110. <
  111. std::is_void<mpt1_found_t>::value,
  112. geometry::model::multi_point<pt1_t>,
  113. mpt1_found_t
  114. >;
  115. using mls1_t = std::conditional_t
  116. <
  117. std::is_void<mls1_found_t>::value,
  118. geometry::model::multi_linestring<geometry::model::linestring<pt1_t>>,
  119. mls1_found_t
  120. >;
  121. using mpo1_t = std::conditional_t
  122. <
  123. std::is_void<mpo1_found_t>::value,
  124. geometry::model::multi_polygon<geometry::model::polygon<pt1_t>>,
  125. mpo1_found_t
  126. >;
  127. using tuple1_t = boost::tuple<mpt1_t, mls1_t, mpo1_t>;
  128. using mpt2_found_t = typename util::sequence_find_if
  129. <
  130. typename traits::geometry_types<Geometry2>::type,
  131. util::is_multi_point
  132. >::type;
  133. using mls2_found_t = typename util::sequence_find_if
  134. <
  135. typename traits::geometry_types<Geometry2>::type,
  136. util::is_multi_linestring
  137. >::type;
  138. using mpo2_found_t = typename util::sequence_find_if
  139. <
  140. typename traits::geometry_types<Geometry2>::type,
  141. util::is_multi_polygon
  142. >::type;
  143. using pt2_t = typename geometry::point_type<Geometry2>::type;
  144. using mpt2_t = std::conditional_t
  145. <
  146. std::is_void<mpt2_found_t>::value,
  147. geometry::model::multi_point<pt2_t>,
  148. mpt2_found_t
  149. >;
  150. using mls2_t = std::conditional_t
  151. <
  152. std::is_void<mls2_found_t>::value,
  153. geometry::model::multi_linestring<geometry::model::linestring<pt2_t>>,
  154. mls2_found_t
  155. >;
  156. using mpo2_t = std::conditional_t
  157. <
  158. std::is_void<mpo2_found_t>::value,
  159. geometry::model::multi_polygon<geometry::model::polygon<pt2_t>>,
  160. mpo2_found_t
  161. >;
  162. using tuple2_t = boost::tuple<mpt2_t, mls2_t, mpo2_t>;
  163. template <typename Geometry>
  164. using kind_id = util::index_constant
  165. <
  166. util::is_areal<Geometry>::value ? 2
  167. : util::is_linear<Geometry>::value ? 1
  168. : 0
  169. >;
  170. template <typename Result, typename Strategy>
  171. static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  172. Result & result,
  173. Strategy const& strategy)
  174. {
  175. using gc1_view_t = random_access_view<Geometry1 const>;
  176. using gc2_view_t = random_access_view<Geometry2 const>;
  177. gc1_view_t const gc1_view(geometry1);
  178. gc2_view_t const gc2_view(geometry2);
  179. bool inters_found[2][3] = {{false, false, false}, {false, false, false}};
  180. bool disjoint_found[2][3] = {{false, false, false}, {false, false, false}};
  181. bool disjoint_linear_boundary_found[2] = {false, false};
  182. bool has_disjoint = false;
  183. gc_group_elements(gc1_view, gc2_view, strategy,
  184. [&](auto const& inters_group)
  185. {
  186. tuple1_t tuple1;
  187. tuple2_t tuple2;
  188. // Create MPts, MLss and MPos containing all gc elements from this group
  189. // They may potentially intersect each other
  190. for (auto const& id : inters_group)
  191. {
  192. BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1);
  193. if (id.source_id == 0)
  194. {
  195. traits::iter_visit<gc1_view_t>::apply([&](auto const& g1)
  196. {
  197. merge_geometry(tuple1, g1, strategy);
  198. }, boost::begin(gc1_view) + id.gc_id);
  199. }
  200. else
  201. {
  202. traits::iter_visit<gc2_view_t>::apply([&](auto const& g2)
  203. {
  204. merge_geometry(tuple2, g2, strategy);
  205. }, boost::begin(gc2_view) + id.gc_id);
  206. }
  207. }
  208. // Subtract higher topo-dim elements from elements of lower topo-dim
  209. // MPts do not intersect other geometries, MLss and MPos may touch
  210. subtract_elements(tuple1, strategy);
  211. subtract_elements(tuple2, strategy);
  212. // Helpers
  213. auto const& mpt1 = boost::get<0>(tuple1);
  214. auto const& mls1 = boost::get<1>(tuple1);
  215. auto const& mpo1 = boost::get<2>(tuple1);
  216. auto const& mpt2 = boost::get<0>(tuple2);
  217. auto const& mls2 = boost::get<1>(tuple2);
  218. auto const& mpo2 = boost::get<2>(tuple2);
  219. // A/A
  220. if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpo2))
  221. {
  222. inters_found[0][2] = true;
  223. inters_found[1][2] = true;
  224. aa_handler_wrapper<Result> wrapper(result);
  225. call_relate(mpo1, mpo2, wrapper, strategy);
  226. }
  227. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  228. {
  229. return false;
  230. }
  231. bool is_aa_ii = result.template get<interior, interior>() != 'F';
  232. bool is_aa_ie = result.template get<interior, exterior>() != 'F';
  233. bool is_aa_ei = result.template get<exterior, interior>() != 'F';
  234. // is_aa_ii implies is_aa_checked and non-empty Areal geometries
  235. bool are_aa_equal = is_aa_ii && ! is_aa_ie && ! is_aa_ei;
  236. // Boundary checkers are internally initialized lazily later if a point has to be checked
  237. boundary_checker<mls1_t, Strategy> mls1_boundary(mls1, strategy);
  238. boundary_checker<mls2_t, Strategy> mls2_boundary(mls2, strategy);
  239. // If needed divide MLss into two parts:
  240. // - inside Areal of other GC
  241. // - outside of other GC Areal to check WRT Linear of other GC
  242. mls2_t mls2_diff_mpo1, mls2_inters_mpo1;
  243. bool is_mls2_divided = false;
  244. mls1_t mls1_diff_mpo2, mls1_inters_mpo2;
  245. bool is_mls1_divided = false;
  246. // If Areal are equal then Linear are outside of both so there is no need to divide
  247. if (! are_aa_equal && ! geometry::is_empty(mls1) && ! geometry::is_empty(mls2))
  248. {
  249. // LA/L
  250. if (! geometry::is_empty(mpo1))
  251. {
  252. geometry::difference(mls2, mpo1, mls2_diff_mpo1);
  253. geometry::intersection(mls2, mpo1, mls2_inters_mpo1);
  254. is_mls2_divided = true;
  255. }
  256. // L/LA
  257. if (! geometry::is_empty(mpo2))
  258. {
  259. geometry::difference(mls1, mpo2, mls1_diff_mpo2);
  260. geometry::intersection(mls1, mpo2, mls1_inters_mpo2);
  261. is_mls1_divided = true;
  262. }
  263. }
  264. // A/L
  265. if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mls2))
  266. {
  267. inters_found[0][2] = true;
  268. inters_found[1][1] = true;
  269. if (is_aa_ii && ! is_aa_ie && ! is_aa_ei && ! geometry::is_empty(mls1))
  270. {
  271. // Equal Areal and both Linear non-empty, calculate only L/L below
  272. }
  273. else if (is_aa_ii && ! is_aa_ie && geometry::is_empty(mls1))
  274. {
  275. // An alternative would be to calculate L/L with one empty below
  276. mpo1_t empty;
  277. call_relate_al(empty, mls2, mls2_boundary, result, strategy);
  278. }
  279. else
  280. {
  281. if (is_mls2_divided)
  282. {
  283. if (! geometry::is_empty(mls2_inters_mpo1))
  284. {
  285. call_relate_al(mpo1, mls2_inters_mpo1, mls2_boundary, result, strategy);
  286. }
  287. }
  288. else
  289. {
  290. call_relate_al(mpo1, mls2, mls2_boundary, result, strategy);
  291. }
  292. }
  293. }
  294. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  295. {
  296. return false;
  297. }
  298. // L/A
  299. if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpo2))
  300. {
  301. inters_found[0][1] = true;
  302. inters_found[1][2] = true;
  303. if (is_aa_ii && ! is_aa_ei && ! is_aa_ie && ! geometry::is_empty(mls2))
  304. {
  305. // Equal Areal and both Linear non-empty, calculate only L/L below
  306. }
  307. else if (is_aa_ii && ! is_aa_ei && geometry::is_empty(mls2))
  308. {
  309. // An alternative would be to calculate L/L with one empty below
  310. mpo2_t empty;
  311. call_relate_la(mls1, empty, mls1_boundary, result, strategy);
  312. }
  313. else
  314. {
  315. if (is_mls1_divided)
  316. {
  317. if (! geometry::is_empty(mls1_inters_mpo2))
  318. {
  319. call_relate_la(mls1_inters_mpo2, mpo2, mls1_boundary, result, strategy);
  320. }
  321. }
  322. else
  323. {
  324. call_relate_la(mls1, mpo2, mls1_boundary, result, strategy);
  325. }
  326. }
  327. }
  328. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  329. {
  330. return false;
  331. }
  332. // L/L
  333. if (! geometry::is_empty(mls1) && ! geometry::is_empty(mls2))
  334. {
  335. inters_found[0][1] = true;
  336. inters_found[1][1] = true;
  337. if (is_mls1_divided && is_mls2_divided)
  338. {
  339. if (! geometry::is_empty(mls1_diff_mpo2) && ! geometry::is_empty(mls2_diff_mpo1))
  340. {
  341. call_relate_ll(mls1_diff_mpo2, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy);
  342. }
  343. }
  344. else if (is_mls1_divided)
  345. {
  346. if (! geometry::is_empty(mls1_diff_mpo2))
  347. {
  348. call_relate_ll(mls1_diff_mpo2, mls2, mls1_boundary, mls2_boundary, result, strategy);
  349. }
  350. }
  351. else if (is_mls2_divided)
  352. {
  353. if (! geometry::is_empty(mls2_diff_mpo1))
  354. {
  355. call_relate_ll(mls1, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy);
  356. }
  357. }
  358. else
  359. {
  360. call_relate_ll(mls1, mls2, mls1_boundary, mls2_boundary, result, strategy);
  361. }
  362. }
  363. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  364. {
  365. return false;
  366. }
  367. // A/P
  368. if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpt2))
  369. {
  370. inters_found[0][2] = true;
  371. inters_found[1][0] = true;
  372. call_relate(mpo1, mpt2, result, strategy);
  373. }
  374. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  375. {
  376. return false;
  377. }
  378. // P/A
  379. if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpo2))
  380. {
  381. inters_found[0][0] = true;
  382. inters_found[1][2] = true;
  383. call_relate(mpt1, mpo2, result, strategy);
  384. }
  385. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  386. {
  387. return false;
  388. }
  389. // L/P
  390. if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpt2))
  391. {
  392. inters_found[0][1] = true;
  393. inters_found[1][0] = true;
  394. call_relate(mls1, mpt2, result, strategy);
  395. }
  396. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  397. {
  398. return false;
  399. }
  400. // P/L
  401. if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mls2))
  402. {
  403. inters_found[0][0] = true;
  404. inters_found[1][1] = true;
  405. call_relate(mpt1, mls2, result, strategy);
  406. }
  407. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  408. {
  409. return false;
  410. }
  411. // P/P
  412. if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpt2))
  413. {
  414. inters_found[0][0] = true;
  415. inters_found[1][0] = true;
  416. call_relate(mpt1, mpt2, result, strategy);
  417. }
  418. if (BOOST_GEOMETRY_CONDITION(result.interrupt))
  419. {
  420. return false;
  421. }
  422. return true;
  423. },
  424. [&](auto const& disjoint_group)
  425. {
  426. for (auto const& id : disjoint_group)
  427. {
  428. BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1);
  429. if (id.source_id == 0)
  430. {
  431. traits::iter_visit<gc1_view_t>::apply([&](auto const& g1)
  432. {
  433. if (! geometry::is_empty(g1))
  434. {
  435. static const std::size_t index = kind_id<util::remove_cref_t<decltype(g1)>>::value;
  436. disjoint_found[0][index] = true;
  437. disjoint_linear_boundary_found[0] = has_linear_boundary(g1, strategy);
  438. has_disjoint = true;
  439. }
  440. }, boost::begin(gc1_view) + id.gc_id);
  441. }
  442. else
  443. {
  444. traits::iter_visit<gc2_view_t>::apply([&](auto const& g2)
  445. {
  446. if (! geometry::is_empty(g2))
  447. {
  448. static const std::size_t index = kind_id<util::remove_cref_t<decltype(g2)>>::value;
  449. disjoint_found[1][index] = true;
  450. disjoint_linear_boundary_found[1] = has_linear_boundary(g2, strategy);
  451. has_disjoint = true;
  452. }
  453. }, boost::begin(gc2_view) + id.gc_id);
  454. }
  455. }
  456. }, true);
  457. // Based on found disjoint geometries as well as those intersecting set exteriors
  458. if (has_disjoint)
  459. {
  460. if (disjoint_found[0][2] == true)
  461. {
  462. update<interior, exterior, '2'>(result);
  463. update<boundary, exterior, '1'>(result);
  464. }
  465. else if (disjoint_found[0][1] == true)
  466. {
  467. update<interior, exterior, '1'>(result);
  468. if (disjoint_linear_boundary_found[0])
  469. {
  470. update<boundary, exterior, '0'>(result);
  471. }
  472. }
  473. else if (disjoint_found[0][0] == true)
  474. {
  475. update<interior, exterior, '0'>(result);
  476. }
  477. if (disjoint_found[1][2] == true)
  478. {
  479. update<exterior, interior, '2'>(result);
  480. update<exterior, boundary, '1'>(result);
  481. }
  482. else if (disjoint_found[1][1] == true)
  483. {
  484. update<exterior, interior, '1'>(result);
  485. if (disjoint_linear_boundary_found[1])
  486. {
  487. update<exterior, boundary, '0'>(result);
  488. }
  489. }
  490. else if (disjoint_found[1][0] == true)
  491. {
  492. update<exterior, interior, '0'>(result);
  493. }
  494. }
  495. }
  496. private:
  497. template <typename Tuple, typename Geometry, typename Strategy>
  498. static inline void merge_geometry(Tuple& tuple, Geometry const& geometry, Strategy const& strategy)
  499. {
  500. static const std::size_t index = kind_id<Geometry>::value;
  501. typename boost::tuples::element<index, Tuple>::type temp_out;
  502. geometry::union_(boost::get<index>(tuple), geometry, temp_out, strategy);
  503. boost::get<index>(tuple) = std::move(temp_out);
  504. }
  505. template <typename Tuple, typename Strategy>
  506. static inline void subtract_elements(Tuple& tuple, Strategy const& strategy)
  507. {
  508. if (! geometry::is_empty(boost::get<1>(tuple)))
  509. {
  510. if (! geometry::is_empty(boost::get<2>(tuple)))
  511. {
  512. typename boost::tuples::element<1, Tuple>::type mls;
  513. geometry::difference(boost::get<1>(tuple), boost::get<2>(tuple), mls, strategy);
  514. boost::get<1>(tuple) = std::move(mls);
  515. }
  516. }
  517. if (! geometry::is_empty(boost::get<0>(tuple)))
  518. {
  519. if (! geometry::is_empty(boost::get<2>(tuple)))
  520. {
  521. typename boost::tuples::element<0, Tuple>::type mpt;
  522. geometry::difference(boost::get<0>(tuple), boost::get<2>(tuple), mpt, strategy);
  523. boost::get<0>(tuple) = std::move(mpt);
  524. }
  525. if (! geometry::is_empty(boost::get<1>(tuple)))
  526. {
  527. typename boost::tuples::element<0, Tuple>::type mpt;
  528. geometry::difference(boost::get<0>(tuple), boost::get<1>(tuple), mpt, strategy);
  529. boost::get<0>(tuple) = std::move(mpt);
  530. }
  531. }
  532. }
  533. template
  534. <
  535. typename Geometry, typename Strategy,
  536. std::enable_if_t<util::is_linear<Geometry>::value, int> = 0
  537. >
  538. static inline bool has_linear_boundary(Geometry const& geometry, Strategy const& strategy)
  539. {
  540. topology_check<Geometry, Strategy> tc(geometry, strategy);
  541. return tc.has_boundary();
  542. }
  543. template
  544. <
  545. typename Geometry, typename Strategy,
  546. std::enable_if_t<! util::is_linear<Geometry>::value, int> = 0
  547. >
  548. static inline bool has_linear_boundary(Geometry const& , Strategy const& )
  549. {
  550. return false;
  551. }
  552. template <typename Multi1, typename Multi2, typename Result, typename Strategy>
  553. static inline void call_relate(Multi1 const& multi1, Multi2 const& multi2,
  554. Result& result, Strategy const& strategy)
  555. {
  556. dispatch::relate
  557. <
  558. Multi1, Multi2
  559. >::apply(multi1, multi2, result, strategy);
  560. }
  561. template <typename MLs, typename MPo, typename MLsBoundary, typename Result, typename Strategy>
  562. static inline void call_relate_la(MLs const& mls, MPo const& mpo,
  563. MLsBoundary const& mls_boundary,
  564. Result& result, Strategy const& strategy)
  565. {
  566. linear_areal<MLs, MPo>::apply(mls, mpo, mls_boundary, result, strategy);
  567. }
  568. template <typename MPo, typename MLs, typename MLsBoundary, typename Result, typename Strategy>
  569. static inline void call_relate_al(MPo const& mls, MLs const& mpo,
  570. MLsBoundary const& mls_boundary,
  571. Result& result, Strategy const& strategy)
  572. {
  573. areal_linear<MPo, MLs>::apply(mls, mpo, mls_boundary, result, strategy);
  574. }
  575. template <typename MLs1, typename MLs2, typename MLs1Boundary, typename MLs2Boundary, typename Result, typename Strategy>
  576. static inline void call_relate_ll(MLs1 const& mls1, MLs2 const& mls2,
  577. MLs1Boundary const& mls1_boundary,
  578. MLs2Boundary const& mls2_boundary,
  579. Result& result, Strategy const& strategy)
  580. {
  581. linear_linear<MLs1, MLs2>::apply(mls1, mls2, mls1_boundary, mls2_boundary,
  582. result, strategy);
  583. }
  584. };
  585. }} // namespace detail::relate
  586. #endif // DOXYGEN_NO_DETAIL
  587. #ifndef DOXYGEN_NO_DISPATCH
  588. namespace dispatch {
  589. template <typename Geometry1, typename Geometry2>
  590. struct relate<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag, -1, -1, false>
  591. : detail::relate::gc_gc<Geometry1, Geometry2>
  592. {};
  593. template <typename Geometry1, typename Geometry2, typename Tag1, int TopDim1>
  594. struct relate<Geometry1, Geometry2, Tag1, geometry_collection_tag, TopDim1, -1, false>
  595. {
  596. static const bool interruption_enabled = true;
  597. template <typename Result, typename Strategy>
  598. static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  599. Result & result,
  600. Strategy const& strategy)
  601. {
  602. using gc1_view_t = detail::geometry_collection_view<Geometry1>;
  603. relate<gc1_view_t, Geometry2>::apply(gc1_view_t(geometry1), geometry2, result, strategy);
  604. }
  605. };
  606. template <typename Geometry1, typename Geometry2, typename Tag2, int TopDim2>
  607. struct relate<Geometry1, Geometry2, geometry_collection_tag, Tag2, -1, TopDim2, false>
  608. {
  609. static const bool interruption_enabled = true;
  610. template <typename Result, typename Strategy>
  611. static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  612. Result & result,
  613. Strategy const& strategy)
  614. {
  615. using gc2_view_t = detail::geometry_collection_view<Geometry2>;
  616. relate<Geometry1, gc2_view_t>::apply(geometry1, gc2_view_t(geometry2), result, strategy);
  617. }
  618. };
  619. } // namespace dispatch
  620. #endif // DOXYGEN_NO_DISPATCH
  621. }} // namespace boost::geometry
  622. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP