]>
Commit | Line | Data |
---|---|---|
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 | ||
22 | namespace boost { namespace geometry | |
23 | { | |
24 | ||
25 | namespace math | |
26 | { | |
27 | ||
28 | #ifndef DOXYGEN_NO_DETAIL | |
29 | namespace detail | |
30 | { | |
31 | ||
b32b8144 FG |
32 | // CoordinateType, radian, true |
33 | template <typename CoordinateType, typename Units, bool IsEquatorial = true> | |
7c673cae FG |
34 | struct 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 | ||
77 | template <typename CoordinateType> | |
b32b8144 FG |
78 | struct 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 | ||
92 | template <typename CoordinateType> | |
93 | struct 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 |
131 | template <typename CoordinateType> |
132 | struct 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 | |
151 | template <typename Units, typename CoordinateType> | |
b32b8144 FG |
152 | inline 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 | ||
164 | template <typename Units, bool IsEquatorial, typename T> | |
165 | static 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 | ||
181 | template <typename Units, typename T> | |
182 | static 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 | |
196 | namespace detail | |
197 | { | |
198 | ||
199 | ||
200 | template <typename Units, bool IsEquatorial> | |
201 | struct latitude_convert_if_polar | |
202 | { | |
203 | template <typename T> | |
11fdf7f2 | 204 | static inline void apply(T & /*lat*/) {} |
b32b8144 FG |
205 | }; |
206 | ||
207 | template <typename Units> | |
208 | struct 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 | ||
218 | template <typename Units, typename CoordinateType, bool IsEquatorial = true> | |
7c673cae FG |
219 | class normalize_spheroidal_coordinates |
220 | { | |
221 | typedef constants_on_spheroid<CoordinateType, Units> constants; | |
222 | ||
223 | protected: | |
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 | ||
238 | public: | |
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 | */ | |
329 | template <typename Units, typename CoordinateType> | |
330 | inline 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 |
339 | template <typename Units, bool IsEquatorial, typename CoordinateType> |
340 | inline 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 | */ | |
358 | template <typename Units, typename CoordinateType> | |
359 | inline 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 | */ | |
375 | template <typename Units, typename CoordinateType> | |
376 | inline 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 | |
386 | TODO: adl1995 - Merge this function with | |
387 | formulas/vertex_longitude.hpp | |
388 | */ | |
389 | template<typename ValueType> | |
390 | inline 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 | */ | |
408 | template <typename Units, typename CoordinateType> | |
409 | inline 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 | */ | |
427 | template <typename Units, typename CoordinateType> | |
428 | inline 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 | */ | |
453 | template <typename Units, typename CoordinateType> | |
454 | inline CoordinateType longitude_difference(CoordinateType const& longitude1, | |
455 | CoordinateType const& longitude2) | |
456 | { | |
457 | return math::abs(math::longitude_distance_signed<Units>(longitude1, longitude2)); | |
458 | } | |
459 | ||
460 | template <typename Units, typename CoordinateType> | |
461 | inline 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 |