]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | // Unit Test | |
3 | ||
4 | // Copyright (c) 2015, Oracle and/or its affiliates. | |
5 | ||
6 | // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle | |
7 | ||
8 | // Licensed under the Boost Software License version 1.0. | |
9 | // http://www.boost.org/users/license.html | |
10 | ||
11 | #include <iostream> | |
12 | ||
13 | #ifndef BOOST_TEST_MODULE | |
14 | #define BOOST_TEST_MODULE test_distance_spherical_equatorial_point_box | |
15 | #endif | |
16 | ||
17 | #include <boost/range.hpp> | |
18 | #include <boost/type_traits/is_same.hpp> | |
19 | ||
20 | #include <boost/test/included/unit_test.hpp> | |
21 | #include <boost/geometry/util/condition.hpp> | |
22 | #include <boost/geometry/strategies/strategies.hpp> | |
23 | ||
24 | #include "test_distance_se_common.hpp" | |
25 | ||
26 | ||
27 | typedef bg::cs::spherical_equatorial<bg::degree> cs_type; | |
28 | typedef bg::model::point<double, 2, cs_type> point_type; | |
11fdf7f2 | 29 | typedef bg::model::multi_point<point_type> multi_point_type; |
7c673cae FG |
30 | typedef bg::model::segment<point_type> segment_type; |
31 | typedef bg::model::box<point_type> box_type; | |
32 | ||
33 | namespace distance = bg::strategy::distance; | |
34 | namespace services = distance::services; | |
35 | typedef bg::default_distance_result<point_type, point_type>::type return_type; | |
36 | ||
37 | typedef distance::cross_track_point_box<> point_box_strategy; | |
38 | typedef distance::cross_track_point_box | |
39 | < | |
40 | void, distance::comparable::cross_track<> | |
41 | > comparable_point_box_strategy; | |
42 | ||
43 | //=========================================================================== | |
44 | ||
45 | inline bg::distance_result | |
46 | < | |
47 | point_type, point_type, distance::haversine<double> | |
48 | >::type | |
49 | distance_pp(std::string const& wkt1, | |
50 | std::string const& wkt2, | |
51 | double radius) | |
52 | { | |
53 | point_type p1, p2; | |
54 | bg::read_wkt(wkt1, p1); | |
55 | bg::read_wkt(wkt2, p2); | |
56 | ||
57 | distance::haversine<double> strategy(radius); | |
58 | return bg::distance(p1, p2, strategy); | |
59 | } | |
60 | ||
61 | inline bg::default_comparable_distance_result<point_type>::type | |
62 | comparable_distance_pp(std::string const& wkt1, | |
63 | std::string const& wkt2) | |
64 | { | |
65 | point_type p1, p2; | |
66 | bg::read_wkt(wkt1, p1); | |
67 | bg::read_wkt(wkt2, p2); | |
68 | return bg::comparable_distance(p1, p2); | |
69 | } | |
70 | ||
71 | inline bg::distance_result | |
72 | < | |
73 | point_type, point_type, distance::cross_track<> | |
74 | >::type | |
75 | distance_ps(std::string const& wkt_point, | |
76 | std::string const& wkt_segment, | |
77 | double radius) | |
78 | { | |
79 | point_type point; | |
80 | segment_type segment; | |
81 | bg::read_wkt(wkt_point, point); | |
82 | bg::read_wkt(wkt_segment, segment); | |
83 | ||
84 | distance::cross_track<> strategy(radius); | |
85 | return bg::distance(point, segment, strategy); | |
86 | } | |
87 | ||
88 | inline bg::default_comparable_distance_result<point_type>::type | |
89 | comparable_distance_ps(std::string const& wkt_point, | |
90 | std::string const& wkt_segment) | |
91 | { | |
92 | point_type point; | |
93 | segment_type segment; | |
94 | bg::read_wkt(wkt_point, point); | |
95 | bg::read_wkt(wkt_segment, segment); | |
96 | return bg::comparable_distance(point, segment); | |
97 | } | |
98 | ||
99 | enum features_type { pp, ps }; | |
100 | ||
101 | template <typename Geometry1, typename Geometry2> | |
102 | struct test_distances | |
103 | { | |
104 | template <typename Strategy> | |
105 | static inline void apply(std::string const& case_id, | |
106 | std::string const& wkt1, | |
107 | std::string const& wkt2, | |
108 | double expected_distance, | |
109 | double expected_comparable_distance, | |
110 | Strategy const& strategy) | |
111 | { | |
112 | typedef test_distance_of_geometries<Geometry1, Geometry2> tester; | |
113 | ||
114 | bool const is_comparable = boost::is_same | |
115 | < | |
116 | Strategy, | |
117 | typename services::comparable_type<Strategy>::type | |
118 | >::value; | |
119 | ||
120 | if (BOOST_GEOMETRY_CONDITION(is_comparable)) | |
121 | { | |
122 | tester::apply(case_id, wkt1, wkt2, | |
123 | expected_comparable_distance, | |
124 | expected_comparable_distance, | |
125 | strategy); | |
126 | } | |
127 | else | |
128 | { | |
129 | tester::apply(case_id, wkt1, wkt2, | |
130 | expected_distance, | |
131 | expected_comparable_distance, | |
132 | strategy); | |
133 | } | |
134 | } | |
135 | ||
136 | template <typename Strategy> | |
137 | static inline void apply(std::string const& case_id, | |
138 | std::string const& wkt1, | |
139 | std::string const& wkt2, | |
140 | std::string const& feature1, | |
141 | std::string const& feature2, | |
142 | features_type ftype, | |
143 | Strategy const& strategy) | |
144 | { | |
145 | double const radius = strategy.radius(); | |
146 | double expected_distance, expected_comparable_distance; | |
147 | ||
148 | if (ftype == pp) | |
149 | { | |
150 | expected_distance = distance_pp(feature1, feature2, radius); | |
151 | expected_comparable_distance | |
152 | = comparable_distance_pp(feature1, feature2); | |
153 | } | |
154 | else | |
155 | { | |
156 | expected_distance = distance_ps(feature1, feature2, radius); | |
157 | expected_comparable_distance | |
158 | = comparable_distance_ps(feature1, feature2); | |
159 | } | |
160 | ||
161 | apply(case_id, wkt1, wkt2, | |
162 | expected_distance, expected_comparable_distance, | |
163 | strategy); | |
164 | } | |
165 | }; | |
166 | ||
167 | template <typename T, typename U> | |
168 | T to_comparable(T const& value, U const& radius) | |
169 | { | |
170 | T x = sin(value / (radius * 2.0)); | |
171 | return x * x; | |
172 | } | |
173 | ||
174 | //=========================================================================== | |
175 | ||
176 | template <typename Strategy> | |
177 | void test_distance_point_box(Strategy const& strategy) | |
178 | { | |
179 | #ifdef BOOST_GEOMETRY_TEST_DEBUG | |
180 | std::cout << std::endl; | |
181 | std::cout << "point/box distance tests" << std::endl; | |
182 | #endif | |
183 | typedef test_distances<point_type, box_type> tester; | |
184 | ||
185 | double const radius = strategy.radius(); | |
186 | double const d2r = bg::math::d2r<double>(); | |
187 | ||
188 | // Cases for relative location of a point wrt to a box | |
189 | // | |
190 | // | | | |
191 | // | 3 | | |
192 | // | | | |
193 | // +---------+ | |
194 | // | | | |
195 | // 1 | 5 | 2 | |
196 | // | | | |
197 | // +---------+ | |
198 | // | | | |
199 | // | 4 | | |
200 | // | | | |
201 | // | |
202 | // and also the following cases | |
203 | // | |
204 | // | | | |
205 | // A B | |
206 | // | | | |
207 | // +----C----+ | |
208 | // | | | |
209 | // D E | |
210 | // | | | |
211 | // +----F----+ | |
212 | // | | | |
213 | // G H | |
214 | // | | | |
215 | // | |
216 | // and finally we have the corners | |
217 | // | |
218 | // | | | |
219 | // | | | |
220 | // | | | |
221 | // a---------b | |
222 | // | | | |
223 | // | | | |
224 | // | | | |
225 | // c---------d | |
226 | // | | | |
227 | // | | | |
228 | // | | | |
229 | // | |
230 | // for each relative position we also have to test the shifted point | |
231 | // (this is due to the fact that boxes have longitudes in the | |
232 | // range [-180, 540) | |
233 | ||
234 | std::string const box1 = "BOX(10 10,20 20)"; | |
235 | ||
236 | // case 1 | |
237 | tester::apply("pb1-1a", "POINT(5 25)", box1, | |
238 | "POINT(5 25)", "POINT(10 20)", pp, | |
239 | strategy); | |
240 | ||
241 | // case 1 | |
242 | tester::apply("pb1-1b", "POINT(3 12)", box1, | |
243 | "POINT(3 12)", "SEGMENT(10 10,10 20)", ps, | |
244 | strategy); | |
245 | ||
246 | // case 1 | |
247 | tester::apply("pb1-1c", "POINT(3 17)", box1, | |
248 | "POINT(3 17)", "SEGMENT(10 10,10 20)", ps, | |
249 | strategy); | |
250 | ||
251 | // case 1 | |
252 | tester::apply("pb1-1d", "POINT(5 4)", box1, | |
253 | "POINT(5 4)", "POINT(10 10)", pp, | |
254 | strategy); | |
255 | ||
256 | // case 1 | |
257 | tester::apply("pb1-1e", "POINT(-100 20)", box1, | |
258 | "POINT(-100 20)", "POINT(10 20)", pp, | |
259 | strategy); | |
260 | ||
261 | // case 1 | |
262 | tester::apply("pb1-1g", "POINT(-100 10)", box1, | |
263 | "POINT(-100 10)", "SEGMENT(10 10,10 20)", ps, | |
264 | strategy); | |
265 | ||
266 | // case 2 | |
267 | tester::apply("pb1-2a", "POINT(31 25)", box1, | |
268 | "POINT(31 25)", "POINT(20 20)", pp, | |
269 | strategy); | |
270 | ||
271 | // case 2 | |
272 | tester::apply("pb1-2b", "POINT(23 17)", box1, | |
273 | "POINT(23 17)", "SEGMENT(20 10,20 20)", ps, | |
274 | strategy); | |
275 | ||
276 | // case 2 | |
277 | tester::apply("pb1-2c", "POINT(29 3)", box1, | |
278 | "POINT(29 3)", "POINT(20 10)", pp, | |
279 | strategy); | |
280 | ||
281 | // case 2 | |
282 | tester::apply("pb1-2d", "POINT(131 65)", box1, | |
283 | "POINT(131 65)", "POINT(20 20)", pp, | |
284 | strategy); | |
285 | ||
286 | // case 2 | |
287 | tester::apply("pb1-2e", "POINT(110 10)", box1, | |
288 | "POINT(110 10)", "SEGMENT(20 10,20 20)", ps, | |
289 | strategy); | |
290 | ||
291 | // case 2 | |
292 | tester::apply("pb1-2f", "POINT(150 20)", box1, | |
293 | "POINT(150 20)", "POINT(20 20)", pp, | |
294 | strategy); | |
295 | ||
296 | // case 3 | |
297 | tester::apply("pb1-3a", "POINT(11 25)", box1, | |
298 | 5.0 * d2r * radius, | |
299 | to_comparable(5.0 * d2r * radius, radius), | |
300 | strategy); | |
301 | ||
302 | // case 3 | |
303 | tester::apply("pb1-3b", "POINT(15 25)", box1, | |
304 | 5.0 * d2r * radius, | |
305 | to_comparable(5.0 * d2r * radius, radius), | |
306 | strategy); | |
307 | ||
308 | // case 3 | |
309 | tester::apply("pb1-3c", "POINT(18 25)", box1, | |
310 | 5.0 * d2r * radius, | |
311 | to_comparable(5.0 * d2r * radius, radius), | |
312 | strategy); | |
313 | ||
314 | // case 4 | |
315 | tester::apply("pb1-4a", "POINT(13 4)", box1, | |
316 | 6.0 * radius * d2r, | |
317 | to_comparable(6.0 * radius * d2r, radius), | |
318 | strategy); | |
319 | ||
320 | // case 4 | |
321 | tester::apply("pb1-4b", "POINT(19 4)", box1, | |
322 | 6.0 * radius * d2r, | |
323 | to_comparable(6.0 * radius * d2r, radius), | |
324 | strategy); | |
325 | ||
326 | // case 5 | |
327 | tester::apply("pb1-5", "POINT(15 14)", box1, 0, 0, strategy); | |
328 | ||
329 | // case A | |
330 | tester::apply("pb1-A", "POINT(10 28)", box1, | |
331 | 8.0 * d2r * radius, | |
332 | to_comparable(8.0 * d2r * radius, radius), | |
333 | strategy); | |
334 | ||
335 | // case B | |
336 | tester::apply("pb1-B", "POINT(20 28)", box1, | |
337 | 8.0 * d2r * radius, | |
338 | to_comparable(8.0 * d2r * radius, radius), | |
339 | strategy); | |
340 | ||
341 | // case C | |
342 | tester::apply("pb1-C", "POINT(14 20)", box1, 0, 0, strategy); | |
343 | ||
344 | // case D | |
345 | tester::apply("pb1-D", "POINT(10 17)", box1, 0, 0, strategy); | |
346 | ||
347 | // case E | |
348 | tester::apply("pb1-E", "POINT(20 11)", box1, 0, 0, strategy); | |
349 | ||
350 | // case F | |
351 | tester::apply("pb1-F", "POINT(19 10)", box1, 0, 0, strategy); | |
352 | ||
353 | // case G | |
354 | tester::apply("pb1-G", "POINT(10 -40)", box1, | |
355 | 50.0 * d2r * radius, | |
356 | to_comparable(50.0 * d2r * radius, radius), | |
357 | strategy); | |
358 | ||
359 | // case H | |
360 | tester::apply("pb1-H", | |
361 | "POINT(20 -50)", box1, | |
362 | 60.0 * d2r * radius, | |
363 | to_comparable(60.0 * d2r * radius, radius), | |
364 | strategy); | |
365 | ||
366 | // case a | |
367 | tester::apply("pb1-a", "POINT(10 20)", box1, 0, 0, strategy); | |
368 | // case b | |
369 | tester::apply("pb1-b", "POINT(20 20)", box1, 0, 0, strategy); | |
370 | // case c | |
371 | tester::apply("pb1-c", "POINT(10 10)", box1, 0, 0, strategy); | |
372 | // case d | |
373 | tester::apply("pb1-d", "POINT(20 10)", box1, 0, 0, strategy); | |
374 | ||
375 | ||
376 | ||
377 | std::string const box2 = "BOX(170 -60,400 80)"; | |
378 | ||
379 | // case 1 - point is closer to western meridian | |
380 | tester::apply("pb2-1a", "POINT(160 0)", box2, | |
381 | "POINT(160 0)", "SEGMENT(170 -60,170 80)", ps, | |
382 | strategy); | |
383 | ||
384 | // case 1 - point is closer to eastern meridian | |
385 | tester::apply("pb2-1b", "POINT(50 0)", box2, | |
386 | "POINT(50 0)", "SEGMENT(40 -60,40 80)", ps, | |
387 | strategy); | |
388 | ||
389 | // case 3 - equivalent point POINT(390 85) is above the box | |
390 | tester::apply("pb2-3", "POINT(30 85)", box2, | |
391 | 5.0 * d2r * radius, | |
392 | to_comparable(5.0 * d2r * radius, radius), | |
393 | strategy); | |
394 | ||
395 | // case 4 - equivalent point POINT(390 -75) is below the box | |
396 | tester::apply("pb2-4", "POINT(30 -75)", box2, | |
397 | 15.0 * d2r * radius, | |
398 | to_comparable(15.0 * d2r * radius, radius), | |
399 | strategy); | |
400 | ||
401 | // case 5 - equivalent point POINT(390 0) is inside box | |
402 | tester::apply("pb2-5", "POINT(30 0)", box2, 0, 0, strategy); | |
403 | ||
404 | ||
405 | std::string const box3 = "BOX(-150 -50,-40 70)"; | |
406 | ||
407 | // case 1 - point is closer to western meridian | |
408 | tester::apply("pb3-1a", "POINT(-170 10)", box3, | |
409 | "POINT(-170 10)", "SEGMENT(-150 -50,-150 70)", ps, | |
410 | strategy); | |
411 | ||
412 | // case 2 - point is closer to eastern meridian | |
413 | tester::apply("pb3-2a", "POINT(5 10)", box3, | |
414 | "POINT(5 10)", "SEGMENT(-40 -50,-40 70)", ps, | |
415 | strategy); | |
416 | ||
417 | // case 2 - point is closer to western meridian | |
418 | tester::apply("pb3-2a", "POINT(160 10)", box3, | |
419 | "POINT(160 10)", "SEGMENT(-150 -50,-150 70)", ps, | |
420 | strategy); | |
421 | ||
422 | // case 2 - point is at equal distance from eastern and western meridian | |
423 | tester::apply("pb3-2c1", "POINT(85 20)", box3, | |
424 | "POINT(85 20)", "SEGMENT(-150 -50,-150 70)", ps, | |
425 | strategy); | |
426 | ||
427 | // case 2 - point is at equal distance from eastern and western meridian | |
428 | tester::apply("pb3-2c2", "POINT(85 20)", box3, | |
429 | "POINT(85 20)", "SEGMENT(-40 -50,-40 70)", ps, | |
430 | strategy); | |
431 | ||
432 | // box that is symmetric wrt the prime meridian | |
433 | std::string const box4 = "BOX(-75 -45,75 65)"; | |
434 | ||
435 | // case 1 - point is closer to western meridian | |
436 | tester::apply("pb4-1a", "POINT(-100 10)", box4, | |
437 | "POINT(-100 10)", "SEGMENT(-75 -45,-75 65)", ps, | |
438 | strategy); | |
439 | ||
440 | // case 2 - point is closer to eastern meridian | |
441 | tester::apply("pb4-2a", "POINT(90 15)", box4, | |
442 | "POINT(90 15)", "SEGMENT(75 -45,75 65)", ps, | |
443 | strategy); | |
444 | ||
445 | // case 2 - point is at equal distance from eastern and western meridian | |
446 | tester::apply("pb4-2c1", "POINT(-180 20)", box4, | |
447 | "POINT(-180 20)", "SEGMENT(-75 -45,-75 65)", ps, | |
448 | strategy); | |
449 | ||
450 | // case 2 - point is at equal distance from eastern and western meridian | |
451 | tester::apply("pb4-2c2", "POINT(-180 20)", box4, | |
452 | "POINT(-180 20)", "SEGMENT(75 -45,75 65)", ps, | |
453 | strategy); | |
11fdf7f2 TL |
454 | |
455 | } | |
456 | ||
457 | template <typename Strategy> | |
458 | void test_distance_multipoint_box(Strategy const& strategy) | |
459 | { | |
460 | ||
461 | #ifdef BOOST_GEOMETRY_TEST_DEBUG | |
462 | std::cout << std::endl; | |
463 | std::cout << "multipoint/box distance tests" << std::endl; | |
464 | #endif | |
465 | typedef test_distances<multi_point_type, box_type> tester; | |
466 | ||
467 | std::string const box1 = "BOX(10 10,20 20)"; | |
468 | ||
469 | tester::apply("mpb1-1a", "MULTIPOINT(5 25,25 26)", box1, | |
470 | "POINT(5 25)", "POINT(10 20)", pp, | |
471 | strategy); | |
472 | ||
473 | tester::apply("mpb1-2e", "MULTIPOINT(110 10,110 9,110 0)", box1, | |
474 | "POINT(110 10)", "SEGMENT(20 10,20 20)", ps, | |
475 | strategy); | |
7c673cae FG |
476 | } |
477 | ||
478 | BOOST_AUTO_TEST_CASE( test_point_box ) | |
479 | { | |
480 | test_distance_point_box(point_box_strategy()); | |
481 | test_distance_point_box(point_box_strategy(earth_radius_km)); | |
482 | test_distance_point_box(point_box_strategy(earth_radius_miles)); | |
483 | ||
484 | test_distance_point_box(comparable_point_box_strategy()); | |
485 | test_distance_point_box(comparable_point_box_strategy(earth_radius_km)); | |
486 | test_distance_point_box(comparable_point_box_strategy(earth_radius_miles)); | |
11fdf7f2 TL |
487 | |
488 | test_distance_multipoint_box(point_box_strategy()); | |
489 | test_distance_multipoint_box(point_box_strategy(earth_radius_km)); | |
490 | test_distance_multipoint_box(point_box_strategy(earth_radius_miles)); | |
7c673cae | 491 | } |