Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:50

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
0005 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
0006 
0007 // This file was modified by Oracle on 2015.
0008 // Modifications copyright (c) 2015 Oracle and/or its affiliates.
0009 
0010 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
0011 
0012 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
0013 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
0014 
0015 // Use, modification and distribution is subject to the Boost Software License,
0016 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0017 // http://www.boost.org/LICENSE_1_0.txt)
0018 
0019 #ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
0020 #define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
0021 
0022 #include <cstddef>
0023 #include <cmath>
0024 #include <functional>
0025 
0026 #include <boost/numeric/conversion/cast.hpp>
0027 
0028 #include <boost/geometry/algorithms/convert.hpp>
0029 #include <boost/geometry/arithmetic/arithmetic.hpp>
0030 #include <boost/geometry/core/access.hpp>
0031 #include <boost/geometry/core/radian_access.hpp>
0032 #include <boost/geometry/core/coordinate_dimension.hpp>
0033 #include <boost/geometry/core/coordinate_promotion.hpp>
0034 #include <boost/geometry/strategies/transform.hpp>
0035 
0036 #include <boost/geometry/util/math.hpp>
0037 #include <boost/geometry/util/select_coordinate_type.hpp>
0038 
0039 namespace boost { namespace geometry
0040 {
0041 
0042 namespace strategy { namespace transform
0043 {
0044 
0045 #ifndef DOXYGEN_NO_DETAIL
0046 namespace detail
0047 {
0048 
0049 template
0050 <
0051     typename Src, typename Dst,
0052     std::size_t D, std::size_t N,
0053     template <typename> class F
0054 >
0055 struct transform_coordinates
0056 {
0057     template <typename T>
0058     static inline void transform(Src const& source, Dst& dest, T value)
0059     {
0060         typedef typename select_coordinate_type<Src, Dst>::type coordinate_type;
0061 
0062         F<coordinate_type> function;
0063         set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value)));
0064         transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value);
0065     }
0066 };
0067 
0068 template
0069 <
0070     typename Src, typename Dst,
0071     std::size_t N,
0072     template <typename> class F
0073 >
0074 struct transform_coordinates<Src, Dst, N, N, F>
0075 {
0076     template <typename T>
0077     static inline void transform(Src const& , Dst& , T )
0078     {
0079     }
0080 };
0081 
0082 } // namespace detail
0083 #endif // DOXYGEN_NO_DETAIL
0084 
0085 
0086 /*!
0087     \brief Transformation strategy to copy one point to another using assignment operator
0088     \ingroup transform
0089     \tparam P point type
0090  */
0091 template <typename P>
0092 struct copy_direct
0093 {
0094     inline bool apply(P const& p1, P& p2) const
0095     {
0096         p2 = p1;
0097         return true;
0098     }
0099 };
0100 
0101 /*!
0102     \brief Transformation strategy to do copy a point, copying per coordinate.
0103     \ingroup transform
0104     \tparam P1 first point type
0105     \tparam P2 second point type
0106  */
0107 template <typename P1, typename P2>
0108 struct copy_per_coordinate
0109 {
0110     inline bool apply(P1 const& p1, P2& p2) const
0111     {
0112         // Defensive check, dimensions are equal, selected by specialization
0113         assert_dimension_equal<P1, P2>();
0114 
0115         geometry::convert(p1, p2);
0116         return true;
0117     }
0118 };
0119 
0120 
0121 /*!
0122     \brief Transformation strategy to go from degree to radian and back
0123     \ingroup transform
0124     \tparam P1 first point type
0125     \tparam P2 second point type
0126     \tparam F additional functor to divide or multiply with d2r
0127  */
0128 template <typename P1, typename P2, template <typename> class F>
0129 struct degree_radian_vv
0130 {
0131     inline bool apply(P1 const& p1, P2& p2) const
0132     {
0133         // Spherical coordinates always have 2 coordinates measured in angles
0134         // The optional third one is distance/height, provided in another strategy
0135         // Polar coordinates having one angle, will be also in another strategy
0136         assert_dimension<P1, 2>();
0137         assert_dimension<P2, 2>();
0138 
0139         typedef typename promote_floating_point
0140             <
0141                 typename select_coordinate_type<P1, P2>::type
0142             >::type calculation_type;
0143 
0144         detail::transform_coordinates
0145             <
0146                 P1, P2, 0, 2, F
0147             >::transform(p1, p2, math::d2r<calculation_type>());
0148         return true;
0149     }
0150 };
0151 
0152 template <typename P1, typename P2, template <typename> class F>
0153 struct degree_radian_vv_3
0154 {
0155     inline bool apply(P1 const& p1, P2& p2) const
0156     {
0157         assert_dimension<P1, 3>();
0158         assert_dimension<P2, 3>();
0159 
0160         typedef typename promote_floating_point
0161             <
0162                 typename select_coordinate_type<P1, P2>::type
0163             >::type calculation_type;
0164 
0165         detail::transform_coordinates
0166             <
0167                 P1, P2, 0, 2, F
0168             >::transform(p1, p2, math::d2r<calculation_type>());
0169 
0170         // Copy height or other third dimension
0171         set<2>(p2, get<2>(p1));
0172         return true;
0173     }
0174 };
0175 
0176 
0177 #ifndef DOXYGEN_NO_DETAIL
0178 namespace detail
0179 {
0180 
0181     /// Helper function for conversion, phi/theta are in radians
0182     template <typename P, typename T, typename R>
0183     inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p)
0184     {
0185         assert_dimension<P, 3>();
0186 
0187         // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
0188         // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
0189         // https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
0190         // http://en.citizendium.org/wiki/Spherical_polar_coordinates
0191 
0192         // Phi = first, theta is second, r is third, see documentation on cs::spherical
0193 
0194         // (calculations are splitted to implement user defined types)
0195 
0196         T r_sin_theta = r;
0197         T r_cos_theta = r;
0198         r_sin_theta *= sin(theta);
0199         r_cos_theta *= cos(theta);
0200 
0201         set<0>(p, r_sin_theta * cos(phi));
0202         set<1>(p, r_sin_theta * sin(phi));
0203         set<2>(p, r_cos_theta);
0204     }
0205 
0206     /// Helper function for conversion, lambda/delta (lon lat) are in radians
0207     template <typename P, typename T, typename R>
0208     inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
0209     {
0210         assert_dimension<P, 3>();
0211 
0212         // http://mathworld.wolfram.com/GreatCircle.html
0213         // http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
0214 
0215         T r_cos_delta = r;
0216         T r_sin_delta = r;
0217         r_cos_delta *= cos(delta);
0218         r_sin_delta *= sin(delta);
0219 
0220         set<0>(p, r_cos_delta * cos(lambda));
0221         set<1>(p, r_cos_delta * sin(lambda));
0222         set<2>(p, r_sin_delta);
0223     }
0224 
0225 
0226     /// Helper function for conversion
0227     template <typename P, typename T>
0228     inline bool cartesian_to_spherical2(T x, T y, T z, P& p)
0229     {
0230         assert_dimension<P, 2>();
0231 
0232         // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
0233 
0234 #if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE)
0235         // TODO: MAYBE ONLY IF TO BE CHECKED?
0236         T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z);
0237 
0238         // Unit sphere, so r should be 1
0239         if (geometry::math::abs(r - 1.0) > T(1e-6))
0240         {
0241             return false;
0242         }
0243         // end todo
0244 #endif
0245 
0246         set_from_radian<0>(p, atan2(y, x));
0247         set_from_radian<1>(p, acos(z));
0248         return true;
0249     }
0250 
0251     template <typename P, typename T>
0252     inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
0253     {
0254         assert_dimension<P, 2>();
0255 
0256         set_from_radian<0>(p, atan2(y, x));
0257         set_from_radian<1>(p, asin(z));
0258         return true;
0259     }
0260 
0261 
0262     template <typename P, typename T>
0263     inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
0264     {
0265         assert_dimension<P, 3>();
0266 
0267         // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
0268         T const r = math::sqrt(x * x + y * y + z * z);
0269         set<2>(p, r);
0270         set_from_radian<0>(p, atan2(y, x));
0271         if (r > 0.0)
0272         {
0273             set_from_radian<1>(p, acos(z / r));
0274             return true;
0275         }
0276         return false;
0277     }
0278 
0279     template <typename P, typename T>
0280     inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
0281     {
0282         assert_dimension<P, 3>();
0283 
0284         // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
0285         T const r = math::sqrt(x * x + y * y + z * z);
0286         set<2>(p, r);
0287         set_from_radian<0>(p, atan2(y, x));
0288         if (r > 0.0)
0289         {
0290             set_from_radian<1>(p, asin(z / r));
0291             return true;
0292         }
0293         return false;
0294     }
0295 
0296 } // namespace detail
0297 #endif // DOXYGEN_NO_DETAIL
0298 
0299 
0300 /*!
0301     \brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z)
0302     \details on Unit sphere
0303     \ingroup transform
0304     \tparam P1 first point type
0305     \tparam P2 second point type
0306  */
0307 template <typename P1, typename P2>
0308 struct from_spherical_polar_2_to_cartesian_3
0309 {
0310     inline bool apply(P1 const& p1, P2& p2) const
0311     {
0312         assert_dimension<P1, 2>();
0313         detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
0314         return true;
0315     }
0316 };
0317 
0318 template <typename P1, typename P2>
0319 struct from_spherical_equatorial_2_to_cartesian_3
0320 {
0321     inline bool apply(P1 const& p1, P2& p2) const
0322     {
0323         assert_dimension<P1, 2>();
0324         detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
0325         return true;
0326     }
0327 };
0328 
0329 
0330 /*!
0331     \brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z)
0332     \ingroup transform
0333     \tparam P1 first point type
0334     \tparam P2 second point type
0335  */
0336 template <typename P1, typename P2>
0337 struct from_spherical_polar_3_to_cartesian_3
0338 {
0339     inline bool apply(P1 const& p1, P2& p2) const
0340     {
0341         assert_dimension<P1, 3>();
0342         detail::spherical_polar_to_cartesian(
0343                     get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
0344         return true;
0345     }
0346 };
0347 
0348 template <typename P1, typename P2>
0349 struct from_spherical_equatorial_3_to_cartesian_3
0350 {
0351     inline bool apply(P1 const& p1, P2& p2) const
0352     {
0353         assert_dimension<P1, 3>();
0354         detail::spherical_equatorial_to_cartesian(
0355                     get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
0356         return true;
0357     }
0358 };
0359 
0360 
0361 /*!
0362     \brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta)
0363     \details on Unit sphere
0364     \ingroup transform
0365     \tparam P1 first point type
0366     \tparam P2 second point type
0367     \note If x,y,z point is not lying on unit sphere, transformation will return false
0368  */
0369 template <typename P1, typename P2>
0370 struct from_cartesian_3_to_spherical_polar_2
0371 {
0372     inline bool apply(P1 const& p1, P2& p2) const
0373     {
0374         assert_dimension<P1, 3>();
0375         return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
0376     }
0377 };
0378 
0379 template <typename P1, typename P2>
0380 struct from_cartesian_3_to_spherical_equatorial_2
0381 {
0382     inline bool apply(P1 const& p1, P2& p2) const
0383     {
0384         assert_dimension<P1, 3>();
0385         return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
0386     }
0387 };
0388 
0389 
0390 /*!
0391     \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r)
0392     \ingroup transform
0393     \tparam P1 first point type
0394     \tparam P2 second point type
0395  */
0396 template <typename P1, typename P2>
0397 struct from_cartesian_3_to_spherical_polar_3
0398 {
0399     inline bool apply(P1 const& p1, P2& p2) const
0400     {
0401         assert_dimension<P1, 3>();
0402         return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
0403     }
0404 };
0405 
0406 template <typename P1, typename P2>
0407 struct from_cartesian_3_to_spherical_equatorial_3
0408 {
0409     inline bool apply(P1 const& p1, P2& p2) const
0410     {
0411         assert_dimension<P1, 3>();
0412         return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
0413     }
0414 };
0415 
0416 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
0417 
0418 namespace services
0419 {
0420 
0421 /// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied
0422 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
0423 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
0424 {
0425     typedef copy_direct<P> type;
0426 };
0427 
0428 /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
0429 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
0430 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
0431 {
0432     typedef copy_per_coordinate<P1, P2> type;
0433 };
0434 
0435 /// Specialization to transform from degree to radian for any coordinate system / point type combination
0436 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
0437 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
0438 {
0439     typedef degree_radian_vv<P1, P2, std::multiplies> type;
0440 };
0441 
0442 /// Specialization to transform from radian to degree for any coordinate system / point type combination
0443 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
0444 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
0445 {
0446     typedef degree_radian_vv<P1, P2, std::divides> type;
0447 };
0448 
0449 
0450 /// Specialization degree->radian in 3D
0451 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
0452 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
0453 {
0454     typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
0455 };
0456 
0457 /// Specialization radian->degree in 3D
0458 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
0459 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
0460 {
0461     typedef degree_radian_vv_3<P1, P2, std::divides> type;
0462 };
0463 
0464 /// Specialization to transform from unit sphere(phi,theta) to XYZ
0465 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0466 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
0467 {
0468     typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type;
0469 };
0470 
0471 /// Specialization to transform from sphere(phi,theta,r) to XYZ
0472 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0473 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
0474 {
0475     typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type;
0476 };
0477 
0478 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0479 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
0480 {
0481     typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type;
0482 };
0483 
0484 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0485 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
0486 {
0487     typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type;
0488 };
0489 
0490 /// Specialization to transform from XYZ to unit sphere(phi,theta)
0491 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0492 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
0493 {
0494     typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type;
0495 };
0496 
0497 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0498 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
0499 {
0500     typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type;
0501 };
0502 
0503 /// Specialization to transform from XYZ to sphere(phi,theta,r)
0504 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0505 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
0506 {
0507     typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type;
0508 };
0509 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
0510 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
0511 {
0512     typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
0513 };
0514 
0515 
0516 } // namespace services
0517 
0518 
0519 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
0520 
0521 
0522 }} // namespace strategy::transform
0523 
0524 
0525 }} // namespace boost::geometry
0526 
0527 #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP