Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 08:15:40

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