]> git.tdb.fi Git - libs/math.git/blob - source/geometry/affinetransformation.h
0e377baaa51d633186969ace978494d79edfccf1
[libs/math.git] / source / geometry / affinetransformation.h
1 #ifndef MSP_GEOMETRY_AFFINETRANSFORMATION_H_
2 #define MSP_GEOMETRY_AFFINETRANSFORMATION_H_
3
4 #include <msp/linal/squarematrix.h>
5 #include "angle.h"
6
7 namespace Msp {
8 namespace Geometry {
9
10 template<typename T, unsigned D>
11 class AffineTransformation;
12
13
14 /**
15 Helper class to provide specialized operations for AffineTransformation.
16 */
17 template<typename T, unsigned D>
18 class AffineTransformationOps
19 {
20 protected:
21         AffineTransformationOps() { }
22 };
23
24 template<typename T>
25 class AffineTransformationOps<T, 2>
26 {
27 protected:
28         AffineTransformationOps() { }
29
30 public:
31         static AffineTransformation<T, 2> rotation(const Angle<T> &);
32 };
33
34 template<typename T>
35 class AffineTransformationOps<T, 3>
36 {
37 protected:
38         AffineTransformationOps() { }
39
40 public:
41         static AffineTransformation<T, 3> rotation(const Angle<T> &, const LinAl::Vector<T, 3> &);
42 };
43
44
45 /**
46 An affine transformation in D dimensions.  Affine transformations preserve
47 straightness of lines and ratios of distances.  Angles and distances themselves
48 may change.  Internally this is represented by a square matrix of size D+1.
49 */
50 template<typename T, unsigned D>
51 class AffineTransformation: public AffineTransformationOps<T, D>
52 {
53         friend class AffineTransformationOps<T, D>;
54
55 private:
56         LinAl::SquareMatrix<T, D+1> matrix;
57
58 public:
59         AffineTransformation();
60
61         static AffineTransformation<T, D> translation(const LinAl::Vector<T, D> &);
62         static AffineTransformation<T, D> scaling(const LinAl::Vector<T, D> &);
63         static AffineTransformation<T, D> shear(const LinAl::Vector<T, D> &, const LinAl::Vector<T, D> &);
64
65         AffineTransformation &operator*=(const AffineTransformation &);
66         AffineTransformation &invert();
67
68         const LinAl::SquareMatrix<T, D+1> &get_matrix() const { return matrix; }
69         operator const LinAl::SquareMatrix<T, D+1> &() const { return matrix; }
70
71         LinAl::Vector<T, D> transform(const LinAl::Vector<T, D> &) const;
72         LinAl::Vector<T, D> transform_linear(const LinAl::Vector<T, D> &) const;
73 };
74
75 template<typename T, unsigned D>
76 inline AffineTransformation<T, D>::AffineTransformation()
77 {
78         this->matrix = LinAl::SquareMatrix<T, D+1>::identity();
79 }
80
81
82 template<typename T, unsigned D>
83 AffineTransformation<T, D> AffineTransformation<T, D>::translation(const LinAl::Vector<T, D> &v)
84 {
85         AffineTransformation<T, D> r;
86         for(unsigned i=0; i<D; ++i)
87                 r.matrix(i, D) = v[i];
88         return r;
89 }
90
91 template<typename T, unsigned D>
92 AffineTransformation<T, D> AffineTransformation<T, D>::scaling(const LinAl::Vector<T, D> &factors)
93 {
94         AffineTransformation<T, D> r;
95         for(unsigned i=0; i<D; ++i)
96                 r.matrix(i, i) = factors[i];
97         return r;
98 }
99
100 template<typename T, unsigned D>
101 AffineTransformation<T, D> AffineTransformation<T, D>::shear(const LinAl::Vector<T, D> &normal, const LinAl::Vector<T, D> &shift)
102 {
103         AffineTransformation<T, D> r;
104         for(unsigned i=0; i<D; ++i)
105                 for(unsigned j=0; j<D; ++j)
106                         r.matrix(i, j) += normal[j]*shift[i];
107         return r;
108 }
109
110 template<typename T>
111 AffineTransformation<T, 2> AffineTransformationOps<T, 2>::rotation(const Angle<T> &angle)
112 {
113         AffineTransformation<T, 2> r;
114         T c = cos(angle);
115         T s = sin(angle);
116         r.matrix(0, 0) = c;
117         r.matrix(0, 1) = -s;
118         r.matrix(1, 0) = s;
119         r.matrix(1, 1) = c;
120         return r;
121 }
122
123 template<typename T>
124 AffineTransformation<T, 3> AffineTransformationOps<T, 3>::rotation(const Angle<T> &angle, const LinAl::Vector<T, 3> &axis)
125 {
126         AffineTransformation<T, 3> r;
127         LinAl::Vector<T, 3> axn = normalize(axis);
128         T c = cos(angle);
129         T s = sin(angle);
130         // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
131         r.matrix(0, 0) = c+axn.x*axn.x*(1-c);
132         r.matrix(0, 1) = axn.x*axn.y*(1-c)-axn.z*s;
133         r.matrix(0, 2) = axn.x*axn.z*(1-c)+axn.y*s;
134         r.matrix(1, 0) = axn.y*axn.x*(1-c)+axn.z*s;
135         r.matrix(1, 1) = c+axn.y*axn.y*(1-c);
136         r.matrix(1, 2) = axn.y*axn.z*(1-c)-axn.x*s;
137         r.matrix(2, 0) = axn.z*axn.x*(1-c)-axn.y*s;
138         r.matrix(2, 1) = axn.z*axn.y*(1-c)+axn.x*s;
139         r.matrix(2, 2) = c+axn.z*axn.z*(1-c);
140         return r;
141 }
142
143 template<typename T, unsigned D>
144 inline AffineTransformation<T, D> &AffineTransformation<T, D>::operator*=(const AffineTransformation<T, D> &other)
145 {
146         matrix *= other.get_matrix();
147         return *this;
148 }
149
150 template<typename T, unsigned D>
151 inline AffineTransformation<T, D> operator*(const AffineTransformation<T, D> &at1, const AffineTransformation<T, D> &at2)
152 {
153         AffineTransformation<T, D> r = at1;
154         return r *= at2;
155 }
156
157 template<typename T, unsigned D>
158 inline AffineTransformation<T, D> &AffineTransformation<T, D>::invert()
159 {
160         matrix.invert();
161         return *this;
162 }
163
164 template<typename T, unsigned D>
165 inline AffineTransformation<T, D> invert(const AffineTransformation<T, D> &at)
166 {
167         AffineTransformation<T, D> r = at;
168         return r.invert();
169 }
170
171 template<typename T, unsigned D>
172 inline LinAl::Vector<T, D> AffineTransformation<T, D>::transform(const LinAl::Vector<T, D> &v) const
173 {
174         return LinAl::Vector<T, D>(matrix*LinAl::Vector<T, D+1>(v, T(1)));
175 }
176
177 template<typename T, unsigned D>
178 inline LinAl::Vector<T, D> AffineTransformation<T, D>::transform_linear(const LinAl::Vector<T, D> &v) const
179 {
180         return LinAl::Vector<T, D>(matrix*LinAl::Vector<T, D+1>(v, T(0)));
181 }
182
183 } // namespace Geometry
184 } // namespace Msp
185
186 #endif