• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3 
4 // Copyright (c) 2014-2017, Oracle and/or its affiliates.
5 
6 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8 
9 // Licensed under the Boost Software License version 1.0.
10 // http://www.boost.org/users/license.html
11 
12 #ifndef BOOST_GEOMETRY_TEST_DISTANCE_SE_COMMON_HPP
13 #define BOOST_GEOMETRY_TEST_DISTANCE_SE_COMMON_HPP
14 
15 #include <iostream>
16 #include <string>
17 
18 #include <boost/mpl/assert.hpp>
19 #include <boost/type_traits/is_integral.hpp>
20 #include <boost/type_traits/is_same.hpp>
21 
22 #include <boost/geometry/geometries/point.hpp>
23 #include <boost/geometry/geometries/point_xy.hpp>
24 #include <boost/geometry/geometries/segment.hpp>
25 #include <boost/geometry/geometries/linestring.hpp>
26 #include <boost/geometry/geometries/polygon.hpp>
27 #include <boost/geometry/geometries/ring.hpp>
28 #include <boost/geometry/geometries/box.hpp>
29 #include <boost/geometry/geometries/multi_point.hpp>
30 #include <boost/geometry/geometries/multi_linestring.hpp>
31 #include <boost/geometry/geometries/multi_polygon.hpp>
32 
33 #include <boost/geometry/io/wkt/write.hpp>
34 #include <boost/geometry/io/dsv/write.hpp>
35 
36 #include <boost/geometry/algorithms/num_interior_rings.hpp>
37 #include <boost/geometry/algorithms/distance.hpp>
38 #include <boost/geometry/algorithms/comparable_distance.hpp>
39 
40 #include <boost/geometry/strategies/strategies.hpp>
41 
42 #include <from_wkt.hpp>
43 #include <string_from_type.hpp>
44 
45 #include "distance_brute_force.hpp"
46 
47 namespace bg = ::boost::geometry;
48 
49 static const double earth_radius_km = 6371.0;
50 static const double earth_radius_miles = 3959.0;
51 
52 
53 //========================================================================
54 
55 
56 template <typename T>
57 struct check_equal
58 {
59     template <typename Value, typename = void>
60     struct equal_to
61     {
applycheck_equal::equal_to62         static inline void apply(Value const& x, Value const& y)
63         {
64             BOOST_CHECK(x == y);
65         }
66     };
67 
68     template <typename Dummy>
69     struct equal_to<double, Dummy>
70     {
applycheck_equal::equal_to71         static inline void apply(double x, double y)
72         {
73             BOOST_CHECK_CLOSE(x, y, 0.001);
74         }
75     };
76 
77     template <typename Geometry1, typename Geometry2>
applycheck_equal78     static inline void apply(std::string const& /*case_id*/,
79                              std::string const& /*subcase_id*/,
80                              Geometry1 const& /*geometry1*/,
81                              Geometry2 const& /*geometry2*/,
82                              T const& detected,
83                              T const& expected)
84     {
85         equal_to<T>::apply(expected, detected);
86         /*
87           TODO:
88           Ideally we would want the following, but it does not work well
89           approximate equality test.
90 
91         BOOST_CHECK_MESSAGE(equal_to<T>::apply(expected, detected),
92              "case ID: " << case_id << "-" << subcase_id << "; "
93              << "G1: " << bg::wkt(geometry1)
94              << " - "
95              << "G2: " << bg::wkt(geometry2)
96              << " -> Detected: " << detected
97              << "; Expected: " << expected);
98         */
99     }
100 };
101 
102 //========================================================================
103 
104 template
105 <
106     typename Geometry1, typename Geometry2,
107     int id1 = bg::geometry_id<Geometry1>::value,
108     int id2 = bg::geometry_id<Geometry2>::value
109 >
110 struct test_distance_of_geometries
111     : public test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
112 {};
113 
114 
115 template <typename Geometry1, typename Geometry2>
116 struct test_distance_of_geometries<Geometry1, Geometry2, 0, 0>
117 {
118     template
119     <
120         typename DistanceType,
121         typename ComparableDistanceType,
122         typename Strategy
123     >
124     static inline
applytest_distance_of_geometries125     void apply(std::string const& case_id,
126                std::string const& wkt1,
127                std::string const& wkt2,
128                DistanceType const& expected_distance,
129                ComparableDistanceType const& expected_comparable_distance,
130                Strategy const& strategy,
131                bool test_reversed = true)
132     {
133         Geometry1 geometry1 = from_wkt<Geometry1>(wkt1);
134         Geometry2 geometry2 = from_wkt<Geometry2>(wkt2);
135 
136         apply(case_id, geometry1, geometry2,
137               expected_distance, expected_comparable_distance,
138               strategy, test_reversed);
139     }
140 
141     template <typename DistanceType, typename Strategy>
142     static inline
applytest_distance_of_geometries143     void apply(std::string const& case_id,
144                std::string const& wkt1,
145                std::string const& wkt2,
146                DistanceType const& expected_distance,
147                Strategy const& strategy,
148                bool test_reversed = true)
149     {
150         Geometry1 geometry1 = from_wkt<Geometry1>(wkt1);
151         Geometry2 geometry2 = from_wkt<Geometry2>(wkt2);
152 
153         apply(case_id, geometry1, geometry2,
154               expected_distance, expected_distance,
155               strategy, test_reversed);
156     }
157 
158 
159     template
160     <
161         typename DistanceType,
162         typename ComparableDistanceType,
163         typename Strategy
164     >
165     static inline
applytest_distance_of_geometries166     void apply(std::string const& case_id,
167                Geometry1 const& geometry1,
168                Geometry2 const& geometry2,
169                DistanceType const& expected_distance,
170                ComparableDistanceType const& expected_comparable_distance,
171                Strategy const& strategy,
172                bool test_reversed = true)
173     {
174 #ifdef BOOST_GEOMETRY_TEST_DEBUG
175         std::cout << "case ID: " << case_id << "; "
176                   << "G1: " << bg::wkt(geometry1)
177                   << " - "
178                   << "G2: " << bg::wkt(geometry2)
179                   << std::endl;
180 #endif
181         namespace services = bg::strategy::distance::services;
182 
183         using bg::unit_test::distance_brute_force;
184 
185         typedef typename bg::default_distance_result
186             <
187                 Geometry1, Geometry2
188             >::type default_distance_result;
189 
190         typedef typename services::return_type
191             <
192                 Strategy, Geometry1, Geometry2
193             >::type distance_result_from_strategy;
194 
195         static const bool same_regular = boost::is_same
196             <
197                 default_distance_result,
198                 distance_result_from_strategy
199             >::type::value;
200 
201         BOOST_CHECK(same_regular);
202 
203         typedef typename bg::default_comparable_distance_result
204             <
205                 Geometry1, Geometry2
206             >::type default_comparable_distance_result;
207 
208         typedef typename services::return_type
209             <
210                 typename services::comparable_type<Strategy>::type,
211                 Geometry1,
212                 Geometry2
213             >::type comparable_distance_result_from_strategy;
214 
215         static const bool same_comparable = boost::is_same
216             <
217                 default_comparable_distance_result,
218                 comparable_distance_result_from_strategy
219             >::type::value;
220 
221         BOOST_CHECK( same_comparable );
222 
223         // check distance with passed strategy
224         distance_result_from_strategy dist =
225             bg::distance(geometry1, geometry2, strategy);
226 
227         check_equal
228             <
229                 distance_result_from_strategy
230             >::apply(case_id, "a", geometry1, geometry2,
231                      dist, expected_distance);
232 
233         // check against the comparable distance computed in a
234         // brute-force manner
235         default_distance_result dist_brute_force
236             = distance_brute_force(geometry1, geometry2, strategy);
237 
238         check_equal
239             <
240                 default_distance_result
241             >::apply(case_id, "b", geometry1, geometry2,
242                      dist_brute_force, expected_distance);
243 
244         // check comparable distance with passed strategy
245         comparable_distance_result_from_strategy cdist =
246             bg::comparable_distance(geometry1, geometry2, strategy);
247 
248         check_equal
249             <
250                 default_comparable_distance_result
251             >::apply(case_id, "c", geometry1, geometry2,
252                      cdist, expected_comparable_distance);
253 
254         // check against the comparable distance computed in a
255         // brute-force manner
256         default_comparable_distance_result cdist_brute_force
257             = distance_brute_force(geometry1,
258                                    geometry2,
259                                    services::get_comparable
260                                        <
261                                            Strategy
262                                        >::apply(strategy));
263 
264         check_equal
265             <
266                 default_comparable_distance_result
267             >::apply(case_id, "d", geometry1, geometry2,
268                      cdist_brute_force, expected_comparable_distance);
269 
270 #ifdef BOOST_GEOMETRY_TEST_DEBUG
271         std::cout << string_from_type<typename bg::coordinate_type<Geometry1>::type>::name()
272                   << string_from_type<typename bg::coordinate_type<Geometry2>::type>::name()
273                   << " -> "
274                   << string_from_type<default_distance_result>::name()
275                   << string_from_type<default_comparable_distance_result>::name()
276                   << std::endl;
277         std::cout << "strategy radius: " << strategy.radius() << std::endl;
278         std::cout << "expected distance = "
279                   << expected_distance << " ; "
280                   << "expected comp. distance = "
281                   << expected_comparable_distance
282                   << std::endl;
283         std::cout << "distance = "
284                   << dist << " ; "
285                   << "comp. distance = "
286                   << cdist
287                   << std::endl;
288 
289         if ( !test_reversed )
290         {
291             std::cout << std::endl;
292         }
293 #endif
294 
295         if ( test_reversed )
296         {
297             // check distance with given strategy
298             dist = bg::distance(geometry2, geometry1, strategy);
299 
300             check_equal
301                 <
302                     default_distance_result
303                 >::apply(case_id, "ra", geometry2, geometry1,
304                          dist, expected_distance);
305 
306             // check comparable distance with given strategy
307             cdist = bg::comparable_distance(geometry2, geometry1, strategy);
308 
309             check_equal
310                 <
311                     default_comparable_distance_result
312                 >::apply(case_id, "rc", geometry2, geometry1,
313                          cdist, expected_comparable_distance);
314 
315 #ifdef BOOST_GEOMETRY_TEST_DEBUG
316             std::cout << "distance[reversed args] = "
317                       << dist << " ; "
318                       << "comp. distance[reversed args] = "
319                       << cdist
320                       << std::endl;
321             std::cout << std::endl;
322 #endif
323         }
324     }
325 };
326 
327 
328 //========================================================================
329 
330 
331 template <typename Geometry1, typename Geometry2, typename Strategy>
test_empty_input(Geometry1 const & geometry1,Geometry2 const & geometry2,Strategy const & strategy)332 void test_empty_input(Geometry1 const& geometry1,
333                       Geometry2 const& geometry2,
334                       Strategy const& strategy)
335 {
336     try
337     {
338         bg::distance(geometry1, geometry2);
339     }
340     catch(bg::empty_input_exception const& )
341     {
342         return;
343     }
344     BOOST_CHECK_MESSAGE(false,
345                         "A empty_input_exception should have been thrown");
346 
347     try
348     {
349         bg::distance(geometry2, geometry1);
350     }
351     catch(bg::empty_input_exception const& )
352     {
353         return;
354     }
355     BOOST_CHECK_MESSAGE(false,
356                         "A empty_input_exception should have been thrown");
357 
358     try
359     {
360         bg::distance(geometry1, geometry2, strategy);
361     }
362     catch(bg::empty_input_exception const& )
363     {
364         return;
365     }
366     BOOST_CHECK_MESSAGE(false,
367                         "A empty_input_exception should have been thrown");
368 
369     try
370     {
371         bg::distance(geometry2, geometry1, strategy);
372     }
373     catch(bg::empty_input_exception const& )
374     {
375         return;
376     }
377     BOOST_CHECK_MESSAGE(false,
378                         "A empty_input_exception should have been thrown");
379 }
380 
381 #endif // BOOST_GEOMETRY_TEST_DISTANCE_SE_COMMON_HPP
382