multi_point_geometry.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. // Boost.Geometry
  2. // Copyright (c) 2014-2023, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  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_MULTI_POINT_GEOMETRY_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
  10. #include <boost/range/begin.hpp>
  11. #include <boost/range/end.hpp>
  12. #include <boost/range/size.hpp>
  13. #include <boost/range/value_type.hpp>
  14. #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
  15. #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
  16. #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
  17. #include <boost/geometry/algorithms/detail/partition.hpp>
  18. #include <boost/geometry/algorithms/detail/relate/result.hpp>
  19. #include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
  20. #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
  21. #include <boost/geometry/algorithms/envelope.hpp>
  22. #include <boost/geometry/core/point_type.hpp>
  23. #include <boost/geometry/geometries/box.hpp>
  24. #include <boost/geometry/index/rtree.hpp>
  25. // TEMP
  26. #include <boost/geometry/strategies/envelope/cartesian.hpp>
  27. #include <boost/geometry/strategies/envelope/geographic.hpp>
  28. #include <boost/geometry/strategies/envelope/spherical.hpp>
  29. #include <boost/geometry/util/type_traits.hpp>
  30. namespace boost { namespace geometry
  31. {
  32. #ifndef DOXYGEN_NO_DETAIL
  33. namespace detail { namespace relate
  34. {
  35. template
  36. <
  37. typename Geometry,
  38. typename Tag = typename tag<Geometry>::type
  39. >
  40. struct multi_point_geometry_eb
  41. {
  42. template <typename MultiPoint, typename Strategy>
  43. static inline bool apply(MultiPoint const& ,
  44. detail::relate::topology_check<Geometry, Strategy> const& )
  45. {
  46. return true;
  47. }
  48. };
  49. template <typename Geometry>
  50. struct multi_point_geometry_eb<Geometry, linestring_tag>
  51. {
  52. template <typename Points>
  53. struct boundary_visitor
  54. {
  55. boundary_visitor(Points const& points)
  56. : m_points(points)
  57. , m_boundary_found(false)
  58. {}
  59. template <typename Point, typename Strategy>
  60. struct find_pred
  61. {
  62. find_pred(Point const& point, Strategy const& strategy)
  63. : m_point(point)
  64. , m_strategy(strategy)
  65. {}
  66. template <typename Pt>
  67. bool operator()(Pt const& pt) const
  68. {
  69. return detail::equals::equals_point_point(pt, m_point, m_strategy);
  70. }
  71. Point const& m_point;
  72. Strategy const& m_strategy;
  73. };
  74. template <typename Point, typename Strategy>
  75. bool apply(Point const& boundary_point, Strategy const& strategy)
  76. {
  77. if ( std::none_of(m_points.begin(), m_points.end(),
  78. find_pred<Point, Strategy>(boundary_point, strategy)))
  79. {
  80. m_boundary_found = true;
  81. return false;
  82. }
  83. return true;
  84. }
  85. bool result() const { return m_boundary_found; }
  86. private:
  87. Points const& m_points;
  88. bool m_boundary_found;
  89. };
  90. template <typename MultiPoint, typename Strategy>
  91. static inline bool apply(MultiPoint const& multi_point,
  92. detail::relate::topology_check<Geometry, Strategy> const& tc)
  93. {
  94. boundary_visitor<MultiPoint> visitor(multi_point);
  95. tc.for_each_boundary_point(visitor);
  96. return visitor.result();
  97. }
  98. };
  99. template <typename Geometry>
  100. struct multi_point_geometry_eb<Geometry, multi_linestring_tag>
  101. {
  102. template <typename Points>
  103. struct boundary_visitor
  104. {
  105. boundary_visitor(Points const& points)
  106. : m_points(points)
  107. , m_boundary_found(false)
  108. {}
  109. template <typename Point, typename Strategy>
  110. bool apply(Point const& boundary_point, Strategy const&)
  111. {
  112. typedef geometry::less<void, -1, Strategy> less_type;
  113. if (! std::binary_search(m_points.begin(), m_points.end(),
  114. boundary_point, less_type()) )
  115. {
  116. m_boundary_found = true;
  117. return false;
  118. }
  119. return true;
  120. }
  121. bool result() const { return m_boundary_found; }
  122. private:
  123. Points const& m_points;
  124. bool m_boundary_found;
  125. };
  126. template <typename MultiPoint, typename Strategy>
  127. static inline bool apply(MultiPoint const& multi_point,
  128. detail::relate::topology_check<Geometry, Strategy> const& tc)
  129. {
  130. typedef typename boost::range_value<MultiPoint>::type point_type;
  131. typedef std::vector<point_type> points_type;
  132. typedef geometry::less<void, -1, Strategy> less_type;
  133. points_type points(boost::begin(multi_point), boost::end(multi_point));
  134. std::sort(points.begin(), points.end(), less_type());
  135. boundary_visitor<points_type> visitor(points);
  136. tc.for_each_boundary_point(visitor);
  137. return visitor.result();
  138. }
  139. };
  140. // SingleGeometry - Linear or Areal
  141. template <typename MultiPoint, typename SingleGeometry, bool Transpose = false>
  142. struct multi_point_single_geometry
  143. {
  144. static const bool interruption_enabled = true;
  145. template <typename Result, typename Strategy>
  146. static inline void apply(MultiPoint const& multi_point,
  147. SingleGeometry const& single_geometry,
  148. Result & result,
  149. Strategy const& strategy)
  150. {
  151. typedef typename point_type<SingleGeometry>::type point2_type;
  152. typedef model::box<point2_type> box2_type;
  153. box2_type box2;
  154. geometry::envelope(single_geometry, box2, strategy);
  155. geometry::detail::expand_by_epsilon(box2);
  156. for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it)
  157. {
  158. if (! (relate::may_update<interior, interior, '0', Transpose>(result)
  159. || relate::may_update<interior, boundary, '0', Transpose>(result)
  160. || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
  161. {
  162. break;
  163. }
  164. // The default strategy is enough for Point/Box
  165. if (detail::disjoint::disjoint_point_box(*it, box2, strategy))
  166. {
  167. update<interior, exterior, '0', Transpose>(result);
  168. }
  169. else
  170. {
  171. int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy);
  172. if (in_val > 0) // within
  173. {
  174. update<interior, interior, '0', Transpose>(result);
  175. }
  176. else if (in_val == 0)
  177. {
  178. update<interior, boundary, '0', Transpose>(result);
  179. }
  180. else // in_val < 0 - not within
  181. {
  182. update<interior, exterior, '0', Transpose>(result);
  183. }
  184. }
  185. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  186. {
  187. return;
  188. }
  189. }
  190. typedef detail::relate::topology_check<SingleGeometry, Strategy> tc_t;
  191. if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
  192. || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
  193. {
  194. tc_t tc(single_geometry, strategy);
  195. if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
  196. && tc.has_interior() )
  197. {
  198. // TODO: this is not true if a linestring is degenerated to a point
  199. // then the interior has topological dimension = 0, not 1
  200. update<exterior, interior, tc_t::interior, Transpose>(result);
  201. }
  202. if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
  203. && tc.has_boundary() )
  204. {
  205. if (multi_point_geometry_eb<SingleGeometry>::apply(multi_point, tc))
  206. {
  207. update<exterior, boundary, tc_t::boundary, Transpose>(result);
  208. }
  209. }
  210. }
  211. update<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
  212. }
  213. };
  214. // MultiGeometry - Linear or Areal
  215. // part of the algorithm calculating II and IB when no IE has to be calculated
  216. // using partition()
  217. template <typename MultiPoint, typename MultiGeometry, bool Transpose>
  218. class multi_point_multi_geometry_ii_ib
  219. {
  220. template <typename Strategy>
  221. struct expand_box_point
  222. {
  223. expand_box_point(Strategy const& strategy)
  224. : m_strategy(strategy)
  225. {}
  226. template <typename Box, typename Point>
  227. inline void apply(Box& total, Point const& point) const
  228. {
  229. geometry::expand(total, point, m_strategy);
  230. }
  231. private:
  232. Strategy const& m_strategy;
  233. };
  234. template <typename Strategy>
  235. struct expand_box_box_pair
  236. {
  237. expand_box_box_pair(Strategy const& strategy)
  238. : m_strategy(strategy)
  239. {}
  240. template <typename Box, typename BoxPair>
  241. inline void apply(Box& total, BoxPair const& box_pair) const
  242. {
  243. geometry::expand(total, box_pair.first, m_strategy);
  244. }
  245. private:
  246. Strategy const& m_strategy;
  247. };
  248. template <typename Strategy>
  249. struct overlaps_box_point
  250. {
  251. overlaps_box_point(Strategy const& strategy)
  252. : m_strategy(strategy)
  253. {}
  254. template <typename Box, typename Point>
  255. inline bool apply(Box const& box, Point const& point) const
  256. {
  257. // The default strategy is enough for Point/Box
  258. return ! detail::disjoint::disjoint_point_box(point, box,
  259. m_strategy);
  260. }
  261. private:
  262. Strategy const& m_strategy;
  263. };
  264. template <typename Strategy>
  265. struct overlaps_box_box_pair
  266. {
  267. overlaps_box_box_pair(Strategy const& strategy)
  268. : m_strategy(strategy)
  269. {}
  270. template <typename Box, typename BoxPair>
  271. inline bool apply(Box const& box, BoxPair const& box_pair) const
  272. {
  273. // The default strategy is enough for Box/Box
  274. return ! detail::disjoint::disjoint_box_box(box_pair.first, box,
  275. m_strategy);
  276. }
  277. private:
  278. Strategy const& m_strategy;
  279. };
  280. template <typename Result, typename Strategy>
  281. class item_visitor_type
  282. {
  283. typedef detail::relate::topology_check<MultiGeometry, Strategy> topology_check_type;
  284. public:
  285. item_visitor_type(MultiGeometry const& multi_geometry,
  286. topology_check_type const& tc,
  287. Result & result,
  288. Strategy const& strategy)
  289. : m_multi_geometry(multi_geometry)
  290. , m_tc(tc)
  291. , m_result(result)
  292. , m_strategy(strategy)
  293. {}
  294. template <typename Point, typename BoxPair>
  295. inline bool apply(Point const& point, BoxPair const& box_pair)
  296. {
  297. // The default strategy is enough for Point/Box
  298. if (! detail::disjoint::disjoint_point_box(point, box_pair.first, m_strategy) )
  299. {
  300. typename boost::range_value<MultiGeometry>::type const&
  301. single = range::at(m_multi_geometry, box_pair.second);
  302. int in_val = detail::within::point_in_geometry(point, single, m_strategy);
  303. if (in_val > 0) // within
  304. {
  305. update<interior, interior, '0', Transpose>(m_result);
  306. }
  307. else if (in_val == 0)
  308. {
  309. if (m_tc.check_boundary_point(point))
  310. {
  311. update<interior, boundary, '0', Transpose>(m_result);
  312. }
  313. else
  314. {
  315. update<interior, interior, '0', Transpose>(m_result);
  316. }
  317. }
  318. }
  319. if ( BOOST_GEOMETRY_CONDITION(m_result.interrupt) )
  320. {
  321. return false;
  322. }
  323. if (! (relate::may_update<interior, interior, '0', Transpose>(m_result)
  324. || relate::may_update<interior, boundary, '0', Transpose>(m_result) ) )
  325. {
  326. return false;
  327. }
  328. return true;
  329. }
  330. private:
  331. MultiGeometry const& m_multi_geometry;
  332. topology_check_type const& m_tc;
  333. Result & m_result;
  334. Strategy const& m_strategy;
  335. };
  336. public:
  337. typedef typename point_type<MultiPoint>::type point1_type;
  338. typedef typename point_type<MultiGeometry>::type point2_type;
  339. typedef model::box<point1_type> box1_type;
  340. typedef model::box<point2_type> box2_type;
  341. typedef std::pair<box2_type, std::size_t> box_pair_type;
  342. template <typename Result, typename Strategy>
  343. static inline void apply(MultiPoint const& multi_point,
  344. MultiGeometry const& multi_geometry,
  345. std::vector<box_pair_type> const& boxes,
  346. detail::relate::topology_check
  347. <
  348. MultiGeometry, Strategy
  349. > const& tc,
  350. Result & result,
  351. Strategy const& strategy)
  352. {
  353. item_visitor_type<Result, Strategy> visitor(multi_geometry, tc, result, strategy);
  354. geometry::partition
  355. <
  356. box1_type
  357. >::apply(multi_point, boxes, visitor,
  358. expand_box_point<Strategy>(strategy),
  359. overlaps_box_point<Strategy>(strategy),
  360. expand_box_box_pair<Strategy>(strategy),
  361. overlaps_box_box_pair<Strategy>(strategy));
  362. }
  363. };
  364. // MultiGeometry - Linear or Areal
  365. // part of the algorithm calculating II, IB and IE
  366. // using rtree
  367. template <typename MultiPoint, typename MultiGeometry, bool Transpose>
  368. struct multi_point_multi_geometry_ii_ib_ie
  369. {
  370. typedef typename point_type<MultiPoint>::type point1_type;
  371. typedef typename point_type<MultiGeometry>::type point2_type;
  372. typedef model::box<point1_type> box1_type;
  373. typedef model::box<point2_type> box2_type;
  374. typedef std::pair<box2_type, std::size_t> box_pair_type;
  375. typedef std::vector<box_pair_type> boxes_type;
  376. template <typename Result, typename Strategy>
  377. static inline void apply(MultiPoint const& multi_point,
  378. MultiGeometry const& multi_geometry,
  379. std::vector<box_pair_type> const& boxes,
  380. detail::relate::topology_check
  381. <
  382. MultiGeometry, Strategy
  383. > const& tc,
  384. Result & result,
  385. Strategy const& strategy)
  386. {
  387. typedef index::parameters
  388. <
  389. index::rstar<4>, Strategy
  390. > index_parameters_type;
  391. index::rtree<box_pair_type, index_parameters_type>
  392. rtree(boxes.begin(), boxes.end(),
  393. index_parameters_type(index::rstar<4>(), strategy));
  394. for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it)
  395. {
  396. if (! (relate::may_update<interior, interior, '0', Transpose>(result)
  397. || relate::may_update<interior, boundary, '0', Transpose>(result)
  398. || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
  399. {
  400. return;
  401. }
  402. typename boost::range_value<MultiPoint>::type const& point = *it;
  403. boxes_type boxes_found;
  404. rtree.query(index::intersects(point), std::back_inserter(boxes_found));
  405. bool found_ii_or_ib = false;
  406. for (auto const& box_found : boxes_found)
  407. {
  408. typename boost::range_value<MultiGeometry>::type const&
  409. single = range::at(multi_geometry, box_found.second);
  410. int in_val = detail::within::point_in_geometry(point, single, strategy);
  411. if (in_val > 0) // within
  412. {
  413. update<interior, interior, '0', Transpose>(result);
  414. found_ii_or_ib = true;
  415. }
  416. else if (in_val == 0) // on boundary of single
  417. {
  418. if (tc.check_boundary_point(point))
  419. {
  420. update<interior, boundary, '0', Transpose>(result);
  421. }
  422. else
  423. {
  424. update<interior, interior, '0', Transpose>(result);
  425. }
  426. found_ii_or_ib = true;
  427. }
  428. }
  429. // neither interior nor boundary found -> exterior
  430. if (found_ii_or_ib == false)
  431. {
  432. update<interior, exterior, '0', Transpose>(result);
  433. }
  434. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  435. {
  436. return;
  437. }
  438. }
  439. }
  440. };
  441. // MultiGeometry - Linear or Areal
  442. template <typename MultiPoint, typename MultiGeometry, bool Transpose = false>
  443. struct multi_point_multi_geometry
  444. {
  445. static const bool interruption_enabled = true;
  446. template <typename Result, typename Strategy>
  447. static inline void apply(MultiPoint const& multi_point,
  448. MultiGeometry const& multi_geometry,
  449. Result & result,
  450. Strategy const& strategy)
  451. {
  452. typedef typename point_type<MultiGeometry>::type point2_type;
  453. typedef model::box<point2_type> box2_type;
  454. typedef std::pair<box2_type, std::size_t> box_pair_type;
  455. std::size_t count2 = boost::size(multi_geometry);
  456. std::vector<box_pair_type> boxes(count2);
  457. for (std::size_t i = 0 ; i < count2 ; ++i)
  458. {
  459. geometry::envelope(range::at(multi_geometry, i), boxes[i].first, strategy);
  460. geometry::detail::expand_by_epsilon(boxes[i].first);
  461. boxes[i].second = i;
  462. }
  463. typedef detail::relate::topology_check<MultiGeometry, Strategy> tc_t;
  464. tc_t tc(multi_geometry, strategy);
  465. if ( relate::may_update<interior, interior, '0', Transpose>(result)
  466. || relate::may_update<interior, boundary, '0', Transpose>(result)
  467. || relate::may_update<interior, exterior, '0', Transpose>(result) )
  468. {
  469. // If there is no need to calculate IE, use partition
  470. if (! relate::may_update<interior, exterior, '0', Transpose>(result) )
  471. {
  472. multi_point_multi_geometry_ii_ib<MultiPoint, MultiGeometry, Transpose>
  473. ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
  474. }
  475. else // otherwise use rtree
  476. {
  477. multi_point_multi_geometry_ii_ib_ie<MultiPoint, MultiGeometry, Transpose>
  478. ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
  479. }
  480. }
  481. if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
  482. {
  483. return;
  484. }
  485. if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
  486. || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
  487. {
  488. if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
  489. && tc.has_interior() )
  490. {
  491. // TODO: this is not true if a linestring is degenerated to a point
  492. // then the interior has topological dimension = 0, not 1
  493. update<exterior, interior, tc_t::interior, Transpose>(result);
  494. }
  495. if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
  496. && tc.has_boundary() )
  497. {
  498. if (multi_point_geometry_eb<MultiGeometry>::apply(multi_point, tc))
  499. {
  500. update<exterior, boundary, tc_t::boundary, Transpose>(result);
  501. }
  502. }
  503. }
  504. update<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
  505. }
  506. };
  507. template
  508. <
  509. typename MultiPoint, typename Geometry,
  510. bool Transpose = false,
  511. bool isMulti = util::is_multi<Geometry>::value
  512. >
  513. struct multi_point_geometry
  514. : multi_point_single_geometry<MultiPoint, Geometry, Transpose>
  515. {};
  516. template <typename MultiPoint, typename Geometry, bool Transpose>
  517. struct multi_point_geometry<MultiPoint, Geometry, Transpose, true>
  518. : multi_point_multi_geometry<MultiPoint, Geometry, Transpose>
  519. {};
  520. // transposed result of multi_point_geometry
  521. template <typename Geometry, typename MultiPoint>
  522. struct geometry_multi_point
  523. {
  524. static const bool interruption_enabled = true;
  525. template <typename Result, typename Strategy>
  526. static inline void apply(Geometry const& geometry, MultiPoint const& multi_point,
  527. Result & result, Strategy const& strategy)
  528. {
  529. multi_point_geometry<MultiPoint, Geometry, true>::apply(multi_point, geometry, result, strategy);
  530. }
  531. };
  532. }} // namespace detail::relate
  533. #endif // DOXYGEN_NO_DETAIL
  534. }} // namespace boost::geometry
  535. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP