discrete_hausdorff_distance.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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.
  6. // Modifications copyright (c) 2018, 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/geometry/algorithms/detail/throw_on_empty_input.hpp>
  22. #include <boost/geometry/algorithms/not_implemented.hpp>
  23. #include <boost/geometry/core/point_type.hpp>
  24. #include <boost/geometry/core/tag.hpp>
  25. #include <boost/geometry/core/tags.hpp>
  26. #include <boost/geometry/strategies/distance.hpp>
  27. #include <boost/geometry/strategies/distance_result.hpp>
  28. #include <boost/geometry/util/range.hpp>
  29. #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  30. #include <boost/geometry/index/rtree.hpp>
  31. #endif // BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  32. namespace boost { namespace geometry
  33. {
  34. #ifndef DOXYGEN_NO_DETAIL
  35. namespace detail { namespace discrete_hausdorff_distance
  36. {
  37. struct point_range
  38. {
  39. template <typename Point, typename Range, typename Strategy>
  40. static inline
  41. typename distance_result
  42. <
  43. typename point_type<Point>::type,
  44. typename point_type<Range>::type,
  45. Strategy
  46. >::type
  47. apply(Point const& pnt, Range const& rng, Strategy const& strategy)
  48. {
  49. typedef typename distance_result
  50. <
  51. typename point_type<Point>::type,
  52. typename point_type<Range>::type,
  53. Strategy
  54. >::type result_type;
  55. typedef typename boost::range_size<Range>::type size_type;
  56. size_type const n = boost::size(rng);
  57. result_type dis_min = 0;
  58. bool is_dis_min_set = false;
  59. for (size_type i = 0 ; i < n ; i++)
  60. {
  61. result_type dis_temp = strategy.apply(pnt, range::at(rng, i));
  62. if (! is_dis_min_set || dis_temp < dis_min)
  63. {
  64. dis_min = dis_temp;
  65. is_dis_min_set = true;
  66. }
  67. }
  68. return dis_min;
  69. }
  70. };
  71. struct range_range
  72. {
  73. template <typename Range1, typename Range2, typename Strategy>
  74. static inline
  75. typename distance_result
  76. <
  77. typename point_type<Range1>::type,
  78. typename point_type<Range2>::type,
  79. Strategy
  80. >::type
  81. apply(Range1 const& r1, Range2 const& r2, Strategy const& strategy)
  82. {
  83. typedef typename distance_result
  84. <
  85. typename point_type<Range1>::type,
  86. typename point_type<Range2>::type,
  87. Strategy
  88. >::type result_type;
  89. typedef typename boost::range_size<Range1>::type size_type;
  90. boost::geometry::detail::throw_on_empty_input(r1);
  91. boost::geometry::detail::throw_on_empty_input(r2);
  92. size_type const n = boost::size(r1);
  93. result_type dis_max = 0;
  94. #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  95. namespace bgi = boost::geometry::index;
  96. typedef typename point_type<Range1>::type point_t;
  97. typedef bgi::rtree<point_t, bgi::linear<4> > rtree_type;
  98. rtree_type rtree(boost::begin(r2), boost::end(r2));
  99. point_t res;
  100. #endif
  101. for (size_type i = 0 ; i < n ; i++)
  102. {
  103. #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE
  104. size_type found = rtree.query(bgi::nearest(range::at(r1, i), 1), &res);
  105. result_type dis_min = strategy.apply(range::at(r1,i), res);
  106. #else
  107. result_type dis_min = point_range::apply(range::at(r1, i), r2, strategy);
  108. #endif
  109. if (dis_min > dis_max )
  110. {
  111. dis_max = dis_min;
  112. }
  113. }
  114. return dis_max;
  115. }
  116. };
  117. struct range_multi_range
  118. {
  119. template <typename Range, typename Multi_range, typename Strategy>
  120. static inline
  121. typename distance_result
  122. <
  123. typename point_type<Range>::type,
  124. typename point_type<Multi_range>::type,
  125. Strategy
  126. >::type
  127. apply(Range const& rng, Multi_range const& mrng, Strategy const& strategy)
  128. {
  129. typedef typename distance_result
  130. <
  131. typename point_type<Range>::type,
  132. typename point_type<Multi_range>::type,
  133. Strategy
  134. >::type result_type;
  135. typedef typename boost::range_size<Multi_range>::type size_type;
  136. boost::geometry::detail::throw_on_empty_input(rng);
  137. boost::geometry::detail::throw_on_empty_input(mrng);
  138. size_type b = boost::size(mrng);
  139. result_type haus_dis = 0;
  140. for (size_type j = 0 ; j < b ; j++)
  141. {
  142. result_type dis_max = range_range::apply(rng, range::at(mrng, j), strategy);
  143. if (dis_max > haus_dis)
  144. {
  145. haus_dis = dis_max;
  146. }
  147. }
  148. return haus_dis;
  149. }
  150. };
  151. struct multi_range_multi_range
  152. {
  153. template <typename Multi_Range1, typename Multi_range2, typename Strategy>
  154. static inline
  155. typename distance_result
  156. <
  157. typename point_type<Multi_Range1>::type,
  158. typename point_type<Multi_range2>::type,
  159. Strategy
  160. >::type
  161. apply(Multi_Range1 const& mrng1, Multi_range2 const& mrng2, Strategy const& strategy)
  162. {
  163. typedef typename distance_result
  164. <
  165. typename point_type<Multi_Range1>::type,
  166. typename point_type<Multi_range2>::type,
  167. Strategy
  168. >::type result_type;
  169. typedef typename boost::range_size<Multi_Range1>::type size_type;
  170. boost::geometry::detail::throw_on_empty_input(mrng1);
  171. boost::geometry::detail::throw_on_empty_input(mrng2);
  172. size_type n = boost::size(mrng1);
  173. result_type haus_dis = 0;
  174. for (size_type i = 0 ; i < n ; i++)
  175. {
  176. result_type dis_max = range_multi_range::apply(range::at(mrng1, i), mrng2, strategy);
  177. if (dis_max > haus_dis)
  178. {
  179. haus_dis = dis_max;
  180. }
  181. }
  182. return haus_dis;
  183. }
  184. };
  185. }} // namespace detail::hausdorff_distance
  186. #endif // DOXYGEN_NO_DETAIL
  187. #ifndef DOXYGEN_NO_DISPATCH
  188. namespace dispatch
  189. {
  190. template
  191. <
  192. typename Geometry1,
  193. typename Geometry2,
  194. typename Tag1 = typename tag<Geometry1>::type,
  195. typename Tag2 = typename tag<Geometry2>::type
  196. >
  197. struct discrete_hausdorff_distance : not_implemented<Tag1, Tag2>
  198. {};
  199. // Specialization for point and multi_point
  200. template <typename Point, typename MultiPoint>
  201. struct discrete_hausdorff_distance<Point, MultiPoint, point_tag, multi_point_tag>
  202. : detail::discrete_hausdorff_distance::point_range
  203. {};
  204. // Specialization for linestrings
  205. template <typename Linestring1, typename Linestring2>
  206. struct discrete_hausdorff_distance<Linestring1, Linestring2, linestring_tag, linestring_tag>
  207. : detail::discrete_hausdorff_distance::range_range
  208. {};
  209. // Specialization for multi_point-multi_point
  210. template <typename MultiPoint1, typename MultiPoint2>
  211. struct discrete_hausdorff_distance<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
  212. : detail::discrete_hausdorff_distance::range_range
  213. {};
  214. // Specialization for Linestring and MultiLinestring
  215. template <typename Linestring, typename MultiLinestring>
  216. struct discrete_hausdorff_distance<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
  217. : detail::discrete_hausdorff_distance::range_multi_range
  218. {};
  219. // Specialization for MultiLinestring and MultiLinestring
  220. template <typename MultiLinestring1, typename MultiLinestring2>
  221. struct discrete_hausdorff_distance<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
  222. : detail::discrete_hausdorff_distance::multi_range_multi_range
  223. {};
  224. } // namespace dispatch
  225. #endif // DOXYGEN_NO_DISPATCH
  226. // Algorithm overload using explicitly passed Pt-Pt distance strategy
  227. /*!
  228. \brief Calculate discrete Hausdorff distance between two geometries (currently
  229. works for LineString-LineString, MultiPoint-MultiPoint, Point-MultiPoint,
  230. MultiLineString-MultiLineString) using specified strategy.
  231. \ingroup discrete_hausdorff_distance
  232. \tparam Geometry1 \tparam_geometry
  233. \tparam Geometry2 \tparam_geometry
  234. \tparam Strategy A type fulfilling a DistanceStrategy concept
  235. \param geometry1 Input geometry
  236. \param geometry2 Input geometry
  237. \param strategy Distance strategy to be used to calculate Pt-Pt distance
  238. \qbk{distinguish,with strategy}
  239. \qbk{[include reference/algorithms/discrete_hausdorff_distance.qbk]}
  240. \qbk{
  241. [heading Available Strategies]
  242. \* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
  243. \* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
  244. [/ \* more (currently extensions): Vincenty\, Andoyer (geographic) ]
  245. [heading Example]
  246. [discrete_hausdorff_distance_strategy]
  247. [discrete_hausdorff_distance_strategy_output]
  248. }
  249. */
  250. template <typename Geometry1, typename Geometry2, typename Strategy>
  251. inline
  252. typename distance_result
  253. <
  254. typename point_type<Geometry1>::type,
  255. typename point_type<Geometry2>::type,
  256. Strategy
  257. >::type
  258. discrete_hausdorff_distance(Geometry1 const& geometry1,
  259. Geometry2 const& geometry2,
  260. Strategy const& strategy)
  261. {
  262. return dispatch::discrete_hausdorff_distance
  263. <
  264. Geometry1, Geometry2
  265. >::apply(geometry1, geometry2, strategy);
  266. }
  267. /*!
  268. \brief Calculate discrete Hausdorff distance between two geometries (currently
  269. works for LineString-LineString, MultiPoint-MultiPoint, Point-MultiPoint,
  270. MultiLineString-MultiLineString).
  271. \ingroup discrete_hausdorff_distance
  272. \tparam Geometry1 \tparam_geometry
  273. \tparam Geometry2 \tparam_geometry
  274. \param geometry1 Input geometry
  275. \param geometry2 Input geometry
  276. \qbk{[include reference/algorithms/discrete_hausdorff_distance.qbk]}
  277. \qbk{
  278. [heading Example]
  279. [discrete_hausdorff_distance]
  280. [discrete_hausdorff_distance_output]
  281. }
  282. */
  283. template <typename Geometry1, typename Geometry2>
  284. inline
  285. typename distance_result
  286. <
  287. typename point_type<Geometry1>::type,
  288. typename point_type<Geometry2>::type
  289. >::type
  290. discrete_hausdorff_distance(Geometry1 const& geometry1,
  291. Geometry2 const& geometry2)
  292. {
  293. typedef typename strategy::distance::services::default_strategy
  294. <
  295. point_tag, point_tag,
  296. typename point_type<Geometry1>::type,
  297. typename point_type<Geometry2>::type
  298. >::type strategy_type;
  299. return discrete_hausdorff_distance(geometry1, geometry2, strategy_type());
  300. }
  301. }} // namespace boost::geometry
  302. #endif // BOOST_GEOMETRY_ALGORITHMS_DISCRETE_HAUSDORFF_DISTANCE_HPP