1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 #ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
15 #define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
21 #include <boost/numeric/conversion/cast.hpp>
23 #include <boost/geometry/algorithms/convert.hpp>
24 #include <boost/geometry/arithmetic/arithmetic.hpp>
25 #include <boost/geometry/core/access.hpp>
26 #include <boost/geometry/core/radian_access.hpp>
27 #include <boost/geometry/core/coordinate_dimension.hpp>
28 #include <boost/geometry/strategies/transform.hpp>
30 #include <boost/geometry/util/math.hpp>
31 #include <boost/geometry/util/select_coordinate_type.hpp>
33 namespace boost { namespace geometry
36 namespace strategy { namespace transform
39 #ifndef DOXYGEN_NO_DETAIL
45 typename Src, typename Dst,
46 std::size_t D, std::size_t N,
47 template <typename> class F
49 struct transform_coordinates
52 static inline void transform(Src const& source, Dst& dest, T value)
54 typedef typename select_coordinate_type<Src, Dst>::type coordinate_type;
56 F<coordinate_type> function;
57 set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value)));
58 transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value);
64 typename Src, typename Dst,
66 template <typename> class F
68 struct transform_coordinates<Src, Dst, N, N, F>
71 static inline void transform(Src const& , Dst& , T )
77 #endif // DOXYGEN_NO_DETAIL
81 \brief Transformation strategy to copy one point to another using assignment operator
88 inline bool apply(P const& p1, P& p2) const
96 \brief Transformation strategy to do copy a point, copying per coordinate.
98 \tparam P1 first point type
99 \tparam P2 second point type
101 template <typename P1, typename P2>
102 struct copy_per_coordinate
104 inline bool apply(P1 const& p1, P2& p2) const
106 // Defensive check, dimensions are equal, selected by specialization
107 assert_dimension_equal<P1, P2>();
109 geometry::convert(p1, p2);
116 \brief Transformation strategy to go from degree to radian and back
118 \tparam P1 first point type
119 \tparam P2 second point type
120 \tparam F additional functor to divide or multiply with d2r
122 template <typename P1, typename P2, template <typename> class F>
123 struct degree_radian_vv
125 inline bool apply(P1 const& p1, P2& p2) const
127 // Spherical coordinates always have 2 coordinates measured in angles
128 // The optional third one is distance/height, provided in another strategy
129 // Polar coordinates having one angle, will be also in another strategy
130 assert_dimension<P1, 2>();
131 assert_dimension<P2, 2>();
133 detail::transform_coordinates<P1, P2, 0, 2, F>::transform(p1, p2, math::d2r);
138 template <typename P1, typename P2, template <typename> class F>
139 struct degree_radian_vv_3
141 inline bool apply(P1 const& p1, P2& p2) const
143 assert_dimension<P1, 3>();
144 assert_dimension<P2, 3>();
146 detail::transform_coordinates<P1, P2, 0, 2, F>::transform(p1, p2, math::d2r);
147 // Copy height or other third dimension
148 set<2>(p2, get<2>(p1));
154 #ifndef DOXYGEN_NO_DETAIL
158 /// Helper function for conversion, phi/theta are in radians
159 template <typename P, typename T, typename R>
160 inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p)
162 assert_dimension<P, 3>();
164 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
165 // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
166 // https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
167 // http://en.citizendium.org/wiki/Spherical_polar_coordinates
169 // Phi = first, theta is second, r is third, see documentation on cs::spherical
171 // (calculations are splitted to implement ttmath)
175 r_sin_theta *= sin(theta);
176 r_cos_theta *= cos(theta);
178 set<0>(p, r_sin_theta * cos(phi));
179 set<1>(p, r_sin_theta * sin(phi));
180 set<2>(p, r_cos_theta);
183 /// Helper function for conversion, lambda/delta (lon lat) are in radians
184 template <typename P, typename T, typename R>
185 inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
187 assert_dimension<P, 3>();
189 // http://mathworld.wolfram.com/GreatCircle.html
190 // http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
194 r_cos_delta *= cos(delta);
195 r_sin_delta *= sin(delta);
197 set<0>(p, r_cos_delta * cos(lambda));
198 set<1>(p, r_cos_delta * sin(lambda));
199 set<2>(p, r_sin_delta);
203 /// Helper function for conversion
204 template <typename P, typename T>
205 inline bool cartesian_to_spherical2(T x, T y, T z, P& p)
207 assert_dimension<P, 2>();
209 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
211 #if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE)
212 // TODO: MAYBE ONLY IF TO BE CHECKED?
213 T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z);
215 // Unit sphere, so r should be 1
216 if (geometry::math::abs(r - 1.0) > T(1e-6))
223 set_from_radian<0>(p, atan2(y, x));
224 set_from_radian<1>(p, acos(z));
228 template <typename P, typename T>
229 inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
231 assert_dimension<P, 2>();
233 set_from_radian<0>(p, atan2(y, x));
234 set_from_radian<1>(p, asin(z));
239 template <typename P, typename T>
240 inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
242 assert_dimension<P, 3>();
244 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
245 T const r = math::sqrt(x * x + y * y + z * z);
247 set_from_radian<0>(p, atan2(y, x));
250 set_from_radian<1>(p, acos(z / r));
256 template <typename P, typename T>
257 inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
259 assert_dimension<P, 3>();
261 // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
262 T const r = math::sqrt(x * x + y * y + z * z);
264 set_from_radian<0>(p, atan2(y, x));
267 set_from_radian<1>(p, asin(z / r));
273 } // namespace detail
274 #endif // DOXYGEN_NO_DETAIL
278 \brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z)
279 \details on Unit sphere
281 \tparam P1 first point type
282 \tparam P2 second point type
284 template <typename P1, typename P2>
285 struct from_spherical_polar_2_to_cartesian_3
287 inline bool apply(P1 const& p1, P2& p2) const
289 assert_dimension<P1, 2>();
290 detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
295 template <typename P1, typename P2>
296 struct from_spherical_equatorial_2_to_cartesian_3
298 inline bool apply(P1 const& p1, P2& p2) const
300 assert_dimension<P1, 2>();
301 detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
308 \brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z)
310 \tparam P1 first point type
311 \tparam P2 second point type
313 template <typename P1, typename P2>
314 struct from_spherical_polar_3_to_cartesian_3
316 inline bool apply(P1 const& p1, P2& p2) const
318 assert_dimension<P1, 3>();
319 detail::spherical_polar_to_cartesian(
320 get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
325 template <typename P1, typename P2>
326 struct from_spherical_equatorial_3_to_cartesian_3
328 inline bool apply(P1 const& p1, P2& p2) const
330 assert_dimension<P1, 3>();
331 detail::spherical_equatorial_to_cartesian(
332 get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
339 \brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta)
340 \details on Unit sphere
342 \tparam P1 first point type
343 \tparam P2 second point type
344 \note If x,y,z point is not lying on unit sphere, transformation will return false
346 template <typename P1, typename P2>
347 struct from_cartesian_3_to_spherical_polar_2
349 inline bool apply(P1 const& p1, P2& p2) const
351 assert_dimension<P1, 3>();
352 return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
356 template <typename P1, typename P2>
357 struct from_cartesian_3_to_spherical_equatorial_2
359 inline bool apply(P1 const& p1, P2& p2) const
361 assert_dimension<P1, 3>();
362 return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
368 \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r)
370 \tparam P1 first point type
371 \tparam P2 second point type
373 template <typename P1, typename P2>
374 struct from_cartesian_3_to_spherical_polar_3
376 inline bool apply(P1 const& p1, P2& p2) const
378 assert_dimension<P1, 3>();
379 return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
383 template <typename P1, typename P2>
384 struct from_cartesian_3_to_spherical_equatorial_3
386 inline bool apply(P1 const& p1, P2& p2) const
388 assert_dimension<P1, 3>();
389 return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
393 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
398 /// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied
399 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
400 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
402 typedef copy_direct<P> type;
405 /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
406 template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
407 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
409 typedef copy_per_coordinate<P1, P2> type;
412 /// Specialization to transform from degree to radian for any coordinate system / point type combination
413 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
414 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
416 typedef degree_radian_vv<P1, P2, std::multiplies> type;
419 /// Specialization to transform from radian to degree for any coordinate system / point type combination
420 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
421 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
423 typedef degree_radian_vv<P1, P2, std::divides> type;
427 /// Specialization degree->radian in 3D
428 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
429 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
431 typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
434 /// Specialization radian->degree in 3D
435 template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
436 struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
438 typedef degree_radian_vv_3<P1, P2, std::divides> type;
441 /// Specialization to transform from unit sphere(phi,theta) to XYZ
442 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
443 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
445 typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type;
448 /// Specialization to transform from sphere(phi,theta,r) to XYZ
449 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
450 struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
452 typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type;
455 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
456 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
458 typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type;
461 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
462 struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
464 typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type;
467 /// Specialization to transform from XYZ to unit sphere(phi,theta)
468 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
469 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
471 typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type;
474 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
475 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
477 typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type;
480 /// Specialization to transform from XYZ to sphere(phi,theta,r)
481 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
482 struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
484 typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type;
486 template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
487 struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
489 typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
493 } // namespace services
496 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
499 }} // namespace strategy::transform
502 }} // namespace boost::geometry
504 #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP