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

type; Chris@16: }; Chris@16: Chris@16: /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef copy_per_coordinate type; Chris@16: }; Chris@16: Chris@16: /// Specialization to transform from degree to radian for any coordinate system / point type combination Chris@16: template class CoordSys, typename P1, typename P2> Chris@16: struct default_strategy, CoordSys, 2, 2, P1, P2> Chris@16: { Chris@16: typedef degree_radian_vv type; Chris@16: }; Chris@16: Chris@16: /// Specialization to transform from radian to degree for any coordinate system / point type combination Chris@16: template class CoordSys, typename P1, typename P2> Chris@16: struct default_strategy, CoordSys, 2, 2, P1, P2> Chris@16: { Chris@16: typedef degree_radian_vv type; Chris@16: }; Chris@16: Chris@16: Chris@16: /// Specialization degree->radian in 3D Chris@16: template class CoordSys, typename P1, typename P2> Chris@16: struct default_strategy, CoordSys, 3, 3, P1, P2> Chris@16: { Chris@16: typedef degree_radian_vv_3 type; Chris@16: }; Chris@16: Chris@16: /// Specialization radian->degree in 3D Chris@16: template class CoordSys, typename P1, typename P2> Chris@16: struct default_strategy, CoordSys, 3, 3, P1, P2> Chris@16: { Chris@16: typedef degree_radian_vv_3 type; Chris@16: }; Chris@16: Chris@16: /// Specialization to transform from unit sphere(phi,theta) to XYZ Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_spherical_polar_2_to_cartesian_3 type; Chris@16: }; Chris@16: Chris@16: /// Specialization to transform from sphere(phi,theta,r) to XYZ Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_spherical_polar_3_to_cartesian_3 type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_spherical_equatorial_2_to_cartesian_3 type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_spherical_equatorial_3_to_cartesian_3 type; Chris@16: }; Chris@16: Chris@16: /// Specialization to transform from XYZ to unit sphere(phi,theta) Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_cartesian_3_to_spherical_polar_2 type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_cartesian_3_to_spherical_equatorial_2 type; Chris@16: }; Chris@16: Chris@16: /// Specialization to transform from XYZ to sphere(phi,theta,r) Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_cartesian_3_to_spherical_polar_3 type; Chris@16: }; Chris@16: template Chris@16: struct default_strategy Chris@16: { Chris@16: typedef from_cartesian_3_to_spherical_equatorial_3 type; Chris@16: }; Chris@16: Chris@16: Chris@16: } // namespace services Chris@16: Chris@16: Chris@16: #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS Chris@16: Chris@16: Chris@16: }} // namespace strategy::transform Chris@16: Chris@16: Chris@16: }} // namespace boost::geometry Chris@16: Chris@16: #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP