📄 transformationmatrix.cpp
字号:
/* * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "TransformationMatrix.h"#include "FloatPoint3D.h"#include "FloatRect.h"#include "FloatQuad.h"#include "IntRect.h"#include <wtf/MathExtras.h>namespace WebCore {//// Supporting Math Functions//// This is a set of function from various places (attributed inline) to do things like// inversion and decomposition of a 4x4 matrix. They are used throughout the code////// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes // with no guarantee.typedef double Vector4[4];typedef double Vector3[3];const double SMALL_NUMBER = 1.e-8;// inverse(original_matrix, inverse_matrix)// // calculate the inverse of a 4x4 matrix// // -1 // A = ___1__ adjoint A// det A// double = determinant2x2(double a, double b, double c, double d)// // calculate the determinant of a 2x2 matrix.static double determinant2x2(double a, double b, double c, double d){ return a * d - b * c;}// double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)// // Calculate the determinant of a 3x3 matrix// in the form// // | a1, b1, c1 |// | a2, b2, c2 |// | a3, b3, c3 |static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3){ return a1 * determinant2x2(b2, b3, c2, c3) - b1 * determinant2x2(a2, a3, c2, c3) + c1 * determinant2x2(a2, a3, b2, b3);}// double = determinant4x4(matrix)// // calculate the determinant of a 4x4 matrix.static double determinant4x4(const TransformationMatrix::Matrix4& m){ // Assign to individual variable names to aid selecting // correct elements double a1 = m[0][0]; double b1 = m[0][1]; double c1 = m[0][2]; double d1 = m[0][3]; double a2 = m[1][0]; double b2 = m[1][1]; double c2 = m[1][2]; double d2 = m[1][3]; double a3 = m[2][0]; double b3 = m[2][1]; double c3 = m[2][2]; double d3 = m[2][3]; double a4 = m[3][0]; double b4 = m[3][1]; double c4 = m[3][2]; double d4 = m[3][3]; return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);}// adjoint( original_matrix, inverse_matrix )//// calculate the adjoint of a 4x4 matrix//// Let a denote the minor determinant of matrix A obtained by// ij//// deleting the ith row and jth column from A.// // i+j// Let b = (-1) a// ij ji// // The matrix B = (b ) is the adjoint of A// ijstatic void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result){ // Assign to individual variable names to aid // selecting correct values double a1 = matrix[0][0]; double b1 = matrix[0][1]; double c1 = matrix[0][2]; double d1 = matrix[0][3]; double a2 = matrix[1][0]; double b2 = matrix[1][1]; double c2 = matrix[1][2]; double d2 = matrix[1][3]; double a3 = matrix[2][0]; double b3 = matrix[2][1]; double c3 = matrix[2][2]; double d3 = matrix[2][3]; double a4 = matrix[3][0]; double b4 = matrix[3][1]; double c4 = matrix[3][2]; double d4 = matrix[3][3]; // Row column labeling reversed since we transpose rows & columns result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);}// Returns false if the matrix is not invertiblestatic bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result){ // Calculate the adjoint matrix adjoint(matrix, result); // Calculate the 4x4 determinant // If the determinant is zero, // then the inverse matrix is not unique. double det = determinant4x4(matrix); if (fabs(det) < SMALL_NUMBER) return false; // Scale the adjoint matrix to get the inverse for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) result[i][j] = result[i][j] / det; return true;}// End of code adapted from Matrix Inversion by Richard Carling// Perform a decomposition on the passed matrix, return false if unsuccessful// From Graphics Gems: unmatrix.c// Transpose rotation portion of matrix a, return bstatic void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b){ for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) b[i][j] = a[j][i];}// Multiply a homogeneous point by a matrix and return the transformed pointstatic void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result){ result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) + (p[2] * m[2][0]) + (p[3] * m[3][0]); result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) + (p[2] * m[2][1]) + (p[3] * m[3][1]); result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) + (p[2] * m[2][2]) + (p[3] * m[3][2]); result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) + (p[2] * m[2][3]) + (p[3] * m[3][3]);}static double v3Length(Vector3 a){ return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));}static void v3Scale(Vector3 v, double desiredLength) { double len = v3Length(v); if (len != 0) { double l = desiredLength / len; v[0] *= l; v[1] *= l; v[2] *= l; }}static double v3Dot(const Vector3 a, const Vector3 b) { return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);}// Make a linear combination of two vectors and return the result.// result = (a * ascl) + (b * bscl)static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl){ result[0] = (ascl * a[0]) + (bscl * b[0]); result[1] = (ascl * a[1]) + (bscl * b[1]); result[2] = (ascl * a[2]) + (bscl * b[2]);}// Return the cross product result = a cross b */static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result){ result[0] = (a[1] * b[2]) - (a[2] * b[1]); result[1] = (a[2] * b[0]) - (a[0] * b[2]); result[2] = (a[0] * b[1]) - (a[1] * b[0]);}static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result){ TransformationMatrix::Matrix4 localMatrix; memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4)); // Normalize the matrix. if (localMatrix[3][3] == 0) return false; int i, j; for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) localMatrix[i][j] /= localMatrix[3][3]; // perspectiveMatrix is used to solve for perspective, but it also provides // an easy way to test for singularity of the upper 3x3 component. TransformationMatrix::Matrix4 perspectiveMatrix; memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4)); for (i = 0; i < 3; i++) perspectiveMatrix[i][3] = 0; perspectiveMatrix[3][3] = 1; if (determinant4x4(perspectiveMatrix) == 0) return false; // First, isolate perspective. This is the messiest. if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) { // rightHandSide is the right hand side of the equation. Vector4 rightHandSide; rightHandSide[0] = localMatrix[0][3]; rightHandSide[1] = localMatrix[1][3]; rightHandSide[2] = localMatrix[2][3]; rightHandSide[3] = localMatrix[3][3]; // Solve the equation by inverting perspectiveMatrix and multiplying // rightHandSide by the inverse. (This is the easiest way, not // necessarily the best.) TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix; inverse(perspectiveMatrix, inversePerspectiveMatrix); transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); Vector4 perspectivePoint; v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); result.perspectiveX = perspectivePoint[0]; result.perspectiveY = perspectivePoint[1]; result.perspectiveZ = perspectivePoint[2]; result.perspectiveW = perspectivePoint[3]; // Clear the perspective partition localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0; localMatrix[3][3] = 1; } else { // No perspective. result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0; result.perspectiveW = 1; } // Next take care of translation (easy). result.translateX = localMatrix[3][0]; localMatrix[3][0] = 0; result.translateY = localMatrix[3][1]; localMatrix[3][1] = 0; result.translateZ = localMatrix[3][2]; localMatrix[3][2] = 0; // Vector4 type and functions need to be added to the common set. Vector3 row[3], pdum3; // Now get scale and shear. for (i = 0; i < 3; i++) { row[i][0] = localMatrix[i][0]; row[i][1] = localMatrix[i][1]; row[i][2] = localMatrix[i][2]; } // Compute X scale factor and normalize first row. result.scaleX = v3Length(row[0]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -