1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
7 // This file was modified by Oracle on 2015.
8 // Modifications copyright (c) 2015 Oracle and/or its affiliates.
10 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
15 // Use, modification and distribution is subject to the Boost Software License,
16 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
17 // http://www.boost.org/LICENSE_1_0.txt)
19 #ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
20 #define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
26 #include <boost/numeric/conversion/cast.hpp>
28 #include <boost/geometry/algorithms/convert.hpp>
29 #include <boost/geometry/arithmetic/arithmetic.hpp>
30 #include <boost/geometry/core/access.hpp>
31 #include <boost/geometry/core/radian_access.hpp>
32 #include <boost/geometry/core/coordinate_dimension.hpp>
33 #include <boost/geometry/core/coordinate_promotion.hpp>
34 #include <boost/geometry/strategies/transform.hpp>
36 #include <boost/geometry/util/math.hpp>
37 #include <boost/geometry/util/select_coordinate_type.hpp>
39 namespace boost { namespace geometry
42 namespace strategy { namespace transform
45 #ifndef DOXYGEN_NO_DETAIL
51 typename Src, typename Dst,
52 std::size_t D, std::size_t N,
53 template <typename> class F
55 struct transform_coordinates
58 static inline void transform(Src const& source, Dst& dest, T value)
60 typedef typename select_coordinate_type<Src, Dst>::type coordinate_type;
62 F<coordinate_type> function;
63 set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value)));
64 transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value);
70 typename Src, typename Dst,
72 template <typename> class F
74 struct transform_coordinates<Src, Dst, N, N, F>
77 static inline void transform(Src const& , Dst& , T )
83 #endif // DOXYGEN_NO_DETAIL
87 \brief Transformation strategy to copy one point to another using assignment operator
94 inline bool apply(P const& p1, P& p2) const
102 \brief Transformation strategy to do copy a point, copying per coordinate.
104 \tparam P1 first point type
105 \tparam P2 second point type
107 template <typename P1, typename P2>
108 struct copy_per_coordinate
110 inline bool apply(P1 const& p1, P2& p2) const
112 // Defensive check, dimensions are equal, selected by specialization
113 assert_dimension_equal<P1, P2>();
115 geometry::convert(p1, p2);
122 \brief Transformation strategy to go from degree to radian and back
124 \tparam P1 first point type
125 \tparam P2 second point type
126 \tparam F additional functor to divide or multiply with d2r
128 template <typename P1, typename P2, template <typename> class F>
129 struct degree_radian_vv
131 inline bool apply(P1 const& p1, P2& p2) const
133 // Spherical coordinates always have 2 coordinates measured in angles
134 // The optional third one is distance/height, provided in another strategy
135 // Polar coordinates having one angle, will be also in another strategy
136 assert_dimension<P1, 2>();
137 assert_dimension<P2, 2>();
139 typedef typename promote_floating_point
141 typename select_coordinate_type<P1, P2>::type
142 >::type calculation_type;
144 detail::transform_coordinates
147 >::transform(p1, p2, math::d2r<calculation_type>());
152 template <typename P1, typename P2, template <typename> class F>
153 struct degree_radian_vv_3
155 inline bool apply(P1 const& p1, P2& p2) const
157 assert_dimension<P1, 3>();
158 assert_dimension<P2, 3>();
160 typedef typename promote_floating_point
162 typename select_coordinate_type<P1, P2>::type
163 >::type calculation_type;
165 detail::transform_coordinates
168 >::transform(p1, p2, math::d2r<calculation_type>());
170 // Copy height or other third dimension
171 set<2>(p2, get<2>(p1));
177 #ifndef DOXYGEN_NO_DETAIL
181 /// Helper function for conversion, phi/theta are in radians
182 template <typename P, typename T, typename R>
183 inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p)
185 assert_dimension<P, 3>();
187 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
188 // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
189 // https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
190 // http://en.citizendium.org/wiki/Spherical_polar_coordinates
192 // Phi = first, theta is second, r is third, see documentation on cs::spherical
194 // (calculations are splitted to implement user defined types)
198 r_sin_theta *= sin(theta);
199 r_cos_theta *= cos(theta);
201 set<0>(p, r_sin_theta * cos(phi));
202 set<1>(p, r_sin_theta * sin(phi));
203 set<2>(p, r_cos_theta);
206 /// Helper function for conversion, lambda/delta (lon lat) are in radians
207 template <typename P, typename T, typename R>
208 inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
210 assert_dimension<P, 3>();
212 // http://mathworld.wolfram.com/GreatCircle.html
213 // http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
217 r_cos_delta *= cos(delta);
218 r_sin_delta *= sin(delta);
220 set<0>(p, r_cos_delta * cos(lambda));
221 set<1>(p, r_cos_delta * sin(lambda));
222 set<2>(p, r_sin_delta);
226 /// Helper function for conversion
227 template <typename P, typename T>
228 inline bool cartesian_to_spherical2(T x, T y, T z, P& p)
230 assert_dimension<P, 2>();
232 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
234 #if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE)
235 // TODO: MAYBE ONLY IF TO BE CHECKED?
236 T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z);
238 // Unit sphere, so r should be 1
239 if (geometry::math::abs(r - 1.0) > T(1e-6))
246 set_from_radian<0>(p, atan2(y, x));
247 set_from_radian<1>(p, acos(z));
251 template <typename P, typename T>
252 inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
254 assert_dimension<P, 2>();
256 set_from_radian<0>(p, atan2(y, x));
257 set_from_radian<1>(p, asin(z));
262 template <typename P, typename T>
263 inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
265 assert_dimension<P, 3>();
267 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
268 T const r = math::sqrt(x * x + y * y + z * z);
270 set_from_radian<0>(p, atan2(y, x));
273 set_from_radian<1>(p, acos(z / r));
279 template <typename P, typename T>
280 inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
282 assert_dimension<P, 3>();
284 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
285 T const r = math::sqrt(x * x + y * y + z * z);
287 set_from_radian<0>(p, atan2(y, x));
290 set_from_radian<1>(p, asin(z / r));
296 } // namespace detail
297 #endif // DOXYGEN_NO_DETAIL
301 \brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z)
302 \details on Unit sphere
304 \tparam P1 first point type
305 \tparam P2 second point type
307 template <typename P1, typename P2>
308 struct from_spherical_polar_2_to_cartesian_3
310 inline bool apply(P1 const& p1, P2& p2) const
312 assert_dimension<P1, 2>();
313 detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
318 template <typename P1, typename P2>
319 struct from_spherical_equatorial_2_to_cartesian_3
321 inline bool apply(P1 const& p1, P2& p2) const
323 assert_dimension<P1, 2>();
324 detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
331 \brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z)
333 \tparam P1 first point type
334 \tparam P2 second point type
336 template <typename P1, typename P2>
337 struct from_spherical_polar_3_to_cartesian_3
339 inline bool apply(P1 const& p1, P2& p2) const
341 assert_dimension<P1, 3>();
342 detail::spherical_polar_to_cartesian(
343 get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
348 template <typename P1, typename P2>
349 struct from_spherical_equatorial_3_to_cartesian_3
351 inline bool apply(P1 const& p1, P2& p2) const
353 assert_dimension<P1, 3>();
354 detail::spherical_equatorial_to_cartesian(
355 get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
362 \brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta)
363 \details on Unit sphere
365 \tparam P1 first point type
366 \tparam P2 second point type
367 \note If x,y,z point is not lying on unit sphere, transformation will return false
369 template <typename P1, typename P2>
370 struct from_cartesian_3_to_spherical_polar_2
372 inline bool apply(P1 const& p1, P2& p2) const
374 assert_dimension<P1, 3>();
375 return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
379 template <typename P1, typename P2>
380 struct from_cartesian_3_to_spherical_equatorial_2
382 inline bool apply(P1 const& p1, P2& p2) const
384 assert_dimension<P1, 3>();
385 return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
391 \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r)
393 \tparam P1 first point type
394 \tparam P2 second point type
396 template <typename P1, typename P2>
397 struct from_cartesian_3_to_spherical_polar_3
399 inline bool apply(P1 const& p1, P2& p2) const
401 assert_dimension<P1, 3>();
402 return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
406 template <typename P1, typename P2>
407 struct from_cartesian_3_to_spherical_equatorial_3
409 inline bool apply(P1 const& p1, P2& p2) const
411 assert_dimension<P1, 3>();
412 return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
416 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
421 /// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied
422 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
423 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
425 typedef copy_direct<P> type;
428 /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
429 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
430 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
432 typedef copy_per_coordinate<P1, P2> type;
435 /// Specialization to transform from degree to radian for any coordinate system / point type combination
436 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
437 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
439 typedef degree_radian_vv<P1, P2, std::multiplies> type;
442 /// Specialization to transform from radian to degree for any coordinate system / point type combination
443 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
444 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
446 typedef degree_radian_vv<P1, P2, std::divides> type;
450 /// Specialization degree->radian in 3D
451 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
452 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
454 typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
457 /// Specialization radian->degree in 3D
458 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
459 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
461 typedef degree_radian_vv_3<P1, P2, std::divides> type;
464 /// Specialization to transform from unit sphere(phi,theta) to XYZ
465 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
466 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
468 typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type;
471 /// Specialization to transform from sphere(phi,theta,r) to XYZ
472 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
473 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
475 typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type;
478 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
479 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
481 typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type;
484 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
485 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
487 typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type;
490 /// Specialization to transform from XYZ to unit sphere(phi,theta)
491 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
492 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
494 typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type;
497 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
498 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
500 typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type;
503 /// Specialization to transform from XYZ to sphere(phi,theta,r)
504 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
505 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
507 typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type;
509 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
510 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
512 typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
516 } // namespace services
519 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
522 }} // namespace strategy::transform
525 }} // namespace boost::geometry
527 #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP