1 // Boost.Geometry (aka GGL, Generic Geometry Library)
4 // Copyright (c) 2016-2021, Oracle and/or its affiliates.
5 // Contributed and/or modified by Vissarion Fysikopoulos, 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_GEO_COMMON_HPP
12 #define BOOST_GEOMETRY_TEST_DISTANCE_GEO_COMMON_HPP
17 #include <boost/geometry/algorithms/distance.hpp>
18 #include <boost/geometry/algorithms/num_interior_rings.hpp>
20 #include <boost/geometry/geometries/geometries.hpp>
22 #include <boost/geometry/io/wkt/write.hpp>
23 #include <boost/geometry/io/dsv/write.hpp>
25 #include <boost/geometry/strategies/strategies.hpp>
27 #include <boost/geometry/util/condition.hpp>
29 #include <from_wkt.hpp>
30 #include <string_from_type.hpp>
32 #include "distance_brute_force.hpp"
34 namespace bg = ::boost::geometry;
36 typedef bg::srs::spheroid<double> stype;
38 // Spherical strategy for point-point distance
40 typedef bg::strategy::distance::haversine<double> spherical_pp;
42 // Geo strategies for point-point distance
44 typedef bg::strategy::distance::andoyer<stype> andoyer_pp;
45 typedef bg::strategy::distance::thomas<stype> thomas_pp;
46 typedef bg::strategy::distance::vincenty<stype> vincenty_pp;
47 typedef bg::strategy::distance::karney<stype> karney_pp;
49 // Spherical strategy for point-segment distance
51 typedef bg::strategy::distance::cross_track<> spherical_ps;
53 // Geo strategies for point-segment distance
55 typedef bg::strategy::distance::geographic_cross_track<bg::strategy::andoyer, stype, double>
58 typedef bg::strategy::distance::geographic_cross_track<bg::strategy::thomas, stype, double>
61 typedef bg::strategy::distance::geographic_cross_track<bg::strategy::vincenty, stype, double>
64 typedef bg::strategy::distance::geographic_cross_track<bg::strategy::karney, stype, double>
67 typedef bg::strategy::distance::detail::geographic_cross_track<bg::strategy::vincenty, stype, double, true>
68 vincenty_ps_bisection;
70 // Spherical strategy for point-box distance
72 typedef bg::strategy::distance::cross_track_point_box<> spherical_pb;
74 // Geo strategies for point-box distance
76 typedef bg::strategy::distance::geographic_cross_track_point_box
78 bg::strategy::andoyer,
83 typedef bg::strategy::distance::geographic_cross_track_point_box
90 typedef bg::strategy::distance::geographic_cross_track_point_box
92 bg::strategy::vincenty,
97 typedef bg::strategy::distance::geographic_cross_track_point_box
104 // Spherical strategy for segment-box distance
106 typedef bg::strategy::distance::spherical_segment_box<> spherical_sb;
108 // Geo strategies for segment-box distance
110 typedef bg::strategy::distance::geographic_segment_box<bg::strategy::andoyer, stype, double>
113 typedef bg::strategy::distance::geographic_segment_box<bg::strategy::thomas, stype, double>
116 typedef bg::strategy::distance::geographic_segment_box<bg::strategy::vincenty, stype, double>
119 typedef bg::strategy::distance::geographic_segment_box<bg::strategy::karney, stype, double>
122 // Strategies for box-box distance
124 typedef bg::strategy::distance::cross_track_box_box<> spherical_bb;
126 typedef bg::strategy::distance::geographic_cross_track_box_box
128 bg::strategy::andoyer,
133 typedef bg::strategy::distance::geographic_cross_track_box_box
135 bg::strategy::thomas,
140 typedef bg::strategy::distance::geographic_cross_track_box_box
142 bg::strategy::vincenty,
147 typedef bg::strategy::distance::geographic_cross_track_box_box
149 bg::strategy::karney,
154 //===========================================================================
156 template <typename Point, typename Strategy>
157 inline typename bg::default_distance_result<Point>::type
158 pp_distance(std::string const& wkt1,
159 std::string const& wkt2,
160 Strategy const& strategy)
163 bg::read_wkt(wkt1, p1);
164 bg::read_wkt(wkt2, p2);
165 return bg::distance(p1, p2, strategy);
168 //===========================================================================
170 template <typename Point, typename Strategy>
171 inline typename bg::default_distance_result<Point>::type
172 ps_distance(std::string const& wkt1,
173 std::string const& wkt2,
174 Strategy const& strategy)
177 typedef bg::model::segment<Point> segment_type;
179 bg::read_wkt(wkt1, p);
180 bg::read_wkt(wkt2, s);
181 return bg::distance(p, s, strategy);
184 //===========================================================================
186 template <typename Point, typename Strategy>
187 inline typename bg::default_distance_result<Point>::type
188 sb_distance(std::string const& wkt1,
189 std::string const& wkt2,
190 Strategy const& strategy)
192 typedef bg::model::segment<Point> segment_type;
193 typedef bg::model::box<Point> box_type;
196 bg::read_wkt(wkt1, s);
197 bg::read_wkt(wkt2, b);
198 return bg::distance(s, b, strategy);
201 //===================================================================
203 template <typename Tag> struct dispatch
205 //tag dispatching for swaping arguments in segments
206 template <typename T>
207 static inline T swap(T const& t)
212 // mirror geometry w.r.t. equator
213 template <typename T>
214 static inline T mirror(T const& t)
220 // Specialization for segments
221 template <> struct dispatch<bg::segment_tag>
223 template <typename Segment>
224 static inline Segment swap(Segment const& s)
228 bg::set<0, 0>(s_swaped, bg::get<1, 0>(s));
229 bg::set<0, 1>(s_swaped, bg::get<1, 1>(s));
230 bg::set<1, 0>(s_swaped, bg::get<0, 0>(s));
231 bg::set<1, 1>(s_swaped, bg::get<0, 1>(s));
236 template <typename Segment>
237 static inline Segment mirror(Segment const& s)
241 bg::set<0, 0>(s_mirror, bg::get<0, 0>(s));
242 bg::set<0, 1>(s_mirror, bg::get<0, 1>(s) * -1);
243 bg::set<1, 0>(s_mirror, bg::get<1, 0>(s));
244 bg::set<1, 1>(s_mirror, bg::get<1, 1>(s) * -1);
250 // Specialization for boxes
251 template <> struct dispatch<bg::box_tag>
253 template <typename T>
254 static inline T swap(T const& t)
259 template <typename Box>
260 static inline Box mirror(Box const& b)
264 bg::set<0, 0>(b_mirror, bg::get<bg::min_corner, 0>(b));
265 bg::set<0, 1>(b_mirror, bg::get<bg::max_corner, 1>(b) * -1);
266 bg::set<1, 0>(b_mirror, bg::get<bg::max_corner, 0>(b));
267 bg::set<1, 1>(b_mirror, bg::get<bg::min_corner, 1>(b) * -1);
274 // Specialization for points
275 template <> struct dispatch<bg::point_tag>
277 template <typename T>
278 static inline T swap(T const& t)
283 template <typename Point>
284 static inline Point mirror(Point const& p)
288 bg::set<0>(p_mirror, bg::get<0>(p));
289 bg::set<1>(p_mirror, bg::get<1>(p) * -1);
295 //========================================================================
298 template <typename T>
301 template <typename Value, typename = void>
304 static inline void apply(Value const& x, Value const& y)
310 template <typename Dummy>
311 struct equal_to<double, Dummy>
313 static inline void apply(double x, double y)
315 BOOST_CHECK_CLOSE(x, y, 0.001);
319 template <typename Geometry1, typename Geometry2>
320 static inline void apply(std::string const& /*case_id*/,
321 std::string const& /*subcase_id*/,
322 Geometry1 const& /*geometry1*/,
323 Geometry2 const& /*geometry2*/,
327 equal_to<T>::apply(expected, detected);
331 //========================================================================
335 typename Geometry1, typename Geometry2,
336 int id1 = bg::geometry_id<Geometry1>::value,
337 int id2 = bg::geometry_id<Geometry2>::value
339 struct test_distance_of_geometries
340 : public test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
344 template <typename Geometry1, typename Geometry2>
345 struct test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
347 template <typename DistanceType, typename Strategy>
349 void apply(std::string const& case_id,
350 std::string const& wkt1,
351 std::string const& wkt2,
352 DistanceType const& expected_distance,
353 Strategy const& strategy,
354 bool test_reversed = true,
355 bool swap_geometry_args = false,
356 bool mirror_geometry = true)
358 Geometry1 geometry1 = from_wkt<Geometry1>(wkt1);
359 Geometry2 geometry2 = from_wkt<Geometry2>(wkt2);
361 apply(case_id, geometry1, geometry2,
363 strategy, test_reversed, swap_geometry_args,
370 typename DistanceType,
374 void apply(std::string const& case_id,
375 Geometry1 const& geometry1,
376 Geometry2 const& geometry2,
377 DistanceType const& expected_distance,
378 Strategy const& strategy,
379 bool test_reversed = true,
380 bool swap_geometry_args = false,
381 bool mirror_geometry = true)
383 #ifdef BOOST_GEOMETRY_TEST_DEBUG
384 std::cout << "case ID: " << case_id << "; "
385 << "G1: " << bg::wkt(geometry1)
387 << "G2: " << bg::wkt(geometry2)
390 namespace services = bg::strategy::distance::services;
392 using bg::unit_test::distance_brute_force;
394 typedef typename bg::default_distance_result
397 >::type default_distance_result;
399 typedef typename services::return_type
401 Strategy, Geometry1, Geometry2
402 >::type distance_result_from_strategy;
404 static const bool same_regular = std::is_same
406 default_distance_result,
407 distance_result_from_strategy
410 BOOST_CHECK(same_regular);
412 // check distance with passed strategy
413 distance_result_from_strategy dist =
414 bg::distance(geometry1, geometry2, strategy);
418 distance_result_from_strategy
419 >::apply(case_id, "a", geometry1, geometry2,
420 dist, expected_distance);
422 // check against the comparable distance computed in a
423 // brute-force manner
424 default_distance_result dist_brute_force
425 = distance_brute_force(geometry1, geometry2, strategy);
429 default_distance_result
430 >::apply(case_id, "b", geometry1, geometry2,
431 dist_brute_force, expected_distance);
433 #ifdef BOOST_GEOMETRY_TEST_DEBUG
434 std::cout << string_from_type<typename bg::coordinate_type<Geometry1>::type>::name()
435 << string_from_type<typename bg::coordinate_type<Geometry2>::type>::name()
437 << string_from_type<default_distance_result>::name()
439 std::cout << "expected distance = " << std::setprecision(10)
440 << expected_distance << " ; "
442 std::cout << "distance = " << std::setprecision(10)
446 if ( !test_reversed )
448 std::cout << std::endl;
454 // check distance with given strategy
455 dist = bg::distance(geometry2, geometry1, strategy);
459 default_distance_result
460 >::apply(case_id, "ra", geometry2, geometry1,
461 dist, expected_distance);
463 #ifdef BOOST_GEOMETRY_TEST_DEBUG
464 std::cout << "distance[reversed args] = " << std::setprecision(10)
470 if (swap_geometry_args)
472 Geometry1 g1 = dispatch
474 typename bg::tag<Geometry1>::type
477 Geometry2 g2 = dispatch
479 typename bg::tag<Geometry2>::type
482 // check distance with given strategy
483 dist = bg::distance(g1, g2, strategy);
487 default_distance_result
488 >::apply(case_id, "swap", g1, g2,
489 dist, expected_distance);
491 #ifdef BOOST_GEOMETRY_TEST_DEBUG
492 std::cout << "distance[swap geometry args] = " << std::setprecision(10)
495 std::cout << std::endl;
500 Geometry1 g1 = dispatch
502 typename bg::tag<Geometry1>::type
503 >::mirror(geometry1);
505 Geometry2 g2 = dispatch
507 typename bg::tag<Geometry2>::type
508 >::mirror(geometry2);
510 // check distance with given strategy
511 dist = bg::distance(g1, g2, strategy);
515 default_distance_result
516 >::apply(case_id, "mirror", g1, g2,
517 dist, expected_distance);
519 #ifdef BOOST_GEOMETRY_TEST_DEBUG
520 std::cout << "distance[mirror geometries] = " << std::setprecision(10)
523 std::cout << std::endl;
526 #ifdef BOOST_GEOMETRY_TEST_DEBUG
527 std::cout << std::endl;
534 //========================================================================
537 template <typename Geometry1, typename Geometry2, typename Strategy>
538 void test_empty_input(Geometry1 const& geometry1,
539 Geometry2 const& geometry2,
540 Strategy const& strategy)
544 bg::distance(geometry1, geometry2);
546 catch(bg::empty_input_exception const& )
550 BOOST_CHECK_MESSAGE(false,
551 "A empty_input_exception should have been thrown");
555 bg::distance(geometry2, geometry1);
557 catch(bg::empty_input_exception const& )
561 BOOST_CHECK_MESSAGE(false,
562 "A empty_input_exception should have been thrown");
566 bg::distance(geometry1, geometry2, strategy);
568 catch(bg::empty_input_exception const& )
572 BOOST_CHECK_MESSAGE(false,
573 "A empty_input_exception should have been thrown");
577 bg::distance(geometry2, geometry1, strategy);
579 catch(bg::empty_input_exception const& )
583 BOOST_CHECK_MESSAGE(false,
584 "A empty_input_exception should have been thrown");
587 #endif // BOOST_GEOMETRY_TEST_DISTANCE_GEO_COMMON_HPP