]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / strategies / spherical / distance_cross_track_point_box.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
4 // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
5 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
6
7 // This file was modified by Oracle on 2014-2017.
8 // Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
9
10 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
11 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
12 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
13
14 // Use, modification and distribution is subject to the Boost Software License,
15 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
16 // http://www.boost.org/LICENSE_1_0.txt)
17
18 #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
19 #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
20
21 #include <boost/config.hpp>
22 #include <boost/concept_check.hpp>
23 #include <boost/mpl/if.hpp>
24 #include <boost/type_traits/is_void.hpp>
25
26 #include <boost/geometry/core/access.hpp>
27 #include <boost/geometry/core/assert.hpp>
28 #include <boost/geometry/core/point_type.hpp>
29 #include <boost/geometry/core/radian_access.hpp>
30 #include <boost/geometry/core/tags.hpp>
31
32 #include <boost/geometry/strategies/distance.hpp>
33 #include <boost/geometry/strategies/concepts/distance_concept.hpp>
34 #include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
35
36 #include <boost/geometry/util/math.hpp>
37 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
38
39
40 namespace boost { namespace geometry
41 {
42
43 namespace strategy { namespace distance
44 {
45
46 namespace details
47 {
48
49 template <typename ReturnType>
50 class cross_track_point_box_generic
51 {
52 public :
53
54 template
55 <
56 typename Point,
57 typename Box,
58 typename Strategy
59 >
60 ReturnType static inline apply (Point const& point,
61 Box const& box,
62 Strategy ps_strategy)
63 {
64 // this method assumes that the coordinates of the point and
65 // the box are normalized
66
67 typedef typename point_type<Box>::type box_point_type;
68
69 box_point_type bottom_left, bottom_right, top_left, top_right;
70 geometry::detail::assign_box_corners(box,
71 bottom_left, bottom_right,
72 top_left, top_right);
73
74 ReturnType const plon = geometry::get_as_radian<0>(point);
75 ReturnType const plat = geometry::get_as_radian<1>(point);
76
77 ReturnType const lon_min = geometry::get_as_radian<0>(bottom_left);
78 ReturnType const lat_min = geometry::get_as_radian<1>(bottom_left);
79 ReturnType const lon_max = geometry::get_as_radian<0>(top_right);
80 ReturnType const lat_max = geometry::get_as_radian<1>(top_right);
81
82 ReturnType const pi = math::pi<ReturnType>();
83 ReturnType const two_pi = math::two_pi<ReturnType>();
84
85 typedef typename point_type<Box>::type box_point_type;
86
87 // First check if the point is within the band defined by the
88 // minimum and maximum longitude of the box; if yes, determine
89 // if the point is above, below or inside the box and compute
90 // the distance (easy in this case)
91 //
92 // Notice that the point may not be inside the longitude range
93 // of the box, but the shifted point may be inside the
94 // longitude range of the box; in this case the point is still
95 // considered as inside the longitude range band of the box
96 if ((plon >= lon_min && plon <= lon_max) || plon + two_pi <= lon_max)
97 {
98 if (plat > lat_max)
99 {
100 return geometry::strategy::distance::services::result_from_distance
101 <
102 Strategy, Point, box_point_type
103 >::apply(ps_strategy, ps_strategy
104 .vertical_or_meridian(plat, lat_max));
105 }
106 else if (plat < lat_min)
107 {
108 return geometry::strategy::distance::services::result_from_distance
109 <
110 Strategy, Point, box_point_type
111 >::apply(ps_strategy, ps_strategy
112 .vertical_or_meridian(lat_min, plat));
113 }
114 else
115 {
116 BOOST_GEOMETRY_ASSERT(plat >= lat_min && plat <= lat_max);
117 return ReturnType(0);
118 }
119 }
120
121 // Otherwise determine which among the two medirian segments of the
122 // box the point is closest to, and compute the distance of
123 // the point to this closest segment
124
125 // Below lon_midway is the longitude of the meridian that:
126 // (1) is midway between the meridians of the left and right
127 // meridians of the box, and
128 // (2) does not intersect the box
129 ReturnType const two = 2.0;
130 bool use_left_segment;
131 if (lon_max > pi)
132 {
133 // the box crosses the antimeridian
134
135 // midway longitude = lon_min - (lon_min + (lon_max - 2 * pi)) / 2;
136 ReturnType const lon_midway = (lon_min - lon_max) / two + pi;
137 BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
138
139 use_left_segment = plon > lon_midway;
140 }
141 else
142 {
143 // the box does not cross the antimeridian
144
145 ReturnType const lon_sum = lon_min + lon_max;
146 if (math::equals(lon_sum, ReturnType(0)))
147 {
148 // special case: the box is symmetric with respect to
149 // the prime meridian; the midway meridian is the antimeridian
150
151 use_left_segment = plon < lon_min;
152 }
153 else
154 {
155 // midway long. = lon_min - (2 * pi - (lon_max - lon_min)) / 2;
156 ReturnType lon_midway = (lon_min + lon_max) / two - pi;
157
158 // normalize the midway longitude
159 if (lon_midway > pi)
160 {
161 lon_midway -= two_pi;
162 }
163 else if (lon_midway < -pi)
164 {
165 lon_midway += two_pi;
166 }
167 BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
168
169 // if lon_sum is positive the midway meridian is left
170 // of the box, or right of the box otherwise
171 use_left_segment = lon_sum > 0
172 ? (plon < lon_min && plon >= lon_midway)
173 : (plon <= lon_max || plon > lon_midway);
174 }
175 }
176
177 return use_left_segment
178 ? ps_strategy.apply(point, bottom_left, top_left)
179 : ps_strategy.apply(point, bottom_right, top_right);
180 }
181 };
182
183 } //namespace details
184
185 /*!
186 \brief Strategy functor for distance point to box calculation
187 \ingroup strategies
188 \details Class which calculates the distance of a point to a box, for
189 points and boxes on a sphere or globe
190 \tparam CalculationType \tparam_calculation
191 \tparam Strategy underlying point-point distance strategy
192 \qbk{
193 [heading See also]
194 [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
195 }
196 */
197 template
198 <
199 typename CalculationType = void,
200 typename Strategy = haversine<double, CalculationType>
201 >
202 class cross_track_point_box
203 {
204 public:
205 template <typename Point, typename Box>
206 struct return_type
207 : services::return_type<Strategy, Point, typename point_type<Box>::type>
208 {};
209
210 typedef typename Strategy::radius_type radius_type;
211
212 // strategy getters
213
214 // point-segment strategy getters
215 struct distance_ps_strategy
216 {
217 typedef cross_track<CalculationType, Strategy> type;
218 };
219
220 typedef typename strategy::distance::services::comparable_type
221 <
222 Strategy
223 >::type pp_comparable_strategy;
224
225 typedef typename boost::mpl::if_
226 <
227 boost::is_same
228 <
229 pp_comparable_strategy,
230 Strategy
231 >,
232 typename strategy::distance::services::comparable_type
233 <
234 typename distance_ps_strategy::type
235 >::type,
236 typename distance_ps_strategy::type
237 >::type ps_strategy_type;
238
239 // constructors
240
241 inline cross_track_point_box()
242 {}
243
244 explicit inline cross_track_point_box(typename Strategy::radius_type const& r)
245 : m_strategy(r)
246 {}
247
248 inline cross_track_point_box(Strategy const& s)
249 : m_strategy(s)
250 {}
251
252
253 // methods
254
255 // It might be useful in the future
256 // to overload constructor with strategy info.
257 // crosstrack(...) {}
258
259 template <typename Point, typename Box>
260 inline typename return_type<Point, Box>::type
261 apply(Point const& point, Box const& box) const
262 {
263 #if !defined(BOOST_MSVC)
264 BOOST_CONCEPT_ASSERT
265 (
266 (concepts::PointDistanceStrategy
267 <
268 Strategy, Point, typename point_type<Box>::type
269 >)
270 );
271 #endif
272 typedef typename return_type<Point, Box>::type return_type;
273 return details::cross_track_point_box_generic
274 <return_type>::apply(point, box,
275 ps_strategy_type(m_strategy));
276 }
277
278 inline typename Strategy::radius_type radius() const
279 {
280 return m_strategy.radius();
281 }
282
283 private:
284 Strategy m_strategy;
285 };
286
287
288
289 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
290 namespace services
291 {
292
293 template <typename CalculationType, typename Strategy>
294 struct tag<cross_track_point_box<CalculationType, Strategy> >
295 {
296 typedef strategy_tag_distance_point_box type;
297 };
298
299
300 template <typename CalculationType, typename Strategy, typename P, typename Box>
301 struct return_type<cross_track_point_box<CalculationType, Strategy>, P, Box>
302 : cross_track_point_box
303 <
304 CalculationType, Strategy
305 >::template return_type<P, Box>
306 {};
307
308
309 template <typename CalculationType, typename Strategy>
310 struct comparable_type<cross_track_point_box<CalculationType, Strategy> >
311 {
312 typedef cross_track_point_box
313 <
314 CalculationType, typename comparable_type<Strategy>::type
315 > type;
316 };
317
318
319 template <typename CalculationType, typename Strategy>
320 struct get_comparable<cross_track_point_box<CalculationType, Strategy> >
321 {
322 typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
323 typedef typename comparable_type<this_strategy>::type comparable_type;
324
325 public:
326 static inline comparable_type apply(this_strategy const& strategy)
327 {
328 return comparable_type(strategy.radius());
329 }
330 };
331
332
333 template <typename CalculationType, typename Strategy, typename P, typename Box>
334 struct result_from_distance
335 <
336 cross_track_point_box<CalculationType, Strategy>, P, Box
337 >
338 {
339 private:
340 typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
341
342 typedef typename this_strategy::template return_type
343 <
344 P, Box
345 >::type return_type;
346
347 public:
348 template <typename T>
349 static inline return_type apply(this_strategy const& strategy,
350 T const& distance)
351 {
352 Strategy s(strategy.radius());
353
354 return result_from_distance
355 <
356 Strategy, P, typename point_type<Box>::type
357 >::apply(s, distance);
358 }
359 };
360
361
362 // define cross_track_point_box<default_point_segment_strategy> as
363 // default point-box strategy for the spherical equatorial coordinate system
364 template <typename Point, typename Box, typename Strategy>
365 struct default_strategy
366 <
367 point_tag, box_tag, Point, Box,
368 spherical_equatorial_tag, spherical_equatorial_tag,
369 Strategy
370 >
371 {
372 typedef cross_track_point_box
373 <
374 void,
375 typename boost::mpl::if_
376 <
377 boost::is_void<Strategy>,
378 typename default_strategy
379 <
380 point_tag, point_tag,
381 Point, typename point_type<Box>::type,
382 spherical_equatorial_tag, spherical_equatorial_tag
383 >::type,
384 Strategy
385 >::type
386 > type;
387 };
388
389
390 template <typename Box, typename Point, typename Strategy>
391 struct default_strategy
392 <
393 box_tag, point_tag, Box, Point,
394 spherical_equatorial_tag, spherical_equatorial_tag,
395 Strategy
396 >
397 {
398 typedef typename default_strategy
399 <
400 point_tag, box_tag, Point, Box,
401 spherical_equatorial_tag, spherical_equatorial_tag,
402 Strategy
403 >::type type;
404 };
405
406
407 } // namespace services
408 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
409
410
411 }} // namespace strategy::distance
412
413
414 }} // namespace boost::geometry
415
416
417 #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP