|
@@ -1,5 +1,5 @@
|
|
|
/**
|
|
|
- * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
+ * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
*
|
|
|
* @author David Sehnal <david.sehnal@gmail.com>
|
|
|
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
@@ -17,10 +17,11 @@
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
*/
|
|
|
|
|
|
-import { Mat4 } from '../3d'
|
|
|
+import { Mat4, Vec3 } from '../3d'
|
|
|
import { NumberArray } from '../../../mol-util/type-helpers';
|
|
|
|
|
|
interface Mat3 extends Array<number> { [d: number]: number, '@type': 'mat3', length: 9 }
|
|
|
+interface ReadonlyMat3 extends Array<number> { readonly [d: number]: number, '@type': 'mat3', length: 9 }
|
|
|
|
|
|
function Mat3() {
|
|
|
return Mat3.zero();
|
|
@@ -102,6 +103,20 @@ namespace Mat3 {
|
|
|
return out;
|
|
|
}
|
|
|
|
|
|
+ export function create(a00: number, a01: number, a02: number, a10: number, a11: number, a12: number, a20: number, a21: number, a22: number): Mat3 {
|
|
|
+ const out = zero();
|
|
|
+ out[0] = a00
|
|
|
+ out[1] = a01
|
|
|
+ out[2] = a02
|
|
|
+ out[3] = a10
|
|
|
+ out[4] = a11
|
|
|
+ out[5] = a12
|
|
|
+ out[6] = a20
|
|
|
+ out[7] = a21
|
|
|
+ out[8] = a22
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
export function hasNaN(m: Mat3) {
|
|
|
for (let i = 0; i < 9; i++) if (isNaN(m[i])) return true
|
|
|
return false
|
|
@@ -114,6 +129,13 @@ namespace Mat3 {
|
|
|
return Mat3.copy(Mat3.zero(), a);
|
|
|
}
|
|
|
|
|
|
+ export function areEqual(a: Mat3, b: Mat3, eps: number) {
|
|
|
+ for (let i = 0; i < 9; i++) {
|
|
|
+ if (Math.abs(a[i] - b[i]) > eps) return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
export function setValue(a: Mat3, i: number, j: number, value: number) {
|
|
|
a[3 * j + i] = value;
|
|
|
}
|
|
@@ -210,6 +232,172 @@ namespace Mat3 {
|
|
|
// Calculate the determinant
|
|
|
return a00 * b01 + a01 * b11 + a02 * b21;
|
|
|
}
|
|
|
+
|
|
|
+ export function trace(a: Mat3) {
|
|
|
+ return a[0] + a[4] + a[8]
|
|
|
+ }
|
|
|
+
|
|
|
+ export function sub(out: Mat3, a: Mat3, b: Mat3) {
|
|
|
+ out[0] = a[0] - b[0]
|
|
|
+ out[1] = a[1] - b[1]
|
|
|
+ out[2] = a[2] - b[2]
|
|
|
+ out[3] = a[3] - b[3]
|
|
|
+ out[4] = a[4] - b[4]
|
|
|
+ out[5] = a[5] - b[5]
|
|
|
+ out[6] = a[6] - b[6]
|
|
|
+ out[7] = a[7] - b[7]
|
|
|
+ out[8] = a[8] - b[8]
|
|
|
+ return out
|
|
|
+ }
|
|
|
+
|
|
|
+ export function add(out: Mat3, a: Mat3, b: Mat3) {
|
|
|
+ out[0] = a[0] + b[0]
|
|
|
+ out[1] = a[1] + b[1]
|
|
|
+ out[2] = a[2] + b[2]
|
|
|
+ out[3] = a[3] + b[3]
|
|
|
+ out[4] = a[4] + b[4]
|
|
|
+ out[5] = a[5] + b[5]
|
|
|
+ out[6] = a[6] + b[6]
|
|
|
+ out[7] = a[7] + b[7]
|
|
|
+ out[8] = a[8] + b[8]
|
|
|
+ return out
|
|
|
+ }
|
|
|
+
|
|
|
+ export function mul(out: Mat3, a: Mat3, b: Mat3) {
|
|
|
+ const a00 = a[0], a01 = a[1], a02 = a[2],
|
|
|
+ a10 = a[3], a11 = a[4], a12 = a[5],
|
|
|
+ a20 = a[6], a21 = a[7], a22 = a[8];
|
|
|
+
|
|
|
+ const b00 = b[0], b01 = b[1], b02 = b[2],
|
|
|
+ b10 = b[3], b11 = b[4], b12 = b[5],
|
|
|
+ b20 = b[6], b21 = b[7], b22 = b[8];
|
|
|
+
|
|
|
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
|
|
|
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
|
|
|
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
|
|
|
+
|
|
|
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
|
|
|
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
|
|
|
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
|
|
|
+
|
|
|
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
|
|
|
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
|
|
|
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
+ export function subScalar(out: Mat3, a: Mat3, s: number) {
|
|
|
+ out[0] = a[0] - s
|
|
|
+ out[1] = a[1] - s
|
|
|
+ out[2] = a[2] - s
|
|
|
+ out[3] = a[3] - s
|
|
|
+ out[4] = a[4] - s
|
|
|
+ out[5] = a[5] - s
|
|
|
+ out[6] = a[6] - s
|
|
|
+ out[7] = a[7] - s
|
|
|
+ out[8] = a[8] - s
|
|
|
+ return out
|
|
|
+ }
|
|
|
+
|
|
|
+ export function addScalar(out: Mat3, a: Mat3, s: number) {
|
|
|
+ out[0] = a[0] + s
|
|
|
+ out[1] = a[1] + s
|
|
|
+ out[2] = a[2] + s
|
|
|
+ out[3] = a[3] + s
|
|
|
+ out[4] = a[4] + s
|
|
|
+ out[5] = a[5] + s
|
|
|
+ out[6] = a[6] + s
|
|
|
+ out[7] = a[7] + s
|
|
|
+ out[8] = a[8] + s
|
|
|
+ return out
|
|
|
+ }
|
|
|
+
|
|
|
+ export function mulScalar(out: Mat3, a: Mat3, s: number) {
|
|
|
+ out[0] = a[0] * s
|
|
|
+ out[1] = a[1] * s
|
|
|
+ out[2] = a[2] * s
|
|
|
+ out[3] = a[3] * s
|
|
|
+ out[4] = a[4] * s
|
|
|
+ out[5] = a[5] * s
|
|
|
+ out[6] = a[6] * s
|
|
|
+ out[7] = a[7] * s
|
|
|
+ out[8] = a[8] * s
|
|
|
+ return out
|
|
|
+ }
|
|
|
+
|
|
|
+ const piThird = Math.PI / 3
|
|
|
+ const tmpB = Mat3()
|
|
|
+ /**
|
|
|
+ * Given a real symmetric 3x3 matrix A, compute the eigenvalues
|
|
|
+ *
|
|
|
+ * From https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3.C3.973_matrices
|
|
|
+ */
|
|
|
+ export function symmetricEigenvalues(out: Vec3, a: Mat3) {
|
|
|
+ const p1 = a[1] * a[1] + a[2] * a[2] + a[5] * a[5]
|
|
|
+ if (p1 === 0) {
|
|
|
+ out[0] = a[0]
|
|
|
+ out[1] = a[4]
|
|
|
+ out[2] = a[8]
|
|
|
+ } else {
|
|
|
+ const q = trace(a) / 3
|
|
|
+ const a1 = a[0] - q
|
|
|
+ const a2 = a[4] - q
|
|
|
+ const a3 = a[8] - q
|
|
|
+ const p2 = a1 * a1 + a2 * a2 + a3 * a3 + 2 * p1
|
|
|
+ const p = Math.sqrt(p2 / 6)
|
|
|
+ mulScalar(tmpB, Identity, q)
|
|
|
+ sub(tmpB, a, tmpB)
|
|
|
+ mulScalar(tmpB, tmpB, (1 / p))
|
|
|
+ const r = determinant(tmpB) / 2
|
|
|
+ // In exact arithmetic for a symmetric matrix -1 <= r <= 1
|
|
|
+ // but computation error can leave it slightly outside this range.
|
|
|
+ const phi = r <= -1 ? piThird : r >= 1 ?
|
|
|
+ 0 : Math.acos(r) / 3
|
|
|
+ // the eigenvalues satisfy eig3 <= eig2 <= eig1
|
|
|
+ out[0] = q + 2 * p * Math.cos(phi)
|
|
|
+ out[2] = q + 2 * p * Math.cos(phi + (2 * piThird))
|
|
|
+ out[1] = 3 * q - out[0] - out[2] // since trace(A) = eig1 + eig2 + eig3
|
|
|
+ }
|
|
|
+ return out
|
|
|
+ }
|
|
|
+
|
|
|
+ const tmpR0 = [0.1, 0.0, 0.0] as Vec3
|
|
|
+ const tmpR1 = [0.1, 0.0, 0.0] as Vec3
|
|
|
+ const tmpR2 = [0.1, 0.0, 0.0] as Vec3
|
|
|
+ const tmpR0xR1 = [0.1, 0.0, 0.0] as Vec3
|
|
|
+ const tmpR0xR2 = [0.1, 0.0, 0.0] as Vec3
|
|
|
+ const tmpR1xR2 = [0.1, 0.0, 0.0] as Vec3
|
|
|
+ /**
|
|
|
+ * Calculates the eigenvector for the given eigenvalue `e` of matrix `a`
|
|
|
+ */
|
|
|
+ export function eigenvector(out: Vec3, a: Mat3, e: number) {
|
|
|
+ Vec3.set(tmpR0, a[0] - e, a[1], a[2])
|
|
|
+ Vec3.set(tmpR1, a[1], a[4] - e, a[5])
|
|
|
+ Vec3.set(tmpR2, a[2], a[5], a[8] - e)
|
|
|
+ Vec3.cross(tmpR0xR1, tmpR0, tmpR1)
|
|
|
+ Vec3.cross(tmpR0xR2, tmpR0, tmpR2)
|
|
|
+ Vec3.cross(tmpR1xR2, tmpR1, tmpR2)
|
|
|
+ const d0 = Vec3.dot(tmpR0xR1, tmpR0xR1)
|
|
|
+ const d1 = Vec3.dot(tmpR0xR2, tmpR0xR2)
|
|
|
+ const d2 = Vec3.dot(tmpR1xR2, tmpR1xR2)
|
|
|
+ let dmax = d0
|
|
|
+ let imax = 0
|
|
|
+ if (d1 > dmax) {
|
|
|
+ dmax = d1
|
|
|
+ imax = 1
|
|
|
+ }
|
|
|
+ if (d2 > dmax) imax = 2
|
|
|
+ if (imax === 0) {
|
|
|
+ Vec3.scale(out, tmpR0xR1, 1 / Math.sqrt(d0))
|
|
|
+ } else if (imax === 1) {
|
|
|
+ Vec3.scale(out, tmpR0xR2, 1 / Math.sqrt(d1))
|
|
|
+ } else {
|
|
|
+ Vec3.scale(out, tmpR1xR2, 1 / Math.sqrt(d2))
|
|
|
+ }
|
|
|
+ return out
|
|
|
+ }
|
|
|
+
|
|
|
+ export const Identity: ReadonlyMat3 = identity()
|
|
|
}
|
|
|
|
|
|
export default Mat3
|