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