123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
- // Copyright (c) 2015-2022, Oracle and/or its affiliates.
- // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
- // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
- // Contributed and/or modified by Adeel Ahmad, as part of Google Summer of Code 2018 program
- // Licensed under the Boost Software License version 1.0.
- // http://www.boost.org/users/license.html
- #ifndef BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP
- #define BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP
- #include <boost/geometry/core/assert.hpp>
- #include <boost/geometry/core/cs.hpp>
- #include <boost/geometry/util/math.hpp>
- namespace boost { namespace geometry
- {
- namespace math
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail
- {
- // CoordinateType, radian, true
- template <typename CoordinateType, typename Units, bool IsEquatorial = true>
- struct constants_on_spheroid
- {
- static inline CoordinateType period()
- {
- return math::two_pi<CoordinateType>();
- }
- static inline CoordinateType half_period()
- {
- return math::pi<CoordinateType>();
- }
- static inline CoordinateType quarter_period()
- {
- static CoordinateType const
- pi_half = math::pi<CoordinateType>() / CoordinateType(2);
- return pi_half;
- }
- static inline CoordinateType min_longitude()
- {
- static CoordinateType const minus_pi = -math::pi<CoordinateType>();
- return minus_pi;
- }
- static inline CoordinateType max_longitude()
- {
- return math::pi<CoordinateType>();
- }
- static inline CoordinateType min_latitude()
- {
- static CoordinateType const minus_half_pi
- = -math::half_pi<CoordinateType>();
- return minus_half_pi;
- }
- static inline CoordinateType max_latitude()
- {
- return math::half_pi<CoordinateType>();
- }
- };
- template <typename CoordinateType>
- struct constants_on_spheroid<CoordinateType, radian, false>
- : constants_on_spheroid<CoordinateType, radian, true>
- {
- static inline CoordinateType min_latitude()
- {
- return CoordinateType(0);
- }
- static inline CoordinateType max_latitude()
- {
- return math::pi<CoordinateType>();
- }
- };
- template <typename CoordinateType>
- struct constants_on_spheroid<CoordinateType, degree, true>
- {
- static inline CoordinateType period()
- {
- return CoordinateType(360.0);
- }
- static inline CoordinateType half_period()
- {
- return CoordinateType(180.0);
- }
- static inline CoordinateType quarter_period()
- {
- return CoordinateType(90.0);
- }
- static inline CoordinateType min_longitude()
- {
- return CoordinateType(-180.0);
- }
- static inline CoordinateType max_longitude()
- {
- return CoordinateType(180.0);
- }
- static inline CoordinateType min_latitude()
- {
- return CoordinateType(-90.0);
- }
- static inline CoordinateType max_latitude()
- {
- return CoordinateType(90.0);
- }
- };
- template <typename CoordinateType>
- struct constants_on_spheroid<CoordinateType, degree, false>
- : constants_on_spheroid<CoordinateType, degree, true>
- {
- static inline CoordinateType min_latitude()
- {
- return CoordinateType(0);
- }
- static inline CoordinateType max_latitude()
- {
- return CoordinateType(180.0);
- }
- };
- } // namespace detail
- #endif // DOXYGEN_NO_DETAIL
- template <typename Units, typename CoordinateType>
- inline CoordinateType latitude_convert_ep(CoordinateType const& lat)
- {
- typedef math::detail::constants_on_spheroid
- <
- CoordinateType,
- Units
- > constants;
- return constants::quarter_period() - lat;
- }
- template <typename Units, bool IsEquatorial, typename T>
- static bool is_latitude_pole(T const& lat)
- {
- typedef math::detail::constants_on_spheroid
- <
- T,
- Units
- > constants;
- return math::equals(math::abs(IsEquatorial
- ? lat
- : math::latitude_convert_ep<Units>(lat)),
- constants::quarter_period());
- }
- template <typename Units, typename T>
- static bool is_longitude_antimeridian(T const& lon)
- {
- typedef math::detail::constants_on_spheroid
- <
- T,
- Units
- > constants;
- return math::equals(math::abs(lon), constants::half_period());
- }
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail
- {
- template <typename Units, bool IsEquatorial>
- struct latitude_convert_if_polar
- {
- template <typename T>
- static inline void apply(T & /*lat*/) {}
- };
- template <typename Units>
- struct latitude_convert_if_polar<Units, false>
- {
- template <typename T>
- static inline void apply(T & lat)
- {
- lat = latitude_convert_ep<Units>(lat);
- }
- };
- template <typename Units, typename CoordinateType, bool IsEquatorial = true>
- class normalize_spheroidal_coordinates
- {
- typedef constants_on_spheroid<CoordinateType, Units> constants;
- protected:
- static inline CoordinateType normalize_up(CoordinateType const& value)
- {
- return
- math::mod(value + constants::half_period(), constants::period())
- - constants::half_period();
- }
- static inline CoordinateType normalize_down(CoordinateType const& value)
- {
- return
- math::mod(value - constants::half_period(), constants::period())
- + constants::half_period();
- }
- public:
- static inline void apply(CoordinateType& longitude)
- {
- // normalize longitude
- if (math::equals(math::abs(longitude), constants::half_period()))
- {
- longitude = constants::half_period();
- }
- else if (longitude > constants::half_period())
- {
- longitude = normalize_up(longitude);
- if (math::equals(longitude, -constants::half_period()))
- {
- longitude = constants::half_period();
- }
- }
- else if (longitude < -constants::half_period())
- {
- longitude = normalize_down(longitude);
- }
- }
- static inline void apply(CoordinateType& longitude,
- CoordinateType& latitude,
- bool normalize_poles = true)
- {
- latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude);
- #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
- // normalize latitude
- if (math::larger(latitude, constants::half_period()))
- {
- latitude = normalize_up(latitude);
- }
- else if (math::smaller(latitude, -constants::half_period()))
- {
- latitude = normalize_down(latitude);
- }
- // fix latitude range
- if (latitude < constants::min_latitude())
- {
- latitude = -constants::half_period() - latitude;
- longitude -= constants::half_period();
- }
- else if (latitude > constants::max_latitude())
- {
- latitude = constants::half_period() - latitude;
- longitude -= constants::half_period();
- }
- #endif // BOOST_GEOMETRY_NORMALIZE_LATITUDE
- // normalize longitude
- apply(longitude);
- // finally normalize poles
- if (normalize_poles)
- {
- if (math::equals(math::abs(latitude), constants::max_latitude()))
- {
- // for the north and south pole we set the longitude to 0
- // (works for both radians and degrees)
- longitude = CoordinateType(0);
- }
- }
- latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude);
- #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
- BOOST_GEOMETRY_ASSERT(! math::larger(constants::min_latitude(), latitude));
- BOOST_GEOMETRY_ASSERT(! math::larger(latitude, constants::max_latitude()));
- #endif // BOOST_GEOMETRY_NORMALIZE_LATITUDE
- BOOST_GEOMETRY_ASSERT(! math::larger_or_equals(constants::min_longitude(), longitude));
- BOOST_GEOMETRY_ASSERT(! math::larger(longitude, constants::max_longitude()));
- }
- };
- template <typename Units, typename CoordinateType>
- inline void normalize_angle_loop(CoordinateType& angle)
- {
- typedef constants_on_spheroid<CoordinateType, Units> constants;
- CoordinateType const pi = constants::half_period();
- CoordinateType const two_pi = constants::period();
- while (angle > pi)
- angle -= two_pi;
- while (angle <= -pi)
- angle += two_pi;
- }
- template <typename Units, typename CoordinateType>
- inline void normalize_angle_cond(CoordinateType& angle)
- {
- typedef constants_on_spheroid<CoordinateType, Units> constants;
- CoordinateType const pi = constants::half_period();
- CoordinateType const two_pi = constants::period();
- if (angle > pi)
- angle -= two_pi;
- else if (angle <= -pi)
- angle += two_pi;
- }
- } // namespace detail
- #endif // DOXYGEN_NO_DETAIL
- /*!
- \brief Short utility to normalize the coordinates on a spheroid
- \tparam Units The units of the coordindate system in the spheroid
- \tparam CoordinateType The type of the coordinates
- \param longitude Longitude
- \param latitude Latitude
- \ingroup utility
- */
- template <typename Units, typename CoordinateType>
- inline void normalize_spheroidal_coordinates(CoordinateType& longitude,
- CoordinateType& latitude)
- {
- detail::normalize_spheroidal_coordinates
- <
- Units, CoordinateType
- >::apply(longitude, latitude);
- }
- template <typename Units, bool IsEquatorial, typename CoordinateType>
- inline void normalize_spheroidal_coordinates(CoordinateType& longitude,
- CoordinateType& latitude)
- {
- detail::normalize_spheroidal_coordinates
- <
- Units, CoordinateType, IsEquatorial
- >::apply(longitude, latitude);
- }
- /*!
- \brief Short utility to normalize the longitude on a spheroid.
- Note that in general both coordinates should be normalized at once.
- This utility is suitable e.g. for normalization of the difference of longitudes.
- \tparam Units The units of the coordindate system in the spheroid
- \tparam CoordinateType The type of the coordinates
- \param longitude Longitude
- \ingroup utility
- */
- template <typename Units, typename CoordinateType>
- inline void normalize_longitude(CoordinateType& longitude)
- {
- detail::normalize_spheroidal_coordinates
- <
- Units, CoordinateType
- >::apply(longitude);
- }
- /*!
- \brief Short utility to normalize the azimuth on a spheroid
- in the range (-180, 180].
- \tparam Units The units of the coordindate system in the spheroid
- \tparam CoordinateType The type of the coordinates
- \param angle Angle
- \ingroup utility
- */
- template <typename Units, typename CoordinateType>
- inline void normalize_azimuth(CoordinateType& angle)
- {
- normalize_longitude<Units, CoordinateType>(angle);
- }
- /*!
- \brief Normalize the given values.
- \tparam ValueType The type of the values
- \param x Value x
- \param y Value y
- TODO: adl1995 - Merge this function with
- formulas/vertex_longitude.hpp
- */
- template<typename ValueType>
- inline void normalize_unit_vector(ValueType& x, ValueType& y)
- {
- ValueType h = boost::math::hypot(x, y);
- BOOST_GEOMETRY_ASSERT(h > 0);
- x /= h; y /= h;
- }
- /*!
- \brief Short utility to calculate difference between two longitudes
- normalized in range (-180, 180].
- \tparam Units The units of the coordindate system in the spheroid
- \tparam CoordinateType The type of the coordinates
- \param longitude1 Longitude 1
- \param longitude2 Longitude 2
- \ingroup utility
- */
- template <typename Units, typename CoordinateType>
- inline CoordinateType longitude_distance_signed(CoordinateType const& longitude1,
- CoordinateType const& longitude2)
- {
- CoordinateType diff = longitude2 - longitude1;
- math::normalize_longitude<Units, CoordinateType>(diff);
- return diff;
- }
- /*!
- \brief Short utility to calculate difference between two longitudes
- normalized in range [0, 360).
- \tparam Units The units of the coordindate system in the spheroid
- \tparam CoordinateType The type of the coordinates
- \param longitude1 Longitude 1
- \param longitude2 Longitude 2
- \ingroup utility
- */
- template <typename Units, typename CoordinateType>
- inline CoordinateType longitude_distance_unsigned(CoordinateType const& longitude1,
- CoordinateType const& longitude2)
- {
- typedef math::detail::constants_on_spheroid
- <
- CoordinateType, Units
- > constants;
- CoordinateType const c0 = 0;
- CoordinateType diff = longitude_distance_signed<Units>(longitude1, longitude2);
- if (diff < c0) // (-180, 180] -> [0, 360)
- {
- diff += constants::period();
- }
- return diff;
- }
- /*!
- \brief The abs difference between longitudes in range [0, 180].
- \tparam Units The units of the coordindate system in the spheroid
- \tparam CoordinateType The type of the coordinates
- \param longitude1 Longitude 1
- \param longitude2 Longitude 2
- \ingroup utility
- */
- template <typename Units, typename CoordinateType>
- inline CoordinateType longitude_difference(CoordinateType const& longitude1,
- CoordinateType const& longitude2)
- {
- return math::abs(math::longitude_distance_signed<Units>(longitude1, longitude2));
- }
- template <typename Units, typename CoordinateType>
- inline CoordinateType longitude_interval_distance_signed(CoordinateType const& longitude_a1,
- CoordinateType const& longitude_a2,
- CoordinateType const& longitude_b)
- {
- CoordinateType const c0 = 0;
- CoordinateType dist_a12 = longitude_distance_signed<Units>(longitude_a1, longitude_a2);
- CoordinateType dist_a1b = longitude_distance_signed<Units>(longitude_a1, longitude_b);
- if (dist_a12 < c0)
- {
- dist_a12 = -dist_a12;
- dist_a1b = -dist_a1b;
- }
- return dist_a1b < c0 ? dist_a1b
- : dist_a1b > dist_a12 ? dist_a1b - dist_a12
- : c0;
- }
- } // namespace math
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP
|