Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / geometry / strategies / transform / matrix_transformers.hpp
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>
61     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>
77     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>
89     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>
104     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 :
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
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>
159     inline matrix_transformer(Matrix const& matrix)
160     {
161         qvm::assign(this->m_matrix, matrix);
162     }
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>
173     inline matrix_transformer(Matrix const& matrix)
174     {
175         qvm::assign(this->m_matrix, matrix);
176     }
177
178     inline matrix_transformer() {}
179
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>
191     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>
215     inline matrix_transformer(Matrix const& matrix)
216     {
217         qvm::assign(this->m_matrix, matrix);
218     }
219
220     inline matrix_transformer() {}
221
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>
233     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>
261     inline matrix_transformer(Matrix const& matrix)
262     {
263         qvm::assign(this->m_matrix, matrix);
264     }
265
266     inline matrix_transformer() {}
267
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>
282     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.
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 :
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:
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 :
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
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 :
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
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>
455     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>
465     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 :
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 :
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