decompose3DMatrix static method
Implementation
static List? decompose3DMatrix(Matrix4 matrix4) {
List<double> m4storage = matrix4.storage;
List<List<double>> matrix = [
m4storage.sublist(0, 4),
m4storage.sublist(4, 8),
m4storage.sublist(8, 12),
m4storage.sublist(12, 16)
];
// Returns null if the matrix cannot be decomposed.
// Normalize the matrix.
if (matrix[3][3] == 0) {
return null;
}
// perspectiveMatrix is used to solve for perspective, but it also provides
// an easy way to test for singularity of the upper 3x3 component.
List<List<double>?> perspectiveMatrix = List.filled(4, null);
for (int i = 0; i < 4; i++) {
perspectiveMatrix[i] = matrix[i].sublist(0);
}
for (int i = 0; i < 3; i++) {
perspectiveMatrix[i]![3] = 0;
}
perspectiveMatrix[3]![3] = 1;
if (_determinant(perspectiveMatrix) == 0) {
return null;
}
// First, isolate perspective.
// rightHandSide is the right hand side of the equation.
List<double> rightHandSide = List.filled(4, 0);
List<double> perspective;
if (matrix[0][3] != 0 || matrix[1][3] != 0 || matrix[2][3] != 0) {
rightHandSide[0] = matrix[0][3];
rightHandSide[1] = matrix[1][3];
rightHandSide[2] = matrix[2][3];
rightHandSide[3] = matrix[3][3];
// Solve the equation by inverting perspectiveMatrix and multiplying
// rightHandSide by the inverse.
var inversePerspectiveMatrix = _inverse(perspectiveMatrix);
var transposedInversePerspectiveMatrix = _transposeMatrix4(inversePerspectiveMatrix);
perspective = _multVecMatrix(rightHandSide, transposedInversePerspectiveMatrix);
} else {
// No perspective.
perspective = [0, 0, 0, 1];
}
// Next take care of translation
List<double> translate = matrix[3].sublist(0, 3);
// Now get scale and shear. 'row' is a 3 element array of 3 component vectors
List<List<double>> row = [];
row.add(matrix[0].sublist(0, 3));
// Compute X scale factor and _normalize first row.
List<double> scale = List.filled(3, 0);
scale[0] = _length(row[0]);
row[0] = _normalize(row[0]);
// Compute XY shear factor and make 2nd row orthogonal to 1st.
// skew factors XY,XZ,YZ represented as a 3 component vector
List<double> skew = List.filled(3, 0);
row.add(matrix[1].sublist(0, 3));
skew[0] = _dot(row[0], row[1]);
row[1] = _combine(row[1], row[0], 1.0, -skew[0]);
// Now, compute Y scale and _normalize 2nd row.
scale[1] = _length(row[1]);
row[1] = _normalize(row[1]);
skew[0] /= scale[1];
// Compute XZ and YZ shears, orthogonalize 3rd row
row.add(matrix[2].sublist(0, 3));
skew[1] = _dot(row[0], row[2]);
row[2] = _combine(row[2], row[0], 1.0, -skew[1]);
skew[2] = _dot(row[1], row[2]);
row[2] = _combine(row[2], row[1], 1.0, -skew[2]);
// Next, get Z scale and _normalize 3rd row.
scale[2] = _length(row[2]);
row[2] = _normalize(row[2]);
skew[1] /= scale[2];
skew[2] /= scale[2];
// At this point, the matrix (in rows) is orthonormal.
// Check for a coordinate system flip. If the _determinant
// is -1, then negate the matrix and the scaling factors.
var pdum3 = _cross(row[1], row[2]);
if (_dot(row[0], pdum3) < 0) {
for (var i = 0; i < 3; i++) {
scale[i] *= -1;
row[i][0] *= -1;
row[i][1] *= -1;
row[i][2] *= -1;
}
}
// Now, get the rotations out
List<double> quaternion = List.filled(4, 0); // a 4 component vector
quaternion[0] = 0.5 * sqrt(max<double>(1 + row[0][0] - row[1][1] - row[2][2], 0));
quaternion[1] = 0.5 * sqrt(max<double>(1 - row[0][0] + row[1][1] - row[2][2], 0));
quaternion[2] = 0.5 * sqrt(max<double>(1 - row[0][0] - row[1][1] + row[2][2], 0));
quaternion[3] = 0.5 * sqrt(max<double>(1 + row[0][0] + row[1][1] + row[2][2], 0));
if (row[2][1] > row[1][2])
quaternion[0] = -quaternion[0];
if (row[0][2] > row[2][0])
quaternion[1] = -quaternion[1];
if (row[1][0] > row[0][1])
quaternion[2] = -quaternion[2];
return [translate, scale, skew, perspective, quaternion];
}