@flighthq/geometry 0.5.1-next.903.f434bc2 → 0.5.1-next.905.5fbf787
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/README.md +2 -2
- package/package.json +5 -5
- package/src/aabb.test.ts +8 -1
- package/src/boundingSphere.test.ts +8 -1
- package/src/capsule.test.ts +21 -14
- package/src/frustum.test.ts +8 -1
- package/src/matrix.test.ts +8 -1
- package/src/matrix3.test.ts +8 -1
- package/src/matrix4.test.ts +13 -6
- package/src/obb.test.ts +92 -85
- package/src/plane.test.ts +8 -1
- package/src/quaternion.test.ts +8 -1
- package/src/ray3d.test.ts +19 -13
- package/src/rectangle.test.ts +8 -1
- package/src/transform2d.test.ts +6 -1
- package/src/transform3d.test.ts +11 -1
- package/src/vector2.test.ts +8 -1
- package/src/vector3.test.ts +8 -1
- package/src/vector4.test.ts +10 -3
package/README.md
CHANGED
|
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/geometry`. The `@fli
|
|
|
13
13
|
This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
|
|
14
14
|
|
|
15
15
|
- [Flight project](https://github.com/flighthq/flight)
|
|
16
|
-
- [Source for @flighthq/geometry@0.5.1-next.
|
|
17
|
-
- [License](https://github.com/flighthq/flight/blob/
|
|
16
|
+
- [Source for @flighthq/geometry@0.5.1-next.905.5fbf787](https://github.com/flighthq/flight/tree/5fbf7874064c384307542d68b4dcb6a895ff0dcf/packages/geometry)
|
|
17
|
+
- [License](https://github.com/flighthq/flight/blob/5fbf7874064c384307542d68b4dcb6a895ff0dcf/LICENSE.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/geometry",
|
|
3
|
-
"version": "0.5.1-next.
|
|
3
|
+
"version": "0.5.1-next.905.5fbf787",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/entity": "0.5.1-next.
|
|
42
|
-
"@flighthq/log": "0.5.1-next.
|
|
43
|
-
"@flighthq/math": "0.5.1-next.
|
|
44
|
-
"@flighthq/types": "0.5.1-next.
|
|
41
|
+
"@flighthq/entity": "0.5.1-next.905.5fbf787",
|
|
42
|
+
"@flighthq/log": "0.5.1-next.905.5fbf787",
|
|
43
|
+
"@flighthq/math": "0.5.1-next.905.5fbf787",
|
|
44
|
+
"@flighthq/types": "0.5.1-next.905.5fbf787"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"typescript": "^5.3.0"
|
package/src/aabb.test.ts
CHANGED
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
unionAabb,
|
|
23
23
|
} from '@flighthq/geometry/contract';
|
|
24
24
|
|
|
25
|
+
import { initializeAabb } from './aabb';
|
|
26
|
+
|
|
25
27
|
describe('cloneAabb', () => {
|
|
26
28
|
it('creates an independent copy with independent corner vectors', () => {
|
|
27
29
|
const a = createAabb(-1, -2, -3, 4, 5, 6);
|
|
@@ -198,6 +200,12 @@ describe('getClosestPointOnAabb', () => {
|
|
|
198
200
|
});
|
|
199
201
|
});
|
|
200
202
|
|
|
203
|
+
describe('initializeAabb', () => {
|
|
204
|
+
it('is the construction initializer of createAabb', () => {
|
|
205
|
+
expect(typeof initializeAabb).toBe('function');
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
201
209
|
describe('intersectAabb', () => {
|
|
202
210
|
it('produces the overlapping sub-box for two overlapping boxes', () => {
|
|
203
211
|
const a = createAabb(0, 0, 0, 4, 4, 4);
|
|
@@ -361,7 +369,6 @@ describe('transformAabbByMatrix4', () => {
|
|
|
361
369
|
expect(a.max.z).toBeCloseTo(6, 6);
|
|
362
370
|
});
|
|
363
371
|
});
|
|
364
|
-
|
|
365
372
|
describe('unionAabb', () => {
|
|
366
373
|
it('encloses both boxes', () => {
|
|
367
374
|
const a = createAabb(0, 0, 0, 1, 1, 1);
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
transformBoundingSphereByMatrix4,
|
|
16
16
|
} from '@flighthq/geometry/contract';
|
|
17
17
|
|
|
18
|
+
import { initializeBoundingSphere } from './boundingSphere';
|
|
19
|
+
|
|
18
20
|
describe('cloneBoundingSphere', () => {
|
|
19
21
|
it('creates an independent copy with an independent center', () => {
|
|
20
22
|
const s = createBoundingSphere(1, 2, 3, 4);
|
|
@@ -122,6 +124,12 @@ describe('getClosestPointOnBoundingSphere', () => {
|
|
|
122
124
|
});
|
|
123
125
|
});
|
|
124
126
|
|
|
127
|
+
describe('initializeBoundingSphere', () => {
|
|
128
|
+
it('is the construction initializer of createBoundingSphere', () => {
|
|
129
|
+
expect(typeof initializeBoundingSphere).toBe('function');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
125
133
|
describe('isBoundingSphereIntersectingBoundingSphere', () => {
|
|
126
134
|
it('returns true for overlapping spheres', () => {
|
|
127
135
|
const a = createBoundingSphere(0, 0, 0, 2);
|
|
@@ -242,7 +250,6 @@ describe('setBoundingSphereFromAabb', () => {
|
|
|
242
250
|
expect(s.radius).toBe(-1);
|
|
243
251
|
});
|
|
244
252
|
});
|
|
245
|
-
|
|
246
253
|
describe('transformBoundingSphereByMatrix4', () => {
|
|
247
254
|
it('translates the center and preserves the radius', () => {
|
|
248
255
|
const s = createBoundingSphere(0, 0, 0, 2);
|
package/src/capsule.test.ts
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
setCapsule,
|
|
13
13
|
} from '@flighthq/geometry/contract';
|
|
14
14
|
|
|
15
|
+
import { initializeCapsule } from './capsule';
|
|
16
|
+
|
|
15
17
|
describe('createCapsule', () => {
|
|
16
18
|
it('stores all fields', () => {
|
|
17
19
|
const c = createCapsule(1, 2, 3, 4, 5, 6, 0.5);
|
|
@@ -109,6 +111,12 @@ describe('getClosestPointOnCapsule', () => {
|
|
|
109
111
|
});
|
|
110
112
|
});
|
|
111
113
|
|
|
114
|
+
describe('initializeCapsule', () => {
|
|
115
|
+
it('is the construction initializer of createCapsule', () => {
|
|
116
|
+
expect(typeof initializeCapsule).toBe('function');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
112
120
|
describe('intersectRay3DCapsule', () => {
|
|
113
121
|
it('hits a unit capsule from the side', () => {
|
|
114
122
|
// Capsule from (0,-1,0) to (0,1,0) with radius 1.
|
|
@@ -308,20 +316,6 @@ describe('isCapsuleIntersectingSphere', () => {
|
|
|
308
316
|
});
|
|
309
317
|
});
|
|
310
318
|
|
|
311
|
-
describe('setCapsule', () => {
|
|
312
|
-
it('updates all fields in place', () => {
|
|
313
|
-
const c = createCapsule(0, 0, 0, 0, 0, 0, 0);
|
|
314
|
-
setCapsule(c, 1, 2, 3, 4, 5, 6, 7);
|
|
315
|
-
expect(c.startX).toBe(1);
|
|
316
|
-
expect(c.startY).toBe(2);
|
|
317
|
-
expect(c.startZ).toBe(3);
|
|
318
|
-
expect(c.endX).toBe(4);
|
|
319
|
-
expect(c.endY).toBe(5);
|
|
320
|
-
expect(c.endZ).toBe(6);
|
|
321
|
-
expect(c.radius).toBe(7);
|
|
322
|
-
});
|
|
323
|
-
});
|
|
324
|
-
|
|
325
319
|
// The six coordinates of a capsule axis: start x, y, z then end x, y, z.
|
|
326
320
|
type SegmentArguments = [number, number, number, number, number, number];
|
|
327
321
|
|
|
@@ -347,3 +341,16 @@ function measureSegmentDistance(first: readonly number[], second: readonly numbe
|
|
|
347
341
|
}
|
|
348
342
|
return smallest;
|
|
349
343
|
}
|
|
344
|
+
describe('setCapsule', () => {
|
|
345
|
+
it('updates all fields in place', () => {
|
|
346
|
+
const c = createCapsule(0, 0, 0, 0, 0, 0, 0);
|
|
347
|
+
setCapsule(c, 1, 2, 3, 4, 5, 6, 7);
|
|
348
|
+
expect(c.startX).toBe(1);
|
|
349
|
+
expect(c.startY).toBe(2);
|
|
350
|
+
expect(c.startZ).toBe(3);
|
|
351
|
+
expect(c.endX).toBe(4);
|
|
352
|
+
expect(c.endY).toBe(5);
|
|
353
|
+
expect(c.endZ).toBe(6);
|
|
354
|
+
expect(c.radius).toBe(7);
|
|
355
|
+
});
|
|
356
|
+
});
|
package/src/frustum.test.ts
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
} from '@flighthq/geometry/contract';
|
|
19
19
|
import type { Matrix4 } from '@flighthq/types/contract';
|
|
20
20
|
|
|
21
|
+
import { initializeFrustum } from './frustum';
|
|
22
|
+
|
|
21
23
|
// View-projection for a camera at (0,0,5) looking toward the origin down -z.
|
|
22
24
|
function createTestViewProjection(): Matrix4 {
|
|
23
25
|
const projection = createPerspectiveMatrix4(0.5, 1, 0.1, 100);
|
|
@@ -96,6 +98,12 @@ describe('getFrustumCorners', () => {
|
|
|
96
98
|
});
|
|
97
99
|
});
|
|
98
100
|
|
|
101
|
+
describe('initializeFrustum', () => {
|
|
102
|
+
it('is the construction initializer of createFrustum', () => {
|
|
103
|
+
expect(typeof initializeFrustum).toBe('function');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
99
107
|
describe('isFrustumContainingPoint', () => {
|
|
100
108
|
it('contains a point in front of the camera', () => {
|
|
101
109
|
const f = createFrustum();
|
|
@@ -196,7 +204,6 @@ describe('isFrustumIntersectingSphere', () => {
|
|
|
196
204
|
expect(isFrustumIntersectingSphere(f, createBoundingSphere(0, 0, 5.5, 2))).toBe(true);
|
|
197
205
|
});
|
|
198
206
|
});
|
|
199
|
-
|
|
200
207
|
describe('setFrustumFromMatrix4', () => {
|
|
201
208
|
it('produces unit-length plane normals', () => {
|
|
202
209
|
const f = createFrustum();
|
package/src/matrix.test.ts
CHANGED
|
@@ -43,6 +43,8 @@ import {
|
|
|
43
43
|
} from '@flighthq/geometry/contract';
|
|
44
44
|
import type { Matrix, Matrix3Like, Matrix4Like } from '@flighthq/types/contract';
|
|
45
45
|
|
|
46
|
+
import { initializeMatrix } from './matrix';
|
|
47
|
+
|
|
46
48
|
describe('cloneMatrix', () => {
|
|
47
49
|
it('should clone the matrix3x2 correctly', () => {
|
|
48
50
|
const m1 = createMatrix(2, 3, 4, 5, 6, 7);
|
|
@@ -305,6 +307,12 @@ describe('equalsMatrix', () => {
|
|
|
305
307
|
});
|
|
306
308
|
});
|
|
307
309
|
|
|
310
|
+
describe('initializeMatrix', () => {
|
|
311
|
+
it('is the construction initializer of createMatrix', () => {
|
|
312
|
+
expect(typeof initializeMatrix).toBe('function');
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
308
316
|
describe('inverseMatrix', () => {
|
|
309
317
|
it('should invert the matrix3x2 correctly', () => {
|
|
310
318
|
// Create a matrix3x2 with scaling of 2 and translation of (5, 3)
|
|
@@ -1180,7 +1188,6 @@ describe('translateMatrixByVectorXY', () => {
|
|
|
1180
1188
|
expect(matrix).toMatchObject({ a: 2, b: 3, c: 4, d: 5, tx: 28, ty: 36 });
|
|
1181
1189
|
});
|
|
1182
1190
|
});
|
|
1183
|
-
|
|
1184
1191
|
describe('writeMatrixToFloat32Array', () => {
|
|
1185
1192
|
it('writes 6 values at the offset', () => {
|
|
1186
1193
|
const array = new Float32Array(6);
|
package/src/matrix3.test.ts
CHANGED
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
} from '@flighthq/geometry/contract';
|
|
31
31
|
import type { Matrix3 } from '@flighthq/types/contract';
|
|
32
32
|
|
|
33
|
+
import { initializeMatrix3 } from './matrix3';
|
|
34
|
+
|
|
33
35
|
// Matrix3 storage is column-major: element (row r, column c) lives at m[3 * c + r], matching
|
|
34
36
|
// Matrix4 and the GL/GLSL/WGSL uniform ABI. A matrix-like {m} built from a raw Float32Array below
|
|
35
37
|
// therefore lists its values column-by-column. getMatrix3Element(r, c) / column / row accessors are
|
|
@@ -363,6 +365,12 @@ describe('getMatrix3Element', () => {
|
|
|
363
365
|
});
|
|
364
366
|
});
|
|
365
367
|
|
|
368
|
+
describe('initializeMatrix3', () => {
|
|
369
|
+
it('is the construction initializer of createMatrix3', () => {
|
|
370
|
+
expect(typeof initializeMatrix3).toBe('function');
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
366
374
|
describe('inverseMatrix3', () => {
|
|
367
375
|
it('should invert the matrix correctly', () => {
|
|
368
376
|
// A scale of 2 with translation of (5, 3): rows [2,0,5],[0,2,3],[0,0,1].
|
|
@@ -833,7 +841,6 @@ describe('transposeMatrix3', () => {
|
|
|
833
841
|
expect(Array.from(out.m)).toEqual([1, 0, 0, 0, 1, 0, 0, 0, 1]);
|
|
834
842
|
});
|
|
835
843
|
});
|
|
836
|
-
|
|
837
844
|
describe('writeMatrix3ToFloat32Array', () => {
|
|
838
845
|
it('writes 9 values starting at the given offset', () => {
|
|
839
846
|
const m = createMatrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
package/src/matrix4.test.ts
CHANGED
|
@@ -58,6 +58,8 @@ import {
|
|
|
58
58
|
} from '@flighthq/geometry/contract';
|
|
59
59
|
import type { Matrix, Matrix4 } from '@flighthq/types/contract';
|
|
60
60
|
|
|
61
|
+
import { initializeMatrix4 } from './matrix4';
|
|
62
|
+
|
|
61
63
|
const X_AXIS = { x: 1, y: 0, z: 0, w: 0 };
|
|
62
64
|
const Y_AXIS = { x: 0, y: 1, z: 0, w: 0 };
|
|
63
65
|
const Z_AXIS = { x: 0, y: 0, z: 1, w: 0 };
|
|
@@ -837,6 +839,12 @@ describe('getMatrix4Position', () => {
|
|
|
837
839
|
});
|
|
838
840
|
});
|
|
839
841
|
|
|
842
|
+
describe('initializeMatrix4', () => {
|
|
843
|
+
it('is the construction initializer of createMatrix4', () => {
|
|
844
|
+
expect(typeof initializeMatrix4).toBe('function');
|
|
845
|
+
});
|
|
846
|
+
});
|
|
847
|
+
|
|
840
848
|
describe('interpolateMatrix4', () => {
|
|
841
849
|
it('returns a at t=0', () => {
|
|
842
850
|
const a = createMatrix4();
|
|
@@ -2044,6 +2052,11 @@ describe('transposeMatrix4', () => {
|
|
|
2044
2052
|
});
|
|
2045
2053
|
});
|
|
2046
2054
|
|
|
2055
|
+
function expectMatrix4Close(actual: Matrix4, expected: Matrix4): void {
|
|
2056
|
+
for (let i = 0; i < 16; i++) {
|
|
2057
|
+
expect(actual.m[i]).toBeCloseTo(expected.m[i]);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2047
2060
|
describe('writeMatrix4ToFloat32Array', () => {
|
|
2048
2061
|
it('writes 16 elements at offset 0', () => {
|
|
2049
2062
|
const m = createMatrix4();
|
|
@@ -2068,9 +2081,3 @@ describe('writeMatrix4ToFloat32Array', () => {
|
|
|
2068
2081
|
expect(arr[3]).toBe(0);
|
|
2069
2082
|
});
|
|
2070
2083
|
});
|
|
2071
|
-
|
|
2072
|
-
function expectMatrix4Close(actual: Matrix4, expected: Matrix4): void {
|
|
2073
|
-
for (let i = 0; i < 16; i++) {
|
|
2074
|
-
expect(actual.m[i]).toBeCloseTo(expected.m[i]);
|
|
2075
|
-
}
|
|
2076
|
-
}
|
package/src/obb.test.ts
CHANGED
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
} from '@flighthq/geometry/contract';
|
|
21
21
|
import type { Matrix4, Obb, Vector3 } from '@flighthq/types/contract';
|
|
22
22
|
|
|
23
|
+
import { initializeObb } from './obb';
|
|
24
|
+
|
|
23
25
|
describe('createObb', () => {
|
|
24
26
|
it('stores center, half-extents, and orientation', () => {
|
|
25
27
|
const o = createObb(1, 2, 3, 4, 5, 6, 0, 0, 0, 1);
|
|
@@ -72,6 +74,12 @@ describe('getClosestPointOnObb', () => {
|
|
|
72
74
|
});
|
|
73
75
|
});
|
|
74
76
|
|
|
77
|
+
describe('initializeObb', () => {
|
|
78
|
+
it('is the construction initializer of createObb', () => {
|
|
79
|
+
expect(typeof initializeObb).toBe('function');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
75
83
|
describe('intersectRay3DObb', () => {
|
|
76
84
|
it('hits a unit OBB at the expected t from outside', () => {
|
|
77
85
|
const o = createObb(0, 0, 0, 1, 1, 1, 0, 0, 0, 1);
|
|
@@ -293,91 +301,6 @@ describe('setObb', () => {
|
|
|
293
301
|
});
|
|
294
302
|
});
|
|
295
303
|
|
|
296
|
-
describe('transformObbByMatrix4', () => {
|
|
297
|
-
it('translates the center by a translation matrix', () => {
|
|
298
|
-
const o = createObb(0, 0, 0, 1, 1, 1, 0, 0, 0, 1);
|
|
299
|
-
const m = createMatrix4();
|
|
300
|
-
setMatrix4Position(m, createVector3(5, 0, 0));
|
|
301
|
-
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
302
|
-
transformObbByMatrix4(out, o, m);
|
|
303
|
-
expect(out.centerX).toBeCloseTo(5, 6);
|
|
304
|
-
expect(out.centerY).toBeCloseTo(0, 6);
|
|
305
|
-
expect(out.halfExtentX).toBeCloseTo(1, 6);
|
|
306
|
-
expect(out.orientationW).toBeCloseTo(1, 5);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it('scales half-extents by a uniform scale matrix', () => {
|
|
310
|
-
const o = createObb(0, 0, 0, 1, 1, 1, 0, 0, 0, 1);
|
|
311
|
-
const m = createMatrix4(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1);
|
|
312
|
-
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
313
|
-
transformObbByMatrix4(out, o, m);
|
|
314
|
-
expect(out.halfExtentX).toBeCloseTo(2, 6);
|
|
315
|
-
expect(out.halfExtentY).toBeCloseTo(2, 6);
|
|
316
|
-
expect(out.halfExtentZ).toBeCloseTo(2, 6);
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
it('supports out === obb', () => {
|
|
320
|
-
const o = createObb(1, 0, 0, 1, 1, 1, 0, 0, 0, 1);
|
|
321
|
-
const m = createMatrix4();
|
|
322
|
-
setMatrix4Position(m, createVector3(0, 3, 0));
|
|
323
|
-
transformObbByMatrix4(o, o, m);
|
|
324
|
-
expect(o.centerX).toBeCloseTo(1, 6);
|
|
325
|
-
expect(o.centerY).toBeCloseTo(3, 6);
|
|
326
|
-
expect(o.halfExtentX).toBeCloseTo(1, 6);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
it('rotates the box the same way the matrix rotates points', () => {
|
|
330
|
-
// The orientation extracted from the matrix must turn the box in the matrix's own direction.
|
|
331
|
-
// A conjugated extraction turns it by the same angle about the opposite axis, which is
|
|
332
|
-
// invisible for axis-aligned boxes and half turns but wrong for every general rotation.
|
|
333
|
-
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(1, 0, 0, 0.7), createTiltedObb());
|
|
334
|
-
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(1, 2, 3, 0.9), createTiltedObb());
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
it('rotates the box correctly near a half turn about each axis', () => {
|
|
338
|
-
// A half turn drives the three `trace <= 0` branches of the matrix-to-quaternion extraction,
|
|
339
|
-
// one per dominant diagonal term. Just short of pi so the conjugate is a different rotation:
|
|
340
|
-
// at exactly pi the quaternion equals its own conjugate up to sign and hides an error.
|
|
341
|
-
const nearHalfTurn = Math.PI - 0.01;
|
|
342
|
-
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(1, 0, 0, nearHalfTurn), createTiltedObb());
|
|
343
|
-
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(0, 1, 0, nearHalfTurn), createTiltedObb());
|
|
344
|
-
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(0, 0, 1, nearHalfTurn), createTiltedObb());
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
it('flattens the box along a collapsed matrix column and keeps the other extents', () => {
|
|
348
|
-
// A zero-length column has no direction to read, so that axis falls back to its identity
|
|
349
|
-
// direction rather than dividing by zero, and the half-extent along it goes to zero.
|
|
350
|
-
const o = createObb(0, 0, 0, 2, 3, 4, 0, 0, 0, 1);
|
|
351
|
-
const m = createMatrix4(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
|
352
|
-
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
353
|
-
transformObbByMatrix4(out, o, m);
|
|
354
|
-
expect(out.halfExtentX).toBe(0);
|
|
355
|
-
expect(out.halfExtentY).toBeCloseTo(3, 6);
|
|
356
|
-
expect(out.halfExtentZ).toBeCloseTo(4, 6);
|
|
357
|
-
expect(out.orientationW).toBeCloseTo(1, 6);
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
it('collapses the box to a point at the matrix position when every column is zero', () => {
|
|
361
|
-
// All three columns collapse, so the fallback rotation is the identity and the box keeps the
|
|
362
|
-
// orientation it came in with — the transform contributes nothing but the translation.
|
|
363
|
-
const tilt = orientationFromAxisAngle(1, 1, 1, 0.6);
|
|
364
|
-
const o = createObb(1, 2, 3, 2, 3, 4, ...tilt);
|
|
365
|
-
const m = createMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 1);
|
|
366
|
-
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
367
|
-
transformObbByMatrix4(out, o, m);
|
|
368
|
-
expect(out.centerX).toBeCloseTo(5, 6);
|
|
369
|
-
expect(out.centerY).toBeCloseTo(6, 6);
|
|
370
|
-
expect(out.centerZ).toBeCloseTo(7, 6);
|
|
371
|
-
expect(out.halfExtentX).toBe(0);
|
|
372
|
-
expect(out.halfExtentY).toBe(0);
|
|
373
|
-
expect(out.halfExtentZ).toBe(0);
|
|
374
|
-
expect(out.orientationX).toBeCloseTo(tilt[0], 6);
|
|
375
|
-
expect(out.orientationY).toBeCloseTo(tilt[1], 6);
|
|
376
|
-
expect(out.orientationZ).toBeCloseTo(tilt[2], 6);
|
|
377
|
-
expect(out.orientationW).toBeCloseTo(tilt[3], 6);
|
|
378
|
-
});
|
|
379
|
-
});
|
|
380
|
-
|
|
381
304
|
// A thin rod: long along one of its own local axes, barely thick along the other two, so the
|
|
382
305
|
// dominant feature of the box is a single edge direction.
|
|
383
306
|
function createRodObb(
|
|
@@ -486,3 +409,87 @@ const FACE_AXIS_SEPARATIONS: ReadonlyArray<{
|
|
|
486
409
|
{ axis: 1, clear: 4.7, extents: [0.5, 1.5, 2.5], ofTurnedBox: true },
|
|
487
410
|
{ axis: 2, clear: 3.7, extents: [2.5, 1.5, 0.5], ofTurnedBox: true },
|
|
488
411
|
];
|
|
412
|
+
describe('transformObbByMatrix4', () => {
|
|
413
|
+
it('translates the center by a translation matrix', () => {
|
|
414
|
+
const o = createObb(0, 0, 0, 1, 1, 1, 0, 0, 0, 1);
|
|
415
|
+
const m = createMatrix4();
|
|
416
|
+
setMatrix4Position(m, createVector3(5, 0, 0));
|
|
417
|
+
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
418
|
+
transformObbByMatrix4(out, o, m);
|
|
419
|
+
expect(out.centerX).toBeCloseTo(5, 6);
|
|
420
|
+
expect(out.centerY).toBeCloseTo(0, 6);
|
|
421
|
+
expect(out.halfExtentX).toBeCloseTo(1, 6);
|
|
422
|
+
expect(out.orientationW).toBeCloseTo(1, 5);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it('scales half-extents by a uniform scale matrix', () => {
|
|
426
|
+
const o = createObb(0, 0, 0, 1, 1, 1, 0, 0, 0, 1);
|
|
427
|
+
const m = createMatrix4(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1);
|
|
428
|
+
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
429
|
+
transformObbByMatrix4(out, o, m);
|
|
430
|
+
expect(out.halfExtentX).toBeCloseTo(2, 6);
|
|
431
|
+
expect(out.halfExtentY).toBeCloseTo(2, 6);
|
|
432
|
+
expect(out.halfExtentZ).toBeCloseTo(2, 6);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('supports out === obb', () => {
|
|
436
|
+
const o = createObb(1, 0, 0, 1, 1, 1, 0, 0, 0, 1);
|
|
437
|
+
const m = createMatrix4();
|
|
438
|
+
setMatrix4Position(m, createVector3(0, 3, 0));
|
|
439
|
+
transformObbByMatrix4(o, o, m);
|
|
440
|
+
expect(o.centerX).toBeCloseTo(1, 6);
|
|
441
|
+
expect(o.centerY).toBeCloseTo(3, 6);
|
|
442
|
+
expect(o.halfExtentX).toBeCloseTo(1, 6);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('rotates the box the same way the matrix rotates points', () => {
|
|
446
|
+
// The orientation extracted from the matrix must turn the box in the matrix's own direction.
|
|
447
|
+
// A conjugated extraction turns it by the same angle about the opposite axis, which is
|
|
448
|
+
// invisible for axis-aligned boxes and half turns but wrong for every general rotation.
|
|
449
|
+
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(1, 0, 0, 0.7), createTiltedObb());
|
|
450
|
+
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(1, 2, 3, 0.9), createTiltedObb());
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it('rotates the box correctly near a half turn about each axis', () => {
|
|
454
|
+
// A half turn drives the three `trace <= 0` branches of the matrix-to-quaternion extraction,
|
|
455
|
+
// one per dominant diagonal term. Just short of pi so the conjugate is a different rotation:
|
|
456
|
+
// at exactly pi the quaternion equals its own conjugate up to sign and hides an error.
|
|
457
|
+
const nearHalfTurn = Math.PI - 0.01;
|
|
458
|
+
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(1, 0, 0, nearHalfTurn), createTiltedObb());
|
|
459
|
+
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(0, 1, 0, nearHalfTurn), createTiltedObb());
|
|
460
|
+
expectTransformedObbMatchesRotatedPoints(rotationMatrix4(0, 0, 1, nearHalfTurn), createTiltedObb());
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('flattens the box along a collapsed matrix column and keeps the other extents', () => {
|
|
464
|
+
// A zero-length column has no direction to read, so that axis falls back to its identity
|
|
465
|
+
// direction rather than dividing by zero, and the half-extent along it goes to zero.
|
|
466
|
+
const o = createObb(0, 0, 0, 2, 3, 4, 0, 0, 0, 1);
|
|
467
|
+
const m = createMatrix4(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
|
468
|
+
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
469
|
+
transformObbByMatrix4(out, o, m);
|
|
470
|
+
expect(out.halfExtentX).toBe(0);
|
|
471
|
+
expect(out.halfExtentY).toBeCloseTo(3, 6);
|
|
472
|
+
expect(out.halfExtentZ).toBeCloseTo(4, 6);
|
|
473
|
+
expect(out.orientationW).toBeCloseTo(1, 6);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('collapses the box to a point at the matrix position when every column is zero', () => {
|
|
477
|
+
// All three columns collapse, so the fallback rotation is the identity and the box keeps the
|
|
478
|
+
// orientation it came in with — the transform contributes nothing but the translation.
|
|
479
|
+
const tilt = orientationFromAxisAngle(1, 1, 1, 0.6);
|
|
480
|
+
const o = createObb(1, 2, 3, 2, 3, 4, ...tilt);
|
|
481
|
+
const m = createMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 1);
|
|
482
|
+
const out = createObb(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
483
|
+
transformObbByMatrix4(out, o, m);
|
|
484
|
+
expect(out.centerX).toBeCloseTo(5, 6);
|
|
485
|
+
expect(out.centerY).toBeCloseTo(6, 6);
|
|
486
|
+
expect(out.centerZ).toBeCloseTo(7, 6);
|
|
487
|
+
expect(out.halfExtentX).toBe(0);
|
|
488
|
+
expect(out.halfExtentY).toBe(0);
|
|
489
|
+
expect(out.halfExtentZ).toBe(0);
|
|
490
|
+
expect(out.orientationX).toBeCloseTo(tilt[0], 6);
|
|
491
|
+
expect(out.orientationY).toBeCloseTo(tilt[1], 6);
|
|
492
|
+
expect(out.orientationZ).toBeCloseTo(tilt[2], 6);
|
|
493
|
+
expect(out.orientationW).toBeCloseTo(tilt[3], 6);
|
|
494
|
+
});
|
|
495
|
+
});
|
package/src/plane.test.ts
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
setPlaneFromPoints,
|
|
14
14
|
} from '@flighthq/geometry/contract';
|
|
15
15
|
|
|
16
|
+
import { initializePlane } from './plane';
|
|
17
|
+
|
|
16
18
|
describe('clonePlane', () => {
|
|
17
19
|
it('creates an independent copy', () => {
|
|
18
20
|
const p = createPlane(1, 0, 0, -5);
|
|
@@ -124,6 +126,12 @@ describe('getPlaneSignedDistanceToPoint', () => {
|
|
|
124
126
|
});
|
|
125
127
|
});
|
|
126
128
|
|
|
129
|
+
describe('initializePlane', () => {
|
|
130
|
+
it('is the construction initializer of createPlane', () => {
|
|
131
|
+
expect(typeof initializePlane).toBe('function');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
127
135
|
describe('normalizePlane', () => {
|
|
128
136
|
it('normalizes a plane with non-unit normal', () => {
|
|
129
137
|
// Normal (0,2,0), d=4 → normalized (0,1,0), d=2.
|
|
@@ -201,7 +209,6 @@ describe('setPlaneFromNormalAndPoint', () => {
|
|
|
201
209
|
expect(p.d).toBeCloseTo(-3, 6);
|
|
202
210
|
});
|
|
203
211
|
});
|
|
204
|
-
|
|
205
212
|
describe('setPlaneFromPoints', () => {
|
|
206
213
|
it('builds the XZ plane from three points in XZ', () => {
|
|
207
214
|
const p = createPlane();
|
package/src/quaternion.test.ts
CHANGED
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
} from '@flighthq/geometry/contract';
|
|
29
29
|
import type { Quaternion } from '@flighthq/types/contract';
|
|
30
30
|
|
|
31
|
+
import { initializeQuaternion } from './quaternion';
|
|
32
|
+
|
|
31
33
|
function expectQuaternionClose(q: Readonly<Quaternion>, x: number, y: number, z: number, w: number): void {
|
|
32
34
|
expect(q.x).toBeCloseTo(x, 6);
|
|
33
35
|
expect(q.y).toBeCloseTo(y, 6);
|
|
@@ -277,6 +279,12 @@ describe('getQuaternionEuler', () => {
|
|
|
277
279
|
});
|
|
278
280
|
});
|
|
279
281
|
|
|
282
|
+
describe('initializeQuaternion', () => {
|
|
283
|
+
it('is the construction initializer of createQuaternion', () => {
|
|
284
|
+
expect(typeof initializeQuaternion).toBe('function');
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
280
288
|
describe('inverseQuaternion', () => {
|
|
281
289
|
it('q * inverse(q) ≈ identity for a unit quaternion', () => {
|
|
282
290
|
const q = createQuaternion();
|
|
@@ -679,7 +687,6 @@ describe('setQuaternionLookRotation', () => {
|
|
|
679
687
|
expectQuaternionClose(aliasedUp, distinct.x, distinct.y, distinct.z, distinct.w);
|
|
680
688
|
});
|
|
681
689
|
});
|
|
682
|
-
|
|
683
690
|
describe('slerpQuaternion', () => {
|
|
684
691
|
it('returns a at t=0 and b at t=1', () => {
|
|
685
692
|
const a = createQuaternion();
|
package/src/ray3d.test.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getClosestPointBetweenRay3Ds,
|
|
10
10
|
getClosestPointOnRay3D,
|
|
11
11
|
getRay3DPointAt,
|
|
12
|
+
initializeRay3D,
|
|
12
13
|
intersectRay3DAabb,
|
|
13
14
|
intersectRay3DPlane,
|
|
14
15
|
intersectRay3DSphere,
|
|
@@ -204,6 +205,12 @@ describe('getRay3DPointAt', () => {
|
|
|
204
205
|
});
|
|
205
206
|
});
|
|
206
207
|
|
|
208
|
+
describe('initializeRay3D', () => {
|
|
209
|
+
it('is the construction initializer of createRay3D', () => {
|
|
210
|
+
expect(typeof initializeRay3D).toBe('function');
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
207
214
|
describe('intersectRay3DAabb', () => {
|
|
208
215
|
it('returns t=0 when the ray origin is inside the box', () => {
|
|
209
216
|
const ray = createRay3D(0, 0, 0, 0, 0, 1);
|
|
@@ -489,6 +496,18 @@ describe('setRay3D', () => {
|
|
|
489
496
|
});
|
|
490
497
|
});
|
|
491
498
|
|
|
499
|
+
// Six rays, one per side of the box spanning (-1, -4, -6) to (2, 3, 5), each starting 10 units out
|
|
500
|
+
// along an axis and aimed at it. The last number is where that ray meets the box: all six differ,
|
|
501
|
+
// so a slab reading another axis' bound gives a different answer rather than the same one.
|
|
502
|
+
// Reversing the direction of each turns the set into six rays aimed away from the box.
|
|
503
|
+
const RAYS_INTO_LOPSIDED_BOX: ReadonlyArray<readonly [number, number, number, number, number, number, number]> = [
|
|
504
|
+
[-10, 0, 0, 1, 0, 0, 9],
|
|
505
|
+
[10, 0, 0, -1, 0, 0, 8],
|
|
506
|
+
[0, -10, 0, 0, 1, 0, 6],
|
|
507
|
+
[0, 10, 0, 0, -1, 0, 7],
|
|
508
|
+
[0, 0, -10, 0, 0, 1, 4],
|
|
509
|
+
[0, 0, 10, 0, 0, -1, 5],
|
|
510
|
+
];
|
|
492
511
|
describe('transformRay3DByMatrix4', () => {
|
|
493
512
|
it('leaves the ray unchanged under the identity matrix', () => {
|
|
494
513
|
const ray = createRay3D(1, 2, 3, 0, 0, 1);
|
|
@@ -530,16 +549,3 @@ describe('transformRay3DByMatrix4', () => {
|
|
|
530
549
|
expect(ray.direction.z).toBeCloseTo(1);
|
|
531
550
|
});
|
|
532
551
|
});
|
|
533
|
-
|
|
534
|
-
// Six rays, one per side of the box spanning (-1, -4, -6) to (2, 3, 5), each starting 10 units out
|
|
535
|
-
// along an axis and aimed at it. The last number is where that ray meets the box: all six differ,
|
|
536
|
-
// so a slab reading another axis' bound gives a different answer rather than the same one.
|
|
537
|
-
// Reversing the direction of each turns the set into six rays aimed away from the box.
|
|
538
|
-
const RAYS_INTO_LOPSIDED_BOX: ReadonlyArray<readonly [number, number, number, number, number, number, number]> = [
|
|
539
|
-
[-10, 0, 0, 1, 0, 0, 9],
|
|
540
|
-
[10, 0, 0, -1, 0, 0, 8],
|
|
541
|
-
[0, -10, 0, 0, 1, 0, 6],
|
|
542
|
-
[0, 10, 0, 0, -1, 0, 7],
|
|
543
|
-
[0, 0, -10, 0, 0, 1, 4],
|
|
544
|
-
[0, 0, 10, 0, 0, -1, 5],
|
|
545
|
-
];
|
package/src/rectangle.test.ts
CHANGED
|
@@ -43,6 +43,8 @@ import {
|
|
|
43
43
|
} from '@flighthq/geometry/contract';
|
|
44
44
|
import type { Rectangle } from '@flighthq/types/contract';
|
|
45
45
|
|
|
46
|
+
import { initializeRectangle } from './rectangle';
|
|
47
|
+
|
|
46
48
|
let r: Rectangle;
|
|
47
49
|
let r2: Rectangle;
|
|
48
50
|
|
|
@@ -601,6 +603,12 @@ describe('inflateRectangle', () => {
|
|
|
601
603
|
});
|
|
602
604
|
});
|
|
603
605
|
|
|
606
|
+
describe('initializeRectangle', () => {
|
|
607
|
+
it('is the construction initializer of createRectangle', () => {
|
|
608
|
+
expect(typeof initializeRectangle).toBe('function');
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
604
612
|
describe('intersectsRectangle', () => {
|
|
605
613
|
it('returns true if rectangles overlap', () => {
|
|
606
614
|
const r3 = createRectangle(5, 10, 10, 10);
|
|
@@ -1004,7 +1012,6 @@ describe('setRectangleTopLeft', () => {
|
|
|
1004
1012
|
expect(r.y).toBe(10);
|
|
1005
1013
|
});
|
|
1006
1014
|
});
|
|
1007
|
-
|
|
1008
1015
|
describe('setTo', () => {
|
|
1009
1016
|
it('assigns all four properties', () => {
|
|
1010
1017
|
const rect = createRectangle();
|
package/src/transform2d.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
3
|
import { createMatrix } from './matrix';
|
|
4
|
-
import { createTransform2D, decomposeMatrixToTransform2D } from './transform2d';
|
|
4
|
+
import { createTransform2D, decomposeMatrixToTransform2D, initializeTransform2D } from './transform2d';
|
|
5
5
|
|
|
6
6
|
const DEG_TO_RAD = Math.PI / 180;
|
|
7
7
|
|
|
@@ -120,3 +120,8 @@ function expectRoundTrip(source: Readonly<ReturnType<typeof createMatrix>>) {
|
|
|
120
120
|
expect(rebuilt.c).toBeCloseTo(source.c);
|
|
121
121
|
expect(rebuilt.d).toBeCloseTo(source.d);
|
|
122
122
|
}
|
|
123
|
+
describe('initializeTransform2D', () => {
|
|
124
|
+
it('is the construction initializer of createTransform2D', () => {
|
|
125
|
+
expect(typeof initializeTransform2D).toBe('function');
|
|
126
|
+
});
|
|
127
|
+
});
|
package/src/transform3d.test.ts
CHANGED
|
@@ -2,7 +2,12 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
import { createMatrix4 } from './matrix4';
|
|
4
4
|
import { createQuaternion } from './quaternion';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
composeMatrix4FromTransform3D,
|
|
7
|
+
createTransform3D,
|
|
8
|
+
decomposeMatrix4ToTransform3D,
|
|
9
|
+
initializeTransform3D,
|
|
10
|
+
} from './transform3d';
|
|
6
11
|
import { createVector3 } from './vector3';
|
|
7
12
|
|
|
8
13
|
describe('composeMatrix4FromTransform3D', () => {
|
|
@@ -48,3 +53,8 @@ describe('decomposeMatrix4ToTransform3D', () => {
|
|
|
48
53
|
expect(out.scale.z).toBeCloseTo(4);
|
|
49
54
|
});
|
|
50
55
|
});
|
|
56
|
+
describe('initializeTransform3D', () => {
|
|
57
|
+
it('is the construction initializer of createTransform3D', () => {
|
|
58
|
+
expect(typeof initializeTransform3D).toBe('function');
|
|
59
|
+
});
|
|
60
|
+
});
|
package/src/vector2.test.ts
CHANGED
|
@@ -36,6 +36,8 @@ import {
|
|
|
36
36
|
} from '@flighthq/geometry/contract';
|
|
37
37
|
import type { Vector2 } from '@flighthq/types/contract';
|
|
38
38
|
|
|
39
|
+
import { initializeVector2 } from './vector2';
|
|
40
|
+
|
|
39
41
|
let pt: Vector2;
|
|
40
42
|
let pt2: Vector2;
|
|
41
43
|
|
|
@@ -511,6 +513,12 @@ describe('getVector2LengthSquared', () => {
|
|
|
511
513
|
});
|
|
512
514
|
});
|
|
513
515
|
|
|
516
|
+
describe('initializeVector2', () => {
|
|
517
|
+
it('is the construction initializer of createVector2', () => {
|
|
518
|
+
expect(typeof initializeVector2).toBe('function');
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
|
|
514
522
|
describe('interpolateVector2', () => {
|
|
515
523
|
const cases = [
|
|
516
524
|
{ t: 0, expected: (a: number, _: number) => a },
|
|
@@ -1181,7 +1189,6 @@ describe('subtractVector2', () => {
|
|
|
1181
1189
|
expect(result).not.toBe(pt2);
|
|
1182
1190
|
});
|
|
1183
1191
|
});
|
|
1184
|
-
|
|
1185
1192
|
describe('writeVector2ToFloat32Array', () => {
|
|
1186
1193
|
it('writes 2 values at the offset', () => {
|
|
1187
1194
|
const array = new Float32Array(6);
|
package/src/vector3.test.ts
CHANGED
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
} from '@flighthq/geometry/contract';
|
|
40
40
|
import type { Vector3 } from '@flighthq/types/contract';
|
|
41
41
|
|
|
42
|
+
import { initializeVector3 } from './vector3';
|
|
43
|
+
|
|
42
44
|
describe('addVector3', () => {
|
|
43
45
|
it('returns a new vector when no target is passed', () => {
|
|
44
46
|
const a = createVector3(1, 2, 3);
|
|
@@ -461,6 +463,12 @@ describe('getVector3Spherical', () => {
|
|
|
461
463
|
});
|
|
462
464
|
});
|
|
463
465
|
|
|
466
|
+
describe('initializeVector3', () => {
|
|
467
|
+
it('is the construction initializer of createVector3', () => {
|
|
468
|
+
expect(typeof initializeVector3).toBe('function');
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
|
|
464
472
|
describe('interpolateVector3', () => {
|
|
465
473
|
it('returns a at t=0 and b at t=1', () => {
|
|
466
474
|
const out = createVector3();
|
|
@@ -947,7 +955,6 @@ describe('Y_AXIS', () => {
|
|
|
947
955
|
expect(yAxis.z).toBe(0);
|
|
948
956
|
});
|
|
949
957
|
});
|
|
950
|
-
|
|
951
958
|
describe('Z_AXIS', () => {
|
|
952
959
|
it('returns the unit vector along the Z-axis', () => {
|
|
953
960
|
const zAxis: Vector3 = VECTOR3_Z_AXIS;
|
package/src/vector4.test.ts
CHANGED
|
@@ -36,6 +36,8 @@ import {
|
|
|
36
36
|
} from '@flighthq/geometry/contract';
|
|
37
37
|
import type { Vector4 } from '@flighthq/types/contract';
|
|
38
38
|
|
|
39
|
+
import { initializeVector4 } from './vector4';
|
|
40
|
+
|
|
39
41
|
describe('addVector4', () => {
|
|
40
42
|
it('returns a new vector when no target is passed', () => {
|
|
41
43
|
const a = createVector4(1, 2, 3, 10);
|
|
@@ -398,6 +400,12 @@ describe('getVector4LengthSquared', () => {
|
|
|
398
400
|
});
|
|
399
401
|
});
|
|
400
402
|
|
|
403
|
+
describe('initializeVector4', () => {
|
|
404
|
+
it('is the construction initializer of createVector4', () => {
|
|
405
|
+
expect(typeof initializeVector4).toBe('function');
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
401
409
|
describe('interpolateVector4', () => {
|
|
402
410
|
it('returns a at t=0 and b at t=1', () => {
|
|
403
411
|
const out = createVector4();
|
|
@@ -583,6 +591,8 @@ describe('nearEqualsVector4', () => {
|
|
|
583
591
|
});
|
|
584
592
|
});
|
|
585
593
|
|
|
594
|
+
// Properties
|
|
595
|
+
|
|
586
596
|
describe('negateVector4', () => {
|
|
587
597
|
it('inverts the values of the vector components', () => {
|
|
588
598
|
const v = createVector4(1, -2, 3, -4);
|
|
@@ -604,8 +614,6 @@ describe('negateVector4', () => {
|
|
|
604
614
|
});
|
|
605
615
|
});
|
|
606
616
|
|
|
607
|
-
// Properties
|
|
608
|
-
|
|
609
617
|
describe('normalizeVector4', () => {
|
|
610
618
|
it('normalizes the vector', () => {
|
|
611
619
|
const v = createVector4(3, 4, 0, 0);
|
|
@@ -878,7 +886,6 @@ describe('Y_AXIS', () => {
|
|
|
878
886
|
expect(yAxis.w).toBe(0);
|
|
879
887
|
});
|
|
880
888
|
});
|
|
881
|
-
|
|
882
889
|
describe('Z_AXIS', () => {
|
|
883
890
|
it('returns the unit vector along the Z-axis', () => {
|
|
884
891
|
const zAxis = VECTOR4_Z_AXIS;
|