test_distance_geo_common.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Unit Test
  3. // Copyright (c) 2016-2017, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  5. // Licensed under the Boost Software License version 1.0.
  6. // http://www.boost.org/users/license.html
  7. #ifndef BOOST_GEOMETRY_TEST_DISTANCE_GEO_COMMON_HPP
  8. #define BOOST_GEOMETRY_TEST_DISTANCE_GEO_COMMON_HPP
  9. #include <iostream>
  10. #include <string>
  11. #include <boost/mpl/assert.hpp>
  12. #include <boost/type_traits/is_integral.hpp>
  13. #include <boost/type_traits/is_same.hpp>
  14. #include <boost/geometry/geometries/point.hpp>
  15. #include <boost/geometry/geometries/point_xy.hpp>
  16. #include <boost/geometry/geometries/segment.hpp>
  17. #include <boost/geometry/geometries/linestring.hpp>
  18. #include <boost/geometry/geometries/polygon.hpp>
  19. #include <boost/geometry/geometries/ring.hpp>
  20. #include <boost/geometry/geometries/box.hpp>
  21. #include <boost/geometry/geometries/multi_point.hpp>
  22. #include <boost/geometry/geometries/multi_linestring.hpp>
  23. #include <boost/geometry/geometries/multi_polygon.hpp>
  24. #include <boost/geometry/io/wkt/write.hpp>
  25. #include <boost/geometry/io/dsv/write.hpp>
  26. #include <boost/geometry/algorithms/num_interior_rings.hpp>
  27. #include <boost/geometry/algorithms/distance.hpp>
  28. #include <boost/geometry/strategies/strategies.hpp>
  29. #include <from_wkt.hpp>
  30. #include <string_from_type.hpp>
  31. #include "distance_brute_force.hpp"
  32. namespace bg = ::boost::geometry;
  33. typedef bg::srs::spheroid<double> stype;
  34. // Spherical strategy for point-point distance
  35. typedef bg::strategy::distance::haversine<double> spherical_pp;
  36. // Geo strategies for point-point distance
  37. typedef bg::strategy::distance::andoyer<stype> andoyer_pp;
  38. typedef bg::strategy::distance::thomas<stype> thomas_pp;
  39. typedef bg::strategy::distance::vincenty<stype> vincenty_pp;
  40. // Spherical strategy for point-segment distance
  41. typedef bg::strategy::distance::cross_track<> spherical_ps;
  42. // Geo strategies for point-segment distance
  43. typedef bg::strategy::distance::geographic_cross_track<bg::strategy::andoyer, stype, double>
  44. andoyer_ps;
  45. typedef bg::strategy::distance::geographic_cross_track<bg::strategy::thomas, stype, double>
  46. thomas_ps;
  47. typedef bg::strategy::distance::geographic_cross_track<bg::strategy::vincenty, stype, double>
  48. vincenty_ps;
  49. typedef bg::strategy::distance::detail::geographic_cross_track<bg::strategy::vincenty, stype, double, true>
  50. vincenty_ps_bisection;
  51. // Spherical strategy for point-box distance
  52. typedef bg::strategy::distance::cross_track_point_box<> spherical_pb;
  53. // Geo strategies for point-box distance
  54. typedef bg::strategy::distance::geographic_cross_track_point_box
  55. <
  56. bg::strategy::andoyer,
  57. stype,
  58. double
  59. > andoyer_pb;
  60. typedef bg::strategy::distance::geographic_cross_track_point_box
  61. <
  62. bg::strategy::thomas,
  63. stype,
  64. double
  65. > thomas_pb;
  66. typedef bg::strategy::distance::geographic_cross_track_point_box
  67. <
  68. bg::strategy::vincenty,
  69. stype,
  70. double
  71. > vincenty_pb;
  72. // Spherical strategy for segment-box distance
  73. typedef bg::strategy::distance::spherical_segment_box<> spherical_sb;
  74. // Geo strategies for segment-box distance
  75. typedef bg::strategy::distance::geographic_segment_box<bg::strategy::andoyer, stype, double>
  76. andoyer_sb;
  77. typedef bg::strategy::distance::geographic_segment_box<bg::strategy::thomas, stype, double>
  78. thomas_sb;
  79. typedef bg::strategy::distance::geographic_segment_box<bg::strategy::vincenty, stype, double>
  80. vincenty_sb;
  81. // Strategies for box-box distance
  82. typedef bg::strategy::distance::cross_track_box_box<> spherical_bb;
  83. typedef bg::strategy::distance::geographic_cross_track_box_box
  84. <
  85. bg::strategy::andoyer,
  86. stype,
  87. double
  88. > andoyer_bb;
  89. typedef bg::strategy::distance::geographic_cross_track_box_box
  90. <
  91. bg::strategy::thomas,
  92. stype,
  93. double
  94. > thomas_bb;
  95. typedef bg::strategy::distance::geographic_cross_track_box_box
  96. <
  97. bg::strategy::vincenty,
  98. stype,
  99. double
  100. > vincenty_bb;
  101. //===========================================================================
  102. template <typename Point, typename Strategy>
  103. inline typename bg::default_distance_result<Point>::type
  104. pp_distance(std::string const& wkt1,
  105. std::string const& wkt2,
  106. Strategy const& strategy)
  107. {
  108. Point p1, p2;
  109. bg::read_wkt(wkt1, p1);
  110. bg::read_wkt(wkt2, p2);
  111. return bg::distance(p1, p2, strategy);
  112. }
  113. //===========================================================================
  114. template <typename Point, typename Strategy>
  115. inline typename bg::default_distance_result<Point>::type
  116. ps_distance(std::string const& wkt1,
  117. std::string const& wkt2,
  118. Strategy const& strategy)
  119. {
  120. Point p;
  121. typedef bg::model::segment<Point> segment_type;
  122. segment_type s;
  123. bg::read_wkt(wkt1, p);
  124. bg::read_wkt(wkt2, s);
  125. return bg::distance(p, s, strategy);
  126. }
  127. //===========================================================================
  128. template <typename Point, typename Strategy>
  129. inline typename bg::default_distance_result<Point>::type
  130. sb_distance(std::string const& wkt1,
  131. std::string const& wkt2,
  132. Strategy const& strategy)
  133. {
  134. typedef bg::model::segment<Point> segment_type;
  135. typedef bg::model::box<Point> box_type;
  136. segment_type s;
  137. box_type b;
  138. bg::read_wkt(wkt1, s);
  139. bg::read_wkt(wkt2, b);
  140. return bg::distance(s, b, strategy);
  141. }
  142. //===================================================================
  143. template <typename Tag> struct dispatch
  144. {
  145. //tag dispatching for swaping arguments in segments
  146. template <typename T>
  147. static inline T swap(T const& t)
  148. {
  149. return t;
  150. }
  151. // mirror geometry w.r.t. equator
  152. template <typename T>
  153. static inline T mirror(T const& t)
  154. {
  155. return t;
  156. }
  157. };
  158. // Specialization for segments
  159. template <> struct dispatch<boost::geometry::segment_tag>
  160. {
  161. template <typename Segment>
  162. static inline Segment swap(Segment const& s)
  163. {
  164. Segment s_swaped;
  165. bg::set<0, 0>(s_swaped, bg::get<1, 0>(s));
  166. bg::set<0, 1>(s_swaped, bg::get<1, 1>(s));
  167. bg::set<1, 0>(s_swaped, bg::get<0, 0>(s));
  168. bg::set<1, 1>(s_swaped, bg::get<0, 1>(s));
  169. return s_swaped;
  170. }
  171. template <typename Segment>
  172. static inline Segment mirror(Segment const& s)
  173. {
  174. Segment s_mirror;
  175. bg::set<0, 0>(s_mirror, bg::get<0, 0>(s));
  176. bg::set<0, 1>(s_mirror, bg::get<0, 1>(s) * -1);
  177. bg::set<1, 0>(s_mirror, bg::get<1, 0>(s));
  178. bg::set<1, 1>(s_mirror, bg::get<1, 1>(s) * -1);
  179. return s_mirror;
  180. }
  181. };
  182. // Specialization for boxes
  183. template <> struct dispatch<boost::geometry::box_tag>
  184. {
  185. template <typename T>
  186. static inline T swap(T const& t)
  187. {
  188. return t;
  189. }
  190. template <typename Box>
  191. static inline Box mirror(Box const& b)
  192. {
  193. Box b_mirror;
  194. bg::set<0, 0>(b_mirror, bg::get<bg::min_corner, 0>(b));
  195. bg::set<0, 1>(b_mirror, bg::get<bg::max_corner, 1>(b) * -1);
  196. bg::set<1, 0>(b_mirror, bg::get<bg::max_corner, 0>(b));
  197. bg::set<1, 1>(b_mirror, bg::get<bg::min_corner, 1>(b) * -1);
  198. return b_mirror;
  199. }
  200. };
  201. // Specialization for points
  202. template <> struct dispatch<boost::geometry::point_tag>
  203. {
  204. template <typename T>
  205. static inline T swap(T const& t)
  206. {
  207. return t;
  208. }
  209. template <typename Point>
  210. static inline Point mirror(Point const& p)
  211. {
  212. Point p_mirror;
  213. bg::set<0>(p_mirror, bg::get<0>(p));
  214. bg::set<1>(p_mirror, bg::get<1>(p) * -1);
  215. return p_mirror;
  216. }
  217. };
  218. //========================================================================
  219. template <typename T>
  220. struct check_equal
  221. {
  222. template <typename Value, typename = void>
  223. struct equal_to
  224. {
  225. static inline void apply(Value const& x, Value const& y)
  226. {
  227. BOOST_CHECK(x == y);
  228. }
  229. };
  230. template <typename Dummy>
  231. struct equal_to<double, Dummy>
  232. {
  233. static inline void apply(double x, double y)
  234. {
  235. BOOST_CHECK_CLOSE(x, y, 0.001);
  236. }
  237. };
  238. template <typename Geometry1, typename Geometry2>
  239. static inline void apply(std::string const& /*case_id*/,
  240. std::string const& /*subcase_id*/,
  241. Geometry1 const& /*geometry1*/,
  242. Geometry2 const& /*geometry2*/,
  243. T const& detected,
  244. T const& expected)
  245. {
  246. equal_to<T>::apply(expected, detected);
  247. }
  248. };
  249. //========================================================================
  250. template
  251. <
  252. typename Geometry1, typename Geometry2,
  253. int id1 = bg::geometry_id<Geometry1>::value,
  254. int id2 = bg::geometry_id<Geometry2>::value
  255. >
  256. struct test_distance_of_geometries
  257. : public test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
  258. {};
  259. template <typename Geometry1, typename Geometry2>
  260. struct test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
  261. {
  262. template <typename DistanceType, typename Strategy>
  263. static inline
  264. void apply(std::string const& case_id,
  265. std::string const& wkt1,
  266. std::string const& wkt2,
  267. DistanceType const& expected_distance,
  268. Strategy const& strategy,
  269. bool test_reversed = true,
  270. bool swap_geometry_args = false,
  271. bool mirror_geometry = true)
  272. {
  273. Geometry1 geometry1 = from_wkt<Geometry1>(wkt1);
  274. Geometry2 geometry2 = from_wkt<Geometry2>(wkt2);
  275. apply(case_id, geometry1, geometry2,
  276. expected_distance,
  277. strategy, test_reversed, swap_geometry_args,
  278. mirror_geometry);
  279. }
  280. template
  281. <
  282. typename DistanceType,
  283. typename Strategy
  284. >
  285. static inline
  286. void apply(std::string const& case_id,
  287. Geometry1 const& geometry1,
  288. Geometry2 const& geometry2,
  289. DistanceType const& expected_distance,
  290. Strategy const& strategy,
  291. bool test_reversed = true,
  292. bool swap_geometry_args = false,
  293. bool mirror_geometry = true)
  294. {
  295. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  296. std::cout << "case ID: " << case_id << "; "
  297. << "G1: " << bg::wkt(geometry1)
  298. << " - "
  299. << "G2: " << bg::wkt(geometry2)
  300. << std::endl;
  301. #endif
  302. namespace services = bg::strategy::distance::services;
  303. using bg::unit_test::distance_brute_force;
  304. typedef typename bg::default_distance_result
  305. <
  306. Geometry1, Geometry2
  307. >::type default_distance_result;
  308. typedef typename services::return_type
  309. <
  310. Strategy, Geometry1, Geometry2
  311. >::type distance_result_from_strategy;
  312. static const bool same_regular = boost::is_same
  313. <
  314. default_distance_result,
  315. distance_result_from_strategy
  316. >::type::value;
  317. BOOST_CHECK(same_regular);
  318. // check distance with passed strategy
  319. distance_result_from_strategy dist =
  320. bg::distance(geometry1, geometry2, strategy);
  321. check_equal
  322. <
  323. distance_result_from_strategy
  324. >::apply(case_id, "a", geometry1, geometry2,
  325. dist, expected_distance);
  326. // check against the comparable distance computed in a
  327. // brute-force manner
  328. default_distance_result dist_brute_force
  329. = distance_brute_force(geometry1, geometry2, strategy);
  330. check_equal
  331. <
  332. default_distance_result
  333. >::apply(case_id, "b", geometry1, geometry2,
  334. dist_brute_force, expected_distance);
  335. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  336. std::cout << string_from_type<typename bg::coordinate_type<Geometry1>::type>::name()
  337. << string_from_type<typename bg::coordinate_type<Geometry2>::type>::name()
  338. << " -> "
  339. << string_from_type<default_distance_result>::name()
  340. << std::endl;
  341. std::cout << "expected distance = " << std::setprecision(10)
  342. << expected_distance << " ; "
  343. << std::endl;
  344. std::cout << "distance = " << std::setprecision(10)
  345. << dist << " ; "
  346. << std::endl;
  347. if ( !test_reversed )
  348. {
  349. std::cout << std::endl;
  350. }
  351. #endif
  352. if ( test_reversed )
  353. {
  354. // check distance with given strategy
  355. dist = bg::distance(geometry2, geometry1, strategy);
  356. check_equal
  357. <
  358. default_distance_result
  359. >::apply(case_id, "ra", geometry2, geometry1,
  360. dist, expected_distance);
  361. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  362. std::cout << "distance[reversed args] = " << std::setprecision(10)
  363. << dist
  364. << std::endl;
  365. #endif
  366. }
  367. if (swap_geometry_args)
  368. {
  369. Geometry1 g1 = dispatch
  370. <
  371. typename boost::geometry::tag<Geometry1>::type
  372. >::swap(geometry1);
  373. Geometry2 g2 = dispatch
  374. <
  375. typename boost::geometry::tag<Geometry2>::type
  376. >::swap(geometry2);
  377. // check distance with given strategy
  378. dist = bg::distance(g1, g2, strategy);
  379. check_equal
  380. <
  381. default_distance_result
  382. >::apply(case_id, "swap", g1, g2,
  383. dist, expected_distance);
  384. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  385. std::cout << "distance[swap geometry args] = " << std::setprecision(10)
  386. << dist
  387. << std::endl;
  388. std::cout << std::endl;
  389. #endif
  390. }
  391. if (mirror_geometry)
  392. {
  393. Geometry1 g1 = dispatch
  394. <
  395. typename boost::geometry::tag<Geometry1>::type
  396. >::mirror(geometry1);
  397. Geometry2 g2 = dispatch
  398. <
  399. typename boost::geometry::tag<Geometry2>::type
  400. >::mirror(geometry2);
  401. // check distance with given strategy
  402. dist = bg::distance(g1, g2, strategy);
  403. check_equal
  404. <
  405. default_distance_result
  406. >::apply(case_id, "mirror", g1, g2,
  407. dist, expected_distance);
  408. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  409. std::cout << "distance[mirror geometries] = " << std::setprecision(10)
  410. << dist
  411. << std::endl;
  412. std::cout << std::endl;
  413. #endif
  414. }
  415. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  416. std::cout << std::endl;
  417. #endif
  418. }
  419. };
  420. //========================================================================
  421. template <typename Geometry1, typename Geometry2, typename Strategy>
  422. void test_empty_input(Geometry1 const& geometry1,
  423. Geometry2 const& geometry2,
  424. Strategy const& strategy)
  425. {
  426. try
  427. {
  428. bg::distance(geometry1, geometry2);
  429. }
  430. catch(bg::empty_input_exception const& )
  431. {
  432. return;
  433. }
  434. BOOST_CHECK_MESSAGE(false,
  435. "A empty_input_exception should have been thrown");
  436. try
  437. {
  438. bg::distance(geometry2, geometry1);
  439. }
  440. catch(bg::empty_input_exception const& )
  441. {
  442. return;
  443. }
  444. BOOST_CHECK_MESSAGE(false,
  445. "A empty_input_exception should have been thrown");
  446. try
  447. {
  448. bg::distance(geometry1, geometry2, strategy);
  449. }
  450. catch(bg::empty_input_exception const& )
  451. {
  452. return;
  453. }
  454. BOOST_CHECK_MESSAGE(false,
  455. "A empty_input_exception should have been thrown");
  456. try
  457. {
  458. bg::distance(geometry2, geometry1, strategy);
  459. }
  460. catch(bg::empty_input_exception const& )
  461. {
  462. return;
  463. }
  464. BOOST_CHECK_MESSAGE(false,
  465. "A empty_input_exception should have been thrown");
  466. }
  467. #endif // BOOST_GEOMETRY_TEST_DISTANCE_GEO_COMMON_HPP