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