discrete_hausdorff_distance.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. // Boost.Geometry
  2. // Copyright (c) 2018 Yaghyavardhan Singh Khangarot, Hyderabad, India.
  3. // Contributed and/or modified by Yaghyavardhan Singh Khangarot,
  4. // as part of Google Summer of Code 2018 program.
  5. // This file was modified by Oracle on 2018-2021.
  6. // Modifications copyright (c) 2018-2021, Oracle and/or its affiliates.
  7. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  8. // Use, modification and distribution is subject to the Boost Software License,
  9. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #ifndef BOOST_GEOMETRY_ALGORITHMS_DISCRETE_HAUSDORFF_DISTANCE_HPP
  12. #define BOOST_GEOMETRY_ALGORITHMS_DISCRETE_HAUSDORFF_DISTANCE_HPP
  13. #include <algorithm>
  14. #ifdef BOOST_GEOMETRY_DEBUG_HAUSDORFF_DISTANCE
  15. #include <iostream>
  16. #endif
  17. #include <iterator>
  18. #include <utility>
  19. #include <vector>
  20. #include <limits>
  21. #include <boost/range/size.hpp>
  22. #include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
  23. #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
  24. #include <boost/geometry/algorithms/not_implemented.hpp>
  25. #include <boost/geometry/core/point_type.hpp>
  26. #include <boost/geometry/core/tag.hpp>
  27. #include <boost/geometry/core/tags.hpp>
  28. #include <boost/geometry/strategies/detail.hpp>
  29. #include <boost/geometry/strategies/discrete_distance/cartesian.hpp>
  30. #include <boost/geometry/strategies/discrete_distance/geographic.hpp>
  31. #include <boost/geometry/strategies/discrete_distance/spherical.hpp>
  32. #include <boost/geometry/strategies/distance_result.hpp>
  33. #include <boost/geometry/util/range.hpp>
  34. // Note that in order for this to work umbrella strategy has to contain
  35. // index strategies.
  36. #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  37. #include <boost/geometry/index/rtree.hpp>
  38. #endif // BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  39. namespace boost { namespace geometry
  40. {
  41. #ifndef DOXYGEN_NO_DETAIL
  42. namespace detail { namespace discrete_hausdorff_distance
  43. {
  44. // TODO: The implementation should calculate comparable distances
  45. struct point_range
  46. {
  47. template <typename Point, typename Range, typename Strategies>
  48. static inline auto apply(Point const& pnt, Range const& rng,
  49. Strategies const& strategies)
  50. {
  51. typedef typename distance_result
  52. <
  53. Point,
  54. typename point_type<Range>::type,
  55. Strategies
  56. >::type result_type;
  57. typedef typename boost::range_size<Range>::type size_type;
  58. boost::geometry::detail::throw_on_empty_input(rng);
  59. auto const strategy = strategies.distance(dummy_point(), dummy_point());
  60. size_type const n = boost::size(rng);
  61. result_type dis_min = 0;
  62. bool is_dis_min_set = false;
  63. for (size_type i = 0 ; i < n ; i++)
  64. {
  65. result_type dis_temp = strategy.apply(pnt, range::at(rng, i));
  66. if (! is_dis_min_set || dis_temp < dis_min)
  67. {
  68. dis_min = dis_temp;
  69. is_dis_min_set = true;
  70. }
  71. }
  72. return dis_min;
  73. }
  74. };
  75. struct range_range
  76. {
  77. template <typename Range1, typename Range2, typename Strategies>
  78. static inline auto apply(Range1 const& r1, Range2 const& r2,
  79. Strategies const& strategies)
  80. {
  81. typedef typename distance_result
  82. <
  83. typename point_type<Range1>::type,
  84. typename point_type<Range2>::type,
  85. Strategies
  86. >::type result_type;
  87. typedef typename boost::range_size<Range1>::type size_type;
  88. boost::geometry::detail::throw_on_empty_input(r1);
  89. boost::geometry::detail::throw_on_empty_input(r2);
  90. size_type const n = boost::size(r1);
  91. result_type dis_max = 0;
  92. #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  93. namespace bgi = boost::geometry::index;
  94. typedef typename point_type<Range1>::type point_t;
  95. typedef bgi::rtree<point_t, bgi::linear<4> > rtree_type;
  96. rtree_type rtree(boost::begin(r2), boost::end(r2));
  97. point_t res;
  98. #endif
  99. for (size_type i = 0 ; i < n ; i++)
  100. {
  101. #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  102. size_type found = rtree.query(bgi::nearest(range::at(r1, i), 1), &res);
  103. result_type dis_min = strategy.apply(range::at(r1,i), res);
  104. #else
  105. result_type dis_min = point_range::apply(range::at(r1, i), r2, strategies);
  106. #endif
  107. if (dis_min > dis_max )
  108. {
  109. dis_max = dis_min;
  110. }
  111. }
  112. return dis_max;
  113. }
  114. };
  115. struct range_multi_range
  116. {
  117. template <typename Range, typename Multi_range, typename Strategies>
  118. static inline auto apply(Range const& rng, Multi_range const& mrng,
  119. Strategies const& strategies)
  120. {
  121. typedef typename distance_result
  122. <
  123. typename point_type<Range>::type,
  124. typename point_type<Multi_range>::type,
  125. Strategies
  126. >::type result_type;
  127. typedef typename boost::range_size<Multi_range>::type size_type;
  128. boost::geometry::detail::throw_on_empty_input(rng);
  129. boost::geometry::detail::throw_on_empty_input(mrng);
  130. size_type b = boost::size(mrng);
  131. result_type haus_dis = 0;
  132. for (size_type j = 0 ; j < b ; j++)
  133. {
  134. result_type dis_max = range_range::apply(rng, range::at(mrng, j), strategies);
  135. if (dis_max > haus_dis)
  136. {
  137. haus_dis = dis_max;
  138. }
  139. }
  140. return haus_dis;
  141. }
  142. };
  143. struct multi_range_multi_range
  144. {
  145. template <typename Multi_Range1, typename Multi_range2, typename Strategies>
  146. static inline auto apply(Multi_Range1 const& mrng1, Multi_range2 const& mrng2,
  147. Strategies const& strategies)
  148. {
  149. typedef typename distance_result
  150. <
  151. typename point_type<Multi_Range1>::type,
  152. typename point_type<Multi_range2>::type,
  153. Strategies
  154. >::type result_type;
  155. typedef typename boost::range_size<Multi_Range1>::type size_type;
  156. boost::geometry::detail::throw_on_empty_input(mrng1);
  157. boost::geometry::detail::throw_on_empty_input(mrng2);
  158. size_type n = boost::size(mrng1);
  159. result_type haus_dis = 0;
  160. for (size_type i = 0 ; i < n ; i++)
  161. {
  162. result_type dis_max = range_multi_range::apply(range::at(mrng1, i), mrng2, strategies);
  163. if (dis_max > haus_dis)
  164. {
  165. haus_dis = dis_max;
  166. }
  167. }
  168. return haus_dis;
  169. }
  170. };
  171. }} // namespace detail::hausdorff_distance
  172. #endif // DOXYGEN_NO_DETAIL
  173. #ifndef DOXYGEN_NO_DISPATCH
  174. namespace dispatch
  175. {
  176. template
  177. <
  178. typename Geometry1,
  179. typename Geometry2,
  180. typename Tag1 = typename tag<Geometry1>::type,
  181. typename Tag2 = typename tag<Geometry2>::type
  182. >
  183. struct discrete_hausdorff_distance : not_implemented<Tag1, Tag2>
  184. {};
  185. // Specialization for point and multi_point
  186. template <typename Point, typename MultiPoint>
  187. struct discrete_hausdorff_distance<Point, MultiPoint, point_tag, multi_point_tag>
  188. : detail::discrete_hausdorff_distance::point_range
  189. {};
  190. // Specialization for linestrings
  191. template <typename Linestring1, typename Linestring2>
  192. struct discrete_hausdorff_distance<Linestring1, Linestring2, linestring_tag, linestring_tag>
  193. : detail::discrete_hausdorff_distance::range_range
  194. {};
  195. // Specialization for multi_point-multi_point
  196. template <typename MultiPoint1, typename MultiPoint2>
  197. struct discrete_hausdorff_distance<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
  198. : detail::discrete_hausdorff_distance::range_range
  199. {};
  200. // Specialization for Linestring and MultiLinestring
  201. template <typename Linestring, typename MultiLinestring>
  202. struct discrete_hausdorff_distance<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
  203. : detail::discrete_hausdorff_distance::range_multi_range
  204. {};
  205. // Specialization for MultiLinestring and MultiLinestring
  206. template <typename MultiLinestring1, typename MultiLinestring2>
  207. struct discrete_hausdorff_distance<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
  208. : detail::discrete_hausdorff_distance::multi_range_multi_range
  209. {};
  210. } // namespace dispatch
  211. #endif // DOXYGEN_NO_DISPATCH
  212. namespace resolve_strategy {
  213. template
  214. <
  215. typename Strategies,
  216. bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
  217. >
  218. struct discrete_hausdorff_distance
  219. {
  220. template <typename Geometry1, typename Geometry2>
  221. static inline auto apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  222. Strategies const& strategies)
  223. {
  224. return dispatch::discrete_hausdorff_distance
  225. <
  226. Geometry1, Geometry2
  227. >::apply(geometry1, geometry2, strategies);
  228. }
  229. };
  230. template <typename Strategy>
  231. struct discrete_hausdorff_distance<Strategy, false>
  232. {
  233. template <typename Geometry1, typename Geometry2>
  234. static inline auto apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  235. Strategy const& strategy)
  236. {
  237. using strategies::discrete_distance::services::strategy_converter;
  238. return dispatch::discrete_hausdorff_distance
  239. <
  240. Geometry1, Geometry2
  241. >::apply(geometry1, geometry2,
  242. strategy_converter<Strategy>::get(strategy));
  243. }
  244. };
  245. template <>
  246. struct discrete_hausdorff_distance<default_strategy, false>
  247. {
  248. template <typename Geometry1, typename Geometry2>
  249. static inline auto apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
  250. default_strategy const&)
  251. {
  252. typedef typename strategies::discrete_distance::services::default_strategy
  253. <
  254. Geometry1, Geometry2
  255. >::type strategies_type;
  256. return dispatch::discrete_hausdorff_distance
  257. <
  258. Geometry1, Geometry2
  259. >::apply(geometry1, geometry2, strategies_type());
  260. }
  261. };
  262. } // namespace resolve_strategy
  263. /*!
  264. \brief Calculate discrete Hausdorff distance between two geometries (currently
  265. works for LineString-LineString, MultiPoint-MultiPoint, Point-MultiPoint,
  266. MultiLineString-MultiLineString) using specified strategy.
  267. \ingroup discrete_hausdorff_distance
  268. \tparam Geometry1 \tparam_geometry
  269. \tparam Geometry2 \tparam_geometry
  270. \tparam Strategy A type fulfilling a DistanceStrategy concept
  271. \param geometry1 Input geometry
  272. \param geometry2 Input geometry
  273. \param strategy Distance strategy to be used to calculate Pt-Pt distance
  274. \qbk{distinguish,with strategy}
  275. \qbk{[include reference/algorithms/discrete_hausdorff_distance.qbk]}
  276. \qbk{
  277. [heading Available Strategies]
  278. \* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
  279. \* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
  280. [/ \* more (currently extensions): Vincenty\, Andoyer (geographic) ]
  281. [heading Example]
  282. [discrete_hausdorff_distance_strategy]
  283. [discrete_hausdorff_distance_strategy_output]
  284. }
  285. */
  286. template <typename Geometry1, typename Geometry2, typename Strategy>
  287. inline auto discrete_hausdorff_distance(Geometry1 const& geometry1,
  288. Geometry2 const& geometry2,
  289. Strategy const& strategy)
  290. {
  291. return resolve_strategy::discrete_hausdorff_distance
  292. <
  293. Strategy
  294. >::apply(geometry1, geometry2, strategy);
  295. }
  296. /*!
  297. \brief Calculate discrete Hausdorff distance between two geometries (currently
  298. works for LineString-LineString, MultiPoint-MultiPoint, Point-MultiPoint,
  299. MultiLineString-MultiLineString).
  300. \ingroup discrete_hausdorff_distance
  301. \tparam Geometry1 \tparam_geometry
  302. \tparam Geometry2 \tparam_geometry
  303. \param geometry1 Input geometry
  304. \param geometry2 Input geometry
  305. \qbk{[include reference/algorithms/discrete_hausdorff_distance.qbk]}
  306. \qbk{
  307. [heading Example]
  308. [discrete_hausdorff_distance]
  309. [discrete_hausdorff_distance_output]
  310. }
  311. */
  312. template <typename Geometry1, typename Geometry2>
  313. inline auto discrete_hausdorff_distance(Geometry1 const& geometry1,
  314. Geometry2 const& geometry2)
  315. {
  316. return resolve_strategy::discrete_hausdorff_distance
  317. <
  318. default_strategy
  319. >::apply(geometry1, geometry2, default_strategy());
  320. }
  321. }} // namespace boost::geometry
  322. #endif // BOOST_GEOMETRY_ALGORITHMS_DISCRETE_HAUSDORFF_DISTANCE_HPP