@inglorious/utils 2.3.0 → 3.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 (45) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/algorithms/decision-tree.test.js +7 -6
  4. package/src/algorithms/index.js +4 -0
  5. package/src/algorithms/path-finding.js +2 -2
  6. package/src/data-structures/index.js +10 -0
  7. package/src/functions/index.js +4 -0
  8. package/src/index.js +8 -0
  9. package/src/math/{geometry/circle.js → circle.js} +6 -6
  10. package/src/math/{geometry/circle.test.js → circle.test.js} +23 -22
  11. package/src/math/{geometry/hitmask.test.js → hitmask.test.js} +16 -15
  12. package/src/math/index.js +35 -0
  13. package/src/math/{geometry/line.js → line.js} +4 -6
  14. package/src/math/{geometry/line.test.js → line.test.js} +11 -10
  15. package/src/math/linear-interpolation.js +0 -1
  16. package/src/math/{geometry/point.js → point.js} +5 -5
  17. package/src/math/{geometry/point.test.js → point.test.js} +23 -22
  18. package/src/math/{linear-algebra/quaternion.js → quaternion.js} +4 -4
  19. package/src/math/{linear-algebra/quaternion.test.js → quaternion.test.js} +1 -1
  20. package/src/math/{linear-algebra/quaternions.js → quaternions.js} +7 -4
  21. package/src/math/{linear-algebra/quaternions.test.js → quaternions.test.js} +1 -1
  22. package/src/math/{geometry/rectangle.js → rectangle.js} +3 -5
  23. package/src/math/{geometry/rectangle.test.js → rectangle.test.js} +13 -12
  24. package/src/math/rng.js +0 -2
  25. package/src/math/{geometry/segment.js → segment.js} +5 -9
  26. package/src/math/{geometry/segment.test.js → segment.test.js} +48 -47
  27. package/src/math/{geometry/triangle.js → triangle.js} +1 -1
  28. package/src/math/{geometry/types.d.ts → types.d.ts} +10 -0
  29. package/src/math/{linear-algebra/vector.js → vector.js} +73 -80
  30. package/src/math/{linear-algebra/vector.test.js → vector.test.js} +73 -63
  31. package/src/math/{linear-algebra/vectors.js → vectors.js} +18 -13
  32. package/src/math/{linear-algebra/vectors.test.js → vectors.test.js} +12 -30
  33. package/src/physics/acceleration.js +5 -5
  34. package/src/physics/friction.js +2 -3
  35. package/src/physics/friction.test.js +7 -6
  36. package/src/physics/gravity.js +2 -2
  37. package/src/physics/gravity.test.js +10 -9
  38. package/src/physics/index.js +7 -0
  39. package/src/physics/jump.js +1 -2
  40. package/src/physics/velocity.js +3 -4
  41. package/src/v.js +17 -0
  42. package/src/v.test.js +13 -0
  43. package/src/math/linear-algebra/types.d.ts +0 -5
  44. /package/src/math/{geometry/hitmask.js → hitmask.js} +0 -0
  45. /package/src/math/{geometry/triangle.test.js → triangle.test.js} +0 -0
@@ -4,20 +4,21 @@
4
4
  * @typedef {import('./types').Vector3} Vector3
5
5
  */
6
6
 
7
- import { isArray } from "../../data-structures/array.js"
8
- import { hypothenuse } from "../geometry/triangle.js"
7
+ import { isArray } from "../data-structures/array.js"
8
+ import { v } from "../v.js"
9
9
  import {
10
10
  abs as nAbs,
11
11
  clamp as nClamp,
12
12
  mod as nMod,
13
13
  snap as nSnap,
14
- } from "../numbers.js"
15
- import { atan2, cos, sin } from "../trigonometry.js"
14
+ } from "./numbers.js"
16
15
  import { quaternion } from "./quaternion.js"
16
+ import { hypothenuse } from "./triangle.js"
17
+ import { atan2, cos, sin } from "./trigonometry.js"
17
18
  import { cross, sum } from "./vectors.js"
18
19
 
