decompose3DMatrix static method

List? decompose3DMatrix(
  1. Matrix4 matrix4
)

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];
}