diff options
Diffstat (limited to 'boost/geometry/util')
-rw-r--r-- | boost/geometry/util/math.hpp | 171 | ||||
-rw-r--r-- | boost/geometry/util/normalize_spheroidal_box_coordinates.hpp | 160 | ||||
-rw-r--r-- | boost/geometry/util/normalize_spheroidal_coordinates.hpp | 218 | ||||
-rw-r--r-- | boost/geometry/util/range.hpp | 28 |
4 files changed, 545 insertions, 32 deletions
diff --git a/boost/geometry/util/math.hpp b/boost/geometry/util/math.hpp index 4042f4e4cd..d84b11f480 100644 --- a/boost/geometry/util/math.hpp +++ b/boost/geometry/util/math.hpp @@ -26,12 +26,11 @@ #include <boost/core/ignore_unused.hpp> #include <boost/math/constants/constants.hpp> -#ifdef BOOST_GEOMETRY_SQRT_CHECK_FINITENESS #include <boost/math/special_functions/fpclassify.hpp> -#endif // BOOST_GEOMETRY_SQRT_CHECK_FINITENESS -#include <boost/math/special_functions/round.hpp> +//#include <boost/math/special_functions/round.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/type_traits/is_fundamental.hpp> +#include <boost/type_traits/is_integral.hpp> #include <boost/geometry/util/select_most_precise.hpp> @@ -86,6 +85,9 @@ struct abs<T, true> { static inline T apply(T const& value) { + using ::fabs; + using std::fabs; // for long double + return fabs(value); } }; @@ -161,7 +163,17 @@ struct equals<Type, true> return true; } - return abs<Type>::apply(a - b) <= std::numeric_limits<Type>::epsilon() * policy.apply(a, b); + if (boost::math::isfinite(a) && boost::math::isfinite(b)) + { + // If a is INF and b is e.g. 0, the expression below returns true + // but the values are obviously not equal, hence the condition + return abs<Type>::apply(a - b) + <= std::numeric_limits<Type>::epsilon() * policy.apply(a, b); + } + else + { + return a == b; + } } }; @@ -295,8 +307,66 @@ struct square_root<T, true> }; + +template +< + typename T, + bool IsFundemantal = boost::is_fundamental<T>::value /* false */ +> +struct modulo +{ + typedef T return_type; + + static inline T apply(T const& value1, T const& value2) + { + // for non-fundamental number types assume that a free + // function mod() is defined either: + // 1) at T's scope, or + // 2) at global scope + return mod(value1, value2); + } +}; + +template +< + typename Fundamental, + bool IsIntegral = boost::is_integral<Fundamental>::value +> +struct modulo_for_fundamental +{ + typedef Fundamental return_type; + + static inline Fundamental apply(Fundamental const& value1, + Fundamental const& value2) + { + return value1 % value2; + } +}; + +// specialization for floating-point numbers +template <typename Fundamental> +struct modulo_for_fundamental<Fundamental, false> +{ + typedef Fundamental return_type; + + static inline Fundamental apply(Fundamental const& value1, + Fundamental const& value2) + { + return std::fmod(value1, value2); + } +}; + +// specialization for fundamental number type +template <typename Fundamental> +struct modulo<Fundamental, true> + : modulo_for_fundamental<Fundamental> +{}; + + + /*! -\brief Short construct to enable partial specialization for PI, currently not possible in Math. +\brief Short constructs to enable partial specialization for PI, 2*PI + and PI/2, currently not possible in Math. */ template <typename T> struct define_pi @@ -309,6 +379,26 @@ struct define_pi }; template <typename T> +struct define_two_pi +{ + static inline T apply() + { + // Default calls Boost.Math + return boost::math::constants::two_pi<T>(); + } +}; + +template <typename T> +struct define_half_pi +{ + static inline T apply() + { + // Default calls Boost.Math + return boost::math::constants::half_pi<T>(); + } +}; + +template <typename T> struct relaxed_epsilon { static inline T apply(const T& factor) @@ -321,7 +411,7 @@ struct relaxed_epsilon template <typename Result, typename Source, bool ResultIsInteger = std::numeric_limits<Result>::is_integer, bool SourceIsInteger = std::numeric_limits<Source>::is_integer> -struct round +struct rounding_cast { static inline Result apply(Source const& v) { @@ -329,16 +419,25 @@ struct round } }; +// TtoT +template <typename Source, bool ResultIsInteger, bool SourceIsInteger> +struct rounding_cast<Source, Source, ResultIsInteger, SourceIsInteger> +{ + static inline Source apply(Source const& v) + { + return v; + } +}; + // FtoI template <typename Result, typename Source> -struct round<Result, Source, true, false> +struct rounding_cast<Result, Source, true, false> { static inline Result apply(Source const& v) { - namespace bmp = boost::math::policies; - // ignore rounding errors for backward compatibility - typedef bmp::policy< bmp::rounding_error<bmp::ignore_error> > policy; - return boost::numeric_cast<Result>(boost::math::round(v, policy())); + return boost::numeric_cast<Result>(v < Source(0) ? + v - Source(0.5) : + v + Source(0.5)); } }; @@ -350,6 +449,12 @@ template <typename T> inline T pi() { return detail::define_pi<T>::apply(); } template <typename T> +inline T two_pi() { return detail::define_two_pi<T>::apply(); } + +template <typename T> +inline T half_pi() { return detail::define_half_pi<T>::apply(); } + +template <typename T> inline T relaxed_epsilon(T const& factor) { return detail::relaxed_epsilon<T>::apply(factor); @@ -408,9 +513,20 @@ inline bool larger(T1 const& a, T2 const& b) } +template <typename T> +inline T d2r() +{ + static T const conversion_coefficient = geometry::math::pi<T>() / T(180.0); + return conversion_coefficient; +} + +template <typename T> +inline T r2d() +{ + static T const conversion_coefficient = T(180.0) / geometry::math::pi<T>(); + return conversion_coefficient; +} -double const d2r = geometry::math::pi<double>() / 180.0; -double const r2d = 1.0 / d2r; /*! \brief Calculates the haversine of an angle @@ -455,6 +571,24 @@ sqrt(T const& value) } /*! +\brief Short utility to return the modulo of two values +\ingroup utility +\param value1 First value +\param value2 Second value +\return The result of the modulo operation on the (ordered) pair +(value1, value2) +*/ +template <typename T> +inline typename detail::modulo<T>::return_type +mod(T const& value1, T const& value2) +{ + return detail::modulo + < + T, boost::is_fundamental<T>::value + >::apply(value1, value2); +} + +/*! \brief Short utility to workaround gcc/clang problem that abs is converting to integer and that older versions of MSVC does not support abs of long long... \ingroup utility @@ -470,23 +604,24 @@ inline T abs(T const& value) \ingroup utility */ template <typename T> -static inline int sign(T const& value) +inline int sign(T const& value) { T const zero = T(); return value > zero ? 1 : value < zero ? -1 : 0; } /*! -\brief Short utility to calculate the rounded value of a number. +\brief Short utility to cast a value possibly rounding it to the nearest + integral value. \ingroup utility \note If the source T is NOT an integral type and Result is an integral type the value is rounded towards the closest integral value. Otherwise it's - casted. + casted without rounding. */ template <typename Result, typename T> -inline Result round(T const& v) +inline Result rounding_cast(T const& v) { - return detail::round<Result, T>::apply(v); + return detail::rounding_cast<Result, T>::apply(v); } } // namespace math diff --git a/boost/geometry/util/normalize_spheroidal_box_coordinates.hpp b/boost/geometry/util/normalize_spheroidal_box_coordinates.hpp new file mode 100644 index 0000000000..eb947bb092 --- /dev/null +++ b/boost/geometry/util/normalize_spheroidal_box_coordinates.hpp @@ -0,0 +1,160 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_BOX_COORDINATES_HPP +#define BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_BOX_COORDINATES_HPP + +#include <boost/geometry/core/assert.hpp> +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> + + +namespace boost { namespace geometry +{ + +namespace math +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + + +template <typename Units, typename CoordinateType> +class normalize_spheroidal_box_coordinates +{ +private: + typedef normalize_spheroidal_coordinates<Units, CoordinateType> normalize; + typedef constants_on_spheroid<CoordinateType, Units> constants; + + static inline bool is_band(CoordinateType const& longitude1, + CoordinateType const& longitude2) + { + return ! math::smaller(math::abs(longitude1 - longitude2), + constants::period()); + } + +public: + static inline void apply(CoordinateType& longitude1, + CoordinateType& latitude1, + CoordinateType& longitude2, + CoordinateType& latitude2, + bool band) + { + normalize::apply(longitude1, latitude1, false); + normalize::apply(longitude2, latitude2, false); + + if (math::equals(latitude1, constants::min_latitude()) + && math::equals(latitude2, constants::min_latitude())) + { + // box degenerates to the south pole + longitude1 = longitude2 = CoordinateType(0); + } + else if (math::equals(latitude1, constants::max_latitude()) + && math::equals(latitude2, constants::max_latitude())) + { + // box degenerates to the north pole + longitude1 = longitude2 = CoordinateType(0); + } + else if (band) + { + // the box is a band between two small circles (parallel + // to the equator) on the spheroid + longitude1 = constants::min_longitude(); + longitude2 = constants::max_longitude(); + } + else if (longitude1 > longitude2) + { + // the box crosses the antimeridian, so we need to adjust + // the longitudes + longitude2 += constants::period(); + } + +#ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE + BOOST_GEOMETRY_ASSERT(! math::larger(latitude1, latitude2)); + BOOST_GEOMETRY_ASSERT(! math::smaller(latitude1, constants::min_latitude())); + BOOST_GEOMETRY_ASSERT(! math::larger(latitude2, constants::max_latitude())); +#endif + + BOOST_GEOMETRY_ASSERT(! math::larger(longitude1, longitude2)); + BOOST_GEOMETRY_ASSERT(! math::smaller(longitude1, constants::min_longitude())); + BOOST_GEOMETRY_ASSERT + (! math::larger(longitude2 - longitude1, constants::period())); + } + + static inline void apply(CoordinateType& longitude1, + CoordinateType& latitude1, + CoordinateType& longitude2, + CoordinateType& latitude2) + { + bool const band = is_band(longitude1, longitude2); + + apply(longitude1, latitude1, longitude2, latitude2, band); + } +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +/*! +\brief Short utility to normalize the coordinates of a box on a spheroid +\tparam Units The units of the coordindate system in the spheroid +\tparam CoordinateType The type of the coordinates +\param longitude1 Minimum longitude of the box +\param latitude1 Minimum latitude of the box +\param longitude2 Maximum longitude of the box +\param latitude2 Maximum latitude of the box +\ingroup utility +*/ +template <typename Units, typename CoordinateType> +inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1, + CoordinateType& latitude1, + CoordinateType& longitude2, + CoordinateType& latitude2) +{ + detail::normalize_spheroidal_box_coordinates + < + Units, CoordinateType + >::apply(longitude1, latitude1, longitude2, latitude2); +} + +/*! +\brief Short utility to normalize the coordinates of a box on a spheroid +\tparam Units The units of the coordindate system in the spheroid +\tparam CoordinateType The type of the coordinates +\param longitude1 Minimum longitude of the box +\param latitude1 Minimum latitude of the box +\param longitude2 Maximum longitude of the box +\param latitude2 Maximum latitude of the box +\param band Indicates whether the box should be treated as a band or + not and avoid the computation done in the other version of the function +\ingroup utility +*/ +template <typename Units, typename CoordinateType> +inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1, + CoordinateType& latitude1, + CoordinateType& longitude2, + CoordinateType& latitude2, + bool band) +{ + detail::normalize_spheroidal_box_coordinates + < + Units, CoordinateType + >::apply(longitude1, latitude1, longitude2, latitude2, band); +} + + +} // namespace math + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_BOX_COORDINATES_HPP diff --git a/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/boost/geometry/util/normalize_spheroidal_coordinates.hpp new file mode 100644 index 0000000000..72dfa5a6f1 --- /dev/null +++ b/boost/geometry/util/normalize_spheroidal_coordinates.hpp @@ -0,0 +1,218 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// 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 +{ + + +template <typename CoordinateType, typename Units> +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 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, degree> +{ + static inline CoordinateType period() + { + return CoordinateType(360.0); + } + + static inline CoordinateType half_period() + { + return CoordinateType(180.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 Units, typename CoordinateType> +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, + CoordinateType& latitude, + bool normalize_poles = true) + { +#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 + 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); + } + + // 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); + } + } + +#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::smaller(constants::min_longitude(), longitude)); + BOOST_GEOMETRY_ASSERT(! math::larger(longitude, constants::max_longitude())); + } +}; + + +} // 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); +} + + +} // namespace math + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_UTIL_NORMALIZE_SPHEROIDAL_COORDINATES_HPP diff --git a/boost/geometry/util/range.hpp b/boost/geometry/util/range.hpp index cf69413411..0f480df58a 100644 --- a/boost/geometry/util/range.hpp +++ b/boost/geometry/util/range.hpp @@ -16,7 +16,6 @@ #include <algorithm> -#include <boost/assert.hpp> #include <boost/concept_check.hpp> #include <boost/config.hpp> #include <boost/range/concepts.hpp> @@ -26,6 +25,7 @@ #include <boost/range/size.hpp> #include <boost/type_traits/is_convertible.hpp> +#include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/mutable_range.hpp> namespace boost { namespace geometry { namespace range { @@ -59,7 +59,7 @@ inline typename boost::range_iterator<RandomAccessRange const>::type pos(RandomAccessRange const& rng, typename boost::range_size<RandomAccessRange const>::type i) { - BOOST_ASSERT(i <= boost::size(rng)); + BOOST_GEOMETRY_ASSERT(i <= boost::size(rng)); return detail::pos<RandomAccessRange const>::apply(rng, i); } @@ -72,7 +72,7 @@ inline typename boost::range_iterator<RandomAccessRange>::type pos(RandomAccessRange & rng, typename boost::range_size<RandomAccessRange>::type i) { - BOOST_ASSERT(i <= boost::size(rng)); + BOOST_GEOMETRY_ASSERT(i <= boost::size(rng)); return detail::pos<RandomAccessRange>::apply(rng, i); } @@ -85,7 +85,7 @@ inline typename boost::range_reference<RandomAccessRange const>::type at(RandomAccessRange const& rng, typename boost::range_size<RandomAccessRange const>::type i) { - BOOST_ASSERT(i < boost::size(rng)); + BOOST_GEOMETRY_ASSERT(i < boost::size(rng)); return * detail::pos<RandomAccessRange const>::apply(rng, i); } @@ -98,7 +98,7 @@ inline typename boost::range_reference<RandomAccessRange>::type at(RandomAccessRange & rng, typename boost::range_size<RandomAccessRange>::type i) { - BOOST_ASSERT(i < boost::size(rng)); + BOOST_GEOMETRY_ASSERT(i < boost::size(rng)); return * detail::pos<RandomAccessRange>::apply(rng, i); } @@ -110,7 +110,7 @@ template <typename Range> inline typename boost::range_reference<Range const>::type front(Range const& rng) { - BOOST_ASSERT(!boost::empty(rng)); + BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); return *boost::begin(rng); } @@ -122,7 +122,7 @@ template <typename Range> inline typename boost::range_reference<Range>::type front(Range & rng) { - BOOST_ASSERT(!boost::empty(rng)); + BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); return *boost::begin(rng); } @@ -137,7 +137,7 @@ inline typename boost::range_reference<BidirectionalRange const>::type back(BidirectionalRange const& rng) { BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept<BidirectionalRange const> )); - BOOST_ASSERT(!boost::empty(rng)); + BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); return *(boost::rbegin(rng)); } @@ -150,7 +150,7 @@ inline typename boost::range_reference<BidirectionalRange>::type back(BidirectionalRange & rng) { BOOST_RANGE_CONCEPT_ASSERT((boost::BidirectionalRangeConcept<BidirectionalRange>)); - BOOST_ASSERT(!boost::empty(rng)); + BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); return *(boost::rbegin(rng)); } @@ -200,7 +200,7 @@ inline void resize(Range & rng, template <typename Range> inline void pop_back(Range & rng) { - BOOST_ASSERT(!boost::empty(rng)); + BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); range::resize(rng, boost::size(rng) - 1); } @@ -260,8 +260,8 @@ inline typename boost::range_iterator<Range>::type erase(Range & rng, typename boost::range_iterator<Range>::type it) { - BOOST_ASSERT(!boost::empty(rng)); - BOOST_ASSERT(it != boost::end(rng)); + BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); + BOOST_GEOMETRY_ASSERT(it != boost::end(rng)); typename boost::range_difference<Range>::type const d = std::distance(boost::begin(rng), it); @@ -314,10 +314,10 @@ erase(Range & rng, { typename boost::range_difference<Range>::type const diff = std::distance(first, last); - BOOST_ASSERT(diff >= 0); + BOOST_GEOMETRY_ASSERT(diff >= 0); std::size_t const count = static_cast<std::size_t>(diff); - BOOST_ASSERT(count <= boost::size(rng)); + BOOST_GEOMETRY_ASSERT(count <= boost::size(rng)); if ( count > 0 ) { |