]>
Commit | Line | Data |
---|---|---|
a90939db JF |
1 | /* |
2 | * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #ifndef TransformationMatrix_h | |
27 | #define TransformationMatrix_h | |
28 | ||
29 | #include "FloatPoint.h" | |
30 | #include "IntPoint.h" | |
31 | #include <string.h> //for memcpy | |
32 | ||
33 | #if PLATFORM(CG) | |
34 | #include <CoreGraphics/CGAffineTransform.h> | |
35 | #endif | |
36 | ||
37 | namespace WebCore { | |
38 | ||
39 | class IntRect; | |
40 | class FloatPoint3D; | |
41 | class FloatRect; | |
42 | class FloatQuad; | |
43 | ||
44 | class TransformationMatrix { | |
45 | public: | |
46 | typedef double Matrix4[4][4]; | |
47 | ||
48 | TransformationMatrix() { makeIdentity(); } | |
49 | TransformationMatrix(const TransformationMatrix& t) { *this = t; } | |
50 | TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); } | |
51 | TransformationMatrix(double m11, double m12, double m13, double m14, | |
52 | double m21, double m22, double m23, double m24, | |
53 | double m31, double m32, double m33, double m34, | |
54 | double m41, double m42, double m43, double m44) | |
55 | { | |
56 | setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44); | |
57 | } | |
58 | ||
59 | void setMatrix(double a, double b, double c, double d, double e, double f) | |
60 | { | |
61 | m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0; | |
62 | m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0; | |
63 | m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0; | |
64 | m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1; | |
65 | } | |
66 | ||
67 | void setMatrix(double m11, double m12, double m13, double m14, | |
68 | double m21, double m22, double m23, double m24, | |
69 | double m31, double m32, double m33, double m34, | |
70 | double m41, double m42, double m43, double m44) | |
71 | { | |
72 | m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14; | |
73 | m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24; | |
74 | m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34; | |
75 | m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44; | |
76 | } | |
77 | ||
78 | TransformationMatrix& operator =(const TransformationMatrix &t) | |
79 | { | |
80 | setMatrix(t.m_matrix); | |
81 | return *this; | |
82 | } | |
83 | ||
84 | TransformationMatrix& makeIdentity() | |
85 | { | |
86 | setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); | |
87 | return *this; | |
88 | } | |
89 | ||
90 | bool isIdentity() const | |
91 | { | |
92 | return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && | |
93 | m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && | |
94 | m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && | |
95 | m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1; | |
96 | } | |
97 | ||
98 | // This form preserves the double math from input to output | |
99 | void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); } | |
100 | ||
101 | // Map a 3D point through the transform, returning a 3D point. | |
102 | FloatPoint3D mapPoint(const FloatPoint3D&) const; | |
103 | ||
104 | // Map a 2D point through the transform, returning a 2D point. | |
105 | // Note that this ignores the z component, effectively projecting the point into the z=0 plane. | |
106 | FloatPoint mapPoint(const FloatPoint&) const; | |
107 | ||
108 | // Like the version above, except that it rounds the mapped point to the nearest integer value. | |
109 | IntPoint mapPoint(const IntPoint& p) const | |
110 | { | |
111 | return roundedIntPoint(mapPoint(p)); | |
112 | } | |
113 | ||
114 | // If the matrix has 3D components, the z component of the result is | |
115 | // dropped, effectively projecting the rect into the z=0 plane | |
116 | FloatRect mapRect(const FloatRect&) const; | |
117 | ||
118 | // Rounds the resulting mapped rectangle out. This is helpful for bounding | |
119 | // box computations but may not be what is wanted in other contexts. | |
120 | IntRect mapRect(const IntRect&) const; | |
121 | ||
122 | // If the matrix has 3D components, the z component of the result is | |
123 | // dropped, effectively projecting the quad into the z=0 plane | |
124 | FloatQuad mapQuad(const FloatQuad&) const; | |
125 | ||
126 | // Map a point on the z=0 plane into a point on | |
127 | // the plane with with the transform applied, by extending | |
128 | // a ray perpendicular to the source plane and computing | |
129 | // the local x,y position of the point where that ray intersects | |
130 | // with the destination plane. | |
131 | FloatPoint projectPoint(const FloatPoint&) const; | |
132 | // Projects the four corners of the quad | |
133 | FloatQuad projectQuad(const FloatQuad&) const; | |
134 | ||
135 | double m11() const { return m_matrix[0][0]; } | |
136 | void setM11(double f) { m_matrix[0][0] = f; } | |
137 | double m12() const { return m_matrix[0][1]; } | |
138 | void setM12(double f) { m_matrix[0][1] = f; } | |
139 | double m13() const { return m_matrix[0][2]; } | |
140 | void setM13(double f) { m_matrix[0][2] = f; } | |
141 | double m14() const { return m_matrix[0][3]; } | |
142 | void setM14(double f) { m_matrix[0][3] = f; } | |
143 | double m21() const { return m_matrix[1][0]; } | |
144 | void setM21(double f) { m_matrix[1][0] = f; } | |
145 | double m22() const { return m_matrix[1][1]; } | |
146 | void setM22(double f) { m_matrix[1][1] = f; } | |
147 | double m23() const { return m_matrix[1][2]; } | |
148 | void setM23(double f) { m_matrix[1][2] = f; } | |
149 | double m24() const { return m_matrix[1][3]; } | |
150 | void setM24(double f) { m_matrix[1][3] = f; } | |
151 | double m31() const { return m_matrix[2][0]; } | |
152 | void setM31(double f) { m_matrix[2][0] = f; } | |
153 | double m32() const { return m_matrix[2][1]; } | |
154 | void setM32(double f) { m_matrix[2][1] = f; } | |
155 | double m33() const { return m_matrix[2][2]; } | |
156 | void setM33(double f) { m_matrix[2][2] = f; } | |
157 | double m34() const { return m_matrix[2][3]; } | |
158 | void setM34(double f) { m_matrix[2][3] = f; } | |
159 | double m41() const { return m_matrix[3][0]; } | |
160 | void setM41(double f) { m_matrix[3][0] = f; } | |
161 | double m42() const { return m_matrix[3][1]; } | |
162 | void setM42(double f) { m_matrix[3][1] = f; } | |
163 | double m43() const { return m_matrix[3][2]; } | |
164 | void setM43(double f) { m_matrix[3][2] = f; } | |
165 | double m44() const { return m_matrix[3][3]; } | |
166 | void setM44(double f) { m_matrix[3][3] = f; } | |
167 | ||
168 | double a() const { return m_matrix[0][0]; } | |
169 | void setA(double a) { m_matrix[0][0] = a; } | |
170 | ||
171 | double b() const { return m_matrix[0][1]; } | |
172 | void setB(double b) { m_matrix[0][1] = b; } | |
173 | ||
174 | double c() const { return m_matrix[1][0]; } | |
175 | void setC(double c) { m_matrix[1][0] = c; } | |
176 | ||
177 | double d() const { return m_matrix[1][1]; } | |
178 | void setD(double d) { m_matrix[1][1] = d; } | |
179 | ||
180 | double e() const { return m_matrix[3][0]; } | |
181 | void setE(double e) { m_matrix[3][0] = e; } | |
182 | ||
183 | double f() const { return m_matrix[3][1]; } | |
184 | void setF(double f) { m_matrix[3][1] = f; } | |
185 | ||
186 | // this = this * mat | |
187 | TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; } | |
188 | ||
189 | // this = mat * this | |
190 | TransformationMatrix& multLeft(const TransformationMatrix& mat); | |
191 | ||
192 | TransformationMatrix& scale(double); | |
193 | TransformationMatrix& scaleNonUniform(double sx, double sy); | |
194 | TransformationMatrix& scale3d(double sx, double sy, double sz); | |
195 | ||
196 | TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); } | |
197 | TransformationMatrix& rotateFromVector(double x, double y); | |
198 | TransformationMatrix& rotate3d(double rx, double ry, double rz); | |
199 | ||
200 | // The vector (x,y,z) is normalized if it's not already. A vector of | |
201 | // (0,0,0) uses a vector of (0,0,1). | |
202 | TransformationMatrix& rotate3d(double x, double y, double z, double angle); | |
203 | ||
204 | TransformationMatrix& translate(double tx, double ty); | |
205 | TransformationMatrix& translate3d(double tx, double ty, double tz); | |
206 | ||
207 | // translation added with a post-multiply | |
208 | TransformationMatrix& translateRight(double tx, double ty); | |
209 | TransformationMatrix& translateRight3d(double tx, double ty, double tz); | |
210 | ||
211 | TransformationMatrix& flipX(); | |
212 | TransformationMatrix& flipY(); | |
213 | TransformationMatrix& skew(double angleX, double angleY); | |
214 | TransformationMatrix& skewX(double angle) { return skew(angle, 0); } | |
215 | TransformationMatrix& skewY(double angle) { return skew(0, angle); } | |
216 | ||
217 | TransformationMatrix& applyPerspective(double p); | |
218 | bool hasPerspective() const { return m_matrix[2][3] != 0.0f; } | |
219 | ||
220 | bool isInvertible() const; | |
221 | ||
222 | // This method returns the identity matrix if it is not invertible. | |
223 | // Use isInvertible() before calling this if you need to know. | |
224 | TransformationMatrix inverse() const; | |
225 | ||
226 | // decompose the matrix into its component parts | |
227 | typedef struct { | |
228 | double scaleX, scaleY, scaleZ; | |
229 | double skewXY, skewXZ, skewYZ; | |
230 | double quaternionX, quaternionY, quaternionZ, quaternionW; | |
231 | double translateX, translateY, translateZ; | |
232 | double perspectiveX, perspectiveY, perspectiveZ, perspectiveW; | |
233 | } DecomposedType; | |
234 | ||
235 | bool decompose(DecomposedType& decomp) const; | |
236 | void recompose(const DecomposedType& decomp); | |
237 | ||
238 | void blend(const TransformationMatrix& from, double progress); | |
239 | ||
240 | bool isAffine() const | |
241 | { | |
242 | return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 && | |
243 | m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1); | |
244 | } | |
245 | ||
246 | // Throw away the non-affine parts of the matrix (lossy!) | |
247 | void makeAffine(); | |
248 | ||
249 | bool operator==(const TransformationMatrix& m2) const | |
250 | { | |
251 | return (m_matrix[0][0] == m2.m_matrix[0][0] && | |
252 | m_matrix[0][1] == m2.m_matrix[0][1] && | |
253 | m_matrix[0][2] == m2.m_matrix[0][2] && | |
254 | m_matrix[0][3] == m2.m_matrix[0][3] && | |
255 | m_matrix[1][0] == m2.m_matrix[1][0] && | |
256 | m_matrix[1][1] == m2.m_matrix[1][1] && | |
257 | m_matrix[1][2] == m2.m_matrix[1][2] && | |
258 | m_matrix[1][3] == m2.m_matrix[1][3] && | |
259 | m_matrix[2][0] == m2.m_matrix[2][0] && | |
260 | m_matrix[2][1] == m2.m_matrix[2][1] && | |
261 | m_matrix[2][2] == m2.m_matrix[2][2] && | |
262 | m_matrix[2][3] == m2.m_matrix[2][3] && | |
263 | m_matrix[3][0] == m2.m_matrix[3][0] && | |
264 | m_matrix[3][1] == m2.m_matrix[3][1] && | |
265 | m_matrix[3][2] == m2.m_matrix[3][2] && | |
266 | m_matrix[3][3] == m2.m_matrix[3][3]); | |
267 | } | |
268 | ||
269 | bool operator!=(const TransformationMatrix& other) const { return !(*this == other); } | |
270 | ||
271 | // *this = *this * t (i.e., a multRight) | |
272 | TransformationMatrix& operator*=(const TransformationMatrix& t) | |
273 | { | |
274 | *this = *this * t; | |
275 | return *this; | |
276 | } | |
277 | ||
278 | // result = *this * t (i.e., a multRight) | |
279 | TransformationMatrix operator*(const TransformationMatrix& t) | |
280 | { | |
281 | TransformationMatrix result = t; | |
282 | result.multLeft(*this); | |
283 | return result; | |
284 | } | |
285 | ||
286 | #if PLATFORM(CG) | |
287 | operator CGAffineTransform() const; | |
288 | #endif | |
289 | ||
290 | private: | |
291 | TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest); | |
292 | ||
293 | // multiply passed 2D point by matrix (assume z=0) | |
294 | void multVecMatrix(double x, double y, double& dstX, double& dstY) const; | |
295 | ||
296 | // multiply passed 3D point by matrix | |
297 | void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const; | |
298 | ||
299 | void setMatrix(const Matrix4 m) | |
300 | { | |
301 | if (m && m != m_matrix) | |
302 | memcpy(m_matrix, m, sizeof(Matrix4)); | |
303 | } | |
304 | ||
305 | bool isIdentityOrTranslation() const | |
306 | { | |
307 | return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && | |
308 | m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && | |
309 | m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && | |
310 | m_matrix[3][3] == 1; | |
311 | } | |
312 | ||
313 | Matrix4 m_matrix; | |
314 | }; | |
315 | ||
316 | } // namespace WebCore | |
317 | ||
318 | #endif // TransformationMatrix_h |