| // 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_64.dart'; |
| |
| /// 2D Matrix. |
| /// Values are stored in column major order. |
| class Matrix2 { |
| final Float64List _m2storage; |
| |
| /// The components of the matrix. |
| Float64List get storage => _m2storage; |
| |
| /// Solve [A] * [x] = [b]. |
| static void solve(Matrix2 A, Vector2 x, Vector2 b) { |
| final a11 = A.entry(0, 0); |
| final a12 = A.entry(0, 1); |
| final a21 = A.entry(1, 0); |
| final a22 = A.entry(1, 1); |
| final bx = b.x; |
| final by = b.y; |
| var det = a11 * a22 - a12 * a21; |
| |
| if (det != 0.0) { |
| det = 1.0 / det; |
| } |
| |
| x |
| ..x = det * (a22 * bx - a12 * by) |
| ..y = det * (a11 * by - a21 * bx); |
| } |
| |
| /// Return index in storage for [row], [col] value. |
| int index(int row, int col) => (col * 2) + row; |
| |
| /// Value at [row], [col]. |
| double entry(int row, int col) { |
| assert((row >= 0) && (row < dimension)); |
| assert((col >= 0) && (col < dimension)); |
| |
| return _m2storage[index(row, col)]; |
| } |
| |
| /// Set value at [row], [col] to be [v]. |
| void setEntry(int row, int col, double v) { |
| assert((row >= 0) && (row < dimension)); |
| assert((col >= 0) && (col < dimension)); |
| |
| _m2storage[index(row, col)] = v; |
| } |
| |
| /// New matrix with specified values. |
| factory Matrix2(double arg0, double arg1, double arg2, double arg3) => |
| Matrix2.zero()..setValues(arg0, arg1, arg2, arg3); |
| |
| /// New matrix from [values]. |
| factory Matrix2.fromList(List<double> values) => |
| Matrix2.zero()..setValues(values[0], values[1], values[2], values[3]); |
| |
| /// Zero matrix. |
| Matrix2.zero() : _m2storage = Float64List(4); |
| |
| /// Identity matrix. |
| factory Matrix2.identity() => Matrix2.zero()..setIdentity(); |
| |
| /// Copies values from [other]. |
| factory Matrix2.copy(Matrix2 other) => Matrix2.zero()..setFrom(other); |
| |
| /// Matrix with values from column arguments. |
| factory Matrix2.columns(Vector2 arg0, Vector2 arg1) => |
| Matrix2.zero()..setColumns(arg0, arg1); |
| |
| /// Outer product of [u] and [v]. |
| factory Matrix2.outer(Vector2 u, Vector2 v) => Matrix2.zero()..setOuter(u, v); |
| |
| /// Rotation of [radians]. |
| factory Matrix2.rotation(double radians) => |
| Matrix2.zero()..setRotation(radians); |
| |
| /// Sets the matrix with specified values. |
| void setValues(double arg0, double arg1, double arg2, double arg3) { |
| _m2storage[3] = arg3; |
| _m2storage[2] = arg2; |
| _m2storage[1] = arg1; |
| _m2storage[0] = arg0; |
| } |
| |
| /// Sets the entire matrix to the column values. |
| void setColumns(Vector2 arg0, Vector2 arg1) { |
| final arg0Storage = arg0._v2storage; |
| final arg1Storage = arg1._v2storage; |
| _m2storage[0] = arg0Storage[0]; |
| _m2storage[1] = arg0Storage[1]; |
| _m2storage[2] = arg1Storage[0]; |
| _m2storage[3] = arg1Storage[1]; |
| } |
| |
| /// Sets the entire matrix to the matrix in [arg]. |
| void setFrom(Matrix2 arg) { |
| final argStorage = arg._m2storage; |
| _m2storage[3] = argStorage[3]; |
| _m2storage[2] = argStorage[2]; |
| _m2storage[1] = argStorage[1]; |
| _m2storage[0] = argStorage[0]; |
| } |
| |
| /// Set this to the outer product of [u] and [v]. |
| void setOuter(Vector2 u, Vector2 v) { |
| final uStorage = u._v2storage; |
| final vStorage = v._v2storage; |
| _m2storage[0] = uStorage[0] * vStorage[0]; |
| _m2storage[1] = uStorage[0] * vStorage[1]; |
| _m2storage[2] = uStorage[1] * vStorage[0]; |
| _m2storage[3] = uStorage[1] * vStorage[1]; |
| } |
| |
| /// Sets the diagonal to [arg]. |
| void splatDiagonal(double arg) { |
| _m2storage[0] = arg; |
| _m2storage[3] = arg; |
| } |
| |
| /// Sets the diagonal of the matrix to be [arg]. |
| void setDiagonal(Vector2 arg) { |
| final argStorage = arg._v2storage; |
| _m2storage[0] = argStorage[0]; |
| _m2storage[3] = argStorage[1]; |
| } |
| |
| /// Returns a printable string |
| @override |
| String toString() => '[0] ${getRow(0)}\n[1] ${getRow(1)}\n'; |
| |
| /// Dimension of the matrix. |
| int get dimension => 2; |
| |
| /// Access the element of the matrix at the index [i]. |
| double operator [](int i) => _m2storage[i]; |
| |
| /// Set the element of the matrix at the index [i]. |
| void operator []=(int i, double v) { |
| _m2storage[i] = v; |
| } |
| |
| /// Check if two matrices are the same. |
| @override |
| bool operator ==(Object other) => |
| (other is Matrix2) && |
| (_m2storage[0] == other._m2storage[0]) && |
| (_m2storage[1] == other._m2storage[1]) && |
| (_m2storage[2] == other._m2storage[2]) && |
| (_m2storage[3] == other._m2storage[3]); |
| |
| @override |
| int get hashCode => Object.hashAll(_m2storage); |
| |
| /// Returns row 0 |
| Vector2 get row0 => getRow(0); |
| |
| /// Returns row 1 |
| Vector2 get row1 => getRow(1); |
| |
| /// Sets row 0 to [arg] |
| set row0(Vector2 arg) => setRow(0, arg); |
| |
| /// Sets row 1 to [arg] |
| set row1(Vector2 arg) => setRow(1, arg); |
| |
| /// Sets [row] of the matrix to values in [arg] |
| void setRow(int row, Vector2 arg) { |
| final argStorage = arg._v2storage; |
| _m2storage[index(row, 0)] = argStorage[0]; |
| _m2storage[index(row, 1)] = argStorage[1]; |
| } |
| |
| /// Gets the [row] of the matrix |
| Vector2 getRow(int row) { |
| final r = Vector2.zero(); |
| final rStorage = r._v2storage; |
| rStorage[0] = _m2storage[index(row, 0)]; |
| rStorage[1] = _m2storage[index(row, 1)]; |
| return r; |
| } |
| |
| /// Assigns the [column] of the matrix [arg] |
| void setColumn(int column, Vector2 arg) { |
| final argStorage = arg._v2storage; |
| final entry = column * 2; |
| _m2storage[entry + 1] = argStorage[1]; |
| _m2storage[entry + 0] = argStorage[0]; |
| } |
| |
| /// Gets the [column] of the matrix |
| Vector2 getColumn(int column) { |
| final r = Vector2.zero(); |
| final entry = column * 2; |
| final rStorage = r._v2storage; |
| rStorage[1] = _m2storage[entry + 1]; |
| rStorage[0] = _m2storage[entry + 0]; |
| return r; |
| } |
| |
| /// Create a copy of this. |
| Matrix2 clone() => Matrix2.copy(this); |
| |
| /// Copy this into [arg]. |
| Matrix2 copyInto(Matrix2 arg) { |
| final argStorage = arg._m2storage; |
| argStorage[0] = _m2storage[0]; |
| argStorage[1] = _m2storage[1]; |
| argStorage[2] = _m2storage[2]; |
| argStorage[3] = _m2storage[3]; |
| return arg; |
| } |
| |
| /// 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 Vector2) { |
| return transformed(arg); |
| } |
| if (arg is Matrix2) { |
| return multiplied(arg); |
| } |
| throw ArgumentError(arg); |
| } |
| |
| /// Returns new matrix after component wise this + [arg] |
| Matrix2 operator +(Matrix2 arg) => clone()..add(arg); |
| |
| /// Returns new matrix after component wise this - [arg] |
| Matrix2 operator -(Matrix2 arg) => clone()..sub(arg); |
| |
| /// Returns new matrix -this |
| Matrix2 operator -() => clone()..negate(); |
| |
| /// Zeros this. |
| void setZero() { |
| _m2storage[0] = 0.0; |
| _m2storage[1] = 0.0; |
| _m2storage[2] = 0.0; |
| _m2storage[3] = 0.0; |
| } |
| |
| /// Makes this into the identity matrix. |
| void setIdentity() { |
| _m2storage[0] = 1.0; |
| _m2storage[1] = 0.0; |
| _m2storage[2] = 0.0; |
| _m2storage[3] = 1.0; |
| } |
| |
| /// Returns the tranpose of this. |
| Matrix2 transposed() => clone()..transpose(); |
| |
| void transpose() { |
| final temp = _m2storage[2]; |
| _m2storage[2] = _m2storage[1]; |
| _m2storage[1] = temp; |
| } |
| |
| /// Returns the component wise absolute value of this. |
| Matrix2 absolute() { |
| final r = Matrix2.zero(); |
| final rStorage = r._m2storage; |
| rStorage[0] = _m2storage[0].abs(); |
| rStorage[1] = _m2storage[1].abs(); |
| rStorage[2] = _m2storage[2].abs(); |
| rStorage[3] = _m2storage[3].abs(); |
| return r; |
| } |
| |
| /// Returns the determinant of this matrix. |
| double determinant() => |
| (_m2storage[0] * _m2storage[3]) - (_m2storage[1] * _m2storage[2]); |
| |
| /// Returns the dot product of row [i] and [v]. |
| double dotRow(int i, Vector2 v) { |
| final vStorage = v._v2storage; |
| return _m2storage[i] * vStorage[0] + _m2storage[2 + i] * vStorage[1]; |
| } |
| |
| /// Returns the dot product of column [j] and [v]. |
| double dotColumn(int j, Vector2 v) { |
| final vStorage = v._v2storage; |
| return _m2storage[j * 2] * vStorage[0] + |
| _m2storage[(j * 2) + 1] * vStorage[1]; |
| } |
| |
| /// Trace of the matrix. |
| double trace() { |
| var t = 0.0; |
| t += _m2storage[0]; |
| t += _m2storage[3]; |
| return t; |
| } |
| |
| /// Returns infinity norm of the matrix. Used for numerical analysis. |
| double infinityNorm() { |
| var norm = 0.0; |
| { |
| var rowNorm = 0.0; |
| rowNorm += _m2storage[0].abs(); |
| rowNorm += _m2storage[1].abs(); |
| norm = rowNorm > norm ? rowNorm : norm; |
| } |
| { |
| var rowNorm = 0.0; |
| rowNorm += _m2storage[2].abs(); |
| rowNorm += _m2storage[3].abs(); |
| norm = rowNorm > norm ? rowNorm : norm; |
| } |
| return norm; |
| } |
| |
| /// Returns relative error between this and [correct] |
| double relativeError(Matrix2 correct) { |
| final diff = correct - this; |
| final correctNorm = correct.infinityNorm(); |
| final diff_norm = diff.infinityNorm(); |
| return diff_norm / correctNorm; |
| } |
| |
| /// Returns absolute error between this and [correct] |
| double absoluteError(Matrix2 correct) { |
| final this_norm = infinityNorm(); |
| final correct_norm = correct.infinityNorm(); |
| final diff_norm = (this_norm - correct_norm).abs(); |
| return diff_norm; |
| } |
| |
| /// Invert the matrix. Returns the determinant. |
| double invert() { |
| final det = determinant(); |
| if (det == 0.0) { |
| return 0.0; |
| } |
| final invDet = 1.0 / det; |
| final temp = _m2storage[0]; |
| _m2storage[0] = _m2storage[3] * invDet; |
| _m2storage[1] = -_m2storage[1] * invDet; |
| _m2storage[2] = -_m2storage[2] * invDet; |
| _m2storage[3] = temp * invDet; |
| return det; |
| } |
| |
| /// Set this matrix to be the inverse of [arg] |
| double copyInverse(Matrix2 arg) { |
| final det = arg.determinant(); |
| if (det == 0.0) { |
| setFrom(arg); |
| return 0.0; |
| } |
| final invDet = 1.0 / det; |
| final argStorage = arg._m2storage; |
| _m2storage[0] = argStorage[3] * invDet; |
| _m2storage[1] = -argStorage[1] * invDet; |
| _m2storage[2] = -argStorage[2] * invDet; |
| _m2storage[3] = argStorage[0] * invDet; |
| return det; |
| } |
| |
| /// Turns the matrix into a rotation of [radians] |
| void setRotation(double radians) { |
| final c = math.cos(radians); |
| final s = math.sin(radians); |
| _m2storage[0] = c; |
| _m2storage[1] = s; |
| _m2storage[2] = -s; |
| _m2storage[3] = c; |
| } |
| |
| /// Converts into Adjugate matrix and scales by [scale] |
| void scaleAdjoint(double scale) { |
| final temp = _m2storage[0]; |
| _m2storage[0] = _m2storage[3] * scale; |
| _m2storage[2] = -_m2storage[2] * scale; |
| _m2storage[1] = -_m2storage[1] * scale; |
| _m2storage[3] = temp * scale; |
| } |
| |
| /// Scale this by [scale]. |
| void scale(double scale) { |
| _m2storage[0] = _m2storage[0] * scale; |
| _m2storage[1] = _m2storage[1] * scale; |
| _m2storage[2] = _m2storage[2] * scale; |
| _m2storage[3] = _m2storage[3] * scale; |
| } |
| |
| /// Create a copy of this scaled by [scale]. |
| Matrix2 scaled(double scale) => clone()..scale(scale); |
| |
| /// Add [o] to this. |
| void add(Matrix2 o) { |
| final oStorage = o._m2storage; |
| _m2storage[0] = _m2storage[0] + oStorage[0]; |
| _m2storage[1] = _m2storage[1] + oStorage[1]; |
| _m2storage[2] = _m2storage[2] + oStorage[2]; |
| _m2storage[3] = _m2storage[3] + oStorage[3]; |
| } |
| |
| /// Subtract [o] from this. |
| void sub(Matrix2 o) { |
| final oStorage = o._m2storage; |
| _m2storage[0] = _m2storage[0] - oStorage[0]; |
| _m2storage[1] = _m2storage[1] - oStorage[1]; |
| _m2storage[2] = _m2storage[2] - oStorage[2]; |
| _m2storage[3] = _m2storage[3] - oStorage[3]; |
| } |
| |
| /// Negate this. |
| void negate() { |
| _m2storage[0] = -_m2storage[0]; |
| _m2storage[1] = -_m2storage[1]; |
| _m2storage[2] = -_m2storage[2]; |
| _m2storage[3] = -_m2storage[3]; |
| } |
| |
| /// Multiply this with [arg] and store it in this. |
| void multiply(Matrix2 arg) { |
| final m00 = _m2storage[0]; |
| final m01 = _m2storage[2]; |
| final m10 = _m2storage[1]; |
| final m11 = _m2storage[3]; |
| final argStorage = arg._m2storage; |
| final n00 = argStorage[0]; |
| final n01 = argStorage[2]; |
| final n10 = argStorage[1]; |
| final n11 = argStorage[3]; |
| _m2storage[0] = (m00 * n00) + (m01 * n10); |
| _m2storage[2] = (m00 * n01) + (m01 * n11); |
| _m2storage[1] = (m10 * n00) + (m11 * n10); |
| _m2storage[3] = (m10 * n01) + (m11 * n11); |
| } |
| |
| /// Multiply this with [arg] and return the product. |
| Matrix2 multiplied(Matrix2 arg) => clone()..multiply(arg); |
| |
| /// Multiply a transposed this with [arg]. |
| void transposeMultiply(Matrix2 arg) { |
| final m00 = _m2storage[0]; |
| final m01 = _m2storage[1]; |
| final m10 = _m2storage[2]; |
| final m11 = _m2storage[3]; |
| final argStorage = arg._m2storage; |
| _m2storage[0] = (m00 * argStorage[0]) + (m01 * argStorage[1]); |
| _m2storage[2] = (m00 * argStorage[2]) + (m01 * argStorage[3]); |
| _m2storage[1] = (m10 * argStorage[0]) + (m11 * argStorage[1]); |
| _m2storage[3] = (m10 * argStorage[2]) + (m11 * argStorage[3]); |
| } |
| |
| /// Multiply this with a transposed [arg]. |
| void multiplyTranspose(Matrix2 arg) { |
| final m00 = _m2storage[0]; |
| final m01 = _m2storage[2]; |
| final m10 = _m2storage[1]; |
| final m11 = _m2storage[3]; |
| final argStorage = arg._m2storage; |
| _m2storage[0] = (m00 * argStorage[0]) + (m01 * argStorage[2]); |
| _m2storage[2] = (m00 * argStorage[1]) + (m01 * argStorage[3]); |
| _m2storage[1] = (m10 * argStorage[0]) + (m11 * argStorage[2]); |
| _m2storage[3] = (m10 * argStorage[1]) + (m11 * argStorage[3]); |
| } |
| |
| /// Transform [arg] of type [Vector2] using the transformation defined by |
| /// this. |
| Vector2 transform(Vector2 arg) { |
| final argStorage = arg._v2storage; |
| final x = (_m2storage[0] * argStorage[0]) + (_m2storage[2] * argStorage[1]); |
| final y = (_m2storage[1] * argStorage[0]) + (_m2storage[3] * argStorage[1]); |
| argStorage[0] = x; |
| argStorage[1] = y; |
| return arg; |
| } |
| |
| /// Transform a copy of [arg] of type [Vector2] using the transformation |
| /// defined by this. If a [out] parameter is supplied, the copy is stored in |
| /// [out]. |
| Vector2 transformed(Vector2 arg, [Vector2? out]) { |
| if (out == null) { |
| out = Vector2.copy(arg); |
| } else { |
| out.setFrom(arg); |
| } |
| return transform(out); |
| } |
| |
| /// Copies this into [array] starting at [offset]. |
| void copyIntoArray(List<num> array, [int offset = 0]) { |
| final i = offset; |
| array[i + 3] = _m2storage[3]; |
| array[i + 2] = _m2storage[2]; |
| array[i + 1] = _m2storage[1]; |
| array[i + 0] = _m2storage[0]; |
| } |
| |
| /// Copies elements from [array] into this starting at [offset]. |
| void copyFromArray(List<double> array, [int offset = 0]) { |
| final i = offset; |
| _m2storage[3] = array[i + 3]; |
| _m2storage[2] = array[i + 2]; |
| _m2storage[1] = array[i + 1]; |
| _m2storage[0] = array[i + 0]; |
| } |
| } |