@inglorious/utils 3.7.3 → 4.0.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 (69) hide show
  1. package/README.md +67 -3
  2. package/package.json +89 -9
  3. package/src/algorithms/decision-tree.js +3 -3
  4. package/src/algorithms/path-finding.js +6 -6
  5. package/src/data-structures/board.js +97 -15
  6. package/src/data-structures/index.js +2 -2
  7. package/src/data-structures/objects.js +352 -34
  8. package/src/data-structures/string.js +13 -0
  9. package/src/data-structures/tree.js +1 -1
  10. package/src/functions/functions.js +168 -0
  11. package/src/functions/index.js +1 -4
  12. package/src/math/circle.js +5 -7
  13. package/src/math/index.js +0 -4
  14. package/src/math/line.js +3 -3
  15. package/src/math/point.js +10 -9
  16. package/src/math/quaternions.js +20 -4
  17. package/src/math/rectangle.js +4 -4
  18. package/src/math/segment.js +11 -5
  19. package/src/math/vectors.js +471 -65
  20. package/src/physics/acceleration.js +2 -3
  21. package/src/physics/friction.js +2 -2
  22. package/src/physics/gravity.js +2 -2
  23. package/src/physics/jump.js +0 -4
  24. package/src/physics/velocity.js +2 -3
  25. package/src/v.js +1 -1
  26. package/types/algorithms/decision-tree.d.ts +27 -0
  27. package/types/algorithms/index.d.ts +2 -0
  28. package/types/algorithms/path-finding.d.ts +69 -0
  29. package/types/data-structures/array.d.ts +56 -0
  30. package/types/data-structures/board.d.ts +121 -0
  31. package/types/data-structures/boolean.d.ts +4 -0
  32. package/types/data-structures/heap.d.ts +69 -0
  33. package/types/data-structures/index.d.ts +8 -0
  34. package/types/data-structures/objects.d.ts +237 -0
  35. package/types/data-structures/set.d.ts +4 -0
  36. package/types/data-structures/string.d.ts +7 -0
  37. package/types/data-structures/tree.d.ts +21 -0
  38. package/types/functions/functions.d.ts +57 -0
  39. package/types/functions/index.d.ts +1 -0
  40. package/types/index.d.ts +6 -4
  41. package/types/math/circle.d.ts +22 -0
  42. package/types/math/hitmask.d.ts +20 -0
  43. package/types/math/index.d.ts +14 -0
  44. package/types/math/line.d.ts +11 -0
  45. package/types/math/linear-interpolation.d.ts +2 -0
  46. package/types/math/numbers.d.ts +26 -0
  47. package/types/math/point.d.ts +25 -0
  48. package/types/math/quaternions.d.ts +10 -0
  49. package/types/math/rectangle.d.ts +36 -0
  50. package/types/math/rng.d.ts +14 -0
  51. package/types/math/segment.d.ts +23 -0
  52. package/types/math/statistics.d.ts +11 -0
  53. package/types/math/triangle.d.ts +5 -0
  54. package/types/math/trigonometry.d.ts +26 -0
  55. package/types/math/vectors.d.ts +190 -0
  56. package/types/physics/acceleration.d.ts +24 -0
  57. package/types/physics/friction.d.ts +11 -0
  58. package/types/physics/gravity.d.ts +20 -0
  59. package/types/physics/index.d.ts +5 -0
  60. package/types/physics/jump.d.ts +10 -0
  61. package/types/physics/velocity.d.ts +20 -0
  62. package/types/v.d.ts +7 -3
  63. package/src/data-structures/object.js +0 -320
  64. package/src/functions/function.js +0 -9
  65. package/src/math/quaternion.js +0 -22
  66. package/src/math/vector.js +0 -426
  67. package/types/algorithms.d.ts +0 -26
  68. package/types/data-structures.d.ts +0 -53
  69. package/types/math.d.ts +0 -90
@@ -1,12 +1,41 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector2} Vector2
3
- * @typedef {import("../../types/math").Vector3} Vector3
4
- * @typedef {import("../../types/math").Vector7} Vector7
2
+ * @typedef {import("../../types/math/vectors").Vector} Vector
3
+ * @typedef {import("../../types/math/vectors").Vector2} Vector2
4
+ * @typedef {import("../../types/math/vectors").Vector3} Vector3
5
+ * @typedef {import("../../types/math/vectors").Vector7} Vector7
5
6
  */
6
7
 
7
8
  import { v } from "../v.js"
8
- import { mod as nMod } from "./numbers.js"
9
- import { magnitude, shift } from "./vector.js"
9
+ import {
10
+ abs as nAbs,
11
+ clamp as nClamp,
12
+ mod as nMod,
13
+ snap as nSnap,
14
+ } from "./numbers.js"
15
+ import { quaternion } from "./quaternions.js"
16
+ import { hypothenuse } from "./triangle.js"
17
+ import { atan2, cos, sin } from "./trigonometry.js"
18
+
19
+ const ZERO_VECTOR = v(0, 0, 0) // eslint-disable-line no-magic-numbers
20
+ const UNIT_VECTOR = v(1, 0, 0) // eslint-disable-line no-magic-numbers
21
+
22
+ const X = 0
23
+ const Y = 1
24
+ const Z = 2
25
+ const LAST_COORDINATE = 1
26
+ const TWO_COORDINATES = 2
27
+ const NO_Y = 0
28
+ const DEFAULT_PRECISION = 1
29
+ const DEFAULT_DECIMALS = 0
30
+
31
+ /**
32
+ * Returns the absolute value of each component in the vector.
33
+ * @param {Vector} vector - The input vector.
34
+ * @returns {Vector} The vector with absolute values.
35
+ */
36
+ export function abs(vector) {
37
+ return v(...vector.map(nAbs))
38
+ }
10
39
 
11
40
  /**
12
41
  * Alias for the sum function.
@@ -14,6 +43,65 @@ import { magnitude, shift } from "./vector.js"
14
43
  */
15
44
  export const add = sum
16
45
 
46
+ /**
47
+ * Calculates the angle of the vector in radians.
48
+ * @param {Vector} vector - The input vector.
49
+ * @returns {number} The angle of the vector in the XZ plane (for 3D) or XY plane (for 2D), in radians.
50
+ */
51
+ export function angle(vector) {
52
+ return atan2(vector[vector.length - LAST_COORDINATE], vector[X])
53
+ }
54
+
55
+ /**
56
+ * Clamps the magnitude of the vector between the given min and max values.
57
+ * @param {Vector} vector - The input vector.
58
+ * @param {number|Vector} min - The minimum magnitude or a vector representing the lower bounds for each component.
59
+ * @param {number|Vector} max - The maximum magnitude or a vector representing the upper bounds for each component.
60
+ * @returns {Vector} The clamped vector.
61
+ */
62
+ export function clamp(vector, min, max) {
63
+ const length = magnitude(vector)
64
+
65
+ if (typeof min === "number" && length < min) {
66
+ return setMagnitude(vector, min)
67
+ }
68
+
69
+ if (typeof max === "number" && length > max) {
70
+ return setMagnitude(vector, max)
71
+ }
72
+
73
+ if (typeof min !== "number" && typeof max !== "number") {
74
+ return v(
75
+ ...vector.map((coordinate, index) =>
76
+ nClamp(coordinate, min[index], max[index]),
77
+ ),
78
+ )
79
+ }
80
+
81
+ return vector
82
+ }
83
+
84
+ /**
85
+ * Returns the conjugate of the vector.
86
+ * @param {Vector} vector - The input vector.
87
+ * @returns {Vector} The conjugated vector.
88
+ */
89
+ export function conjugate(vector) {
90
+ return v(
91
+ ...vector.map((coordinate, index) => (index ? -coordinate : coordinate)),
92
+ )
93
+ }
94
+
95
+ /**
96
+ * Creates a 3D vector with the given magnitude and angle.
97
+ * @param {number} magnitude - The magnitude of the vector.
98
+ * @param {number} angle - The angle of the vector in radians.
99
+ * @returns {Vector3} The created 3D vector.
100
+ */
101
+ export function createVector(magnitude, angle) {
102
+ return scale(fromAngle(angle), magnitude)
103
+ }
104
+
17
105
  /**
18
106
  * Computes the cross product of multiple vectors.
19
107
  * @param {...Vector3 | Vector7} vectors - The vectors to compute the cross product for.
@@ -33,12 +121,23 @@ export function distance(...vectors) {
33
121
  }
34
122
 
35
123
  /**
36
- * Computes the component-wise division of multiple vectors.
37
- * @param {...Vector2 | Vector3} vectors - The vectors to divide.
124
+ * Computes the component-wise division of vectors. A scalar operand is applied
125
+ * to every component.
126
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to divide, or a scalar to divide each component by.
38
127
  * @returns {Vector2 | Vector3} The resulting vector.
39
128
  */
40
- export function divide(...vectors) {
41
- return v(...vectors.reduce(divideCoordinates))
129
+ export function divide(...operands) {
130
+ return v(...operands.reduce(divideCoordinates))
131
+ }
132
+
133
+ /**
134
+ * Divides a scalar by each component of the vector.
135
+ * @param {number} scalar - The dividend.
136
+ * @param {Vector} vector - The divisor vector.
137
+ * @returns {Vector} The resulting vector.
138
+ */
139
+ export function divideBy(scalar, vector) {
140
+ return v(...vector.map((coordinate) => scalar / coordinate))
42
141
  }
43
142
 
44
143
  /**
@@ -52,6 +151,25 @@ export function dot(...vectors) {
52
151
  .reduce((coord1, coord2) => coord1 + coord2)
53
152
  }
54
153
 
154
+ /**
155
+ * Converts a 2D vector [x, z] into a 3D vector [x, 0, z].
156
+ * @param {Vector2} vector - A 2D vector represented as [x, z].
157
+ * @returns {Vector3} A 3D vector represented as [x, 0, z].
158
+ */
159
+ export function from2D(vector) {
160
+ const [x, z] = vector
161
+ return v(x, NO_Y, z)
162
+ }
163
+
164
+ /**
165
+ * Creates a 3D unit vector from the given angle in the XZ plane.
166
+ * @param {number} angle - The angle in radians.
167
+ * @returns {Vector3} The unit vector.
168
+ */
169
+ export function fromAngle(angle) {
170
+ return rotate(UNIT_VECTOR, angle)
171
+ }
172
+
55
173
  /**
56
174
  * Alias for the multiply function.
57
175
  * @type {typeof multiply}
@@ -59,30 +177,114 @@ export function dot(...vectors) {
59
177
  export const hadamard = multiply
60
178
 
61
179
  /**
62
- * Computes the component-wise modulus of multiple vectors.
63
- * @param {...Vector2 | Vector3} vectors - The vectors to compute the modulus for.
180
+ * Checks if a value is a vector.
181
+ * This is determined by checking for the `__isVector__` property, which is
182
+ * added by the `v()` factory function for efficient type checking.
183
+ * @param {*} value - The value to check.
184
+ * @returns {boolean} True if the value is a vector, false otherwise.
185
+ */
186
+ export function isVector(value) {
187
+ return !!value?.__isVector__
188
+ }
189
+
190
+ /**
191
+ * Calculates the magnitude (length) of the vector.
192
+ * @param {Vector} vector - The input vector.
193
+ * @returns {number} The magnitude of the vector.
194
+ */
195
+ export function magnitude(vector) {
196
+ return hypothenuse(...vector)
197
+ }
198
+
199
+ export const length = magnitude
200
+
201
+ /**
202
+ * Computes the component-wise modulus of vectors. A scalar operand is applied
203
+ * to every component.
204
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to compute the modulus for, or a scalar divisor for each component.
64
205
  * @returns {Vector2 | Vector3} The resulting vector after the modulus.
65
206
  */
66
- export function mod(...vectors) {
67
- return v(...vectors.reduce(modCoordinates))
207
+ export function mod(...operands) {
208
+ return v(...operands.reduce(modCoordinates))
68
209
  }
69
210
 
70
211
  /**
71
- * Computes the component-wise multiplication of multiple vectors (Hadamard product).
72
- * @param {...Vector2 | Vector3} vectors - The vectors to multiply.
212
+ * Calculates the modulus of a scalar with each component of the vector.
213
+ * @param {number} scalar - The dividend.
214
+ * @param {Vector} vector - The divisor vector.
215
+ * @returns {Vector} The resulting vector.
216
+ */
217
+ export function modOf(scalar, vector) {
218
+ return v(...vector.map((coordinate) => nMod(scalar, coordinate)))
219
+ }
220
+
221
+ /**
222
+ * Computes the component-wise multiplication of vectors. A scalar operand is
223
+ * applied to every component.
224
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to multiply, or a scalar to multiply each component by.
73
225
  * @returns {Vector2 | Vector3} The resulting vector.
74
226
  */
75
- export function multiply(...vectors) {
76
- return v(...vectors.reduce(multiplyCoordinates))
227
+ export function multiply(...operands) {
228
+ return v(...operands.reduce(multiplyCoordinates))
77
229
  }
78
230
 
79
231
  /**
80
- * Computes the component-wise power of multiple vectors.
81
- * @param {...Vector2 | Vector3} vectors - The vectors to compute the power for.
232
+ * Normalizes the vector to have a magnitude of 1.
233
+ * @param {Vector} vector - The input vector.
234
+ * @returns {Vector} The normalized vector.
235
+ */
236
+ export function normalize(vector) {
237
+ const length = magnitude(vector)
238
+ return v(...vector.map((coordinate) => coordinate / length))
239
+ }
240
+
241
+ /**
242
+ * Alias for the power function.
243
+ * @type {typeof power}
244
+ */
245
+ export const pow = power
246
+
247
+ /**
248
+ * Computes the component-wise power of vectors. A scalar operand is applied
249
+ * to every component.
250
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to compute the power for, or a scalar exponent for each component.
82
251
  * @returns {Vector2 | Vector3} The resulting vector after the power.
83
252
  */
84
- export function power(...vectors) {
85
- return v(...vectors.reduce(powerCoordinates))
253
+ export function power(...operands) {
254
+ return v(...operands.reduce(powerCoordinates))
255
+ }
256
+
257
+ /**
258
+ * Raises a scalar to the power of each component of the vector.
259
+ * @param {number} scalar - The base value.
260
+ * @param {Vector} vector - The exponent vector.
261
+ * @returns {Vector} The resulting vector.
262
+ */
263
+ export function powerOf(scalar, vector) {
264
+ return v(...vector.map((coordinate) => scalar ** coordinate))
265
+ }
266
+
267
+ /**
268
+ * Alias for the mod function.
269
+ * @type {typeof mod}
270
+ */
271
+ export const remainder = mod
272
+
273
+ /**
274
+ * Rotates the vector by the given angle. Handles 2D and 3D vectors.
275
+ * For 3D vectors, rotation is around the Y-axis.
276
+ * @param {Vector} vector - The input vector (2D or 3D).
277
+ * @param {number} angle - The angle in radians.
278
+ * @returns {Vector} The rotated vector.
279
+ */
280
+ export function rotate(vector, angle) {
281
+ const is2D = vector.length === TWO_COORDINATES
282
+
283
+ const vector3 = is2D ? from2D(vector) : vector
284
+
285
+ const result = rotateWithQuaternion(vector3, angle)
286
+
287
+ return is2D ? to2D(result) : result
86
288
  }
87
289
 
88
290
  /**
@@ -91,6 +293,63 @@ export function power(...vectors) {
91
293
  */
92
294
  export const scalarProduct = dot
93
295
 
296
+ /**
297
+ * Alias for the multiply function.
298
+ * @type {typeof multiply}
299
+ */
300
+ export const scale = multiply
301
+
302
+ /**
303
+ * Sets the angle of the vector in the XZ plane while maintaining its magnitude.
304
+ * @param {Vector} vector - The input vector.
305
+ * @param {number} angle - The new angle in radians.
306
+ * @returns {Vector3} The vector with the updated angle.
307
+ */
308
+ export function setAngle(vector, angle) {
309
+ const length = magnitude(vector)
310
+ const [x, z] = toCartesian([length, angle])
311
+ return v(x, NO_Y, z)
312
+ }
313
+
314
+ /**
315
+ * Alias for the setMagnitude function.
316
+ * @type {typeof setMagnitude}
317
+ */
318
+ export const setLength = setMagnitude
319
+
320
+ /**
321
+ * Sets the magnitude of the vector while maintaining its direction.
322
+ * @param {Vector} vector - The input vector.
323
+ * @param {number} length - The new magnitude.
324
+ * @returns {Vector} The vector with the updated magnitude.
325
+ */
326
+ export function setMagnitude(vector, length) {
327
+ const normalized = normalize(vector)
328
+ return scale(normalized, length)
329
+ }
330
+
331
+ /**
332
+ * Shifts the components of the vector by the given index.
333
+ * @param {Vector} vector - The input vector.
334
+ * @param {number} index - The index to shift by.
335
+ * @returns {Vector} The shifted vector.
336
+ */
337
+ export function shift(vector, index) {
338
+ return v(...vector.slice(index), ...vector.slice(X, index))
339
+ }
340
+
341
+ /**
342
+ * Snaps each component of the vector to the nearest multiple of the given precision.
343
+ * @param {Vector} vector - The input vector.
344
+ * @param {number} [precision=DEFAULT_PRECISION] - The precision value.
345
+ * @returns {Vector} The snapped vector.
346
+ */
347
+ export function snap(vector, precision = DEFAULT_PRECISION) {
348
+ return v(
349
+ ...vector.map((coordinate) => nSnap(coordinate, -precision, precision)),
350
+ )
351
+ }
352
+
94
353
  /**
95
354
  * Subtracts multiple vectors.
96
355
  * @param {...Vector2 | Vector3} vectors - The vectors to subtract.
@@ -110,71 +369,121 @@ export function sum(...vectors) {
110
369
  }
111
370
 
112
371
  /**
113
- * Alias for the cross product function.
114
- * @type {typeof cross}
372
+ * Alias for the multiply function.
373
+ * @type {typeof multiply}
115
374
  */
116
- export const vectorProduct = cross
375
+ export const times = multiply
117
376
 
118
377
  /**
119
- * Adds the coordinates of two vectors.
120
- * @param {Vector2 | Vector3} vector1 - The first vector.
121
- * @param {Vector2 | Vector3} vector2 - The second vector.
122
- * @returns {Vector2 | Vector3} The resulting vector after addition.
378
+ * Converts a 3D vector [x, y, z] into a 2D vector [x, z].
379
+ * @param {Vector3} vector - A 3D vector represented as [x, y, z].
380
+ * @returns {Vector2} A 2D vector represented as [x, z].
123
381
  */
124
- function sumCoordinates(vector1, vector2) {
125
- return v(...vector1.map((coordinate, index) => coordinate + vector2[index]))
382
+ export function to2D(vector) {
383
+ const [x, , z] = vector
384
+ return v(x, z)
126
385
  }
127
386
 
128
387
  /**
129
- * Subtracts the coordinates of two vectors.
130
- * @param {Vector2 | Vector3} vector1 - The first vector.
131
- * @param {Vector2 | Vector3} vector2 - The second vector.
132
- * @returns {Vector2 | Vector3} The resulting vector after subtraction.
388
+ * Converts 2D polar coordinates to 2D Cartesian coordinates.
389
+ * @param {Vector2} vector - The polar coordinates [magnitude, angle].
390
+ * @returns {Vector2} The Cartesian coordinates [x, y].
133
391
  */
134
- function subtractCoordinates(vector1, vector2) {
135
- return v(...vector1.map((coordinate, index) => coordinate - vector2[index]))
392
+ export function toCartesian([magnitude, angle]) {
393
+ return v(magnitude * cos(angle), magnitude * sin(angle))
136
394
  }
137
395
 
138
396
  /**
139
- * Divides the coordinates of two vectors component-wise.
140
- * @param {Vector2 | Vector3} vector1 - The dividend vector.
141
- * @param {Vector2 | Vector3} vector2 - The divisor vector.
142
- * @returns {Vector2 | Vector3} The resulting vector.
397
+ * Converts a 3D cartesian vector to cylindrical coordinates.
398
+ * @param {Vector3} vector - The input vector [x, y, z].
399
+ * @returns {Vector3} The cylindrical coordinates [radius, theta, z].
143
400
  */
144
- function divideCoordinates(vector1, vector2) {
145
- return v(...vector1.map((coordinate, index) => coordinate / vector2[index]))
401
+ export function toCylindrical(vector) {
402
+ const radius = magnitude(vector)
403
+ const theta = angle(vector)
404
+ return v(radius * cos(theta), radius * sin(theta), vector[Z])
146
405
  }
147
406
 
148
407
  /**
149
- * Computes the component-wise modulus of two vectors.
150
- * @param {Vector2 | Vector3} vector1 - The first vector.
151
- * @param {Vector2 | Vector3} vector2 - The second vector.
152
- * @returns {Vector2 | Vector3} The resulting vector after the modulus.
408
+ * Converts a 2D cartesian vector to 2D polar coordinates.
409
+ * @param {Vector2} vector - The input vector [x, y].
410
+ * @returns {Vector2} The polar coordinates [magnitude, angle].
153
411
  */
154
- function modCoordinates(vector1, vector2) {
155
- return v(
156
- ...vector1.map((coordinate, index) => nMod(coordinate, vector2[index])),
157
- )
412
+ export function toPolar(vector) {
413
+ return v(magnitude(vector), angle(vector))
158
414
  }
159
415
 
160
416
  /**
161
- * Multiplies the coordinates of two vectors component-wise.
162
- * @param {Vector2 | Vector3} vector1 - The first vector.
163
- * @param {Vector2 | Vector3} vector2 - The second vector.
164
- * @returns {Vector2 | Vector3} The resulting vector.
417
+ * Converts a vector to a string representation.
418
+ * @param {Vector} vector - The input vector.
419
+ * @param {number} [decimals=DEFAULT_DECIMALS] - The number of decimal places.
420
+ * @returns {string} The string representation of the vector.
165
421
  */
166
- function multiplyCoordinates(vector1, vector2) {
167
- return v(...vector1.map((coordinate, index) => coordinate * vector2[index]))
422
+ export function toString(vector, decimals = DEFAULT_DECIMALS) {
423
+ return `[${vector
424
+ .map((coordinate) => coordinate.toFixed(decimals))
425
+ .join(", ")}]`
168
426
  }
169
427
 
170
428
  /**
171
- * Raises the coordinates of the first vector to the power of the second vector's coordinates.
172
- * @param {Vector2 | Vector3} vector1 - The base vector.
173
- * @param {Vector2 | Vector3} vector2 - The exponent vector.
174
- * @returns {Vector2 | Vector3} The resulting vector.
429
+ * Converts a 3D cartesian vector to spherical coordinates [radius, inclination, azimuth].
430
+ * - radius (r): distance from the origin.
431
+ * - inclination (θ): angle from the Y-axis (0 to PI).
432
+ * - azimuth (φ): angle from the X-axis in the XZ-plane (-PI to PI).
433
+ * @param {Vector3} vector The cartesian vector [x, y, z].
434
+ * @returns {Vector3} The spherical coordinates [r, θ, φ].
175
435
  */
176
- function powerCoordinates(vector1, vector2) {
177
- return v(...vector1.map((coordinate, index) => coordinate ** vector2[index]))
436
+ export function toSpherical(vector) {
437
+ const r = magnitude(vector)
438
+
439
+ if (!r) {
440
+ return zero()
441
+ }
442
+
443
+ // In a Y-up system, inclination is the angle with the Y axis.
444
+ const inclination = Math.acos(vector[Y] / r)
445
+ // Azimuth is the angle in the XZ plane, which `angle()` calculates.
446
+ const azimuth = angle(vector)
447
+
448
+ return v(r, inclination, azimuth)
449
+ }
450
+
451
+ /**
452
+ * Creates a 3D unit vector in the XZ plane with the given angle.
453
+ * @param {number} [angle=0] - The angle in radians.
454
+ * @returns {Vector3} The unit vector.
455
+ */
456
+ export function unit(angle) {
457
+ if (!angle) {
458
+ return v(...UNIT_VECTOR)
459
+ }
460
+
461
+ return setAngle(UNIT_VECTOR, angle)
462
+ }
463
+
464
+ /**
465
+ * Alias for the cross product function.
466
+ * @type {typeof cross}
467
+ */
468
+ export const vectorProduct = cross
469
+
470
+ /**
471
+ * Creates a zero vector of 3 dimensions.
472
+ * @returns {Vector3} The zero vector.
473
+ */
474
+ export function zero() {
475
+ return v(...ZERO_VECTOR)
476
+ }
477
+
478
+ /**
479
+ * Reads the value at the given index of a vector operand, broadcasting a
480
+ * scalar operand to every index.
481
+ * @param {number | Vector2 | Vector3 | Vector7} operand - A vector or a scalar.
482
+ * @param {number} index - The index of the coordinate to read.
483
+ * @returns {number} The coordinate value.
484
+ */
485
+ function broadcast(operand, index) {
486
+ return typeof operand === "number" ? operand : operand[index]
178
487
  }
179
488
 
180
489
  /**
@@ -202,11 +511,108 @@ function crossMultiplyCoordinates(vector1, vector2) {
202
511
  }
203
512
 
204
513
  /**
205
- * Multiplies the coordinates of two vectors.
514
+ * Divides the coordinates of two vectors component-wise. Scalars are broadcast.
515
+ * @param {Vector2 | Vector3} vector1 - The dividend vector.
516
+ * @param {number | Vector2 | Vector3} vector2 - The divisor vector or scalar.
517
+ * @returns {Vector2 | Vector3} The resulting vector.
518
+ */
519
+ function divideCoordinates(vector1, vector2) {
520
+ return v(
521
+ ...vector1.map(
522
+ (coordinate, index) => coordinate / broadcast(vector2, index),
523
+ ),
524
+ )
525
+ }
526
+
527
+ /**
528
+ * Multiplies the coordinates of two vectors component-wise. Scalars are broadcast.
206
529
  * @param {Vector2 | Vector3} vector1 - The first vector.
207
- * @param {Vector2 | Vector3} vector2 - The second vector.
208
- * @returns {Vector2 | Vector3} The resulting vector containing multiplied coordinates.
530
+ * @param {number | Vector2 | Vector3} vector2 - The second vector or scalar.
531
+ * @returns {Vector2 | Vector3} The resulting vector.
209
532
  */
210
533
  function dotMultiplyCoordinates(vector1, vector2) {
211
534
  return v(...vector1.map((coordinate, index) => coordinate * vector2[index]))
212
535
  }
536
+
537
+ /**
538
+ * Computes the component-wise modulus of two vectors. Scalars are broadcast.
539
+ * @param {Vector2 | Vector3} vector1 - The first vector.
540
+ * @param {number | Vector2 | Vector3} vector2 - The second vector or scalar.
541
+ * @returns {Vector2 | Vector3} The resulting vector.
542
+ */
543
+ function modCoordinates(vector1, vector2) {
544
+ return v(
545
+ ...vector1.map((coordinate, index) =>
546
+ nMod(coordinate, broadcast(vector2, index)),
547
+ ),
548
+ )
549
+ }
550
+
551
+ /**
552
+ * Multiplies the coordinates of two vectors component-wise. Scalars are broadcast.
553
+ * @param {Vector2 | Vector3} vector1 - The first vector.
554
+ * @param {number | Vector2 | Vector3} vector2 - The second vector or scalar.
555
+ * @returns {Vector2 | Vector3} The resulting vector.
556
+ */
557
+ function multiplyCoordinates(vector1, vector2) {
558
+ return v(
559
+ ...vector1.map(
560
+ (coordinate, index) => coordinate * broadcast(vector2, index),
561
+ ),
562
+ )
563
+ }
564
+
565
+ /**
566
+ * Raises the coordinates of the first vector to the power of the second vector's coordinates. Scalars are broadcast.
567
+ * @param {Vector2 | Vector3} vector1 - The base vector.
568
+ * @param {number | Vector2 | Vector3} vector2 - The exponent vector or scalar.
569
+ * @returns {Vector2 | Vector3} The resulting vector.
570
+ */
571
+ function powerCoordinates(vector1, vector2) {
572
+ return v(
573
+ ...vector1.map(
574
+ (coordinate, index) => coordinate ** broadcast(vector2, index),
575
+ ),
576
+ )
577
+ }
578
+
579
+ /**
580
+ * Subtracts the coordinates of two vectors.
581
+ * @param {Vector2 | Vector3} vector1 - The first vector.
582
+ * @param {Vector2 | Vector3} vector2 - The second vector.
583
+ * @returns {Vector2 | Vector3} The resulting vector after subtraction.
584
+ */
585
+ function subtractCoordinates(vector1, vector2) {
586
+ return v(...vector1.map((coordinate, index) => coordinate - vector2[index]))
587
+ }
588
+
589
+ /**
590
+ * Adds the coordinates of two vectors.
591
+ * @param {Vector2 | Vector3} vector1 - The first vector.
592
+ * @param {Vector2 | Vector3} vector2 - The second vector.
593
+ * @returns {Vector2 | Vector3} The resulting vector after addition.
594
+ */
595
+ function sumCoordinates(vector1, vector2) {
596
+ return v(...vector1.map((coordinate, index) => coordinate + vector2[index]))
597
+ }
598
+
599
+ /**
600
+ * Rotates a 3D vector around the Y-axis using a quaternion.
601
+ * @param {Vector3} vector - The input vector.
602
+ * @param {number} angle - The angle in radians.
603
+ * @returns {Vector3} The rotated vector.
604
+ */
605
+ function rotateWithQuaternion(vector, angle) {
606
+ if (!angle) {
607
+ return vector
608
+ }
609
+
610
+ // @see https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Performance_comparisons
611
+ const [w, ...r] = quaternion(angle)
612
+ const result = sum(
613
+ vector,
614
+ cross(scale(r, 2), sum(cross(r, vector), scale(vector, w))), // eslint-disable-line no-magic-numbers
615
+ )
616
+
617
+ return conjugate(result) // HACK: not really sure why I should invert the result, it just works this way
618
+ }
@@ -1,9 +1,8 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vectors").Vector3} Vector3
3
3
  */
4
4
 
5
- import { clamp, multiply, zero } from "../math/vector.js"
6
- import { sum } from "../math/vectors.js"
5
+ import { clamp, multiply, sum, zero } from "../math/vectors.js"
7
6
  import { applyFriction } from "./friction.js"
8
7
 
9
8
  const DEFAULT_DT = 1 // Default time delta for the applyAcceleration function.
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vectors").Vector3} Vector3
3
3
  */
4
4
 
5
- import { magnitude, setMagnitude, zero } from "../math/vector.js"
5
+ import { magnitude, setMagnitude, zero } from "../math/vectors.js"
6
6
 
7
7
  const DEFAULT_DT = 1 // Default time delta for the applyFriction function.
8
8
  const NO_FRICTION = 0 // No friction constant.
@@ -1,10 +1,10 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vectors").Vector3} Vector3
3
3
  */
4
4
 
5
5
  /* eslint-disable no-magic-numbers */
6
6
 
7
- import { zero } from "../math/vector.js"
7
+ import { zero } from "../math/vectors.js"
8
8
 
9
9
  const DEFAULT_DT = 1 // Default delta time for the applyGravity function.
10
10
  const DEFAULT_JUMP = 0 // Default maximum jump height.
@@ -1,7 +1,3 @@
1
- /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
3
- */
4
-
5
1
  /* eslint-disable no-magic-numbers */
6
2
 
7
3
  const DEFAULT_MAX_JUMP = 0 // Default maximum jump height.