@flighthq/geometry 0.1.0 → 0.2.1-next.410.a23f189
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aabb.d.ts +4 -4
- package/dist/aabb.d.ts.map +1 -1
- package/dist/aabb.js +11 -11
- package/dist/aabb.js.map +1 -1
- package/dist/boundingSphere.d.ts +5 -5
- package/dist/boundingSphere.d.ts.map +1 -1
- package/dist/boundingSphere.js +12 -12
- package/dist/boundingSphere.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/matrix.d.ts +5 -2
- package/dist/matrix.d.ts.map +1 -1
- package/dist/matrix.js +19 -15
- package/dist/matrix.js.map +1 -1
- package/dist/matrix3.d.ts +13 -7
- package/dist/matrix3.d.ts.map +1 -1
- package/dist/matrix3.js +158 -195
- package/dist/matrix3.js.map +1 -1
- package/dist/matrix4.d.ts.map +1 -1
- package/dist/matrix4.js +5 -3
- package/dist/matrix4.js.map +1 -1
- package/dist/quaternion.d.ts +1 -0
- package/dist/quaternion.d.ts.map +1 -1
- package/dist/quaternion.js +8 -0
- package/dist/quaternion.js.map +1 -1
- package/dist/transform2d.d.ts +4 -0
- package/dist/transform2d.d.ts.map +1 -0
- package/dist/transform2d.js +53 -0
- package/dist/transform2d.js.map +1 -0
- package/dist/transform3d.d.ts +5 -0
- package/dist/transform3d.d.ts.map +1 -0
- package/dist/transform3d.js +23 -0
- package/dist/transform3d.js.map +1 -0
- package/dist/vector3.d.ts +2 -2
- package/dist/vector3.js +5 -5
- package/package.json +8 -3
- package/src/aabb.test.ts +14 -14
- package/src/boundingSphere.test.ts +23 -23
- package/src/matrix.test.ts +28 -1
- package/src/matrix3.test.ts +150 -88
- package/src/matrix4.test.ts +23 -0
- package/src/quaternion.test.ts +9 -0
- package/src/transform2d.test.ts +84 -0
- package/src/transform3d.test.ts +50 -0
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
createBoundingSphere,
|
|
6
6
|
createMatrix4,
|
|
7
7
|
createVector3,
|
|
8
|
-
|
|
8
|
+
containsBoundingSpherePoint,
|
|
9
9
|
getClosestPointOnBoundingSphere,
|
|
10
10
|
isBoundingSphereIntersectingBoundingSphere,
|
|
11
11
|
mergeBoundingSphere,
|
|
@@ -28,6 +28,24 @@ describe('cloneBoundingSphere', () => {
|
|
|
28
28
|
});
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
describe('containsBoundingSpherePoint', () => {
|
|
32
|
+
it('returns true inside and on the surface', () => {
|
|
33
|
+
const s = createBoundingSphere(0, 0, 0, 2);
|
|
34
|
+
expect(containsBoundingSpherePoint(s, createVector3(1, 0, 0))).toBe(true);
|
|
35
|
+
expect(containsBoundingSpherePoint(s, createVector3(2, 0, 0))).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns false outside', () => {
|
|
39
|
+
const s = createBoundingSphere(0, 0, 0, 2);
|
|
40
|
+
expect(containsBoundingSpherePoint(s, createVector3(3, 0, 0))).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('an empty sphere contains no points', () => {
|
|
44
|
+
const s = createBoundingSphere(0, 0, 0, -1);
|
|
45
|
+
expect(containsBoundingSpherePoint(s, createVector3(0, 0, 0))).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
31
49
|
describe('copyBoundingSphere', () => {
|
|
32
50
|
it('copies center and radius', () => {
|
|
33
51
|
const src = createBoundingSphere(1, 2, 3, 4);
|
|
@@ -59,24 +77,6 @@ describe('createBoundingSphere', () => {
|
|
|
59
77
|
});
|
|
60
78
|
});
|
|
61
79
|
|
|
62
|
-
describe('getBoundingSphereContainsPoint', () => {
|
|
63
|
-
it('returns true inside and on the surface', () => {
|
|
64
|
-
const s = createBoundingSphere(0, 0, 0, 2);
|
|
65
|
-
expect(getBoundingSphereContainsPoint(s, createVector3(1, 0, 0))).toBe(true);
|
|
66
|
-
expect(getBoundingSphereContainsPoint(s, createVector3(2, 0, 0))).toBe(true);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('returns false outside', () => {
|
|
70
|
-
const s = createBoundingSphere(0, 0, 0, 2);
|
|
71
|
-
expect(getBoundingSphereContainsPoint(s, createVector3(3, 0, 0))).toBe(false);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('an empty sphere contains no points', () => {
|
|
75
|
-
const s = createBoundingSphere(0, 0, 0, -1);
|
|
76
|
-
expect(getBoundingSphereContainsPoint(s, createVector3(0, 0, 0))).toBe(false);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
80
|
describe('getClosestPointOnBoundingSphere', () => {
|
|
81
81
|
it('projects an outside point onto the surface', () => {
|
|
82
82
|
const s = createBoundingSphere(0, 0, 0, 2);
|
|
@@ -156,8 +156,8 @@ describe('mergeBoundingSphere', () => {
|
|
|
156
156
|
const out = createBoundingSphere();
|
|
157
157
|
mergeBoundingSphere(out, a, b);
|
|
158
158
|
// Both original spheres must be contained.
|
|
159
|
-
expect(
|
|
160
|
-
expect(
|
|
159
|
+
expect(containsBoundingSpherePoint(out, createVector3(-2, 0, 0))).toBe(true);
|
|
160
|
+
expect(containsBoundingSpherePoint(out, createVector3(2, 0, 0))).toBe(true);
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
it('if a contains b, result equals a', () => {
|
|
@@ -182,8 +182,8 @@ describe('mergeBoundingSphere', () => {
|
|
|
182
182
|
const a = createBoundingSphere(-1, 0, 0, 1);
|
|
183
183
|
const b = createBoundingSphere(1, 0, 0, 1);
|
|
184
184
|
mergeBoundingSphere(a, a, b);
|
|
185
|
-
expect(
|
|
186
|
-
expect(
|
|
185
|
+
expect(containsBoundingSpherePoint(a, createVector3(-2, 0, 0))).toBe(true);
|
|
186
|
+
expect(containsBoundingSpherePoint(a, createVector3(2, 0, 0))).toBe(true);
|
|
187
187
|
});
|
|
188
188
|
});
|
|
189
189
|
|
package/src/matrix.test.ts
CHANGED
|
@@ -331,6 +331,32 @@ describe('inverseMatrix', () => {
|
|
|
331
331
|
|
|
332
332
|
expect(equalsMatrix(matrix, expected)).toBe(true);
|
|
333
333
|
});
|
|
334
|
+
|
|
335
|
+
it('returns true on success', () => {
|
|
336
|
+
const m = createMatrix(2, 0, 0, 2, 5, 3);
|
|
337
|
+
const out = createMatrix();
|
|
338
|
+
expect(inverseMatrix(out, m)).toBe(true);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('returns false and writes a degenerate fill for a singular matrix', () => {
|
|
342
|
+
const m = createMatrix(0, 0, 0, 0, 5, 3); // det = a*d - c*b = 0
|
|
343
|
+
const out = createMatrix();
|
|
344
|
+
expect(inverseMatrix(out, m)).toBe(false);
|
|
345
|
+
expect(out.a).toBe(0);
|
|
346
|
+
expect(out.b).toBe(0);
|
|
347
|
+
expect(out.c).toBe(0);
|
|
348
|
+
expect(out.d).toBe(0);
|
|
349
|
+
expect(out.tx).toBe(-5);
|
|
350
|
+
expect(out.ty).toBe(-3);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('returns false for a singular matrix with out === source', () => {
|
|
354
|
+
const m = createMatrix(0, 0, 0, 0, 5, 3);
|
|
355
|
+
expect(inverseMatrix(m, m)).toBe(false);
|
|
356
|
+
expect(m.a).toBe(0);
|
|
357
|
+
expect(m.tx).toBe(-5);
|
|
358
|
+
expect(m.ty).toBe(-3);
|
|
359
|
+
});
|
|
334
360
|
});
|
|
335
361
|
|
|
336
362
|
describe('inverseMatrixTransformPoint', () => {
|
|
@@ -918,7 +944,8 @@ describe('setMatrixFromMatrix3', () => {
|
|
|
918
944
|
beforeEach(() => {
|
|
919
945
|
// Setup a basic Matrix3x3 instance for testing
|
|
920
946
|
mat3 = {
|
|
921
|
-
|
|
947
|
+
// Column-major storage of rows [1,2,3],[4,5,6],[7,8,9].
|
|
948
|
+
m: new Float32Array([1, 4, 7, 2, 5, 8, 3, 6, 9]),
|
|
922
949
|
};
|
|
923
950
|
mat2D = createMatrix(); // Create a createMatrix instance
|
|
924
951
|
});
|
package/src/matrix3.test.ts
CHANGED
|
@@ -30,6 +30,11 @@ import {
|
|
|
30
30
|
} from '@flighthq/geometry';
|
|
31
31
|
import type { Matrix3 } from '@flighthq/types';
|
|
32
32
|
|
|
33
|
+
// Matrix3 storage is column-major: element (row r, column c) lives at m[3 * c + r], matching
|
|
34
|
+
// Matrix4 and the GL/GLSL/WGSL uniform ABI. A matrix-like {m} built from a raw Float32Array below
|
|
35
|
+
// therefore lists its values column-by-column. getMatrix3Element(r, c) / column / row accessors are
|
|
36
|
+
// layout-agnostic, so those assertions double as storage-independent behavior locks.
|
|
37
|
+
|
|
33
38
|
describe('cloneMatrix3', () => {
|
|
34
39
|
it('should clone the matrix correctly', () => {
|
|
35
40
|
const m1 = createMatrix3(2, 3, 4, 5, 6, 7, 8, 9, 10);
|
|
@@ -46,7 +51,8 @@ describe('cloneMatrix3', () => {
|
|
|
46
51
|
});
|
|
47
52
|
|
|
48
53
|
it('should also clone matrix-like objects', () => {
|
|
49
|
-
|
|
54
|
+
// Column-major storage of rows [2,3,4],[5,6,7],[8,9,10].
|
|
55
|
+
const obj = { m: new Float32Array([2, 5, 8, 3, 6, 9, 4, 7, 10]) };
|
|
50
56
|
const m2 = cloneMatrix3(obj);
|
|
51
57
|
expect(getMatrix3Element(m2, 0, 0)).toBe(2);
|
|
52
58
|
expect(getMatrix3Element(m2, 0, 1)).toBe(3);
|
|
@@ -60,7 +66,7 @@ describe('cloneMatrix3', () => {
|
|
|
60
66
|
});
|
|
61
67
|
|
|
62
68
|
it('should return a matrix instance', () => {
|
|
63
|
-
const obj = { m: new Float32Array([2,
|
|
69
|
+
const obj = { m: new Float32Array([2, 5, 8, 3, 6, 9, 4, 7, 10]) };
|
|
64
70
|
const m2: Matrix3 = cloneMatrix3(obj);
|
|
65
71
|
expect(m2).not.toBeNull();
|
|
66
72
|
});
|
|
@@ -153,7 +159,8 @@ describe('copyMatrix3ColumnToVector3', () => {
|
|
|
153
159
|
});
|
|
154
160
|
|
|
155
161
|
it('should allow matrix-like and vector-like objects', () => {
|
|
156
|
-
|
|
162
|
+
// Column-major storage of rows [1,2,3],[4,5,6],[7,8,9]; column 0 = (1,4,7).
|
|
163
|
+
const m = { m: new Float32Array([1, 4, 7, 2, 5, 8, 3, 6, 9]) };
|
|
157
164
|
const v = { x: 0, y: 0, z: 0 };
|
|
158
165
|
copyMatrix3ColumnToVector3(v, 0, m); // column 0
|
|
159
166
|
expect(v.x).toBe(1);
|
|
@@ -190,10 +197,10 @@ describe('copyMatrix3RowFromVector3', () => {
|
|
|
190
197
|
it('should allow matrix-like and vector-like objects', () => {
|
|
191
198
|
const m = { m: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]) };
|
|
192
199
|
const v = { x: 1, y: 2, z: 3 };
|
|
193
|
-
copyMatrix3RowFromVector3(m, 0, v); // row 0
|
|
200
|
+
copyMatrix3RowFromVector3(m, 0, v); // row 0 -> column-major indices 0, 3, 6
|
|
194
201
|
expect(m.m[0]).toBe(1);
|
|
195
|
-
expect(m.m[
|
|
196
|
-
expect(m.m[
|
|
202
|
+
expect(m.m[3]).toBe(2);
|
|
203
|
+
expect(m.m[6]).toBe(3);
|
|
197
204
|
});
|
|
198
205
|
});
|
|
199
206
|
|
|
@@ -226,7 +233,8 @@ describe('copyMatrix3RowToVector3', () => {
|
|
|
226
233
|
});
|
|
227
234
|
|
|
228
235
|
it('should allow matrix-like and vector-like objects', () => {
|
|
229
|
-
|
|
236
|
+
// Column-major storage of rows [1,2,3],[4,5,6],[7,8,9]; row 0 = (1,2,3).
|
|
237
|
+
const m = { m: new Float32Array([1, 4, 7, 2, 5, 8, 3, 6, 9]) };
|
|
230
238
|
const v = { x: 0, y: 0, z: 0 };
|
|
231
239
|
copyMatrix3RowToVector3(v, 0, m); // row 0
|
|
232
240
|
expect(v.x).toBe(1); // m.a
|
|
@@ -249,6 +257,11 @@ describe('createMatrix3', () => {
|
|
|
249
257
|
expect(getMatrix3Element(m, 2, 2)).toBe(10);
|
|
250
258
|
});
|
|
251
259
|
|
|
260
|
+
it('stores its (row, column) arguments column-major', () => {
|
|
261
|
+
const m = createMatrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
|
262
|
+
expect(Array.from(m.m)).toEqual([1, 4, 7, 2, 5, 8, 3, 6, 9]);
|
|
263
|
+
});
|
|
264
|
+
|
|
252
265
|
it('should default to identity matrix when no values are provided', () => {
|
|
253
266
|
const m = createMatrix3();
|
|
254
267
|
expect(getMatrix3Element(m, 0, 0)).toBe(1);
|
|
@@ -295,7 +308,8 @@ describe('equalsMatrix3', () => {
|
|
|
295
308
|
|
|
296
309
|
it('should return true if one object is matrix-like and one is not', () => {
|
|
297
310
|
const mat1 = createMatrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
|
298
|
-
|
|
311
|
+
// Column-major storage of the same matrix.
|
|
312
|
+
const mat2 = { m: new Float32Array([1, 4, 7, 2, 5, 8, 3, 6, 9]) };
|
|
299
313
|
expect(equalsMatrix3(mat1, mat2)).toBe(true);
|
|
300
314
|
});
|
|
301
315
|
|
|
@@ -335,24 +349,19 @@ describe('getMatrix3Element', () => {
|
|
|
335
349
|
|
|
336
350
|
describe('inverseMatrix3', () => {
|
|
337
351
|
it('should invert the matrix correctly', () => {
|
|
338
|
-
//
|
|
352
|
+
// A scale of 2 with translation of (5, 3): rows [2,0,5],[0,2,3],[0,0,1].
|
|
339
353
|
const m = createMatrix3(2, 0, 5, 0, 2, 3, 0, 0, 1);
|
|
340
354
|
|
|
341
|
-
|
|
342
|
-
let out = createMatrix3();
|
|
355
|
+
const out = createMatrix3();
|
|
343
356
|
inverseMatrix3(out, m);
|
|
344
357
|
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
//
|
|
350
|
-
expect(out.m[
|
|
351
|
-
expect(out.m[
|
|
352
|
-
expect(out.m[3]).toBeCloseTo(0); // No shear on y
|
|
353
|
-
expect(out.m[4]).toBeCloseTo(0.5); // Inverse scaling on y
|
|
354
|
-
expect(out.m[2]).toBeCloseTo(-2.5); // Inverse translation on x
|
|
355
|
-
expect(out.m[5]).toBeCloseTo(-1.5); // Inverse translation on y
|
|
358
|
+
// Inverse: scale 0.5, translation (-2.5, -1.5). Column-major storage.
|
|
359
|
+
expect(out.m[0]).toBeCloseTo(0.5); // (0,0) inverse scale x
|
|
360
|
+
expect(out.m[1]).toBeCloseTo(0); // (1,0) no shear
|
|
361
|
+
expect(out.m[3]).toBeCloseTo(0); // (0,1) no shear
|
|
362
|
+
expect(out.m[4]).toBeCloseTo(0.5); // (1,1) inverse scale y
|
|
363
|
+
expect(out.m[6]).toBeCloseTo(-2.5); // (0,2) inverse translation x
|
|
364
|
+
expect(out.m[7]).toBeCloseTo(-1.5); // (1,2) inverse translation y
|
|
356
365
|
});
|
|
357
366
|
|
|
358
367
|
it('should not depend on initial out matrix values', () => {
|
|
@@ -364,22 +373,23 @@ describe('inverseMatrix3', () => {
|
|
|
364
373
|
const result = createMatrix3();
|
|
365
374
|
multiplyMatrix3(result, source, out);
|
|
366
375
|
|
|
367
|
-
expect(result
|
|
368
|
-
expect(result
|
|
369
|
-
expect(result
|
|
370
|
-
expect(result
|
|
376
|
+
expect(getMatrix3Element(result, 0, 0)).toBeCloseTo(1);
|
|
377
|
+
expect(getMatrix3Element(result, 0, 1)).toBeCloseTo(0);
|
|
378
|
+
expect(getMatrix3Element(result, 1, 0)).toBeCloseTo(0);
|
|
379
|
+
expect(getMatrix3Element(result, 1, 1)).toBeCloseTo(1);
|
|
371
380
|
});
|
|
372
381
|
|
|
373
382
|
it('should should allow matrix-like objects', () => {
|
|
374
|
-
|
|
375
|
-
|
|
383
|
+
// Column-major storage of the affine scale-2 translate-(5,3).
|
|
384
|
+
const m = { m: new Float32Array([2, 0, 0, 0, 2, 0, 5, 3, 1]) };
|
|
385
|
+
const out = { m: new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0]) };
|
|
376
386
|
inverseMatrix3(out, m);
|
|
377
|
-
expect(out.m[0]).toBeCloseTo(0.5); //
|
|
378
|
-
expect(out.m[1]).toBeCloseTo(0); //
|
|
379
|
-
expect(out.m[3]).toBeCloseTo(0); //
|
|
380
|
-
expect(out.m[4]).toBeCloseTo(0.5); //
|
|
381
|
-
expect(out.m[
|
|
382
|
-
expect(out.m[
|
|
387
|
+
expect(out.m[0]).toBeCloseTo(0.5); // (0,0) inverse scale x
|
|
388
|
+
expect(out.m[1]).toBeCloseTo(0); // (1,0) no shear
|
|
389
|
+
expect(out.m[3]).toBeCloseTo(0); // (0,1) no shear
|
|
390
|
+
expect(out.m[4]).toBeCloseTo(0.5); // (1,1) inverse scale y
|
|
391
|
+
expect(out.m[6]).toBeCloseTo(-2.5); // (0,2) inverse translation x
|
|
392
|
+
expect(out.m[7]).toBeCloseTo(-1.5); // (1,2) inverse translation y
|
|
383
393
|
});
|
|
384
394
|
|
|
385
395
|
it('supports out === source for affine matrices', () => {
|
|
@@ -401,6 +411,33 @@ describe('inverseMatrix3', () => {
|
|
|
401
411
|
|
|
402
412
|
expect(equalsMatrix3(matrix, expected)).toBe(true);
|
|
403
413
|
});
|
|
414
|
+
|
|
415
|
+
it('returns true on success', () => {
|
|
416
|
+
const m = createMatrix3(2, 0, 5, 0, 2, 3, 0, 0, 1);
|
|
417
|
+
const out = createMatrix3();
|
|
418
|
+
expect(inverseMatrix3(out, m)).toBe(true);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('returns false and fills NaN for a singular affine matrix', () => {
|
|
422
|
+
const m = createMatrix3(0, 0, 5, 0, 0, 3, 0, 0, 1); // zero linear part -> det 0
|
|
423
|
+
const out = createMatrix3();
|
|
424
|
+
expect(inverseMatrix3(out, m)).toBe(false);
|
|
425
|
+
expect(out.m[0]).toBeNaN();
|
|
426
|
+
expect(out.m[4]).toBeNaN();
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('returns false and fills NaN for a singular non-affine matrix', () => {
|
|
430
|
+
const m = createMatrix3(1, 2, 3, 2, 4, 6, 1, 1, 1); // rows 0,1 linearly dependent -> det 0
|
|
431
|
+
const out = createMatrix3();
|
|
432
|
+
expect(inverseMatrix3(out, m)).toBe(false);
|
|
433
|
+
expect(out.m[0]).toBeNaN();
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('returns false for a singular matrix with out === source', () => {
|
|
437
|
+
const m = createMatrix3(0, 0, 5, 0, 0, 3, 0, 0, 1);
|
|
438
|
+
expect(inverseMatrix3(m, m)).toBe(false);
|
|
439
|
+
expect(m.m[0]).toBeNaN();
|
|
440
|
+
});
|
|
404
441
|
});
|
|
405
442
|
|
|
406
443
|
describe('isAffineMatrix3', () => {
|
|
@@ -449,12 +486,22 @@ describe('multiplyMatrix3', () => {
|
|
|
449
486
|
expect(equalsMatrix3(out, b)).toBe(true);
|
|
450
487
|
});
|
|
451
488
|
|
|
489
|
+
it('composes an affine scale then translate (row/column semantics)', () => {
|
|
490
|
+
// a = scale(2,2), b = translate(5,5). a * b applies b then a to a column vector.
|
|
491
|
+
const a = createMatrix3(2, 0, 0, 0, 2, 0, 0, 0, 1);
|
|
492
|
+
const b = createMatrix3(1, 0, 5, 0, 1, 5, 0, 0, 1);
|
|
493
|
+
multiplyMatrix3(a, a, b);
|
|
494
|
+
expect(getMatrix3Element(a, 0, 2)).toBe(10);
|
|
495
|
+
expect(getMatrix3Element(a, 1, 2)).toBe(10);
|
|
496
|
+
});
|
|
497
|
+
|
|
452
498
|
it('should allow matrix-like objects', () => {
|
|
499
|
+
// Column-major: a = diag(2,2,1), b = translate(5,5).
|
|
453
500
|
const a = { m: new Float32Array([2, 0, 0, 0, 2, 0, 0, 0, 1]) };
|
|
454
|
-
const b = { m: new Float32Array([1, 0,
|
|
501
|
+
const b = { m: new Float32Array([1, 0, 0, 0, 1, 0, 5, 5, 1]) };
|
|
455
502
|
multiplyMatrix3(a, a, b);
|
|
456
|
-
expect(a.m[
|
|
457
|
-
expect(a.m[
|
|
503
|
+
expect(a.m[6]).toBe(10); // (0,2)
|
|
504
|
+
expect(a.m[7]).toBe(10); // (1,2)
|
|
458
505
|
});
|
|
459
506
|
});
|
|
460
507
|
|
|
@@ -463,24 +510,24 @@ describe('rotateMatrix3', () => {
|
|
|
463
510
|
const m = createMatrix3(1, 0, 0, 0, 1, 0, 0, 0, 1);
|
|
464
511
|
const out = createMatrix3();
|
|
465
512
|
rotateMatrix3(out, m, Math.PI / 2); // 90 degrees
|
|
466
|
-
|
|
467
|
-
expect(out
|
|
468
|
-
expect(out
|
|
469
|
-
expect(out
|
|
513
|
+
// Rotation (0,1)-plane: (0,0)=0, (0,1)=-1, (1,0)=1, (1,1)=0.
|
|
514
|
+
expect(getMatrix3Element(out, 0, 0)).toBeCloseTo(0);
|
|
515
|
+
expect(getMatrix3Element(out, 0, 1)).toBeCloseTo(-1);
|
|
516
|
+
expect(getMatrix3Element(out, 1, 0)).toBeCloseTo(1);
|
|
517
|
+
expect(getMatrix3Element(out, 1, 1)).toBeCloseTo(0);
|
|
470
518
|
});
|
|
471
519
|
|
|
472
520
|
it('should allow a matrix-like object', () => {
|
|
473
521
|
const m = { m: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]) };
|
|
474
522
|
const out = { m: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]) };
|
|
475
523
|
|
|
476
|
-
// Apply 90 degrees rotation (π/2 radians)
|
|
477
524
|
rotateMatrix3(out, m, Math.PI / 2);
|
|
478
525
|
|
|
479
|
-
//
|
|
480
|
-
expect(out.m[0]).toBeCloseTo(0); //
|
|
481
|
-
expect(out.m[1]).toBeCloseTo(
|
|
482
|
-
expect(out.m[3]).toBeCloseTo(1); //
|
|
483
|
-
expect(out.m[4]).toBeCloseTo(0); //
|
|
526
|
+
// 90-degree rotation, column-major storage: (0,0)=0,(0,1)=-1,(1,0)=1,(1,1)=0.
|
|
527
|
+
expect(out.m[0]).toBeCloseTo(0); // (0,0)
|
|
528
|
+
expect(out.m[1]).toBeCloseTo(1); // (1,0)
|
|
529
|
+
expect(out.m[3]).toBeCloseTo(-1); // (0,1)
|
|
530
|
+
expect(out.m[4]).toBeCloseTo(0); // (1,1)
|
|
484
531
|
});
|
|
485
532
|
|
|
486
533
|
it('supports out === source', () => {
|
|
@@ -498,21 +545,21 @@ describe('scaleMatrix3', () => {
|
|
|
498
545
|
const m = createMatrix3();
|
|
499
546
|
const out = createMatrix3();
|
|
500
547
|
scaleMatrix3(out, m, 2, 3);
|
|
501
|
-
expect(out
|
|
502
|
-
expect(out
|
|
548
|
+
expect(getMatrix3Element(out, 0, 0)).toBe(2);
|
|
549
|
+
expect(getMatrix3Element(out, 1, 1)).toBe(3);
|
|
503
550
|
});
|
|
504
551
|
|
|
505
552
|
it('should allow a matrix-like object', () => {
|
|
506
553
|
const m = { m: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]) };
|
|
507
554
|
const out = createMatrix3();
|
|
508
555
|
scaleMatrix3(out, m, 2, 3);
|
|
509
|
-
expect(out.m[0]).toBe(2); //
|
|
510
|
-
expect(out.m[4]).toBe(3); //
|
|
556
|
+
expect(out.m[0]).toBe(2); // (0,0)
|
|
557
|
+
expect(out.m[4]).toBe(3); // (1,1)
|
|
511
558
|
});
|
|
512
559
|
});
|
|
513
560
|
|
|
514
561
|
describe('setMatrix3', () => {
|
|
515
|
-
it('sets all 9 elements
|
|
562
|
+
it('sets all 9 elements by (row, column)', () => {
|
|
516
563
|
const m = createMatrix3();
|
|
517
564
|
setMatrix3(m, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
|
518
565
|
for (let row = 0; row < 3; row++) {
|
|
@@ -521,6 +568,12 @@ describe('setMatrix3', () => {
|
|
|
521
568
|
}
|
|
522
569
|
}
|
|
523
570
|
});
|
|
571
|
+
|
|
572
|
+
it('stores its arguments column-major', () => {
|
|
573
|
+
const m = createMatrix3();
|
|
574
|
+
setMatrix3(m, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
|
575
|
+
expect(Array.from(m.m)).toEqual([1, 4, 7, 2, 5, 8, 3, 6, 9]);
|
|
576
|
+
});
|
|
524
577
|
});
|
|
525
578
|
|
|
526
579
|
describe('setMatrix3Element', () => {
|
|
@@ -556,36 +609,22 @@ describe('setMatrix3FromFloat32Array', () => {
|
|
|
556
609
|
|
|
557
610
|
describe('setMatrix3FromMatrix', () => {
|
|
558
611
|
it('should convert a Matrix3x2 to a Matrix3', () => {
|
|
559
|
-
// Define a matrix (6 values, row-major)
|
|
560
612
|
const mat2D = createMatrix();
|
|
561
|
-
|
|
562
|
-
// Define an empty Matrix3 to store the result
|
|
563
613
|
const mat = createMatrix3();
|
|
564
|
-
|
|
565
|
-
// Call the fromMatrix3x2 function
|
|
566
614
|
setMatrix3FromMatrix(mat, mat2D);
|
|
567
615
|
|
|
568
|
-
//
|
|
616
|
+
// Identity, column-major.
|
|
569
617
|
const expectedMatrix3 = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
|
|
570
|
-
|
|
571
|
-
// Assert that the result matches the expected outcome
|
|
572
618
|
expect(mat.m).toEqual(expectedMatrix3);
|
|
573
619
|
});
|
|
574
620
|
|
|
575
621
|
it('should handle scaling and translation', () => {
|
|
576
|
-
// Define a matrix with scaling and translation
|
|
577
622
|
const mat2D = createMatrix(2, 0, 0, 3, 5, 10); // Scaling by 2,3 and translation by (5,10)
|
|
578
|
-
|
|
579
|
-
// Define an empty Matrix3 to store the result
|
|
580
623
|
const mat = createMatrix3();
|
|
581
|
-
|
|
582
|
-
// Call the fromMatrix3x2 function
|
|
583
624
|
setMatrix3FromMatrix(mat, mat2D);
|
|
584
625
|
|
|
585
|
-
//
|
|
586
|
-
const expectedMatrix3 = new Float32Array([2, 0,
|
|
587
|
-
|
|
588
|
-
// Assert that the result matches the expected outcome
|
|
626
|
+
// Column-major storage of the affine scale-(2,3) translate-(5,10).
|
|
627
|
+
const expectedMatrix3 = new Float32Array([2, 0, 0, 0, 3, 0, 5, 10, 1]);
|
|
589
628
|
expect(mat.m).toEqual(expectedMatrix3);
|
|
590
629
|
});
|
|
591
630
|
});
|
|
@@ -616,9 +655,7 @@ describe('setMatrix3FromMatrix4', () => {
|
|
|
616
655
|
const mat = createMatrix3();
|
|
617
656
|
setMatrix3FromMatrix4(mat, Matrix4x4);
|
|
618
657
|
|
|
619
|
-
// Expected result: Identity matrix for Matrix3
|
|
620
658
|
const expectedMatrix3 = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
|
|
621
|
-
|
|
622
659
|
expect(mat.m).toEqual(expectedMatrix3);
|
|
623
660
|
});
|
|
624
661
|
|
|
@@ -647,11 +684,20 @@ describe('setMatrix3FromMatrix4', () => {
|
|
|
647
684
|
const mat = createMatrix3();
|
|
648
685
|
setMatrix3FromMatrix4(mat, Matrix4x4);
|
|
649
686
|
|
|
650
|
-
// Expected result: Upper-left 3x3 part of Matrix4x4
|
|
651
687
|
const expectedMatrix3 = new Float32Array([2, 0, 0, 0, 3, 0, 0, 0, 4]);
|
|
652
|
-
|
|
653
688
|
expect(mat.m).toEqual(expectedMatrix3);
|
|
654
689
|
});
|
|
690
|
+
|
|
691
|
+
it('copies the upper-left 3x3 column-major (no transpose)', () => {
|
|
692
|
+
// Matrix4 columns [1,2,3,0],[4,5,6,0],[7,8,9,0],[0,0,0,1]; upper-left 3x3 is column-major
|
|
693
|
+
// [1,2,3, 4,5,6, 7,8,9] and copies straight through.
|
|
694
|
+
const m4 = { m: new Float32Array([1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 0, 0, 0, 0, 1]) };
|
|
695
|
+
const mat = createMatrix3();
|
|
696
|
+
setMatrix3FromMatrix4(mat, m4);
|
|
697
|
+
expect(Array.from(mat.m)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
698
|
+
expect(getMatrix3Element(mat, 0, 1)).toBe(4);
|
|
699
|
+
expect(getMatrix3Element(mat, 1, 0)).toBe(2);
|
|
700
|
+
});
|
|
655
701
|
});
|
|
656
702
|
|
|
657
703
|
describe('setMatrix3Identity', () => {
|
|
@@ -672,13 +718,24 @@ describe('setMatrix3NormalFromMatrix4', () => {
|
|
|
672
718
|
const m4 = createMatrix4(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
|
673
719
|
const out = createMatrix3();
|
|
674
720
|
setMatrix3NormalFromMatrix4(out, m4);
|
|
675
|
-
// For a pure rotation, normal matrix == rotation
|
|
676
|
-
|
|
721
|
+
// For a pure rotation, normal matrix == rotation R (+x -> +y): (0,0)=0,(0,1)=-1,(1,0)=1,(1,1)=0.
|
|
722
|
+
expect(getMatrix3Element(out, 0, 0)).toBeCloseTo(0, 5);
|
|
723
|
+
expect(getMatrix3Element(out, 0, 1)).toBeCloseTo(-1, 5);
|
|
724
|
+
expect(getMatrix3Element(out, 1, 0)).toBeCloseTo(1, 5);
|
|
725
|
+
expect(getMatrix3Element(out, 1, 1)).toBeCloseTo(0, 5);
|
|
726
|
+
expect(getMatrix3Element(out, 2, 2)).toBeCloseTo(1, 5);
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
it('uploads column-major so a GL upload needs no transpose', () => {
|
|
730
|
+
// The whole point of the migration: the normal matrix' storage matches uniformMatrix3fv(false).
|
|
731
|
+
// 90-degree rotation about z, column-major storage: R = [[0,-1,0],[1,0,0],[0,0,1]] -> [0,1,0,-1,0,0,0,0,1].
|
|
732
|
+
const m4 = createMatrix4(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
|
733
|
+
const out = createMatrix3();
|
|
734
|
+
setMatrix3NormalFromMatrix4(out, m4);
|
|
677
735
|
expect(out.m[0]).toBeCloseTo(0, 5);
|
|
678
|
-
expect(out.m[1]).toBeCloseTo(
|
|
679
|
-
expect(out.m[3]).toBeCloseTo(1, 5);
|
|
736
|
+
expect(out.m[1]).toBeCloseTo(1, 5);
|
|
737
|
+
expect(out.m[3]).toBeCloseTo(-1, 5);
|
|
680
738
|
expect(out.m[4]).toBeCloseTo(0, 5);
|
|
681
|
-
expect(out.m[8]).toBeCloseTo(1, 5);
|
|
682
739
|
});
|
|
683
740
|
|
|
684
741
|
it('keeps a normal perpendicular under non-uniform scale', () => {
|
|
@@ -687,9 +744,9 @@ describe('setMatrix3NormalFromMatrix4', () => {
|
|
|
687
744
|
const normalMatrix = createMatrix3();
|
|
688
745
|
setMatrix3NormalFromMatrix4(normalMatrix, m4);
|
|
689
746
|
// Inverse-transpose of diag(2,1,1) = diag(0.5,1,1).
|
|
690
|
-
expect(normalMatrix
|
|
691
|
-
expect(normalMatrix
|
|
692
|
-
expect(normalMatrix
|
|
747
|
+
expect(getMatrix3Element(normalMatrix, 0, 0)).toBeCloseTo(0.5, 5);
|
|
748
|
+
expect(getMatrix3Element(normalMatrix, 1, 1)).toBeCloseTo(1, 5);
|
|
749
|
+
expect(getMatrix3Element(normalMatrix, 2, 2)).toBeCloseTo(1, 5);
|
|
693
750
|
});
|
|
694
751
|
});
|
|
695
752
|
|
|
@@ -698,16 +755,16 @@ describe('translateMatrix3', () => {
|
|
|
698
755
|
const m = createMatrix3();
|
|
699
756
|
const out = createMatrix3();
|
|
700
757
|
translateMatrix3(out, m, 2, 3);
|
|
701
|
-
expect(out
|
|
702
|
-
expect(out
|
|
758
|
+
expect(getMatrix3Element(out, 0, 2)).toBe(2);
|
|
759
|
+
expect(getMatrix3Element(out, 1, 2)).toBe(3);
|
|
703
760
|
});
|
|
704
761
|
|
|
705
762
|
it('should allow a matrix-like object', () => {
|
|
706
763
|
const m = { m: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]) };
|
|
707
764
|
const out = createMatrix3();
|
|
708
765
|
translateMatrix3(out, m, 2, 3);
|
|
709
|
-
expect(out.m[
|
|
710
|
-
expect(out.m[
|
|
766
|
+
expect(out.m[6]).toBe(2); // (0,2) tx
|
|
767
|
+
expect(out.m[7]).toBe(3); // (1,2) ty
|
|
711
768
|
});
|
|
712
769
|
});
|
|
713
770
|
|
|
@@ -716,13 +773,17 @@ describe('transposeMatrix3', () => {
|
|
|
716
773
|
const m = createMatrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
|
717
774
|
const out = createMatrix3();
|
|
718
775
|
transposeMatrix3(out, m);
|
|
719
|
-
|
|
776
|
+
// Transpose of rows [1,2,3],[4,5,6],[7,8,9] is rows [1,4,7],[2,5,8],[3,6,9];
|
|
777
|
+
// column-major storage of that is [1,2,3,4,5,6,7,8,9].
|
|
778
|
+
expect(Array.from(out.m)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
779
|
+
expect(getMatrix3Element(out, 0, 1)).toBe(4);
|
|
780
|
+
expect(getMatrix3Element(out, 1, 0)).toBe(2);
|
|
720
781
|
});
|
|
721
782
|
|
|
722
783
|
it('supports out === source', () => {
|
|
723
784
|
const m = createMatrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
|
724
785
|
transposeMatrix3(m, m);
|
|
725
|
-
expect(Array.from(m.m)).toEqual([1,
|
|
786
|
+
expect(Array.from(m.m)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
726
787
|
});
|
|
727
788
|
|
|
728
789
|
it('transpose of identity is identity', () => {
|
|
@@ -738,7 +799,8 @@ describe('writeMatrix3ToFloat32Array', () => {
|
|
|
738
799
|
const m = createMatrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
|
739
800
|
const data = new Float32Array(10);
|
|
740
801
|
writeMatrix3ToFloat32Array(data, 1, m);
|
|
741
|
-
|
|
802
|
+
// Column-major storage of the matrix, written verbatim.
|
|
803
|
+
expect(Array.from(data)).toEqual([0, 1, 4, 7, 2, 5, 8, 3, 6, 9]);
|
|
742
804
|
});
|
|
743
805
|
|
|
744
806
|
it('round-trips through setMatrix3FromFloat32Array', () => {
|
package/src/matrix4.test.ts
CHANGED
|
@@ -727,6 +727,16 @@ describe('inverseMatrix4', () => {
|
|
|
727
727
|
expect(inv.m[1]).toBeNaN();
|
|
728
728
|
expect(inv.m[2]).toBeNaN();
|
|
729
729
|
});
|
|
730
|
+
|
|
731
|
+
it('returns false for a singular matrix with out === source', () => {
|
|
732
|
+
const m = createMatrix4();
|
|
733
|
+
m.m[0] = 0; // make determinant zero
|
|
734
|
+
|
|
735
|
+
const ok = inverseMatrix4(m, m);
|
|
736
|
+
|
|
737
|
+
expect(ok).toBe(false);
|
|
738
|
+
expect(m.m[0]).toBeNaN();
|
|
739
|
+
});
|
|
730
740
|
});
|
|
731
741
|
|
|
732
742
|
describe('isAffineMatrix4', () => {
|
|
@@ -1593,6 +1603,19 @@ describe('transposeMatrix4', () => {
|
|
|
1593
1603
|
transposeMatrix4(matrix, matrix);
|
|
1594
1604
|
expect(equalsMatrix4(matrix, expected)).toBe(true);
|
|
1595
1605
|
});
|
|
1606
|
+
|
|
1607
|
+
it('supports out === source with non-symmetric values', () => {
|
|
1608
|
+
// A deliberately non-symmetric matrix where aliasing would corrupt results
|
|
1609
|
+
// if __swap read from out after a prior __swap already wrote to it.
|
|
1610
|
+
const m = createMatrix4();
|
|
1611
|
+
setMatrix4(m, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53);
|
|
1612
|
+
transposeMatrix4(m, m);
|
|
1613
|
+
// Column-major transposed: rows become columns.
|
|
1614
|
+
const expected = [2, 11, 23, 41, 3, 13, 29, 43, 5, 17, 31, 47, 7, 19, 37, 53];
|
|
1615
|
+
for (let i = 0; i < 16; i++) {
|
|
1616
|
+
expect(m.m[i]).toBe(expected[i]);
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1596
1619
|
});
|
|
1597
1620
|
|
|
1598
1621
|
describe('writeMatrix4ToFloat32Array', () => {
|
package/src/quaternion.test.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
normalizeQuaternion,
|
|
16
16
|
rotateVector3ByQuaternion,
|
|
17
17
|
setMatrix4FromQuaternion,
|
|
18
|
+
setQuaternion,
|
|
18
19
|
setQuaternionFromAxisAngle,
|
|
19
20
|
setQuaternionFromEuler,
|
|
20
21
|
setQuaternionFromMatrix4,
|
|
@@ -359,6 +360,14 @@ describe('setMatrix4FromQuaternion', () => {
|
|
|
359
360
|
});
|
|
360
361
|
});
|
|
361
362
|
|
|
363
|
+
describe('setQuaternion', () => {
|
|
364
|
+
it('sets the components directly', () => {
|
|
365
|
+
const out = createQuaternion();
|
|
366
|
+
setQuaternion(out, 0.1, 0.2, 0.3, 0.4);
|
|
367
|
+
expect(out).toMatchObject({ w: 0.4, x: 0.1, y: 0.2, z: 0.3 });
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
|
|
362
371
|
describe('setQuaternionFromAxisAngle', () => {
|
|
363
372
|
it('builds a half-angle quaternion', () => {
|
|
364
373
|
const q = createQuaternion();
|