point_to_geometry.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
  5. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2014-2021.
  7. // Modifications copyright (c) 2014-2021, Oracle and/or its affiliates.
  8. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  9. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  10. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  11. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  12. // Use, modification and distribution is subject to the Boost Software License,
  13. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  14. // http://www.boost.org/LICENSE_1_0.txt)
  15. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
  16. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
  17. #include <iterator>
  18. #include <type_traits>
  19. #include <boost/core/ignore_unused.hpp>
  20. #include <boost/range/begin.hpp>
  21. #include <boost/range/end.hpp>
  22. #include <boost/range/size.hpp>
  23. #include <boost/range/value_type.hpp>
  24. #include <boost/geometry/algorithms/assign.hpp>
  25. #include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp>
  26. #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
  27. #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
  28. #include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
  29. #include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
  30. #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
  31. #include <boost/geometry/algorithms/dispatch/distance.hpp>
  32. #include <boost/geometry/core/closure.hpp>
  33. #include <boost/geometry/core/point_type.hpp>
  34. #include <boost/geometry/core/exterior_ring.hpp>
  35. #include <boost/geometry/core/interior_rings.hpp>
  36. #include <boost/geometry/core/tag.hpp>
  37. #include <boost/geometry/core/tags.hpp>
  38. #include <boost/geometry/strategies/distance.hpp>
  39. #include <boost/geometry/strategies/relate/services.hpp>
  40. #include <boost/geometry/strategies/tags.hpp>
  41. #include <boost/geometry/util/math.hpp>
  42. namespace boost { namespace geometry
  43. {
  44. #ifndef DOXYGEN_NO_DETAIL
  45. namespace detail { namespace distance
  46. {
  47. template
  48. <
  49. typename P1, typename P2, typename Strategies,
  50. bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
  51. >
  52. struct point_to_point
  53. {
  54. static inline
  55. auto apply(P1 const& p1, P2 const& p2, Strategies const& strategies)
  56. {
  57. boost::ignore_unused(strategies);
  58. return strategies.distance(p1, p2).apply(p1, p2);
  59. }
  60. };
  61. // TEMP?
  62. // called by geometry_to_range
  63. template <typename P1, typename P2, typename Strategy>
  64. struct point_to_point<P1, P2, Strategy, false>
  65. {
  66. static inline
  67. auto apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
  68. {
  69. boost::ignore_unused(strategy);
  70. return strategy.apply(p1, p2);
  71. }
  72. };
  73. template
  74. <
  75. typename Point, typename Segment, typename Strategies,
  76. bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
  77. >
  78. struct point_to_segment
  79. {
  80. static inline auto apply(Point const& point, Segment const& segment,
  81. Strategies const& strategies)
  82. {
  83. typename point_type<Segment>::type p[2];
  84. geometry::detail::assign_point_from_index<0>(segment, p[0]);
  85. geometry::detail::assign_point_from_index<1>(segment, p[1]);
  86. boost::ignore_unused(strategies);
  87. return strategies.distance(point, segment).apply(point, p[0], p[1]);
  88. }
  89. };
  90. // TEMP?
  91. // called by geometry_to_range
  92. template <typename Point, typename Segment, typename Strategy>
  93. struct point_to_segment<Point, Segment, Strategy, false>
  94. {
  95. static inline auto apply(Point const& point, Segment const& segment,
  96. Strategy const& strategy)
  97. {
  98. typename point_type<Segment>::type p[2];
  99. geometry::detail::assign_point_from_index<0>(segment, p[0]);
  100. geometry::detail::assign_point_from_index<1>(segment, p[1]);
  101. boost::ignore_unused(strategy);
  102. return strategy.apply(point, p[0], p[1]);
  103. }
  104. };
  105. template
  106. <
  107. typename Point, typename Box, typename Strategies,
  108. bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
  109. >
  110. struct point_to_box
  111. {
  112. static inline auto apply(Point const& point, Box const& box,
  113. Strategies const& strategies)
  114. {
  115. boost::ignore_unused(strategies);
  116. return strategies.distance(point, box).apply(point, box);
  117. }
  118. };
  119. // TEMP?
  120. // called by geometry_to_range
  121. template <typename Point, typename Box, typename Strategy>
  122. struct point_to_box<Point, Box, Strategy, false>
  123. {
  124. static inline auto apply(Point const& point, Box const& box,
  125. Strategy const& strategy)
  126. {
  127. boost::ignore_unused(strategy);
  128. return strategy.apply(point, box);
  129. }
  130. };
  131. template
  132. <
  133. typename Point,
  134. typename Range,
  135. closure_selector Closure,
  136. typename Strategies
  137. >
  138. class point_to_range
  139. {
  140. private:
  141. typedef distance::strategy_t<Point, Range, Strategies> strategy_type;
  142. typedef detail::closest_feature::point_to_point_range
  143. <
  144. Point, Range, Closure
  145. > point_to_point_range;
  146. public:
  147. typedef distance::return_t<Point, Range, Strategies> return_type;
  148. static inline return_type apply(Point const& point, Range const& range,
  149. Strategies const& strategies)
  150. {
  151. if (boost::size(range) == 0)
  152. {
  153. return return_type(0);
  154. }
  155. distance::creturn_t<Point, Range, Strategies> cd_min;
  156. std::pair
  157. <
  158. typename boost::range_iterator<Range const>::type,
  159. typename boost::range_iterator<Range const>::type
  160. > it_pair
  161. = point_to_point_range::apply(point,
  162. boost::begin(range),
  163. boost::end(range),
  164. strategy::distance::services::get_comparable
  165. <
  166. strategy_type
  167. >::apply(strategies.distance(point, range)),
  168. cd_min);
  169. return
  170. is_comparable<strategy_type>::value
  171. ?
  172. cd_min
  173. :
  174. strategies.distance(point, range).apply(point, *it_pair.first, *it_pair.second);
  175. }
  176. };
  177. template
  178. <
  179. typename Point,
  180. typename Ring,
  181. closure_selector Closure,
  182. typename Strategies
  183. >
  184. struct point_to_ring
  185. {
  186. typedef distance::return_t<Point, Ring, Strategies> return_type;
  187. static inline return_type apply(Point const& point,
  188. Ring const& ring,
  189. Strategies const& strategies)
  190. {
  191. if (within::within_point_geometry(point, ring, strategies))
  192. {
  193. return return_type(0);
  194. }
  195. return point_to_range
  196. <
  197. Point, Ring, closure<Ring>::value, Strategies
  198. >::apply(point, ring, strategies);
  199. }
  200. };
  201. template
  202. <
  203. typename Point,
  204. typename Polygon,
  205. closure_selector Closure,
  206. typename Strategies
  207. >
  208. class point_to_polygon
  209. {
  210. public:
  211. typedef distance::return_t<Point, Polygon, Strategies> return_type;
  212. private:
  213. typedef point_to_range
  214. <
  215. Point, typename ring_type<Polygon>::type, Closure, Strategies
  216. > per_ring;
  217. struct distance_to_interior_rings
  218. {
  219. template <typename InteriorRingIterator>
  220. static inline return_type apply(Point const& point,
  221. InteriorRingIterator first,
  222. InteriorRingIterator last,
  223. Strategies const& strategies)
  224. {
  225. for (InteriorRingIterator it = first; it != last; ++it)
  226. {
  227. if (within::within_point_geometry(point, *it, strategies))
  228. {
  229. // the point is inside a polygon hole, so its distance
  230. // to the polygon its distance to the polygon's
  231. // hole boundary
  232. return per_ring::apply(point, *it, strategies);
  233. }
  234. }
  235. return return_type(0);
  236. }
  237. template <typename InteriorRings>
  238. static inline return_type apply(Point const& point, InteriorRings const& interior_rings,
  239. Strategies const& strategies)
  240. {
  241. return apply(point,
  242. boost::begin(interior_rings),
  243. boost::end(interior_rings),
  244. strategies);
  245. }
  246. };
  247. public:
  248. static inline return_type apply(Point const& point,
  249. Polygon const& polygon,
  250. Strategies const& strategies)
  251. {
  252. if (! within::covered_by_point_geometry(point, exterior_ring(polygon),
  253. strategies))
  254. {
  255. // the point is outside the exterior ring, so its distance
  256. // to the polygon is its distance to the polygon's exterior ring
  257. return per_ring::apply(point, exterior_ring(polygon), strategies);
  258. }
  259. // Check interior rings
  260. return distance_to_interior_rings::apply(point,
  261. interior_rings(polygon),
  262. strategies);
  263. }
  264. };
  265. template
  266. <
  267. typename Point,
  268. typename MultiGeometry,
  269. typename Strategies,
  270. bool CheckCoveredBy = std::is_same
  271. <
  272. typename tag<MultiGeometry>::type, multi_polygon_tag
  273. >::value
  274. >
  275. class point_to_multigeometry
  276. {
  277. private:
  278. typedef detail::closest_feature::geometry_to_range geometry_to_range;
  279. typedef distance::strategy_t<Point, MultiGeometry, Strategies> strategy_type;
  280. public:
  281. typedef distance::return_t<Point, MultiGeometry, Strategies> return_type;
  282. static inline return_type apply(Point const& point,
  283. MultiGeometry const& multigeometry,
  284. Strategies const& strategies)
  285. {
  286. typedef iterator_selector<MultiGeometry const> selector_type;
  287. distance::creturn_t<Point, MultiGeometry, Strategies> cd;
  288. typename selector_type::iterator_type it_min
  289. = geometry_to_range::apply(point,
  290. selector_type::begin(multigeometry),
  291. selector_type::end(multigeometry),
  292. strategy::distance::services::get_comparable
  293. <
  294. strategy_type
  295. >::apply(strategies.distance(point, multigeometry)),
  296. cd);
  297. // TODO - It would be possible to use a tool similar to result_from_distance
  298. // but working in the opposite way, i.e. calculating the distance
  299. // value from comparable distance value. This way the additional distance
  300. // call would not be needed.
  301. return
  302. is_comparable<strategy_type>::value
  303. ?
  304. cd
  305. :
  306. dispatch::distance
  307. <
  308. Point,
  309. typename std::iterator_traits
  310. <
  311. typename selector_type::iterator_type
  312. >::value_type,
  313. Strategies
  314. >::apply(point, *it_min, strategies);
  315. }
  316. };
  317. // this is called only for multipolygons, hence the change in the
  318. // template parameter name MultiGeometry to MultiPolygon
  319. template <typename Point, typename MultiPolygon, typename Strategies>
  320. struct point_to_multigeometry<Point, MultiPolygon, Strategies, true>
  321. {
  322. typedef distance::return_t<Point, MultiPolygon, Strategies> return_type;
  323. static inline return_type apply(Point const& point,
  324. MultiPolygon const& multipolygon,
  325. Strategies const& strategies)
  326. {
  327. if (within::covered_by_point_geometry(point, multipolygon, strategies))
  328. {
  329. return return_type(0);
  330. }
  331. return point_to_multigeometry
  332. <
  333. Point, MultiPolygon, Strategies, false
  334. >::apply(point, multipolygon, strategies);
  335. }
  336. };
  337. }} // namespace detail::distance
  338. #endif // DOXYGEN_NO_DETAIL
  339. #ifndef DOXYGEN_NO_DISPATCH
  340. namespace dispatch
  341. {
  342. template <typename P1, typename P2, typename Strategy>
  343. struct distance
  344. <
  345. P1, P2, Strategy, point_tag, point_tag,
  346. strategy_tag_distance_point_point, false
  347. > : detail::distance::point_to_point<P1, P2, Strategy>
  348. {};
  349. template <typename Point, typename Linestring, typename Strategy>
  350. struct distance
  351. <
  352. Point, Linestring, Strategy, point_tag, linestring_tag,
  353. strategy_tag_distance_point_segment, false
  354. > : detail::distance::point_to_range<Point, Linestring, closed, Strategy>
  355. {};
  356. template <typename Point, typename Ring, typename Strategy>
  357. struct distance
  358. <
  359. Point, Ring, Strategy, point_tag, ring_tag,
  360. strategy_tag_distance_point_segment, false
  361. > : detail::distance::point_to_ring
  362. <
  363. Point, Ring, closure<Ring>::value, Strategy
  364. >
  365. {};
  366. template <typename Point, typename Polygon, typename Strategy>
  367. struct distance
  368. <
  369. Point, Polygon, Strategy, point_tag, polygon_tag,
  370. strategy_tag_distance_point_segment, false
  371. > : detail::distance::point_to_polygon
  372. <
  373. Point, Polygon, closure<Polygon>::value, Strategy
  374. >
  375. {};
  376. template <typename Point, typename Segment, typename Strategy>
  377. struct distance
  378. <
  379. Point, Segment, Strategy, point_tag, segment_tag,
  380. strategy_tag_distance_point_segment, false
  381. > : detail::distance::point_to_segment<Point, Segment, Strategy>
  382. {};
  383. template <typename Point, typename Box, typename Strategy>
  384. struct distance
  385. <
  386. Point, Box, Strategy, point_tag, box_tag,
  387. strategy_tag_distance_point_box, false
  388. > : detail::distance::point_to_box<Point, Box, Strategy>
  389. {};
  390. template<typename Point, typename MultiPoint, typename Strategy>
  391. struct distance
  392. <
  393. Point, MultiPoint, Strategy, point_tag, multi_point_tag,
  394. strategy_tag_distance_point_point, false
  395. > : detail::distance::point_to_multigeometry
  396. <
  397. Point, MultiPoint, Strategy
  398. >
  399. {};
  400. template<typename Point, typename MultiLinestring, typename Strategy>
  401. struct distance
  402. <
  403. Point, MultiLinestring, Strategy, point_tag, multi_linestring_tag,
  404. strategy_tag_distance_point_segment, false
  405. > : detail::distance::point_to_multigeometry
  406. <
  407. Point, MultiLinestring, Strategy
  408. >
  409. {};
  410. template<typename Point, typename MultiPolygon, typename Strategy>
  411. struct distance
  412. <
  413. Point, MultiPolygon, Strategy, point_tag, multi_polygon_tag,
  414. strategy_tag_distance_point_segment, false
  415. > : detail::distance::point_to_multigeometry
  416. <
  417. Point, MultiPolygon, Strategy
  418. >
  419. {};
  420. template <typename Point, typename Linear, typename Strategy>
  421. struct distance
  422. <
  423. Point, Linear, Strategy, point_tag, linear_tag,
  424. strategy_tag_distance_point_segment, false
  425. > : distance
  426. <
  427. Point, Linear, Strategy,
  428. point_tag, typename tag<Linear>::type,
  429. strategy_tag_distance_point_segment, false
  430. >
  431. {};
  432. template <typename Point, typename Areal, typename Strategy>
  433. struct distance
  434. <
  435. Point, Areal, Strategy, point_tag, areal_tag,
  436. strategy_tag_distance_point_segment, false
  437. > : distance
  438. <
  439. Point, Areal, Strategy,
  440. point_tag, typename tag<Areal>::type,
  441. strategy_tag_distance_point_segment, false
  442. >
  443. {};
  444. } // namespace dispatch
  445. #endif // DOXYGEN_NO_DISPATCH
  446. }} // namespace boost::geometry
  447. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP