@pawells/math-extended 1.0.5 → 2.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.
- package/README.md +5 -5
- package/build/angles.d.ts +43 -3
- package/build/angles.d.ts.map +1 -1
- package/build/angles.js +61 -34
- package/build/angles.js.map +1 -1
- package/build/clamp.d.ts +5 -3
- package/build/clamp.d.ts.map +1 -1
- package/build/clamp.js +5 -3
- package/build/clamp.js.map +1 -1
- package/build/interpolation.d.ts +444 -67
- package/build/interpolation.d.ts.map +1 -1
- package/build/interpolation.js +444 -67
- package/build/interpolation.js.map +1 -1
- package/build/matrices/_exports.d.ts +13 -0
- package/build/matrices/_exports.d.ts.map +1 -0
- package/build/matrices/_exports.js +13 -0
- package/build/matrices/_exports.js.map +1 -0
- package/build/matrices/arithmetic.d.ts +170 -181
- package/build/matrices/arithmetic.d.ts.map +1 -1
- package/build/matrices/arithmetic.js +192 -202
- package/build/matrices/arithmetic.js.map +1 -1
- package/build/matrices/asserts.d.ts +244 -116
- package/build/matrices/asserts.d.ts.map +1 -1
- package/build/matrices/asserts.js +291 -94
- package/build/matrices/asserts.js.map +1 -1
- package/build/matrices/core.d.ts +40 -41
- package/build/matrices/core.d.ts.map +1 -1
- package/build/matrices/core.js +12 -13
- package/build/matrices/core.js.map +1 -1
- package/build/matrices/decompositions.d.ts +121 -124
- package/build/matrices/decompositions.d.ts.map +1 -1
- package/build/matrices/decompositions.js +168 -226
- package/build/matrices/decompositions.js.map +1 -1
- package/build/matrices/index.d.ts +3 -2
- package/build/matrices/index.d.ts.map +1 -1
- package/build/matrices/index.js +5 -2
- package/build/matrices/index.js.map +1 -1
- package/build/matrices/linear-algebra.d.ts +18 -13
- package/build/matrices/linear-algebra.d.ts.map +1 -1
- package/build/matrices/linear-algebra.js +58 -23
- package/build/matrices/linear-algebra.js.map +1 -1
- package/build/matrices/normalization.d.ts +8 -8
- package/build/matrices/transformations.d.ts +184 -168
- package/build/matrices/transformations.d.ts.map +1 -1
- package/build/matrices/transformations.js +99 -83
- package/build/matrices/transformations.js.map +1 -1
- package/build/matrices/types.d.ts +12 -12
- package/build/matrices/types.d.ts.map +1 -1
- package/build/quaternions/_exports.d.ts +11 -0
- package/build/quaternions/_exports.d.ts.map +1 -0
- package/build/quaternions/_exports.js +11 -0
- package/build/quaternions/_exports.js.map +1 -0
- package/build/quaternions/asserts.d.ts +115 -7
- package/build/quaternions/asserts.d.ts.map +1 -1
- package/build/quaternions/asserts.js +162 -8
- package/build/quaternions/asserts.js.map +1 -1
- package/build/quaternions/conversions.d.ts +31 -21
- package/build/quaternions/conversions.d.ts.map +1 -1
- package/build/quaternions/conversions.js +28 -18
- package/build/quaternions/conversions.js.map +1 -1
- package/build/quaternions/core.d.ts +73 -41
- package/build/quaternions/core.d.ts.map +1 -1
- package/build/quaternions/core.js +84 -49
- package/build/quaternions/core.js.map +1 -1
- package/build/quaternions/index.d.ts +3 -2
- package/build/quaternions/index.d.ts.map +1 -1
- package/build/quaternions/index.js +5 -2
- package/build/quaternions/index.js.map +1 -1
- package/build/quaternions/interpolation.d.ts +15 -9
- package/build/quaternions/interpolation.d.ts.map +1 -1
- package/build/quaternions/interpolation.js +15 -9
- package/build/quaternions/interpolation.js.map +1 -1
- package/build/quaternions/predefined.d.ts +9 -3
- package/build/quaternions/predefined.d.ts.map +1 -1
- package/build/quaternions/predefined.js +9 -3
- package/build/quaternions/predefined.js.map +1 -1
- package/build/quaternions/types.d.ts +3 -3
- package/build/random.d.ts +5 -2
- package/build/random.d.ts.map +1 -1
- package/build/random.js +20 -17
- package/build/random.js.map +1 -1
- package/build/vectors/_exports.d.ts +10 -0
- package/build/vectors/_exports.d.ts.map +1 -0
- package/build/vectors/_exports.js +10 -0
- package/build/vectors/_exports.js.map +1 -0
- package/build/vectors/asserts.d.ts +153 -49
- package/build/vectors/asserts.d.ts.map +1 -1
- package/build/vectors/asserts.js +202 -52
- package/build/vectors/asserts.js.map +1 -1
- package/build/vectors/core.d.ts +216 -137
- package/build/vectors/core.d.ts.map +1 -1
- package/build/vectors/core.js +217 -158
- package/build/vectors/core.js.map +1 -1
- package/build/vectors/index.d.ts +1 -0
- package/build/vectors/index.d.ts.map +1 -1
- package/build/vectors/index.js +3 -0
- package/build/vectors/index.js.map +1 -1
- package/build/vectors/interpolation.d.ts +39 -27
- package/build/vectors/interpolation.d.ts.map +1 -1
- package/build/vectors/interpolation.js +39 -27
- package/build/vectors/interpolation.js.map +1 -1
- package/build/vectors/predefined.d.ts +48 -24
- package/build/vectors/predefined.d.ts.map +1 -1
- package/build/vectors/predefined.js +38 -18
- package/build/vectors/predefined.js.map +1 -1
- package/package.json +12 -15
package/build/vectors/core.js
CHANGED
|
@@ -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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const original = [1, 2, 3];
|
|
18
|
+
* const copy = VectorClone(original);
|
|
19
|
+
* copy[0] = 10; // original remains unchanged
|
|
20
|
+
* ```
|
|
19
21
|
*/
|
|
20
22
|
export function VectorClone(vector) {
|
|
21
23
|
AssertVector(vector);
|
|
@@ -32,10 +34,12 @@ export function VectorClone(vector) {
|
|
|
32
34
|
* @returns True if vectors are equal within tolerance, false otherwise
|
|
33
35
|
*
|
|
34
36
|
* @example
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const a = [1.0001, 2.0001];
|
|
39
|
+
* const b = [1.0002, 2.0002];
|
|
40
|
+
* const exactlyEqual = VectorEquals(a, b); // false
|
|
41
|
+
* const approximatelyEqual = VectorEquals(a, b, 0.001); // true
|
|
42
|
+
* ```
|
|
39
43
|
*/
|
|
40
44
|
export function VectorEquals(a, b, tolerance = 0) {
|
|
41
45
|
AssertVectors([a, b]);
|
|
@@ -64,9 +68,11 @@ export function VectorEquals(a, b, tolerance = 0) {
|
|
|
64
68
|
* @returns String representation of the vector
|
|
65
69
|
*
|
|
66
70
|
* @example
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const vec = [1, 2, 3];
|
|
73
|
+
* const parens = VectorToString(vec, 'parens'); // "(1, 2, 3)"
|
|
74
|
+
* const brackets = VectorToString(vec, 'brackets'); // "[1, 2, 3]"
|
|
75
|
+
* ```
|
|
70
76
|
*/
|
|
71
77
|
export function VectorToString(vector, style = 'parens') {
|
|
72
78
|
AssertVector(vector);
|
|
@@ -74,12 +80,7 @@ export function VectorToString(vector, style = 'parens') {
|
|
|
74
80
|
if (style === 'parens') {
|
|
75
81
|
return `(${components})`;
|
|
76
82
|
}
|
|
77
|
-
|
|
78
|
-
return `[${components}]`;
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
throw new Error(`Invalid style: ${style}. Use 'parens' or 'brackets'.`);
|
|
82
|
-
}
|
|
83
|
+
return `[${components}]`;
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
86
|
* Performs component-wise addition of two vectors.
|
|
@@ -91,9 +92,11 @@ export function VectorToString(vector, style = 'parens') {
|
|
|
91
92
|
* @returns New vector where each component is the sum of corresponding components
|
|
92
93
|
*
|
|
93
94
|
* @example
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const position = [10, 20, 30];
|
|
97
|
+
* const velocity = [1, -2, 0.5];
|
|
98
|
+
* const newPosition = VectorAdd(position, velocity); // [11, 18, 30.5]
|
|
99
|
+
* ```
|
|
97
100
|
*/
|
|
98
101
|
export function VectorAdd(a, b) {
|
|
99
102
|
AssertVectors([a, b]);
|
|
@@ -117,9 +120,11 @@ export function VectorAdd(a, b) {
|
|
|
117
120
|
* @returns New vector where each component is the difference of corresponding components
|
|
118
121
|
*
|
|
119
122
|
* @example
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const target = [100, 50, 0];
|
|
125
|
+
* const current = [80, 30, 0];
|
|
126
|
+
* const direction = VectorSubtract(target, current); // [20, 20, 0]
|
|
127
|
+
* ```
|
|
123
128
|
*/
|
|
124
129
|
export function VectorSubtract(a, b) {
|
|
125
130
|
AssertVectors([a, b]);
|
|
@@ -143,10 +148,12 @@ export function VectorSubtract(a, b) {
|
|
|
143
148
|
* @returns New vector with multiplied components
|
|
144
149
|
*
|
|
145
150
|
* @example
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
* ```typescript
|
|
152
|
+
* const velocity = [10, 5, 0];
|
|
153
|
+
* const scaled = VectorMultiply(velocity, 2); // [20, 10, 0] - scalar multiplication
|
|
154
|
+
* const factors = [1, -1, 0.5];
|
|
155
|
+
* const componentWise = VectorMultiply(velocity, factors); // [10, -5, 0] - component-wise
|
|
156
|
+
* ```
|
|
150
157
|
*/
|
|
151
158
|
export function VectorMultiply(a, b) {
|
|
152
159
|
const result = [];
|
|
@@ -180,9 +187,11 @@ export function VectorMultiply(a, b) {
|
|
|
180
187
|
* @returns The straight-line distance between the two points represented by the vectors
|
|
181
188
|
*
|
|
182
189
|
* @example
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
* ```typescript
|
|
191
|
+
* const pointA = [0, 0, 0];
|
|
192
|
+
* const pointB = [3, 4, 0];
|
|
193
|
+
* const distance = VectorDistance(pointA, pointB); // 5.0 (3-4-5 triangle)
|
|
194
|
+
* ```
|
|
186
195
|
*/
|
|
187
196
|
export function VectorDistance(a, b) {
|
|
188
197
|
return Math.sqrt(VectorDistanceSquared(a, b));
|
|
@@ -197,9 +206,11 @@ export function VectorDistance(a, b) {
|
|
|
197
206
|
* @returns The squared distance between vectors
|
|
198
207
|
*
|
|
199
208
|
* @example
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
209
|
+
* ```typescript
|
|
210
|
+
* const pointA = [1, 1];
|
|
211
|
+
* const pointB = [4, 5];
|
|
212
|
+
* const distSq = VectorDistanceSquared(pointA, pointB); // 25 (faster than distance comparison)
|
|
213
|
+
* ```
|
|
203
214
|
*/
|
|
204
215
|
export function VectorDistanceSquared(a, b) {
|
|
205
216
|
AssertVectors([a, b]);
|
|
@@ -209,7 +220,8 @@ export function VectorDistanceSquared(a, b) {
|
|
|
209
220
|
AssertVectorValue(av, {});
|
|
210
221
|
const bv = b[i];
|
|
211
222
|
AssertVectorValue(bv, {});
|
|
212
|
-
|
|
223
|
+
const diff = bv - av;
|
|
224
|
+
sum += diff * diff;
|
|
213
225
|
}
|
|
214
226
|
return sum;
|
|
215
227
|
}
|
|
@@ -223,12 +235,13 @@ export function VectorDistanceSquared(a, b) {
|
|
|
223
235
|
* @returns The dot product (scalar value)
|
|
224
236
|
*
|
|
225
237
|
* @example
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
238
|
+
* ```typescript
|
|
239
|
+
* const forward = [0, 0, 1];
|
|
240
|
+
* const direction = [0, 0, 2];
|
|
241
|
+
* const dot = VectorDot(forward, direction); // 2 (same direction)
|
|
242
|
+
* const perpendicular = [1, 0, 0];
|
|
243
|
+
* const dotPerp = VectorDot(forward, perpendicular); // 0 (perpendicular)
|
|
244
|
+
* ```
|
|
232
245
|
*/
|
|
233
246
|
export function VectorDot(a, b) {
|
|
234
247
|
AssertVectors([a, b]);
|
|
@@ -253,11 +266,12 @@ export function VectorDot(a, b) {
|
|
|
253
266
|
* @throws {VectorError} If the vector is zero or has infinite magnitude
|
|
254
267
|
*
|
|
255
268
|
* @example
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const vector = [3, 4, 0];
|
|
271
|
+
* const normalized = VectorNormalize(vector); // [0.6, 0.8, 0] (magnitude = 1)
|
|
272
|
+
* const direction = [10, 0, 0];
|
|
273
|
+
* const unitDirection = VectorNormalize(direction); // [1, 0, 0]
|
|
274
|
+
* ```
|
|
261
275
|
*/
|
|
262
276
|
export function VectorNormalize(a) {
|
|
263
277
|
AssertVector(a);
|
|
@@ -282,18 +296,19 @@ export function VectorNormalize(a) {
|
|
|
282
296
|
* @returns The magnitude (length) of the vector
|
|
283
297
|
*
|
|
284
298
|
* @example
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
299
|
+
* ```typescript
|
|
300
|
+
* const velocity = [3, 4, 0];
|
|
301
|
+
* const speed = VectorMagnitude(velocity); // 5.0
|
|
302
|
+
* const unitVector = [1, 0, 0];
|
|
303
|
+
* const unitLength = VectorMagnitude(unitVector); // 1.0
|
|
304
|
+
* ```
|
|
290
305
|
*/
|
|
291
306
|
export function VectorMagnitude(a) {
|
|
292
307
|
AssertVector(a);
|
|
293
308
|
let sum = 0;
|
|
294
309
|
for (const av of a) {
|
|
295
310
|
AssertVectorValue(av, {});
|
|
296
|
-
sum +=
|
|
311
|
+
sum += av * av;
|
|
297
312
|
}
|
|
298
313
|
return Math.sqrt(sum);
|
|
299
314
|
}
|
|
@@ -306,11 +321,12 @@ export function VectorMagnitude(a) {
|
|
|
306
321
|
* @returns New vector with absolute values of all components
|
|
307
322
|
*
|
|
308
323
|
* @example
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
324
|
+
* ```typescript
|
|
325
|
+
* const vector = [-3, 4, -2];
|
|
326
|
+
* const absolute = VectorAbs(vector); // [3, 4, 2]
|
|
327
|
+
* const mixed = [1.5, -2.7, 0];
|
|
328
|
+
* const absValues = VectorAbs(mixed); // [1.5, 2.7, 0]
|
|
329
|
+
* ```
|
|
314
330
|
*/
|
|
315
331
|
export function VectorAbs(a) {
|
|
316
332
|
AssertVector(a);
|
|
@@ -329,11 +345,12 @@ export function VectorAbs(a) {
|
|
|
329
345
|
* @returns True if all components are zero, false otherwise
|
|
330
346
|
*
|
|
331
347
|
* @example
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
348
|
+
* ```typescript
|
|
349
|
+
* const zero = [0, 0, 0];
|
|
350
|
+
* const isZero = VectorIsZero(zero); // true
|
|
351
|
+
* const notZero = [0, 0.001, 0];
|
|
352
|
+
* const isNotZero = VectorIsZero(notZero); // false
|
|
353
|
+
* ```
|
|
337
354
|
*/
|
|
338
355
|
export function VectorIsZero(vector) {
|
|
339
356
|
return vector.every((v) => v === 0);
|
|
@@ -349,13 +366,14 @@ export function VectorIsZero(vector) {
|
|
|
349
366
|
* @throws {VectorError} If either vector is zero
|
|
350
367
|
*
|
|
351
368
|
* @example
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
369
|
+
* ```typescript
|
|
370
|
+
* const right = [1, 0, 0];
|
|
371
|
+
* const up = [0, 1, 0];
|
|
372
|
+
* const angle = VectorAngle(right, up); // π/2 (90 degrees)
|
|
373
|
+
* const forward = [0, 0, 1];
|
|
374
|
+
* const backward = [0, 0, -1];
|
|
375
|
+
* const oppositeAngle = VectorAngle(forward, backward); // π (180 degrees)
|
|
376
|
+
* ```
|
|
359
377
|
*/
|
|
360
378
|
export function VectorAngle(a, b) {
|
|
361
379
|
AssertVectors([a, b]);
|
|
@@ -375,9 +393,11 @@ export function VectorAngle(a, b) {
|
|
|
375
393
|
* @returns New rotated 2D vector
|
|
376
394
|
*
|
|
377
395
|
* @example
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
396
|
+
* ```typescript
|
|
397
|
+
* const right = [1, 0];
|
|
398
|
+
* const rotated90 = Vector2Rotate(right, Math.PI / 2); // [0, 1] (up)
|
|
399
|
+
* const rotated180 = Vector2Rotate(right, Math.PI); // [-1, 0] (left)
|
|
400
|
+
* ```
|
|
381
401
|
*/
|
|
382
402
|
export function Vector2Rotate(vector, radians) {
|
|
383
403
|
AssertVector2(vector);
|
|
@@ -397,9 +417,11 @@ export function Vector2Rotate(vector, radians) {
|
|
|
397
417
|
* @returns Unit vector pointing in the specified direction
|
|
398
418
|
*
|
|
399
419
|
* @example
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
420
|
+
* ```typescript
|
|
421
|
+
* const right = Vector2FromAngle(0); // [1, 0]
|
|
422
|
+
* const up = Vector2FromAngle(Math.PI / 2); // [0, 1]
|
|
423
|
+
* const diagonal = Vector2FromAngle(Math.PI / 4); // [0.707, 0.707]
|
|
424
|
+
* ```
|
|
403
425
|
*/
|
|
404
426
|
export function Vector2FromAngle(radians) {
|
|
405
427
|
return [Math.cos(radians), Math.sin(radians)];
|
|
@@ -414,10 +436,12 @@ export function Vector2FromAngle(radians) {
|
|
|
414
436
|
* @returns Scalar cross product (positive = counterclockwise, negative = clockwise)
|
|
415
437
|
*
|
|
416
438
|
* @example
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
439
|
+
* ```typescript
|
|
440
|
+
* const right = [1, 0];
|
|
441
|
+
* const up = [0, 1];
|
|
442
|
+
* const cross = Vector2Cross(right, up); // 1 (counterclockwise)
|
|
443
|
+
* const crossReverse = Vector2Cross(up, right); // -1 (clockwise)
|
|
444
|
+
* ```
|
|
421
445
|
*/
|
|
422
446
|
export function Vector2Cross(a, b) {
|
|
423
447
|
AssertVector2(a);
|
|
@@ -435,9 +459,11 @@ export function Vector2Cross(a, b) {
|
|
|
435
459
|
* @throws {VectorError} If vector b is zero
|
|
436
460
|
*
|
|
437
461
|
* @example
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
462
|
+
* ```typescript
|
|
463
|
+
* const force = [5, 3, 0];
|
|
464
|
+
* const surface = [1, 0, 0];
|
|
465
|
+
* const perpendicular = Vector3Reject(force, surface); // [0, 3, 0]
|
|
466
|
+
* ```
|
|
441
467
|
*/
|
|
442
468
|
export function Vector3Reject(a, b) {
|
|
443
469
|
AssertVector3(a);
|
|
@@ -459,16 +485,18 @@ export function Vector3Reject(a, b) {
|
|
|
459
485
|
* @throws {VectorError} If vector b is zero
|
|
460
486
|
*
|
|
461
487
|
* @example
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
488
|
+
* ```typescript
|
|
489
|
+
* const force = [5, 3, 0];
|
|
490
|
+
* const surface = [1, 0, 0];
|
|
491
|
+
* const parallel = VectorProject(force, surface); // [5, 0, 0]
|
|
492
|
+
* ```
|
|
465
493
|
*/
|
|
466
494
|
export function VectorProject(a, b) {
|
|
467
495
|
AssertVectors([a, b]);
|
|
468
496
|
if (VectorIsZero(b))
|
|
469
497
|
throw new VectorError('Cannot project onto a zero vector');
|
|
470
498
|
const dot = VectorDot(a, b);
|
|
471
|
-
const magSquared =
|
|
499
|
+
const magSquared = VectorDot(b, b);
|
|
472
500
|
const scalar = dot / magSquared;
|
|
473
501
|
const result = [];
|
|
474
502
|
for (const bv of b) {
|
|
@@ -488,9 +516,11 @@ export function VectorProject(a, b) {
|
|
|
488
516
|
* @throws {VectorError} If the normal is a zero vector
|
|
489
517
|
*
|
|
490
518
|
* @example
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
519
|
+
* ```typescript
|
|
520
|
+
* const incoming = [1, -1, 0];
|
|
521
|
+
* const normal = [0, 1, 0]; // surface normal (upward)
|
|
522
|
+
* const reflected = Vector3Reflect(incoming, normal); // [1, 1, 0]
|
|
523
|
+
* ```
|
|
494
524
|
*/
|
|
495
525
|
export function Vector3Reflect(incident, normal) {
|
|
496
526
|
AssertVector3(incident);
|
|
@@ -510,11 +540,12 @@ export function Vector3Reflect(incident, normal) {
|
|
|
510
540
|
* @returns Vector perpendicular to both a and b (following right-hand rule)
|
|
511
541
|
*
|
|
512
542
|
* @example
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
543
|
+
* ```typescript
|
|
544
|
+
* const right = [1, 0, 0];
|
|
545
|
+
* const forward = [0, 0, 1];
|
|
546
|
+
* const up = Vector3Cross(right, forward); // [0, 1, 0]
|
|
547
|
+
* const normal = Vector3Cross([1, 0, 0], [0, 1, 0]); // [0, 0, 1]
|
|
548
|
+
* ```
|
|
518
549
|
*/
|
|
519
550
|
export function Vector3Cross(a, b) {
|
|
520
551
|
AssertVector3(a);
|
|
@@ -535,9 +566,11 @@ export function Vector3Cross(a, b) {
|
|
|
535
566
|
* @returns Magnitude of the cross product
|
|
536
567
|
*
|
|
537
568
|
* @example
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
569
|
+
* ```typescript
|
|
570
|
+
* const side1 = [3, 0, 0];
|
|
571
|
+
* const side2 = [0, 4, 0];
|
|
572
|
+
* const area = VectorCrossMagnitude(side1, side2); // 12 (area of rectangle)
|
|
573
|
+
* ```
|
|
541
574
|
*/
|
|
542
575
|
export function VectorCrossMagnitude(a, b) {
|
|
543
576
|
AssertVector3(a);
|
|
@@ -556,10 +589,12 @@ export function VectorCrossMagnitude(a, b) {
|
|
|
556
589
|
* @returns Signed volume (positive = right-handed orientation)
|
|
557
590
|
*
|
|
558
591
|
* @example
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
592
|
+
* ```typescript
|
|
593
|
+
* const x = [1, 0, 0];
|
|
594
|
+
* const y = [0, 1, 0];
|
|
595
|
+
* const z = [0, 0, 1];
|
|
596
|
+
* const volume = Vector3ScalarTripleProduct(x, y, z); // 1 (unit cube)
|
|
597
|
+
* ```
|
|
563
598
|
*/
|
|
564
599
|
export function Vector3ScalarTripleProduct(a, b, c) {
|
|
565
600
|
AssertVector3(a);
|
|
@@ -579,10 +614,12 @@ export function Vector3ScalarTripleProduct(a, b, c) {
|
|
|
579
614
|
* @returns Vector result of a × (b × c)
|
|
580
615
|
*
|
|
581
616
|
* @example
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
617
|
+
* ```typescript
|
|
618
|
+
* const a = [1, 0, 0];
|
|
619
|
+
* const b = [0, 1, 0];
|
|
620
|
+
* const c = [0, 0, 1];
|
|
621
|
+
* const result = Vector3TripleProduct(a, b, c); // [0, 0, 0]
|
|
622
|
+
* ```
|
|
586
623
|
*/
|
|
587
624
|
export function Vector3TripleProduct(a, b, c) {
|
|
588
625
|
AssertVector3(a);
|
|
@@ -602,9 +639,11 @@ export function Vector3TripleProduct(a, b, c) {
|
|
|
602
639
|
* @returns The reflected vector
|
|
603
640
|
*
|
|
604
641
|
* @example
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
642
|
+
* ```typescript
|
|
643
|
+
* const incoming = [1, -1, 0];
|
|
644
|
+
* const wall = [0, 1, 0]; // vertical wall normal
|
|
645
|
+
* const bounced = VectorReflect(incoming, wall); // [1, 1, 0]
|
|
646
|
+
* ```
|
|
608
647
|
*/
|
|
609
648
|
export function VectorReflect(incident, normal) {
|
|
610
649
|
AssertVectors([incident, normal]);
|
|
@@ -630,11 +669,12 @@ export function VectorReflect(incident, normal) {
|
|
|
630
669
|
* @returns Vector with all components negated
|
|
631
670
|
*
|
|
632
671
|
* @example
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
672
|
+
* ```typescript
|
|
673
|
+
* const forward = [0, 0, 1];
|
|
674
|
+
* const backward = VectorNegate(forward); // [0, 0, -1]
|
|
675
|
+
* const velocity = [5, -3, 2];
|
|
676
|
+
* const opposite = VectorNegate(velocity); // [-5, 3, -2]
|
|
677
|
+
* ```
|
|
638
678
|
*/
|
|
639
679
|
export function VectorNegate(a) {
|
|
640
680
|
const result = [];
|
|
@@ -661,10 +701,12 @@ export function VectorNegate(a) {
|
|
|
661
701
|
* @throws {VectorError} If any divisor component is zero
|
|
662
702
|
*
|
|
663
703
|
* @example
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
704
|
+
* ```typescript
|
|
705
|
+
* const velocity = [20, 10, 0];
|
|
706
|
+
* const halved = VectorDivide(velocity, 2); // [10, 5, 0] - scalar division
|
|
707
|
+
* const factors = [2, 5, 1];
|
|
708
|
+
* const componentWise = VectorDivide(velocity, factors); // [10, 2, 0] - component-wise
|
|
709
|
+
* ```
|
|
668
710
|
*/
|
|
669
711
|
export function VectorDivide(a, b) {
|
|
670
712
|
const result = [];
|
|
@@ -705,12 +747,13 @@ export function VectorDivide(a, b) {
|
|
|
705
747
|
* @returns New vector with each component clamped between min and max
|
|
706
748
|
*
|
|
707
749
|
* @example
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
750
|
+
* ```typescript
|
|
751
|
+
* const v = [5, -3, 12, 0];
|
|
752
|
+
* VectorClamp(v, 0, 10); // [5, 0, 10, 0] - scalar bounds
|
|
753
|
+
* const mins = [0, -5, 0, -1];
|
|
754
|
+
* const maxs = [10, 5, 8, 1];
|
|
755
|
+
* VectorClamp(v, mins, maxs); // [5, -3, 8, 0] - per-component bounds
|
|
756
|
+
* ```
|
|
714
757
|
*/
|
|
715
758
|
export function VectorClamp(a, min, max) {
|
|
716
759
|
AssertVector(a);
|
|
@@ -736,44 +779,58 @@ export function VectorClamp(a, min, max) {
|
|
|
736
779
|
* @throws {VectorError} If max is negative
|
|
737
780
|
*
|
|
738
781
|
* @example
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
export function
|
|
746
|
-
if (
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const scaleFactor = max / magnitude;
|
|
752
|
-
return VectorMultiply(a, scaleFactor);
|
|
753
|
-
}
|
|
754
|
-
/**
|
|
755
|
-
* Validates if the input is a properly formatted vector.
|
|
756
|
-
* Performs comprehensive validation without throwing errors.
|
|
757
|
-
* Useful for input validation and defensive programming.
|
|
758
|
-
*
|
|
759
|
-
* @param vector - Input to validate
|
|
760
|
-
* @returns True if input is a valid vector, false otherwise
|
|
761
|
-
*
|
|
762
|
-
* @example
|
|
763
|
-
* const valid = VectorIsValid([1, 2, 3]); // true
|
|
764
|
-
* const invalid = VectorIsValid("not a vector"); // false
|
|
765
|
-
* const nullVector = VectorIsValid(null); // false
|
|
766
|
-
* const emptyArray = VectorIsValid([]); // depends on implementation
|
|
767
|
-
*/
|
|
768
|
-
export function VectorIsValid(vector) {
|
|
769
|
-
try {
|
|
782
|
+
* ```typescript
|
|
783
|
+
* const velocity = [15, 20, 0]; // magnitude ≈ 25
|
|
784
|
+
* const limited = VectorLimit(velocity, 10); // magnitude = 10, same direction
|
|
785
|
+
* const small = [1, 1, 0]; // magnitude ≈ 1.414
|
|
786
|
+
* const unchanged = VectorLimit(small, 5); // unchanged since already under limit
|
|
787
|
+
* ```
|
|
788
|
+
export function VectorGramSchmidt<T extends TAnyVector>(vectors: T[], normalize: boolean = false): TVectorResult<T>[] {
|
|
789
|
+
if (vectors.length === 0) throw new VectorError('GramSchmidt: Empty Vector Set');
|
|
790
|
+
const [firstVector] = vectors;
|
|
791
|
+
if (!firstVector) throw new VectorError('GramSchmidt: Undefined First Vector');
|
|
792
|
+
const dimension = firstVector.length;
|
|
793
|
+
for (const [i, vector] of vectors.entries()) {
|
|
770
794
|
AssertVector(vector);
|
|
771
|
-
|
|
795
|
+
if (vector.length !== dimension) throw new VectorError(`GramSchmidt: Vector at index ${i} has different dimension than first vector. Expected ${dimension}, got ${vector.length}`);
|
|
796
|
+
if (VectorIsZero(vector)) throw new VectorError(`GramSchmidt: Vector at index ${i} is a zero vector. Cannot orthogonalize zero vectors.`);
|
|
772
797
|
}
|
|
773
|
-
|
|
774
|
-
|
|
798
|
+
|
|
799
|
+
const result: TVectorResult<T>[] = [];
|
|
800
|
+
|
|
801
|
+
for (const [i, currentVector] of vectors.entries()) {
|
|
802
|
+
AssertVector(currentVector);
|
|
803
|
+
|
|
804
|
+
// Start with a clone of the current vector
|
|
805
|
+
let orthogonalVector = VectorClone(currentVector);
|
|
806
|
+
|
|
807
|
+
// Subtract projections of all previous vectors
|
|
808
|
+
for (let j = 0; j < i; j++) {
|
|
809
|
+
const previousVector = result[j];
|
|
810
|
+
AssertVector(previousVector);
|
|
811
|
+
|
|
812
|
+
// Both vectors have the same dimension, projection result is compatible
|
|
813
|
+
const vectorT = currentVector as unknown as T;
|
|
814
|
+
const prevT = previousVector as unknown as T;
|
|
815
|
+
const projection = VectorProject(vectorT, prevT);
|
|
816
|
+
orthogonalVector = VectorSubtract(orthogonalVector as unknown as T, projection as unknown as T);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
if (VectorIsZero(orthogonalVector as unknown as T)) {
|
|
820
|
+
throw new VectorError(`GramSchmidt: Vector at index ${i} is linearly dependent on previous vectors. Cannot orthogonalize linearly dependent vectors.`);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (normalize) {
|
|
824
|
+
orthogonalVector = VectorNormalize(orthogonalVector as unknown as T);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
result.push(orthogonalVector as TVectorResult<T>);
|
|
775
828
|
}
|
|
829
|
+
|
|
830
|
+
return result;
|
|
831
|
+
}}
|
|
776
832
|
}
|
|
833
|
+
|
|
777
834
|
/**
|
|
778
835
|
* Performs Gram-Schmidt orthogonalization on a set of vectors.
|
|
779
836
|
* Converts a set of linearly independent vectors into an orthogonal (or orthonormal) set.
|
|
@@ -786,9 +843,11 @@ export function VectorIsValid(vector) {
|
|
|
786
843
|
* @throws {VectorError} If vectors are linearly dependent or invalid
|
|
787
844
|
*
|
|
788
845
|
* @example
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
846
|
+
* ```typescript
|
|
847
|
+
* const vectors = [[1, 1, 0], [1, 0, 1], [0, 1, 1]];
|
|
848
|
+
* const orthogonal = VectorGramSchmidt(vectors); // Orthogonal set
|
|
849
|
+
* const orthonormal = VectorGramSchmidt(vectors, true); // Orthonormal set
|
|
850
|
+
* ```
|
|
792
851
|
*/
|
|
793
852
|
export function VectorGramSchmidt(vectors, normalize = false) {
|
|
794
853
|
if (vectors.length === 0)
|