@flighthq/geometry 0.3.0 → 0.3.1-next.1041.35b950c

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.
Files changed (125) hide show
  1. package/dist/aabb.d.ts +1 -0
  2. package/dist/aabb.d.ts.map +1 -1
  3. package/dist/aabb.js +58 -38
  4. package/dist/aabb.js.map +1 -1
  5. package/dist/boundingSphere.d.ts.map +1 -1
  6. package/dist/boundingSphere.js +3 -2
  7. package/dist/boundingSphere.js.map +1 -1
  8. package/dist/capsule.d.ts +6 -5
  9. package/dist/capsule.d.ts.map +1 -1
  10. package/dist/capsule.js +38 -15
  11. package/dist/capsule.js.map +1 -1
  12. package/dist/contract.d.ts +1 -0
  13. package/dist/contract.d.ts.map +1 -1
  14. package/dist/contract.js +1 -0
  15. package/dist/contract.js.map +1 -1
  16. package/dist/enableGeometryPoolGuards.d.ts +4 -0
  17. package/dist/enableGeometryPoolGuards.d.ts.map +1 -0
  18. package/dist/enableGeometryPoolGuards.js +32 -0
  19. package/dist/enableGeometryPoolGuards.js.map +1 -0
  20. package/dist/frustum.d.ts +2 -1
  21. package/dist/frustum.d.ts.map +1 -1
  22. package/dist/frustum.js +4 -1
  23. package/dist/frustum.js.map +1 -1
  24. package/dist/geometryPoolGuards.d.ts +6 -0
  25. package/dist/geometryPoolGuards.d.ts.map +1 -0
  26. package/dist/geometryPoolGuards.js +7 -0
  27. package/dist/geometryPoolGuards.js.map +1 -0
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/matrix.d.ts +12 -9
  33. package/dist/matrix.d.ts.map +1 -1
  34. package/dist/matrix.js +103 -106
  35. package/dist/matrix.js.map +1 -1
  36. package/dist/matrix3.d.ts +17 -2
  37. package/dist/matrix3.d.ts.map +1 -1
  38. package/dist/matrix3.js +88 -44
  39. package/dist/matrix3.js.map +1 -1
  40. package/dist/matrix3Pool.d.ts.map +1 -1
  41. package/dist/matrix3Pool.js +6 -0
  42. package/dist/matrix3Pool.js.map +1 -1
  43. package/dist/matrix4.d.ts +23 -10
  44. package/dist/matrix4.d.ts.map +1 -1
  45. package/dist/matrix4.js +74 -53
  46. package/dist/matrix4.js.map +1 -1
  47. package/dist/matrix4Pool.d.ts.map +1 -1
  48. package/dist/matrix4Pool.js +6 -0
  49. package/dist/matrix4Pool.js.map +1 -1
  50. package/dist/matrixPool.d.ts.map +1 -1
  51. package/dist/matrixPool.js +6 -0
  52. package/dist/matrixPool.js.map +1 -1
  53. package/dist/obb.d.ts +4 -2
  54. package/dist/obb.d.ts.map +1 -1
  55. package/dist/obb.js +164 -88
  56. package/dist/obb.js.map +1 -1
  57. package/dist/quaternion.d.ts +7 -4
  58. package/dist/quaternion.d.ts.map +1 -1
  59. package/dist/quaternion.js +40 -25
  60. package/dist/quaternion.js.map +1 -1
  61. package/dist/quaternionPool.d.ts.map +1 -1
  62. package/dist/quaternionPool.js +6 -0
  63. package/dist/quaternionPool.js.map +1 -1
  64. package/dist/ray3d.d.ts +5 -4
  65. package/dist/ray3d.d.ts.map +1 -1
  66. package/dist/ray3d.js +23 -8
  67. package/dist/ray3d.js.map +1 -1
  68. package/dist/rectangle.d.ts.map +1 -1
  69. package/dist/rectangle.js +66 -43
  70. package/dist/rectangle.js.map +1 -1
  71. package/dist/rectanglePool.d.ts.map +1 -1
  72. package/dist/rectanglePool.js +6 -0
  73. package/dist/rectanglePool.js.map +1 -1
  74. package/dist/transform2d.d.ts.map +1 -1
  75. package/dist/transform2d.js +5 -2
  76. package/dist/transform2d.js.map +1 -1
  77. package/dist/typedarray.js +3 -6
  78. package/dist/typedarray.js.map +1 -1
  79. package/dist/vector2.d.ts.map +1 -1
  80. package/dist/vector2.js +44 -26
  81. package/dist/vector2.js.map +1 -1
  82. package/dist/vector2Pool.d.ts.map +1 -1
  83. package/dist/vector2Pool.js +6 -0
  84. package/dist/vector2Pool.js.map +1 -1
  85. package/dist/vector3.d.ts +2 -2
  86. package/dist/vector3.d.ts.map +1 -1
  87. package/dist/vector3.js +55 -37
  88. package/dist/vector3.js.map +1 -1
  89. package/dist/vector3Pool.d.ts.map +1 -1
  90. package/dist/vector3Pool.js +6 -0
  91. package/dist/vector3Pool.js.map +1 -1
  92. package/dist/vector4.d.ts +2 -2
  93. package/dist/vector4.d.ts.map +1 -1
  94. package/dist/vector4.js +66 -48
  95. package/dist/vector4.js.map +1 -1
  96. package/dist/vector4Pool.d.ts.map +1 -1
  97. package/dist/vector4Pool.js +6 -0
  98. package/dist/vector4Pool.js.map +1 -1
  99. package/package.json +4 -3
  100. package/src/aabb.test.ts +18 -0
  101. package/src/boundingSphere.test.ts +39 -0
  102. package/src/capsule.test.ts +158 -0
  103. package/src/enableGeometryPoolGuards.test.ts +121 -0
  104. package/src/frustum.test.ts +38 -0
  105. package/src/geometryPoolGuards.test.ts +16 -0
  106. package/src/matrix.test.ts +52 -6
  107. package/src/matrix3.test.ts +46 -6
  108. package/src/matrix3Pool.test.ts +11 -0
  109. package/src/matrix4.test.ts +553 -135
  110. package/src/matrix4Pool.test.ts +11 -0
  111. package/src/matrixPool.test.ts +11 -0
  112. package/src/obb.test.ts +277 -0
  113. package/src/plane.test.ts +20 -0
  114. package/src/quaternion.test.ts +222 -4
  115. package/src/quaternionPool.test.ts +12 -0
  116. package/src/ray3d.test.ts +204 -0
  117. package/src/rectangle.test.ts +58 -14
  118. package/src/rectanglePool.test.ts +11 -0
  119. package/src/transform2d.test.ts +38 -0
  120. package/src/vector2.test.ts +170 -0
  121. package/src/vector2Pool.test.ts +11 -0
  122. package/src/vector3.test.ts +210 -0
  123. package/src/vector3Pool.test.ts +11 -0
  124. package/src/vector4.test.ts +231 -0
  125. package/src/vector4Pool.test.ts +11 -0
