matrix_transformers.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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_TRANSFORM_MATRIX_TRANSFORMERS_HPP
  14. #define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP
  15. #include <cstddef>
  16. #include <boost/qvm/mat.hpp>
  17. #include <boost/qvm/vec.hpp>
  18. #include <boost/qvm/mat_access.hpp>
  19. #include <boost/qvm/vec_access.hpp>
  20. #include <boost/qvm/mat_operations.hpp>
  21. #include <boost/qvm/vec_mat_operations.hpp>
  22. #include <boost/qvm/map_mat_mat.hpp>
  23. #include <boost/qvm/map_mat_vec.hpp>
  24. #include <boost/geometry/core/access.hpp>
  25. #include <boost/geometry/core/coordinate_dimension.hpp>
  26. #include <boost/geometry/core/coordinate_promotion.hpp>
  27. #include <boost/geometry/core/cs.hpp>
  28. #include <boost/geometry/util/math.hpp>
  29. #include <boost/geometry/util/numeric_cast.hpp>
  30. #include <boost/geometry/util/select_coordinate_type.hpp>
  31. #include <boost/geometry/util/select_most_precise.hpp>
  32. namespace boost { namespace geometry
  33. {
  34. namespace strategy { namespace transform
  35. {
  36. namespace detail { namespace matrix_transformer
  37. {
  38. template
  39. <
  40. typename Point,
  41. std::size_t Dimension = 0,
  42. std::size_t DimensionCount = geometry::dimension<Point>::value
  43. >
  44. struct set_point_from_vec
  45. {
  46. template <typename Vector>
  47. static inline void apply(Point & p, Vector const& v)
  48. {
  49. typedef typename geometry::coordinate_type<Point>::type coord_t;
  50. set<Dimension>(p, util::numeric_cast<coord_t>(qvm::A<Dimension>(v)));
  51. set_point_from_vec<Point, Dimension + 1, DimensionCount>::apply(p, v);
  52. }
  53. };
  54. template
  55. <
  56. typename Point,
  57. std::size_t DimensionCount
  58. >
  59. struct set_point_from_vec<Point, DimensionCount, DimensionCount>
  60. {
  61. template <typename Vector>
  62. static inline void apply(Point &, Vector const&) {}
  63. };
  64. template
  65. <
  66. typename Point,
  67. std::size_t Dimension = 0,
  68. std::size_t DimensionCount = geometry::dimension<Point>::value
  69. >
  70. struct set_vec_from_point
  71. {
  72. template <typename Vector>
  73. static inline void apply(Point const& p, Vector & v)
  74. {
  75. qvm::A<Dimension>(v) = get<Dimension>(p);
  76. set_vec_from_point<Point, Dimension + 1, DimensionCount>::apply(p, v);
  77. }
  78. };
  79. template
  80. <
  81. typename Point,
  82. std::size_t DimensionCount
  83. >
  84. struct set_vec_from_point<Point, DimensionCount, DimensionCount>
  85. {
  86. template <typename Vector>
  87. static inline void apply(Point const&, Vector &) {}
  88. };
  89. template
  90. <
  91. typename CalculationType,
  92. std::size_t Dimension1,
  93. std::size_t Dimension2
  94. >
  95. class matrix_transformer
  96. {
  97. protected :
  98. typedef CalculationType ct;
  99. typedef boost::qvm::mat<ct, Dimension2 + 1, Dimension1 + 1> matrix_type;
  100. matrix_type m_matrix;
  101. public :
  102. matrix_type const& matrix() const { return m_matrix; }
  103. template <typename P1, typename P2>
  104. inline bool apply(P1 const& p1, P2& p2) const
  105. {
  106. assert_dimension_greater_equal<P1,Dimension1>();
  107. assert_dimension_greater_equal<P2,Dimension2>();
  108. qvm::vec<ct,Dimension1 + 1> p1temp;
  109. qvm::A<Dimension1>(p1temp) = 1;
  110. qvm::vec<ct,Dimension2 + 1> p2temp;
  111. set_vec_from_point<P1, 0, Dimension1>::apply(p1, p1temp);
  112. p2temp = m_matrix * p1temp;
  113. set_point_from_vec<P2, 0, Dimension2>::apply(p2, p2temp);
  114. return true;
  115. }
  116. };
  117. }} // namespace detail::matrix_transform
  118. /*!
  119. \brief Affine transformation strategy in Cartesian system.
  120. \details The strategy serves as a generic definition of an affine transformation
  121. matrix and procedure for applying it to a given point.
  122. \see http://en.wikipedia.org/wiki/Affine_transformation
  123. and http://www.devmaster.net/wiki/Transformation_matrices
  124. \ingroup strategies
  125. \tparam Dimension1 number of dimensions to transform from
  126. \tparam Dimension2 number of dimensions to transform to
  127. */
  128. template
  129. <
  130. typename CalculationType,
  131. std::size_t Dimension1,
  132. std::size_t Dimension2
  133. >
  134. class matrix_transformer : public detail::matrix_transformer::matrix_transformer<CalculationType, Dimension1, Dimension2>
  135. {
  136. public:
  137. template<typename Matrix>
  138. inline matrix_transformer(Matrix const& matrix)
  139. {
  140. qvm::assign(this->m_matrix, matrix);
  141. }
  142. inline matrix_transformer() {}
  143. };
  144. template <typename CalculationType>
  145. class matrix_transformer<CalculationType, 2, 2> : public detail::matrix_transformer::matrix_transformer<CalculationType, 2, 2>
  146. {
  147. typedef CalculationType ct;
  148. public :
  149. template<typename Matrix>
  150. inline matrix_transformer(Matrix const& matrix)
  151. {
  152. qvm::assign(this->m_matrix, matrix);
  153. }
  154. inline matrix_transformer() {}
  155. inline matrix_transformer(
  156. ct const& m_0_0, ct const& m_0_1, ct const& m_0_2,
  157. ct const& m_1_0, ct const& m_1_1, ct const& m_1_2,
  158. ct const& m_2_0, ct const& m_2_1, ct const& m_2_2)
  159. {
  160. qvm::A<0,0>(this->m_matrix) = m_0_0; qvm::A<0,1>(this->m_matrix) = m_0_1; qvm::A<0,2>(this->m_matrix) = m_0_2;
  161. qvm::A<1,0>(this->m_matrix) = m_1_0; qvm::A<1,1>(this->m_matrix) = m_1_1; qvm::A<1,2>(this->m_matrix) = m_1_2;
  162. qvm::A<2,0>(this->m_matrix) = m_2_0; qvm::A<2,1>(this->m_matrix) = m_2_1; qvm::A<2,2>(this->m_matrix) = m_2_2;
  163. }
  164. template <typename P1, typename P2>
  165. inline bool apply(P1 const& p1, P2& p2) const
  166. {
  167. assert_dimension_greater_equal<P1, 2>();
  168. assert_dimension_greater_equal<P2, 2>();
  169. ct const& c1 = get<0>(p1);
  170. ct const& c2 = get<1>(p1);
  171. typedef typename geometry::coordinate_type<P2>::type ct2;
  172. set<0>(p2, util::numeric_cast<ct2>(c1 * qvm::A<0,0>(this->m_matrix) + c2 * qvm::A<0,1>(this->m_matrix) + qvm::A<0,2>(this->m_matrix)));
  173. set<1>(p2, util::numeric_cast<ct2>(c1 * qvm::A<1,0>(this->m_matrix) + c2 * qvm::A<1,1>(this->m_matrix) + qvm::A<1,2>(this->m_matrix)));
  174. return true;
  175. }
  176. };
  177. // It IS possible to go from 3 to 2 coordinates
  178. template <typename CalculationType>
  179. class matrix_transformer<CalculationType, 3, 2> : public detail::matrix_transformer::matrix_transformer<CalculationType, 3, 2>
  180. {
  181. typedef CalculationType ct;
  182. public :
  183. template<typename Matrix>
  184. inline matrix_transformer(Matrix const& matrix)
  185. {
  186. qvm::assign(this->m_matrix, matrix);
  187. }
  188. inline matrix_transformer() {}
  189. inline matrix_transformer(
  190. ct const& m_0_0, ct const& m_0_1, ct const& m_0_2,
  191. ct const& m_1_0, ct const& m_1_1, ct const& m_1_2,
  192. ct const& m_2_0, ct const& m_2_1, ct const& m_2_2)
  193. {
  194. qvm::A<0,0>(this->m_matrix) = m_0_0; qvm::A<0,1>(this->m_matrix) = m_0_1; qvm::A<0,2>(this->m_matrix) = 0; qvm::A<0,3>(this->m_matrix) = m_0_2;
  195. qvm::A<1,0>(this->m_matrix) = m_1_0; qvm::A<1,1>(this->m_matrix) = m_1_1; qvm::A<1,2>(this->m_matrix) = 0; qvm::A<1,3>(this->m_matrix) = m_1_2;
  196. qvm::A<2,0>(this->m_matrix) = m_2_0; qvm::A<2,1>(this->m_matrix) = m_2_1; qvm::A<2,2>(this->m_matrix) = 0; qvm::A<2,3>(this->m_matrix) = m_2_2;
  197. }
  198. template <typename P1, typename P2>
  199. inline bool apply(P1 const& p1, P2& p2) const
  200. {
  201. assert_dimension_greater_equal<P1, 3>();
  202. assert_dimension_greater_equal<P2, 2>();
  203. ct const& c1 = get<0>(p1);
  204. ct const& c2 = get<1>(p1);
  205. ct const& c3 = get<2>(p1);
  206. typedef typename geometry::coordinate_type<P2>::type ct2;
  207. set<0>(p2, util::numeric_cast<ct2>(
  208. c1 * qvm::A<0,0>(this->m_matrix) + c2 * qvm::A<0,1>(this->m_matrix) + c3 * qvm::A<0,2>(this->m_matrix) + qvm::A<0,3>(this->m_matrix)));
  209. set<1>(p2, util::numeric_cast<ct2>(
  210. c1 * qvm::A<1,0>(this->m_matrix) + c2 * qvm::A<1,1>(this->m_matrix) + c3 * qvm::A<1,2>(this->m_matrix) + qvm::A<1,3>(this->m_matrix)));
  211. return true;
  212. }
  213. };
  214. template <typename CalculationType>
  215. class matrix_transformer<CalculationType, 3, 3> : public detail::matrix_transformer::matrix_transformer<CalculationType, 3, 3>
  216. {
  217. typedef CalculationType ct;
  218. public :
  219. template<typename Matrix>
  220. inline matrix_transformer(Matrix const& matrix)
  221. {
  222. qvm::assign(this->m_matrix, matrix);
  223. }
  224. inline matrix_transformer() {}
  225. inline matrix_transformer(
  226. ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_0_3,
  227. ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_1_3,
  228. ct const& m_2_0, ct const& m_2_1, ct const& m_2_2, ct const& m_2_3,
  229. ct const& m_3_0, ct const& m_3_1, ct const& m_3_2, ct const& m_3_3
  230. )
  231. {
  232. qvm::A<0,0>(this->m_matrix) = m_0_0; qvm::A<0,1>(this->m_matrix) = m_0_1; qvm::A<0,2>(this->m_matrix) = m_0_2; qvm::A<0,3>(this->m_matrix) = m_0_3;
  233. qvm::A<1,0>(this->m_matrix) = m_1_0; qvm::A<1,1>(this->m_matrix) = m_1_1; qvm::A<1,2>(this->m_matrix) = m_1_2; qvm::A<1,3>(this->m_matrix) = m_1_3;
  234. qvm::A<2,0>(this->m_matrix) = m_2_0; qvm::A<2,1>(this->m_matrix) = m_2_1; qvm::A<2,2>(this->m_matrix) = m_2_2; qvm::A<2,3>(this->m_matrix) = m_2_3;
  235. qvm::A<3,0>(this->m_matrix) = m_3_0; qvm::A<3,1>(this->m_matrix) = m_3_1; qvm::A<3,2>(this->m_matrix) = m_3_2; qvm::A<3,3>(this->m_matrix) = m_3_3;
  236. }
  237. template <typename P1, typename P2>
  238. inline bool apply(P1 const& p1, P2& p2) const
  239. {
  240. assert_dimension_greater_equal<P1, 3>();
  241. assert_dimension_greater_equal<P2, 3>();
  242. ct const& c1 = get<0>(p1);
  243. ct const& c2 = get<1>(p1);
  244. ct const& c3 = get<2>(p1);
  245. typedef typename geometry::coordinate_type<P2>::type ct2;
  246. set<0>(p2, util::numeric_cast<ct2>(
  247. c1 * qvm::A<0,0>(this->m_matrix) + c2 * qvm::A<0,1>(this->m_matrix) + c3 * qvm::A<0,2>(this->m_matrix) + qvm::A<0,3>(this->m_matrix)));
  248. set<1>(p2, util::numeric_cast<ct2>(
  249. c1 * qvm::A<1,0>(this->m_matrix) + c2 * qvm::A<1,1>(this->m_matrix) + c3 * qvm::A<1,2>(this->m_matrix) + qvm::A<1,3>(this->m_matrix)));
  250. set<2>(p2, util::numeric_cast<ct2>(
  251. c1 * qvm::A<2,0>(this->m_matrix) + c2 * qvm::A<2,1>(this->m_matrix) + c3 * qvm::A<2,2>(this->m_matrix) + qvm::A<2,3>(this->m_matrix)));
  252. return true;
  253. }
  254. };
  255. /*!
  256. \brief Strategy of translate transformation in Cartesian system.
  257. \details Translate moves a geometry a fixed distance in 2 or 3 dimensions.
  258. \see http://en.wikipedia.org/wiki/Translation_%28geometry%29
  259. \ingroup strategies
  260. \tparam Dimension1 number of dimensions to transform from
  261. \tparam Dimension2 number of dimensions to transform to
  262. */
  263. template
  264. <
  265. typename CalculationType,
  266. std::size_t Dimension1,
  267. std::size_t Dimension2
  268. >
  269. class translate_transformer
  270. {
  271. };
  272. template<typename CalculationType>
  273. class translate_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2>
  274. {
  275. public :
  276. // To have translate transformers compatible for 2/3 dimensions, the
  277. // constructor takes an optional third argument doing nothing.
  278. inline translate_transformer(CalculationType const& translate_x,
  279. CalculationType const& translate_y,
  280. CalculationType const& = 0)
  281. : matrix_transformer<CalculationType, 2, 2>(
  282. 1, 0, translate_x,
  283. 0, 1, translate_y,
  284. 0, 0, 1)
  285. {}
  286. };
  287. template <typename CalculationType>
  288. class translate_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3>
  289. {
  290. public :
  291. inline translate_transformer(CalculationType const& translate_x,
  292. CalculationType const& translate_y,
  293. CalculationType const& translate_z)
  294. : matrix_transformer<CalculationType, 3, 3>(
  295. 1, 0, 0, translate_x,
  296. 0, 1, 0, translate_y,
  297. 0, 0, 1, translate_z,
  298. 0, 0, 0, 1)
  299. {}
  300. };
  301. /*!
  302. \brief Strategy of scale transformation in Cartesian system.
  303. \details Scale scales a geometry up or down in all its dimensions.
  304. \see http://en.wikipedia.org/wiki/Scaling_%28geometry%29
  305. \ingroup strategies
  306. \tparam Dimension1 number of dimensions to transform from
  307. \tparam Dimension2 number of dimensions to transform to
  308. */
  309. template
  310. <
  311. typename CalculationType,
  312. std::size_t Dimension1,
  313. std::size_t Dimension2
  314. >
  315. class scale_transformer
  316. {
  317. };
  318. template
  319. <
  320. typename CalculationType,
  321. std::size_t Dimension1
  322. >
  323. class scale_transformer<CalculationType, Dimension1, Dimension1> : public matrix_transformer<CalculationType, Dimension1, Dimension1>
  324. {
  325. public:
  326. inline scale_transformer(CalculationType const& scale)
  327. {
  328. boost::qvm::set_identity(this->m_matrix);
  329. this->m_matrix*=scale;
  330. qvm::A<Dimension1,Dimension1>(this->m_matrix) = 1;
  331. }
  332. };
  333. template <typename CalculationType>
  334. class scale_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2>
  335. {
  336. public :
  337. inline scale_transformer(CalculationType const& scale_x,
  338. CalculationType const& scale_y,
  339. CalculationType const& = 0)
  340. : matrix_transformer<CalculationType, 2, 2>(
  341. scale_x, 0, 0,
  342. 0, scale_y, 0,
  343. 0, 0, 1)
  344. {}
  345. inline scale_transformer(CalculationType const& scale)
  346. : matrix_transformer<CalculationType, 2, 2>(
  347. scale, 0, 0,
  348. 0, scale, 0,
  349. 0, 0, 1)
  350. {}
  351. };
  352. template <typename CalculationType>
  353. class scale_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3>
  354. {
  355. public :
  356. inline scale_transformer(CalculationType const& scale_x,
  357. CalculationType const& scale_y,
  358. CalculationType const& scale_z)
  359. : matrix_transformer<CalculationType, 3, 3>(
  360. scale_x, 0, 0, 0,
  361. 0, scale_y, 0, 0,
  362. 0, 0, scale_z, 0,
  363. 0, 0, 0, 1)
  364. {}
  365. inline scale_transformer(CalculationType const& scale)
  366. : matrix_transformer<CalculationType, 3, 3>(
  367. scale, 0, 0, 0,
  368. 0, scale, 0, 0,
  369. 0, 0, scale, 0,
  370. 0, 0, 0, 1)
  371. {}
  372. };
  373. #ifndef DOXYGEN_NO_DETAIL
  374. namespace detail
  375. {
  376. template <typename DegreeOrRadian>
  377. struct as_radian
  378. {};
  379. template <>
  380. struct as_radian<radian>
  381. {
  382. template <typename T>
  383. static inline T get(T const& value)
  384. {
  385. return value;
  386. }
  387. };
  388. template <>
  389. struct as_radian<degree>
  390. {
  391. template <typename T>
  392. static inline T get(T const& value)
  393. {
  394. typedef typename promote_floating_point<T>::type promoted_type;
  395. return value * math::d2r<promoted_type>();
  396. }
  397. };
  398. template
  399. <
  400. typename CalculationType,
  401. std::size_t Dimension1,
  402. std::size_t Dimension2
  403. >
  404. class rad_rotate_transformer
  405. : public transform::matrix_transformer<CalculationType, Dimension1, Dimension2>
  406. {
  407. public :
  408. inline rad_rotate_transformer(CalculationType const& angle)
  409. : transform::matrix_transformer<CalculationType, Dimension1, Dimension2>(
  410. cos(angle), sin(angle), 0,
  411. -sin(angle), cos(angle), 0,
  412. 0, 0, 1)
  413. {}
  414. };
  415. } // namespace detail
  416. #endif // DOXYGEN_NO_DETAIL
  417. /*!
  418. \brief Strategy for rotate transformation in Cartesian coordinate system.
  419. \details Rotate rotates a geometry by a specified angle about a fixed point (e.g. origin).
  420. \see http://en.wikipedia.org/wiki/Rotation_%28mathematics%29
  421. \ingroup strategies
  422. \tparam DegreeOrRadian degree/or/radian, type of rotation angle specification
  423. \note A single angle is needed to specify a rotation in 2D.
  424. Not yet in 3D, the 3D version requires special things to allow
  425. for rotation around X, Y, Z or arbitrary axis.
  426. \todo The 3D version will not compile.
  427. */
  428. template
  429. <
  430. typename DegreeOrRadian,
  431. typename CalculationType,
  432. std::size_t Dimension1,
  433. std::size_t Dimension2
  434. >
  435. class rotate_transformer : public detail::rad_rotate_transformer<CalculationType, Dimension1, Dimension2>
  436. {
  437. public :
  438. inline rotate_transformer(CalculationType const& angle)
  439. : detail::rad_rotate_transformer
  440. <
  441. CalculationType, Dimension1, Dimension2
  442. >(detail::as_radian<DegreeOrRadian>::get(angle))
  443. {}
  444. };
  445. }} // namespace strategy::transform
  446. }} // namespace boost::geometry
  447. #endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP