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