@@ -90,6 +90,33 @@ describe('addVector4', () => {
90
90
  });
91
91
 
92
92
  describe('clampVector4', () => {
93
+ it('clamps each component to its own bounds, below, above, and not at all', () => {
94
+ // Every component gets a DIFFERENT min and max, so a component reading a neighbour's bound
95
+ // comes out as a wrong number instead of the right one by luck. Each component is then run
96
+ // through all three outcomes — under its floor, over its ceiling, and already in range.
97
+ const min = createVector4(-1, -2, -3, -4);
98
+ const max = createVector4(10, 20, 30, 40);
99
+ const out = createVector4();
100
+
101
+ clampVector4(out, createVector4(-5, -6, -7, -8), min, max);
102
+ expect(out.x).toBe(-1);
103
+ expect(out.y).toBe(-2);
104
+ expect(out.z).toBe(-3);
105
+ expect(out.w).toBe(-4);
106
+
107
+ clampVector4(out, createVector4(100, 200, 300, 400), min, max);
108
+ expect(out.x).toBe(10);
109
+ expect(out.y).toBe(20);
110
+ expect(out.z).toBe(30);
111
+ expect(out.w).toBe(40);
112
+
113
+ clampVector4(out, createVector4(0, 1, 2, 3), min, max);
114
+ expect(out.x).toBe(0);
115
+ expect(out.y).toBe(1);
116
+ expect(out.z).toBe(2);
117
+ expect(out.w).toBe(3);
118
+ });
119
+
93
120
  it('clamps each component independently', () => {
94
121
  const out = createVector4();
95
122
  clampVector4(out, createVector4(5, -2, 1, 10), createVector4(0, 0, 0, 0), createVector4(3, 3, 3, 3));
@@ -98,6 +125,29 @@ describe('clampVector4', () => {
98
125
  expect(out.z).toBe(1);
99
126
  expect(out.w).toBe(3);
100
127
  });
128
+
129
+ it('supports out aliasing any input', () => {
130
+ const value = createVector4(5, -2, 1, 10);
131
+ clampVector4(value, value, createVector4(0, 0, 0, 0), createVector4(3, 3, 3, 3));
132
+ expect(value).toMatchObject({ x: 3, y: 0, z: 1, w: 3 });
133
+
134
+ const min = createVector4(0, 0, 0, 0);
135
+ clampVector4(min, createVector4(5, -2, 1, 10), min, createVector4(3, 3, 3, 3));
136
+ expect(min).toMatchObject({ x: 3, y: 0, z: 1, w: 3 });
137
+
138
+ const max = createVector4(3, 3, 3, 3);
139
+ clampVector4(max, createVector4(5, -2, 1, 10), createVector4(0, 0, 0, 0), max);
140
+ expect(max).toMatchObject({ x: 3, y: 0, z: 1, w: 3 });
141
+ });
142
+
143
+ it('covers low, middle, and high outcomes on every component', () => {
144
+ const out = createVector4();
145
+ clampVector4(out, createVector4(-1, 2, 5, -1), createVector4(0, 0, 0, 0), createVector4(3, 3, 3, 3));
146
+ expect(out).toMatchObject({ x: 0, y: 2, z: 3, w: 0 });
147
+
148
+ clampVector4(out, createVector4(1, 5, -1, 2), createVector4(0, 0, 0, 0), createVector4(3, 3, 3, 3));
149
+ expect(out).toMatchObject({ x: 1, y: 3, z: 0, w: 2 });
150
+ });
101
151
  });
102
152
 
103
153
  describe('cloneVector4', () => {
@@ -164,6 +214,37 @@ describe('createVector4', () => {
164
214
  });
165
215
 
166
216
  describe('divideVector4', () => {
217
+ it('gives 0 for a zero divisor on each component in turn', () => {
218
+ // A zero divisor is answered per component, not for the whole vector, so each component is
219
+ // zeroed on its own while the others still divide normally.
220
+ const source = createVector4(6, 8, 9, 10);
221
+ const out = createVector4();
222
+
223
+ divideVector4(out, source, createVector4(0, 4, 3, 5));
224
+ expect(out.x).toBe(0);
225
+ expect(out.y).toBe(2);
226
+ expect(out.z).toBe(3);
227
+ expect(out.w).toBe(2);
228
+
229
+ divideVector4(out, source, createVector4(2, 0, 3, 5));
230
+ expect(out.x).toBe(3);
231
+ expect(out.y).toBe(0);
232
+ expect(out.z).toBe(3);
233
+ expect(out.w).toBe(2);
234
+
235
+ divideVector4(out, source, createVector4(2, 4, 0, 5));
236
+ expect(out.x).toBe(3);
237
+ expect(out.y).toBe(2);
238
+ expect(out.z).toBe(0);
239
+ expect(out.w).toBe(2);
240
+
241
+ divideVector4(out, source, createVector4(2, 4, 3, 0));
242
+ expect(out.x).toBe(3);
243
+ expect(out.y).toBe(2);
244
+ expect(out.z).toBe(3);
245
+ expect(out.w).toBe(0);
246
+ });
247
+
167
248
  it('divides component-wise', () => {
168
249
  const out = createVector4();
169
250
  divideVector4(out, createVector4(6, 8, 9, 12), createVector4(2, 4, 3, 6));
@@ -173,6 +254,16 @@ describe('divideVector4', () => {
173
254
  expect(out.w).toBe(2);
174
255
  });
175
256
 
257
+ it('supports out === source or divisor', () => {
258
+ const source = createVector4(6, 8, 9, 12);
259
+ divideVector4(source, source, createVector4(2, 4, 3, 6));
260
+ expect(source).toMatchObject({ x: 3, y: 2, z: 3, w: 2 });
261
+
262
+ const divisor = createVector4(2, 4, 3, 6);
263
+ divideVector4(divisor, createVector4(6, 8, 9, 12), divisor);
264
+ expect(divisor).toMatchObject({ x: 3, y: 2, z: 3, w: 2 });
265
+ });
266
+
176
267
  it('produces 0 for zero divisor components', () => {
177
268
  const out = createVector4();
178
269
  divideVector4(out, createVector4(6, 8, 9, 12), createVector4(0, 4, 0, 6));
@@ -181,9 +272,20 @@ describe('divideVector4', () => {
181
272
  expect(out.z).toBe(0);
182
273
  expect(out.w).toBe(2);
183
274
  });
275
+
276
+ it('produces 0 for zero y and w divisors', () => {
277
+ const out = createVector4();
278
+ divideVector4(out, createVector4(6, 8, 9, 12), createVector4(2, 0, 3, 0));
279
+ expect(out).toMatchObject({ x: 3, y: 0, z: 3, w: 0 });
280
+ });
184
281
  });
185
282
 
186
283
  describe('equalsVector4', () => {
284
+ it('returns false when either vector is absent', () => {
285
+ expect(equalsVector4(createVector4(), null)).toBe(false);
286
+ expect(equalsVector4(undefined, createVector4())).toBe(false);
287
+ });
288
+
187
289
  it('returns true if vectors are equal', () => {
188
290
  const a = createVector4(1, 2, 3, 4);
189
291
  const b = createVector4(1, 2, 3, 4);
@@ -195,6 +297,36 @@ describe('equalsVector4', () => {
195
297
  const b = createVector4(4, 5, 6, 7);
196
298
  expect(equalsVector4(a, b)).toBe(false);
197
299
  });
300
+
301
+ it('compares every component, not just the first', () => {
302
+ // Four hand-written comparisons in a row: one left reading the wrong field agrees with the
303
+ // right answer on every pair that differs in more than one place, so each differs alone here.
304
+ const a = createVector4(1, 2, 3, 4);
305
+ expect(equalsVector4(a, createVector4(9, 2, 3, 4))).toBe(false);
306
+ expect(equalsVector4(a, createVector4(1, 9, 3, 4))).toBe(false);
307
+ expect(equalsVector4(a, createVector4(1, 2, 9, 4))).toBe(false);
308
+ expect(equalsVector4(a, createVector4(1, 2, 3, 9))).toBe(false);
309
+ });
310
+
311
+ it('returns false when either side is missing', () => {
312
+ // The signature accepts null and undefined, so absence is an answerable input rather than
313
+ // misuse: nothing is equal to a vector, including another absence.
314
+ const v = createVector4(1, 2, 3, 4);
315
+ expect(equalsVector4(v, null)).toBe(false);
316
+ expect(equalsVector4(null, v)).toBe(false);
317
+ expect(equalsVector4(v, undefined)).toBe(false);
318
+ expect(equalsVector4(undefined, v)).toBe(false);
319
+ expect(equalsVector4(null, null)).toBe(false);
320
+ expect(equalsVector4(undefined, undefined)).toBe(false);
321
+ });
322
+
323
+ it('holds a vector equal to itself even with a NaN component', () => {
324
+ // Comparing field by field would say a vector carrying NaN differs from itself, and a caller
325
+ // watching for changes would then see one every time it looked.
326
+ const notANumber = createVector4(NaN, 2, 3, 4);
327
+ expect(equalsVector4(notANumber, notANumber)).toBe(true);
328
+ expect(equalsVector4(notANumber, createVector4(NaN, 2, 3, 4))).toBe(false);
329
+ });
198
330
  });
199
331
 
200
332
  describe('getVector4AngleBetween', () => {
@@ -300,9 +432,36 @@ describe('interpolateVector4', () => {
300
432
  expect(a.z).toBe(3);
301
433
  expect(a.w).toBe(4);
302
434
  });
435
+
436
+ it('supports out === b', () => {
437
+ const b = createVector4(2, 4, 6, 8);
438
+ interpolateVector4(b, createVector4(0, 0, 0, 0), b, 0.5);
439
+ expect(b).toMatchObject({ x: 1, y: 2, z: 3, w: 4 });
440
+ });
303
441
  });
304
442
 
305
443
  describe('maxVector4', () => {
444
+ it('takes each component from whichever side wins, and gives the same answer either way round', () => {
445
+ // The winner alternates between the two arguments component by component, and all 8 numbers
446
+ // are distinct, so a line reading the wrong component or the wrong side cannot land on the
447
+ // right answer anyway. Running it again with the arguments swapped must not change it.
448
+ const a = createVector4(1, 5, 2, 9);
449
+ const b = createVector4(3, 0, 7, 4);
450
+ const out = createVector4();
451
+
452
+ maxVector4(out, a, b);
453
+ expect(out.x).toBe(3);
454
+ expect(out.y).toBe(5);
455
+ expect(out.z).toBe(7);
456
+ expect(out.w).toBe(9);
457
+
458
+ maxVector4(out, b, a);
459
+ expect(out.x).toBe(3);
460
+ expect(out.y).toBe(5);
461
+ expect(out.z).toBe(7);
462
+ expect(out.w).toBe(9);
463
+ });
464
+
306
465
  it('returns the component-wise maximum', () => {
307
466
  const out = createVector4();
308
467
  maxVector4(out, createVector4(1, 5, 2, 9), createVector4(3, 2, 7, 4));
@@ -311,9 +470,46 @@ describe('maxVector4', () => {
311
470
  expect(out.z).toBe(7);
312
471
  expect(out.w).toBe(9);
313
472
  });
473
+
474
+ it('supports out === a or b', () => {
475
+ const a = createVector4(1, 5, 2, 9);
476
+ maxVector4(a, a, createVector4(3, 2, 7, 4));
477
+ expect(a).toMatchObject({ x: 3, y: 5, z: 7, w: 9 });
478
+
479
+ const b = createVector4(3, 2, 7, 4);
480
+ maxVector4(b, createVector4(1, 5, 2, 9), b);
481
+ expect(b).toMatchObject({ x: 3, y: 5, z: 7, w: 9 });
482
+ });
483
+
484
+ it('selects the complementary component outcomes', () => {
485
+ const out = createVector4();
486
+ maxVector4(out, createVector4(5, 1, 7, 2), createVector4(2, 3, 4, 9));
487
+ expect(out).toMatchObject({ x: 5, y: 3, z: 7, w: 9 });
488
+ });
314
489
  });
315
490
 
316
491
  describe('minVector4', () => {
492
+ it('takes each component from whichever side wins, and gives the same answer either way round', () => {
493
+ // The winner alternates between the two arguments component by component, and all 8 numbers
494
+ // are distinct, so a line reading the wrong component or the wrong side cannot land on the
495
+ // right answer anyway. Running it again with the arguments swapped must not change it.
496
+ const a = createVector4(1, 5, 2, 9);
497
+ const b = createVector4(3, 0, 7, 4);
498
+ const out = createVector4();
499
+
500
+ minVector4(out, a, b);
501
+ expect(out.x).toBe(1);
502
+ expect(out.y).toBe(0);
503
+ expect(out.z).toBe(2);
504
+ expect(out.w).toBe(4);
505
+
506
+ minVector4(out, b, a);
507
+ expect(out.x).toBe(1);
508
+ expect(out.y).toBe(0);
509
+ expect(out.z).toBe(2);
510
+ expect(out.w).toBe(4);
511
+ });
512
+
317
513
  it('returns the component-wise minimum', () => {
318
514
  const out = createVector4();
319
515
  minVector4(out, createVector4(1, 5, 2, 9), createVector4(3, 2, 7, 4));
@@ -322,6 +518,22 @@ describe('minVector4', () => {
322
518
  expect(out.z).toBe(2);
323
519
  expect(out.w).toBe(4);
324
520
  });
521
+
522
+ it('supports out === a or b', () => {
523
+ const a = createVector4(1, 5, 2, 9);
524
+ minVector4(a, a, createVector4(3, 2, 7, 4));
525
+ expect(a).toMatchObject({ x: 1, y: 2, z: 2, w: 4 });
526
+
527
+ const b = createVector4(3, 2, 7, 4);
528
+ minVector4(b, createVector4(1, 5, 2, 9), b);
529
+ expect(b).toMatchObject({ x: 1, y: 2, z: 2, w: 4 });
530
+ });
531
+
532
+ it('selects the complementary component outcomes', () => {
533
+ const out = createVector4();
534
+ minVector4(out, createVector4(5, 1, 7, 2), createVector4(2, 3, 4, 9));
535
+ expect(out).toMatchObject({ x: 2, y: 1, z: 4, w: 2 });
536
+ });
325
537
  });
326
538
 
327
539
  describe('multiplyVector4', () => {
@@ -333,6 +545,16 @@ describe('multiplyVector4', () => {
333
545
  expect(out.z).toBe(32);
334
546
  expect(out.w).toBe(45);
335
547
  });
548
+
549
+ it('supports out === a or b', () => {
550
+ const a = createVector4(2, 3, 4, 5);
551
+ multiplyVector4(a, a, createVector4(6, 7, 8, 9));
552
+ expect(a).toMatchObject({ x: 12, y: 21, z: 32, w: 45 });
553
+
554
+ const b = createVector4(6, 7, 8, 9);
555
+ multiplyVector4(b, createVector4(2, 3, 4, 5), b);
556
+ expect(b).toMatchObject({ x: 12, y: 21, z: 32, w: 45 });
557
+ });
336
558
  });
337
559
 
338
560
  describe('nearEqualsVector4', () => {
@@ -486,6 +708,15 @@ describe('reflectVector4', () => {
486
708
  reflectVector4(v, v, createVector4(1, 0, 0, 0));
487
709
  expect(v.x).toBeCloseTo(-1, 6);
488
710
  });
711
+
712
+ it('supports out === normal', () => {
713
+ const normal = createVector4(1, 0, 0, 0);
714
+ reflectVector4(normal, createVector4(1, 0, 0, 0), normal);
715
+ expect(normal.x).toBeCloseTo(-1, 6);
716
+ expect(normal.y).toBeCloseTo(0, 6);
717
+ expect(normal.z).toBeCloseTo(0, 6);
718
+ expect(normal.w).toBeCloseTo(0, 6);
719
+ });
489
720
  });
490
721
 
491
722
  describe('scaleVector4', () => {
@@ -1,3 +1,4 @@
1
+ import { attachEntityBinding, getEntityBinding } from '@flighthq/entity/contract';
1
2
  import type { Vector4 } from '@flighthq/types/contract';
2
3
 
3
4
  import { acquireEmptyVector4, acquireVector4, clearVector4Pool, releaseVector4 } from './vector4Pool';
@@ -65,6 +66,16 @@ describe('clearVector4Pool', () => {
65
66
  });
66
67
 
67
68
  describe('releaseVector4', () => {
69
+ it('detaches the previous owner binding before the vector is reused', () => {
70
+ const v = acquireVector4();
71
+ attachEntityBinding(v, { owner: 'first' });
72
+ releaseVector4(v);
73
+
74
+ const reused = acquireVector4();
75
+ expect(reused).toBe(v);
76
+ expect(getEntityBinding(reused)).toBeNull();
77
+ });
78
+
68
79
  it('handles null safely', () => {
69
80
  expect(() => releaseVector4(null as unknown as Vector4)).not.toThrow();
70
81
  });