1 // Boost.Geometry (aka GGL, Generic Geometry Library)
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.
7 // This file was modified by Oracle on 2015.
8 // Modifications copyright (c) 2015 Oracle and/or its affiliates.
10 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
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)
19 #ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP
20 #define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP
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>
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>
43 namespace boost { namespace geometry
46 namespace strategy { namespace transform
49 namespace detail { namespace matrix_transformer
55 std::size_t Dimension = 0,
56 std::size_t DimensionCount = geometry::dimension<Point>::value
58 struct set_point_from_vec
60 template <typename Vector>
61 static inline void apply(Point & p, Vector const& v)
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);
72 std::size_t DimensionCount
74 struct set_point_from_vec<Point, DimensionCount, DimensionCount>
76 template <typename Vector>
77 static inline void apply(Point &, Vector const&) {}
83 std::size_t Dimension = 0,
84 std::size_t DimensionCount = geometry::dimension<Point>::value
86 struct set_vec_from_point
88 template <typename Vector>
89 static inline void apply(Point const& p, Vector & v)
91 qvm::A<Dimension>(v) = get<Dimension>(p);
92 set_vec_from_point<Point, Dimension + 1, DimensionCount>::apply(p, v);
99 std::size_t DimensionCount
101 struct set_vec_from_point<Point, DimensionCount, DimensionCount>
103 template <typename Vector>
104 static inline void apply(Point const&, Vector &) {}
109 typename CalculationType,
110 std::size_t Dimension1,
111 std::size_t Dimension2
113 class matrix_transformer
116 typedef CalculationType ct;
117 typedef boost::qvm::mat<ct, Dimension2 + 1, Dimension1 + 1> matrix_type;
118 matrix_type m_matrix;
120 matrix_type const& matrix() const { return m_matrix; }
121 template <typename P1, typename P2>
122 inline bool apply(P1 const& p1, P2& p2) const
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);
137 }} // namespace detail::matrix_transform
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
146 \tparam Dimension1 number of dimensions to transform from
147 \tparam Dimension2 number of dimensions to transform to
151 typename CalculationType,
152 std::size_t Dimension1,
153 std::size_t Dimension2
155 class matrix_transformer : public detail::matrix_transformer::matrix_transformer<CalculationType, Dimension1, Dimension2>
158 template<typename Matrix>
159 inline matrix_transformer(Matrix const& matrix)
161 qvm::assign(this->m_matrix, matrix);
163 inline matrix_transformer() {}
167 template <typename CalculationType>
168 class matrix_transformer<CalculationType, 2, 2> : public detail::matrix_transformer::matrix_transformer<CalculationType, 2, 2>
170 typedef CalculationType ct;
172 template<typename Matrix>
173 inline matrix_transformer(Matrix const& matrix)
175 qvm::assign(this->m_matrix, matrix);
178 inline matrix_transformer() {}
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)
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;
190 template <typename P1, typename P2>
191 inline bool apply(P1 const& p1, P2& p2) const
193 assert_dimension_greater_equal<P1, 2>();
194 assert_dimension_greater_equal<P2, 2>();
196 ct const& c1 = get<0>(p1);
197 ct const& c2 = get<1>(p1);
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)));
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>
212 typedef CalculationType ct;
214 template<typename Matrix>
215 inline matrix_transformer(Matrix const& matrix)
217 qvm::assign(this->m_matrix, matrix);
220 inline matrix_transformer() {}
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)
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;
232 template <typename P1, typename P2>
233 inline bool apply(P1 const& p1, P2& p2) const
235 assert_dimension_greater_equal<P1, 3>();
236 assert_dimension_greater_equal<P2, 2>();
238 ct const& c1 = get<0>(p1);
239 ct const& c2 = get<1>(p1);
240 ct const& c3 = get<2>(p1);
242 typedef typename geometry::coordinate_type<P2>::type ct2;
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)));
255 template <typename CalculationType>
256 class matrix_transformer<CalculationType, 3, 3> : public detail::matrix_transformer::matrix_transformer<CalculationType, 3, 3>
258 typedef CalculationType ct;
260 template<typename Matrix>
261 inline matrix_transformer(Matrix const& matrix)
263 qvm::assign(this->m_matrix, matrix);
266 inline matrix_transformer() {}
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
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;
281 template <typename P1, typename P2>
282 inline bool apply(P1 const& p1, P2& p2) const
284 assert_dimension_greater_equal<P1, 3>();
285 assert_dimension_greater_equal<P2, 3>();
287 ct const& c1 = get<0>(p1);
288 ct const& c2 = get<1>(p1);
289 ct const& c3 = get<2>(p1);
291 typedef typename geometry::coordinate_type<P2>::type ct2;
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)));
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
310 \tparam Dimension1 number of dimensions to transform from
311 \tparam Dimension2 number of dimensions to transform to
315 typename CalculationType,
316 std::size_t Dimension1,
317 std::size_t Dimension2
319 class translate_transformer
324 template<typename CalculationType>
325 class translate_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2>
328 // To have translate transformers compatible for 2/3 dimensions, the
329 // constructor takes an optional third argument doing nothing.
330 inline translate_transformer(CalculationType const& translate_x,
331 CalculationType const& translate_y,
332 CalculationType const& = 0)
333 : matrix_transformer<CalculationType, 2, 2>(
341 template <typename CalculationType>
342 class translate_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3>
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,
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
363 \tparam Dimension1 number of dimensions to transform from
364 \tparam Dimension2 number of dimensions to transform to
368 typename CalculationType,
369 std::size_t Dimension1,
370 std::size_t Dimension2
372 class scale_transformer
378 typename CalculationType,
379 std::size_t Dimension1
381 class scale_transformer<CalculationType, Dimension1, Dimension1> : public matrix_transformer<CalculationType, Dimension1, Dimension1>
384 inline scale_transformer(CalculationType const& scale)
386 boost::qvm::set_identity(this->m_matrix);
387 this->m_matrix*=scale;
388 qvm::A<Dimension1,Dimension1>(this->m_matrix) = 1;
392 template <typename CalculationType>
393 class scale_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2>
397 inline scale_transformer(CalculationType const& scale_x,
398 CalculationType const& scale_y,
399 CalculationType const& = 0)
400 : matrix_transformer<CalculationType, 2, 2>(
407 inline scale_transformer(CalculationType const& scale)
408 : matrix_transformer<CalculationType, 2, 2>(
416 template <typename CalculationType>
417 class scale_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3>
420 inline scale_transformer(CalculationType const& scale_x,
421 CalculationType const& scale_y,
422 CalculationType const& scale_z)
423 : matrix_transformer<CalculationType, 3, 3>(
431 inline scale_transformer(CalculationType const& scale)
432 : matrix_transformer<CalculationType, 3, 3>(
441 #ifndef DOXYGEN_NO_DETAIL
446 template <typename DegreeOrRadian>
452 struct as_radian<radian>
454 template <typename T>
455 static inline T get(T const& value)
462 struct as_radian<degree>
464 template <typename T>
465 static inline T get(T const& value)
467 typedef typename promote_floating_point<T>::type promoted_type;
468 return value * math::d2r<promoted_type>();
476 typename CalculationType,
477 std::size_t Dimension1,
478 std::size_t Dimension2
480 class rad_rotate_transformer
481 : public transform::matrix_transformer<CalculationType, Dimension1, Dimension2>
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,
493 } // namespace detail
494 #endif // DOXYGEN_NO_DETAIL
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
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.
510 typename DegreeOrRadian,
511 typename CalculationType,
512 std::size_t Dimension1,
513 std::size_t Dimension2
515 class rotate_transformer : public detail::rad_rotate_transformer<CalculationType, Dimension1, Dimension2>
519 inline rotate_transformer(CalculationType const& angle)
520 : detail::rad_rotate_transformer
522 CalculationType, Dimension1, Dimension2
523 >(detail::as_radian<DegreeOrRadian>::get(angle))
528 }} // namespace strategy::transform
531 }} // namespace boost::geometry
534 #endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP