blob: 0e3e4b42801d69b14c35565cc5d32816f7ad8211 [file] [log] [blame]
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
part of vector_math;
/// 4D Matrix.
/// Values are stored in column major order.
class Matrix4 {
final Float32List _m4storage;
/// The components of the matrix.
Float32List get storage => _m4storage;
/// Solve [A] * [x] = [b].
static void solve2(Matrix4 A, Vector2 x, Vector2 b) {
final double a11 = A.entry(0, 0);
final double a12 = A.entry(0, 1);
final double a21 = A.entry(1, 0);
final double a22 = A.entry(1, 1);
final double bx = b.x - A._m4storage[8];
final double by = b.y - A._m4storage[9];
double det = a11 * a22 - a12 * a21;
if (det != 0.0) {
det = 1.0 / det;
}
x.x = det * (a22 * bx - a12 * by);
x.y = det * (a11 * by - a21 * bx);
}
/// Solve [A] * [x] = [b].
static void solve3(Matrix4 A, Vector3 x, Vector3 b) {
final double A0x = A.entry(0, 0);
final double A0y = A.entry(1, 0);
final double A0z = A.entry(2, 0);
final double A1x = A.entry(0, 1);
final double A1y = A.entry(1, 1);
final double A1z = A.entry(2, 1);
final double A2x = A.entry(0, 2);
final double A2y = A.entry(1, 2);
final double A2z = A.entry(2, 2);
final double bx = b.x - A._m4storage[12];
final double by = b.y - A._m4storage[13];
final double bz = b.z - A._m4storage[14];
double rx, ry, rz;
double det;
// Column1 cross Column 2
rx = A1y * A2z - A1z * A2y;
ry = A1z * A2x - A1x * A2z;
rz = A1x * A2y - A1y * A2x;
// A.getColumn(0).dot(x)
det = A0x * rx + A0y * ry + A0z * rz;
if (det != 0.0) {
det = 1.0 / det;
}
// b dot [Column1 cross Column 2]
final double x_ = det * (bx * rx + by * ry + bz * rz);
// Column2 cross b
rx = -(A2y * bz - A2z * by);
ry = -(A2z * bx - A2x * bz);
rz = -(A2x * by - A2y * bx);
// Column0 dot -[Column2 cross b (Column3)]
final double y_ = det * (A0x * rx + A0y * ry + A0z * rz);
// b cross Column 1
rx = -(by * A1z - bz * A1y);
ry = -(bz * A1x - bx * A1z);
rz = -(bx * A1y - by * A1x);
// Column0 dot -[b cross Column 1]
final double z_ = det * (A0x * rx + A0y * ry + A0z * rz);
x.x = x_;
x.y = y_;
x.z = z_;
}
/// Solve [A] * [x] = [b].
static void solve(Matrix4 A, Vector4 x, Vector4 b) {
final double a00 = A._m4storage[0];
final double a01 = A._m4storage[1];
final double a02 = A._m4storage[2];
final double a03 = A._m4storage[3];
final double a10 = A._m4storage[4];
final double a11 = A._m4storage[5];
final double a12 = A._m4storage[6];
final double a13 = A._m4storage[7];
final double a20 = A._m4storage[8];
final double a21 = A._m4storage[9];
final double a22 = A._m4storage[10];
final double a23 = A._m4storage[11];
final double a30 = A._m4storage[12];
final double a31 = A._m4storage[13];
final double a32 = A._m4storage[14];
final double a33 = A._m4storage[15];
final double b00 = a00 * a11 - a01 * a10;
final double b01 = a00 * a12 - a02 * a10;
final double b02 = a00 * a13 - a03 * a10;
final double b03 = a01 * a12 - a02 * a11;
final double b04 = a01 * a13 - a03 * a11;
final double b05 = a02 * a13 - a03 * a12;
final double b06 = a20 * a31 - a21 * a30;
final double b07 = a20 * a32 - a22 * a30;
final double b08 = a20 * a33 - a23 * a30;
final double b09 = a21 * a32 - a22 * a31;
final double b10 = a21 * a33 - a23 * a31;
final double b11 = a22 * a33 - a23 * a32;
final double bX = b.storage[0];
final double bY = b.storage[1];
final double bZ = b.storage[2];
final double bW = b.storage[3];
double det =
b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (det != 0.0) {
det = 1.0 / det;
}
x.x = det *
((a11 * b11 - a12 * b10 + a13 * b09) * bX -
(a10 * b11 - a12 * b08 + a13 * b07) * bY +
(a10 * b10 - a11 * b08 + a13 * b06) * bZ -
(a10 * b09 - a11 * b07 + a12 * b06) * bW);
x.y = det *
-((a01 * b11 - a02 * b10 + a03 * b09) * bX -
(a00 * b11 - a02 * b08 + a03 * b07) * bY +
(a00 * b10 - a01 * b08 + a03 * b06) * bZ -
(a00 * b09 - a01 * b07 + a02 * b06) * bW);
x.z = det *
((a31 * b05 - a32 * b04 + a33 * b03) * bX -
(a30 * b05 - a32 * b02 + a33 * b01) * bY +
(a30 * b04 - a31 * b02 + a33 * b00) * bZ -
(a30 * b03 - a31 * b01 + a32 * b00) * bW);
x.w = det *
-((a21 * b05 - a22 * b04 + a23 * b03) * bX -
(a20 * b05 - a22 * b02 + a23 * b01) * bY +
(a20 * b04 - a21 * b02 + a23 * b00) * bZ -
(a20 * b03 - a21 * b01 + a22 * b00) * bW);
}
/// Return index in storage for [row], [col] value.
int index(int row, int col) => (col * 4) + row;
/// Value at [row], [col].
double entry(int row, int col) {
assert((row >= 0) && (row < dimension));
assert((col >= 0) && (col < dimension));
return _m4storage[index(row, col)];
}
/// Set value at [row], [col] to be [v].
setEntry(int row, int col, double v) {
assert((row >= 0) && (row < dimension));
assert((col >= 0) && (col < dimension));
_m4storage[index(row, col)] = v;
}
/// Constructs a new mat4.
factory Matrix4(
double arg0,
double arg1,
double arg2,
double arg3,
double arg4,
double arg5,
double arg6,
double arg7,
double arg8,
double arg9,
double arg10,
double arg11,
double arg12,
double arg13,
double arg14,
double arg15) =>
new Matrix4.zero()
..setValues(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
arg10, arg11, arg12, arg13, arg14, arg15);
/// New matrix from [values].
factory Matrix4.fromList(List<double> values) {
return new Matrix4.zero()
..setValues(
values[0],
values[1],
values[2],
values[3],
values[4],
values[5],
values[6],
values[7],
values[8],
values[9],
values[10],
values[11],
values[12],
values[13],
values[14],
values[15]);
}
/// Zero matrix.
Matrix4.zero() : _m4storage = new Float32List(16);
/// Identity matrix.
factory Matrix4.identity() => new Matrix4.zero()..setIdentity();
/// Copies values from [other].
factory Matrix4.copy(Matrix4 other) => new Matrix4.zero()..setFrom(other);
/// Constructs a matrix that is the inverse of [other].
factory Matrix4.inverted(Matrix4 other) {
Matrix4 r = new Matrix4.zero();
double determinant = r.copyInverse(other);
if (determinant == 0.0) {
throw new ArgumentError.value(
other, 'other', 'Matrix cannot be inverted');
}
return r;
}
/// Constructs a new mat4 from columns.
factory Matrix4.columns(
Vector4 arg0, Vector4 arg1, Vector4 arg2, Vector4 arg3) =>
new Matrix4.zero()..setColumns(arg0, arg1, arg2, arg3);
/// Outer product of [u] and [v].
factory Matrix4.outer(Vector4 u, Vector4 v) =>
new Matrix4.zero()..setOuter(u, v);
/// Rotation of [radians_] around X.
factory Matrix4.rotationX(double radians) => new Matrix4.zero()
.._m4storage[15] = 1.0
..setRotationX(radians);
/// Rotation of [radians_] around Y.
factory Matrix4.rotationY(double radians) => new Matrix4.zero()
.._m4storage[15] = 1.0
..setRotationY(radians);
/// Rotation of [radians_] around Z.
factory Matrix4.rotationZ(double radians) => new Matrix4.zero()
.._m4storage[15] = 1.0
..setRotationZ(radians);
/// Translation matrix.
factory Matrix4.translation(Vector3 translation) => new Matrix4.zero()
..setIdentity()
..setTranslation(translation);
/// Translation matrix.
factory Matrix4.translationValues(double x, double y, double z) =>
new Matrix4.zero()
..setIdentity()
..setTranslationRaw(x, y, z);
/// Scale matrix.
factory Matrix4.diagonal3(Vector3 scale) {
final m = new Matrix4.zero();
final mStorage = m._m4storage;
final scaleStorage = scale._v3storage;
mStorage[15] = 1.0;
mStorage[10] = scaleStorage[2];
mStorage[5] = scaleStorage[1];
mStorage[0] = scaleStorage[0];
return m;
}
/// Scale matrix.
factory Matrix4.diagonal3Values(double x, double y, double z) =>
new Matrix4.zero()
.._m4storage[15] = 1.0
.._m4storage[10] = z
.._m4storage[5] = y
.._m4storage[0] = x;
/// Skew matrix around X axis
factory Matrix4.skewX(double alpha) {
final m = new Matrix4.identity();
m._m4storage[4] = Math.tan(alpha);
return m;
}
/// Skew matrix around Y axis.
factory Matrix4.skewY(double beta) {
final m = new Matrix4.identity();
m._m4storage[1] = Math.tan(beta);
return m;
}
/// Skew matrix around X axis (alpha) and Y axis (beta).
factory Matrix4.skew(double alpha, double beta) {
final m = new Matrix4.identity();
m._m4storage[1] = Math.tan(beta);
m._m4storage[4] = Math.tan(alpha);
return m;
}
/// Constructs Matrix4 with given [Float32List] as [storage].
Matrix4.fromFloat32List(this._m4storage);
/// Constructs Matrix4 with a [storage] that views given [buffer] starting at
/// [offset]. [offset] has to be multiple of [Float32List.BYTES_PER_ELEMENT].
Matrix4.fromBuffer(ByteBuffer buffer, int offset)
: _m4storage = new Float32List.view(buffer, offset, 16);
/// Constructs Matrix4 from [translation], [rotation] and [scale].
factory Matrix4.compose(
Vector3 translation, Quaternion rotation, Vector3 scale) =>
new Matrix4.zero()
..setFromTranslationRotationScale(translation, rotation, scale);
/// Sets the diagonal to [arg].
void splatDiagonal(double arg) {
_m4storage[0] = arg;
_m4storage[5] = arg;
_m4storage[10] = arg;
_m4storage[15] = arg;
}
/// Sets the matrix with specified values.
void setValues(
double arg0,
double arg1,
double arg2,
double arg3,
double arg4,
double arg5,
double arg6,
double arg7,
double arg8,
double arg9,
double arg10,
double arg11,
double arg12,
double arg13,
double arg14,
double arg15) {
_m4storage[15] = arg15;
_m4storage[14] = arg14;
_m4storage[13] = arg13;
_m4storage[12] = arg12;
_m4storage[11] = arg11;
_m4storage[10] = arg10;
_m4storage[9] = arg9;
_m4storage[8] = arg8;
_m4storage[7] = arg7;
_m4storage[6] = arg6;
_m4storage[5] = arg5;
_m4storage[4] = arg4;
_m4storage[3] = arg3;
_m4storage[2] = arg2;
_m4storage[1] = arg1;
_m4storage[0] = arg0;
}
/// Sets the entire matrix to the column values.
void setColumns(Vector4 arg0, Vector4 arg1, Vector4 arg2, Vector4 arg3) {
final arg0Storage = arg0._v4storage;
final arg1Storage = arg1._v4storage;
final arg2Storage = arg2._v4storage;
final arg3Storage = arg3._v4storage;
_m4storage[0] = arg0Storage[0];
_m4storage[1] = arg0Storage[1];
_m4storage[2] = arg0Storage[2];
_m4storage[3] = arg0Storage[3];
_m4storage[4] = arg1Storage[0];
_m4storage[5] = arg1Storage[1];
_m4storage[6] = arg1Storage[2];
_m4storage[7] = arg1Storage[3];
_m4storage[8] = arg2Storage[0];
_m4storage[9] = arg2Storage[1];
_m4storage[10] = arg2Storage[2];
_m4storage[11] = arg2Storage[3];
_m4storage[12] = arg3Storage[0];
_m4storage[13] = arg3Storage[1];
_m4storage[14] = arg3Storage[2];
_m4storage[15] = arg3Storage[3];
}
/// Sets the entire matrix to the matrix in [arg].
void setFrom(Matrix4 arg) {
final argStorage = arg._m4storage;
_m4storage[15] = argStorage[15];
_m4storage[14] = argStorage[14];
_m4storage[13] = argStorage[13];
_m4storage[12] = argStorage[12];
_m4storage[11] = argStorage[11];
_m4storage[10] = argStorage[10];
_m4storage[9] = argStorage[9];
_m4storage[8] = argStorage[8];
_m4storage[7] = argStorage[7];
_m4storage[6] = argStorage[6];
_m4storage[5] = argStorage[5];
_m4storage[4] = argStorage[4];
_m4storage[3] = argStorage[3];
_m4storage[2] = argStorage[2];
_m4storage[1] = argStorage[1];
_m4storage[0] = argStorage[0];
}
/// Sets the matrix from translation [arg0] and rotation [arg1].
void setFromTranslationRotation(Vector3 arg0, Quaternion arg1) {
final arg1Storage = arg1._qStorage;
double x = arg1Storage[0];
double y = arg1Storage[1];
double z = arg1Storage[2];
double w = arg1Storage[3];
double x2 = x + x;
double y2 = y + y;
double z2 = z + z;
double xx = x * x2;
double xy = x * y2;
double xz = x * z2;
double yy = y * y2;
double yz = y * z2;
double zz = z * z2;
double wx = w * x2;
double wy = w * y2;
double wz = w * z2;
final arg0Storage = arg0._v3storage;
_m4storage[0] = 1.0 - (yy + zz);
_m4storage[1] = xy + wz;
_m4storage[2] = xz - wy;
_m4storage[3] = 0.0;
_m4storage[4] = xy - wz;
_m4storage[5] = 1.0 - (xx + zz);
_m4storage[6] = yz + wx;
_m4storage[7] = 0.0;
_m4storage[8] = xz + wy;
_m4storage[9] = yz - wx;
_m4storage[10] = 1.0 - (xx + yy);
_m4storage[11] = 0.0;
_m4storage[12] = arg0Storage[0];
_m4storage[13] = arg0Storage[1];
_m4storage[14] = arg0Storage[2];
_m4storage[15] = 1.0;
}
/// Sets the matrix from [translation], [rotation] and [scale].
void setFromTranslationRotationScale(
Vector3 translation, Quaternion rotation, Vector3 scale) {
setFromTranslationRotation(translation, rotation);
this.scale(scale);
}
/// Sets the upper 2x2 of the matrix to be [arg].
void setUpper2x2(Matrix2 arg) {
final argStorage = arg._m2storage;
_m4storage[0] = argStorage[0];
_m4storage[1] = argStorage[1];
_m4storage[4] = argStorage[2];
_m4storage[5] = argStorage[3];
}
/// Sets the diagonal of the matrix to be [arg].
void setDiagonal(Vector4 arg) {
final argStorage = arg._v4storage;
_m4storage[0] = argStorage[0];
_m4storage[5] = argStorage[1];
_m4storage[10] = argStorage[2];
_m4storage[15] = argStorage[3];
}
void setOuter(Vector4 u, Vector4 v) {
final uStorage = u._v4storage;
final vStorage = v._v4storage;
_m4storage[0] = uStorage[0] * vStorage[0];
_m4storage[1] = uStorage[0] * vStorage[1];
_m4storage[2] = uStorage[0] * vStorage[2];
_m4storage[3] = uStorage[0] * vStorage[3];
_m4storage[4] = uStorage[1] * vStorage[0];
_m4storage[5] = uStorage[1] * vStorage[1];
_m4storage[6] = uStorage[1] * vStorage[2];
_m4storage[7] = uStorage[1] * vStorage[3];
_m4storage[8] = uStorage[2] * vStorage[0];
_m4storage[9] = uStorage[2] * vStorage[1];
_m4storage[10] = uStorage[2] * vStorage[2];
_m4storage[11] = uStorage[2] * vStorage[3];
_m4storage[12] = uStorage[3] * vStorage[0];
_m4storage[13] = uStorage[3] * vStorage[1];
_m4storage[14] = uStorage[3] * vStorage[2];
_m4storage[15] = uStorage[3] * vStorage[3];
}
/// Returns a printable string
String toString() => '[0] ${getRow(0)}\n[1] ${getRow(1)}\n'
'[2] ${getRow(2)}\n[3] ${getRow(3)}\n';
/// Dimension of the matrix.
int get dimension => 4;
/// Access the element of the matrix at the index [i].
double operator [](int i) => _m4storage[i];
/// Set the element of the matrix at the index [i].
void operator []=(int i, double v) {
_m4storage[i] = v;
}
/// Check if two matrices are the same.
bool operator ==(other) {
return (other is Matrix4) &&
(_m4storage[0] == other._m4storage[0]) &&
(_m4storage[1] == other._m4storage[1]) &&
(_m4storage[2] == other._m4storage[2]) &&
(_m4storage[3] == other._m4storage[3]) &&
(_m4storage[4] == other._m4storage[4]) &&
(_m4storage[5] == other._m4storage[5]) &&
(_m4storage[6] == other._m4storage[6]) &&
(_m4storage[7] == other._m4storage[7]) &&
(_m4storage[8] == other._m4storage[8]) &&
(_m4storage[9] == other._m4storage[9]) &&
(_m4storage[10] == other._m4storage[10]) &&
(_m4storage[11] == other._m4storage[11]) &&
(_m4storage[12] == other._m4storage[12]) &&
(_m4storage[13] == other._m4storage[13]) &&
(_m4storage[14] == other._m4storage[14]) &&
(_m4storage[15] == other._m4storage[15]);
}
int get hashCode => quiver.hashObjects(_m4storage);
/// Returns row 0
Vector4 get row0 => getRow(0);
/// Returns row 1
Vector4 get row1 => getRow(1);
/// Returns row 2
Vector4 get row2 => getRow(2);
/// Returns row 3
Vector4 get row3 => getRow(3);
/// Sets row 0 to [arg]
set row0(Vector4 arg) => setRow(0, arg);
/// Sets row 1 to [arg]
set row1(Vector4 arg) => setRow(1, arg);
/// Sets row 2 to [arg]
set row2(Vector4 arg) => setRow(2, arg);
/// Sets row 3 to [arg]
set row3(Vector4 arg) => setRow(3, arg);
/// Assigns the [row] of the matrix [arg]
void setRow(int row, Vector4 arg) {
final argStorage = arg._v4storage;
_m4storage[index(row, 0)] = argStorage[0];
_m4storage[index(row, 1)] = argStorage[1];
_m4storage[index(row, 2)] = argStorage[2];
_m4storage[index(row, 3)] = argStorage[3];
}
/// Gets the [row] of the matrix
Vector4 getRow(int row) {
Vector4 r = new Vector4.zero();
final rStorage = r._v4storage;
rStorage[0] = _m4storage[index(row, 0)];
rStorage[1] = _m4storage[index(row, 1)];
rStorage[2] = _m4storage[index(row, 2)];
rStorage[3] = _m4storage[index(row, 3)];
return r;
}
/// Assigns the [column] of the matrix [arg]
void setColumn(int column, Vector4 arg) {
int entry = column * 4;
final argStorage = arg._v4storage;
_m4storage[entry + 3] = argStorage[3];
_m4storage[entry + 2] = argStorage[2];
_m4storage[entry + 1] = argStorage[1];
_m4storage[entry + 0] = argStorage[0];
}
/// Gets the [column] of the matrix
Vector4 getColumn(int column) {
Vector4 r = new Vector4.zero();
final rStorage = r._v4storage;
int entry = column * 4;
rStorage[3] = _m4storage[entry + 3];
rStorage[2] = _m4storage[entry + 2];
rStorage[1] = _m4storage[entry + 1];
rStorage[0] = _m4storage[entry + 0];
return r;
}
/// Clone matrix.
Matrix4 clone() => new Matrix4.copy(this);
/// Copy into [arg].
Matrix4 copyInto(Matrix4 arg) {
final argStorage = arg._m4storage;
argStorage[0] = _m4storage[0];
argStorage[1] = _m4storage[1];
argStorage[2] = _m4storage[2];
argStorage[3] = _m4storage[3];
argStorage[4] = _m4storage[4];
argStorage[5] = _m4storage[5];
argStorage[6] = _m4storage[6];
argStorage[7] = _m4storage[7];
argStorage[8] = _m4storage[8];
argStorage[9] = _m4storage[9];
argStorage[10] = _m4storage[10];
argStorage[11] = _m4storage[11];
argStorage[12] = _m4storage[12];
argStorage[13] = _m4storage[13];
argStorage[14] = _m4storage[14];
argStorage[15] = _m4storage[15];
return arg;
}
/// Returns new matrix -this
Matrix4 operator -() => clone()..negate();
/// Returns a new vector or matrix by multiplying [this] with [arg].
dynamic operator *(dynamic arg) {
if (arg is double) {
return scaled(arg);
}
if (arg is Vector4) {
return transformed(arg);
}
if (arg is Vector3) {
return transformed3(arg);
}
if (arg.dimension == 4) {
return multiplied(arg);
}
throw new ArgumentError(arg);
}
/// Returns new matrix after component wise [this] + [arg]
Matrix4 operator +(Matrix4 arg) => clone()..add(arg);
/// Returns new matrix after component wise [this] - [arg]
Matrix4 operator -(Matrix4 arg) => clone()..sub(arg);
/// Translate this matrix by a [Vector3], [Vector4], or x,y,z
void translate(x, [double y = 0.0, double z = 0.0]) {
double tx;
double ty;
double tz;
double tw = x is Vector4 ? x.w : 1.0;
if (x is Vector3 || x is Vector4) {
tx = x.x;
ty = x.y;
tz = x.z;
} else {
tx = x;
ty = y;
tz = z;
}
var t1 = _m4storage[0] * tx +
_m4storage[4] * ty +
_m4storage[8] * tz +
_m4storage[12] * tw;
var t2 = _m4storage[1] * tx +
_m4storage[5] * ty +
_m4storage[9] * tz +
_m4storage[13] * tw;
var t3 = _m4storage[2] * tx +
_m4storage[6] * ty +
_m4storage[10] * tz +
_m4storage[14] * tw;
var t4 = _m4storage[3] * tx +
_m4storage[7] * ty +
_m4storage[11] * tz +
_m4storage[15] * tw;
_m4storage[12] = t1;
_m4storage[13] = t2;
_m4storage[14] = t3;
_m4storage[15] = t4;
}
/// Multiply [this] by a translation from the left.
/// The translation can be specified with a [Vector3], [Vector4], or x, y, z.
void leftTranslate(x, [double y = 0.0, double z = 0.0]) {
double tx;
double ty;
double tz;
double tw = x is Vector4 ? x.w : 1.0;
if (x is Vector3 || x is Vector4) {
tx = x.x;
ty = x.y;
tz = x.z;
} else {
tx = x;
ty = y;
tz = z;
}
// Column 1
_m4storage[0] += tx * _m4storage[3];
_m4storage[1] += ty * _m4storage[3];
_m4storage[2] += tz * _m4storage[3];
_m4storage[3] = tw * _m4storage[3];
// Column 2
_m4storage[4] += tx * _m4storage[7];
_m4storage[5] += ty * _m4storage[7];
_m4storage[6] += tz * _m4storage[7];
_m4storage[7] = tw * _m4storage[7];
// Column 3
_m4storage[8] += tx * _m4storage[11];
_m4storage[9] += ty * _m4storage[11];
_m4storage[10] += tz * _m4storage[11];
_m4storage[11] = tw * _m4storage[11];
// Column 4
_m4storage[12] += tx * _m4storage[15];
_m4storage[13] += ty * _m4storage[15];
_m4storage[14] += tz * _m4storage[15];
_m4storage[15] = tw * _m4storage[15];
}
/// Rotate this [angle] radians around [axis]
void rotate(Vector3 axis, double angle) {
var len = axis.length;
final axisStorage = axis._v3storage;
var x = axisStorage[0] / len;
var y = axisStorage[1] / len;
var z = axisStorage[2] / len;
var c = Math.cos(angle);
var s = Math.sin(angle);
var C = 1.0 - c;
var m11 = x * x * C + c;
var m12 = x * y * C - z * s;
var m13 = x * z * C + y * s;
var m21 = y * x * C + z * s;
var m22 = y * y * C + c;
var m23 = y * z * C - x * s;
var m31 = z * x * C - y * s;
var m32 = z * y * C + x * s;
var m33 = z * z * C + c;
var t1 = _m4storage[0] * m11 + _m4storage[4] * m21 + _m4storage[8] * m31;
var t2 = _m4storage[1] * m11 + _m4storage[5] * m21 + _m4storage[9] * m31;
var t3 = _m4storage[2] * m11 + _m4storage[6] * m21 + _m4storage[10] * m31;
var t4 = _m4storage[3] * m11 + _m4storage[7] * m21 + _m4storage[11] * m31;
var t5 = _m4storage[0] * m12 + _m4storage[4] * m22 + _m4storage[8] * m32;
var t6 = _m4storage[1] * m12 + _m4storage[5] * m22 + _m4storage[9] * m32;
var t7 = _m4storage[2] * m12 + _m4storage[6] * m22 + _m4storage[10] * m32;
var t8 = _m4storage[3] * m12 + _m4storage[7] * m22 + _m4storage[11] * m32;
var t9 = _m4storage[0] * m13 + _m4storage[4] * m23 + _m4storage[8] * m33;
var t10 = _m4storage[1] * m13 + _m4storage[5] * m23 + _m4storage[9] * m33;
var t11 = _m4storage[2] * m13 + _m4storage[6] * m23 + _m4storage[10] * m33;
var t12 = _m4storage[3] * m13 + _m4storage[7] * m23 + _m4storage[11] * m33;
_m4storage[0] = t1;
_m4storage[1] = t2;
_m4storage[2] = t3;
_m4storage[3] = t4;
_m4storage[4] = t5;
_m4storage[5] = t6;
_m4storage[6] = t7;
_m4storage[7] = t8;
_m4storage[8] = t9;
_m4storage[9] = t10;
_m4storage[10] = t11;
_m4storage[11] = t12;
}
/// Rotate this [angle] radians around X
void rotateX(double angle) {
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
var t1 = _m4storage[4] * cosAngle + _m4storage[8] * sinAngle;
var t2 = _m4storage[5] * cosAngle + _m4storage[9] * sinAngle;
var t3 = _m4storage[6] * cosAngle + _m4storage[10] * sinAngle;
var t4 = _m4storage[7] * cosAngle + _m4storage[11] * sinAngle;
var t5 = _m4storage[4] * -sinAngle + _m4storage[8] * cosAngle;
var t6 = _m4storage[5] * -sinAngle + _m4storage[9] * cosAngle;
var t7 = _m4storage[6] * -sinAngle + _m4storage[10] * cosAngle;
var t8 = _m4storage[7] * -sinAngle + _m4storage[11] * cosAngle;
_m4storage[4] = t1;
_m4storage[5] = t2;
_m4storage[6] = t3;
_m4storage[7] = t4;
_m4storage[8] = t5;
_m4storage[9] = t6;
_m4storage[10] = t7;
_m4storage[11] = t8;
}
/// Rotate this matrix [angle] radians around Y
void rotateY(double angle) {
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
var t1 = _m4storage[0] * cosAngle + _m4storage[8] * -sinAngle;
var t2 = _m4storage[1] * cosAngle + _m4storage[9] * -sinAngle;
var t3 = _m4storage[2] * cosAngle + _m4storage[10] * -sinAngle;
var t4 = _m4storage[3] * cosAngle + _m4storage[11] * -sinAngle;
var t5 = _m4storage[0] * sinAngle + _m4storage[8] * cosAngle;
var t6 = _m4storage[1] * sinAngle + _m4storage[9] * cosAngle;
var t7 = _m4storage[2] * sinAngle + _m4storage[10] * cosAngle;
var t8 = _m4storage[3] * sinAngle + _m4storage[11] * cosAngle;
_m4storage[0] = t1;
_m4storage[1] = t2;
_m4storage[2] = t3;
_m4storage[3] = t4;
_m4storage[8] = t5;
_m4storage[9] = t6;
_m4storage[10] = t7;
_m4storage[11] = t8;
}
/// Rotate this matrix [angle] radians around Z
void rotateZ(double angle) {
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
var t1 = _m4storage[0] * cosAngle + _m4storage[4] * sinAngle;
var t2 = _m4storage[1] * cosAngle + _m4storage[5] * sinAngle;
var t3 = _m4storage[2] * cosAngle + _m4storage[6] * sinAngle;
var t4 = _m4storage[3] * cosAngle + _m4storage[7] * sinAngle;
var t5 = _m4storage[0] * -sinAngle + _m4storage[4] * cosAngle;
var t6 = _m4storage[1] * -sinAngle + _m4storage[5] * cosAngle;
var t7 = _m4storage[2] * -sinAngle + _m4storage[6] * cosAngle;
var t8 = _m4storage[3] * -sinAngle + _m4storage[7] * cosAngle;
_m4storage[0] = t1;
_m4storage[1] = t2;
_m4storage[2] = t3;
_m4storage[3] = t4;
_m4storage[4] = t5;
_m4storage[5] = t6;
_m4storage[6] = t7;
_m4storage[7] = t8;
}
/// Scale this matrix by a [Vector3], [Vector4], or x,y,z
void scale(x, [double y, double z]) {
double sx;
double sy;
double sz;
double sw = x is Vector4 ? x.w : 1.0;
if (x is Vector3 || x is Vector4) {
sx = x.x;
sy = x.y;
sz = x.z;
} else {
sx = x;
sy = y == null ? x : y.toDouble();
sz = z == null ? x : z.toDouble();
}
_m4storage[0] *= sx;
_m4storage[1] *= sx;
_m4storage[2] *= sx;
_m4storage[3] *= sx;
_m4storage[4] *= sy;
_m4storage[5] *= sy;
_m4storage[6] *= sy;
_m4storage[7] *= sy;
_m4storage[8] *= sz;
_m4storage[9] *= sz;
_m4storage[10] *= sz;
_m4storage[11] *= sz;
_m4storage[12] *= sw;
_m4storage[13] *= sw;
_m4storage[14] *= sw;
_m4storage[15] *= sw;
}
/// Create a copy of [this] scaled by a [Vector3], [Vector4] or [x],[y], and
/// [z].
Matrix4 scaled(x, [double y = null, double z = null]) =>
clone()..scale(x, y, z);
/// Zeros [this].
void setZero() {
_m4storage[0] = 0.0;
_m4storage[1] = 0.0;
_m4storage[2] = 0.0;
_m4storage[3] = 0.0;
_m4storage[4] = 0.0;
_m4storage[5] = 0.0;
_m4storage[6] = 0.0;
_m4storage[7] = 0.0;
_m4storage[8] = 0.0;
_m4storage[9] = 0.0;
_m4storage[10] = 0.0;
_m4storage[11] = 0.0;
_m4storage[12] = 0.0;
_m4storage[13] = 0.0;
_m4storage[14] = 0.0;
_m4storage[15] = 0.0;
}
/// Makes [this] into the identity matrix.
void setIdentity() {
_m4storage[0] = 1.0;
_m4storage[1] = 0.0;
_m4storage[2] = 0.0;
_m4storage[3] = 0.0;
_m4storage[4] = 0.0;
_m4storage[5] = 1.0;
_m4storage[6] = 0.0;
_m4storage[7] = 0.0;
_m4storage[8] = 0.0;
_m4storage[9] = 0.0;
_m4storage[10] = 1.0;
_m4storage[11] = 0.0;
_m4storage[12] = 0.0;
_m4storage[13] = 0.0;
_m4storage[14] = 0.0;
_m4storage[15] = 1.0;
}
/// Returns the tranpose of this.
Matrix4 transposed() => clone()..transpose();
void transpose() {
double temp;
temp = _m4storage[4];
_m4storage[4] = _m4storage[1];
_m4storage[1] = temp;
temp = _m4storage[8];
_m4storage[8] = _m4storage[2];
_m4storage[2] = temp;
temp = _m4storage[12];
_m4storage[12] = _m4storage[3];
_m4storage[3] = temp;
temp = _m4storage[9];
_m4storage[9] = _m4storage[6];
_m4storage[6] = temp;
temp = _m4storage[13];
_m4storage[13] = _m4storage[7];
_m4storage[7] = temp;
temp = _m4storage[14];
_m4storage[14] = _m4storage[11];
_m4storage[11] = temp;
}
/// Returns the component wise absolute value of this.
Matrix4 absolute() {
Matrix4 r = new Matrix4.zero();
final rStorage = r._m4storage;
rStorage[0] = _m4storage[0].abs();
rStorage[1] = _m4storage[1].abs();
rStorage[2] = _m4storage[2].abs();
rStorage[3] = _m4storage[3].abs();
rStorage[4] = _m4storage[4].abs();
rStorage[5] = _m4storage[5].abs();
rStorage[6] = _m4storage[6].abs();
rStorage[7] = _m4storage[7].abs();
rStorage[8] = _m4storage[8].abs();
rStorage[9] = _m4storage[9].abs();
rStorage[10] = _m4storage[10].abs();
rStorage[11] = _m4storage[11].abs();
rStorage[12] = _m4storage[12].abs();
rStorage[13] = _m4storage[13].abs();
rStorage[14] = _m4storage[14].abs();
rStorage[15] = _m4storage[15].abs();
return r;
}
/// Returns the determinant of this matrix.
double determinant() {
double det2_01_01 =
_m4storage[0] * _m4storage[5] - _m4storage[1] * _m4storage[4];
double det2_01_02 =
_m4storage[0] * _m4storage[6] - _m4storage[2] * _m4storage[4];
double det2_01_03 =
_m4storage[0] * _m4storage[7] - _m4storage[3] * _m4storage[4];
double det2_01_12 =
_m4storage[1] * _m4storage[6] - _m4storage[2] * _m4storage[5];
double det2_01_13 =
_m4storage[1] * _m4storage[7] - _m4storage[3] * _m4storage[5];
double det2_01_23 =
_m4storage[2] * _m4storage[7] - _m4storage[3] * _m4storage[6];
double det3_201_012 = _m4storage[8] * det2_01_12 -
_m4storage[9] * det2_01_02 +
_m4storage[10] * det2_01_01;
double det3_201_013 = _m4storage[8] * det2_01_13 -
_m4storage[9] * det2_01_03 +
_m4storage[11] * det2_01_01;
double det3_201_023 = _m4storage[8] * det2_01_23 -
_m4storage[10] * det2_01_03 +
_m4storage[11] * det2_01_02;
double det3_201_123 = _m4storage[9] * det2_01_23 -
_m4storage[10] * det2_01_13 +
_m4storage[11] * det2_01_12;
return -det3_201_123 * _m4storage[12] +
det3_201_023 * _m4storage[13] -
det3_201_013 * _m4storage[14] +
det3_201_012 * _m4storage[15];
}
/// Returns the dot product of row [i] and [v].
double dotRow(int i, Vector4 v) {
final vStorage = v._v4storage;
return _m4storage[i] * vStorage[0] +
_m4storage[4 + i] * vStorage[1] +
_m4storage[8 + i] * vStorage[2] +
_m4storage[12 + i] * vStorage[3];
}
/// Returns the dot product of column [j] and [v].
double dotColumn(int j, Vector4 v) {
final vStorage = v._v4storage;
return _m4storage[j * 4] * vStorage[0] +
_m4storage[j * 4 + 1] * vStorage[1] +
_m4storage[j * 4 + 2] * vStorage[2] +
_m4storage[j * 4 + 3] * vStorage[3];
}
/// Returns the trace of the matrix. The trace of a matrix is the sum of the
/// diagonal entries.
double trace() {
double t = 0.0;
t += _m4storage[0];
t += _m4storage[5];
t += _m4storage[10];
t += _m4storage[15];
return t;
}
/// Returns infinity norm of the matrix. Used for numerical analysis.
double infinityNorm() {
double norm = 0.0;
{
double row_norm = 0.0;
row_norm += _m4storage[0].abs();
row_norm += _m4storage[1].abs();
row_norm += _m4storage[2].abs();
row_norm += _m4storage[3].abs();
norm = row_norm > norm ? row_norm : norm;
}
{
double row_norm = 0.0;
row_norm += _m4storage[4].abs();
row_norm += _m4storage[5].abs();
row_norm += _m4storage[6].abs();
row_norm += _m4storage[7].abs();
norm = row_norm > norm ? row_norm : norm;
}
{
double row_norm = 0.0;
row_norm += _m4storage[8].abs();
row_norm += _m4storage[9].abs();
row_norm += _m4storage[10].abs();
row_norm += _m4storage[11].abs();
norm = row_norm > norm ? row_norm : norm;
}
{
double row_norm = 0.0;
row_norm += _m4storage[12].abs();
row_norm += _m4storage[13].abs();
row_norm += _m4storage[14].abs();
row_norm += _m4storage[15].abs();
norm = row_norm > norm ? row_norm : norm;
}
return norm;
}
/// Returns relative error between [this] and [correct]
double relativeError(Matrix4 correct) {
Matrix4 diff = correct - this;
double correct_norm = correct.infinityNorm();
double diff_norm = diff.infinityNorm();
return diff_norm / correct_norm;
}
/// Returns absolute error between [this] and [correct]
double absoluteError(Matrix4 correct) {
double this_norm = infinityNorm();
double correct_norm = correct.infinityNorm();
double diff_norm = (this_norm - correct_norm).abs();
return diff_norm;
}
/// Returns the translation vector from this homogeneous transformation matrix.
Vector3 getTranslation() {
double z = _m4storage[14];
double y = _m4storage[13];
double x = _m4storage[12];
return new Vector3(x, y, z);
}
/// Sets the translation vector in this homogeneous transformation matrix.
void setTranslation(Vector3 t) {
final tStorage = t._v3storage;
double z = tStorage[2];
double y = tStorage[1];
double x = tStorage[0];
_m4storage[14] = z;
_m4storage[13] = y;
_m4storage[12] = x;
}
/// Sets the translation vector in this homogeneous transformation matrix.
void setTranslationRaw(double x, double y, double z) {
_m4storage[14] = z;
_m4storage[13] = y;
_m4storage[12] = x;
}
/// Returns the rotation matrix from this homogeneous transformation matrix.
Matrix3 getRotation() {
Matrix3 r = new Matrix3.zero();
copyRotation(r);
return r;
}
/// Copies the rotation matrix from this homogeneous transformation matrix
/// into [rotation].
void copyRotation(Matrix3 rotation) {
final rStorage = rotation._m3storage;
rStorage[0] = _m4storage[0];
rStorage[1] = _m4storage[1];
rStorage[2] = _m4storage[2];
rStorage[3] = _m4storage[4];
rStorage[4] = _m4storage[5];
rStorage[5] = _m4storage[6];
rStorage[6] = _m4storage[8];
rStorage[7] = _m4storage[9];
rStorage[8] = _m4storage[10];
}
/// Sets the rotation matrix in this homogeneous transformation matrix.
void setRotation(Matrix3 r) {
final rStorage = r._m3storage;
_m4storage[0] = rStorage[0];
_m4storage[1] = rStorage[1];
_m4storage[2] = rStorage[2];
_m4storage[4] = rStorage[3];
_m4storage[5] = rStorage[4];
_m4storage[6] = rStorage[5];
_m4storage[8] = rStorage[6];
_m4storage[9] = rStorage[7];
_m4storage[10] = rStorage[8];
}
/// Returns the normal matrix from this homogeneous transformation matrix. The normal
/// matrix is the transpose of the inverse of the top-left 3x3 part of this 4x4 matrix.
Matrix3 getNormalMatrix() => new Matrix3.identity()..copyNormalMatrix(this);
/// Returns the max scale value of the 3 axes.
double getMaxScaleOnAxis() {
final scaleXSq = _m4storage[0] * _m4storage[0] +
_m4storage[1] * _m4storage[1] +
_m4storage[2] * _m4storage[2];
final scaleYSq = _m4storage[4] * _m4storage[4] +
_m4storage[5] * _m4storage[5] +
_m4storage[6] * _m4storage[6];
final scaleZSq = _m4storage[8] * _m4storage[8] +
_m4storage[9] * _m4storage[9] +
_m4storage[10] * _m4storage[10];
return Math.sqrt(Math.max(scaleXSq, Math.max(scaleYSq, scaleZSq)));
}
/// Transposes just the upper 3x3 rotation matrix.
void transposeRotation() {
double temp;
temp = _m4storage[1];
_m4storage[1] = _m4storage[4];
_m4storage[4] = temp;
temp = _m4storage[2];
_m4storage[2] = _m4storage[8];
_m4storage[8] = temp;
temp = _m4storage[4];
_m4storage[4] = _m4storage[1];
_m4storage[1] = temp;
temp = _m4storage[6];
_m4storage[6] = _m4storage[9];
_m4storage[9] = temp;
temp = _m4storage[8];
_m4storage[8] = _m4storage[2];
_m4storage[2] = temp;
temp = _m4storage[9];
_m4storage[9] = _m4storage[6];
_m4storage[6] = temp;
}
/// Invert [this].
double invert() => copyInverse(this);
/// Set this matrix to be the inverse of [arg]
double copyInverse(Matrix4 arg) {
final argStorage = arg._m4storage;
double a00 = argStorage[0];
double a01 = argStorage[1];
double a02 = argStorage[2];
double a03 = argStorage[3];
double a10 = argStorage[4];
double a11 = argStorage[5];
double a12 = argStorage[6];
double a13 = argStorage[7];
double a20 = argStorage[8];
double a21 = argStorage[9];
double a22 = argStorage[10];
double a23 = argStorage[11];
double a30 = argStorage[12];
double a31 = argStorage[13];
double a32 = argStorage[14];
double a33 = argStorage[15];
var b00 = a00 * a11 - a01 * a10;
var b01 = a00 * a12 - a02 * a10;
var b02 = a00 * a13 - a03 * a10;
var b03 = a01 * a12 - a02 * a11;
var b04 = a01 * a13 - a03 * a11;
var b05 = a02 * a13 - a03 * a12;
var b06 = a20 * a31 - a21 * a30;
var b07 = a20 * a32 - a22 * a30;
var b08 = a20 * a33 - a23 * a30;
var b09 = a21 * a32 - a22 * a31;
var b10 = a21 * a33 - a23 * a31;
var b11 = a22 * a33 - a23 * a32;
var det =
(b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06);
if (det == 0.0) {
setFrom(arg);
return 0.0;
}
var invDet = 1.0 / det;
_m4storage[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
_m4storage[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet;
_m4storage[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet;
_m4storage[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet;
_m4storage[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet;
_m4storage[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet;
_m4storage[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet;
_m4storage[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet;
_m4storage[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet;
_m4storage[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet;
_m4storage[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet;
_m4storage[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet;
_m4storage[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet;
_m4storage[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet;
_m4storage[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet;
_m4storage[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet;
return det;
}
double invertRotation() {
double det = determinant();
if (det == 0.0) {
return 0.0;
}
double invDet = 1.0 / det;
double ix;
double iy;
double iz;
double jx;
double jy;
double jz;
double kx;
double ky;
double kz;
ix = invDet *
(_m4storage[5] * _m4storage[10] - _m4storage[6] * _m4storage[9]);
iy = invDet *
(_m4storage[2] * _m4storage[9] - _m4storage[1] * _m4storage[10]);
iz = invDet *
(_m4storage[1] * _m4storage[6] - _m4storage[2] * _m4storage[5]);
jx = invDet *
(_m4storage[6] * _m4storage[8] - _m4storage[4] * _m4storage[10]);
jy = invDet *
(_m4storage[0] * _m4storage[10] - _m4storage[2] * _m4storage[8]);
jz = invDet *
(_m4storage[2] * _m4storage[4] - _m4storage[0] * _m4storage[6]);
kx = invDet *
(_m4storage[4] * _m4storage[9] - _m4storage[5] * _m4storage[8]);
ky = invDet *
(_m4storage[1] * _m4storage[8] - _m4storage[0] * _m4storage[9]);
kz = invDet *
(_m4storage[0] * _m4storage[5] - _m4storage[1] * _m4storage[4]);
_m4storage[0] = ix;
_m4storage[1] = iy;
_m4storage[2] = iz;
_m4storage[4] = jx;
_m4storage[5] = jy;
_m4storage[6] = jz;
_m4storage[8] = kx;
_m4storage[9] = ky;
_m4storage[10] = kz;
return det;
}
/// Sets the upper 3x3 to a rotation of [radians] around X
void setRotationX(double radians) {
double c = Math.cos(radians);
double s = Math.sin(radians);
_m4storage[0] = 1.0;
_m4storage[1] = 0.0;
_m4storage[2] = 0.0;
_m4storage[4] = 0.0;
_m4storage[5] = c;
_m4storage[6] = s;
_m4storage[8] = 0.0;
_m4storage[9] = -s;
_m4storage[10] = c;
_m4storage[3] = 0.0;
_m4storage[7] = 0.0;
_m4storage[11] = 0.0;
}
/// Sets the upper 3x3 to a rotation of [radians] around Y
void setRotationY(double radians) {
double c = Math.cos(radians);
double s = Math.sin(radians);
_m4storage[0] = c;
_m4storage[1] = 0.0;
_m4storage[2] = -s;
_m4storage[4] = 0.0;
_m4storage[5] = 1.0;
_m4storage[6] = 0.0;
_m4storage[8] = s;
_m4storage[9] = 0.0;
_m4storage[10] = c;
_m4storage[3] = 0.0;
_m4storage[7] = 0.0;
_m4storage[11] = 0.0;
}
/// Sets the upper 3x3 to a rotation of [radians] around Z
void setRotationZ(double radians) {
double c = Math.cos(radians);
double s = Math.sin(radians);
_m4storage[0] = c;
_m4storage[1] = s;
_m4storage[2] = 0.0;
_m4storage[4] = -s;
_m4storage[5] = c;
_m4storage[6] = 0.0;
_m4storage[8] = 0.0;
_m4storage[9] = 0.0;
_m4storage[10] = 1.0;
_m4storage[3] = 0.0;
_m4storage[7] = 0.0;
_m4storage[11] = 0.0;
}
/// Converts into Adjugate matrix and scales by [scale]
void scaleAdjoint(double scale) {
// Adapted from code by Richard Carling.
double a1 = _m4storage[0];
double b1 = _m4storage[4];
double c1 = _m4storage[8];
double d1 = _m4storage[12];
double a2 = _m4storage[1];
double b2 = _m4storage[5];
double c2 = _m4storage[9];
double d2 = _m4storage[13];
double a3 = _m4storage[2];
double b3 = _m4storage[6];
double c3 = _m4storage[10];
double d3 = _m4storage[14];
double a4 = _m4storage[3];
double b4 = _m4storage[7];
double c4 = _m4storage[11];
double d4 = _m4storage[15];
_m4storage[0] = (b2 * (c3 * d4 - c4 * d3) -
c2 * (b3 * d4 - b4 * d3) +
d2 * (b3 * c4 - b4 * c3)) *
scale;
_m4storage[1] = -(a2 * (c3 * d4 - c4 * d3) -
c2 * (a3 * d4 - a4 * d3) +
d2 * (a3 * c4 - a4 * c3)) *
scale;
_m4storage[2] = (a2 * (b3 * d4 - b4 * d3) -
b2 * (a3 * d4 - a4 * d3) +
d2 * (a3 * b4 - a4 * b3)) *
scale;
_m4storage[3] = -(a2 * (b3 * c4 - b4 * c3) -
b2 * (a3 * c4 - a4 * c3) +
c2 * (a3 * b4 - a4 * b3)) *
scale;
_m4storage[4] = -(b1 * (c3 * d4 - c4 * d3) -
c1 * (b3 * d4 - b4 * d3) +
d1 * (b3 * c4 - b4 * c3)) *
scale;
_m4storage[5] = (a1 * (c3 * d4 - c4 * d3) -
c1 * (a3 * d4 - a4 * d3) +
d1 * (a3 * c4 - a4 * c3)) *
scale;
_m4storage[6] = -(a1 * (b3 * d4 - b4 * d3) -
b1 * (a3 * d4 - a4 * d3) +
d1 * (a3 * b4 - a4 * b3)) *
scale;
_m4storage[7] = (a1 * (b3 * c4 - b4 * c3) -
b1 * (a3 * c4 - a4 * c3) +
c1 * (a3 * b4 - a4 * b3)) *
scale;
_m4storage[8] = (b1 * (c2 * d4 - c4 * d2) -
c1 * (b2 * d4 - b4 * d2) +
d1 * (b2 * c4 - b4 * c2)) *
scale;
_m4storage[9] = -(a1 * (c2 * d4 - c4 * d2) -
c1 * (a2 * d4 - a4 * d2) +
d1 * (a2 * c4 - a4 * c2)) *
scale;
_m4storage[10] = (a1 * (b2 * d4 - b4 * d2) -
b1 * (a2 * d4 - a4 * d2) +
d1 * (a2 * b4 - a4 * b2)) *
scale;
_m4storage[11] = -(a1 * (b2 * c4 - b4 * c2) -
b1 * (a2 * c4 - a4 * c2) +
c1 * (a2 * b4 - a4 * b2)) *
scale;
_m4storage[12] = -(b1 * (c2 * d3 - c3 * d2) -
c1 * (b2 * d3 - b3 * d2) +
d1 * (b2 * c3 - b3 * c2)) *
scale;
_m4storage[13] = (a1 * (c2 * d3 - c3 * d2) -
c1 * (a2 * d3 - a3 * d2) +
d1 * (a2 * c3 - a3 * c2)) *
scale;
_m4storage[14] = -(a1 * (b2 * d3 - b3 * d2) -
b1 * (a2 * d3 - a3 * d2) +
d1 * (a2 * b3 - a3 * b2)) *
scale;
_m4storage[15] = (a1 * (b2 * c3 - b3 * c2) -
b1 * (a2 * c3 - a3 * c2) +
c1 * (a2 * b3 - a3 * b2)) *
scale;
}
/// Rotates [arg] by the absolute rotation of [this]
/// Returns [arg].
/// Primarily used by AABB transformation code.
Vector3 absoluteRotate(Vector3 arg) {
double m00 = _m4storage[0].abs();
double m01 = _m4storage[4].abs();
double m02 = _m4storage[8].abs();
double m10 = _m4storage[1].abs();
double m11 = _m4storage[5].abs();
double m12 = _m4storage[9].abs();
double m20 = _m4storage[2].abs();
double m21 = _m4storage[6].abs();
double m22 = _m4storage[10].abs();
final argStorage = arg._v3storage;
double x = argStorage[0];
double y = argStorage[1];
double z = argStorage[2];
argStorage[0] = x * m00 + y * m01 + z * m02 + 0.0 * 0.0;
argStorage[1] = x * m10 + y * m11 + z * m12 + 0.0 * 0.0;
argStorage[2] = x * m20 + y * m21 + z * m22 + 0.0 * 0.0;
return arg;
}
/// Adds [o] to [this].
void add(Matrix4 o) {
final oStorage = o._m4storage;
_m4storage[0] = _m4storage[0] + oStorage[0];
_m4storage[1] = _m4storage[1] + oStorage[1];
_m4storage[2] = _m4storage[2] + oStorage[2];
_m4storage[3] = _m4storage[3] + oStorage[3];
_m4storage[4] = _m4storage[4] + oStorage[4];
_m4storage[5] = _m4storage[5] + oStorage[5];
_m4storage[6] = _m4storage[6] + oStorage[6];
_m4storage[7] = _m4storage[7] + oStorage[7];
_m4storage[8] = _m4storage[8] + oStorage[8];
_m4storage[9] = _m4storage[9] + oStorage[9];
_m4storage[10] = _m4storage[10] + oStorage[10];
_m4storage[11] = _m4storage[11] + oStorage[11];
_m4storage[12] = _m4storage[12] + oStorage[12];
_m4storage[13] = _m4storage[13] + oStorage[13];
_m4storage[14] = _m4storage[14] + oStorage[14];
_m4storage[15] = _m4storage[15] + oStorage[15];
}
/// Subtracts [o] from [this].
void sub(Matrix4 o) {
final oStorage = o._m4storage;
_m4storage[0] = _m4storage[0] - oStorage[0];
_m4storage[1] = _m4storage[1] - oStorage[1];
_m4storage[2] = _m4storage[2] - oStorage[2];
_m4storage[3] = _m4storage[3] - oStorage[3];
_m4storage[4] = _m4storage[4] - oStorage[4];
_m4storage[5] = _m4storage[5] - oStorage[5];
_m4storage[6] = _m4storage[6] - oStorage[6];
_m4storage[7] = _m4storage[7] - oStorage[7];
_m4storage[8] = _m4storage[8] - oStorage[8];
_m4storage[9] = _m4storage[9] - oStorage[9];
_m4storage[10] = _m4storage[10] - oStorage[10];
_m4storage[11] = _m4storage[11] - oStorage[11];
_m4storage[12] = _m4storage[12] - oStorage[12];
_m4storage[13] = _m4storage[13] - oStorage[13];
_m4storage[14] = _m4storage[14] - oStorage[14];
_m4storage[15] = _m4storage[15] - oStorage[15];
}
/// Negate [this].
void negate() {
_m4storage[0] = -_m4storage[0];
_m4storage[1] = -_m4storage[1];
_m4storage[2] = -_m4storage[2];
_m4storage[3] = -_m4storage[3];
_m4storage[4] = -_m4storage[4];
_m4storage[5] = -_m4storage[5];
_m4storage[6] = -_m4storage[6];
_m4storage[7] = -_m4storage[7];
_m4storage[8] = -_m4storage[8];
_m4storage[9] = -_m4storage[9];
_m4storage[10] = -_m4storage[10];
_m4storage[11] = -_m4storage[11];
_m4storage[12] = -_m4storage[12];
_m4storage[13] = -_m4storage[13];
_m4storage[14] = -_m4storage[14];
_m4storage[15] = -_m4storage[15];
}
/// Multiply [this] by [arg].
void multiply(Matrix4 arg) {
final m00 = _m4storage[0];
final m01 = _m4storage[4];
final m02 = _m4storage[8];
final m03 = _m4storage[12];
final m10 = _m4storage[1];
final m11 = _m4storage[5];
final m12 = _m4storage[9];
final m13 = _m4storage[13];
final m20 = _m4storage[2];
final m21 = _m4storage[6];
final m22 = _m4storage[10];
final m23 = _m4storage[14];
final m30 = _m4storage[3];
final m31 = _m4storage[7];
final m32 = _m4storage[11];
final m33 = _m4storage[15];
final argStorage = arg._m4storage;
final n00 = argStorage[0];
final n01 = argStorage[4];
final n02 = argStorage[8];
final n03 = argStorage[12];
final n10 = argStorage[1];
final n11 = argStorage[5];
final n12 = argStorage[9];
final n13 = argStorage[13];
final n20 = argStorage[2];
final n21 = argStorage[6];
final n22 = argStorage[10];
final n23 = argStorage[14];
final n30 = argStorage[3];
final n31 = argStorage[7];
final n32 = argStorage[11];
final n33 = argStorage[15];
_m4storage[0] = (m00 * n00) + (m01 * n10) + (m02 * n20) + (m03 * n30);
_m4storage[4] = (m00 * n01) + (m01 * n11) + (m02 * n21) + (m03 * n31);
_m4storage[8] = (m00 * n02) + (m01 * n12) + (m02 * n22) + (m03 * n32);
_m4storage[12] = (m00 * n03) + (m01 * n13) + (m02 * n23) + (m03 * n33);
_m4storage[1] = (m10 * n00) + (m11 * n10) + (m12 * n20) + (m13 * n30);
_m4storage[5] = (m10 * n01) + (m11 * n11) + (m12 * n21) + (m13 * n31);
_m4storage[9] = (m10 * n02) + (m11 * n12) + (m12 * n22) + (m13 * n32);
_m4storage[13] = (m10 * n03) + (m11 * n13) + (m12 * n23) + (m13 * n33);
_m4storage[2] = (m20 * n00) + (m21 * n10) + (m22 * n20) + (m23 * n30);
_m4storage[6] = (m20 * n01) + (m21 * n11) + (m22 * n21) + (m23 * n31);
_m4storage[10] = (m20 * n02) + (m21 * n12) + (m22 * n22) + (m23 * n32);
_m4storage[14] = (m20 * n03) + (m21 * n13) + (m22 * n23) + (m23 * n33);
_m4storage[3] = (m30 * n00) + (m31 * n10) + (m32 * n20) + (m33 * n30);
_m4storage[7] = (m30 * n01) + (m31 * n11) + (m32 * n21) + (m33 * n31);
_m4storage[11] = (m30 * n02) + (m31 * n12) + (m32 * n22) + (m33 * n32);
_m4storage[15] = (m30 * n03) + (m31 * n13) + (m32 * n23) + (m33 * n33);
}
/// Multiply a copy of [this] with [arg].
Matrix4 multiplied(Matrix4 arg) => clone()..multiply(arg);
/// Multiply a transposed [this] with [arg].
void transposeMultiply(Matrix4 arg) {
double m00 = _m4storage[0];
double m01 = _m4storage[1];
double m02 = _m4storage[2];
double m03 = _m4storage[3];
double m10 = _m4storage[4];
double m11 = _m4storage[5];
double m12 = _m4storage[6];
double m13 = _m4storage[7];
double m20 = _m4storage[8];
double m21 = _m4storage[9];
double m22 = _m4storage[10];
double m23 = _m4storage[11];
double m30 = _m4storage[12];
double m31 = _m4storage[13];
double m32 = _m4storage[14];
double m33 = _m4storage[15];
final argStorage = arg._m4storage;
_m4storage[0] = (m00 * argStorage[0]) +
(m01 * argStorage[1]) +
(m02 * argStorage[2]) +
(m03 * argStorage[3]);
_m4storage[4] = (m00 * argStorage[4]) +
(m01 * argStorage[5]) +
(m02 * argStorage[6]) +
(m03 * argStorage[7]);
_m4storage[8] = (m00 * argStorage[8]) +
(m01 * argStorage[9]) +
(m02 * argStorage[10]) +
(m03 * argStorage[11]);
_m4storage[12] = (m00 * argStorage[12]) +
(m01 * argStorage[13]) +
(m02 * argStorage[14]) +
(m03 * argStorage[15]);
_m4storage[1] = (m10 * argStorage[0]) +
(m11 * argStorage[1]) +
(m12 * argStorage[2]) +
(m13 * argStorage[3]);
_m4storage[5] = (m10 * argStorage[4]) +
(m11 * argStorage[5]) +
(m12 * argStorage[6]) +
(m13 * argStorage[7]);
_m4storage[9] = (m10 * argStorage[8]) +
(m11 * argStorage[9]) +
(m12 * argStorage[10]) +
(m13 * argStorage[11]);
_m4storage[13] = (m10 * argStorage[12]) +
(m11 * argStorage[13]) +
(m12 * argStorage[14]) +
(m13 * argStorage[15]);
_m4storage[2] = (m20 * argStorage[0]) +
(m21 * argStorage[1]) +
(m22 * argStorage[2]) +
(m23 * argStorage[3]);
_m4storage[6] = (m20 * argStorage[4]) +
(m21 * argStorage[5]) +
(m22 * argStorage[6]) +
(m23 * argStorage[7]);
_m4storage[10] = (m20 * argStorage[8]) +
(m21 * argStorage[9]) +
(m22 * argStorage[10]) +
(m23 * argStorage[11]);
_m4storage[14] = (m20 * argStorage[12]) +
(m21 * argStorage[13]) +
(m22 * argStorage[14]) +
(m23 * argStorage[15]);
_m4storage[3] = (m30 * argStorage[0]) +
(m31 * argStorage[1]) +
(m32 * argStorage[2]) +
(m33 * argStorage[3]);
_m4storage[7] = (m30 * argStorage[4]) +
(m31 * argStorage[5]) +
(m32 * argStorage[6]) +
(m33 * argStorage[7]);
_m4storage[11] = (m30 * argStorage[8]) +
(m31 * argStorage[9]) +
(m32 * argStorage[10]) +
(m33 * argStorage[11]);
_m4storage[15] = (m30 * argStorage[12]) +
(m31 * argStorage[13]) +
(m32 * argStorage[14]) +
(m33 * argStorage[15]);
}
/// Multiply [this] with a transposed [arg].
void multiplyTranspose(Matrix4 arg) {
double m00 = _m4storage[0];
double m01 = _m4storage[4];
double m02 = _m4storage[8];
double m03 = _m4storage[12];
double m10 = _m4storage[1];
double m11 = _m4storage[5];
double m12 = _m4storage[9];
double m13 = _m4storage[13];
double m20 = _m4storage[2];
double m21 = _m4storage[6];
double m22 = _m4storage[10];
double m23 = _m4storage[14];
double m30 = _m4storage[3];
double m31 = _m4storage[7];
double m32 = _m4storage[11];
double m33 = _m4storage[15];
final argStorage = arg._m4storage;
_m4storage[0] = (m00 * argStorage[0]) +
(m01 * argStorage[4]) +
(m02 * argStorage[8]) +
(m03 * argStorage[12]);
_m4storage[4] = (m00 * argStorage[1]) +
(m01 * argStorage[5]) +
(m02 * argStorage[9]) +
(m03 * argStorage[13]);
_m4storage[8] = (m00 * argStorage[2]) +
(m01 * argStorage[6]) +
(m02 * argStorage[10]) +
(m03 * argStorage[14]);
_m4storage[12] = (m00 * argStorage[3]) +
(m01 * argStorage[7]) +
(m02 * argStorage[11]) +
(m03 * argStorage[15]);
_m4storage[1] = (m10 * argStorage[0]) +
(m11 * argStorage[4]) +
(m12 * argStorage[8]) +
(m13 * argStorage[12]);
_m4storage[5] = (m10 * argStorage[1]) +
(m11 * argStorage[5]) +
(m12 * argStorage[9]) +
(m13 * argStorage[13]);
_m4storage[9] = (m10 * argStorage[2]) +
(m11 * argStorage[6]) +
(m12 * argStorage[10]) +
(m13 * argStorage[14]);
_m4storage[13] = (m10 * argStorage[3]) +
(m11 * argStorage[7]) +
(m12 * argStorage[11]) +
(m13 * argStorage[15]);
_m4storage[2] = (m20 * argStorage[0]) +
(m21 * argStorage[4]) +
(m22 * argStorage[8]) +
(m23 * argStorage[12]);
_m4storage[6] = (m20 * argStorage[1]) +
(m21 * argStorage[5]) +
(m22 * argStorage[9]) +
(m23 * argStorage[13]);
_m4storage[10] = (m20 * argStorage[2]) +
(m21 * argStorage[6]) +
(m22 * argStorage[10]) +
(m23 * argStorage[14]);
_m4storage[14] = (m20 * argStorage[3]) +
(m21 * argStorage[7]) +
(m22 * argStorage[11]) +
(m23 * argStorage[15]);
_m4storage[3] = (m30 * argStorage[0]) +
(m31 * argStorage[4]) +
(m32 * argStorage[8]) +
(m33 * argStorage[12]);
_m4storage[7] = (m30 * argStorage[1]) +
(m31 * argStorage[5]) +
(m32 * argStorage[9]) +
(m33 * argStorage[13]);
_m4storage[11] = (m30 * argStorage[2]) +
(m31 * argStorage[6]) +
(m32 * argStorage[10]) +
(m33 * argStorage[14]);
_m4storage[15] = (m30 * argStorage[3]) +
(m31 * argStorage[7]) +
(m32 * argStorage[11]) +
(m33 * argStorage[15]);
}
/// Decomposes [this] into [translation], [rotation] and [scale] components.
void decompose(Vector3 translation, Quaternion rotation, Vector3 scale) {
final v = new Vector3.zero();
var sx = (v..setValues(_m4storage[0], _m4storage[1], _m4storage[2])).length;
var sy = (v..setValues(_m4storage[4], _m4storage[5], _m4storage[6])).length;
var sz =
(v..setValues(_m4storage[8], _m4storage[9], _m4storage[10])).length;
if (determinant() < 0) sx = -sx;
translation._v3storage[0] = _m4storage[12];
translation._v3storage[1] = _m4storage[13];
translation._v3storage[2] = _m4storage[14];
final invSX = 1.0 / sx;
final invSY = 1.0 / sy;
final invSZ = 1.0 / sz;
final m = new Matrix4.copy(this);
m._m4storage[0] *= invSX;
m._m4storage[1] *= invSX;
m._m4storage[2] *= invSX;
m._m4storage[4] *= invSY;
m._m4storage[5] *= invSY;
m._m4storage[6] *= invSY;
m._m4storage[8] *= invSZ;
m._m4storage[9] *= invSZ;
m._m4storage[10] *= invSZ;
rotation.setFromRotation(m.getRotation());
scale._v3storage[0] = sx;
scale._v3storage[1] = sy;
scale._v3storage[2] = sz;
}
/// Rotate [arg] of type [Vector3] using the rotation defined by [this].
Vector3 rotate3(Vector3 arg) {
final argStorage = arg._v3storage;
final x_ = (_m4storage[0] * argStorage[0]) +
(_m4storage[4] * argStorage[1]) +
(_m4storage[8] * argStorage[2]);
final y_ = (_m4storage[1] * argStorage[0]) +
(_m4storage[5] * argStorage[1]) +
(_m4storage[9] * argStorage[2]);
final z_ = (_m4storage[2] * argStorage[0]) +
(_m4storage[6] * argStorage[1]) +
(_m4storage[10] * argStorage[2]);
argStorage[0] = x_;
argStorage[1] = y_;
argStorage[2] = z_;
return arg;
}
/// Rotate a copy of [arg] of type [Vector3] using the rotation defined by
/// [this]. If a [out] parameter is supplied, the copy is stored in [out].
Vector3 rotated3(Vector3 arg, [Vector3 out]) {
if (out == null) {
out = new Vector3.copy(arg);
} else {
out.setFrom(arg);
}
return rotate3(out);
}
/// Transform [arg] of type [Vector3] using the transformation defined by
/// [this].
Vector3 transform3(Vector3 arg) {
final argStorage = arg._v3storage;
final x_ = (_m4storage[0] * argStorage[0]) +
(_m4storage[4] * argStorage[1]) +
(_m4storage[8] * argStorage[2]) +
_m4storage[12];
final y_ = (_m4storage[1] * argStorage[0]) +
(_m4storage[5] * argStorage[1]) +
(_m4storage[9] * argStorage[2]) +
_m4storage[13];
final z_ = (_m4storage[2] * argStorage[0]) +
(_m4storage[6] * argStorage[1]) +
(_m4storage[10] * argStorage[2]) +
_m4storage[14];
argStorage[0] = x_;
argStorage[1] = y_;
argStorage[2] = z_;
return arg;
}
/// Transform a copy of [arg] of type [Vector3] using the transformation
/// defined by [this]. If a [out] parameter is supplied, the copy is stored in
/// [out].
Vector3 transformed3(Vector3 arg, [Vector3 out]) {
if (out == null) {
out = new Vector3.copy(arg);
} else {
out.setFrom(arg);
}
return transform3(out);
}
/// Transform [arg] of type [Vector4] using the transformation defined by
/// [this].
Vector4 transform(Vector4 arg) {
final argStorage = arg._v4storage;
final x_ = (_m4storage[0] * argStorage[0]) +
(_m4storage[4] * argStorage[1]) +
(_m4storage[8] * argStorage[2]) +
(_m4storage[12] * argStorage[3]);
final y_ = (_m4storage[1] * argStorage[0]) +
(_m4storage[5] * argStorage[1]) +
(_m4storage[9] * argStorage[2]) +
(_m4storage[13] * argStorage[3]);
final z_ = (_m4storage[2] * argStorage[0]) +
(_m4storage[6] * argStorage[1]) +
(_m4storage[10] * argStorage[2]) +
(_m4storage[14] * argStorage[3]);
final w_ = (_m4storage[3] * argStorage[0]) +
(_m4storage[7] * argStorage[1]) +
(_m4storage[11] * argStorage[2]) +
(_m4storage[15] * argStorage[3]);
argStorage[0] = x_;
argStorage[1] = y_;
argStorage[2] = z_;
argStorage[3] = w_;
return arg;
}
/// Transform [arg] of type [Vector3] using the perspective transformation
/// defined by [this].
Vector3 perspectiveTransform(Vector3 arg) {
final argStorage = arg._v3storage;
final x_ = (_m4storage[0] * argStorage[0]) +
(_m4storage[4] * argStorage[1]) +
(_m4storage[8] * argStorage[2]) +
_m4storage[12];
final y_ = (_m4storage[1] * argStorage[0]) +
(_m4storage[5] * argStorage[1]) +
(_m4storage[9] * argStorage[2]) +
_m4storage[13];
final z_ = (_m4storage[2] * argStorage[0]) +
(_m4storage[6] * argStorage[1]) +
(_m4storage[10] * argStorage[2]) +
_m4storage[14];
final w_ = 1.0 /
((_m4storage[3] * argStorage[0]) +
(_m4storage[7] * argStorage[1]) +
(_m4storage[11] * argStorage[2]) +
_m4storage[15]);
argStorage[0] = x_ * w_;
argStorage[1] = y_ * w_;
argStorage[2] = z_ * w_;
return arg;
}
/// Transform a copy of [arg] of type [Vector4] using the transformation
/// defined by [this]. If a [out] parameter is supplied, the copy is stored in
/// [out].
Vector4 transformed(Vector4 arg, [Vector4 out]) {
if (out == null) {
out = new Vector4.copy(arg);
} else {
out.setFrom(arg);
}
return transform(out);
}
/// Copies [this] into [array] starting at [offset].
void copyIntoArray(List<num> array, [int offset = 0]) {
int i = offset;
array[i + 15] = _m4storage[15];
array[i + 14] = _m4storage[14];
array[i + 13] = _m4storage[13];
array[i + 12] = _m4storage[12];
array[i + 11] = _m4storage[11];
array[i + 10] = _m4storage[10];
array[i + 9] = _m4storage[9];
array[i + 8] = _m4storage[8];
array[i + 7] = _m4storage[7];
array[i + 6] = _m4storage[6];
array[i + 5] = _m4storage[5];
array[i + 4] = _m4storage[4];
array[i + 3] = _m4storage[3];
array[i + 2] = _m4storage[2];
array[i + 1] = _m4storage[1];
array[i + 0] = _m4storage[0];
}
/// Copies elements from [array] into [this] starting at [offset].
void copyFromArray(List<double> array, [int offset = 0]) {
int i = offset;
_m4storage[15] = array[i + 15];
_m4storage[14] = array[i + 14];
_m4storage[13] = array[i + 13];
_m4storage[12] = array[i + 12];
_m4storage[11] = array[i + 11];
_m4storage[10] = array[i + 10];
_m4storage[9] = array[i + 9];
_m4storage[8] = array[i + 8];
_m4storage[7] = array[i + 7];
_m4storage[6] = array[i + 6];
_m4storage[5] = array[i + 5];
_m4storage[4] = array[i + 4];
_m4storage[3] = array[i + 3];
_m4storage[2] = array[i + 2];
_m4storage[1] = array[i + 1];
_m4storage[0] = array[i + 0];
}
/// Multiply [this] to each set of xyz values in [array] starting at [offset].
List<double> applyToVector3Array(List<double> array, [int offset = 0]) {
for (var i = 0, j = offset; i < array.length; i += 3, j += 3) {
final v = new Vector3.array(array, j)..applyMatrix4(this);
array[j] = v.storage[0];
array[j + 1] = v.storage[1];
array[j + 2] = v.storage[2];
}
return array;
}
Vector3 get right {
double x = _m4storage[0];
double y = _m4storage[1];
double z = _m4storage[2];
return new Vector3(x, y, z);
}
Vector3 get up {
double x = _m4storage[4];
double y = _m4storage[5];
double z = _m4storage[6];
return new Vector3(x, y, z);
}
Vector3 get forward {
double x = _m4storage[8];
double y = _m4storage[9];
double z = _m4storage[10];
return new Vector3(x, y, z);
}
/// Is [this] the identity matrix?
bool isIdentity() {
return _m4storage[0] == 1.0 // col 1
&& _m4storage[1] == 0.0
&& _m4storage[2] == 0.0
&& _m4storage[3] == 0.0
&& _m4storage[4] == 0.0 // col 2
&& _m4storage[5] == 1.0
&& _m4storage[6] == 0.0
&& _m4storage[7] == 0.0
&& _m4storage[8] == 0.0 // col 3
&& _m4storage[9] == 0.0
&& _m4storage[10] == 1.0
&& _m4storage[11] == 0.0
&& _m4storage[12] == 0.0 // col 4
&& _m4storage[13] == 0.0
&& _m4storage[14] == 0.0
&& _m4storage[15] == 1.0;
}
/// Is [this] the zero matrix?
bool isZero() {
return _m4storage[0] == 0.0 // col 1
&& _m4storage[1] == 0.0
&& _m4storage[2] == 0.0
&& _m4storage[3] == 0.0
&& _m4storage[4] == 0.0 // col 2
&& _m4storage[5] == 0.0
&& _m4storage[6] == 0.0
&& _m4storage[7] == 0.0
&& _m4storage[8] == 0.0 // col 3
&& _m4storage[9] == 0.0
&& _m4storage[10] == 0.0
&& _m4storage[11] == 0.0
&& _m4storage[12] == 0.0 // col 4
&& _m4storage[13] == 0.0
&& _m4storage[14] == 0.0
&& _m4storage[15] == 0.0;
}
}