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