@pawells/math-extended 1.1.1 → 3.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 (113) hide show
  1. package/README.md +15 -21
  2. package/build/angles.d.ts +28 -18
  3. package/build/angles.d.ts.map +1 -1
  4. package/build/angles.js +28 -18
  5. package/build/angles.js.map +1 -1
  6. package/build/clamp.d.ts +2 -0
  7. package/build/clamp.d.ts.map +1 -1
  8. package/build/clamp.js +2 -0
  9. package/build/clamp.js.map +1 -1
  10. package/build/core.d.ts +23 -0
  11. package/build/core.d.ts.map +1 -0
  12. package/build/core.js +25 -0
  13. package/build/core.js.map +1 -0
  14. package/build/index.d.ts +1 -4
  15. package/build/index.d.ts.map +1 -1
  16. package/build/index.js +1 -6
  17. package/build/index.js.map +1 -1
  18. package/build/interpolation.d.ts +62 -13
  19. package/build/interpolation.d.ts.map +1 -1
  20. package/build/interpolation.js +66 -23
  21. package/build/interpolation.js.map +1 -1
  22. package/build/matrices/arithmetic.d.ts +65 -76
  23. package/build/matrices/arithmetic.d.ts.map +1 -1
  24. package/build/matrices/arithmetic.js +65 -107
  25. package/build/matrices/arithmetic.js.map +1 -1
  26. package/build/matrices/asserts.d.ts +26 -273
  27. package/build/matrices/asserts.d.ts.map +1 -1
  28. package/build/matrices/asserts.js +106 -350
  29. package/build/matrices/asserts.js.map +1 -1
  30. package/build/matrices/core.d.ts +150 -79
  31. package/build/matrices/core.d.ts.map +1 -1
  32. package/build/matrices/core.js +128 -104
  33. package/build/matrices/core.js.map +1 -1
  34. package/build/matrices/decompositions.d.ts +41 -44
  35. package/build/matrices/decompositions.d.ts.map +1 -1
  36. package/build/matrices/decompositions.js +51 -94
  37. package/build/matrices/decompositions.js.map +1 -1
  38. package/build/matrices/index.d.ts +2 -2
  39. package/build/matrices/index.d.ts.map +1 -1
  40. package/build/matrices/index.js +2 -2
  41. package/build/matrices/index.js.map +1 -1
  42. package/build/matrices/linear-algebra.d.ts +56 -19
  43. package/build/matrices/linear-algebra.d.ts.map +1 -1
  44. package/build/matrices/linear-algebra.js +80 -36
  45. package/build/matrices/linear-algebra.js.map +1 -1
  46. package/build/matrices/normalization.d.ts +36 -15
  47. package/build/matrices/normalization.d.ts.map +1 -1
  48. package/build/matrices/normalization.js +32 -23
  49. package/build/matrices/normalization.js.map +1 -1
  50. package/build/matrices/transformations.d.ts +39 -52
  51. package/build/matrices/transformations.d.ts.map +1 -1
  52. package/build/matrices/transformations.js +8 -11
  53. package/build/matrices/transformations.js.map +1 -1
  54. package/build/matrices/types.d.ts +39 -67
  55. package/build/matrices/types.d.ts.map +1 -1
  56. package/build/matrices/types.js +63 -1
  57. package/build/matrices/types.js.map +1 -1
  58. package/build/quaternions/asserts.d.ts +114 -15
  59. package/build/quaternions/asserts.d.ts.map +1 -1
  60. package/build/quaternions/asserts.js +189 -51
  61. package/build/quaternions/asserts.js.map +1 -1
  62. package/build/quaternions/conversions.d.ts +18 -8
  63. package/build/quaternions/conversions.d.ts.map +1 -1
  64. package/build/quaternions/conversions.js +14 -4
  65. package/build/quaternions/conversions.js.map +1 -1
  66. package/build/quaternions/core.d.ts +31 -2
  67. package/build/quaternions/core.d.ts.map +1 -1
  68. package/build/quaternions/core.js +32 -4
  69. package/build/quaternions/core.js.map +1 -1
  70. package/build/quaternions/index.d.ts +2 -2
  71. package/build/quaternions/index.d.ts.map +1 -1
  72. package/build/quaternions/index.js +3 -2
  73. package/build/quaternions/index.js.map +1 -1
  74. package/build/quaternions/interpolation.d.ts +7 -1
  75. package/build/quaternions/interpolation.d.ts.map +1 -1
  76. package/build/quaternions/interpolation.js +12 -6
  77. package/build/quaternions/interpolation.js.map +1 -1
  78. package/build/quaternions/predefined.d.ts +7 -1
  79. package/build/quaternions/predefined.d.ts.map +1 -1
  80. package/build/quaternions/predefined.js +6 -0
  81. package/build/quaternions/predefined.js.map +1 -1
  82. package/build/quaternions/types.d.ts +24 -13
  83. package/build/quaternions/types.d.ts.map +1 -1
  84. package/build/quaternions/types.js +51 -1
  85. package/build/quaternions/types.js.map +1 -1
  86. package/build/random.d.ts +66 -20
  87. package/build/random.d.ts.map +1 -1
  88. package/build/random.js +73 -20
  89. package/build/random.js.map +1 -1
  90. package/build/vectors/asserts.d.ts +33 -99
  91. package/build/vectors/asserts.d.ts.map +1 -1
  92. package/build/vectors/asserts.js +145 -181
  93. package/build/vectors/asserts.js.map +1 -1
  94. package/build/vectors/core.d.ts +76 -44
  95. package/build/vectors/core.d.ts.map +1 -1
  96. package/build/vectors/core.js +128 -119
  97. package/build/vectors/core.js.map +1 -1
  98. package/build/vectors/index.d.ts.map +1 -1
  99. package/build/vectors/index.js +1 -0
  100. package/build/vectors/index.js.map +1 -1
  101. package/build/vectors/interpolation.d.ts +13 -1
  102. package/build/vectors/interpolation.d.ts.map +1 -1
  103. package/build/vectors/interpolation.js +48 -47
  104. package/build/vectors/interpolation.js.map +1 -1
  105. package/build/vectors/predefined.d.ts +73 -25
  106. package/build/vectors/predefined.d.ts.map +1 -1
  107. package/build/vectors/predefined.js +62 -18
  108. package/build/vectors/predefined.js.map +1 -1
  109. package/build/vectors/types.d.ts +26 -4
  110. package/build/vectors/types.d.ts.map +1 -1
  111. package/build/vectors/types.js +50 -1
  112. package/build/vectors/types.js.map +1 -1
  113. package/package.json +4 -3
