1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3 
4 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
5 // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
6 // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
7 // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
8 
9 // This file was modified by Oracle on 2014, 2017.
10 // Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
11 
12 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
13 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
14 
15 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
16 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
17 
18 // Use, modification and distribution is subject to the Boost Software License,
19 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
20 // http://www.boost.org/LICENSE_1_0.txt)
21 
22 
23 #include <sstream>
24 
25 #include <boost/mpl/if.hpp>
26 #include <boost/type_traits/is_integral.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 #include <geometry_test_common.hpp>
29 
30 #include <boost/geometry/algorithms/comparable_distance.hpp>
31 #include <boost/geometry/algorithms/make.hpp>
32 
33 #include <boost/geometry/geometries/geometries.hpp>
34 #include <boost/geometry/geometries/point_xy.hpp>
35 #include <boost/geometry/io/wkt/read.hpp>
36 #include <boost/geometry/strategies/strategies.hpp>
37 
38 template <typename P>
test_distance_result()39 void test_distance_result()
40 {
41     typedef typename bg::default_distance_result<P, P>::type distance_type;
42 
43     P p1 = bg::make<P>(0, 0);
44     P p2 = bg::make<P>(3, 0);
45     P p3 = bg::make<P>(0, 4);
46 
47     distance_type dr12 = bg::comparable_distance(p1, p2);
48     distance_type dr13 = bg::comparable_distance(p1, p3);
49     distance_type dr23 = bg::comparable_distance(p2, p3);
50 
51     BOOST_CHECK_CLOSE(dr12, 9.000, 0.001);
52     BOOST_CHECK_CLOSE(dr13, 16.000, 0.001);
53     BOOST_CHECK_CLOSE(dr23, 25.000, 0.001);
54 
55 }
56 
57 template <typename P>
test_distance_point()58 void test_distance_point()
59 {
60     P p1;
61     bg::set<0>(p1, 1);
62     bg::set<1>(p1, 1);
63 
64     P p2;
65     bg::set<0>(p2, 2);
66     bg::set<1>(p2, 2);
67 
68     typename bg::coordinate_type<P>::type d = bg::comparable_distance(p1, p2);
69     BOOST_CHECK_CLOSE(d, 2.0, 0.001);
70 }
71 
72 template <typename P>
test_distance_segment()73 void test_distance_segment()
74 {
75     typedef typename bg::coordinate_type<P>::type coordinate_type;
76 
77     P s1 = bg::make<P>(2, 2);
78     P s2 = bg::make<P>(3, 3);
79 
80     // Check points left, right, projected-left, projected-right, on segment
81     P p1 = bg::make<P>(0, 0);
82     P p2 = bg::make<P>(4, 4);
83     P p3 = bg::make<P>(2.4, 2.6);
84     P p4 = bg::make<P>(2.6, 2.4);
85     P p5 = bg::make<P>(2.5, 2.5);
86 
87     bg::model::referring_segment<P const> const seg(s1, s2);
88 
89     coordinate_type d1 = bg::comparable_distance(p1, seg); BOOST_CHECK_CLOSE(d1, 8.0, 0.001);
90     coordinate_type d2 = bg::comparable_distance(p2, seg); BOOST_CHECK_CLOSE(d2, 2.0, 0.001);
91     coordinate_type d3 = bg::comparable_distance(p3, seg); BOOST_CHECK_CLOSE(d3, 0.02, 0.001);
92     coordinate_type d4 = bg::comparable_distance(p4, seg); BOOST_CHECK_CLOSE(d4, 0.02, 0.001);
93     coordinate_type d5 = bg::comparable_distance(p5, seg); BOOST_CHECK_CLOSE(d5, 0.0, 0.001);
94 
95     // Reverse case
96     coordinate_type dr1 = bg::comparable_distance(seg, p1); BOOST_CHECK_CLOSE(dr1, d1, 0.001);
97     coordinate_type dr2 = bg::comparable_distance(seg, p2); BOOST_CHECK_CLOSE(dr2, d2, 0.001);
98 }
99 
100 template <typename P>
test_distance_linestring()101 void test_distance_linestring()
102 {
103     bg::model::linestring<P> points;
104     points.push_back(bg::make<P>(1, 1));
105     points.push_back(bg::make<P>(3, 3));
106 
107     P p = bg::make<P>(2, 1);
108 
109     typename bg::coordinate_type<P>::type d = bg::comparable_distance(p, points);
110     BOOST_CHECK_CLOSE(d, 0.5, 0.001);
111 
112     p = bg::make<P>(5, 5);
113     d = bg::comparable_distance(p, points);
114     BOOST_CHECK_CLOSE(d, 8.0, 0.001);
115 
116 
117     bg::model::linestring<P> line;
118     line.push_back(bg::make<P>(1,1));
119     line.push_back(bg::make<P>(2,2));
120     line.push_back(bg::make<P>(3,3));
121 
122     p = bg::make<P>(5, 5);
123 
124     d = bg::comparable_distance(p, line);
125     BOOST_CHECK_CLOSE(d, 8.0, 0.001);
126 
127     // Reverse case
128     d = bg::comparable_distance(line, p);
129     BOOST_CHECK_CLOSE(d, 8.0, 0.001);
130 }
131 
132 template <typename P>
test_all()133 void test_all()
134 {
135     test_distance_result<P>();
136     test_distance_point<P>();
137     test_distance_segment<P>();
138     test_distance_linestring<P>();
139 }
140 
141 template <typename T>
test_double_result_from_integer()142 void test_double_result_from_integer()
143 {
144     typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
145 
146     point_type point;
147 
148     // Check linestring
149     bg::model::linestring<point_type> linestring;
150     bg::read_wkt("POINT(2 2)", point);
151     bg::read_wkt("LINESTRING(4 1,1 4)", linestring);
152 
153     double normal_distance = bg::distance(point, linestring);
154     double comparable_distance = bg::comparable_distance(point, linestring);
155 
156     BOOST_CHECK_CLOSE(normal_distance, std::sqrt(0.5), 0.001);
157     BOOST_CHECK_CLOSE(comparable_distance, 0.5, 0.001);
158 
159     // Check polygon
160     bg::model::polygon<point_type> polygon;
161     bg::read_wkt("POLYGON((0 0,1 9,8 1,0 0),(1 1,4 1,1 4,1 1))", polygon);
162 
163     normal_distance = bg::distance(point, polygon);
164     comparable_distance = bg::comparable_distance(point, polygon);
165 
166     BOOST_CHECK_CLOSE(normal_distance, std::sqrt(0.5), 0.001);
167     BOOST_CHECK_CLOSE(comparable_distance, 0.5, 0.001);
168 }
169 
170 template <typename T>
171 struct test_variant_different_default_strategy
172 {
applytest_variant_different_default_strategy173     static inline void apply()
174     {
175         typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
176         typedef bg::model::segment<point_type> segment_type;
177         typedef bg::model::box<point_type> box_type;
178         typedef boost::variant<point_type, segment_type, box_type> variant_type;
179 
180         point_type point;
181         bg::read_wkt("POINT(1 3)", point);
182 
183         segment_type seg;
184         bg::read_wkt("LINESTRING(1 1,4 4)", seg);
185 
186         box_type box;
187         bg::read_wkt("BOX(-1 -1,0 0)", box);
188 
189         variant_type v1, v2;
190 
191         BOOST_MPL_ASSERT((
192             boost::is_same
193                 <
194                     typename bg::comparable_distance_result
195                         <
196                             variant_type, variant_type, bg::default_strategy
197                         >::type,
198                     typename bg::comparable_distance_result
199                         <
200                             point_type, point_type, bg::default_strategy
201                         >::type
202                 >
203         ));
204 
205         // Default strategy
206         v1 = point;
207         v2 = point;
208         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2),
209                           bg::comparable_distance(point, point),
210                           0.0001);
211         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, point),
212                           bg::comparable_distance(point, point),
213                           0.0001);
214         BOOST_CHECK_CLOSE(bg::comparable_distance(point, v2),
215                           bg::comparable_distance(point, point),
216                           0.0001);
217         v1 = point;
218         v2 = seg;
219         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2),
220                           bg::comparable_distance(point, seg),
221                           0.0001);
222         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, seg),
223                           bg::comparable_distance(point, seg),
224                           0.0001);
225         BOOST_CHECK_CLOSE(bg::comparable_distance(point, v2),
226                           bg::comparable_distance(point, seg), 0.0001);
227         v1 = point;
228         v2 = box;
229         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2),
230                           bg::comparable_distance(point, box),
231                           0.0001);
232         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, box),
233                           bg::comparable_distance(point, box),
234                           0.0001);
235         BOOST_CHECK_CLOSE(bg::comparable_distance(point, v2),
236                           bg::comparable_distance(point, box), 0.0001);
237     }
238 };
239 
240 template <typename T, typename ExpectedResultType = double>
241 struct test_variant_same_default_strategy
242 {
applytest_variant_same_default_strategy243     static inline void apply()
244     {
245         typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
246         typedef bg::model::segment<point_type> segment_type;
247         typedef bg::model::linestring<point_type> linestring_type;
248         typedef boost::variant
249             <
250                 point_type, segment_type, linestring_type
251             > variant_type;
252 
253         point_type point;
254         bg::read_wkt("POINT(1 3)", point);
255 
256         segment_type seg;
257         bg::read_wkt("LINESTRING(1 1,4 4)", seg);
258 
259         linestring_type linestring;
260         bg::read_wkt("LINESTRING(-1 -1,-1 0,0 0,0 -1,-1 -1)", linestring);
261 
262         variant_type v1, v2;
263 
264         BOOST_MPL_ASSERT((
265             boost::is_same
266                 <
267                     typename bg::comparable_distance_result
268                         <
269                             variant_type, variant_type, bg::default_strategy
270                         >::type,
271                     ExpectedResultType
272                 >
273         ));
274 
275         BOOST_MPL_ASSERT((
276             boost::is_same
277                 <
278                     typename bg::comparable_distance_result
279                         <
280                             point_type, point_type, bg::default_strategy
281                         >::type,
282                     ExpectedResultType
283                 >
284         ));
285 
286         // Default strategy
287         v1 = point;
288         v2 = point;
289         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2),
290                           bg::comparable_distance(point, point),
291                           0.0001);
292         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, point),
293                           bg::comparable_distance(point, point),
294                           0.0001);
295         BOOST_CHECK_CLOSE(bg::comparable_distance(point, v2),
296                           bg::comparable_distance(point, point),
297                           0.0001);
298         v1 = point;
299         v2 = seg;
300         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2),
301                           bg::comparable_distance(point, seg),
302                           0.0001);
303         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, seg),
304                           bg::comparable_distance(point, seg),
305                           0.0001);
306         BOOST_CHECK_CLOSE(bg::comparable_distance(point, v2),
307                           bg::comparable_distance(point, seg),
308                           0.0001);
309         v1 = point;
310         v2 = linestring;
311         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2),
312                           bg::comparable_distance(point, linestring),
313                           0.0001);
314         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, linestring),
315                           bg::comparable_distance(point, linestring),
316                           0.0001);
317         BOOST_CHECK_CLOSE(bg::comparable_distance(point, v2),
318                           bg::comparable_distance(point, linestring),
319                           0.0001);
320     }
321 };
322 
323 template <typename T, typename ExpectedResultType = T>
324 struct test_variant_with_strategy
325 {
applytest_variant_with_strategy326     static inline void apply()
327     {
328         typedef bg::strategy::distance::projected_point<T> strategy_type;
329 
330         typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
331         typedef bg::model::segment<point_type> segment_type;
332         typedef bg::model::linestring<point_type> linestring_type;
333         typedef bg::model::multi_linestring
334             <
335                 linestring_type
336             > multi_linestring_type;
337         typedef boost::variant
338             <
339                 segment_type, linestring_type, multi_linestring_type
340             > variant_type;
341 
342         segment_type seg;
343         bg::read_wkt("LINESTRING(1 1,4 4)", seg);
344 
345         linestring_type ls;
346         bg::read_wkt("LINESTRING(-1 -1,-1 0,0 0,0 -1,-1 -1)", ls);
347 
348         multi_linestring_type mls;
349         bg::read_wkt("MULTILINESTRING((10 0,20 0),(30 0,40 0))", mls);
350 
351         variant_type v1, v2;
352 
353         strategy_type strategy;
354 
355         BOOST_MPL_ASSERT((
356             boost::is_same
357                 <
358                     typename bg::comparable_distance_result
359                         <
360                             variant_type, variant_type, strategy_type
361                         >::type,
362                     ExpectedResultType
363                 >
364         ));
365 
366         BOOST_MPL_ASSERT((
367             boost::is_same
368                 <
369                     typename bg::comparable_distance_result
370                         <
371                             segment_type, linestring_type, strategy_type
372                         >::type,
373                     ExpectedResultType
374                 >
375         ));
376 
377         // Passed strategy
378         v1 = seg;
379         v2 = seg;
380         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2, strategy),
381                           bg::comparable_distance(seg, seg, strategy),
382                           0.0001);
383         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, seg, strategy),
384                           bg::comparable_distance(seg, seg, strategy),
385                           0.0001);
386         BOOST_CHECK_CLOSE(bg::comparable_distance(seg, v2, strategy),
387                           bg::comparable_distance(seg, seg, strategy),
388                           0.0001);
389         v1 = seg;
390         v2 = ls;
391         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2, strategy),
392                           bg::comparable_distance(seg, ls, strategy),
393                           0.0001);
394         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, ls, strategy),
395                           bg::comparable_distance(seg, ls, strategy),
396                           0.0001);
397         BOOST_CHECK_CLOSE(bg::comparable_distance(seg, v2, strategy),
398                           bg::comparable_distance(seg, ls, strategy),
399                           0.0001);
400         v1 = seg;
401         v2 = mls;
402         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2, strategy),
403                           bg::comparable_distance(seg, mls, strategy),
404                           0.0001);
405         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, mls, strategy),
406                           bg::comparable_distance(seg, mls, strategy),
407                           0.0001);
408         BOOST_CHECK_CLOSE(bg::comparable_distance(seg, v2, strategy),
409                           bg::comparable_distance(seg, mls, strategy),
410                           0.0001);
411         v1 = ls;
412         v2 = mls;
413         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, v2, strategy),
414                           bg::comparable_distance(ls, mls, strategy),
415                           0.0001);
416         BOOST_CHECK_CLOSE(bg::comparable_distance(v1, mls, strategy),
417                           bg::comparable_distance(ls, mls, strategy),
418                           0.0001);
419         BOOST_CHECK_CLOSE(bg::comparable_distance(ls, v2, strategy),
420                           bg::comparable_distance(ls, mls, strategy),
421                           0.0001);
422     }
423 };
424 
425 template <typename T, bool IsIntergral = boost::is_integral<T>::value>
426 struct check_result
427 {
428     template <typename ExpectedResult>
applycheck_result429     static inline void apply(T const& value,
430                              ExpectedResult const& expected_value)
431     {
432         BOOST_CHECK_EQUAL(value, expected_value);
433     }
434 };
435 
436 template <typename T>
437 struct check_result<T, false>
438 {
439     template <typename ExpectedResult>
applycheck_result440     static inline void apply(T const& value,
441                              ExpectedResult const& expected_value)
442     {
443         BOOST_CHECK_CLOSE(value, expected_value, 0.0001);
444     }
445 };
446 
447 template <typename T>
448 struct test_variant_boxes
449 {
applytest_variant_boxes450     static inline void apply()
451     {
452         typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
453         typedef bg::model::box<point_type> box_type;
454         typedef boost::variant<box_type> variant_type;
455 
456         box_type box1, box2;
457         bg::read_wkt("BOX(-1 -1,0 0)", box1);
458         bg::read_wkt("BOX(1 1,2 2)", box2);
459 
460         variant_type v1 = box1, v2 = box2;
461 
462         typedef typename boost::mpl::if_c
463             <
464                 boost::is_float<T>::value,
465                 double,
466                 typename bg::util::detail::default_integral::type
467             >::type expected_result_type;
468 
469         BOOST_MPL_ASSERT((
470             boost::is_same
471                 <
472                     typename bg::comparable_distance_result
473                         <
474                             variant_type, variant_type, bg::default_strategy
475                         >::type,
476                     expected_result_type
477                 >
478         ));
479 
480         // Default strategy
481         check_result<T>::apply(bg::comparable_distance(v1, v2),
482                                bg::comparable_distance(box1, box2));
483         check_result<T>::apply(bg::comparable_distance(v1, box2),
484                                bg::comparable_distance(box1, box2));
485         check_result<T>::apply(bg::comparable_distance(box1, v2),
486                                bg::comparable_distance(box1, box2));
487     }
488 };
489 
490 
test_main(int,char * [])491 int test_main(int, char* [])
492 {
493     test_double_result_from_integer<int>();
494     test_double_result_from_integer<boost::long_long_type>();
495 
496     test_all<bg::model::d2::point_xy<float> >();
497     test_all<bg::model::d2::point_xy<double> >();
498 
499     // test variant support
500     test_variant_different_default_strategy<double>::apply();
501 
502     test_variant_same_default_strategy<double>::apply();
503     test_variant_same_default_strategy<int>::apply();
504     test_variant_same_default_strategy<long>::apply();
505 
506     test_variant_with_strategy<double>::apply();
507     test_variant_with_strategy<float>::apply();
508     test_variant_with_strategy<long double>::apply();
509     test_variant_with_strategy<int, double>::apply();
510 
511     test_variant_boxes<double>::apply();
512     test_variant_boxes<int>::apply();
513     test_variant_boxes<long>::apply();
514 
515     return 0;
516 }
517