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