1 // Boost.Geometry (aka GGL, Generic Geometry Library)
4 // Copyright (c) 2014-2021, Oracle and/or its affiliates.
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8 // Licensed under the Boost Software License version 1.0.
9 // http://www.boost.org/users/license.html
11 #ifndef BOOST_GEOMETRY_TEST_DISTANCE_COMMON_HPP
12 #define BOOST_GEOMETRY_TEST_DISTANCE_COMMON_HPP
17 #include <boost/math/special_functions/fpclassify.hpp>
19 #include <boost/geometry/algorithms/distance.hpp>
20 #include <boost/geometry/algorithms/comparable_distance.hpp>
21 #include <boost/geometry/algorithms/num_interior_rings.hpp>
23 #include <boost/geometry/geometries/geometries.hpp>
25 #include <boost/geometry/io/wkt/write.hpp>
26 #include <boost/geometry/io/dsv/write.hpp>
28 #include <boost/geometry/strategies/strategies.hpp>
30 #include <from_wkt.hpp>
31 #include <string_from_type.hpp>
34 #ifndef BOOST_GEOMETRY_TEST_DISTANCE_HPP
36 namespace bg = ::boost::geometry;
38 // function copied from BG's test_distance.hpp
40 template <typename Geometry1, typename Geometry2>
41 void test_empty_input(Geometry1 const& geometry1, Geometry2 const& geometry2)
45 bg::distance(geometry1, geometry2);
47 catch(bg::empty_input_exception const& )
51 BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
53 #endif // BOOST_GEOMETRY_TEST_DISTANCE_HPP
55 //========================================================================
59 #ifdef BOOST_GEOMETRY_TEST_DEBUG
60 // pretty print geometry -- START
61 template <typename Geometry, typename GeometryTag>
62 struct pretty_print_geometry_dispatch
64 template <typename Stream>
65 static inline Stream& apply(Geometry const& geometry, Stream& os)
67 os << bg::wkt(geometry);
72 template <typename Geometry>
73 struct pretty_print_geometry_dispatch<Geometry, bg::segment_tag>
75 template <typename Stream>
76 static inline Stream& apply(Geometry const& geometry, Stream& os)
78 os << "SEGMENT" << bg::dsv(geometry);
83 template <typename Geometry>
84 struct pretty_print_geometry_dispatch<Geometry, bg::box_tag>
86 template <typename Stream>
87 static inline Stream& apply(Geometry const& geometry, Stream& os)
89 os << "BOX" << bg::dsv(geometry);
95 template <typename Geometry>
96 struct pretty_print_geometry
98 template <typename Stream>
99 static inline Stream& apply(Geometry const& geometry, Stream& os)
101 return pretty_print_geometry_dispatch
103 Geometry, typename bg::tag<Geometry>::type
104 >::apply(geometry, os);
107 // pretty print geometry -- END
108 #endif // BOOST_GEOMETRY_TEST_DEBUG
111 //========================================================================
114 template <typename T>
117 static inline void apply(T const& detected, T const& expected,
122 BOOST_CHECK(detected == expected);
126 BOOST_CHECK(! boost::math::isfinite(detected));
132 struct check_equal<double>
134 static inline void apply(double detected, double expected,
139 BOOST_CHECK_CLOSE(detected, expected, 0.0001);
143 BOOST_CHECK(! boost::math::isfinite(detected));
149 //========================================================================
153 typename Geometry1, typename Geometry2,
154 int id1 = bg::geometry_id<Geometry1>::value,
155 int id2 = bg::geometry_id<Geometry2>::value
157 struct test_distance_of_geometries
158 : public test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
161 #ifdef BOOST_GEOMETRY_TEST_DEBUG
162 #define ENABLE_IF_DEBUG(ID) ID
164 #define ENABLE_IF_DEBUG(ID)
167 template <typename Geometry1, typename Geometry2>
168 class test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
175 typename DistanceType,
176 typename ComparableDistanceType,
180 void base_test(std::string const& ENABLE_IF_DEBUG(header),
181 G1 const& g1, G2 const& g2,
182 DistanceType const& expected_distance,
183 ComparableDistanceType const& expected_comparable_distance,
184 Strategy const& strategy,
187 typedef typename bg::default_distance_result
190 >::type default_distance_result;
192 typedef typename bg::strategy::distance::services::return_type
195 >::type distance_result_from_strategy;
197 static const bool same_regular = std::is_same
199 default_distance_result,
200 distance_result_from_strategy
203 BOOST_CHECK( same_regular );
206 typedef typename bg::default_comparable_distance_result
209 >::type default_comparable_distance_result;
211 typedef typename bg::strategy::distance::services::return_type
213 typename bg::strategy::distance::services::comparable_type
219 >::type comparable_distance_result_from_strategy;
221 static const bool same_comparable = std::is_same
223 default_comparable_distance_result,
224 comparable_distance_result_from_strategy
227 BOOST_CHECK( same_comparable );
230 // check distance with default strategy
231 default_distance_result dist_def = bg::distance(g1, g2);
235 default_distance_result
236 >::apply(dist_def, expected_distance, is_finite);
239 // check distance with passed strategy
240 distance_result_from_strategy dist = bg::distance(g1, g2, strategy);
244 default_distance_result
245 >::apply(dist, expected_distance, is_finite);
248 // check comparable distance with default strategy
249 default_comparable_distance_result cdist_def =
250 bg::comparable_distance(g1, g2);
254 default_comparable_distance_result
255 >::apply(cdist_def, expected_comparable_distance, is_finite);
258 // check comparable distance with passed strategy
259 comparable_distance_result_from_strategy cdist =
260 bg::comparable_distance(g1, g2, strategy);
264 default_comparable_distance_result
265 >::apply(cdist, expected_comparable_distance, is_finite);
267 #ifdef BOOST_GEOMETRY_TEST_DEBUG
268 std::cout << string_from_type<typename bg::coordinate_type<Geometry1>::type>::name()
269 << string_from_type<typename bg::coordinate_type<Geometry2>::type>::name()
271 << string_from_type<default_distance_result>::name()
272 << string_from_type<default_comparable_distance_result>::name()
275 std::cout << "distance" << header
276 << " (def. strategy) = " << dist_def << " ; "
277 << "distance" << header
278 <<" (passed strategy) = " << dist << " ; "
279 << "comp. distance" << header <<" (def. strategy) = "
280 << cdist_def << " ; "
281 << "comp. distance" << header <<" (passed strategy) = "
282 << cdist << std::endl;
289 typename DistanceType,
290 typename ComparableDistanceType,
294 void apply(std::string const& wkt1,
295 std::string const& wkt2,
296 DistanceType const& expected_distance,
297 ComparableDistanceType const& expected_comparable_distance,
298 Strategy const& strategy,
299 bool is_finite = true)
301 Geometry1 geometry1 = from_wkt<Geometry1>(wkt1);
302 Geometry2 geometry2 = from_wkt<Geometry2>(wkt2);
304 apply(geometry1, geometry2,
305 expected_distance, expected_comparable_distance,
306 strategy, is_finite);
312 typename DistanceType,
313 typename ComparableDistanceType,
317 void apply(Geometry1 const& geometry1,
318 Geometry2 const& geometry2,
319 DistanceType const& expected_distance,
320 ComparableDistanceType const& expected_comparable_distance,
321 Strategy const& strategy,
322 bool is_finite = true)
324 #ifdef BOOST_GEOMETRY_TEST_DEBUG
325 typedef pretty_print_geometry<Geometry1> PPG1;
326 typedef pretty_print_geometry<Geometry2> PPG2;
327 PPG1::apply(geometry1, std::cout);
329 PPG2::apply(geometry2, std::cout);
330 std::cout << std::endl;
333 base_test("", geometry1, geometry2,
334 expected_distance, expected_comparable_distance,
335 strategy, is_finite);
337 base_test("[reversed args]", geometry2, geometry1,
338 expected_distance, expected_comparable_distance,
339 strategy, is_finite);
341 #ifdef BOOST_GEOMETRY_TEST_DEBUG
342 std::cout << std::endl;
348 //========================================================================
350 template <typename Segment, typename Polygon>
351 struct test_distance_of_geometries
354 92 /* segment */, 3 /* polygon */
356 : public test_distance_of_geometries<Segment, Polygon, 0, 0>
358 typedef test_distance_of_geometries<Segment, Polygon, 0, 0> base;
360 typedef typename bg::ring_type<Polygon>::type ring_type;
364 typename DistanceType,
365 typename ComparableDistanceType,
369 void apply(std::string const& wkt_segment,
370 std::string const& wkt_polygon,
371 DistanceType const& expected_distance,
372 ComparableDistanceType const& expected_comparable_distance,
373 Strategy const& strategy,
374 bool is_finite = true)
376 Segment segment = from_wkt<Segment>(wkt_segment);
377 Polygon polygon = from_wkt<Polygon>(wkt_polygon);
381 expected_comparable_distance,
389 typename DistanceType,
390 typename ComparableDistanceType,
394 void apply(Segment const& segment,
395 Polygon const& polygon,
396 DistanceType const& expected_distance,
397 ComparableDistanceType const& expected_comparable_distance,
398 Strategy const& strategy,
399 bool is_finite = true)
401 base::apply(segment, polygon, expected_distance,
402 expected_comparable_distance, strategy, is_finite);
404 if ( bg::num_interior_rings(polygon) == 0 ) {
405 #ifdef BOOST_GEOMETRY_TEST_DEBUG
406 std::cout << "... testing also exterior ring ..." << std::endl;
408 test_distance_of_geometries
412 bg::exterior_ring(polygon),
414 expected_comparable_distance,
421 //========================================================================
423 template <typename Box, typename Segment>
424 struct test_distance_of_geometries
427 94 /* box */, 92 /* segment */
432 typename DistanceType,
433 typename ComparableDistanceType,
437 void apply(std::string const& wkt_box,
438 std::string const& wkt_segment,
439 DistanceType const& expected_distance,
440 ComparableDistanceType const& expected_comparable_distance,
441 Strategy const& strategy,
442 bool is_finite = true)
444 test_distance_of_geometries
447 >::apply(wkt_segment,
450 expected_comparable_distance,
457 template <typename Segment, typename Box>
458 struct test_distance_of_geometries
461 92 /* segment */, 94 /* box */
463 : public test_distance_of_geometries<Segment, Box, 0, 0>
465 typedef test_distance_of_geometries<Segment, Box, 0, 0> base;
469 typename DistanceType,
470 typename ComparableDistanceType,
474 void apply(std::string const& wkt_segment,
475 std::string const& wkt_box,
476 DistanceType const& expected_distance,
477 ComparableDistanceType const& expected_comparable_distance,
478 Strategy const& strategy,
479 bool is_finite = true)
481 Segment segment = from_wkt<Segment>(wkt_segment);
482 Box box = from_wkt<Box>(wkt_box);
486 expected_comparable_distance,
494 typename DistanceType,
495 typename ComparableDistanceType,
499 void apply(Segment const& segment,
501 DistanceType const& expected_distance,
502 ComparableDistanceType const& expected_comparable_distance,
503 Strategy const& strategy,
504 bool is_finite = true)
506 typedef typename bg::strategy::distance::services::return_type
508 Strategy, Segment, Box
509 >::type distance_result_type;
511 typedef typename bg::strategy::distance::services::comparable_type
514 >::type comparable_strategy;
516 typedef typename bg::strategy::distance::services::return_type
518 comparable_strategy, Segment, Box
519 >::type comparable_distance_result_type;
522 base::apply(segment, box, expected_distance,
523 expected_comparable_distance, strategy, is_finite);
525 auto strategies = bg::strategies::distance::services::strategy_converter<Strategy>::get(strategy);
526 auto cstrategies = bg::strategies::distance::detail::make_comparable(strategies);
528 // TODO: these algorithms are used only here. Remove them?
530 distance_result_type distance_generic =
531 bg::detail::distance::segment_to_box_2D_generic
533 Segment, Box, decltype(strategies), false
534 >::apply(segment, box, strategies);
536 comparable_distance_result_type comparable_distance_generic =
537 bg::detail::distance::segment_to_box_2D_generic
539 Segment, Box, decltype(cstrategies), false
540 >::apply(segment, box, cstrategies);
545 >::apply(distance_generic, expected_distance, is_finite);
549 comparable_distance_result_type
550 >::apply(comparable_distance_generic,
551 expected_comparable_distance,
555 bg::detail::distance::segment_to_box_2D_generic
557 Segment, Box, decltype(strategies), true
558 >::apply(segment, box, strategies);
560 comparable_distance_generic =
561 bg::detail::distance::segment_to_box_2D_generic
563 Segment, Box, decltype(cstrategies), true
564 >::apply(segment, box, cstrategies);
569 >::apply(distance_generic, expected_distance, is_finite);
573 comparable_distance_result_type
574 >::apply(comparable_distance_generic,
575 expected_comparable_distance,
578 #ifdef BOOST_GEOMETRY_TEST_DEBUG
579 std::cout << "... testing with naive seg-box distance algorithm..."
581 std::cout << "distance (generic algorithm) = "
582 << distance_generic << " ; "
583 << "comp. distance (generic algorithm) = "
584 << comparable_distance_generic
586 std::cout << std::endl << std::endl;
591 //========================================================================
594 template <typename Geometry1, typename Geometry2, typename Strategy>
595 void test_empty_input(Geometry1 const& geometry1,
596 Geometry2 const& geometry2,
597 Strategy const& strategy)
601 bg::distance(geometry1, geometry2, strategy);
603 catch(bg::empty_input_exception const& )
607 BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
611 bg::distance(geometry2, geometry1, strategy);
613 catch(bg::empty_input_exception const& )
617 BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" );
620 #endif // BOOST_GEOMETRY_TEST_DISTANCE_COMMON_HPP