Skip to content

Commit 6bf9427

Browse files
committed
feat(math): expose new convenient matrix functions
1 parent 4652c98 commit 6bf9427

File tree

5 files changed

+130
-31
lines changed

5 files changed

+130
-31
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const IDENTITY = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
2+
export const IDENTITY_3X3 = [1, 0, 0, 0, 1, 0, 0, 0, 1];
3+
4+
export const EPSILON = 1e-6;
5+
export const VTK_SMALL_NUMBER = 1.0e-12;
6+
7+
export default {
8+
IDENTITY,
9+
IDENTITY_3X3,
10+
EPSILON,
11+
VTK_SMALL_NUMBER,
12+
};

Sources/Common/Core/Math/index.d.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,12 +489,41 @@ export function transpose3x3(in_3x3: Matrix3x3, outT_3x3: Matrix3x3): void;
489489
*/
490490
export function invert3x3(in_3x3: Matrix3x3, outI_3x3: Matrix3x3): void;
491491

492+
/**
493+
* Set mat to the identity matrix.
494+
* @param {Number} n The size of the matrix.
495+
* @param {Number[]} mat The output matrix.
496+
* @see isIdentity()
497+
* @see identity3x3()
498+
*/
499+
export function identity(n: number, mat: number[]): void;
500+
492501
/**
493502
* Set mat_3x3 to the identity matrix.
494503
* @param {Matrix3x3} mat_3x3 The input 3x3 matrix.
504+
* @see isIdentity3x3()
505+
* @see identity()
495506
*/
496507
export function identity3x3(mat_3x3: Matrix3x3): void;
497508

509+
/**
510+
* Returns true if provided matrix is the identity matrix.
511+
* @param {Number[]} mat The 3x3 matrix to check
512+
* @param {Number} [eps] The tolerance value.
513+
* @see isIdentity()
514+
* @see identity()
515+
*/
516+
export function isIdentity(mat: Matrix3x3, eps?: number): boolean;
517+
518+
/**
519+
* Returns true if provided 3x3 matrix is the identity matrix.
520+
* @param {Matrix3x3} mat The 3x3 matrix to check
521+
* @param {Number} [eps] The tolerance value.
522+
* @see isIdentity()
523+
* @see identity3x3()
524+
*/
525+
export function isIdentity3x3(mat: Matrix3x3, eps?: number): boolean;
526+
498527
/**
499528
* Calculate the determinant of a 3x3 matrix.
500529
* @param {Matrix3x3} mat_3x3 The input 3x3 matrix.
@@ -606,13 +635,14 @@ export function solveLinearSystem(A: Matrix, x: number[], size: number): number;
606635

607636
/**
608637
*
609-
* @param {Matrix} A
610-
* @param {Matrix} AI
611-
* @param {Number} [size]
638+
* @param {Matrix} A The input matrix. It is modified during the inversion.
639+
* @param {Matrix} AI The output inverse matrix. Can be the same as input matrix.
640+
* @param {Number} [size] The square size of the matrix to invert : 4 for a 4x4
612641
* @param {Number[]} [index]
613642
* @param {Number[]} [column]
643+
* @return AI on success, null otherwise
614644
*/
615-
export function invertMatrix(A: Matrix, AI: Matrix, size?: number, index?: number[], column?: number[]): number;
645+
export function invertMatrix(A: Matrix, AI: Matrix, size?: number, index?: number[], column?: number[]): Matrix|null;
616646

617647
/**
618648
*

Sources/Common/Core/Math/index.js

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import seedrandom from 'seedrandom';
22
import macro from 'vtk.js/Sources/macros';
3+
import {
4+
IDENTITY,
5+
IDENTITY_3X3,
6+
EPSILON,
7+
VTK_SMALL_NUMBER,
8+
} from 'vtk.js/Sources/Common/Core/Math/Constants';
39

410
const { vtkErrorMacro, vtkWarningMacro } = macro;
511

@@ -11,7 +17,6 @@ const { vtkErrorMacro, vtkWarningMacro } = macro;
1117
// ----------------------------------------------------------------------------
1218
let randomSeedValue = 0;
1319
const VTK_MAX_ROTATIONS = 20;
14-
const VTK_SMALL_NUMBER = 1.0e-12;
1520

1621
function notImplemented(method) {
1722
return () => vtkErrorMacro(`vtkMath::${method} - NOT IMPLEMENTED`);
@@ -43,7 +48,11 @@ function swapColumnsMatrix_nxn(matrix, n, column1, column2) {
4348

4449
export function createArray(size = 3) {
4550
// faster than Array.from and/or while loop
46-
return Array(size).fill(0);
51+
const res = Array(size);
52+
for (let i = 0; i < size; ++i) {
53+
res[i] = 0;
54+
}
55+
return res;
4756
}
4857

4958
export const Pi = () => Math.PI;
@@ -697,6 +706,25 @@ export function determinant3x3(mat_3x3) {
697706
);
698707
}
699708

709+
/**
710+
* Returns true if elements of both arrays are equals.
711+
* @param {Array} a an array of numbers (vector, point, matrix...)
712+
* @param {Array} b an array of numbers (vector, point, matrix...)
713+
* @param {Number} eps tolerance
714+
*/
715+
export function areEquals(a, b, eps = EPSILON) {
716+
if (a.length !== b.length) {
717+
return false;
718+
}
719+
720+
function isEqual(element, index) {
721+
return Math.abs(element - b[index]) <= eps;
722+
}
723+
return a.every(isEqual);
724+
}
725+
726+
export const areMatricesEqual = areEquals;
727+
700728
export function identity3x3(mat_3x3) {
701729
for (let i = 0; i < 3; i++) {
702730
/* eslint-disable-next-line no-multi-assign */
@@ -715,6 +743,14 @@ export function identity(n, mat) {
715743
return mat;
716744
}
717745

746+
export function isIdentity(mat, eps = EPSILON) {
747+
return areMatricesEqual(mat, IDENTITY, eps);
748+
}
749+
750+
export function isIdentity3x3(mat, eps = EPSILON) {
751+
return areMatricesEqual(mat, IDENTITY_3X3, eps);
752+
}
753+
718754
export function quaternionToMatrix3x3(quat_4, mat_3x3) {
719755
const ww = quat_4[0] * quat_4[0];
720756
const wx = quat_4[0] * quat_4[1];
@@ -748,25 +784,6 @@ export function quaternionToMatrix3x3(quat_4, mat_3x3) {
748784
mat_3x3[8] = zz * f + s;
749785
}
750786

751-
/**
752-
* Returns true if elements of both arrays are equals.
753-
* @param {Array} a an array of numbers (vector, point, matrix...)
754-
* @param {Array} b an array of numbers (vector, point, matrix...)
755-
* @param {Number} eps tolerance
756-
*/
757-
export function areEquals(a, b, eps = 1e-6) {
758-
if (a.length !== b.length) {
759-
return false;
760-
}
761-
762-
function isEqual(element, index) {
763-
return Math.abs(element - b[index]) <= eps;
764-
}
765-
return a.every(isEqual);
766-
}
767-
768-
export const areMatricesEqual = areEquals;
769-
770787
export function roundNumber(num, digits = 0) {
771788
if (!`${num}`.includes('e')) {
772789
return +`${Math.round(`${num}e+${digits}`)}e-${digits}`;
@@ -1425,6 +1442,7 @@ export function solveLinearSystem(A, x, size) {
14251442
return 1;
14261443
}
14271444

1445+
// Note that A is modified during the inversion !
14281446
export function invertMatrix(A, AI, size, index = null, column = null) {
14291447
const tmp1Size = index || createArray(size);
14301448
const tmp2Size = column || createArray(size);
@@ -1433,7 +1451,7 @@ export function invertMatrix(A, AI, size, index = null, column = null) {
14331451
// Note: tmp1Size returned value is used later, tmp2Size is just working
14341452
// memory whose values are not used in LUSolveLinearSystem
14351453
if (luFactorLinearSystem(A, tmp1Size, size, tmp2Size) === 0) {
1436-
return 0;
1454+
return null;
14371455
}
14381456

14391457
for (let j = 0; j < size; j++) {
@@ -1449,7 +1467,7 @@ export function invertMatrix(A, AI, size, index = null, column = null) {
14491467
}
14501468
}
14511469

1452-
return 1;
1470+
return AI;
14531471
}
14541472

14551473
export function estimateMatrixCondition(A, size) {
@@ -2210,6 +2228,8 @@ export default {
22102228
invert3x3,
22112229
identity3x3,
22122230
identity,
2231+
isIdentity,
2232+
isIdentity3x3,
22132233
determinant3x3,
22142234
quaternionToMatrix3x3,
22152235
areEquals,

Sources/Common/Core/MatrixBuilder/index.d.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { mat4 } from 'gl-matrix';
1+
import { mat3, mat4 } from 'gl-matrix';
22
import { TypedArray, Vector3 } from '../../../types';
33

44
declare interface Transform {
@@ -66,11 +66,22 @@ declare interface Transform {
6666
*/
6767
multiply(mat4x4: mat4): Transform
6868

69+
/**
70+
* Multiply the current matrix with the provided 3x3 matrix.
71+
* @param {mat3} mat3x3 column-first matrix
72+
*/
73+
multiply3x3(mat3x3: mat3): Transform
74+
6975
/**
7076
* Resets the MatrixBuilder to the Identity matrix.
71-
*/
77+
*/
7278
identity(): Transform
7379

80+
/**
81+
* Inverts the MatrixBuilder matrix.
82+
*/
83+
invert(): Transform
84+
7485
/**
7586
* Multiplies the array by the MatrixBuilder's internal matrix, in sets of
7687
* 3. Updates the array in place. If specified, `offset` starts at a given

Sources/Common/Core/MatrixBuilder/index.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import { vec3, mat4, glMatrix } from 'gl-matrix';
22

33
// eslint-disable-next-line import/no-cycle
44
import { areMatricesEqual } from 'vtk.js/Sources/Common/Core/Math';
5+
import { IDENTITY } from 'vtk.js/Sources/Common/Core/Math/Constants';
56

67
const NoOp = (v) => v;
78

8-
const IDENTITY = mat4.identity(new Float64Array(16));
9-
109
const EPSILON = 1e-6;
1110

1211
class Transform {
@@ -84,6 +83,33 @@ class Transform {
8483
return this;
8584
}
8685

86+
multiply3x3(mat3x3) {
87+
mat4.multiply(this.matrix, this.matrix, [
88+
mat3x3[0],
89+
mat3x3[1],
90+
mat3x3[2],
91+
0,
92+
mat3x3[3],
93+
mat3x3[4],
94+
mat3x3[5],
95+
0,
96+
mat3x3[6],
97+
mat3x3[7],
98+
mat3x3[8],
99+
0,
100+
0,
101+
0,
102+
0,
103+
1,
104+
]);
105+
return this;
106+
}
107+
108+
invert() {
109+
mat4.invert(this.matrix, this.matrix);
110+
return this;
111+
}
112+
87113
identity() {
88114
mat4.identity(this.matrix);
89115
return this;

0 commit comments

Comments
 (0)