]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/util/normalize_spheroidal_coordinates.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / util / normalize_spheroidal_coordinates.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
11fdf7f2
TL
3// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
4
92f5a8d4 5// Copyright (c) 2015-2019, Oracle and/or its affiliates.
7c673cae
FG
6
7// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
8// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
92f5a8d4 9// Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program
7c673cae
FG
10
11// Licensed under the Boost Software License version 1.0.
12// http://www.boost.org/users/license.html
13
14#ifndef BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP
15#define BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP
16
17#include <boost/geometry/core/assert.hpp>
18#include <boost/geometry/core/cs.hpp>
19#include <boost/geometry/util/math.hpp>
20
21
22namespace boost { namespace geometry
23{
24
25namespace math
26{
27
28#ifndef DOXYGEN_NO_DETAIL
29namespace detail
30{
31
b32b8144
FG
32// CoordinateType, radian, true
33template <typename CoordinateType, typename Units, bool IsEquatorial = true>
7c673cae
FG
34struct constants_on_spheroid
35{
36 static inline CoordinateType period()
37 {
38 return math::two_pi<CoordinateType>();
39 }
40
41 static inline CoordinateType half_period()
42 {
43 return math::pi<CoordinateType>();
44 }
45
b32b8144
FG
46 static inline CoordinateType quarter_period()
47 {
48 static CoordinateType const
49 pi_half = math::pi<CoordinateType>() / CoordinateType(2);
50 return pi_half;
51 }
52
7c673cae
FG
53 static inline CoordinateType min_longitude()
54 {
55 static CoordinateType const minus_pi = -math::pi<CoordinateType>();
56 return minus_pi;
57 }
58
59 static inline CoordinateType max_longitude()
60 {
61 return math::pi<CoordinateType>();
62 }
63
64 static inline CoordinateType min_latitude()
65 {
66 static CoordinateType const minus_half_pi
67 = -math::half_pi<CoordinateType>();
68 return minus_half_pi;
69 }
70
71 static inline CoordinateType max_latitude()
72 {
73 return math::half_pi<CoordinateType>();
74 }
75};
76
77template <typename CoordinateType>
b32b8144
FG
78struct constants_on_spheroid<CoordinateType, radian, false>
79 : constants_on_spheroid<CoordinateType, radian, true>
80{
81 static inline CoordinateType min_latitude()
82 {
83 return CoordinateType(0);
84 }
85
86 static inline CoordinateType max_latitude()
87 {
88 return math::pi<CoordinateType>();
89 }
90};
91
92template <typename CoordinateType>
93struct constants_on_spheroid<CoordinateType, degree, true>
7c673cae
FG
94{
95 static inline CoordinateType period()
96 {
97 return CoordinateType(360.0);
98 }
99
100 static inline CoordinateType half_period()
101 {
102 return CoordinateType(180.0);
103 }
104
b32b8144
FG
105 static inline CoordinateType quarter_period()
106 {
107 return CoordinateType(90.0);
108 }
109
7c673cae
FG
110 static inline CoordinateType min_longitude()
111 {
112 return CoordinateType(-180.0);
113 }
114
115 static inline CoordinateType max_longitude()
116 {
117 return CoordinateType(180.0);
118 }
119
120 static inline CoordinateType min_latitude()
121 {
122 return CoordinateType(-90.0);
123 }
124
125 static inline CoordinateType max_latitude()
126 {
127 return CoordinateType(90.0);
128 }
129};
130
b32b8144
FG
131template <typename CoordinateType>
132struct constants_on_spheroid<CoordinateType, degree, false>
133 : constants_on_spheroid<CoordinateType, degree, true>
134{
135 static inline CoordinateType min_latitude()
136 {
137 return CoordinateType(0);
138 }
139
140 static inline CoordinateType max_latitude()
141 {
142 return CoordinateType(180.0);
143 }
144};
145
146
147} // namespace detail
148#endif // DOXYGEN_NO_DETAIL
149
7c673cae
FG
150
151template <typename Units, typename CoordinateType>
b32b8144
FG
152inline CoordinateType latitude_convert_ep(CoordinateType const& lat)
153{
154 typedef math::detail::constants_on_spheroid
155 <
156 CoordinateType,
157 Units
158 > constants;
159
160 return constants::quarter_period() - lat;
161}
162
163
164template <typename Units, bool IsEquatorial, typename T>
165static bool is_latitude_pole(T const& lat)
166{
167 typedef math::detail::constants_on_spheroid
168 <
169 T,
170 Units
171 > constants;
172
173 return math::equals(math::abs(IsEquatorial
174 ? lat
175 : math::latitude_convert_ep<Units>(lat)),
176 constants::quarter_period());
177
178}
179
180
181template <typename Units, typename T>
182static bool is_longitude_antimeridian(T const& lon)
183{
184 typedef math::detail::constants_on_spheroid
185 <
186 T,
187 Units
188 > constants;
189
190 return math::equals(math::abs(lon), constants::half_period());
191
192}
193
194
195#ifndef DOXYGEN_NO_DETAIL
196namespace detail
197{
198
199
200template <typename Units, bool IsEquatorial>
201struct latitude_convert_if_polar
202{
203 template <typename T>
11fdf7f2 204 static inline void apply(T & /*lat*/) {}
b32b8144
FG
205};
206
207template <typename Units>
208struct latitude_convert_if_polar<Units, false>
209{
210 template <typename T>
211 static inline void apply(T & lat)
212 {
213 lat = latitude_convert_ep<Units>(lat);
214 }
215};
216
217
218template <typename Units, typename CoordinateType, bool IsEquatorial = true>
7c673cae
FG
219class normalize_spheroidal_coordinates
220{
221 typedef constants_on_spheroid<CoordinateType, Units> constants;
222
223protected:
224 static inline CoordinateType normalize_up(CoordinateType const& value)
225 {
226 return
227 math::mod(value + constants::half_period(), constants::period())
228 - constants::half_period();
229 }
230
231 static inline CoordinateType normalize_down(CoordinateType const& value)
232 {
233 return
234 math::mod(value - constants::half_period(), constants::period())
235 + constants::half_period();
236 }
237
238public:
239 static inline void apply(CoordinateType& longitude)
240 {
241 // normalize longitude
242 if (math::equals(math::abs(longitude), constants::half_period()))
243 {
244 longitude = constants::half_period();
245 }
246 else if (longitude > constants::half_period())
247 {
248 longitude = normalize_up(longitude);
249 if (math::equals(longitude, -constants::half_period()))
250 {
251 longitude = constants::half_period();
252 }
253 }
254 else if (longitude < -constants::half_period())
255 {
256 longitude = normalize_down(longitude);
257 }
258 }
259
260 static inline void apply(CoordinateType& longitude,
261 CoordinateType& latitude,
262 bool normalize_poles = true)
263 {
b32b8144
FG
264 latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude);
265
7c673cae
FG
266#ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
267 // normalize latitude
268 if (math::larger(latitude, constants::half_period()))
269 {
270 latitude = normalize_up(latitude);
271 }
272 else if (math::smaller(latitude, -constants::half_period()))
273 {
274 latitude = normalize_down(latitude);
275 }
276
277 // fix latitude range
278 if (latitude < constants::min_latitude())
279 {
280 latitude = -constants::half_period() - latitude;
281 longitude -= constants::half_period();
282 }
283 else if (latitude > constants::max_latitude())
284 {
285 latitude = constants::half_period() - latitude;
286 longitude -= constants::half_period();
287 }
288#endif // BOOST_GEOMETRY_NORMALIZE_LATITUDE
289
290 // normalize longitude
291 apply(longitude);
292
293 // finally normalize poles
294 if (normalize_poles)
295 {
296 if (math::equals(math::abs(latitude), constants::max_latitude()))
297 {
298 // for the north and south pole we set the longitude to 0
299 // (works for both radians and degrees)
300 longitude = CoordinateType(0);
301 }
302 }
303
b32b8144
FG
304 latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude);
305
7c673cae
FG
306#ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
307 BOOST_GEOMETRY_ASSERT(! math::larger(constants::min_latitude(), latitude));
308 BOOST_GEOMETRY_ASSERT(! math::larger(latitude, constants::max_latitude()));
309#endif // BOOST_GEOMETRY_NORMALIZE_LATITUDE
310
311 BOOST_GEOMETRY_ASSERT(math::smaller(constants::min_longitude(), longitude));
312 BOOST_GEOMETRY_ASSERT(! math::larger(longitude, constants::max_longitude()));
313 }
314};
315
316
317} // namespace detail
318#endif // DOXYGEN_NO_DETAIL
319
320
321/*!
322\brief Short utility to normalize the coordinates on a spheroid
323\tparam Units The units of the coordindate system in the spheroid
324\tparam CoordinateType The type of the coordinates
325\param longitude Longitude
326\param latitude Latitude
327\ingroup utility
328*/
329template <typename Units, typename CoordinateType>
330inline void normalize_spheroidal_coordinates(CoordinateType& longitude,
331 CoordinateType& latitude)
332{
333 detail::normalize_spheroidal_coordinates
334 <
335 Units, CoordinateType
336 >::apply(longitude, latitude);
337}
338
b32b8144
FG
339template <typename Units, bool IsEquatorial, typename CoordinateType>
340inline void normalize_spheroidal_coordinates(CoordinateType& longitude,
341 CoordinateType& latitude)
342{
343 detail::normalize_spheroidal_coordinates
344 <
345 Units, CoordinateType, IsEquatorial
346 >::apply(longitude, latitude);
347}
7c673cae
FG
348
349/*!
350\brief Short utility to normalize the longitude on a spheroid.
351 Note that in general both coordinates should be normalized at once.
352 This utility is suitable e.g. for normalization of the difference of longitudes.
353\tparam Units The units of the coordindate system in the spheroid
354\tparam CoordinateType The type of the coordinates
355\param longitude Longitude
356\ingroup utility
357*/
358template <typename Units, typename CoordinateType>
359inline void normalize_longitude(CoordinateType& longitude)
360{
361 detail::normalize_spheroidal_coordinates
362 <
363 Units, CoordinateType
364 >::apply(longitude);
365}
366
92f5a8d4
TL
367/*!
368\brief Short utility to normalize the azimuth on a spheroid
369 in the range (-180, 180].
370\tparam Units The units of the coordindate system in the spheroid
371\tparam CoordinateType The type of the coordinates
372\param angle Angle
373\ingroup utility
374*/
375template <typename Units, typename CoordinateType>
376inline void normalize_azimuth(CoordinateType& angle)
377{
378 normalize_longitude<Units, CoordinateType>(angle);
379}
380
381/*!
382\brief Normalize the given values.
383\tparam ValueType The type of the values
384\param x Value x
385\param y Value y
386TODO: adl1995 - Merge this function with
387formulas/vertex_longitude.hpp
388*/
389template<typename ValueType>
390inline void normalize_unit_vector(ValueType& x, ValueType& y)
391{
392 ValueType h = boost::math::hypot(x, y);
393
394 BOOST_GEOMETRY_ASSERT(h > 0);
395
396 x /= h; y /= h;
397}
7c673cae
FG
398
399/*!
400\brief Short utility to calculate difference between two longitudes
401 normalized in range (-180, 180].
402\tparam Units The units of the coordindate system in the spheroid
403\tparam CoordinateType The type of the coordinates
404\param longitude1 Longitude 1
405\param longitude2 Longitude 2
406\ingroup utility
407*/
408template <typename Units, typename CoordinateType>
409inline CoordinateType longitude_distance_signed(CoordinateType const& longitude1,
410 CoordinateType const& longitude2)
411{
412 CoordinateType diff = longitude2 - longitude1;
413 math::normalize_longitude<Units, CoordinateType>(diff);
414 return diff;
415}
416
417
418/*!
419\brief Short utility to calculate difference between two longitudes
420 normalized in range [0, 360).
421\tparam Units The units of the coordindate system in the spheroid
422\tparam CoordinateType The type of the coordinates
423\param longitude1 Longitude 1
424\param longitude2 Longitude 2
425\ingroup utility
426*/
427template <typename Units, typename CoordinateType>
428inline CoordinateType longitude_distance_unsigned(CoordinateType const& longitude1,
429 CoordinateType const& longitude2)
430{
431 typedef math::detail::constants_on_spheroid
432 <
433 CoordinateType, Units
434 > constants;
435
436 CoordinateType const c0 = 0;
437 CoordinateType diff = longitude_distance_signed<Units>(longitude1, longitude2);
438 if (diff < c0) // (-180, 180] -> [0, 360)
439 {
440 diff += constants::period();
441 }
442 return diff;
443}
444
b32b8144
FG
445/*!
446\brief The abs difference between longitudes in range [0, 180].
447\tparam Units The units of the coordindate system in the spheroid
448\tparam CoordinateType The type of the coordinates
449\param longitude1 Longitude 1
450\param longitude2 Longitude 2
451\ingroup utility
452*/
453template <typename Units, typename CoordinateType>
454inline CoordinateType longitude_difference(CoordinateType const& longitude1,
455 CoordinateType const& longitude2)
456{
457 return math::abs(math::longitude_distance_signed<Units>(longitude1, longitude2));
458}
459
460template <typename Units, typename CoordinateType>
461inline CoordinateType longitude_interval_distance_signed(CoordinateType const& longitude_a1,
462 CoordinateType const& longitude_a2,
463 CoordinateType const& longitude_b)
464{
465 CoordinateType const c0 = 0;
466 CoordinateType dist_a12 = longitude_distance_signed<Units>(longitude_a1, longitude_a2);
467 CoordinateType dist_a1b = longitude_distance_signed<Units>(longitude_a1, longitude_b);
468 if (dist_a12 < c0)
469 {
470 dist_a12 = -dist_a12;
471 dist_a1b = -dist_a1b;
472 }
473
474 return dist_a1b < c0 ? dist_a1b
475 : dist_a1b > dist_a12 ? dist_a1b - dist_a12
476 : c0;
477}
478
479
7c673cae
FG
480} // namespace math
481
482
483}} // namespace boost::geometry
484
485#endif // BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP