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