19
- const ZERO_VECTOR = [0, 0, 0] // eslint-disable-line no-magic-numbers
20
- const UNIT_VECTOR = [1, 0, 0] // eslint-disable-line no-magic-numbers
20
+ const ZERO_VECTOR = v(0, 0, 0) // eslint-disable-line no-magic-numbers
21
+ const UNIT_VECTOR = v(1, 0, 0) // eslint-disable-line no-magic-numbers
21
22
 
22
23
  const X = 0
23
24
  const Y = 1
@@ -30,17 +31,15 @@ const DEFAULT_DECIMALS = 0
30
31
 
31
32
  /**
32
33
  * Returns the absolute value of each component in the vector.
33
- *
34
34
  * @param {Vector} vector - The input vector.
35
35
  * @returns {Vector} The vector with absolute values.
36
36
  */
37
37
  export function abs(vector) {
38
- return vector.map(nAbs)
38
+ return v(...vector.map(nAbs))
39
39
  }
40
40
 
41
41
  /**
42
42
  * Calculates the angle of the vector in radians.
43
- *
44
43
  * @param {Vector} vector - The input vector.
45
44
  * @returns {number} The angle of the vector in the XZ plane (for 3D) or XY plane (for 2D), in radians.
46
45
  */
@@ -50,7 +49,6 @@ export function angle(vector) {
50
49
 
51
50
  /**
52
51
  * Clamps the magnitude of the vector between the given min and max values.
53
- *
54
52
  * @param {Vector} vector - The input vector.
55
53
  * @param {number|Vector} min - The minimum magnitude or a vector representing the lower bounds for each component.
56
54
  * @param {number|Vector} max - The maximum magnitude or a vector representing the upper bounds for each component.
@@ -68,8 +66,10 @@ export function clamp(vector, min, max) {
68
66
  }
69
67
 
70
68
  if (typeof min !== "number" && typeof max !== "number") {
71
- return vector.map((coordinate, index) =>
72
- nClamp(coordinate, min[index], max[index]),
69
+ return v(
70
+ ...vector.map((coordinate, index) =>
71
+ nClamp(coordinate, min[index], max[index]),
72
+ ),
73
73
  )
74
74
  }
75
75
 
@@ -78,17 +78,17 @@ export function clamp(vector, min, max) {
78
78
 
79
79
  /**
80
80
  * Returns the conjugate of the vector.
81
- *
82
81
  * @param {Vector} vector - The input vector.
83
82
  * @returns {Vector} The conjugated vector.
84
83
  */
85
84
  export function conjugate(vector) {
86
- return vector.map((coordinate, index) => (index ? -coordinate : coordinate))
85
+ return v(
86
+ ...vector.map((coordinate, index) => (index ? -coordinate : coordinate)),
87
+ )
87
88
  }
88
89
 
89
90
  /**
90
91
  * Creates a 3D vector with the given magnitude and angle.
91
- *
92
92
  * @param {number} magnitude - The magnitude of the vector.
93
93
  * @param {number} angle - The angle of the vector in radians.
94
94
  * @returns {Vector3} The created 3D vector.
@@ -99,24 +99,22 @@ export function createVector(magnitude, angle) {
99
99
 
100
100
  /**
101
101
  * Divides each component of the vector by the given scalar.
102
- *
103
102
  * @param {Vector} vector - The input vector.
104
103
  * @param {number} scalar - The scalar value.
105
104
  * @returns {Vector} The resulting vector.
106
105
  */
107
106
  export function divide(vector, scalar) {
108
- return vector.map((coordinate) => coordinate / scalar)
107
+ return v(...vector.map((coordinate) => coordinate / scalar))
109
108
  }
110
109
 
111
110
  /**
112
111
  * Converts a 2D vector [x, z] into a 3D vector [x, 0, z].
113
- *
114
112
  * @param {Vector2} vector - A 2D vector represented as [x, z].
115
113
  * @returns {Vector3} A 3D vector represented as [x, 0, z].
116
114
  */
117
115
  export function from2D(vector) {
118
116
  const [x, z] = vector
119
- return [x, NO_Y, z]
117
+ return v(x, NO_Y, z)
120
118
  }
121
119
 
122
120
  /**
@@ -128,24 +126,23 @@ export function fromAngle(angle) {
128
126
  return rotate(UNIT_VECTOR, angle)
129
127
  }
130
128
 
131
- export const length = magnitude
132
-
133
129
  /**
134
130
  * Checks if a value is a vector.
135
- *
131
+ * A vector is an array of numbers. For performance, vectors created with `v()`
132
+ * are tagged and can be identified more quickly.
136
133
  * @param {*} value - The value to check.
137
134
  * @returns {boolean} True if the value is a vector, false otherwise.
138
135
  */
139
136
  export function isVector(value) {
140
137
  return (
141
- isArray(value) &&
142
- value.every((coordinate) => typeof coordinate === "number")
138
+ value?.__isVector__ ||
139
+ (isArray(value) &&
140
+ value.every((coordinate) => typeof coordinate === "number"))
143
141
  )
144
142
  }
145
143
 
146
144
  /**
147
145
  * Calculates the magnitude (length) of the vector.
148
- *
149
146
  * @param {Vector} vector - The input vector.
150
147
  * @returns {number} The magnitude of the vector.
151
148
  */
@@ -153,45 +150,75 @@ export function magnitude(vector) {
153
150
  return hypothenuse(...vector)
154
151
  }
155
152
 
153
+ export const length = magnitude
154
+
156
155
  /**
157
156
  * Calculates the modulus of each component in the vector with the given divisor.
158
- *
159
157
  * @param {Vector} vector - The input vector.
160
158
  * @param {number} divisor - The divisor value.
161
159
  * @returns {Vector} The resulting vector.
162
160
  */
163
161
  export function mod(vector, divisor) {
164
- return vector.map((coordinate) => nMod(coordinate, divisor))
162
+ return v(...vector.map((coordinate) => nMod(coordinate, divisor)))
165
163
  }
166
164
 
167
165
  /**
168
166
  * Multiplies each component of the vector by the given scalar.
169
- *
170
167
  * @param {Vector} vector - The input vector.
171
168
  * @param {number} scalar - The scalar value.
172
169
  * @returns {Vector} The resulting vector.
173
170
  */
174
171
  export function multiply(vector, scalar) {
175
- return vector.map((coordinate) => coordinate * scalar)
172
+ return v(...vector.map((coordinate) => coordinate * scalar))
173
+ }
174
+
175
+ /**
176
+ * Alias for the power function.
177
+ * @type {typeof power}
178
+ */
179
+ export const pow = power
180
+
181
+ /**
182
+ * Raises each component of the vector to the given exponent.
183
+ * @param {Vector} vector - The input vector.
184
+ * @param {number} exponent - The exponent value.
185
+ * @returns {Vector} The resulting vector.
186
+ */
187
+ export function power(vector, exponent) {
188
+ return v(...vector.map((coordinate) => coordinate ** exponent))
176
189
  }
177
190
 
191
+ /**
192
+ * Alias for the multiply function.
193
+ * @type {typeof multiply}
194
+ */
195
+ export const scale = multiply
196
+
197
+ /**
198
+ * Alias for the multiply function.
199
+ * @type {typeof multiply}
200
+ */
201
+ export const times = multiply
202
+
178
203
  /**
179
204
  * Normalizes the vector to have a magnitude of 1.
180
- *
181
205
  * @param {Vector} vector - The input vector.
182
206
  * @returns {Vector} The normalized vector.
183
207
  */
184
208
  export function normalize(vector) {
185
209
  const length = magnitude(vector)
186
- return vector.map((coordinate) => coordinate / length)
210
+ return v(...vector.map((coordinate) => coordinate / length))
187
211
  }
188
212
 
213
+ /**
214
+ * Alias for the mod function.
215
+ * @type {typeof mod}
216
+ */
189
217
  export const remainder = mod
190
218
 
191
219
  /**
192
220
  * Rotates the vector by the given angle. Handles 2D and 3D vectors.
193
221
  * For 3D vectors, rotation is around the Y-axis.
194
- *
195
222
  * @param {Vector} vector - The input vector (2D or 3D).
196
223
  * @param {number} angle - The angle in radians.
197
224
  * @returns {Vector} The rotated vector.
@@ -206,18 +233,8 @@ export function rotate(vector, angle) {
206
233
  return is2D ? to2D(result) : result
207
234
  }
208
235
 
209
- /**
210
- * Scales the vector by the given scalar. Alias of `multiply`.
211
- *
212
- * @param {Vector} vector - The input vector.
213
- * @param {number} scalar - The scalar value.
214
- * @returns {Vector} The resulting vector.
215
- */
216
- export const scale = multiply
217
-
218
236
  /**
219
237
  * Sets the angle of the vector in the XZ plane while maintaining its magnitude.
220
- *
221
238
  * @param {Vector} vector - The input vector.
222
239
  * @param {number} angle - The new angle in radians.
223
240
  * @returns {Vector3} The vector with the updated angle.
@@ -225,17 +242,17 @@ export const scale = multiply
225
242
  export function setAngle(vector, angle) {
226
243
  const length = magnitude(vector)
227
244
  const [x, z] = toCartesian([length, angle])
228
- return [x, NO_Y, z]
245
+ return v(x, NO_Y, z)
229
246
  }
230
247
 
231
248
  /**
232
- * Sets the length of the vector while maintaining its direction. Alias of `setMagnitude`.
249
+ * Alias for the setMagnitude function.
250
+ * @type {typeof setMagnitude}
233
251
  */
234
252
  export const setLength = setMagnitude
235
253
 
236
254
  /**
237
255
  * Sets the magnitude of the vector while maintaining its direction.
238
- *
239
256
  * @param {Vector} vector - The input vector.
240
257
  * @param {number} length - The new magnitude.
241
258
  * @returns {Vector} The vector with the updated magnitude.
@@ -247,74 +264,67 @@ export function setMagnitude(vector, length) {
247
264
 
248
265
  /**
249
266
  * Shifts the components of the vector by the given index.
250
- *
251
267
  * @param {Vector} vector - The input vector.
252
268
  * @param {number} index - The index to shift by.
253
269
  * @returns {Vector} The shifted vector.
254
270
  */
255
271
  export function shift(vector, index) {
256
- return [...vector.slice(index), ...vector.slice(X, index)]
272
+ return v(...vector.slice(index), ...vector.slice(X, index))
257
273
  }
258
274
 
259
275
  /**
260
276
  * Snaps each component of the vector to the nearest multiple of the given precision.
261
- *
262
277
  * @param {Vector} vector - The input vector.
263
278
  * @param {number} [precision=DEFAULT_PRECISION] - The precision value.
264
279
  * @returns {Vector} The snapped vector.
265
280
  */
266
281
  export function snap(vector, precision = DEFAULT_PRECISION) {
267
- return vector.map((coordinate) => nSnap(coordinate, -precision, precision))
282
+ return v(
283
+ ...vector.map((coordinate) => nSnap(coordinate, -precision, precision)),
284
+ )
268
285
  }
269
286
 
270
- export const times = multiply
271
-
272
287
  /**
273
288
  * Converts a 3D vector [x, y, z] into a 2D vector [x, z].
274
- *
275
289
  * @param {Vector3} vector - A 3D vector represented as [x, y, z].
276
290
  * @returns {Vector2} A 2D vector represented as [x, z].
277
291
  */
278
292
  export function to2D(vector) {
279
293
  const [x, , z] = vector
280
- return [x, z]
294
+ return v(x, z)
281
295
  }
282
296
 
283
297
  /**
284
298
  * Converts 2D polar coordinates to 2D Cartesian coordinates.
285
- *
286
299
  * @param {Vector2} vector - The polar coordinates [magnitude, angle].
287
300
  * @returns {Vector2} The Cartesian coordinates [x, y].
288
301
  */
289
302
  export function toCartesian([magnitude, angle]) {
290
- return [magnitude * cos(angle), magnitude * sin(angle)]
303
+ return v(magnitude * cos(angle), magnitude * sin(angle))
291
304
  }
292
305
 
293
306
  /**
294
307
  * Converts a 3D cartesian vector to cylindrical coordinates.
295
- *
296
308
  * @param {Vector3} vector - The input vector [x, y, z].
297
309
  * @returns {Vector3} The cylindrical coordinates [radius, theta, z].
298
310
  */
299
311
  export function toCylindrical(vector) {
300
312
  const radius = magnitude(vector)
301
313
  const theta = angle(vector)
302
- return [radius * cos(theta), radius * sin(theta), vector[Z]]
314
+ return v(radius * cos(theta), radius * sin(theta), vector[Z])
303
315
  }
304
316
 
305
317
  /**
306
318
  * Converts a 2D cartesian vector to 2D polar coordinates.
307
- *
308
319
  * @param {Vector2} vector - The input vector [x, y].
309
320
  * @returns {Vector2} The polar coordinates [magnitude, angle].
310
321
  */
311
322
  export function toPolar(vector) {
312
- return [magnitude(vector), angle(vector)]
323
+ return v(magnitude(vector), angle(vector))
313
324
  }
314
325
 
315
326
  /**
316
327
  * Converts a vector to a string representation.
317
- *
318
328
  * @param {Vector} vector - The input vector.
319
329
  * @param {number} [decimals=DEFAULT_DECIMALS] - The number of decimal places.
320
330
  * @returns {string} The string representation of the vector.
@@ -325,14 +335,11 @@ export function toString(vector, decimals = DEFAULT_DECIMALS) {
325
335
  .join(", ")}]`
326
336
  }
327
337
 
328
- // TODO: add toSpherical(vector),
329
-
330
338
  /**
331
339
  * Converts a 3D cartesian vector to spherical coordinates [radius, inclination, azimuth].
332
340
  * - radius (r): distance from the origin.
333
341
  * - inclination (θ): angle from the Y-axis (0 to PI).
334
342
  * - azimuth (φ): angle from the X-axis in the XZ-plane (-PI to PI).
335
- *
336
343
  * @param {Vector3} vector The cartesian vector [x, y, z].
337
344
  * @returns {Vector3} The spherical coordinates [r, θ, φ].
338
345
  */
@@ -348,46 +355,32 @@ export function toSpherical(vector) {
348
355
  // Azimuth is the angle in the XZ plane, which `angle()` calculates.
349
356
  const azimuth = angle(vector)
350
357
 
351
- return [r, inclination, azimuth]
358
+ return v(r, inclination, azimuth)
352
359
  }
353
360
 
354
361
  /**
355
362
  * Creates a 3D unit vector in the XZ plane with the given angle.
356
- *
357
363
  * @param {number} [angle=0] - The angle in radians.
358
364
  * @returns {Vector3} The unit vector.
359
365
  */
360
366
  export function unit(angle) {
361
367
  if (!angle) {
362
- return [...UNIT_VECTOR]
368
+ return v(...UNIT_VECTOR)
363
369
  }
364
370
 
365
371
  return setAngle(UNIT_VECTOR, angle)
366
372
  }
367
373
 
368
- /**
369
- * A utility function to create a vector from a list of coordinates.
370
- * This is a shorthand for `[x, y, z, ...]`.
371
- *
372
- * @param {...number} coords - The coordinates of the vector.
373
- * @returns {Vector} The created vector.
374
- */
375
- export function v(...coords) {
376
- return coords
377
- }
378
-
379
374
  /**
380
375
  * Creates a zero vector of 3 dimensions.
381
- *
382
376
  * @returns {Vector3} The zero vector.
383
377
  */
384
378
  export function zero() {
385
- return [...ZERO_VECTOR]
379
+ return v(...ZERO_VECTOR)
386
380
  }
387
381
 
388
382
  /**
389
383
  * Rotates a 3D vector around the Y-axis using a quaternion.
390
- *
391
384
  * @param {Vector3} vector - The input vector.
392
385
  * @param {number} angle - The angle in radians.
393
386
  * @returns {Vector3} The rotated vector.