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