]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / geometry / strategies / spherical / distance_cross_track_box_box.hpp
CommitLineData
11fdf7f2
TL
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
20effc67 3// Copyright (c) 2016-2020 Oracle and/or its affiliates.
11fdf7f2
TL
4// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
5// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
6
7// Use, modification and distribution is subject to the Boost Software License,
8// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10
11#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_BOX_BOX_HPP
12#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_BOX_BOX_HPP
13
20effc67
TL
14
15#include <type_traits>
16
11fdf7f2
TL
17#include <boost/config.hpp>
18#include <boost/concept_check.hpp>
11fdf7f2
TL
19
20#include <boost/geometry/core/access.hpp>
21#include <boost/geometry/core/assert.hpp>
22#include <boost/geometry/core/point_type.hpp>
23#include <boost/geometry/core/radian_access.hpp>
24#include <boost/geometry/core/tags.hpp>
25
26#include <boost/geometry/strategies/distance.hpp>
27#include <boost/geometry/strategies/concepts/distance_concept.hpp>
28#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
29
30#include <boost/geometry/util/math.hpp>
31#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
32
33
34namespace boost { namespace geometry
35{
36
37namespace strategy { namespace distance
38{
39
40namespace details
41{
42
43template <typename ReturnType>
44class cross_track_box_box_generic
45{
46public :
47
92f5a8d4 48 template <typename Point, typename PPStrategy, typename PSStrategy>
11fdf7f2
TL
49 ReturnType static inline diagonal_case(Point topA,
50 Point topB,
51 Point bottomA,
52 Point bottomB,
53 bool north_shortest,
54 bool non_overlap,
92f5a8d4
TL
55 PPStrategy pp_strategy,
56 PSStrategy ps_strategy)
11fdf7f2
TL
57 {
58 if (north_shortest && non_overlap)
59 {
92f5a8d4 60 return pp_strategy.apply(topA, bottomB);
11fdf7f2
TL
61 }
62 if (north_shortest && !non_overlap)
63 {
64 return ps_strategy.apply(topA, topB, bottomB);
65 }
66 if (!north_shortest && non_overlap)
67 {
92f5a8d4 68 return pp_strategy.apply(bottomA, topB);
11fdf7f2
TL
69 }
70 return ps_strategy.apply(bottomA, topB, bottomB);
71 }
72
73
74 template
75 <
76 typename Box1,
77 typename Box2,
92f5a8d4
TL
78 typename PPStrategy,
79 typename PSStrategy
11fdf7f2
TL
80 >
81 ReturnType static inline apply (Box1 const& box1,
82 Box2 const& box2,
92f5a8d4
TL
83 PPStrategy pp_strategy,
84 PSStrategy ps_strategy)
11fdf7f2
TL
85 {
86
87 // this method assumes that the coordinates of the point and
88 // the box are normalized
89
90 typedef typename point_type<Box1>::type box_point_type1;
91 typedef typename point_type<Box2>::type box_point_type2;
92
93 box_point_type1 bottom_left1, bottom_right1, top_left1, top_right1;
94 geometry::detail::assign_box_corners(box1,
95 bottom_left1, bottom_right1,
96 top_left1, top_right1);
97
98 box_point_type2 bottom_left2, bottom_right2, top_left2, top_right2;
99 geometry::detail::assign_box_corners(box2,
100 bottom_left2, bottom_right2,
101 top_left2, top_right2);
102
103 ReturnType lon_min1 = geometry::get_as_radian<0>(bottom_left1);
104 ReturnType const lat_min1 = geometry::get_as_radian<1>(bottom_left1);
105 ReturnType lon_max1 = geometry::get_as_radian<0>(top_right1);
106 ReturnType const lat_max1 = geometry::get_as_radian<1>(top_right1);
107
108 ReturnType lon_min2 = geometry::get_as_radian<0>(bottom_left2);
109 ReturnType const lat_min2 = geometry::get_as_radian<1>(bottom_left2);
110 ReturnType lon_max2 = geometry::get_as_radian<0>(top_right2);
111 ReturnType const lat_max2 = geometry::get_as_radian<1>(top_right2);
112
113 ReturnType const two_pi = math::two_pi<ReturnType>();
114
115 // Test which sides of the boxes are closer and if boxes cross
116 // antimeridian
117 bool right_wrap;
118
119 if (lon_min2 > 0 && lon_max2 < 0) // box2 crosses antimeridian
120 {
121#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
122 std::cout << "(box2 crosses antimeridian)";
123#endif
124 right_wrap = lon_min2 - lon_max1 < lon_min1 - lon_max2;
125 lon_max2 += two_pi;
126 if (lon_min1 > 0 && lon_max1 < 0) // both boxes crosses antimeridian
127 {
128 lon_max1 += two_pi;
129 }
130 }
131 else if (lon_min1 > 0 && lon_max1 < 0) // only box1 crosses antimeridian
132 {
133#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
134 std::cout << "(box1 crosses antimeridian)";
135#endif
92f5a8d4 136 return apply(box2, box1, pp_strategy, ps_strategy);
11fdf7f2
TL
137 }
138 else
139 {
140 right_wrap = lon_max1 <= lon_min2
141 ? lon_min2 - lon_max1 < two_pi - (lon_max2 - lon_min1)
142 : lon_min1 - lon_max2 > two_pi - (lon_max1 - lon_min2);
143
144 }
145
146 // Check1: if box2 crosses the band defined by the
147 // minimum and maximum longitude of box1; if yes, determine
148 // if the box2 is above, below or intersects/is inside box1 and compute
149 // the distance (easy in this case)
150
151 bool lon_min12 = lon_min1 <= lon_min2;
152 bool right = lon_max1 <= lon_min2;
153 bool left = lon_min1 >= lon_max2;
154 bool lon_max12 = lon_max1 <= lon_max2;
155
156 if ((lon_min12 && !right)
157 || (!left && !lon_max12)
158 || (!lon_min12 && lon_max12))
159 {
160#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
161 std::cout << "(up-down)\n";
162#endif
163 if (lat_min1 > lat_max2)
164 {
165 return geometry::strategy::distance::services::result_from_distance
166 <
92f5a8d4
TL
167 PSStrategy, box_point_type1, box_point_type2
168 >::apply(ps_strategy, ps_strategy
169 .vertical_or_meridian(lat_min1, lat_max2));
11fdf7f2
TL
170 }
171 else if (lat_max1 < lat_min2)
172 {
173 return geometry::strategy::distance::services::result_from_distance
174 <
92f5a8d4
TL
175 PSStrategy, box_point_type1, box_point_type2
176 >::apply(ps_strategy, ps_strategy
177 .vertical_or_meridian(lat_min2, lat_max1));
11fdf7f2
TL
178 }
179 else
180 {
181 //BOOST_GEOMETRY_ASSERT(plat >= lat_min && plat <= lat_max);
182 return ReturnType(0);
183 }
184 }
185
186 // Check2: if box2 is right/left of box1
187 // the max lat of box2 should be less than the max lat of box1
188 bool bottom_max;
189
190 ReturnType top_common = (std::min)(lat_max1, lat_max2);
191 ReturnType bottom_common = (std::max)(lat_min1, lat_min2);
192
193 // true if the closest points are on northern hemisphere
194 bool north_shortest = top_common + bottom_common > 0;
195 // true if box bands do not overlap
196 bool non_overlap = top_common < bottom_common;
197
198 if (north_shortest)
199 {
200 bottom_max = lat_max1 >= lat_max2;
201 }
202 else
203 {
204 bottom_max = lat_min1 <= lat_min2;
205 }
206
207#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
208 std::cout << "(diagonal)";
209#endif
210 if (bottom_max && !right_wrap)
211 {
212#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
213 std::cout << "(bottom left)";
214#endif
215 return diagonal_case(top_right2, top_left1,
216 bottom_right2, bottom_left1,
217 north_shortest, non_overlap,
92f5a8d4 218 pp_strategy, ps_strategy);
11fdf7f2
TL
219 }
220 if (bottom_max && right_wrap)
221 {
222#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
223 std::cout << "(bottom right)";
224#endif
225 return diagonal_case(top_left2, top_right1,
226 bottom_left2, bottom_right1,
227 north_shortest, non_overlap,
92f5a8d4 228 pp_strategy, ps_strategy);
11fdf7f2
TL
229 }
230 if (!bottom_max && !right_wrap)
231 {
232#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
233 std::cout << "(top left)";
234#endif
235 return diagonal_case(top_left1, top_right2,
236 bottom_left1, bottom_right2,
237 north_shortest, non_overlap,
92f5a8d4 238 pp_strategy, ps_strategy);
11fdf7f2
TL
239 }
240 if (!bottom_max && right_wrap)
241 {
242#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK_BOX_BOX
243 std::cout << "(top right)";
244#endif
245 return diagonal_case(top_right1, top_left2,
246 bottom_right1, bottom_left2,
247 north_shortest, non_overlap,
92f5a8d4 248 pp_strategy, ps_strategy);
11fdf7f2
TL
249 }
250 return ReturnType(0);
251 }
252};
253
254} //namespace details
255
256/*!
257\brief Strategy functor for distance box to box calculation
258\ingroup strategies
259\details Class which calculates the distance of a box to a box, for
260boxes on a sphere or globe
261\tparam CalculationType \tparam_calculation
262\tparam Strategy underlying point-segment distance strategy, defaults
263to cross track
264\qbk{
265[heading See also]
266[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
267}
268*/
269template
270<
271 typename CalculationType = void,
92f5a8d4 272 typename Strategy = haversine<double, CalculationType>
11fdf7f2
TL
273>
274class cross_track_box_box
275{
276public:
277 template <typename Box1, typename Box2>
278 struct return_type
279 : services::return_type<Strategy,
280 typename point_type<Box1>::type,
281 typename point_type<Box2>::type>
282 {};
283
284 typedef typename Strategy::radius_type radius_type;
285
92f5a8d4
TL
286 // strategy getters
287
288 // point-segment strategy getters
289 struct distance_ps_strategy
290 {
291 typedef cross_track<CalculationType, Strategy> type;
292 };
293
294 typedef typename strategy::distance::services::comparable_type
295 <
296 Strategy
297 >::type pp_comparable_strategy;
298
20effc67 299 typedef std::conditional_t
92f5a8d4 300 <
20effc67 301 std::is_same
92f5a8d4
TL
302 <
303 pp_comparable_strategy,
304 Strategy
20effc67 305 >::value,
92f5a8d4
TL
306 typename strategy::distance::services::comparable_type
307 <
308 typename distance_ps_strategy::type
309 >::type,
310 typename distance_ps_strategy::type
20effc67 311 > ps_strategy_type;
92f5a8d4
TL
312
313 // constructors
314
11fdf7f2
TL
315 inline cross_track_box_box()
316 {}
317
318 explicit inline cross_track_box_box(typename Strategy::radius_type const& r)
92f5a8d4 319 : m_strategy(r)
11fdf7f2
TL
320 {}
321
322 inline cross_track_box_box(Strategy const& s)
92f5a8d4 323 : m_strategy(s)
11fdf7f2
TL
324 {}
325
326
327 // It might be useful in the future
328 // to overload constructor with strategy info.
329 // crosstrack(...) {}
330
331 template <typename Box1, typename Box2>
332 inline typename return_type<Box1, Box2>::type
333 apply(Box1 const& box1, Box2 const& box2) const
334 {
335#if !defined(BOOST_MSVC)
336 BOOST_CONCEPT_ASSERT
337 (
92f5a8d4 338 (concepts::PointDistanceStrategy
11fdf7f2
TL
339 <
340 Strategy,
341 typename point_type<Box1>::type,
342 typename point_type<Box2>::type
343 >)
344 );
345#endif
346 typedef typename return_type<Box1, Box2>::type return_type;
347 return details::cross_track_box_box_generic
92f5a8d4
TL
348 <return_type>::apply(box1, box2,
349 m_strategy,
350 ps_strategy_type(m_strategy));
11fdf7f2
TL
351 }
352
353 inline typename Strategy::radius_type radius() const
354 {
92f5a8d4 355 return m_strategy.radius();
11fdf7f2
TL
356 }
357
358private:
92f5a8d4 359 Strategy m_strategy;
11fdf7f2
TL
360};
361
362
363
364#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
365namespace services
366{
367
368template <typename CalculationType, typename Strategy>
369struct tag<cross_track_box_box<CalculationType, Strategy> >
370{
371 typedef strategy_tag_distance_box_box type;
372};
373
374
375template <typename CalculationType, typename Strategy, typename Box1, typename Box2>
376struct return_type<cross_track_box_box<CalculationType, Strategy>, Box1, Box2>
377 : cross_track_box_box
378 <
379 CalculationType, Strategy
380 >::template return_type<Box1, Box2>
381{};
382
383
384template <typename CalculationType, typename Strategy>
385struct comparable_type<cross_track_box_box<CalculationType, Strategy> >
386{
387 typedef cross_track_box_box
388 <
389 CalculationType, typename comparable_type<Strategy>::type
390 > type;
391};
392
393
394template <typename CalculationType, typename Strategy>
395struct get_comparable<cross_track_box_box<CalculationType, Strategy> >
396{
397 typedef cross_track_box_box<CalculationType, Strategy> this_strategy;
398 typedef typename comparable_type<this_strategy>::type comparable_type;
399
400public:
401 static inline comparable_type apply(this_strategy const& strategy)
402 {
403 return comparable_type(strategy.radius());
404 }
405};
406
407
408template <typename CalculationType, typename Strategy, typename Box1, typename Box2>
409struct result_from_distance
410 <
411 cross_track_box_box<CalculationType, Strategy>, Box1, Box2
412 >
413{
414private:
415 typedef cross_track_box_box<CalculationType, Strategy> this_strategy;
416
417 typedef typename this_strategy::template return_type
418 <
419 Box1, Box2
420 >::type return_type;
421
422public:
423 template <typename T>
424 static inline return_type apply(this_strategy const& strategy,
425 T const& distance)
426 {
427 Strategy s(strategy.radius());
428
429 return result_from_distance
430 <
431 Strategy,
432 typename point_type<Box1>::type,
433 typename point_type<Box2>::type
434 >::apply(s, distance);
435 }
436};
437
438
439// define cross_track_box_box<default_point_segment_strategy> as
440// default box-box strategy for the spherical equatorial coordinate system
441template <typename Box1, typename Box2, typename Strategy>
442struct default_strategy
443 <
444 box_tag, box_tag, Box1, Box2,
445 spherical_equatorial_tag, spherical_equatorial_tag,
446 Strategy
447 >
448{
449 typedef cross_track_box_box
450 <
451 void,
20effc67 452 std::conditional_t
11fdf7f2 453 <
20effc67 454 std::is_void<Strategy>::value,
11fdf7f2
TL
455 typename default_strategy
456 <
92f5a8d4 457 point_tag, point_tag,
11fdf7f2
TL
458 typename point_type<Box1>::type, typename point_type<Box2>::type,
459 spherical_equatorial_tag, spherical_equatorial_tag
460 >::type,
461 Strategy
20effc67 462 >
11fdf7f2
TL
463 > type;
464};
465
466} // namespace services
467#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
468
469
470}} // namespace strategy::distance
471
472
473}} // namespace boost::geometry
474
475#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_BOX_BOX_HPP