@@ -3,7 +3,7 @@
3
3
  * Provides a comprehensive set of vector operations with type safety and error checking.
4
4
  */
5
5
  import { Clamp } from '../clamp.js';
6
- import { AssertVector, AssertVectors, AssertVectorValue, VectorError, AssertVector2, AssertVector3 } from './asserts.js';
6
+ import { AssertVector, AssertVector2, AssertVector3, AssertVectorNonZero, AssertVectorSameSize, ValidateVectorSameSize, VectorError } from './asserts.js';
7
7
  /**
8
8
  * Creates a deep copy of a vector.
9
9
  * Essential for avoiding mutations when performing operations that should preserve the original vector.
@@ -13,9 +13,11 @@ import { AssertVector, AssertVectors, AssertVectorValue, VectorError, AssertVect
13
13
  * @returns A new vector with identical components
14
14
  *
15
15
  * @example
16
+ * ```typescript
16
17
  * const original = [1, 2, 3];
17
18
  * const copy = VectorClone(original);
18
19
  * copy[0] = 10; // original remains unchanged
20
+ * ```
19
21
  */
20
22
  export function VectorClone(vector) {
21
23
  AssertVector(vector);
@@ -32,20 +34,21 @@ export function VectorClone(vector) {
32
34
  * @returns True if vectors are equal within tolerance, false otherwise
33
35
  *
34
36
  * @example
37
+ * ```typescript
35
38
  * const a = [1.0001, 2.0001];
36
39
  * const b = [1.0002, 2.0002];
37
40
  * const exactlyEqual = VectorEquals(a, b); // false
38
41
  * const approximatelyEqual = VectorEquals(a, b, 0.001); // true
42
+ * ```
39
43
  */
40
44
  export function VectorEquals(a, b, tolerance = 0) {
41
- AssertVectors([a, b]);
42
- if (a.length !== b.length)
45
+ if (!ValidateVectorSameSize([a, b]))
43
46
  return false;
47
+ AssertVector(a);
48
+ AssertVector(b);
44
49
  for (let i = 0; i < a.length; i++) {
45
50
  const av = a[i];
46
- AssertVectorValue(av, {});
47
51
  const bv = b[i];
48
- AssertVectorValue(bv, {});
49
52
  if (tolerance !== 0) {
50
53
  if (Math.abs(av - bv) > tolerance)
51
54
  return false;
@@ -64,16 +67,17 @@ export function VectorEquals(a, b, tolerance = 0) {
64
67
  * @returns String representation of the vector
65
68
  *
66
69
  * @example
70
+ * ```typescript
67
71
  * const vec = [1, 2, 3];
68
72
  * const parens = VectorToString(vec, 'parens'); // "(1, 2, 3)"
69
73
  * const brackets = VectorToString(vec, 'brackets'); // "[1, 2, 3]"
74
+ * ```
70
75
  */
71
76
  export function VectorToString(vector, style = 'parens') {
72
77
  AssertVector(vector);
73
78
  const components = vector.map((v) => v.toString()).join(', ');
74
- if (style === 'parens') {
79
+ if (style === 'parens')
75
80
  return `(${components})`;
76
- }
77
81
  return `[${components}]`;
78
82
  }
79
83
  /**
@@ -86,18 +90,20 @@ export function VectorToString(vector, style = 'parens') {
86
90
  * @returns New vector where each component is the sum of corresponding components
87
91
  *
88
92
  * @example
93
+ * ```typescript
89
94
  * const position = [10, 20, 30];
90
95
  * const velocity = [1, -2, 0.5];
91
96
  * const newPosition = VectorAdd(position, velocity); // [11, 18, 30.5]
97
+ * ```
92
98
  */
93
99
  export function VectorAdd(a, b) {
94
- AssertVectors([a, b]);
100
+ AssertVector(a);
101
+ AssertVector(b);
102
+ AssertVectorSameSize([a, b]);
95
103
  const result = [];
96
104
  for (let i = 0; i < a.length; i++) {
97
105
  const av = a[i];
98
- AssertVectorValue(av, {});
99
106
  const bv = b[i];
100
- AssertVectorValue(bv, {});
101
107
  result.push(av + bv);
102
108
  }
103
109
  return result;
@@ -112,18 +118,20 @@ export function VectorAdd(a, b) {
112
118
  * @returns New vector where each component is the difference of corresponding components
113
119
  *
114
120
  * @example
121
+ * ```typescript
115
122
  * const target = [100, 50, 0];
116
123
  * const current = [80, 30, 0];
117
124
  * const direction = VectorSubtract(target, current); // [20, 20, 0]
125
+ * ```
118
126
  */
119
127
  export function VectorSubtract(a, b) {
120
- AssertVectors([a, b]);
128
+ AssertVector(a);
129
+ AssertVector(b);
130
+ AssertVectorSameSize([a, b]);
121
131
  const result = [];
122
132
  for (let i = 0; i < a.length; i++) {
123
133
  const av = a[i];
124
- AssertVectorValue(av, {}, { index: i });
125
134
  const bv = b[i];
126
- AssertVectorValue(bv, {}, { index: i });
127
135
  result.push(av - bv);
128
136
  }
129
137
  return result;
@@ -138,28 +146,28 @@ export function VectorSubtract(a, b) {
138
146
  * @returns New vector with multiplied components
139
147
  *
140
148
  * @example
149
+ * ```typescript
141
150
  * const velocity = [10, 5, 0];
142
151
  * const scaled = VectorMultiply(velocity, 2); // [20, 10, 0] - scalar multiplication
143
152
  * const factors = [1, -1, 0.5];
144
153
  * const componentWise = VectorMultiply(velocity, factors); // [10, -5, 0] - component-wise
154
+ * ```
145
155
  */
146
156
  export function VectorMultiply(a, b) {
157
+ AssertVector(a);
147
158
  const result = [];
148
159
  if (Array.isArray(b)) {
149
- if (b.length !== a.length)
150
- throw new Error('Vector Size Mismatch');
160
+ AssertVector(b);
161
+ AssertVectorSameSize([a, b]);
151
162
  for (let i = 0; i < a.length; i++) {
152
163
  const av = a[i];
153
- AssertVectorValue(av, {});
154
164
  const bv = b[i];
155
- AssertVectorValue(bv, {});
156
165
  const prod = av * bv;
157
166
  result.push(Object.is(prod, -0) ? 0 : prod);
158
167
  }
159
168
  }
160
169
  else if (typeof b === 'number') {
161
170
  for (const av of a) {
162
- AssertVectorValue(av, {});
163
171
  const prod = av * b;
164
172
  result.push(Object.is(prod, -0) ? 0 : prod);
165
173
  }
@@ -175,9 +183,11 @@ export function VectorMultiply(a, b) {
175
183
  * @returns The straight-line distance between the two points represented by the vectors
176
184
  *
177
185
  * @example
186
+ * ```typescript
178
187
  * const pointA = [0, 0, 0];
179
188
  * const pointB = [3, 4, 0];
180
189
  * const distance = VectorDistance(pointA, pointB); // 5.0 (3-4-5 triangle)
190
+ * ```
181
191
  */
182
192
  export function VectorDistance(a, b) {
183
193
  return Math.sqrt(VectorDistanceSquared(a, b));
@@ -192,18 +202,20 @@ export function VectorDistance(a, b) {
192
202
  * @returns The squared distance between vectors
193
203
  *
194
204
  * @example
205
+ * ```typescript
195
206
  * const pointA = [1, 1];
196
207
  * const pointB = [4, 5];
197
208
  * const distSq = VectorDistanceSquared(pointA, pointB); // 25 (faster than distance comparison)
209
+ * ```
198
210
  */
199
211
  export function VectorDistanceSquared(a, b) {
200
- AssertVectors([a, b]);
212
+ AssertVector(a);
213
+ AssertVector(b);
214
+ AssertVectorSameSize([a, b]);
201
215
  let sum = 0;
202
216
  for (let i = 0; i < a.length; i++) {
203
217
  const av = a[i];
204
- AssertVectorValue(av, {});
205
218
  const bv = b[i];
206
- AssertVectorValue(bv, {});
207
219
  const diff = bv - av;
208
220
  sum += diff * diff;
209
221
  }
@@ -219,21 +231,22 @@ export function VectorDistanceSquared(a, b) {
219
231
  * @returns The dot product (scalar value)
220
232
  *
221
233
  * @example
234
+ * ```typescript
222
235
  * const forward = [0, 0, 1];
223
236
  * const direction = [0, 0, 2];
224
237
  * const dot = VectorDot(forward, direction); // 2 (same direction)
225
- *
226
238
  * const perpendicular = [1, 0, 0];
227
239
  * const dotPerp = VectorDot(forward, perpendicular); // 0 (perpendicular)
240
+ * ```
228
241
  */
229
242
  export function VectorDot(a, b) {
230
- AssertVectors([a, b]);
243
+ AssertVector(a);
244
+ AssertVector(b);
245
+ AssertVectorSameSize([a, b]);
231
246
  let dotProduct = 0;
232
247
  for (let i = 0; i < a.length; i++) {
233
248
  const av = a[i];
234
- AssertVectorValue(av, {});
235
249
  const bv = b[i];
236
- AssertVectorValue(bv, {});
237
250
  dotProduct += av * bv;
238
251
  }
239
252
  return dotProduct;
@@ -249,11 +262,12 @@ export function VectorDot(a, b) {
249
262
  * @throws {VectorError} If the vector is zero or has infinite magnitude
250
263
  *
251
264
  * @example
265
+ * ```typescript
252
266
  * const vector = [3, 4, 0];
253
267
  * const normalized = VectorNormalize(vector); // [0.6, 0.8, 0] (magnitude = 1)
254
- *
255
268
  * const direction = [10, 0, 0];
256
269
  * const unitDirection = VectorNormalize(direction); // [1, 0, 0]
270
+ * ```
257
271
  */
258
272
  export function VectorNormalize(a) {
259
273
  AssertVector(a);
@@ -265,7 +279,6 @@ export function VectorNormalize(a) {
265
279
  const result = VectorClone(a);
266
280
  for (let i = 0; i < a.length; i++) {
267
281
  const av = a[i];
268
- AssertVectorValue(av, {});
269
282
  result[i] = av / magnitude;
270
283
  }
271
284
  return result;
@@ -278,19 +291,18 @@ export function VectorNormalize(a) {
278
291
  * @returns The magnitude (length) of the vector
279
292
  *
280
293
  * @example
294
+ * ```typescript
281
295
  * const velocity = [3, 4, 0];
282
296
  * const speed = VectorMagnitude(velocity); // 5.0
283
- *
284
297
  * const unitVector = [1, 0, 0];
285
298
  * const unitLength = VectorMagnitude(unitVector); // 1.0
299
+ * ```
286
300
  */
287
301
  export function VectorMagnitude(a) {
288
302
  AssertVector(a);
289
303
  let sum = 0;
290
- for (const av of a) {
291
- AssertVectorValue(av, {});
304
+ for (const av of a)
292
305
  sum += av * av;
293
- }
294
306
  return Math.sqrt(sum);
295
307
  }
296
308
  /**
@@ -302,19 +314,18 @@ export function VectorMagnitude(a) {
302
314
  * @returns New vector with absolute values of all components
303
315
  *
304
316
  * @example
317
+ * ```typescript
305
318
  * const vector = [-3, 4, -2];
306
319
  * const absolute = VectorAbs(vector); // [3, 4, 2]
307
- *
308
320
  * const mixed = [1.5, -2.7, 0];
309
321
  * const absValues = VectorAbs(mixed); // [1.5, 2.7, 0]
322
+ * ```
310
323
  */
311
324
  export function VectorAbs(a) {
312
325
  AssertVector(a);
313
326
  const result = [];
314
- for (const av of a) {
315
- AssertVectorValue(av, {});
327
+ for (const av of a)
316
328
  result.push(Math.abs(av));
317
- }
318
329
  return result;
319
330
  }
320
331
  /**
@@ -325,11 +336,12 @@ export function VectorAbs(a) {
325
336
  * @returns True if all components are zero, false otherwise
326
337
  *
327
338
  * @example
339
+ * ```typescript
328
340
  * const zero = [0, 0, 0];
329
341
  * const isZero = VectorIsZero(zero); // true
330
- *
331
342
  * const notZero = [0, 0.001, 0];
332
343
  * const isNotZero = VectorIsZero(notZero); // false
344
+ * ```
333
345
  */
334
346
  export function VectorIsZero(vector) {
335
347
  return vector.every((v) => v === 0);
@@ -345,16 +357,19 @@ export function VectorIsZero(vector) {
345
357
  * @throws {VectorError} If either vector is zero
346
358
  *
347
359
  * @example
360
+ * ```typescript
348
361
  * const right = [1, 0, 0];
349
362
  * const up = [0, 1, 0];
350
363
  * const angle = VectorAngle(right, up); // π/2 (90 degrees)
351
- *
352
364
  * const forward = [0, 0, 1];
353
365
  * const backward = [0, 0, -1];
354
366
  * const oppositeAngle = VectorAngle(forward, backward); // π (180 degrees)
367
+ * ```
355
368
  */
356
369
  export function VectorAngle(a, b) {
357
- AssertVectors([a, b]);
370
+ AssertVector(a);
371
+ AssertVector(b);
372
+ AssertVectorSameSize([a, b]);
358
373
  if (VectorIsZero(a) || VectorIsZero(b))
359
374
  throw new VectorError('Cannot Calculate Angle with Zero Vectors');
360
375
  const dot = VectorDot(a, b);
@@ -362,6 +377,32 @@ export function VectorAngle(a, b) {
362
377
  const cosTheta = Clamp(dot / magProduct, -1, 1);
363
378
  return Math.acos(cosTheta);
364
379
  }
380
+ /**
381
+ * Limits (clamps) the magnitude of a vector to a maximum value.
382
+ * If the vector's magnitude exceeds the maximum, scales it down proportionally while preserving direction.
383
+ * If the magnitude is below the maximum, the vector is returned unchanged.
384
+ *
385
+ * @param vector - The input vector to limit
386
+ * @param maxMagnitude - The maximum allowed magnitude (must be >= 0)
387
+ * @returns A new vector with magnitude limited to maxMagnitude
388
+ * @throws {VectorError} If vector is invalid or maxMagnitude is invalid
389
+ *
390
+ * @example
391
+ * ```typescript
392
+ * const v = [3, 4]; // magnitude 5
393
+ * VectorLimit(v, 3); // [1.8, 2.4] — magnitude now 3
394
+ * ```
395
+ */
396
+ export function VectorLimit(vector, maxMagnitude) {
397
+ AssertVector(vector);
398
+ if (maxMagnitude < 0)
399
+ throw new VectorError(`maxMagnitude must be non-negative: ${maxMagnitude}`);
400
+ const mag = VectorMagnitude(vector);
401
+ if (mag <= maxMagnitude || mag === 0)
402
+ return VectorClone(vector);
403
+ const scale = maxMagnitude / mag;
404
+ return VectorMultiply(vector, scale);
405
+ }
365
406
  /**
366
407
  * Rotates a 2D vector by the specified angle in radians.
367
408
  * Essential for 2D transformations, sprite rotations, and directional calculations.
@@ -371,9 +412,11 @@ export function VectorAngle(a, b) {
371
412
  * @returns New rotated 2D vector
372
413
  *
373
414
  * @example
415
+ * ```typescript
374
416
  * const right = [1, 0];
375
417
  * const rotated90 = Vector2Rotate(right, Math.PI / 2); // [0, 1] (up)
376
418
  * const rotated180 = Vector2Rotate(right, Math.PI); // [-1, 0] (left)
419
+ * ```
377
420
  */
378
421
  export function Vector2Rotate(vector, radians) {
379
422
  AssertVector2(vector);
@@ -393,9 +436,11 @@ export function Vector2Rotate(vector, radians) {
393
436
  * @returns Unit vector pointing in the specified direction
394
437
  *
395
438
  * @example
439
+ * ```typescript
396
440
  * const right = Vector2FromAngle(0); // [1, 0]
397
441
  * const up = Vector2FromAngle(Math.PI / 2); // [0, 1]
398
442
  * const diagonal = Vector2FromAngle(Math.PI / 4); // [0.707, 0.707]
443
+ * ```
399
444
  */
400
445
  export function Vector2FromAngle(radians) {
401
446
  return [Math.cos(radians), Math.sin(radians)];
@@ -410,10 +455,12 @@ export function Vector2FromAngle(radians) {
410
455
  * @returns Scalar cross product (positive = counterclockwise, negative = clockwise)
411
456
  *
412
457
  * @example
458
+ * ```typescript
413
459
  * const right = [1, 0];
414
460
  * const up = [0, 1];
415
461
  * const cross = Vector2Cross(right, up); // 1 (counterclockwise)
416
462
  * const crossReverse = Vector2Cross(up, right); // -1 (clockwise)
463
+ * ```
417
464
  */
418
465
  export function Vector2Cross(a, b) {
419
466
  AssertVector2(a);
@@ -431,9 +478,11 @@ export function Vector2Cross(a, b) {
431
478
  * @throws {VectorError} If vector b is zero
432
479
  *
433
480
  * @example
481
+ * ```typescript
434
482
  * const force = [5, 3, 0];
435
483
  * const surface = [1, 0, 0];
436
484
  * const perpendicular = Vector3Reject(force, surface); // [0, 3, 0]
485
+ * ```
437
486
  */
438
487
  export function Vector3Reject(a, b) {
439
488
  AssertVector3(a);
@@ -455,22 +504,24 @@ export function Vector3Reject(a, b) {
455
504
  * @throws {VectorError} If vector b is zero
456
505
  *
457
506
  * @example
507
+ * ```typescript
458
508
  * const force = [5, 3, 0];
459
509
  * const surface = [1, 0, 0];
460
510
  * const parallel = VectorProject(force, surface); // [5, 0, 0]
511
+ * ```
461
512
  */
462
513
  export function VectorProject(a, b) {
463
- AssertVectors([a, b]);
514
+ AssertVector(a);
515
+ AssertVector(b);
516
+ AssertVectorSameSize([a, b]);
464
517
  if (VectorIsZero(b))
465
518
  throw new VectorError('Cannot project onto a zero vector');
466
519
  const dot = VectorDot(a, b);
467
520
  const magSquared = VectorDot(b, b);
468
521
  const scalar = dot / magSquared;
469
522
  const result = [];
470
- for (const bv of b) {
471
- AssertVectorValue(bv, {});
523
+ for (const bv of b)
472
524
  result.push(scalar * bv);
473
- }
474
525
  return result;
475
526
  }
476
527
  /**
@@ -484,9 +535,11 @@ export function VectorProject(a, b) {
484
535
  * @throws {VectorError} If the normal is a zero vector
485
536
  *
486
537
  * @example
538
+ * ```typescript
487
539
  * const incoming = [1, -1, 0];
488
540
  * const normal = [0, 1, 0]; // surface normal (upward)
489
541
  * const reflected = Vector3Reflect(incoming, normal); // [1, 1, 0]
542
+ * ```
490
543
  */
491
544
  export function Vector3Reflect(incident, normal) {
492
545
  AssertVector3(incident);
@@ -506,11 +559,12 @@ export function Vector3Reflect(incident, normal) {
506
559
  * @returns Vector perpendicular to both a and b (following right-hand rule)
507
560
  *
508
561
  * @example
562
+ * ```typescript
509
563
  * const right = [1, 0, 0];
510
564
  * const forward = [0, 0, 1];
511
565
  * const up = Vector3Cross(right, forward); // [0, 1, 0]
512
- *
513
566
  * const normal = Vector3Cross([1, 0, 0], [0, 1, 0]); // [0, 0, 1]
567
+ * ```
514
568
  */
515
569
  export function Vector3Cross(a, b) {
516
570
  AssertVector3(a);
@@ -531,9 +585,11 @@ export function Vector3Cross(a, b) {
531
585
  * @returns Magnitude of the cross product
532
586
  *
533
587
  * @example
588
+ * ```typescript
534
589
  * const side1 = [3, 0, 0];
535
590
  * const side2 = [0, 4, 0];
536
591
  * const area = VectorCrossMagnitude(side1, side2); // 12 (area of rectangle)
592
+ * ```
537
593
  */
538
594
  export function VectorCrossMagnitude(a, b) {
539
595
  AssertVector3(a);
@@ -552,10 +608,12 @@ export function VectorCrossMagnitude(a, b) {
552
608
  * @returns Signed volume (positive = right-handed orientation)
553
609
  *
554
610
  * @example
611
+ * ```typescript
555
612
  * const x = [1, 0, 0];
556
613
  * const y = [0, 1, 0];
557
614
  * const z = [0, 0, 1];
558
615
  * const volume = Vector3ScalarTripleProduct(x, y, z); // 1 (unit cube)
616
+ * ```
559
617
  */
560
618
  export function Vector3ScalarTripleProduct(a, b, c) {
561
619
  AssertVector3(a);
@@ -575,10 +633,12 @@ export function Vector3ScalarTripleProduct(a, b, c) {
575
633
  * @returns Vector result of a × (b × c)
576
634
  *
577
635
  * @example
636
+ * ```typescript
578
637
  * const a = [1, 0, 0];
579
638
  * const b = [0, 1, 0];
580
639
  * const c = [0, 0, 1];
581
640
  * const result = Vector3TripleProduct(a, b, c); // [0, 0, 0]
641
+ * ```
582
642
  */
583
643
  export function Vector3TripleProduct(a, b, c) {
584
644
  AssertVector3(a);
@@ -598,20 +658,22 @@ export function Vector3TripleProduct(a, b, c) {
598
658
  * @returns The reflected vector
599
659
  *
600
660
  * @example
661
+ * ```typescript
601
662
  * const incoming = [1, -1, 0];
602
663
  * const wall = [0, 1, 0]; // vertical wall normal
603
664
  * const bounced = VectorReflect(incoming, wall); // [1, 1, 0]
665
+ * ```
604
666
  */
605
667
  export function VectorReflect(incident, normal) {
606
- AssertVectors([incident, normal]);
668
+ AssertVector(incident);
669
+ AssertVector(normal);
670
+ AssertVectorSameSize([incident, normal]);
607
671
  const normalizedNormal = VectorNormalize(normal);
608
672
  const dot = VectorDot(incident, normalizedNormal);
609
673
  const result = [];
610
674
  for (let i = 0; i < incident.length; i++) {
611
675
  const iv = incident[i];
612
- AssertVectorValue(iv, {});
613
676
  const nnv = normalizedNormal[i];
614
- AssertVectorValue(nnv, {});
615
677
  result.push(iv - (2 * dot * nnv));
616
678
  }
617
679
  return result;
@@ -626,24 +688,18 @@ export function VectorReflect(incident, normal) {
626
688
  * @returns Vector with all components negated
627
689
  *
628
690
  * @example
691
+ * ```typescript
629
692
  * const forward = [0, 0, 1];
630
693
  * const backward = VectorNegate(forward); // [0, 0, -1]
631
- *
632
694
  * const velocity = [5, -3, 2];
633
695
  * const opposite = VectorNegate(velocity); // [-5, 3, -2]
696
+ * ```
634
697
  */
635
698
  export function VectorNegate(a) {
699
+ AssertVector(a);
636
700
  const result = [];
637
- for (const av of a) {
638
- AssertVectorValue(av, {});
639
- // Special handling for zero to avoid negative zero (-0)
640
- if (av === 0) {
641
- result.push(0);
642
- }
643
- else {
644
- result.push(-1 * av);
645
- }
646
- }
701
+ for (const av of a)
702
+ result.push(av === 0 ? 0 : -1 * av);
647
703
  return result;
648
704
  }
649
705
  /**
@@ -657,21 +713,22 @@ export function VectorNegate(a) {
657
713
  * @throws {VectorError} If any divisor component is zero
658
714
  *
659
715
  * @example
716
+ * ```typescript
660
717
  * const velocity = [20, 10, 0];
661
718
  * const halved = VectorDivide(velocity, 2); // [10, 5, 0] - scalar division
662
719
  * const factors = [2, 5, 1];
663
720
  * const componentWise = VectorDivide(velocity, factors); // [10, 2, 0] - component-wise
721
+ * ```
664
722
  */
665
723
  export function VectorDivide(a, b) {
724
+ AssertVector(a);
666
725
  const result = [];
667
726
  if (Array.isArray(b)) {
668
- if (b.length !== a.length)
669
- throw new VectorError('Vector Size Mismatch');
727
+ AssertVector(b);
728
+ AssertVectorSameSize([a, b]);
670
729
  for (let i = 0; i < a.length; i++) {
671
730
  const av = a[i];
672
- AssertVectorValue(av, {});
673
731
  const bv = b[i];
674
- AssertVectorValue(bv, {});
675
732
  if (bv === 0)
676
733
  throw new VectorError(`Division by zero at component [${i}]`);
677
734
  const quot = av / bv;
@@ -682,7 +739,6 @@ export function VectorDivide(a, b) {
682
739
  if (b === 0)
683
740
  throw new VectorError('Division by zero scalar');
684
741
  for (const av of a) {
685
- AssertVectorValue(av, {});
686
742
  const quot = av / b;
687
743
  result.push(Object.is(quot, -0) ? 0 : quot);
688
744
  }
@@ -701,75 +757,25 @@ export function VectorDivide(a, b) {
701
757
  * @returns New vector with each component clamped between min and max
702
758
  *
703
759
  * @example
760
+ * ```typescript
704
761
  * const v = [5, -3, 12, 0];
705
762
  * VectorClamp(v, 0, 10); // [5, 0, 10, 0] - scalar bounds
706
- *
707
763
  * const mins = [0, -5, 0, -1];
708
764
  * const maxs = [10, 5, 8, 1];
709
765
  * VectorClamp(v, mins, maxs); // [5, -3, 8, 0] - per-component bounds
766
+ * ```
710
767
  */
711
768
  export function VectorClamp(a, min, max) {
712
769
  AssertVector(a);
713
770
  const result = [];
714
771
  for (let i = 0; i < a.length; i++) {
715
772
  const av = a[i];
716
- AssertVectorValue(av, {});
717
773
  const minV = Array.isArray(min) ? min[i] : min;
718
774
  const maxV = Array.isArray(max) ? max[i] : max;
719
775
  result.push(Math.max(minV, Math.min(av, maxV)));
720
776
  }
721
777
  return result;
722
778
  }
723
- /**
724
- * Limits the magnitude of a vector to a maximum value.
725
- * If the vector's magnitude exceeds the limit, scales it down proportionally.
726
- * Preserves direction while constraining magnitude.
727
- *
728
- * @template T - The vector type extending TVector
729
- * @param a - Vector to limit
730
- * @param max - Maximum allowed magnitude
731
- * @returns Vector with magnitude limited to max
732
- * @throws {VectorError} If max is negative
733
- *
734
- * @example
735
- * const velocity = [15, 20, 0]; // magnitude ≈ 25
736
- * const limited = VectorLimit(velocity, 10); // magnitude = 10, same direction
737
- *
738
- * const small = [1, 1, 0]; // magnitude ≈ 1.414
739
- * const unchanged = VectorLimit(small, 5); // unchanged since already under limit
740
- */
741
- export function VectorLimit(a, max) {
742
- if (max < 0)
743
- throw new VectorError('Maximum magnitude cannot be negative');
744
- const magnitude = VectorMagnitude(a);
745
- if (magnitude <= max || magnitude === 0)
746
- return VectorClone(a);
747
- const scaleFactor = max / magnitude;
748
- return VectorMultiply(a, scaleFactor);
749
- }
750
- /**
751
- * Validates if the input is a properly formatted vector.
752
- * Performs comprehensive validation without throwing errors.
753
- * Useful for input validation and defensive programming.
754
- *
755
- * @param vector - Input to validate
756
- * @returns True if input is a valid vector, false otherwise
757
- *
758
- * @example
759
- * const valid = VectorIsValid([1, 2, 3]); // true
760
- * const invalid = VectorIsValid("not a vector"); // false
761
- * const nullVector = VectorIsValid(null); // false
762
- * const emptyArray = VectorIsValid([]); // depends on implementation
763
- */
764
- export function VectorIsValid(vector) {
765
- try {
766
- AssertVector(vector);
767
- return true;
768
- }
769
- catch {
770
- return false;
771
- }
772
- }
773
779
  /**
774
780
  * Performs Gram-Schmidt orthogonalization on a set of vectors.
775
781
  * Converts a set of linearly independent vectors into an orthogonal (or orthonormal) set.
@@ -782,9 +788,11 @@ export function VectorIsValid(vector) {
782
788
  * @throws {VectorError} If vectors are linearly dependent or invalid
783
789
  *
784
790
  * @example
791
+ * ```typescript
785
792
  * const vectors = [[1, 1, 0], [1, 0, 1], [0, 1, 1]];
786
793
  * const orthogonal = VectorGramSchmidt(vectors); // Orthogonal set
787
794
  * const orthonormal = VectorGramSchmidt(vectors, true); // Orthonormal set
795
+ * ```
788
796
  */
789
797
  export function VectorGramSchmidt(vectors, normalize = false) {
790
798
  if (vectors.length === 0)
@@ -797,21 +805,22 @@ export function VectorGramSchmidt(vectors, normalize = false) {
797
805
  AssertVector(vector);
798
806
  if (vector.length !== dimension)
799
807
  throw new VectorError(`GramSchmidt: Vector at index ${i} has different dimension than first vector. Expected ${dimension}, got ${vector.length}`);
800
- if (VectorIsZero(vector))
801
- throw new VectorError(`GramSchmidt: Vector at index ${i} is a zero vector. Cannot orthogonalize zero vectors.`);
808
+ AssertVectorNonZero(vector, `GramSchmidt vector at index ${i}`);
802
809
  }
803
810
  const result = [];
804
811
  for (const [i, currentVector] of vectors.entries()) {
805
812
  AssertVector(currentVector);
806
- let orthogonalVector = VectorClone(currentVector);
813
+ // Start with a clone; TVectorResult<T> is dimensionally equivalent to T at runtime
814
+ const orthogonalBase = VectorClone(currentVector);
815
+ let orthogonalVector = orthogonalBase;
807
816
  for (let j = 0; j < i; j++) {
808
817
  const previousVector = result[j];
809
818
  AssertVector(previousVector);
819
+ // Project current onto previous: TVectorResult<T> shares dimensionality with T
810
820
  const projection = VectorProject(currentVector, previousVector);
811
821
  orthogonalVector = VectorSubtract(orthogonalVector, projection);
812
822
  }
813
- if (VectorIsZero(orthogonalVector))
814
- throw new VectorError(`GramSchmidt: Vector at index ${i} is linearly dependent on previous vectors. Cannot orthogonalize linearly dependent vectors.`);
823
+ AssertVectorNonZero(orthogonalVector, `GramSchmidt orthogonalized vector at index ${i}`);
815
824
  if (normalize)
816
825
  orthogonalVector = VectorNormalize(orthogonalVector);
817
826
  result.push(orthogonalVector);