123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
- // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
- // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
- // This file was modified by Oracle on 2015.
- // Modifications copyright (c) 2015 Oracle and/or its affiliates.
- // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
- // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
- // (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_STRATEGY_TRANSFORM_HPP
- #define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
- #include <cstddef>
- #include <cmath>
- #include <functional>
- #include <boost/numeric/conversion/cast.hpp>
- #include <boost/geometry/algorithms/convert.hpp>
- #include <boost/geometry/arithmetic/arithmetic.hpp>
- #include <boost/geometry/core/access.hpp>
- #include <boost/geometry/core/radian_access.hpp>
- #include <boost/geometry/core/coordinate_dimension.hpp>
- #include <boost/geometry/strategies/transform.hpp>
- #include <boost/geometry/util/math.hpp>
- #include <boost/geometry/util/promote_floating_point.hpp>
- #include <boost/geometry/util/select_coordinate_type.hpp>
- namespace boost { namespace geometry
- {
- namespace strategy { namespace transform
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail
- {
- template
- <
- typename Src, typename Dst,
- std::size_t D, std::size_t N,
- template <typename> class F
- >
- struct transform_coordinates
- {
- template <typename T>
- static inline void transform(Src const& source, Dst& dest, T value)
- {
- typedef typename select_coordinate_type<Src, Dst>::type coordinate_type;
- F<coordinate_type> function;
- set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value)));
- transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value);
- }
- };
- template
- <
- typename Src, typename Dst,
- std::size_t N,
- template <typename> class F
- >
- struct transform_coordinates<Src, Dst, N, N, F>
- {
- template <typename T>
- static inline void transform(Src const& , Dst& , T )
- {
- }
- };
- } // namespace detail
- #endif // DOXYGEN_NO_DETAIL
- /*!
- \brief Transformation strategy to copy one point to another using assignment operator
- \ingroup transform
- \tparam P point type
- */
- template <typename P>
- struct copy_direct
- {
- inline bool apply(P const& p1, P& p2) const
- {
- p2 = p1;
- return true;
- }
- };
- /*!
- \brief Transformation strategy to do copy a point, copying per coordinate.
- \ingroup transform
- \tparam P1 first point type
- \tparam P2 second point type
- */
- template <typename P1, typename P2>
- struct copy_per_coordinate
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- // Defensive check, dimensions are equal, selected by specialization
- assert_dimension_equal<P1, P2>();
- geometry::convert(p1, p2);
- return true;
- }
- };
- /*!
- \brief Transformation strategy to go from degree to radian and back
- \ingroup transform
- \tparam P1 first point type
- \tparam P2 second point type
- \tparam F additional functor to divide or multiply with d2r
- */
- template <typename P1, typename P2, template <typename> class F>
- struct degree_radian_vv
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- // Spherical coordinates always have 2 coordinates measured in angles
- // The optional third one is distance/height, provided in another strategy
- // Polar coordinates having one angle, will be also in another strategy
- assert_dimension<P1, 2>();
- assert_dimension<P2, 2>();
- typedef typename promote_floating_point
- <
- typename select_coordinate_type<P1, P2>::type
- >::type calculation_type;
- detail::transform_coordinates
- <
- P1, P2, 0, 2, F
- >::transform(p1, p2, math::d2r<calculation_type>());
- return true;
- }
- };
- template <typename P1, typename P2, template <typename> class F>
- struct degree_radian_vv_3
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- assert_dimension<P2, 3>();
- typedef typename promote_floating_point
- <
- typename select_coordinate_type<P1, P2>::type
- >::type calculation_type;
- detail::transform_coordinates
- <
- P1, P2, 0, 2, F
- >::transform(p1, p2, math::d2r<calculation_type>());
- // Copy height or other third dimension
- set<2>(p2, get<2>(p1));
- return true;
- }
- };
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail
- {
- /// Helper function for conversion, phi/theta are in radians
- template <typename P, typename T, typename R>
- inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p)
- {
- assert_dimension<P, 3>();
- // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
- // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
- // https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
- // http://en.citizendium.org/wiki/Spherical_polar_coordinates
- // Phi = first, theta is second, r is third, see documentation on cs::spherical
- // (calculations are splitted to implement user defined types)
- T r_sin_theta = r;
- T r_cos_theta = r;
- r_sin_theta *= sin(theta);
- r_cos_theta *= cos(theta);
- set<0>(p, r_sin_theta * cos(phi));
- set<1>(p, r_sin_theta * sin(phi));
- set<2>(p, r_cos_theta);
- }
- /// Helper function for conversion, lambda/delta (lon lat) are in radians
- template <typename P, typename T, typename R>
- inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
- {
- assert_dimension<P, 3>();
- // http://mathworld.wolfram.com/GreatCircle.html
- // http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
- T r_cos_delta = r;
- T r_sin_delta = r;
- r_cos_delta *= cos(delta);
- r_sin_delta *= sin(delta);
- set<0>(p, r_cos_delta * cos(lambda));
- set<1>(p, r_cos_delta * sin(lambda));
- set<2>(p, r_sin_delta);
- }
- /// Helper function for conversion
- template <typename P, typename T>
- inline bool cartesian_to_spherical2(T x, T y, T z, P& p)
- {
- assert_dimension<P, 2>();
- // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
- #if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE)
- // TODO: MAYBE ONLY IF TO BE CHECKED?
- T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z);
- // Unit sphere, so r should be 1
- if (geometry::math::abs(r - 1.0) > T(1e-6))
- {
- return false;
- }
- // end todo
- #endif
- set_from_radian<0>(p, atan2(y, x));
- set_from_radian<1>(p, acos(z));
- return true;
- }
- template <typename P, typename T>
- inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
- {
- assert_dimension<P, 2>();
- set_from_radian<0>(p, atan2(y, x));
- set_from_radian<1>(p, asin(z));
- return true;
- }
- template <typename P, typename T>
- inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
- {
- assert_dimension<P, 3>();
- // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
- T const r = math::sqrt(x * x + y * y + z * z);
- set<2>(p, r);
- set_from_radian<0>(p, atan2(y, x));
- if (r > 0.0)
- {
- set_from_radian<1>(p, acos(z / r));
- return true;
- }
- return false;
- }
- template <typename P, typename T>
- inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
- {
- assert_dimension<P, 3>();
- // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
- T const r = math::sqrt(x * x + y * y + z * z);
- set<2>(p, r);
- set_from_radian<0>(p, atan2(y, x));
- if (r > 0.0)
- {
- set_from_radian<1>(p, asin(z / r));
- return true;
- }
- return false;
- }
- } // namespace detail
- #endif // DOXYGEN_NO_DETAIL
- /*!
- \brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z)
- \details on Unit sphere
- \ingroup transform
- \tparam P1 first point type
- \tparam P2 second point type
- */
- template <typename P1, typename P2>
- struct from_spherical_polar_2_to_cartesian_3
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 2>();
- detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
- return true;
- }
- };
- template <typename P1, typename P2>
- struct from_spherical_equatorial_2_to_cartesian_3
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 2>();
- detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
- return true;
- }
- };
- /*!
- \brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z)
- \ingroup transform
- \tparam P1 first point type
- \tparam P2 second point type
- */
- template <typename P1, typename P2>
- struct from_spherical_polar_3_to_cartesian_3
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- detail::spherical_polar_to_cartesian(
- get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
- return true;
- }
- };
- template <typename P1, typename P2>
- struct from_spherical_equatorial_3_to_cartesian_3
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- detail::spherical_equatorial_to_cartesian(
- get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
- return true;
- }
- };
- /*!
- \brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta)
- \details on Unit sphere
- \ingroup transform
- \tparam P1 first point type
- \tparam P2 second point type
- \note If x,y,z point is not lying on unit sphere, transformation will return false
- */
- template <typename P1, typename P2>
- struct from_cartesian_3_to_spherical_polar_2
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
- }
- };
- template <typename P1, typename P2>
- struct from_cartesian_3_to_spherical_equatorial_2
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
- }
- };
- /*!
- \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r)
- \ingroup transform
- \tparam P1 first point type
- \tparam P2 second point type
- */
- template <typename P1, typename P2>
- struct from_cartesian_3_to_spherical_polar_3
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
- }
- };
- template <typename P1, typename P2>
- struct from_cartesian_3_to_spherical_equatorial_3
- {
- inline bool apply(P1 const& p1, P2& p2) const
- {
- assert_dimension<P1, 3>();
- return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
- }
- };
- #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
- namespace services
- {
- /// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied
- template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
- struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
- {
- typedef copy_direct<P> type;
- };
- /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
- template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
- struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
- {
- typedef copy_per_coordinate<P1, P2> type;
- };
- /// Specialization to transform from degree to radian for any coordinate system / point type combination
- template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
- struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
- {
- typedef degree_radian_vv<P1, P2, std::multiplies> type;
- };
- /// Specialization to transform from radian to degree for any coordinate system / point type combination
- template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
- struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
- {
- typedef degree_radian_vv<P1, P2, std::divides> type;
- };
- /// Specialization degree->radian in 3D
- template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
- struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
- {
- typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
- };
- /// Specialization radian->degree in 3D
- template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
- struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
- {
- typedef degree_radian_vv_3<P1, P2, std::divides> type;
- };
- /// Specialization to transform from unit sphere(phi,theta) to XYZ
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
- {
- typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type;
- };
- /// Specialization to transform from sphere(phi,theta,r) to XYZ
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
- {
- typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type;
- };
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
- {
- typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type;
- };
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
- {
- typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type;
- };
- /// Specialization to transform from XYZ to unit sphere(phi,theta)
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
- {
- typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type;
- };
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
- {
- typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type;
- };
- /// Specialization to transform from XYZ to sphere(phi,theta,r)
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
- {
- typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type;
- };
- template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
- struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
- {
- typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
- };
- } // namespace services
- #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
- }} // namespace strategy::transform
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
|