@flighthq/geometry 0.1.0

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 +88 -0
  2. package/dist/aabb.d.ts.map +1 -0
  3. package/dist/aabb.js +230 -0
  4. package/dist/aabb.js.map +1 -0
  5. package/dist/boundingSphere.d.ts +62 -0
  6. package/dist/boundingSphere.d.ts.map +1 -0
  7. package/dist/boundingSphere.js +188 -0
  8. package/dist/boundingSphere.js.map +1 -0
  9. package/dist/capsule.d.ts +38 -0
  10. package/dist/capsule.d.ts.map +1 -0
  11. package/dist/capsule.js +215 -0
  12. package/dist/capsule.js.map +1 -0
  13. package/dist/frustum.d.ts +49 -0
  14. package/dist/frustum.d.ts.map +1 -0
  15. package/dist/frustum.js +149 -0
  16. package/dist/frustum.js.map +1 -0
  17. package/dist/index.d.ts +25 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +25 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/matrix.d.ts +152 -0
  22. package/dist/matrix.d.ts.map +1 -0
  23. package/dist/matrix.js +488 -0
  24. package/dist/matrix.js.map +1 -0
  25. package/dist/matrix3.d.ts +63 -0
  26. package/dist/matrix3.d.ts.map +1 -0
  27. package/dist/matrix3.js +408 -0
  28. package/dist/matrix3.js.map +1 -0
  29. package/dist/matrix3Pool.d.ts +6 -0
  30. package/dist/matrix3Pool.d.ts.map +1 -0
  31. package/dist/matrix3Pool.js +26 -0
  32. package/dist/matrix3Pool.js.map +1 -0
  33. package/dist/matrix4.d.ts +238 -0
  34. package/dist/matrix4.d.ts.map +1 -0
  35. package/dist/matrix4.js +931 -0
  36. package/dist/matrix4.js.map +1 -0
  37. package/dist/matrix4Pool.d.ts +6 -0
  38. package/dist/matrix4Pool.d.ts.map +1 -0
  39. package/dist/matrix4Pool.js +26 -0
  40. package/dist/matrix4Pool.js.map +1 -0
  41. package/dist/matrixPool.d.ts +6 -0
  42. package/dist/matrixPool.d.ts.map +1 -0
  43. package/dist/matrixPool.js +26 -0
  44. package/dist/matrixPool.js.map +1 -0
  45. package/dist/obb.d.ts +44 -0
  46. package/dist/obb.d.ts.map +1 -0
  47. package/dist/obb.js +248 -0
  48. package/dist/obb.js.map +1 -0
  49. package/dist/plane.d.ts +66 -0
  50. package/dist/plane.d.ts.map +1 -0
  51. package/dist/plane.js +140 -0
  52. package/dist/plane.js.map +1 -0
  53. package/dist/quaternion.d.ts +128 -0
  54. package/dist/quaternion.d.ts.map +1 -0
  55. package/dist/quaternion.js +508 -0
  56. package/dist/quaternion.js.map +1 -0
  57. package/dist/quaternionPool.d.ts +6 -0
  58. package/dist/quaternionPool.d.ts.map +1 -0
  59. package/dist/quaternionPool.js +29 -0
  60. package/dist/quaternionPool.js.map +1 -0
  61. package/dist/ray3d.d.ts +69 -0
  62. package/dist/ray3d.d.ts.map +1 -0
  63. package/dist/ray3d.js +264 -0
  64. package/dist/ray3d.js.map +1 -0
  65. package/dist/rectangle.d.ts +56 -0
  66. package/dist/rectangle.d.ts.map +1 -0
  67. package/dist/rectangle.js +235 -0
  68. package/dist/rectangle.js.map +1 -0
  69. package/dist/rectanglePool.d.ts +6 -0
  70. package/dist/rectanglePool.d.ts.map +1 -0
  71. package/dist/rectanglePool.js +29 -0
  72. package/dist/rectanglePool.js.map +1 -0
  73. package/dist/typedarray.d.ts +4 -0
  74. package/dist/typedarray.d.ts.map +1 -0
  75. package/dist/typedarray.js +25 -0
  76. package/dist/typedarray.js.map +1 -0
  77. package/dist/vector2.d.ts +130 -0
  78. package/dist/vector2.d.ts.map +1 -0
  79. package/dist/vector2.js +250 -0
  80. package/dist/vector2.js.map +1 -0
  81. package/dist/vector2Pool.d.ts +6 -0
  82. package/dist/vector2Pool.d.ts.map +1 -0
  83. package/dist/vector2Pool.js +20 -0
  84. package/dist/vector2Pool.js.map +1 -0
  85. package/dist/vector3.d.ts +220 -0
  86. package/dist/vector3.d.ts.map +1 -0
  87. package/dist/vector3.js +380 -0
  88. package/dist/vector3.js.map +1 -0
  89. package/dist/vector3Pool.d.ts +6 -0
  90. package/dist/vector3Pool.d.ts.map +1 -0
  91. package/dist/vector3Pool.js +28 -0
  92. package/dist/vector3Pool.js.map +1 -0
  93. package/dist/vector4.d.ts +180 -0
  94. package/dist/vector4.d.ts.map +1 -0
  95. package/dist/vector4.js +333 -0
  96. package/dist/vector4.js.map +1 -0
  97. package/dist/vector4Pool.d.ts +6 -0
  98. package/dist/vector4Pool.d.ts.map +1 -0
  99. package/dist/vector4Pool.js +29 -0
  100. package/dist/vector4Pool.js.map +1 -0
  101. package/package.json +38 -0
  102. package/src/aabb.test.ts +341 -0
  103. package/src/boundingSphere.test.ts +247 -0
  104. package/src/capsule.test.ts +157 -0
  105. package/src/frustum.test.ts +160 -0
  106. package/src/matrix.test.ts +1111 -0
  107. package/src/matrix3.test.ts +752 -0
  108. package/src/matrix3Pool.test.ts +73 -0
  109. package/src/matrix4.test.ts +1627 -0
  110. package/src/matrix4Pool.test.ts +71 -0
  111. package/src/matrixPool.test.ts +69 -0
  112. package/src/obb.test.ts +183 -0
  113. package/src/plane.test.ts +225 -0
  114. package/src/quaternion.test.ts +531 -0
  115. package/src/quaternionPool.test.ts +64 -0
  116. package/src/ray3d.test.ts +297 -0
  117. package/src/rectangle.test.ts +982 -0
  118. package/src/rectanglePool.test.ts +71 -0
  119. package/src/typedarray.test.ts +118 -0
  120. package/src/vector2.test.ts +958 -0
  121. package/src/vector2Pool.test.ts +65 -0
  122. package/src/vector3.test.ts +749 -0
  123. package/src/vector3Pool.test.ts +68 -0
  124. package/src/vector4.test.ts +660 -0
  125. package/src/vector4Pool.test.ts +71 -0
@@ -0,0 +1,660 @@
1
+ import {
2
+ addVector4,
3
+ clampVector4,
4
+ cloneVector4,
5
+ copyVector4,
6
+ createVector3,
7
+ createVector4,
8
+ divideVector4,
9
+ equalsVector4,
10
+ getVector4AngleBetween,
11
+ getVector4Distance,
12
+ getVector4DistanceSquared,
13
+ getVector4Dot,
14
+ getVector4Length,
15
+ getVector4LengthSquared,
16
+ interpolateVector4,
17
+ maxVector4,
18
+ minVector4,
19
+ multiplyVector4,
20
+ nearEqualsVector4,
21
+ negateVector4,
22
+ normalizeVector4,
23
+ offsetVector4,
24
+ projectVector4,
25
+ reflectVector4,
26
+ scaleVector4,
27
+ setVector4,
28
+ setVector4FromFloat32Array,
29
+ setVector4FromVector3,
30
+ subtractVector4,
31
+ VECTOR4_W_UNIT,
32
+ VECTOR4_X_AXIS,
33
+ VECTOR4_Y_AXIS,
34
+ VECTOR4_Z_AXIS,
35
+ writeVector4ToFloat32Array,
36
+ } from '@flighthq/geometry';
37
+ import type { Vector4 } from '@flighthq/types';
38
+
39
+ describe('addVector4', () => {
40
+ it('returns a new vector when no target is passed', () => {
41
+ const a = createVector4(1, 2, 3, 10);
42
+ const b = createVector4(4, 5, 6, 10);
43
+ const result = createVector4();
44
+ addVector4(result, a, b);
45
+ expect(result.x).toBe(5);
46
+ expect(result.y).toBe(7);
47
+ expect(result.z).toBe(9);
48
+ expect(result.w).toBe(20);
49
+ });
50
+
51
+ it('modifies target when same object is passed as target', () => {
52
+ const a = createVector4(1, 2, 3, 4);
53
+ addVector4(a, a, a); // passing the same object as both source and target
54
+ expect(a.x).toBe(2);
55
+ expect(a.y).toBe(4);
56
+ expect(a.z).toBe(6);
57
+ expect(a.w).toBe(8);
58
+ });
59
+
60
+ it('supports out === a', () => {
61
+ const a = createVector4(1, 2, 3, 4);
62
+ const b = createVector4(4, 5, 6, 7);
63
+ addVector4(a, a, b);
64
+ expect(a.x).toBe(5);
65
+ expect(a.y).toBe(7);
66
+ expect(a.z).toBe(9);
67
+ expect(a.w).toBe(11);
68
+ });
69
+
70
+ it('supports out === b', () => {
71
+ const a = createVector4(1, 2, 3, 4);
72
+ const b = createVector4(4, 5, 6, 7);
73
+ addVector4(b, a, b);
74
+ expect(b.x).toBe(5);
75
+ expect(b.y).toBe(7);
76
+ expect(b.z).toBe(9);
77
+ expect(b.w).toBe(11);
78
+ });
79
+
80
+ it('allows vector-like objects', () => {
81
+ const a = { x: 1, y: 2, z: 3, w: 10 };
82
+ const b = { x: 4, y: 5, z: 6, w: 10 };
83
+ const result = { x: 0, y: 0, z: 0, w: 0 };
84
+ addVector4(result, a, b);
85
+ expect(result.x).toBe(5);
86
+ expect(result.y).toBe(7);
87
+ expect(result.z).toBe(9);
88
+ expect(result.w).toBe(20);
89
+ });
90
+ });
91
+
92
+ describe('clampVector4', () => {
93
+ it('clamps each component independently', () => {
94
+ const out = createVector4();
95
+ clampVector4(out, createVector4(5, -2, 1, 10), createVector4(0, 0, 0, 0), createVector4(3, 3, 3, 3));
96
+ expect(out.x).toBe(3);
97
+ expect(out.y).toBe(0);
98
+ expect(out.z).toBe(1);
99
+ expect(out.w).toBe(3);
100
+ });
101
+ });
102
+
103
+ describe('cloneVector4', () => {
104
+ it('creates a new independent vector', () => {
105
+ const original = createVector4(1, 2, 3, 4);
106
+ const cloned: Vector4 = cloneVector4(original);
107
+ expect(cloned).not.toBe(original); // ensures a new instance
108
+ expect(cloned).not.toBeNull();
109
+ expect(cloned.x).toBe(1);
110
+ expect(cloned.y).toBe(2);
111
+ expect(cloned.z).toBe(3);
112
+ expect(cloned.w).toBe(4);
113
+ });
114
+
115
+ it('allows vector-like objects', () => {
116
+ const original = { x: 1, y: 2, z: 3, w: 4 };
117
+ const cloned: Vector4 = cloneVector4(original);
118
+ expect(cloned).not.toBe(original); // ensures a new instance
119
+ expect(cloned).not.toBeNull();
120
+ expect(cloned.x).toBe(1);
121
+ expect(cloned.y).toBe(2);
122
+ expect(cloned.z).toBe(3);
123
+ expect(cloned.w).toBe(4);
124
+ });
125
+ });
126
+
127
+ describe('copyVector4', () => {
128
+ it('copies values from source to target', () => {
129
+ const source = createVector4(1, 2, 3, 4);
130
+ const target = createVector4();
131
+ copyVector4(target, source);
132
+ expect(target.x).toBe(1);
133
+ expect(target.y).toBe(2);
134
+ expect(target.z).toBe(3);
135
+ expect(target.w).toBe(4);
136
+ });
137
+
138
+ it('does not affect source when same object is used for input and output', () => {
139
+ const vector = createVector4(1, 2, 3, 4);
140
+ copyVector4(vector, vector);
141
+ expect(vector.x).toBe(1);
142
+ expect(vector.y).toBe(2);
143
+ expect(vector.z).toBe(3);
144
+ expect(vector.w).toBe(4);
145
+ });
146
+ });
147
+
148
+ describe('createVector4', () => {
149
+ it('creates a createVector4 with default values', () => {
150
+ const v = createVector4();
151
+ expect(v.x).toBe(0);
152
+ expect(v.y).toBe(0);
153
+ expect(v.z).toBe(0);
154
+ expect(v.w).toBe(0);
155
+ });
156
+
157
+ it('creates a createVector4 with specified values', () => {
158
+ const v = createVector4(1, 2, 3, 4);
159
+ expect(v.x).toBe(1);
160
+ expect(v.y).toBe(2);
161
+ expect(v.z).toBe(3);
162
+ expect(v.w).toBe(4);
163
+ });
164
+ });
165
+
166
+ describe('divideVector4', () => {
167
+ it('divides component-wise', () => {
168
+ const out = createVector4();
169
+ divideVector4(out, createVector4(6, 8, 9, 12), createVector4(2, 4, 3, 6));
170
+ expect(out.x).toBe(3);
171
+ expect(out.y).toBe(2);
172
+ expect(out.z).toBe(3);
173
+ expect(out.w).toBe(2);
174
+ });
175
+
176
+ it('produces 0 for zero divisor components', () => {
177
+ const out = createVector4();
178
+ divideVector4(out, createVector4(6, 8, 9, 12), createVector4(0, 4, 0, 6));
179
+ expect(out.x).toBe(0);
180
+ expect(out.y).toBe(2);
181
+ expect(out.z).toBe(0);
182
+ expect(out.w).toBe(2);
183
+ });
184
+ });
185
+
186
+ describe('equalsVector4', () => {
187
+ it('returns true if vectors are equal', () => {
188
+ const a = createVector4(1, 2, 3, 4);
189
+ const b = createVector4(1, 2, 3, 4);
190
+ expect(equalsVector4(a, b)).toBe(true);
191
+ });
192
+
193
+ it('returns false if vectors are not equal', () => {
194
+ const a = createVector4(1, 2, 3, 4);
195
+ const b = createVector4(4, 5, 6, 7);
196
+ expect(equalsVector4(a, b)).toBe(false);
197
+ });
198
+ });
199
+
200
+ describe('getVector4AngleBetween', () => {
201
+ it('returns 0 for identical vectors', () => {
202
+ const a = createVector4(1, 0, 0, 0);
203
+ expect(getVector4AngleBetween(a, a)).toBeCloseTo(0);
204
+ });
205
+
206
+ it('returns PI/2 for perpendicular vectors', () => {
207
+ const a = createVector4(1, 0, 0, 0);
208
+ const b = createVector4(0, 1, 0, 0);
209
+ expect(getVector4AngleBetween(a, b)).toBeCloseTo(Math.PI / 2);
210
+ });
211
+
212
+ it('returns NaN for a zero-length vector', () => {
213
+ const a = createVector4(0, 0, 0, 0);
214
+ const b = createVector4(1, 0, 0, 0);
215
+ expect(getVector4AngleBetween(a, b)).toBeNaN();
216
+ });
217
+ });
218
+
219
+ describe('getVector4Distance', () => {
220
+ it('returns the distance between two vectors', () => {
221
+ const a = createVector4(1, 1, 1, 1);
222
+ const b = createVector4(4, 5, 6, 5);
223
+ // dx=3, dy=4, dz=5, dw=4
224
+ expect(getVector4Distance(a, b)).toBeCloseTo(Math.sqrt(66));
225
+ });
226
+ });
227
+
228
+ describe('getVector4DistanceSquared', () => {
229
+ it('returns the squared distance between two vectors', () => {
230
+ const a = createVector4(1, 1, 1, 1);
231
+ const b = createVector4(4, 5, 6, 5);
232
+ // dx=3, dy=4, dz=5, dw=4
233
+ expect(getVector4DistanceSquared(a, b)).toBe(66);
234
+ });
235
+ });
236
+
237
+ describe('getVector4Dot', () => {
238
+ it('returns the dot product of two vectors', () => {
239
+ const a = createVector4(1, 2, 3, 4);
240
+ const b = createVector4(4, 5, 6, 7);
241
+ expect(getVector4Dot(a, b)).toBe(1 * 4 + 2 * 5 + 3 * 6 + 4 * 7);
242
+ });
243
+ });
244
+
245
+ describe('getVector4Length', () => {
246
+ it('returns the length of the vector', () => {
247
+ const v = createVector4(3, 4, 0, 12);
248
+ expect(getVector4Length(v)).toBe(13);
249
+ });
250
+
251
+ it('allows a vector-like object', () => {
252
+ const v = { x: 3, y: 4, z: 0, w: 12 };
253
+ expect(getVector4Length(v)).toBe(13);
254
+ });
255
+ });
256
+
257
+ describe('getVector4LengthSquared', () => {
258
+ it('returns the squared length of the vector', () => {
259
+ const v = createVector4(3, 4, 0, 12);
260
+ expect(getVector4LengthSquared(v)).toBe(169); // 3^2 + 4^2 + 12^2 = 169
261
+ });
262
+
263
+ it('allows a vector-like object', () => {
264
+ const v = { x: 3, y: 4, z: 0, w: 12 };
265
+ expect(getVector4LengthSquared(v)).toBe(169);
266
+ });
267
+ });
268
+
269
+ describe('interpolateVector4', () => {
270
+ it('returns a at t=0 and b at t=1', () => {
271
+ const out = createVector4();
272
+ const a = createVector4(1, 2, 3, 4);
273
+ const b = createVector4(5, 6, 7, 8);
274
+ interpolateVector4(out, a, b, 0);
275
+ expect(out.x).toBe(1);
276
+ expect(out.y).toBe(2);
277
+ expect(out.z).toBe(3);
278
+ expect(out.w).toBe(4);
279
+ interpolateVector4(out, a, b, 1);
280
+ expect(out.x).toBe(5);
281
+ expect(out.y).toBe(6);
282
+ expect(out.z).toBe(7);
283
+ expect(out.w).toBe(8);
284
+ });
285
+
286
+ it('interpolates midpoint at t=0.5', () => {
287
+ const out = createVector4();
288
+ interpolateVector4(out, createVector4(0, 0, 0, 0), createVector4(2, 4, 6, 8), 0.5);
289
+ expect(out.x).toBe(1);
290
+ expect(out.y).toBe(2);
291
+ expect(out.z).toBe(3);
292
+ expect(out.w).toBe(4);
293
+ });
294
+
295
+ it('supports out === a', () => {
296
+ const a = createVector4(0, 0, 0, 0);
297
+ interpolateVector4(a, a, createVector4(2, 4, 6, 8), 0.5);
298
+ expect(a.x).toBe(1);
299
+ expect(a.y).toBe(2);
300
+ expect(a.z).toBe(3);
301
+ expect(a.w).toBe(4);
302
+ });
303
+ });
304
+
305
+ describe('maxVector4', () => {
306
+ it('returns the component-wise maximum', () => {
307
+ const out = createVector4();
308
+ maxVector4(out, createVector4(1, 5, 2, 9), createVector4(3, 2, 7, 4));
309
+ expect(out.x).toBe(3);
310
+ expect(out.y).toBe(5);
311
+ expect(out.z).toBe(7);
312
+ expect(out.w).toBe(9);
313
+ });
314
+ });
315
+
316
+ describe('minVector4', () => {
317
+ it('returns the component-wise minimum', () => {
318
+ const out = createVector4();
319
+ minVector4(out, createVector4(1, 5, 2, 9), createVector4(3, 2, 7, 4));
320
+ expect(out.x).toBe(1);
321
+ expect(out.y).toBe(2);
322
+ expect(out.z).toBe(2);
323
+ expect(out.w).toBe(4);
324
+ });
325
+ });
326
+
327
+ describe('multiplyVector4', () => {
328
+ it('multiplies component-wise (Hadamard)', () => {
329
+ const out = createVector4();
330
+ multiplyVector4(out, createVector4(2, 3, 4, 5), createVector4(6, 7, 8, 9));
331
+ expect(out.x).toBe(12);
332
+ expect(out.y).toBe(21);
333
+ expect(out.z).toBe(32);
334
+ expect(out.w).toBe(45);
335
+ });
336
+ });
337
+
338
+ describe('nearEqualsVector4', () => {
339
+ it('returns true for identical vectors', () => {
340
+ const a = createVector4(1, 2, 3, 4);
341
+ expect(nearEqualsVector4(a, a)).toBe(true);
342
+ });
343
+
344
+ it('returns true when difference is within default tolerance', () => {
345
+ const a = createVector4(1, 2, 3, 4);
346
+ const b = createVector4(1 + 1e-7, 2, 3, 4);
347
+ expect(nearEqualsVector4(a, b)).toBe(true);
348
+ });
349
+
350
+ it('returns false when difference exceeds default tolerance', () => {
351
+ const a = createVector4(1, 2, 3, 4);
352
+ const b = createVector4(1 + 1e-5, 2, 3, 4);
353
+ expect(nearEqualsVector4(a, b)).toBe(false);
354
+ });
355
+
356
+ it('respects a custom tolerance', () => {
357
+ const a = createVector4(1, 2, 3, 4);
358
+ const b = createVector4(1.05, 2, 3, 4);
359
+ expect(nearEqualsVector4(a, b, 0.1)).toBe(true);
360
+ expect(nearEqualsVector4(a, b, 0.01)).toBe(false);
361
+ });
362
+ });
363
+
364
+ describe('negateVector4', () => {
365
+ it('inverts the values of the vector components', () => {
366
+ const v = createVector4(1, -2, 3, -4);
367
+ const result = createVector4();
368
+ negateVector4(result, v);
369
+ expect(result.x).toBe(-1);
370
+ expect(result.y).toBe(2);
371
+ expect(result.z).toBe(-3);
372
+ expect(result.w).toBe(4);
373
+ });
374
+
375
+ it('supports out === source', () => {
376
+ const v = createVector4(1, -2, 3, -4);
377
+ negateVector4(v, v);
378
+ expect(v.x).toBe(-1);
379
+ expect(v.y).toBe(2);
380
+ expect(v.z).toBe(-3);
381
+ expect(v.w).toBe(4);
382
+ });
383
+ });
384
+
385
+ // Properties
386
+
387
+ describe('normalizeVector4', () => {
388
+ it('normalizes the vector', () => {
389
+ const v = createVector4(3, 4, 0, 0);
390
+ const result = createVector4();
391
+ const length = normalizeVector4(result, v);
392
+ expect(result.x).toBeCloseTo(0.6, 5);
393
+ expect(result.y).toBeCloseTo(0.8, 5);
394
+ expect(result.z).toBe(0);
395
+ expect(result.w).toBe(0);
396
+ expect(length).toBe(5);
397
+ });
398
+
399
+ it('supports out === source', () => {
400
+ const v = createVector4(3, 4, 0, 0);
401
+ const length = normalizeVector4(v, v);
402
+ expect(v.x).toBeCloseTo(0.6, 5);
403
+ expect(v.y).toBeCloseTo(0.8, 5);
404
+ expect(v.z).toBe(0);
405
+ expect(v.w).toBe(0);
406
+ expect(length).toBe(5);
407
+ });
408
+
409
+ it('writes zero to out for a zero-length source', () => {
410
+ const v = createVector4(0, 0, 0, 0);
411
+ const result = createVector4(1, 2, 3, 4);
412
+ const length = normalizeVector4(result, v);
413
+ expect(result.x).toBe(0);
414
+ expect(result.y).toBe(0);
415
+ expect(result.z).toBe(0);
416
+ expect(result.w).toBe(0);
417
+ expect(length).toBe(0);
418
+ });
419
+ });
420
+
421
+ describe('offsetVector4', () => {
422
+ it('offsets each component by a scalar per axis', () => {
423
+ const v = createVector4(1, 2, 3, 4);
424
+ const result = createVector4();
425
+ offsetVector4(result, v, 10, 20, 30, 40);
426
+ expect(result.x).toBe(11);
427
+ expect(result.y).toBe(22);
428
+ expect(result.z).toBe(33);
429
+ expect(result.w).toBe(44);
430
+ });
431
+
432
+ it('works with negative deltas', () => {
433
+ const v = createVector4(1, 2, 3, 4);
434
+ const result = createVector4();
435
+ offsetVector4(result, v, -5, -10, -15, -20);
436
+ expect(result.x).toBe(-4);
437
+ expect(result.y).toBe(-8);
438
+ expect(result.z).toBe(-12);
439
+ expect(result.w).toBe(-16);
440
+ });
441
+
442
+ it('supports out === source', () => {
443
+ const v = createVector4(1, 2, 3, 4);
444
+ offsetVector4(v, v, 3, 4, 5, 6);
445
+ expect(v.x).toBe(4);
446
+ expect(v.y).toBe(6);
447
+ expect(v.z).toBe(8);
448
+ expect(v.w).toBe(10);
449
+ });
450
+ });
451
+
452
+ describe('projectVector4', () => {
453
+ it('modifies target when same object is passed as target', () => {
454
+ const v = createVector4(10, 20, 30);
455
+ v.w = 5;
456
+ const result = createVector3();
457
+ projectVector4(result, v);
458
+ expect(result.x).toBe(2);
459
+ expect(result.y).toBe(4);
460
+ expect(result.z).toBe(6);
461
+ });
462
+
463
+ it('supports out === source', () => {
464
+ const v = createVector4(10, 20, 30, 5);
465
+ projectVector4(v, v);
466
+ expect(v.x).toBe(2);
467
+ expect(v.y).toBe(4);
468
+ expect(v.z).toBe(6);
469
+ expect(v.w).toBe(5);
470
+ });
471
+ });
472
+
473
+ describe('reflectVector4', () => {
474
+ it('reflects incident vector about a normal', () => {
475
+ const out = createVector4();
476
+ // Reflect (1, 0, 0, 0) about normal (1, 0, 0, 0) gives (-1, 0, 0, 0)
477
+ reflectVector4(out, createVector4(1, 0, 0, 0), createVector4(1, 0, 0, 0));
478
+ expect(out.x).toBeCloseTo(-1, 6);
479
+ expect(out.y).toBeCloseTo(0, 6);
480
+ expect(out.z).toBeCloseTo(0, 6);
481
+ expect(out.w).toBeCloseTo(0, 6);
482
+ });
483
+
484
+ it('supports out === incident', () => {
485
+ const v = createVector4(1, 0, 0, 0);
486
+ reflectVector4(v, v, createVector4(1, 0, 0, 0));
487
+ expect(v.x).toBeCloseTo(-1, 6);
488
+ });
489
+ });
490
+
491
+ describe('scaleVector4', () => {
492
+ it('scales the vector by a scalar', () => {
493
+ const v = createVector4(1, 1, 1, 1);
494
+ const result = createVector4();
495
+ scaleVector4(result, v, 2);
496
+ expect(result.x).toBe(2);
497
+ expect(result.y).toBe(2);
498
+ expect(result.z).toBe(2);
499
+ expect(result.w).toBe(2);
500
+ });
501
+
502
+ it('supports out === source', () => {
503
+ const v = createVector4(1, 1, 1, 1);
504
+ scaleVector4(v, v, 2);
505
+ expect(v.x).toBe(2);
506
+ expect(v.y).toBe(2);
507
+ expect(v.z).toBe(2);
508
+ expect(v.w).toBe(2);
509
+ });
510
+ });
511
+
512
+ describe('setVector4', () => {
513
+ it('sets the values of the vector', () => {
514
+ const v = createVector4();
515
+ setVector4(v, 5, 10, 15, 5);
516
+ expect(v.x).toBe(5);
517
+ expect(v.y).toBe(10);
518
+ expect(v.z).toBe(15);
519
+ expect(v.w).toBe(5);
520
+ });
521
+
522
+ it('modifies target when same object is passed as target', () => {
523
+ const v = createVector4(1, 2, 3, 4);
524
+ setVector4(v, 5, 10, 15, 5);
525
+ expect(v.x).toBe(5);
526
+ expect(v.y).toBe(10);
527
+ expect(v.z).toBe(15);
528
+ expect(v.w).toBe(5);
529
+ });
530
+ });
531
+
532
+ describe('setVector4FromFloat32Array', () => {
533
+ it('reads x/y/z/w from the array at offset', () => {
534
+ const arr = new Float32Array([0, 1, 2, 3, 4, 5]);
535
+ const out = createVector4();
536
+ setVector4FromFloat32Array(out, 1, arr);
537
+ expect(out.x).toBe(1);
538
+ expect(out.y).toBe(2);
539
+ expect(out.z).toBe(3);
540
+ expect(out.w).toBe(4);
541
+ });
542
+ });
543
+
544
+ describe('setVector4FromVector3', () => {
545
+ it('copies x, y, z and sets w to 0 by default', () => {
546
+ const src = { x: 1, y: 2, z: 3 };
547
+ const out = createVector4();
548
+ setVector4FromVector3(out, src);
549
+ expect(out.x).toBe(1);
550
+ expect(out.y).toBe(2);
551
+ expect(out.z).toBe(3);
552
+ expect(out.w).toBe(0);
553
+ });
554
+
555
+ it('sets w to the provided value', () => {
556
+ const src = { x: 1, y: 2, z: 3 };
557
+ const out = createVector4();
558
+ setVector4FromVector3(out, src, 1);
559
+ expect(out.w).toBe(1);
560
+ });
561
+
562
+ it('is safe when out aliases a part of source via a plain object', () => {
563
+ const src = createVector3(5, 6, 7);
564
+ const out = createVector4();
565
+ setVector4FromVector3(out, src, 0);
566
+ expect(out.x).toBe(5);
567
+ expect(out.y).toBe(6);
568
+ expect(out.z).toBe(7);
569
+ expect(out.w).toBe(0);
570
+ });
571
+ });
572
+
573
+ describe('subtractVector4', () => {
574
+ it('returns a new vector when no target is passed', () => {
575
+ const a = createVector4(4, 5, 6, 7);
576
+ const b = createVector4(1, 2, 3, 4);
577
+ const result = createVector4();
578
+ subtractVector4(result, a, b);
579
+ expect(result.x).toBe(3);
580
+ expect(result.y).toBe(3);
581
+ expect(result.z).toBe(3);
582
+ expect(result.w).toBe(3);
583
+ });
584
+
585
+ it('supports out === source', () => {
586
+ const a = createVector4(4, 5, 6, 7);
587
+ const b = createVector4(1, 2, 3, 4);
588
+ subtractVector4(a, a, b);
589
+ expect(a.x).toBe(3);
590
+ expect(a.y).toBe(3);
591
+ expect(a.z).toBe(3);
592
+ expect(a.w).toBe(3);
593
+ });
594
+
595
+ it('supports out === other', () => {
596
+ const a = createVector4(4, 5, 6, 7);
597
+ const b = createVector4(1, 2, 3, 4);
598
+ subtractVector4(b, a, b);
599
+ expect(b.x).toBe(3);
600
+ expect(b.y).toBe(3);
601
+ expect(b.z).toBe(3);
602
+ expect(b.w).toBe(3);
603
+ });
604
+ });
605
+
606
+ describe('W_UNIT', () => {
607
+ it('returns the unit vector along the W-dimension', () => {
608
+ const wUnit = VECTOR4_W_UNIT;
609
+ expect(wUnit).not.toBeNull();
610
+ expect(wUnit.x).toBe(0);
611
+ expect(wUnit.y).toBe(0);
612
+ expect(wUnit.z).toBe(0);
613
+ expect(wUnit.w).toBe(1);
614
+ });
615
+ });
616
+
617
+ describe('writeVector4ToFloat32Array', () => {
618
+ it('writes x/y/z/w to the array at offset', () => {
619
+ const arr = new Float32Array(6);
620
+ writeVector4ToFloat32Array(arr, 1, createVector4(1, 2, 3, 4));
621
+ expect(arr[0]).toBe(0);
622
+ expect(arr[1]).toBe(1);
623
+ expect(arr[2]).toBe(2);
624
+ expect(arr[3]).toBe(3);
625
+ expect(arr[4]).toBe(4);
626
+ });
627
+ });
628
+
629
+ describe('X_AXIS', () => {
630
+ it('returns the unit vector along the X-axis', () => {
631
+ const xAxis: Vector4 = VECTOR4_X_AXIS;
632
+ expect(xAxis).not.toBeNull();
633
+ expect(xAxis.x).toBe(1);
634
+ expect(xAxis.y).toBe(0);
635
+ expect(xAxis.z).toBe(0);
636
+ expect(xAxis.w).toBe(0);
637
+ });
638
+ });
639
+
640
+ describe('Y_AXIS', () => {
641
+ it('returns the unit vector along the Y-axis', () => {
642
+ const yAxis = VECTOR4_Y_AXIS;
643
+ expect(yAxis).not.toBeNull();
644
+ expect(yAxis.x).toBe(0);
645
+ expect(yAxis.y).toBe(1);
646
+ expect(yAxis.z).toBe(0);
647
+ expect(yAxis.w).toBe(0);
648
+ });
649
+ });
650
+
651
+ describe('Z_AXIS', () => {
652
+ it('returns the unit vector along the Z-axis', () => {
653
+ const zAxis = VECTOR4_Z_AXIS;
654
+ expect(zAxis).not.toBeNull();
655
+ expect(zAxis.x).toBe(0);
656
+ expect(zAxis.y).toBe(0);
657
+ expect(zAxis.z).toBe(1);
658
+ expect(zAxis.w).toBe(0);
659
+ });
660
+ });