]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
3 | // Copyright (c) 2015-2016, 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 | ||
30 | template <typename CoordinateType, typename Units> | |
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 min_longitude() | |
44 | { | |
45 | static CoordinateType const minus_pi = -math::pi<CoordinateType>(); | |
46 | return minus_pi; | |
47 | } | |
48 | ||
49 | static inline CoordinateType max_longitude() | |
50 | { | |
51 | return math::pi<CoordinateType>(); | |
52 | } | |
53 | ||
54 | static inline CoordinateType min_latitude() | |
55 | { | |
56 | static CoordinateType const minus_half_pi | |
57 | = -math::half_pi<CoordinateType>(); | |
58 | return minus_half_pi; | |
59 | } | |
60 | ||
61 | static inline CoordinateType max_latitude() | |
62 | { | |
63 | return math::half_pi<CoordinateType>(); | |
64 | } | |
65 | }; | |
66 | ||
67 | template <typename CoordinateType> | |
68 | struct constants_on_spheroid<CoordinateType, degree> | |
69 | { | |
70 | static inline CoordinateType period() | |
71 | { | |
72 | return CoordinateType(360.0); | |
73 | } | |
74 | ||
75 | static inline CoordinateType half_period() | |
76 | { | |
77 | return CoordinateType(180.0); | |
78 | } | |
79 | ||
80 | static inline CoordinateType min_longitude() | |
81 | { | |
82 | return CoordinateType(-180.0); | |
83 | } | |
84 | ||
85 | static inline CoordinateType max_longitude() | |
86 | { | |
87 | return CoordinateType(180.0); | |
88 | } | |
89 | ||
90 | static inline CoordinateType min_latitude() | |
91 | { | |
92 | return CoordinateType(-90.0); | |
93 | } | |
94 | ||
95 | static inline CoordinateType max_latitude() | |
96 | { | |
97 | return CoordinateType(90.0); | |
98 | } | |
99 | }; | |
100 | ||
101 | ||
102 | template <typename Units, typename CoordinateType> | |
103 | class normalize_spheroidal_coordinates | |
104 | { | |
105 | typedef constants_on_spheroid<CoordinateType, Units> constants; | |
106 | ||
107 | protected: | |
108 | static inline CoordinateType normalize_up(CoordinateType const& value) | |
109 | { | |
110 | return | |
111 | math::mod(value + constants::half_period(), constants::period()) | |
112 | - constants::half_period(); | |
113 | } | |
114 | ||
115 | static inline CoordinateType normalize_down(CoordinateType const& value) | |
116 | { | |
117 | return | |
118 | math::mod(value - constants::half_period(), constants::period()) | |
119 | + constants::half_period(); | |
120 | } | |
121 | ||
122 | public: | |
123 | static inline void apply(CoordinateType& longitude) | |
124 | { | |
125 | // normalize longitude | |
126 | if (math::equals(math::abs(longitude), constants::half_period())) | |
127 | { | |
128 | longitude = constants::half_period(); | |
129 | } | |
130 | else if (longitude > constants::half_period()) | |
131 | { | |
132 | longitude = normalize_up(longitude); | |
133 | if (math::equals(longitude, -constants::half_period())) | |
134 | { | |
135 | longitude = constants::half_period(); | |
136 | } | |
137 | } | |
138 | else if (longitude < -constants::half_period()) | |
139 | { | |
140 | longitude = normalize_down(longitude); | |
141 | } | |
142 | } | |
143 | ||
144 | static inline void apply(CoordinateType& longitude, | |
145 | CoordinateType& latitude, | |
146 | bool normalize_poles = true) | |
147 | { | |
148 | #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE | |
149 | // normalize latitude | |
150 | if (math::larger(latitude, constants::half_period())) | |
151 | { | |
152 | latitude = normalize_up(latitude); | |
153 | } | |
154 | else if (math::smaller(latitude, -constants::half_period())) | |
155 | { | |
156 | latitude = normalize_down(latitude); | |
157 | } | |
158 | ||
159 | // fix latitude range | |
160 | if (latitude < constants::min_latitude()) | |
161 | { | |
162 | latitude = -constants::half_period() - latitude; | |
163 | longitude -= constants::half_period(); | |
164 | } | |
165 | else if (latitude > constants::max_latitude()) | |
166 | { | |
167 | latitude = constants::half_period() - latitude; | |
168 | longitude -= constants::half_period(); | |
169 | } | |
170 | #endif // BOOST_GEOMETRY_NORMALIZE_LATITUDE | |
171 | ||
172 | // normalize longitude | |
173 | apply(longitude); | |
174 | ||
175 | // finally normalize poles | |
176 | if (normalize_poles) | |
177 | { | |
178 | if (math::equals(math::abs(latitude), constants::max_latitude())) | |
179 | { | |
180 | // for the north and south pole we set the longitude to 0 | |
181 | // (works for both radians and degrees) | |
182 | longitude = CoordinateType(0); | |
183 | } | |
184 | } | |
185 | ||
186 | #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE | |
187 | BOOST_GEOMETRY_ASSERT(! math::larger(constants::min_latitude(), latitude)); | |
188 | BOOST_GEOMETRY_ASSERT(! math::larger(latitude, constants::max_latitude())); | |
189 | #endif // BOOST_GEOMETRY_NORMALIZE_LATITUDE | |
190 | ||
191 | BOOST_GEOMETRY_ASSERT(math::smaller(constants::min_longitude(), longitude)); | |
192 | BOOST_GEOMETRY_ASSERT(! math::larger(longitude, constants::max_longitude())); | |
193 | } | |
194 | }; | |
195 | ||
196 | ||
197 | } // namespace detail | |
198 | #endif // DOXYGEN_NO_DETAIL | |
199 | ||
200 | ||
201 | /*! | |
202 | \brief Short utility to normalize the coordinates on a spheroid | |
203 | \tparam Units The units of the coordindate system in the spheroid | |
204 | \tparam CoordinateType The type of the coordinates | |
205 | \param longitude Longitude | |
206 | \param latitude Latitude | |
207 | \ingroup utility | |
208 | */ | |
209 | template <typename Units, typename CoordinateType> | |
210 | inline void normalize_spheroidal_coordinates(CoordinateType& longitude, | |
211 | CoordinateType& latitude) | |
212 | { | |
213 | detail::normalize_spheroidal_coordinates | |
214 | < | |
215 | Units, CoordinateType | |
216 | >::apply(longitude, latitude); | |
217 | } | |
218 | ||
219 | ||
220 | /*! | |
221 | \brief Short utility to normalize the longitude on a spheroid. | |
222 | Note that in general both coordinates should be normalized at once. | |
223 | This utility is suitable e.g. for normalization of the difference of longitudes. | |
224 | \tparam Units The units of the coordindate system in the spheroid | |
225 | \tparam CoordinateType The type of the coordinates | |
226 | \param longitude Longitude | |
227 | \ingroup utility | |
228 | */ | |
229 | template <typename Units, typename CoordinateType> | |
230 | inline void normalize_longitude(CoordinateType& longitude) | |
231 | { | |
232 | detail::normalize_spheroidal_coordinates | |
233 | < | |
234 | Units, CoordinateType | |
235 | >::apply(longitude); | |
236 | } | |
237 | ||
238 | ||
239 | /*! | |
240 | \brief Short utility to calculate difference between two longitudes | |
241 | normalized in range (-180, 180]. | |
242 | \tparam Units The units of the coordindate system in the spheroid | |
243 | \tparam CoordinateType The type of the coordinates | |
244 | \param longitude1 Longitude 1 | |
245 | \param longitude2 Longitude 2 | |
246 | \ingroup utility | |
247 | */ | |
248 | template <typename Units, typename CoordinateType> | |
249 | inline CoordinateType longitude_distance_signed(CoordinateType const& longitude1, | |
250 | CoordinateType const& longitude2) | |
251 | { | |
252 | CoordinateType diff = longitude2 - longitude1; | |
253 | math::normalize_longitude<Units, CoordinateType>(diff); | |
254 | return diff; | |
255 | } | |
256 | ||
257 | ||
258 | /*! | |
259 | \brief Short utility to calculate difference between two longitudes | |
260 | normalized in range [0, 360). | |
261 | \tparam Units The units of the coordindate system in the spheroid | |
262 | \tparam CoordinateType The type of the coordinates | |
263 | \param longitude1 Longitude 1 | |
264 | \param longitude2 Longitude 2 | |
265 | \ingroup utility | |
266 | */ | |
267 | template <typename Units, typename CoordinateType> | |
268 | inline CoordinateType longitude_distance_unsigned(CoordinateType const& longitude1, | |
269 | CoordinateType const& longitude2) | |
270 | { | |
271 | typedef math::detail::constants_on_spheroid | |
272 | < | |
273 | CoordinateType, Units | |
274 | > constants; | |
275 | ||
276 | CoordinateType const c0 = 0; | |
277 | CoordinateType diff = longitude_distance_signed<Units>(longitude1, longitude2); | |
278 | if (diff < c0) // (-180, 180] -> [0, 360) | |
279 | { | |
280 | diff += constants::period(); | |
281 | } | |
282 | return diff; | |
283 | } | |
284 | ||
285 | } // namespace math | |
286 | ||
287 | ||
288 | }} // namespace boost::geometry | |
289 | ||
290 | #endif // BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP |