strategy_transform.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
  5. // This file was modified by Oracle on 2015.
  6. // Modifications copyright (c) 2015 Oracle and/or its affiliates.
  7. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  8. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  9. // (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)
  13. #ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
  14. #define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
  15. #include <cstddef>
  16. #include <cmath>
  17. #include <functional>
  18. #include <boost/numeric/conversion/cast.hpp>
  19. #include <boost/geometry/algorithms/convert.hpp>
  20. #include <boost/geometry/arithmetic/arithmetic.hpp>
  21. #include <boost/geometry/core/access.hpp>
  22. #include <boost/geometry/core/radian_access.hpp>
  23. #include <boost/geometry/core/coordinate_dimension.hpp>
  24. #include <boost/geometry/strategies/transform.hpp>
  25. #include <boost/geometry/util/math.hpp>
  26. #include <boost/geometry/util/promote_floating_point.hpp>
  27. #include <boost/geometry/util/select_coordinate_type.hpp>
  28. namespace boost { namespace geometry
  29. {
  30. namespace strategy { namespace transform
  31. {
  32. #ifndef DOXYGEN_NO_DETAIL
  33. namespace detail
  34. {
  35. template
  36. <
  37. typename Src, typename Dst,
  38. std::size_t D, std::size_t N,
  39. template <typename> class F
  40. >
  41. struct transform_coordinates
  42. {
  43. template <typename T>
  44. static inline void transform(Src const& source, Dst& dest, T value)
  45. {
  46. typedef typename select_coordinate_type<Src, Dst>::type coordinate_type;
  47. F<coordinate_type> function;
  48. set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value)));
  49. transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value);
  50. }
  51. };
  52. template
  53. <
  54. typename Src, typename Dst,
  55. std::size_t N,
  56. template <typename> class F
  57. >
  58. struct transform_coordinates<Src, Dst, N, N, F>
  59. {
  60. template <typename T>
  61. static inline void transform(Src const& , Dst& , T )
  62. {
  63. }
  64. };
  65. } // namespace detail
  66. #endif // DOXYGEN_NO_DETAIL
  67. /*!
  68. \brief Transformation strategy to copy one point to another using assignment operator
  69. \ingroup transform
  70. \tparam P point type
  71. */
  72. template <typename P>
  73. struct copy_direct
  74. {
  75. inline bool apply(P const& p1, P& p2) const
  76. {
  77. p2 = p1;
  78. return true;
  79. }
  80. };
  81. /*!
  82. \brief Transformation strategy to do copy a point, copying per coordinate.
  83. \ingroup transform
  84. \tparam P1 first point type
  85. \tparam P2 second point type
  86. */
  87. template <typename P1, typename P2>
  88. struct copy_per_coordinate
  89. {
  90. inline bool apply(P1 const& p1, P2& p2) const
  91. {
  92. // Defensive check, dimensions are equal, selected by specialization
  93. assert_dimension_equal<P1, P2>();
  94. geometry::convert(p1, p2);
  95. return true;
  96. }
  97. };
  98. /*!
  99. \brief Transformation strategy to go from degree to radian and back
  100. \ingroup transform
  101. \tparam P1 first point type
  102. \tparam P2 second point type
  103. \tparam F additional functor to divide or multiply with d2r
  104. */
  105. template <typename P1, typename P2, template <typename> class F>
  106. struct degree_radian_vv
  107. {
  108. inline bool apply(P1 const& p1, P2& p2) const
  109. {
  110. // Spherical coordinates always have 2 coordinates measured in angles
  111. // The optional third one is distance/height, provided in another strategy
  112. // Polar coordinates having one angle, will be also in another strategy
  113. assert_dimension<P1, 2>();
  114. assert_dimension<P2, 2>();
  115. typedef typename promote_floating_point
  116. <
  117. typename select_coordinate_type<P1, P2>::type
  118. >::type calculation_type;
  119. detail::transform_coordinates
  120. <
  121. P1, P2, 0, 2, F
  122. >::transform(p1, p2, math::d2r<calculation_type>());
  123. return true;
  124. }
  125. };
  126. template <typename P1, typename P2, template <typename> class F>
  127. struct degree_radian_vv_3
  128. {
  129. inline bool apply(P1 const& p1, P2& p2) const
  130. {
  131. assert_dimension<P1, 3>();
  132. assert_dimension<P2, 3>();
  133. typedef typename promote_floating_point
  134. <
  135. typename select_coordinate_type<P1, P2>::type
  136. >::type calculation_type;
  137. detail::transform_coordinates
  138. <
  139. P1, P2, 0, 2, F
  140. >::transform(p1, p2, math::d2r<calculation_type>());
  141. // Copy height or other third dimension
  142. set<2>(p2, get<2>(p1));
  143. return true;
  144. }
  145. };
  146. #ifndef DOXYGEN_NO_DETAIL
  147. namespace detail
  148. {
  149. /// Helper function for conversion, phi/theta are in radians
  150. template <typename P, typename T, typename R>
  151. inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p)
  152. {
  153. assert_dimension<P, 3>();
  154. // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
  155. // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
  156. // https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
  157. // http://en.citizendium.org/wiki/Spherical_polar_coordinates
  158. // Phi = first, theta is second, r is third, see documentation on cs::spherical
  159. // (calculations are splitted to implement user defined types)
  160. T r_sin_theta = r;
  161. T r_cos_theta = r;
  162. r_sin_theta *= sin(theta);
  163. r_cos_theta *= cos(theta);
  164. set<0>(p, r_sin_theta * cos(phi));
  165. set<1>(p, r_sin_theta * sin(phi));
  166. set<2>(p, r_cos_theta);
  167. }
  168. /// Helper function for conversion, lambda/delta (lon lat) are in radians
  169. template <typename P, typename T, typename R>
  170. inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
  171. {
  172. assert_dimension<P, 3>();
  173. // http://mathworld.wolfram.com/GreatCircle.html
  174. // http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
  175. T r_cos_delta = r;
  176. T r_sin_delta = r;
  177. r_cos_delta *= cos(delta);
  178. r_sin_delta *= sin(delta);
  179. set<0>(p, r_cos_delta * cos(lambda));
  180. set<1>(p, r_cos_delta * sin(lambda));
  181. set<2>(p, r_sin_delta);
  182. }
  183. /// Helper function for conversion
  184. template <typename P, typename T>
  185. inline bool cartesian_to_spherical2(T x, T y, T z, P& p)
  186. {
  187. assert_dimension<P, 2>();
  188. // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
  189. #if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE)
  190. // TODO: MAYBE ONLY IF TO BE CHECKED?
  191. T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z);
  192. // Unit sphere, so r should be 1
  193. if (geometry::math::abs(r - 1.0) > T(1e-6))
  194. {
  195. return false;
  196. }
  197. // end todo
  198. #endif
  199. set_from_radian<0>(p, atan2(y, x));
  200. set_from_radian<1>(p, acos(z));
  201. return true;
  202. }
  203. template <typename P, typename T>
  204. inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
  205. {
  206. assert_dimension<P, 2>();
  207. set_from_radian<0>(p, atan2(y, x));
  208. set_from_radian<1>(p, asin(z));
  209. return true;
  210. }
  211. template <typename P, typename T>
  212. inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
  213. {
  214. assert_dimension<P, 3>();
  215. // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
  216. T const r = math::sqrt(x * x + y * y + z * z);
  217. set<2>(p, r);
  218. set_from_radian<0>(p, atan2(y, x));
  219. if (r > 0.0)
  220. {
  221. set_from_radian<1>(p, acos(z / r));
  222. return true;
  223. }
  224. return false;
  225. }
  226. template <typename P, typename T>
  227. inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
  228. {
  229. assert_dimension<P, 3>();
  230. // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
  231. T const r = math::sqrt(x * x + y * y + z * z);
  232. set<2>(p, r);
  233. set_from_radian<0>(p, atan2(y, x));
  234. if (r > 0.0)
  235. {
  236. set_from_radian<1>(p, asin(z / r));
  237. return true;
  238. }
  239. return false;
  240. }
  241. } // namespace detail
  242. #endif // DOXYGEN_NO_DETAIL
  243. /*!
  244. \brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z)
  245. \details on Unit sphere
  246. \ingroup transform
  247. \tparam P1 first point type
  248. \tparam P2 second point type
  249. */
  250. template <typename P1, typename P2>
  251. struct from_spherical_polar_2_to_cartesian_3
  252. {
  253. inline bool apply(P1 const& p1, P2& p2) const
  254. {
  255. assert_dimension<P1, 2>();
  256. detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
  257. return true;
  258. }
  259. };
  260. template <typename P1, typename P2>
  261. struct from_spherical_equatorial_2_to_cartesian_3
  262. {
  263. inline bool apply(P1 const& p1, P2& p2) const
  264. {
  265. assert_dimension<P1, 2>();
  266. detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
  267. return true;
  268. }
  269. };
  270. /*!
  271. \brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z)
  272. \ingroup transform
  273. \tparam P1 first point type
  274. \tparam P2 second point type
  275. */
  276. template <typename P1, typename P2>
  277. struct from_spherical_polar_3_to_cartesian_3
  278. {
  279. inline bool apply(P1 const& p1, P2& p2) const
  280. {
  281. assert_dimension<P1, 3>();
  282. detail::spherical_polar_to_cartesian(
  283. get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
  284. return true;
  285. }
  286. };
  287. template <typename P1, typename P2>
  288. struct from_spherical_equatorial_3_to_cartesian_3
  289. {
  290. inline bool apply(P1 const& p1, P2& p2) const
  291. {
  292. assert_dimension<P1, 3>();
  293. detail::spherical_equatorial_to_cartesian(
  294. get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
  295. return true;
  296. }
  297. };
  298. /*!
  299. \brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta)
  300. \details on Unit sphere
  301. \ingroup transform
  302. \tparam P1 first point type
  303. \tparam P2 second point type
  304. \note If x,y,z point is not lying on unit sphere, transformation will return false
  305. */
  306. template <typename P1, typename P2>
  307. struct from_cartesian_3_to_spherical_polar_2
  308. {
  309. inline bool apply(P1 const& p1, P2& p2) const
  310. {
  311. assert_dimension<P1, 3>();
  312. return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
  313. }
  314. };
  315. template <typename P1, typename P2>
  316. struct from_cartesian_3_to_spherical_equatorial_2
  317. {
  318. inline bool apply(P1 const& p1, P2& p2) const
  319. {
  320. assert_dimension<P1, 3>();
  321. return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
  322. }
  323. };
  324. /*!
  325. \brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r)
  326. \ingroup transform
  327. \tparam P1 first point type
  328. \tparam P2 second point type
  329. */
  330. template <typename P1, typename P2>
  331. struct from_cartesian_3_to_spherical_polar_3
  332. {
  333. inline bool apply(P1 const& p1, P2& p2) const
  334. {
  335. assert_dimension<P1, 3>();
  336. return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
  337. }
  338. };
  339. template <typename P1, typename P2>
  340. struct from_cartesian_3_to_spherical_equatorial_3
  341. {
  342. inline bool apply(P1 const& p1, P2& p2) const
  343. {
  344. assert_dimension<P1, 3>();
  345. return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
  346. }
  347. };
  348. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  349. namespace services
  350. {
  351. /// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied
  352. template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
  353. struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
  354. {
  355. typedef copy_direct<P> type;
  356. };
  357. /// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
  358. template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
  359. struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
  360. {
  361. typedef copy_per_coordinate<P1, P2> type;
  362. };
  363. /// Specialization to transform from degree to radian for any coordinate system / point type combination
  364. template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
  365. struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
  366. {
  367. typedef degree_radian_vv<P1, P2, std::multiplies> type;
  368. };
  369. /// Specialization to transform from radian to degree for any coordinate system / point type combination
  370. template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
  371. struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
  372. {
  373. typedef degree_radian_vv<P1, P2, std::divides> type;
  374. };
  375. /// Specialization degree->radian in 3D
  376. template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
  377. struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
  378. {
  379. typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
  380. };
  381. /// Specialization radian->degree in 3D
  382. template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
  383. struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
  384. {
  385. typedef degree_radian_vv_3<P1, P2, std::divides> type;
  386. };
  387. /// Specialization to transform from unit sphere(phi,theta) to XYZ
  388. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  389. struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
  390. {
  391. typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type;
  392. };
  393. /// Specialization to transform from sphere(phi,theta,r) to XYZ
  394. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  395. struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
  396. {
  397. typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type;
  398. };
  399. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  400. struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
  401. {
  402. typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type;
  403. };
  404. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  405. struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
  406. {
  407. typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type;
  408. };
  409. /// Specialization to transform from XYZ to unit sphere(phi,theta)
  410. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  411. struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
  412. {
  413. typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type;
  414. };
  415. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  416. struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
  417. {
  418. typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type;
  419. };
  420. /// Specialization to transform from XYZ to sphere(phi,theta,r)
  421. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  422. struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
  423. {
  424. typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type;
  425. };
  426. template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
  427. struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
  428. {
  429. typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
  430. };
  431. } // namespace services
  432. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  433. }} // namespace strategy::transform
  434. }} // namespace boost::geometry
  435. #endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP