| // Boost.Geometry (aka GGL, Generic Geometry Library) |
| |
| // Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. |
| |
| // Use, modification and distribution is subject to the Boost Software License, |
| // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP |
| #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP |
| |
| #include <boost/math/constants/constants.hpp> |
| |
| #include <boost/geometry/core/cs.hpp> |
| #include <boost/geometry/core/tags.hpp> |
| #include <boost/geometry/strategies/compare.hpp> |
| #include <boost/geometry/util/math.hpp> |
| |
| |
| namespace boost { namespace geometry |
| { |
| |
| |
| namespace strategy { namespace compare |
| { |
| |
| |
| #ifndef DOXYGEN_NO_DETAIL |
| namespace detail |
| { |
| |
| template <typename Units> |
| struct shift |
| { |
| }; |
| |
| template <> |
| struct shift<degree> |
| { |
| static inline double full() { return 360.0; } |
| static inline double half() { return 180.0; } |
| }; |
| |
| template <> |
| struct shift<radian> |
| { |
| static inline double full() { return 2.0 * boost::math::constants::pi<double>(); } |
| static inline double half() { return boost::math::constants::pi<double>(); } |
| }; |
| |
| } // namespace detail |
| #endif |
| |
| /*! |
| \brief Compare (in one direction) strategy for spherical coordinates |
| \ingroup strategies |
| \tparam Point point-type |
| \tparam Dimension dimension |
| */ |
| template <typename CoordinateType, typename Units, typename Compare> |
| struct circular_comparator |
| { |
| static inline CoordinateType put_in_range(CoordinateType const& c, |
| double min_border, double max_border) |
| { |
| CoordinateType value = c; |
| while (value < min_border) |
| { |
| value += detail::shift<Units>::full(); |
| } |
| while (value > max_border) |
| { |
| value -= detail::shift<Units>::full(); |
| } |
| return value; |
| } |
| |
| inline bool operator()(CoordinateType const& c1, CoordinateType const& c2) const |
| { |
| Compare compare; |
| |
| // Check situation that one of them is e.g. std::numeric_limits. |
| static const double full = detail::shift<Units>::full(); |
| double mx = 10.0 * full; |
| if (c1 < -mx || c1 > mx || c2 < -mx || c2 > mx) |
| { |
| // do normal comparison, using circular is not useful |
| return compare(c1, c2); |
| } |
| |
| static const double half = full / 2.0; |
| CoordinateType v1 = put_in_range(c1, -half, half); |
| CoordinateType v2 = put_in_range(c2, -half, half); |
| |
| // Two coordinates on a circle are |
| // at max <= half a circle away from each other. |
| // So if it is more, shift origin. |
| CoordinateType diff = geometry::math::abs(v1 - v2); |
| if (diff > half) |
| { |
| v1 = put_in_range(v1, 0, full); |
| v2 = put_in_range(v2, 0, full); |
| } |
| |
| return compare(v1, v2); |
| } |
| }; |
| |
| }} // namespace strategy::compare |
| |
| #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS |
| |
| // Specialize for the longitude (dim 0) |
| template |
| < |
| typename Point, |
| template<typename> class CoordinateSystem, |
| typename Units |
| > |
| struct strategy_compare<spherical_polar_tag, 1, Point, CoordinateSystem<Units>, 0> |
| { |
| typedef typename coordinate_type<Point>::type coordinate_type; |
| typedef strategy::compare::circular_comparator |
| < |
| coordinate_type, |
| Units, |
| std::less<coordinate_type> |
| > type; |
| }; |
| |
| template |
| < |
| typename Point, |
| template<typename> class CoordinateSystem, |
| typename Units |
| > |
| struct strategy_compare<spherical_polar_tag, -1, Point, CoordinateSystem<Units>, 0> |
| { |
| typedef typename coordinate_type<Point>::type coordinate_type; |
| typedef strategy::compare::circular_comparator |
| < |
| coordinate_type, |
| Units, |
| std::greater<coordinate_type> |
| > type; |
| }; |
| |
| #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS |
| |
| }} // namespace boost::geometry |
| |
| #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP |