// 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 #include #include #include #include #include #include #include #include #include #include #include #include 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 class F > struct transform_coordinates { template static inline void transform(Src const& source, Dst& dest, T value) { typedef typename select_coordinate_type::type coordinate_type; F function; set(dest, boost::numeric_cast(function(get(source), value))); transform_coordinates::transform(source, dest, value); } }; template < typename Src, typename Dst, std::size_t N, template class F > struct transform_coordinates { template 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 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 struct copy_per_coordinate { inline bool apply(P1 const& p1, P2& p2) const { // Defensive check, dimensions are equal, selected by specialization assert_dimension_equal(); 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 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(); assert_dimension(); typedef typename promote_floating_point < typename select_coordinate_type::type >::type calculation_type; detail::transform_coordinates < P1, P2, 0, 2, F >::transform(p1, p2, math::d2r()); return true; } }; template class F> struct degree_radian_vv_3 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); assert_dimension(); typedef typename promote_floating_point < typename select_coordinate_type::type >::type calculation_type; detail::transform_coordinates < P1, P2, 0, 2, F >::transform(p1, p2, math::d2r()); // 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 inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p) { assert_dimension(); // 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 inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p) { assert_dimension(); // 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 inline bool cartesian_to_spherical2(T x, T y, T z, P& p) { assert_dimension(); // 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 inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p) { assert_dimension(); set_from_radian<0>(p, atan2(y, x)); set_from_radian<1>(p, asin(z)); return true; } template inline bool cartesian_to_spherical3(T x, T y, T z, P& p) { assert_dimension(); // 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 inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p) { assert_dimension(); // 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 struct from_spherical_polar_2_to_cartesian_3 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2); return true; } }; template struct from_spherical_equatorial_2_to_cartesian_3 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); 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 struct from_spherical_polar_3_to_cartesian_3 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); detail::spherical_polar_to_cartesian( get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2); return true; } }; template struct from_spherical_equatorial_3_to_cartesian_3 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); 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 struct from_cartesian_3_to_spherical_polar_2 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2); } }; template struct from_cartesian_3_to_spherical_equatorial_2 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); 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 struct from_cartesian_3_to_spherical_polar_3 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2); } }; template struct from_cartesian_3_to_spherical_equatorial_3 { inline bool apply(P1 const& p1, P2& p2) const { assert_dimension(); 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 struct default_strategy { typedef copy_direct

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