OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "TransformationMatrix.h" | 27 #include "TransformationMatrix.h" |
28 | 28 |
| 29 #include "FloatPoint3D.h" |
29 #include "FloatRect.h" | 30 #include "FloatRect.h" |
30 #include "FloatQuad.h" | 31 #include "FloatQuad.h" |
31 #include "IntRect.h" | 32 #include "IntRect.h" |
32 | 33 |
33 #include <wtf/MathExtras.h> | 34 #include <wtf/MathExtras.h> |
34 | 35 |
35 namespace WebCore { | 36 namespace WebCore { |
36 | 37 |
37 static void affineTransformDecompose(const TransformationMatrix& matrix, double
sr[9]) | 38 // |
38 { | 39 // Supporting Math Functions |
39 TransformationMatrix m(matrix); | 40 // |
40 | 41 // This is a set of function from various places (attributed inline) to do thing
s like |
41 // Compute scaling factors | 42 // inversion and decomposition of a 4x4 matrix. They are used throughout the cod
e |
42 double sx = sqrt(m.a() * m.a() + m.b() * m.b()); | 43 // |
43 double sy = sqrt(m.c() * m.c() + m.d() * m.d()); | 44 |
44 | 45 // |
45 /* Compute cross product of transformed unit vectors. If negative, | 46 // Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.a
cm.org/GraphicsGems/index.html>. |
46 one axis was flipped. */ | 47 |
47 | 48 // EULA: The Graphics Gems code is copyright-protected. In other words, you cann
ot claim the text of the code |
48 if (m.a() * m.d() - m.c() * m.b() < 0.0) { | 49 // as your own and resell it. Using the code is permitted in any program, produc
t, or library, non-commercial |
49 // Flip axis with minimum unit vector dot product | 50 // or commercial. Giving credit is not required, though is a nice gesture. The c
ode comes as-is, and if there |
50 | 51 // are any flaws or problems with any Gems code, nobody involved with Gems - aut
hors, editors, publishers, or |
51 if (m.a() < m.d()) | 52 // webmasters - are to be held responsible. Basically, don't be a jerk, and reme
mber that anything free comes |
52 sx = -sx; | 53 // with no guarantee. |
53 else | 54 |
54 sy = -sy; | 55 typedef double Vector4[4]; |
55 } | 56 typedef double Vector3[3]; |
56 | 57 |
57 // Remove scale from matrix | 58 const double SMALL_NUMBER = 1.e-8; |
58 | 59 |
59 m.scale(1.0 / sx, 1.0 / sy); | 60 // inverse(original_matrix, inverse_matrix) |
60 | 61 // |
61 // Compute rotation | 62 // calculate the inverse of a 4x4 matrix |
62 | 63 // |
63 double angle = atan2(m.b(), m.a()); | 64 // -1 |
64 | 65 // A = ___1__ adjoint A |
65 // Remove rotation from matrix | 66 // det A |
66 | 67 |
67 m.rotate(rad2deg(-angle)); | 68 // double = determinant2x2(double a, double b, double c, double d) |
68 | 69 // |
69 // Return results | 70 // calculate the determinant of a 2x2 matrix. |
70 | 71 |
71 sr[0] = sx; sr[1] = sy; sr[2] = angle; | 72 static double determinant2x2(double a, double b, double c, double d) |
72 sr[3] = m.a(); sr[4] = m.b(); | 73 { |
73 sr[5] = m.c(); sr[6] = m.d(); | 74 return a * d - b * c; |
74 sr[7] = m.e(); sr[8] = m.f(); | 75 } |
75 } | 76 |
76 | 77 // double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3) |
77 static void affineTransformCompose(TransformationMatrix& m, const double sr[9]) | 78 // |
78 { | 79 // Calculate the determinant of a 3x3 matrix |
79 m.setA(sr[3]); | 80 // in the form |
80 m.setB(sr[4]); | 81 // |
81 m.setC(sr[5]); | 82 // | a1, b1, c1 | |
82 m.setD(sr[6]); | 83 // | a2, b2, c2 | |
83 m.setE(sr[7]); | 84 // | a3, b3, c3 | |
84 m.setF(sr[8]); | 85 |
85 m.rotate(rad2deg(sr[2])); | 86 static double determinant3x3(double a1, double a2, double a3, double b1, double
b2, double b3, double c1, double c2, double c3) |
86 m.scale(sr[0], sr[1]); | 87 { |
87 } | 88 return a1 * determinant2x2(b2, b3, c2, c3) |
88 | 89 - b1 * determinant2x2(a2, a3, c2, c3) |
89 bool TransformationMatrix::isInvertible() const | 90 + c1 * determinant2x2(a2, a3, b2, b3); |
90 { | 91 } |
91 return det() != 0.0; | 92 |
92 } | 93 // double = determinant4x4(matrix) |
93 | 94 // |
94 TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix&
other) | 95 // calculate the determinant of a 4x4 matrix. |
95 { | 96 |
96 return (*this) *= other; | 97 static double determinant4x4(const TransformationMatrix::Matrix4& m) |
97 } | 98 { |
| 99 // Assign to individual variable names to aid selecting |
| 100 // correct elements |
| 101 |
| 102 double a1 = m[0][0]; |
| 103 double b1 = m[0][1]; |
| 104 double c1 = m[0][2]; |
| 105 double d1 = m[0][3]; |
| 106 |
| 107 double a2 = m[1][0]; |
| 108 double b2 = m[1][1]; |
| 109 double c2 = m[1][2]; |
| 110 double d2 = m[1][3]; |
| 111 |
| 112 double a3 = m[2][0]; |
| 113 double b3 = m[2][1]; |
| 114 double c3 = m[2][2]; |
| 115 double d3 = m[2][3]; |
| 116 |
| 117 double a4 = m[3][0]; |
| 118 double b4 = m[3][1]; |
| 119 double c4 = m[3][2]; |
| 120 double d4 = m[3][3]; |
| 121 |
| 122 return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) |
| 123 - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) |
| 124 + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) |
| 125 - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); |
| 126 } |
| 127 |
| 128 // adjoint( original_matrix, inverse_matrix ) |
| 129 // |
| 130 // calculate the adjoint of a 4x4 matrix |
| 131 // |
| 132 // Let a denote the minor determinant of matrix A obtained by |
| 133 // ij |
| 134 // |
| 135 // deleting the ith row and jth column from A. |
| 136 // |
| 137 // i+j |
| 138 // Let b = (-1) a |
| 139 // ij ji |
| 140 // |
| 141 // The matrix B = (b ) is the adjoint of A |
| 142 // ij |
| 143 |
| 144 static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationM
atrix::Matrix4& result) |
| 145 { |
| 146 // Assign to individual variable names to aid |
| 147 // selecting correct values |
| 148 double a1 = matrix[0][0]; |
| 149 double b1 = matrix[0][1]; |
| 150 double c1 = matrix[0][2]; |
| 151 double d1 = matrix[0][3]; |
| 152 |
| 153 double a2 = matrix[1][0]; |
| 154 double b2 = matrix[1][1]; |
| 155 double c2 = matrix[1][2]; |
| 156 double d2 = matrix[1][3]; |
| 157 |
| 158 double a3 = matrix[2][0]; |
| 159 double b3 = matrix[2][1]; |
| 160 double c3 = matrix[2][2]; |
| 161 double d3 = matrix[2][3]; |
| 162 |
| 163 double a4 = matrix[3][0]; |
| 164 double b4 = matrix[3][1]; |
| 165 double c4 = matrix[3][2]; |
| 166 double d4 = matrix[3][3]; |
| 167 |
| 168 // Row column labeling reversed since we transpose rows & columns |
| 169 result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); |
| 170 result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); |
| 171 result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); |
| 172 result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); |
| 173 |
| 174 result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); |
| 175 result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); |
| 176 result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); |
| 177 result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); |
| 178 |
| 179 result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); |
| 180 result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); |
| 181 result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); |
| 182 result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); |
| 183 |
| 184 result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); |
| 185 result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); |
| 186 result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); |
| 187 result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); |
| 188 } |
| 189 |
| 190 // Returns false if the matrix is not invertible |
| 191 static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationM
atrix::Matrix4& result) |
| 192 { |
| 193 // Calculate the adjoint matrix |
| 194 adjoint(matrix, result); |
| 195 |
| 196 // Calculate the 4x4 determinant |
| 197 // If the determinant is zero, |
| 198 // then the inverse matrix is not unique. |
| 199 double det = determinant4x4(matrix); |
| 200 |
| 201 if (fabs(det) < SMALL_NUMBER) |
| 202 return false; |
| 203 |
| 204 // Scale the adjoint matrix to get the inverse |
| 205 |
| 206 for (int i = 0; i < 4; i++) |
| 207 for (int j = 0; j < 4; j++) |
| 208 result[i][j] = result[i][j] / det; |
| 209 |
| 210 return true; |
| 211 } |
| 212 |
| 213 // End of code adapted from Matrix Inversion by Richard Carling |
| 214 |
| 215 // Perform a decomposition on the passed matrix, return false if unsuccessful |
| 216 // From Graphics Gems: unmatrix.c |
| 217 |
| 218 // Transpose rotation portion of matrix a, return b |
| 219 static void transposeMatrix4(const TransformationMatrix::Matrix4& a, Transformat
ionMatrix::Matrix4& b) |
| 220 { |
| 221 for (int i = 0; i < 4; i++) |
| 222 for (int j = 0; j < 4; j++) |
| 223 b[i][j] = a[j][i]; |
| 224 } |
| 225 |
| 226 // Multiply a homogeneous point by a matrix and return the transformed point |
| 227 static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matr
ix4& m, Vector4 result) |
| 228 { |
| 229 result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) + |
| 230 (p[2] * m[2][0]) + (p[3] * m[3][0]); |
| 231 result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) + |
| 232 (p[2] * m[2][1]) + (p[3] * m[3][1]); |
| 233 result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) + |
| 234 (p[2] * m[2][2]) + (p[3] * m[3][2]); |
| 235 result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) + |
| 236 (p[2] * m[2][3]) + (p[3] * m[3][3]); |
| 237 } |
| 238 |
| 239 static double v3Length(Vector3 a) |
| 240 { |
| 241 return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2])); |
| 242 } |
| 243 |
| 244 static void v3Scale(Vector3 v, double desiredLength) |
| 245 { |
| 246 double len = v3Length(v); |
| 247 if (len != 0) { |
| 248 double l = desiredLength / len; |
| 249 v[0] *= l; |
| 250 v[1] *= l; |
| 251 v[2] *= l; |
| 252 } |
| 253 } |
| 254 |
| 255 static double v3Dot(const Vector3 a, const Vector3 b) |
| 256 { |
| 257 return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); |
| 258 } |
| 259 |
| 260 // Make a linear combination of two vectors and return the result. |
| 261 // result = (a * ascl) + (b * bscl) |
| 262 static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double a
scl, double bscl) |
| 263 { |
| 264 result[0] = (ascl * a[0]) + (bscl * b[0]); |
| 265 result[1] = (ascl * a[1]) + (bscl * b[1]); |
| 266 result[2] = (ascl * a[2]) + (bscl * b[2]); |
| 267 } |
| 268 |
| 269 // Return the cross product result = a cross b */ |
| 270 static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result) |
| 271 { |
| 272 result[0] = (a[1] * b[2]) - (a[2] * b[1]); |
| 273 result[1] = (a[2] * b[0]) - (a[0] * b[2]); |
| 274 result[2] = (a[0] * b[1]) - (a[1] * b[0]); |
| 275 } |
| 276 |
| 277 static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMa
trix::DecomposedType& result) |
| 278 { |
| 279 TransformationMatrix::Matrix4 localMatrix; |
| 280 memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4)); |
| 281 |
| 282 // Normalize the matrix. |
| 283 if (localMatrix[3][3] == 0) |
| 284 return false; |
| 285 |
| 286 int i, j; |
| 287 for (i = 0; i < 4; i++) |
| 288 for (j = 0; j < 4; j++) |
| 289 localMatrix[i][j] /= localMatrix[3][3]; |
| 290 |
| 291 // perspectiveMatrix is used to solve for perspective, but it also provides |
| 292 // an easy way to test for singularity of the upper 3x3 component. |
| 293 TransformationMatrix::Matrix4 perspectiveMatrix; |
| 294 memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4)
); |
| 295 for (i = 0; i < 3; i++) |
| 296 perspectiveMatrix[i][3] = 0; |
| 297 perspectiveMatrix[3][3] = 1; |
| 298 |
| 299 if (determinant4x4(perspectiveMatrix) == 0) |
| 300 return false; |
| 301 |
| 302 // First, isolate perspective. This is the messiest. |
| 303 if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] !=
0) { |
| 304 // rightHandSide is the right hand side of the equation. |
| 305 Vector4 rightHandSide; |
| 306 rightHandSide[0] = localMatrix[0][3]; |
| 307 rightHandSide[1] = localMatrix[1][3]; |
| 308 rightHandSide[2] = localMatrix[2][3]; |
| 309 rightHandSide[3] = localMatrix[3][3]; |
| 310 |
| 311 // Solve the equation by inverting perspectiveMatrix and multiplying |
| 312 // rightHandSide by the inverse. (This is the easiest way, not |
| 313 // necessarily the best.) |
| 314 TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInvers
ePerspectiveMatrix; |
| 315 inverse(perspectiveMatrix, inversePerspectiveMatrix); |
| 316 transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveM
atrix); |
| 317 |
| 318 Vector4 perspectivePoint; |
| 319 v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, pe
rspectivePoint); |
| 320 |
| 321 result.perspectiveX = perspectivePoint[0]; |
| 322 result.perspectiveY = perspectivePoint[1]; |
| 323 result.perspectiveZ = perspectivePoint[2]; |
| 324 result.perspectiveW = perspectivePoint[3]; |
| 325 |
| 326 // Clear the perspective partition |
| 327 localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0; |
| 328 localMatrix[3][3] = 1; |
| 329 } else { |
| 330 // No perspective. |
| 331 result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0; |
| 332 result.perspectiveW = 1; |
| 333 } |
| 334 |
| 335 // Next take care of translation (easy). |
| 336 result.translateX = localMatrix[3][0]; |
| 337 localMatrix[3][0] = 0; |
| 338 result.translateY = localMatrix[3][1]; |
| 339 localMatrix[3][1] = 0; |
| 340 result.translateZ = localMatrix[3][2]; |
| 341 localMatrix[3][2] = 0; |
| 342 |
| 343 // Vector4 type and functions need to be added to the common set. |
| 344 Vector3 row[3], pdum3; |
| 345 |
| 346 // Now get scale and shear. |
| 347 for (i = 0; i < 3; i++) { |
| 348 row[i][0] = localMatrix[i][0]; |
| 349 row[i][1] = localMatrix[i][1]; |
| 350 row[i][2] = localMatrix[i][2]; |
| 351 } |
| 352 |
| 353 // Compute X scale factor and normalize first row. |
| 354 result.scaleX = v3Length(row[0]); |
| 355 v3Scale(row[0], 1.0); |
| 356 |
| 357 // Compute XY shear factor and make 2nd row orthogonal to 1st. |
| 358 result.skewXY = v3Dot(row[0], row[1]); |
| 359 v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY); |
| 360 |
| 361 // Now, compute Y scale and normalize 2nd row. |
| 362 result.scaleY = v3Length(row[1]); |
| 363 v3Scale(row[1], 1.0); |
| 364 result.skewXY /= result.scaleY; |
| 365 |
| 366 // Compute XZ and YZ shears, orthogonalize 3rd row. |
| 367 result.skewXZ = v3Dot(row[0], row[2]); |
| 368 v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ); |
| 369 result.skewYZ = v3Dot(row[1], row[2]); |
| 370 v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ); |
| 371 |
| 372 // Next, get Z scale and normalize 3rd row. |
| 373 result.scaleZ = v3Length(row[2]); |
| 374 v3Scale(row[2], 1.0); |
| 375 result.skewXZ /= result.scaleZ; |
| 376 result.skewYZ /= result.scaleZ; |
| 377 |
| 378 // At this point, the matrix (in rows[]) is orthonormal. |
| 379 // Check for a coordinate system flip. If the determinant |
| 380 // is -1, then negate the matrix and the scaling factors. |
| 381 v3Cross(row[1], row[2], pdum3); |
| 382 if (v3Dot(row[0], pdum3) < 0) { |
| 383 for (i = 0; i < 3; i++) { |
| 384 result.scaleX *= -1; |
| 385 row[i][0] *= -1; |
| 386 row[i][1] *= -1; |
| 387 row[i][2] *= -1; |
| 388 } |
| 389 } |
| 390 |
| 391 // Now, get the rotations out, as described in the gem. |
| 392 |
| 393 // FIXME - Add the ability to return either quaternions (which are |
| 394 // easier to recompose with) or Euler angles (rx, ry, rz), which |
| 395 // are easier for authors to deal with. The latter will only be useful |
| 396 // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I |
| 397 // will leave the Euler angle code here for now. |
| 398 |
| 399 // ret.rotateY = asin(-row[0][2]); |
| 400 // if (cos(ret.rotateY) != 0) { |
| 401 // ret.rotateX = atan2(row[1][2], row[2][2]); |
| 402 // ret.rotateZ = atan2(row[0][1], row[0][0]); |
| 403 // } else { |
| 404 // ret.rotateX = atan2(-row[2][0], row[1][1]); |
| 405 // ret.rotateZ = 0; |
| 406 // } |
| 407 |
| 408 double s, t, x, y, z, w; |
| 409 |
| 410 t = row[0][0] + row[1][1] + row[2][2] + 1.0; |
| 411 |
| 412 if (t > 1e-4) { |
| 413 s = 0.5 / sqrt(t); |
| 414 w = 0.25 / s; |
| 415 x = (row[2][1] - row[1][2]) * s; |
| 416 y = (row[0][2] - row[2][0]) * s; |
| 417 z = (row[1][0] - row[0][1]) * s; |
| 418 } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) { |
| 419 s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx |
| 420 x = 0.25 * s; |
| 421 y = (row[0][1] + row[1][0]) / s; |
| 422 z = (row[0][2] + row[2][0]) / s; |
| 423 w = (row[2][1] - row[1][2]) / s; |
| 424 } else if (row[1][1] > row[2][2]) { |
| 425 s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy |
| 426 x = (row[0][1] + row[1][0]) / s; |
| 427 y = 0.25 * s; |
| 428 z = (row[1][2] + row[2][1]) / s; |
| 429 w = (row[0][2] - row[2][0]) / s; |
| 430 } else { |
| 431 s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz |
| 432 x = (row[0][2] + row[2][0]) / s; |
| 433 y = (row[1][2] + row[2][1]) / s; |
| 434 z = 0.25 * s; |
| 435 w = (row[1][0] - row[0][1]) / s; |
| 436 } |
| 437 |
| 438 result.quaternionX = x; |
| 439 result.quaternionY = y; |
| 440 result.quaternionZ = z; |
| 441 result.quaternionW = w; |
| 442 |
| 443 return true; |
| 444 } |
| 445 |
| 446 // Perform a spherical linear interpolation between the two |
| 447 // passed quaternions with 0 <= t <= 1 |
| 448 static void slerp(double qa[4], const double qb[4], double t) |
| 449 { |
| 450 double ax, ay, az, aw; |
| 451 double bx, by, bz, bw; |
| 452 double cx, cy, cz, cw; |
| 453 double angle; |
| 454 double th, invth, scale, invscale; |
| 455 |
| 456 ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3]; |
| 457 bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3]; |
| 458 |
| 459 angle = ax * bx + ay * by + az * bz + aw * bw; |
| 460 |
| 461 if (angle < 0.0) { |
| 462 ax = -ax; ay = -ay; |
| 463 az = -az; aw = -aw; |
| 464 angle = -angle; |
| 465 } |
| 466 |
| 467 if (angle + 1.0 > .05) { |
| 468 if (1.0 - angle >= .05) { |
| 469 th = acos (angle); |
| 470 invth = 1.0 / sin (th); |
| 471 scale = sin (th * (1.0 - t)) * invth; |
| 472 invscale = sin (th * t) * invth; |
| 473 } else { |
| 474 scale = 1.0 - t; |
| 475 invscale = t; |
| 476 } |
| 477 } else { |
| 478 bx = -ay; |
| 479 by = ax; |
| 480 bz = -aw; |
| 481 bw = az; |
| 482 scale = sin(piDouble * (.5 - t)); |
| 483 invscale = sin (piDouble * t); |
| 484 } |
| 485 |
| 486 cx = ax * scale + bx * invscale; |
| 487 cy = ay * scale + by * invscale; |
| 488 cz = az * scale + bz * invscale; |
| 489 cw = aw * scale + bw * invscale; |
| 490 |
| 491 qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw; |
| 492 } |
| 493 |
| 494 // End of Supporting Math Functions |
98 | 495 |
99 TransformationMatrix& TransformationMatrix::scale(double s) | 496 TransformationMatrix& TransformationMatrix::scale(double s) |
100 { | 497 { |
101 return scale(s, s); | 498 return scaleNonUniform(s, s); |
102 } | |
103 | |
104 TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy
) | |
105 { | |
106 return scale(sx, sy); | |
107 } | 499 } |
108 | 500 |
109 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) | 501 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) |
110 { | 502 { |
111 return rotate(rad2deg(atan2(y, x))); | 503 return rotate(rad2deg(atan2(y, x))); |
112 } | 504 } |
113 | 505 |
114 TransformationMatrix& TransformationMatrix::flipX() | 506 TransformationMatrix& TransformationMatrix::flipX() |
115 { | 507 { |
116 return scale(-1.0f, 1.0f); | 508 return scaleNonUniform(-1.0f, 1.0f); |
117 } | 509 } |
118 | 510 |
119 TransformationMatrix& TransformationMatrix::flipY() | 511 TransformationMatrix& TransformationMatrix::flipY() |
120 { | 512 { |
121 return scale(1.0f, -1.0f); | 513 return scaleNonUniform(1.0f, -1.0f); |
122 } | |
123 | |
124 TransformationMatrix& TransformationMatrix::skew(double angleX, double angleY) | |
125 { | |
126 return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY))); | |
127 } | |
128 | |
129 TransformationMatrix& TransformationMatrix::skewX(double angle) | |
130 { | |
131 return shear(tan(deg2rad(angle)), 0.0f); | |
132 } | |
133 | |
134 TransformationMatrix& TransformationMatrix::skewY(double angle) | |
135 { | |
136 return shear(0.0f, tan(deg2rad(angle))); | |
137 } | 514 } |
138 | 515 |
139 TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRec
t& dest) | 516 TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRec
t& dest) |
140 { | 517 { |
141 TransformationMatrix transform; | 518 TransformationMatrix transform; |
142 transform.translate(dest.x() - source.x(), dest.y() - source.y()); | 519 transform.translate(dest.x() - source.x(), dest.y() - source.y()); |
143 transform.scale(dest.width() / source.width(), dest.height() / source.height
()); | 520 transform.scaleNonUniform(dest.width() / source.width(), dest.height() / sou
rce.height()); |
144 return transform; | 521 return transform; |
145 } | 522 } |
146 | 523 |
| 524 FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const |
| 525 { |
| 526 // This is basically raytracing. We have a point in the destination |
| 527 // plane with z=0, and we cast a ray parallel to the z-axis from that |
| 528 // point to find the z-position at which it intersects the z=0 plane |
| 529 // with the transform applied. Once we have that point we apply the |
| 530 // inverse transform to find the corresponding point in the source |
| 531 // space. |
| 532 // |
| 533 // Given a plane with normal Pn, and a ray starting at point R0 and |
| 534 // with direction defined by the vector Rd, we can find the |
| 535 // intersection point as a distance d from R0 in units of Rd by: |
| 536 // |
| 537 // d = -dot (Pn', R0) / dot (Pn', Rd) |
| 538 |
| 539 double x = p.x(); |
| 540 double y = p.y(); |
| 541 double z = -(m13() * x + m23() * y + m43()) / m33(); |
| 542 |
| 543 double outX = x * m11() + y * m21() + z * m31() + m41(); |
| 544 double outY = x * m12() + y * m22() + z * m32() + m42(); |
| 545 |
| 546 double w = x * m14() + y * m24() + z * m34() + m44(); |
| 547 if (w != 1 && w != 0) { |
| 548 outX /= w; |
| 549 outY /= w; |
| 550 } |
| 551 |
| 552 return FloatPoint(static_cast<float>(outX), static_cast<float>(outY)); |
| 553 } |
| 554 |
| 555 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const |
| 556 { |
| 557 double x, y; |
| 558 multVecMatrix(p.x(), p.y(), x, y); |
| 559 return FloatPoint(static_cast<float>(x), static_cast<float>(y)); |
| 560 } |
| 561 |
| 562 FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const |
| 563 { |
| 564 double x, y, z; |
| 565 multVecMatrix(p.x(), p.y(), p.z(), x, y, z); |
| 566 return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cas
t<float>(z)); |
| 567 } |
| 568 |
147 IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const | 569 IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const |
148 { | 570 { |
149 double x2, y2; | 571 double x, y; |
150 map(point.x(), point.y(), &x2, &y2); | 572 multVecMatrix(point.x(), point.y(), x, y); |
151 | 573 |
152 // Round the point. | 574 // Round the point. |
153 return IntPoint(lround(x2), lround(y2)); | 575 return IntPoint(lround(x), lround(y)); |
154 } | 576 } |
155 | 577 |
156 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& point) const | 578 IntRect TransformationMatrix::mapRect(const IntRect &rect) const |
157 { | 579 { |
158 double x2, y2; | 580 return enclosingIntRect(mapRect(FloatRect(rect))); |
159 map(point.x(), point.y(), &x2, &y2); | 581 } |
160 | 582 |
161 return FloatPoint(static_cast<float>(x2), static_cast<float>(y2)); | 583 FloatRect TransformationMatrix::mapRect(const FloatRect& r) const |
162 } | 584 { |
163 | 585 FloatQuad resultQuad = mapQuad(FloatQuad(r)); |
164 FloatQuad TransformationMatrix::mapQuad(const FloatQuad& quad) const | 586 return resultQuad.boundingBox(); |
165 { | 587 } |
166 // FIXME: avoid 4 seperate library calls. Point mapping really needs | 588 |
167 // to be platform-independent code. | 589 FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const |
168 return FloatQuad(mapPoint(quad.p1()), | 590 { |
169 mapPoint(quad.p2()), | 591 FloatQuad result; |
170 mapPoint(quad.p3()), | 592 result.setP1(mapPoint(q.p1())); |
171 mapPoint(quad.p4())); | 593 result.setP2(mapPoint(q.p2())); |
| 594 result.setP3(mapPoint(q.p3())); |
| 595 result.setP4(mapPoint(q.p4())); |
| 596 return result; |
| 597 } |
| 598 |
| 599 TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy
) |
| 600 { |
| 601 TransformationMatrix mat; |
| 602 mat.m_matrix[0][0] = sx; |
| 603 mat.m_matrix[1][1] = sy; |
| 604 |
| 605 multLeft(mat); |
| 606 return *this; |
| 607 } |
| 608 |
| 609 TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double
sz) |
| 610 { |
| 611 TransformationMatrix mat; |
| 612 mat.m_matrix[0][0] = sx; |
| 613 mat.m_matrix[1][1] = sy; |
| 614 mat.m_matrix[2][2] = sz; |
| 615 |
| 616 multLeft(mat); |
| 617 return *this; |
| 618 } |
| 619 |
| 620 TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double
z, double angle) |
| 621 { |
| 622 // angles are in degrees. Switch to radians |
| 623 angle = deg2rad(angle); |
| 624 |
| 625 angle /= 2.0f; |
| 626 double sinA = sin(angle); |
| 627 double cosA = cos(angle); |
| 628 double sinA2 = sinA * sinA; |
| 629 |
| 630 // normalize |
| 631 double length = sqrt(x * x + y * y + z * z); |
| 632 if (length == 0) { |
| 633 // bad vector, just use something reasonable |
| 634 x = 0; |
| 635 y = 0; |
| 636 z = 1; |
| 637 } else if (length != 1) { |
| 638 x /= length; |
| 639 y /= length; |
| 640 z /= length; |
| 641 } |
| 642 |
| 643 TransformationMatrix mat; |
| 644 |
| 645 // optimize case where axis is along major axis |
| 646 if (x == 1.0f && y == 0.0f && z == 0.0f) { |
| 647 mat.m_matrix[0][0] = 1.0f; |
| 648 mat.m_matrix[0][1] = 0.0f; |
| 649 mat.m_matrix[0][2] = 0.0f; |
| 650 mat.m_matrix[1][0] = 0.0f; |
| 651 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; |
| 652 mat.m_matrix[1][2] = 2.0f * sinA * cosA; |
| 653 mat.m_matrix[2][0] = 0.0f; |
| 654 mat.m_matrix[2][1] = -2.0f * sinA * cosA; |
| 655 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; |
| 656 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; |
| 657 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; |
| 658 mat.m_matrix[3][3] = 1.0f; |
| 659 } else if (x == 0.0f && y == 1.0f && z == 0.0f) { |
| 660 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; |
| 661 mat.m_matrix[0][1] = 0.0f; |
| 662 mat.m_matrix[0][2] = -2.0f * sinA * cosA; |
| 663 mat.m_matrix[1][0] = 0.0f; |
| 664 mat.m_matrix[1][1] = 1.0f; |
| 665 mat.m_matrix[1][2] = 0.0f; |
| 666 mat.m_matrix[2][0] = 2.0f * sinA * cosA; |
| 667 mat.m_matrix[2][1] = 0.0f; |
| 668 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; |
| 669 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; |
| 670 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; |
| 671 mat.m_matrix[3][3] = 1.0f; |
| 672 } else if (x == 0.0f && y == 0.0f && z == 1.0f) { |
| 673 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; |
| 674 mat.m_matrix[0][1] = 2.0f * sinA * cosA; |
| 675 mat.m_matrix[0][2] = 0.0f; |
| 676 mat.m_matrix[1][0] = -2.0f * sinA * cosA; |
| 677 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; |
| 678 mat.m_matrix[1][2] = 0.0f; |
| 679 mat.m_matrix[2][0] = 0.0f; |
| 680 mat.m_matrix[2][1] = 0.0f; |
| 681 mat.m_matrix[2][2] = 1.0f; |
| 682 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; |
| 683 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; |
| 684 mat.m_matrix[3][3] = 1.0f; |
| 685 } else { |
| 686 double x2 = x*x; |
| 687 double y2 = y*y; |
| 688 double z2 = z*z; |
| 689 |
| 690 mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2; |
| 691 mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA); |
| 692 mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA); |
| 693 mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA); |
| 694 mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2; |
| 695 mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA); |
| 696 mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA); |
| 697 mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA); |
| 698 mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2; |
| 699 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; |
| 700 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; |
| 701 mat.m_matrix[3][3] = 1.0f; |
| 702 } |
| 703 multLeft(mat); |
| 704 return *this; |
| 705 } |
| 706 |
| 707 TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, doubl
e rz) |
| 708 { |
| 709 // angles are in degrees. Switch to radians |
| 710 rx = deg2rad(rx); |
| 711 ry = deg2rad(ry); |
| 712 rz = deg2rad(rz); |
| 713 |
| 714 TransformationMatrix mat; |
| 715 |
| 716 rz /= 2.0f; |
| 717 double sinA = sin(rz); |
| 718 double cosA = cos(rz); |
| 719 double sinA2 = sinA * sinA; |
| 720 |
| 721 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; |
| 722 mat.m_matrix[0][1] = 2.0f * sinA * cosA; |
| 723 mat.m_matrix[0][2] = 0.0f; |
| 724 mat.m_matrix[1][0] = -2.0f * sinA * cosA; |
| 725 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; |
| 726 mat.m_matrix[1][2] = 0.0f; |
| 727 mat.m_matrix[2][0] = 0.0f; |
| 728 mat.m_matrix[2][1] = 0.0f; |
| 729 mat.m_matrix[2][2] = 1.0f; |
| 730 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; |
| 731 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; |
| 732 mat.m_matrix[3][3] = 1.0f; |
| 733 |
| 734 TransformationMatrix rmat(mat); |
| 735 |
| 736 ry /= 2.0f; |
| 737 sinA = sin(ry); |
| 738 cosA = cos(ry); |
| 739 sinA2 = sinA * sinA; |
| 740 |
| 741 mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; |
| 742 mat.m_matrix[0][1] = 0.0f; |
| 743 mat.m_matrix[0][2] = -2.0f * sinA * cosA; |
| 744 mat.m_matrix[1][0] = 0.0f; |
| 745 mat.m_matrix[1][1] = 1.0f; |
| 746 mat.m_matrix[1][2] = 0.0f; |
| 747 mat.m_matrix[2][0] = 2.0f * sinA * cosA; |
| 748 mat.m_matrix[2][1] = 0.0f; |
| 749 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; |
| 750 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; |
| 751 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; |
| 752 mat.m_matrix[3][3] = 1.0f; |
| 753 |
| 754 rmat.multLeft(mat); |
| 755 |
| 756 rx /= 2.0f; |
| 757 sinA = sin(rx); |
| 758 cosA = cos(rx); |
| 759 sinA2 = sinA * sinA; |
| 760 |
| 761 mat.m_matrix[0][0] = 1.0f; |
| 762 mat.m_matrix[0][1] = 0.0f; |
| 763 mat.m_matrix[0][2] = 0.0f; |
| 764 mat.m_matrix[1][0] = 0.0f; |
| 765 mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; |
| 766 mat.m_matrix[1][2] = 2.0f * sinA * cosA; |
| 767 mat.m_matrix[2][0] = 0.0f; |
| 768 mat.m_matrix[2][1] = -2.0f * sinA * cosA; |
| 769 mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; |
| 770 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; |
| 771 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; |
| 772 mat.m_matrix[3][3] = 1.0f; |
| 773 |
| 774 rmat.multLeft(mat); |
| 775 |
| 776 multLeft(rmat); |
| 777 return *this; |
| 778 } |
| 779 |
| 780 TransformationMatrix& TransformationMatrix::translate(double tx, double ty) |
| 781 { |
| 782 TransformationMatrix mat; |
| 783 mat.m_matrix[3][0] = tx; |
| 784 mat.m_matrix[3][1] = ty; |
| 785 |
| 786 multLeft(mat); |
| 787 return *this; |
| 788 } |
| 789 |
| 790 TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, do
uble tz) |
| 791 { |
| 792 TransformationMatrix mat; |
| 793 mat.m_matrix[3][0] = tx; |
| 794 mat.m_matrix[3][1] = ty; |
| 795 mat.m_matrix[3][2] = tz; |
| 796 |
| 797 multLeft(mat); |
| 798 return *this; |
| 799 } |
| 800 |
| 801 TransformationMatrix& TransformationMatrix::skew(double sx, double sy) |
| 802 { |
| 803 // angles are in degrees. Switch to radians |
| 804 sx = deg2rad(sx); |
| 805 sy = deg2rad(sy); |
| 806 |
| 807 TransformationMatrix mat; |
| 808 mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row |
| 809 mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row |
| 810 |
| 811 multLeft(mat); |
| 812 return *this; |
| 813 } |
| 814 |
| 815 TransformationMatrix& TransformationMatrix::applyPerspective(double p) |
| 816 { |
| 817 TransformationMatrix mat; |
| 818 if (p != 0) |
| 819 mat.m_matrix[2][3] = -1/p; |
| 820 |
| 821 multLeft(mat); |
| 822 return *this; |
| 823 } |
| 824 |
| 825 // |
| 826 // *this = mat * *this |
| 827 // |
| 828 TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix&
mat) |
| 829 { |
| 830 Matrix4 tmp; |
| 831 |
| 832 tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_ma
trix[1][0] |
| 833 + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_ma
trix[3][0]); |
| 834 tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_ma
trix[1][1] |
| 835 + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_ma
trix[3][1]); |
| 836 tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_ma
trix[1][2] |
| 837 + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_ma
trix[3][2]); |
| 838 tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_ma
trix[1][3] |
| 839 + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_ma
trix[3][3]); |
| 840 |
| 841 tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_ma
trix[1][0] |
| 842 + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_ma
trix[3][0]); |
| 843 tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_ma
trix[1][1] |
| 844 + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_ma
trix[3][1]); |
| 845 tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_ma
trix[1][2] |
| 846 + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_ma
trix[3][2]); |
| 847 tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_ma
trix[1][3] |
| 848 + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_ma
trix[3][3]); |
| 849 |
| 850 tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_ma
trix[1][0] |
| 851 + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_ma
trix[3][0]); |
| 852 tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_ma
trix[1][1] |
| 853 + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_ma
trix[3][1]); |
| 854 tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_ma
trix[1][2] |
| 855 + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_ma
trix[3][2]); |
| 856 tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_ma
trix[1][3] |
| 857 + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_ma
trix[3][3]); |
| 858 |
| 859 tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_ma
trix[1][0] |
| 860 + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_ma
trix[3][0]); |
| 861 tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_ma
trix[1][1] |
| 862 + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_ma
trix[3][1]); |
| 863 tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_ma
trix[1][2] |
| 864 + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_ma
trix[3][2]); |
| 865 tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_ma
trix[1][3] |
| 866 + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_ma
trix[3][3]); |
| 867 |
| 868 setMatrix(tmp); |
| 869 return *this; |
| 870 } |
| 871 |
| 872 void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, do
uble& resultY) const |
| 873 { |
| 874 resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0]; |
| 875 resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1]; |
| 876 double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3]; |
| 877 if (w != 1 && w != 0) { |
| 878 resultX /= w; |
| 879 resultY /= w; |
| 880 } |
| 881 } |
| 882 |
| 883 void TransformationMatrix::multVecMatrix(double x, double y, double z, double& r
esultX, double& resultY, double& resultZ) const |
| 884 { |
| 885 resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_m
atrix[2][0]; |
| 886 resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_m
atrix[2][1]; |
| 887 resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_m
atrix[2][2]; |
| 888 double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_
matrix[2][3]; |
| 889 if (w != 1 && w != 0) { |
| 890 resultX /= w; |
| 891 resultY /= w; |
| 892 resultZ /= w; |
| 893 } |
| 894 } |
| 895 |
| 896 bool TransformationMatrix::isInvertible() const |
| 897 { |
| 898 double det = WebCore::determinant4x4(m_matrix); |
| 899 |
| 900 if (fabs(det) < SMALL_NUMBER) |
| 901 return false; |
| 902 |
| 903 return true; |
| 904 } |
| 905 |
| 906 TransformationMatrix TransformationMatrix::inverse() const |
| 907 { |
| 908 TransformationMatrix invMat; |
| 909 |
| 910 bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix); |
| 911 if (!inverted) |
| 912 return TransformationMatrix(); |
| 913 |
| 914 return invMat; |
| 915 } |
| 916 |
| 917 static inline void blendFloat(double& from, double to, double progress) |
| 918 { |
| 919 if (from != to) |
| 920 from = from + (to - from) * progress; |
172 } | 921 } |
173 | 922 |
174 void TransformationMatrix::blend(const TransformationMatrix& from, double progre
ss) | 923 void TransformationMatrix::blend(const TransformationMatrix& from, double progre
ss) |
175 { | 924 { |
176 double srA[9], srB[9]; | 925 if (from.isIdentity() && isIdentity()) |
177 | 926 return; |
178 affineTransformDecompose(from, srA); | 927 |
179 affineTransformDecompose(*this, srB); | 928 // decompose |
180 | 929 DecomposedType fromDecomp; |
181 // If x-axis of one is flipped, and y-axis of the other, convert to an unfli
pped rotation. | 930 DecomposedType toDecomp; |
182 if ((srA[0] < 0.0 && srB[1] < 0.0) || (srA[1] < 0.0 && srB[0] < 0.0)) { | 931 from.decompose(fromDecomp); |
183 srA[0] = -srA[0]; | 932 decompose(toDecomp); |
184 srA[1] = -srA[1]; | 933 |
185 srA[2] += srA[2] < 0 ? piDouble : -piDouble; | 934 // interpolate |
186 } | 935 blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress); |
187 | 936 blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress); |
188 // Don't rotate the long way around. | 937 blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress); |
189 srA[2] = fmod(srA[2], 2.0 * piDouble); | 938 blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress); |
190 srB[2] = fmod(srB[2], 2.0 * piDouble); | 939 blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress); |
191 | 940 blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress); |
192 if (fabs(srA[2] - srB[2]) > piDouble) { | 941 blendFloat(fromDecomp.translateX, toDecomp.translateX, progress); |
193 if (srA[2] > srB[2]) | 942 blendFloat(fromDecomp.translateY, toDecomp.translateY, progress); |
194 srA[2] -= piDouble * 2.0; | 943 blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress); |
195 else | 944 blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress); |
196 srB[2] -= piDouble * 2.0; | 945 blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress); |
197 } | 946 blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress); |
198 | 947 blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress); |
199 for (int i = 0; i < 9; i++) | 948 |
200 srA[i] = srA[i] + progress * (srB[i] - srA[i]); | 949 slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress); |
201 | 950 |
202 affineTransformCompose(*this, srA); | 951 // recompose |
203 } | 952 recompose(fromDecomp); |
204 | 953 } |
205 } | 954 |
| 955 bool TransformationMatrix::decompose(DecomposedType& decomp) const |
| 956 { |
| 957 if (isIdentity()) { |
| 958 memset(&decomp, 0, sizeof(decomp)); |
| 959 decomp.perspectiveW = 1; |
| 960 decomp.scaleX = 1; |
| 961 decomp.scaleY = 1; |
| 962 decomp.scaleZ = 1; |
| 963 } |
| 964 |
| 965 if (!WebCore::decompose(m_matrix, decomp)) |
| 966 return false; |
| 967 return true; |
| 968 } |
| 969 |
| 970 void TransformationMatrix::recompose(const DecomposedType& decomp) |
| 971 { |
| 972 makeIdentity(); |
| 973 |
| 974 // first apply perspective |
| 975 m_matrix[0][3] = (float) decomp.perspectiveX; |
| 976 m_matrix[1][3] = (float) decomp.perspectiveY; |
| 977 m_matrix[2][3] = (float) decomp.perspectiveZ; |
| 978 m_matrix[3][3] = (float) decomp.perspectiveW; |
| 979 |
| 980 // now translate |
| 981 translate3d((float) decomp.translateX, (float) decomp.translateY, (float) de
comp.translateZ); |
| 982 |
| 983 // apply rotation |
| 984 double xx = decomp.quaternionX * decomp.quaternionX; |
| 985 double xy = decomp.quaternionX * decomp.quaternionY; |
| 986 double xz = decomp.quaternionX * decomp.quaternionZ; |
| 987 double xw = decomp.quaternionX * decomp.quaternionW; |
| 988 double yy = decomp.quaternionY * decomp.quaternionY; |
| 989 double yz = decomp.quaternionY * decomp.quaternionZ; |
| 990 double yw = decomp.quaternionY * decomp.quaternionW; |
| 991 double zz = decomp.quaternionZ * decomp.quaternionZ; |
| 992 double zw = decomp.quaternionZ * decomp.quaternionW; |
| 993 |
| 994 // Construct a composite rotation matrix from the quaternion values |
| 995 TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (x
z + yw), 0, |
| 996 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0, |
| 997 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, |
| 998 0, 0, 0, 1); |
| 999 |
| 1000 multLeft(rotationMatrix); |
| 1001 |
| 1002 // now apply skew |
| 1003 if (decomp.skewYZ) { |
| 1004 TransformationMatrix tmp; |
| 1005 tmp.setM32((float) decomp.skewYZ); |
| 1006 multLeft(tmp); |
| 1007 } |
| 1008 |
| 1009 if (decomp.skewXZ) { |
| 1010 TransformationMatrix tmp; |
| 1011 tmp.setM31((float) decomp.skewXZ); |
| 1012 multLeft(tmp); |
| 1013 } |
| 1014 |
| 1015 if (decomp.skewXY) { |
| 1016 TransformationMatrix tmp; |
| 1017 tmp.setM21((float) decomp.skewXY); |
| 1018 multLeft(tmp); |
| 1019 } |
| 1020 |
| 1021 // finally, apply scale |
| 1022 scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ)
; |
| 1023 } |
| 1024 |
| 1025 } |
OLD | NEW |