test_distance_common.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Unit Test
  3. // Copyright (c) 2014-2017, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Licensed under the Boost Software License version 1.0.
  7. // http://www.boost.org/users/license.html
  8. #ifndef BOOST_GEOMETRY_TEST_DISTANCE_COMMON_HPP
  9. #define BOOST_GEOMETRY_TEST_DISTANCE_COMMON_HPP
  10. #include <iostream>
  11. #include <string>
  12. #include <boost/math/special_functions/fpclassify.hpp>
  13. #include <boost/mpl/assert.hpp>
  14. #include <boost/type_traits/is_integral.hpp>
  15. #include <boost/type_traits/is_same.hpp>
  16. #include <boost/geometry/geometries/point.hpp>
  17. #include <boost/geometry/geometries/point_xy.hpp>
  18. #include <boost/geometry/geometries/segment.hpp>
  19. #include <boost/geometry/geometries/linestring.hpp>
  20. #include <boost/geometry/geometries/polygon.hpp>
  21. #include <boost/geometry/geometries/ring.hpp>
  22. #include <boost/geometry/geometries/box.hpp>
  23. #include <boost/geometry/geometries/multi_point.hpp>
  24. #include <boost/geometry/geometries/multi_linestring.hpp>
  25. #include <boost/geometry/geometries/multi_polygon.hpp>
  26. #include <boost/geometry/io/wkt/write.hpp>
  27. #include <boost/geometry/io/dsv/write.hpp>
  28. #include <boost/geometry/algorithms/num_interior_rings.hpp>
  29. #include <boost/geometry/algorithms/distance.hpp>
  30. #include <boost/geometry/algorithms/comparable_distance.hpp>
  31. #include <boost/geometry/strategies/strategies.hpp>
  32. #include <from_wkt.hpp>
  33. #include <string_from_type.hpp>
  34. #ifndef BOOST_GEOMETRY_TEST_DISTANCE_HPP
  35. namespace bg = ::boost::geometry;
  36. // function copied from BG's test_distance.hpp
  37. template <typename Geometry1, typename Geometry2>
  38. void test_empty_input(Geometry1 const& geometry1, Geometry2 const& geometry2)
  39. {
  40. try
  41. {
  42. bg::distance(geometry1, geometry2);
  43. }
  44. catch(bg::empty_input_exception const& )
  45. {
  46. return;
  47. }
  48. BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
  49. }
  50. #endif // BOOST_GEOMETRY_TEST_DISTANCE_HPP
  51. //========================================================================
  52. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  53. // pretty print geometry -- START
  54. template <typename Geometry, typename GeometryTag>
  55. struct pretty_print_geometry_dispatch
  56. {
  57. template <typename Stream>
  58. static inline Stream& apply(Geometry const& geometry, Stream& os)
  59. {
  60. os << bg::wkt(geometry);
  61. return os;
  62. }
  63. };
  64. template <typename Geometry>
  65. struct pretty_print_geometry_dispatch<Geometry, bg::segment_tag>
  66. {
  67. template <typename Stream>
  68. static inline Stream& apply(Geometry const& geometry, Stream& os)
  69. {
  70. os << "SEGMENT" << bg::dsv(geometry);
  71. return os;
  72. }
  73. };
  74. template <typename Geometry>
  75. struct pretty_print_geometry_dispatch<Geometry, bg::box_tag>
  76. {
  77. template <typename Stream>
  78. static inline Stream& apply(Geometry const& geometry, Stream& os)
  79. {
  80. os << "BOX" << bg::dsv(geometry);
  81. return os;
  82. }
  83. };
  84. template <typename Geometry>
  85. struct pretty_print_geometry
  86. {
  87. template <typename Stream>
  88. static inline Stream& apply(Geometry const& geometry, Stream& os)
  89. {
  90. return pretty_print_geometry_dispatch
  91. <
  92. Geometry, typename bg::tag<Geometry>::type
  93. >::apply(geometry, os);
  94. }
  95. };
  96. // pretty print geometry -- END
  97. #endif // BOOST_GEOMETRY_TEST_DEBUG
  98. //========================================================================
  99. template <typename T>
  100. struct check_equal
  101. {
  102. static inline void apply(T const& detected, T const& expected,
  103. bool is_finite)
  104. {
  105. if (is_finite)
  106. {
  107. BOOST_CHECK(detected == expected);
  108. }
  109. else
  110. {
  111. BOOST_CHECK(! boost::math::isfinite(detected));
  112. }
  113. }
  114. };
  115. template <>
  116. struct check_equal<double>
  117. {
  118. static inline void apply(double detected, double expected,
  119. bool is_finite)
  120. {
  121. if (is_finite)
  122. {
  123. BOOST_CHECK_CLOSE(detected, expected, 0.0001);
  124. }
  125. else
  126. {
  127. BOOST_CHECK(! boost::math::isfinite(detected));
  128. }
  129. }
  130. };
  131. //========================================================================
  132. template
  133. <
  134. typename Geometry1, typename Geometry2,
  135. int id1 = bg::geometry_id<Geometry1>::value,
  136. int id2 = bg::geometry_id<Geometry2>::value
  137. >
  138. struct test_distance_of_geometries
  139. : public test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
  140. {};
  141. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  142. #define ENABLE_IF_DEBUG(ID) ID
  143. #else
  144. #define ENABLE_IF_DEBUG(ID)
  145. #endif
  146. template <typename Geometry1, typename Geometry2>
  147. class test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
  148. {
  149. private:
  150. template
  151. <
  152. typename G1,
  153. typename G2,
  154. typename DistanceType,
  155. typename ComparableDistanceType,
  156. typename Strategy
  157. >
  158. static inline
  159. void base_test(std::string const& ENABLE_IF_DEBUG(header),
  160. G1 const& g1, G2 const& g2,
  161. DistanceType const& expected_distance,
  162. ComparableDistanceType const& expected_comparable_distance,
  163. Strategy const& strategy,
  164. bool is_finite)
  165. {
  166. typedef typename bg::default_distance_result
  167. <
  168. G1, G2
  169. >::type default_distance_result;
  170. typedef typename bg::strategy::distance::services::return_type
  171. <
  172. Strategy, G1, G2
  173. >::type distance_result_from_strategy;
  174. static const bool same_regular = boost::is_same
  175. <
  176. default_distance_result,
  177. distance_result_from_strategy
  178. >::type::value;
  179. BOOST_CHECK( same_regular );
  180. typedef typename bg::default_comparable_distance_result
  181. <
  182. G1, G2
  183. >::type default_comparable_distance_result;
  184. typedef typename bg::strategy::distance::services::return_type
  185. <
  186. typename bg::strategy::distance::services::comparable_type
  187. <
  188. Strategy
  189. >::type,
  190. G1,
  191. G2
  192. >::type comparable_distance_result_from_strategy;
  193. static const bool same_comparable = boost::is_same
  194. <
  195. default_comparable_distance_result,
  196. comparable_distance_result_from_strategy
  197. >::type::value;
  198. BOOST_CHECK( same_comparable );
  199. // check distance with default strategy
  200. default_distance_result dist_def = bg::distance(g1, g2);
  201. check_equal
  202. <
  203. default_distance_result
  204. >::apply(dist_def, expected_distance, is_finite);
  205. // check distance with passed strategy
  206. distance_result_from_strategy dist = bg::distance(g1, g2, strategy);
  207. check_equal
  208. <
  209. default_distance_result
  210. >::apply(dist, expected_distance, is_finite);
  211. // check comparable distance with default strategy
  212. default_comparable_distance_result cdist_def =
  213. bg::comparable_distance(g1, g2);
  214. check_equal
  215. <
  216. default_comparable_distance_result
  217. >::apply(cdist_def, expected_comparable_distance, is_finite);
  218. // check comparable distance with passed strategy
  219. comparable_distance_result_from_strategy cdist =
  220. bg::comparable_distance(g1, g2, strategy);
  221. check_equal
  222. <
  223. default_comparable_distance_result
  224. >::apply(cdist, expected_comparable_distance, is_finite);
  225. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  226. std::cout << string_from_type<typename bg::coordinate_type<Geometry1>::type>::name()
  227. << string_from_type<typename bg::coordinate_type<Geometry2>::type>::name()
  228. << " -> "
  229. << string_from_type<default_distance_result>::name()
  230. << string_from_type<default_comparable_distance_result>::name()
  231. << std::endl;
  232. std::cout << "distance" << header
  233. << " (def. strategy) = " << dist_def << " ; "
  234. << "distance" << header
  235. <<" (passed strategy) = " << dist << " ; "
  236. << "comp. distance" << header <<" (def. strategy) = "
  237. << cdist_def << " ; "
  238. << "comp. distance" << header <<" (passed strategy) = "
  239. << cdist << std::endl;
  240. #endif
  241. }
  242. public:
  243. template
  244. <
  245. typename DistanceType,
  246. typename ComparableDistanceType,
  247. typename Strategy
  248. >
  249. static inline
  250. void apply(std::string const& wkt1,
  251. std::string const& wkt2,
  252. DistanceType const& expected_distance,
  253. ComparableDistanceType const& expected_comparable_distance,
  254. Strategy const& strategy,
  255. bool is_finite = true)
  256. {
  257. Geometry1 geometry1 = from_wkt<Geometry1>(wkt1);
  258. Geometry2 geometry2 = from_wkt<Geometry2>(wkt2);
  259. apply(geometry1, geometry2,
  260. expected_distance, expected_comparable_distance,
  261. strategy, is_finite);
  262. }
  263. template
  264. <
  265. typename DistanceType,
  266. typename ComparableDistanceType,
  267. typename Strategy
  268. >
  269. static inline
  270. void apply(Geometry1 const& geometry1,
  271. Geometry2 const& geometry2,
  272. DistanceType const& expected_distance,
  273. ComparableDistanceType const& expected_comparable_distance,
  274. Strategy const& strategy,
  275. bool is_finite = true)
  276. {
  277. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  278. typedef pretty_print_geometry<Geometry1> PPG1;
  279. typedef pretty_print_geometry<Geometry2> PPG2;
  280. PPG1::apply(geometry1, std::cout);
  281. std::cout << " - ";
  282. PPG2::apply(geometry2, std::cout);
  283. std::cout << std::endl;
  284. #endif
  285. base_test("", geometry1, geometry2,
  286. expected_distance, expected_comparable_distance,
  287. strategy, is_finite);
  288. base_test("[reversed args]", geometry2, geometry1,
  289. expected_distance, expected_comparable_distance,
  290. strategy, is_finite);
  291. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  292. std::cout << std::endl;
  293. #endif
  294. }
  295. };
  296. //========================================================================
  297. template <typename Segment, typename Polygon>
  298. struct test_distance_of_geometries
  299. <
  300. Segment, Polygon,
  301. 92 /* segment */, 3 /* polygon */
  302. >
  303. : public test_distance_of_geometries<Segment, Polygon, 0, 0>
  304. {
  305. typedef test_distance_of_geometries<Segment, Polygon, 0, 0> base;
  306. typedef typename bg::ring_type<Polygon>::type ring_type;
  307. template
  308. <
  309. typename DistanceType,
  310. typename ComparableDistanceType,
  311. typename Strategy
  312. >
  313. static inline
  314. void apply(std::string const& wkt_segment,
  315. std::string const& wkt_polygon,
  316. DistanceType const& expected_distance,
  317. ComparableDistanceType const& expected_comparable_distance,
  318. Strategy const& strategy,
  319. bool is_finite = true)
  320. {
  321. Segment segment = from_wkt<Segment>(wkt_segment);
  322. Polygon polygon = from_wkt<Polygon>(wkt_polygon);
  323. apply(segment,
  324. polygon,
  325. expected_distance,
  326. expected_comparable_distance,
  327. strategy,
  328. is_finite);
  329. }
  330. template
  331. <
  332. typename DistanceType,
  333. typename ComparableDistanceType,
  334. typename Strategy
  335. >
  336. static inline
  337. void apply(Segment const& segment,
  338. Polygon const& polygon,
  339. DistanceType const& expected_distance,
  340. ComparableDistanceType const& expected_comparable_distance,
  341. Strategy const& strategy,
  342. bool is_finite = true)
  343. {
  344. base::apply(segment, polygon, expected_distance,
  345. expected_comparable_distance, strategy, is_finite);
  346. if ( bg::num_interior_rings(polygon) == 0 ) {
  347. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  348. std::cout << "... testing also exterior ring ..." << std::endl;
  349. #endif
  350. test_distance_of_geometries
  351. <
  352. Segment, ring_type
  353. >::apply(segment,
  354. bg::exterior_ring(polygon),
  355. expected_distance,
  356. expected_comparable_distance,
  357. strategy,
  358. is_finite);
  359. }
  360. }
  361. };
  362. //========================================================================
  363. template <typename Box, typename Segment>
  364. struct test_distance_of_geometries
  365. <
  366. Box, Segment,
  367. 94 /* box */, 92 /* segment */
  368. >
  369. {
  370. template
  371. <
  372. typename DistanceType,
  373. typename ComparableDistanceType,
  374. typename Strategy
  375. >
  376. static inline
  377. void apply(std::string const& wkt_box,
  378. std::string const& wkt_segment,
  379. DistanceType const& expected_distance,
  380. ComparableDistanceType const& expected_comparable_distance,
  381. Strategy const& strategy,
  382. bool is_finite = true)
  383. {
  384. test_distance_of_geometries
  385. <
  386. Segment, Box, 92, 94
  387. >::apply(wkt_segment,
  388. wkt_box,
  389. expected_distance,
  390. expected_comparable_distance,
  391. strategy,
  392. is_finite);
  393. }
  394. };
  395. template <typename Segment, typename Box>
  396. struct test_distance_of_geometries
  397. <
  398. Segment, Box,
  399. 92 /* segment */, 94 /* box */
  400. >
  401. : public test_distance_of_geometries<Segment, Box, 0, 0>
  402. {
  403. typedef test_distance_of_geometries<Segment, Box, 0, 0> base;
  404. template
  405. <
  406. typename DistanceType,
  407. typename ComparableDistanceType,
  408. typename Strategy
  409. >
  410. static inline
  411. void apply(std::string const& wkt_segment,
  412. std::string const& wkt_box,
  413. DistanceType const& expected_distance,
  414. ComparableDistanceType const& expected_comparable_distance,
  415. Strategy const& strategy,
  416. bool is_finite = true)
  417. {
  418. Segment segment = from_wkt<Segment>(wkt_segment);
  419. Box box = from_wkt<Box>(wkt_box);
  420. apply(segment,
  421. box,
  422. expected_distance,
  423. expected_comparable_distance,
  424. strategy,
  425. is_finite);
  426. }
  427. template
  428. <
  429. typename DistanceType,
  430. typename ComparableDistanceType,
  431. typename Strategy
  432. >
  433. static inline
  434. void apply(Segment const& segment,
  435. Box const& box,
  436. DistanceType const& expected_distance,
  437. ComparableDistanceType const& expected_comparable_distance,
  438. Strategy const& strategy,
  439. bool is_finite = true)
  440. {
  441. typedef typename bg::strategy::distance::services::return_type
  442. <
  443. Strategy, Segment, Box
  444. >::type distance_result_type;
  445. typedef typename bg::strategy::distance::services::comparable_type
  446. <
  447. Strategy
  448. >::type comparable_strategy;
  449. typedef typename bg::strategy::distance::services::return_type
  450. <
  451. comparable_strategy, Segment, Box
  452. >::type comparable_distance_result_type;
  453. base::apply(segment, box, expected_distance,
  454. expected_comparable_distance, strategy, is_finite);
  455. comparable_strategy cstrategy =
  456. bg::strategy::distance::services::get_comparable
  457. <
  458. Strategy
  459. >::apply(strategy);
  460. distance_result_type distance_generic =
  461. bg::detail::distance::segment_to_box_2D_generic
  462. <
  463. Segment, Box, Strategy
  464. >::apply(segment, box, strategy);
  465. comparable_distance_result_type comparable_distance_generic =
  466. bg::detail::distance::segment_to_box_2D_generic
  467. <
  468. Segment, Box, comparable_strategy
  469. >::apply(segment, box, cstrategy);
  470. check_equal
  471. <
  472. distance_result_type
  473. >::apply(distance_generic, expected_distance, is_finite);
  474. check_equal
  475. <
  476. comparable_distance_result_type
  477. >::apply(comparable_distance_generic,
  478. expected_comparable_distance,
  479. is_finite);
  480. #ifdef BOOST_GEOMETRY_TEST_DEBUG
  481. std::cout << "... testing with naive seg-box distance algorithm..."
  482. << std::endl;
  483. std::cout << "distance (generic algorithm) = "
  484. << distance_generic << " ; "
  485. << "comp. distance (generic algorithm) = "
  486. << comparable_distance_generic
  487. << std::endl;
  488. std::cout << std::endl << std::endl;
  489. #endif
  490. }
  491. };
  492. //========================================================================
  493. template <typename Geometry1, typename Geometry2, typename Strategy>
  494. void test_empty_input(Geometry1 const& geometry1,
  495. Geometry2 const& geometry2,
  496. Strategy const& strategy)
  497. {
  498. try
  499. {
  500. bg::distance(geometry1, geometry2, strategy);
  501. }
  502. catch(bg::empty_input_exception const& )
  503. {
  504. return;
  505. }
  506. BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
  507. try
  508. {
  509. bg::distance(geometry2, geometry1, strategy);
  510. }
  511. catch(bg::empty_input_exception const& )
  512. {
  513. return;
  514. }
  515. BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
  516. }
  517. #endif // BOOST_GEOMETRY_TEST_DISTANCE_COMMON_HPP