1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2015-2016, Oracle and/or its affiliates.
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8 // Licensed under the Boost Software License version 1.0.
9 // http://www.boost.org/users/license.html
11 #ifndef BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP
12 #define BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP
14 #include <boost/geometry/core/assert.hpp>
15 #include <boost/geometry/core/cs.hpp>
16 #include <boost/geometry/util/math.hpp>
19 namespace boost { namespace geometry
25 #ifndef DOXYGEN_NO_DETAIL
30 template <typename CoordinateType, typename Units>
31 struct constants_on_spheroid
33 static inline CoordinateType period()
35 return math::two_pi<CoordinateType>();
38 static inline CoordinateType half_period()
40 return math::pi<CoordinateType>();
43 static inline CoordinateType min_longitude()
45 static CoordinateType const minus_pi = -math::pi<CoordinateType>();
49 static inline CoordinateType max_longitude()
51 return math::pi<CoordinateType>();
54 static inline CoordinateType min_latitude()
56 static CoordinateType const minus_half_pi
57 = -math::half_pi<CoordinateType>();
61 static inline CoordinateType max_latitude()
63 return math::half_pi<CoordinateType>();
67 template <typename CoordinateType>
68 struct constants_on_spheroid<CoordinateType, degree>
70 static inline CoordinateType period()
72 return CoordinateType(360.0);
75 static inline CoordinateType half_period()
77 return CoordinateType(180.0);
80 static inline CoordinateType min_longitude()
82 return CoordinateType(-180.0);
85 static inline CoordinateType max_longitude()
87 return CoordinateType(180.0);
90 static inline CoordinateType min_latitude()
92 return CoordinateType(-90.0);
95 static inline CoordinateType max_latitude()
97 return CoordinateType(90.0);
102 template <typename Units, typename CoordinateType>
103 class normalize_spheroidal_coordinates
105 typedef constants_on_spheroid<CoordinateType, Units> constants;
108 static inline CoordinateType normalize_up(CoordinateType const& value)
111 math::mod(value + constants::half_period(), constants::period())
112 - constants::half_period();
115 static inline CoordinateType normalize_down(CoordinateType const& value)
118 math::mod(value - constants::half_period(), constants::period())
119 + constants::half_period();
123 static inline void apply(CoordinateType& longitude)
125 // normalize longitude
126 if (math::equals(math::abs(longitude), constants::half_period()))
128 longitude = constants::half_period();
130 else if (longitude > constants::half_period())
132 longitude = normalize_up(longitude);
133 if (math::equals(longitude, -constants::half_period()))
135 longitude = constants::half_period();
138 else if (longitude < -constants::half_period())
140 longitude = normalize_down(longitude);
144 static inline void apply(CoordinateType& longitude,
145 CoordinateType& latitude,
146 bool normalize_poles = true)
148 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
149 // normalize latitude
150 if (math::larger(latitude, constants::half_period()))
152 latitude = normalize_up(latitude);
154 else if (math::smaller(latitude, -constants::half_period()))
156 latitude = normalize_down(latitude);
159 // fix latitude range
160 if (latitude < constants::min_latitude())
162 latitude = -constants::half_period() - latitude;
163 longitude -= constants::half_period();
165 else if (latitude > constants::max_latitude())
167 latitude = constants::half_period() - latitude;
168 longitude -= constants::half_period();
170 #endif // BOOST_GEOMETRY_NORMALIZE_LATITUDE
172 // normalize longitude
175 // finally normalize poles
178 if (math::equals(math::abs(latitude), constants::max_latitude()))
180 // for the north and south pole we set the longitude to 0
181 // (works for both radians and degrees)
182 longitude = CoordinateType(0);
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
191 BOOST_GEOMETRY_ASSERT(math::smaller(constants::min_longitude(), longitude));
192 BOOST_GEOMETRY_ASSERT(! math::larger(longitude, constants::max_longitude()));
197 } // namespace detail
198 #endif // DOXYGEN_NO_DETAIL
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
209 template <typename Units, typename CoordinateType>
210 inline void normalize_spheroidal_coordinates(CoordinateType& longitude,
211 CoordinateType& latitude)
213 detail::normalize_spheroidal_coordinates
215 Units, CoordinateType
216 >::apply(longitude, latitude);
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
229 template <typename Units, typename CoordinateType>
230 inline void normalize_longitude(CoordinateType& longitude)
232 detail::normalize_spheroidal_coordinates
234 Units, CoordinateType
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
248 template <typename Units, typename CoordinateType>
249 inline CoordinateType longitude_distance_signed(CoordinateType const& longitude1,
250 CoordinateType const& longitude2)
252 CoordinateType diff = longitude2 - longitude1;
253 math::normalize_longitude<Units, CoordinateType>(diff);
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
267 template <typename Units, typename CoordinateType>
268 inline CoordinateType longitude_distance_unsigned(CoordinateType const& longitude1,
269 CoordinateType const& longitude2)
271 typedef math::detail::constants_on_spheroid
273 CoordinateType, Units
276 CoordinateType const c0 = 0;
277 CoordinateType diff = longitude_distance_signed<Units>(longitude1, longitude2);
278 if (diff < c0) // (-180, 180] -> [0, 360)
280 diff += constants::period();
288 }} // namespace boost::geometry
290 #endif // BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP