@pawells/math-extended 1.0.1
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/LICENSE +21 -0
- package/README.md +319 -0
- package/build/angles.d.ts +31 -0
- package/build/angles.d.ts.map +1 -0
- package/build/angles.js +85 -0
- package/build/angles.js.map +1 -0
- package/build/angles.spec.d.ts +2 -0
- package/build/angles.spec.d.ts.map +1 -0
- package/build/angles.spec.js +147 -0
- package/build/angles.spec.js.map +1 -0
- package/build/clamp.d.ts +17 -0
- package/build/clamp.d.ts.map +1 -0
- package/build/clamp.js +19 -0
- package/build/clamp.js.map +1 -0
- package/build/clamp.spec.d.ts +2 -0
- package/build/clamp.spec.d.ts.map +1 -0
- package/build/clamp.spec.js +19 -0
- package/build/clamp.spec.js.map +1 -0
- package/build/documentation-validation.spec.d.ts +11 -0
- package/build/documentation-validation.spec.d.ts.map +1 -0
- package/build/documentation-validation.spec.js +401 -0
- package/build/documentation-validation.spec.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +8 -0
- package/build/index.js.map +1 -0
- package/build/interpolation.d.ts +175 -0
- package/build/interpolation.d.ts.map +1 -0
- package/build/interpolation.js +369 -0
- package/build/interpolation.js.map +1 -0
- package/build/interpolation.spec.d.ts +2 -0
- package/build/interpolation.spec.d.ts.map +1 -0
- package/build/interpolation.spec.js +480 -0
- package/build/interpolation.spec.js.map +1 -0
- package/build/matrices/arithmetic.d.ts +411 -0
- package/build/matrices/arithmetic.d.ts.map +1 -0
- package/build/matrices/arithmetic.js +954 -0
- package/build/matrices/arithmetic.js.map +1 -0
- package/build/matrices/arithmetic.spec.d.ts +2 -0
- package/build/matrices/arithmetic.spec.d.ts.map +1 -0
- package/build/matrices/arithmetic.spec.js +915 -0
- package/build/matrices/arithmetic.spec.js.map +1 -0
- package/build/matrices/asserts.d.ts +306 -0
- package/build/matrices/asserts.d.ts.map +1 -0
- package/build/matrices/asserts.js +396 -0
- package/build/matrices/asserts.js.map +1 -0
- package/build/matrices/asserts.spec.d.ts +2 -0
- package/build/matrices/asserts.spec.d.ts.map +1 -0
- package/build/matrices/asserts.spec.js +565 -0
- package/build/matrices/asserts.spec.js.map +1 -0
- package/build/matrices/core.d.ts +168 -0
- package/build/matrices/core.d.ts.map +1 -0
- package/build/matrices/core.js +457 -0
- package/build/matrices/core.js.map +1 -0
- package/build/matrices/core.spec.d.ts +2 -0
- package/build/matrices/core.spec.d.ts.map +1 -0
- package/build/matrices/core.spec.js +634 -0
- package/build/matrices/core.spec.js.map +1 -0
- package/build/matrices/decompositions.d.ts +326 -0
- package/build/matrices/decompositions.d.ts.map +1 -0
- package/build/matrices/decompositions.js +816 -0
- package/build/matrices/decompositions.js.map +1 -0
- package/build/matrices/decompositions.spec.d.ts +2 -0
- package/build/matrices/decompositions.spec.d.ts.map +1 -0
- package/build/matrices/decompositions.spec.js +195 -0
- package/build/matrices/decompositions.spec.js.map +1 -0
- package/build/matrices/index.d.ts +9 -0
- package/build/matrices/index.d.ts.map +1 -0
- package/build/matrices/index.js +9 -0
- package/build/matrices/index.js.map +1 -0
- package/build/matrices/linear-algebra.d.ts +64 -0
- package/build/matrices/linear-algebra.d.ts.map +1 -0
- package/build/matrices/linear-algebra.js +253 -0
- package/build/matrices/linear-algebra.js.map +1 -0
- package/build/matrices/linear-algebra.spec.d.ts +2 -0
- package/build/matrices/linear-algebra.spec.d.ts.map +1 -0
- package/build/matrices/linear-algebra.spec.js +355 -0
- package/build/matrices/linear-algebra.spec.js.map +1 -0
- package/build/matrices/normalization.d.ts +62 -0
- package/build/matrices/normalization.d.ts.map +1 -0
- package/build/matrices/normalization.js +167 -0
- package/build/matrices/normalization.js.map +1 -0
- package/build/matrices/normalization.spec.d.ts +2 -0
- package/build/matrices/normalization.spec.d.ts.map +1 -0
- package/build/matrices/normalization.spec.js +335 -0
- package/build/matrices/normalization.spec.js.map +1 -0
- package/build/matrices/transformations.d.ts +484 -0
- package/build/matrices/transformations.d.ts.map +1 -0
- package/build/matrices/transformations.js +592 -0
- package/build/matrices/transformations.js.map +1 -0
- package/build/matrices/transformations.spec.d.ts +2 -0
- package/build/matrices/transformations.spec.d.ts.map +1 -0
- package/build/matrices/transformations.spec.js +755 -0
- package/build/matrices/transformations.spec.js.map +1 -0
- package/build/matrices/types.d.ts +134 -0
- package/build/matrices/types.d.ts.map +1 -0
- package/build/matrices/types.js +6 -0
- package/build/matrices/types.js.map +1 -0
- package/build/quaternions/asserts.d.ts +77 -0
- package/build/quaternions/asserts.d.ts.map +1 -0
- package/build/quaternions/asserts.js +175 -0
- package/build/quaternions/asserts.js.map +1 -0
- package/build/quaternions/asserts.spec.d.ts +2 -0
- package/build/quaternions/asserts.spec.d.ts.map +1 -0
- package/build/quaternions/asserts.spec.js +320 -0
- package/build/quaternions/asserts.spec.js.map +1 -0
- package/build/quaternions/conversions.d.ts +73 -0
- package/build/quaternions/conversions.d.ts.map +1 -0
- package/build/quaternions/conversions.js +179 -0
- package/build/quaternions/conversions.js.map +1 -0
- package/build/quaternions/conversions.spec.d.ts +2 -0
- package/build/quaternions/conversions.spec.d.ts.map +1 -0
- package/build/quaternions/conversions.spec.js +344 -0
- package/build/quaternions/conversions.spec.js.map +1 -0
- package/build/quaternions/core.d.ts +203 -0
- package/build/quaternions/core.d.ts.map +1 -0
- package/build/quaternions/core.js +374 -0
- package/build/quaternions/core.js.map +1 -0
- package/build/quaternions/core.spec.d.ts +2 -0
- package/build/quaternions/core.spec.d.ts.map +1 -0
- package/build/quaternions/core.spec.js +294 -0
- package/build/quaternions/core.spec.js.map +1 -0
- package/build/quaternions/index.d.ts +7 -0
- package/build/quaternions/index.d.ts.map +1 -0
- package/build/quaternions/index.js +7 -0
- package/build/quaternions/index.js.map +1 -0
- package/build/quaternions/interpolation.d.ts +54 -0
- package/build/quaternions/interpolation.d.ts.map +1 -0
- package/build/quaternions/interpolation.js +201 -0
- package/build/quaternions/interpolation.js.map +1 -0
- package/build/quaternions/interpolation.spec.d.ts +2 -0
- package/build/quaternions/interpolation.spec.d.ts.map +1 -0
- package/build/quaternions/interpolation.spec.js +64 -0
- package/build/quaternions/interpolation.spec.js.map +1 -0
- package/build/quaternions/predefined.d.ts +36 -0
- package/build/quaternions/predefined.d.ts.map +1 -0
- package/build/quaternions/predefined.js +42 -0
- package/build/quaternions/predefined.js.map +1 -0
- package/build/quaternions/predefined.spec.d.ts +2 -0
- package/build/quaternions/predefined.spec.d.ts.map +1 -0
- package/build/quaternions/predefined.spec.js +35 -0
- package/build/quaternions/predefined.spec.js.map +1 -0
- package/build/quaternions/types.d.ts +55 -0
- package/build/quaternions/types.d.ts.map +1 -0
- package/build/quaternions/types.js +7 -0
- package/build/quaternions/types.js.map +1 -0
- package/build/random.d.ts +66 -0
- package/build/random.d.ts.map +1 -0
- package/build/random.js +115 -0
- package/build/random.js.map +1 -0
- package/build/random.spec.d.ts +2 -0
- package/build/random.spec.d.ts.map +1 -0
- package/build/random.spec.js +267 -0
- package/build/random.spec.js.map +1 -0
- package/build/vectors/asserts.d.ts +182 -0
- package/build/vectors/asserts.d.ts.map +1 -0
- package/build/vectors/asserts.js +285 -0
- package/build/vectors/asserts.js.map +1 -0
- package/build/vectors/asserts.spec.d.ts +2 -0
- package/build/vectors/asserts.spec.d.ts.map +1 -0
- package/build/vectors/asserts.spec.js +260 -0
- package/build/vectors/asserts.spec.js.map +1 -0
- package/build/vectors/core.d.ts +507 -0
- package/build/vectors/core.d.ts.map +1 -0
- package/build/vectors/core.js +825 -0
- package/build/vectors/core.js.map +1 -0
- package/build/vectors/core.spec.d.ts +2 -0
- package/build/vectors/core.spec.d.ts.map +1 -0
- package/build/vectors/core.spec.js +343 -0
- package/build/vectors/core.spec.js.map +1 -0
- package/build/vectors/index.d.ts +6 -0
- package/build/vectors/index.d.ts.map +1 -0
- package/build/vectors/index.js +6 -0
- package/build/vectors/index.js.map +1 -0
- package/build/vectors/interpolation.d.ts +404 -0
- package/build/vectors/interpolation.d.ts.map +1 -0
- package/build/vectors/interpolation.js +585 -0
- package/build/vectors/interpolation.js.map +1 -0
- package/build/vectors/interpolation.spec.d.ts +2 -0
- package/build/vectors/interpolation.spec.d.ts.map +1 -0
- package/build/vectors/interpolation.spec.js +378 -0
- package/build/vectors/interpolation.spec.js.map +1 -0
- package/build/vectors/predefined.d.ts +191 -0
- package/build/vectors/predefined.d.ts.map +1 -0
- package/build/vectors/predefined.js +191 -0
- package/build/vectors/predefined.js.map +1 -0
- package/build/vectors/predefined.spec.d.ts +2 -0
- package/build/vectors/predefined.spec.d.ts.map +1 -0
- package/build/vectors/predefined.spec.js +333 -0
- package/build/vectors/predefined.spec.js.map +1 -0
- package/build/vectors/types.d.ts +62 -0
- package/build/vectors/types.d.ts.map +1 -0
- package/build/vectors/types.js +6 -0
- package/build/vectors/types.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,825 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core vector mathematics operations for linear algebra and geometric calculations.
|
|
3
|
+
* Provides a comprehensive set of vector operations with type safety and error checking.
|
|
4
|
+
*/
|
|
5
|
+
import { Clamp } from '../clamp.js';
|
|
6
|
+
import { AssertVector, AssertVectors, AssertVectorValue, VectorError, AssertVector2, AssertVector3 } from './asserts.js';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a deep copy of a vector.
|
|
9
|
+
* Essential for avoiding mutations when performing operations that should preserve the original vector.
|
|
10
|
+
*
|
|
11
|
+
* @template T - The vector type extending TVector
|
|
12
|
+
* @param vector - The vector to clone
|
|
13
|
+
* @returns A new vector with identical components
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const original = [1, 2, 3];
|
|
17
|
+
* const copy = VectorClone(original);
|
|
18
|
+
* copy[0] = 10; // original remains unchanged
|
|
19
|
+
*/
|
|
20
|
+
export function VectorClone(vector) {
|
|
21
|
+
AssertVector(vector);
|
|
22
|
+
return vector.map((v) => v);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Compares two vectors for equality with optional tolerance for floating-point precision.
|
|
26
|
+
* Useful for comparing vectors that may have slight numerical differences due to calculations.
|
|
27
|
+
*
|
|
28
|
+
* @template T - The vector type extending TVector
|
|
29
|
+
* @param a - First vector to compare
|
|
30
|
+
* @param b - Second vector to compare
|
|
31
|
+
* @param tolerance - Maximum allowed difference between components (default: 0 for exact equality)
|
|
32
|
+
* @returns True if vectors are equal within tolerance, false otherwise
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const a = [1.0001, 2.0001];
|
|
36
|
+
* const b = [1.0002, 2.0002];
|
|
37
|
+
* const exactlyEqual = VectorEquals(a, b); // false
|
|
38
|
+
* const approximatelyEqual = VectorEquals(a, b, 0.001); // true
|
|
39
|
+
*/
|
|
40
|
+
export function VectorEquals(a, b, tolerance = 0) {
|
|
41
|
+
AssertVectors([a, b]);
|
|
42
|
+
if (a.length !== b.length)
|
|
43
|
+
return false;
|
|
44
|
+
for (let i = 0; i < a.length; i++) {
|
|
45
|
+
const av = a[i];
|
|
46
|
+
AssertVectorValue(av, {});
|
|
47
|
+
const bv = b[i];
|
|
48
|
+
AssertVectorValue(bv, {});
|
|
49
|
+
if (tolerance !== 0) {
|
|
50
|
+
if (Math.abs(av - bv) > tolerance)
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
else if (av !== bv)
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Converts a vector to a human-readable string representation.
|
|
60
|
+
* Useful for debugging, logging, and displaying vector values.
|
|
61
|
+
*
|
|
62
|
+
* @param vector - The vector to convert to string
|
|
63
|
+
* @param style - Output format: 'parens' for (x, y, z) or 'brackets' for [x, y, z]
|
|
64
|
+
* @returns String representation of the vector
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const vec = [1, 2, 3];
|
|
68
|
+
* const parens = VectorToString(vec, 'parens'); // "(1, 2, 3)"
|
|
69
|
+
* const brackets = VectorToString(vec, 'brackets'); // "[1, 2, 3]"
|
|
70
|
+
*/
|
|
71
|
+
export function VectorToString(vector, style = 'parens') {
|
|
72
|
+
AssertVector(vector);
|
|
73
|
+
const components = vector.map((v) => v.toString()).join(', ');
|
|
74
|
+
if (style === 'parens') {
|
|
75
|
+
return `(${components})`;
|
|
76
|
+
}
|
|
77
|
+
else if (style === 'brackets') {
|
|
78
|
+
return `[${components}]`;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw new Error(`Invalid style: ${style}. Use 'parens' or 'brackets'.`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Performs component-wise addition of two vectors.
|
|
86
|
+
* Fundamental operation for vector arithmetic, physics simulations, and geometric transformations.
|
|
87
|
+
*
|
|
88
|
+
* @template T - The vector type extending TVector
|
|
89
|
+
* @param a - First vector (augend)
|
|
90
|
+
* @param b - Second vector (addend)
|
|
91
|
+
* @returns New vector where each component is the sum of corresponding components
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* const position = [10, 20, 30];
|
|
95
|
+
* const velocity = [1, -2, 0.5];
|
|
96
|
+
* const newPosition = VectorAdd(position, velocity); // [11, 18, 30.5]
|
|
97
|
+
*/
|
|
98
|
+
export function VectorAdd(a, b) {
|
|
99
|
+
AssertVectors([a, b]);
|
|
100
|
+
const result = [];
|
|
101
|
+
for (let i = 0; i < a.length; i++) {
|
|
102
|
+
const av = a[i];
|
|
103
|
+
AssertVectorValue(av, {});
|
|
104
|
+
const bv = b[i];
|
|
105
|
+
AssertVectorValue(bv, {});
|
|
106
|
+
result.push(av + bv);
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Performs component-wise subtraction of two vectors.
|
|
112
|
+
* Essential for calculating displacement, relative positions, and vector differences.
|
|
113
|
+
*
|
|
114
|
+
* @template T - The vector type extending TVector
|
|
115
|
+
* @param a - First vector (minuend)
|
|
116
|
+
* @param b - Second vector (subtrahend)
|
|
117
|
+
* @returns New vector where each component is the difference of corresponding components
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* const target = [100, 50, 0];
|
|
121
|
+
* const current = [80, 30, 0];
|
|
122
|
+
* const direction = VectorSubtract(target, current); // [20, 20, 0]
|
|
123
|
+
*/
|
|
124
|
+
export function VectorSubtract(a, b) {
|
|
125
|
+
AssertVectors([a, b]);
|
|
126
|
+
const result = [];
|
|
127
|
+
for (let i = 0; i < a.length; i++) {
|
|
128
|
+
const av = a[i];
|
|
129
|
+
AssertVectorValue(av, {}, { index: i });
|
|
130
|
+
const bv = b[i];
|
|
131
|
+
AssertVectorValue(bv, {}, { index: i });
|
|
132
|
+
result.push(av - bv);
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Multiplies a vector by a scalar or performs component-wise multiplication with another vector.
|
|
138
|
+
* Scalar multiplication scales the vector magnitude; component-wise multiplication is useful for scaling factors.
|
|
139
|
+
*
|
|
140
|
+
* @template T - The vector type extending TVector
|
|
141
|
+
* @param a - Vector to multiply
|
|
142
|
+
* @param b - Scalar number or vector for component-wise multiplication
|
|
143
|
+
* @returns New vector with multiplied components
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* const velocity = [10, 5, 0];
|
|
147
|
+
* const scaled = VectorMultiply(velocity, 2); // [20, 10, 0] - scalar multiplication
|
|
148
|
+
* const factors = [1, -1, 0.5];
|
|
149
|
+
* const componentWise = VectorMultiply(velocity, factors); // [10, -5, 0] - component-wise
|
|
150
|
+
*/
|
|
151
|
+
export function VectorMultiply(a, b) {
|
|
152
|
+
const result = [];
|
|
153
|
+
if (Array.isArray(b)) {
|
|
154
|
+
if (b.length !== a.length)
|
|
155
|
+
throw new Error('Vector Size Mismatch');
|
|
156
|
+
for (let i = 0; i < a.length; i++) {
|
|
157
|
+
const av = a[i];
|
|
158
|
+
AssertVectorValue(av, {});
|
|
159
|
+
const bv = b[i];
|
|
160
|
+
AssertVectorValue(bv, {});
|
|
161
|
+
const prod = av * bv;
|
|
162
|
+
result.push(Object.is(prod, -0) ? 0 : prod);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (typeof b === 'number') {
|
|
166
|
+
for (const av of a) {
|
|
167
|
+
AssertVectorValue(av, {});
|
|
168
|
+
const prod = av * b;
|
|
169
|
+
result.push(Object.is(prod, -0) ? 0 : prod);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Calculates the Euclidean distance between two vectors.
|
|
176
|
+
* Fundamental for spatial calculations, collision detection, and proximity measurements.
|
|
177
|
+
*
|
|
178
|
+
* @param a - First vector
|
|
179
|
+
* @param b - Second vector
|
|
180
|
+
* @returns The straight-line distance between the two points represented by the vectors
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* const pointA = [0, 0, 0];
|
|
184
|
+
* const pointB = [3, 4, 0];
|
|
185
|
+
* const distance = VectorDistance(pointA, pointB); // 5.0 (3-4-5 triangle)
|
|
186
|
+
*/
|
|
187
|
+
export function VectorDistance(a, b) {
|
|
188
|
+
return Math.sqrt(VectorDistanceSquared(a, b));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Calculates the squared distance between two vectors.
|
|
192
|
+
* More efficient than VectorDistance when only relative distances matter,
|
|
193
|
+
* as it avoids the expensive square root operation.
|
|
194
|
+
*
|
|
195
|
+
* @param a - First vector
|
|
196
|
+
* @param b - Second vector
|
|
197
|
+
* @returns The squared distance between vectors
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* const pointA = [1, 1];
|
|
201
|
+
* const pointB = [4, 5];
|
|
202
|
+
* const distSq = VectorDistanceSquared(pointA, pointB); // 25 (faster than distance comparison)
|
|
203
|
+
*/
|
|
204
|
+
export function VectorDistanceSquared(a, b) {
|
|
205
|
+
AssertVectors([a, b]);
|
|
206
|
+
let sum = 0;
|
|
207
|
+
for (let i = 0; i < a.length; i++) {
|
|
208
|
+
const av = a[i];
|
|
209
|
+
AssertVectorValue(av, {});
|
|
210
|
+
const bv = b[i];
|
|
211
|
+
AssertVectorValue(bv, {});
|
|
212
|
+
sum += Math.pow(bv - av, 2);
|
|
213
|
+
}
|
|
214
|
+
return sum;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Calculates the dot product (scalar product) of two vectors.
|
|
218
|
+
* Fundamental operation for projections, angles, and determining vector relationships.
|
|
219
|
+
* Returns positive for acute angles, zero for perpendicular vectors, negative for obtuse angles.
|
|
220
|
+
*
|
|
221
|
+
* @param a - First vector
|
|
222
|
+
* @param b - Second vector
|
|
223
|
+
* @returns The dot product (scalar value)
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* const forward = [0, 0, 1];
|
|
227
|
+
* const direction = [0, 0, 2];
|
|
228
|
+
* const dot = VectorDot(forward, direction); // 2 (same direction)
|
|
229
|
+
*
|
|
230
|
+
* const perpendicular = [1, 0, 0];
|
|
231
|
+
* const dotPerp = VectorDot(forward, perpendicular); // 0 (perpendicular)
|
|
232
|
+
*/
|
|
233
|
+
export function VectorDot(a, b) {
|
|
234
|
+
AssertVectors([a, b]);
|
|
235
|
+
let dotProduct = 0;
|
|
236
|
+
for (let i = 0; i < a.length; i++) {
|
|
237
|
+
const av = a[i];
|
|
238
|
+
AssertVectorValue(av, {});
|
|
239
|
+
const bv = b[i];
|
|
240
|
+
AssertVectorValue(bv, {});
|
|
241
|
+
dotProduct += av * bv;
|
|
242
|
+
}
|
|
243
|
+
return dotProduct;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Normalizes a vector to unit length (magnitude of 1).
|
|
247
|
+
* Essential for direction vectors, surface normals, and unit calculations.
|
|
248
|
+
* Preserves direction while standardizing magnitude.
|
|
249
|
+
*
|
|
250
|
+
* @template T - The vector type extending TVector
|
|
251
|
+
* @param a - Vector to normalize
|
|
252
|
+
* @returns Unit vector in the same direction
|
|
253
|
+
* @throws {VectorError} If the vector is zero or has infinite magnitude
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* const vector = [3, 4, 0];
|
|
257
|
+
* const normalized = VectorNormalize(vector); // [0.6, 0.8, 0] (magnitude = 1)
|
|
258
|
+
*
|
|
259
|
+
* const direction = [10, 0, 0];
|
|
260
|
+
* const unitDirection = VectorNormalize(direction); // [1, 0, 0]
|
|
261
|
+
*/
|
|
262
|
+
export function VectorNormalize(a) {
|
|
263
|
+
AssertVector(a);
|
|
264
|
+
const magnitude = VectorMagnitude(a);
|
|
265
|
+
if (magnitude === 0)
|
|
266
|
+
throw new VectorError(`Cannot Normalize a Zero Vector: ${VectorToString(a)}`);
|
|
267
|
+
if (magnitude === Number.POSITIVE_INFINITY)
|
|
268
|
+
throw new VectorError(`Cannot Normalize a Vector with Infinite Magnitude: ${VectorToString(a)}`);
|
|
269
|
+
const result = VectorClone(a);
|
|
270
|
+
for (let i = 0; i < a.length; i++) {
|
|
271
|
+
const av = a[i];
|
|
272
|
+
AssertVectorValue(av, {});
|
|
273
|
+
result[i] = av / magnitude;
|
|
274
|
+
}
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Calculates the magnitude (length) of a vector.
|
|
279
|
+
* Fundamental for distance calculations, normalization, and vector analysis.
|
|
280
|
+
*
|
|
281
|
+
* @param a - Vector to measure
|
|
282
|
+
* @returns The magnitude (length) of the vector
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* const velocity = [3, 4, 0];
|
|
286
|
+
* const speed = VectorMagnitude(velocity); // 5.0
|
|
287
|
+
*
|
|
288
|
+
* const unitVector = [1, 0, 0];
|
|
289
|
+
* const unitLength = VectorMagnitude(unitVector); // 1.0
|
|
290
|
+
*/
|
|
291
|
+
export function VectorMagnitude(a) {
|
|
292
|
+
AssertVector(a);
|
|
293
|
+
let sum = 0;
|
|
294
|
+
for (const av of a) {
|
|
295
|
+
AssertVectorValue(av, {});
|
|
296
|
+
sum += Math.pow(av, 2);
|
|
297
|
+
}
|
|
298
|
+
return Math.sqrt(sum);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Returns a vector with the absolute value of each component.
|
|
302
|
+
* Useful for distance calculations, bounding box calculations, and ensuring positive values.
|
|
303
|
+
*
|
|
304
|
+
* @template T - The vector type extending TVector
|
|
305
|
+
* @param a - Vector to process
|
|
306
|
+
* @returns New vector with absolute values of all components
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* const vector = [-3, 4, -2];
|
|
310
|
+
* const absolute = VectorAbs(vector); // [3, 4, 2]
|
|
311
|
+
*
|
|
312
|
+
* const mixed = [1.5, -2.7, 0];
|
|
313
|
+
* const absValues = VectorAbs(mixed); // [1.5, 2.7, 0]
|
|
314
|
+
*/
|
|
315
|
+
export function VectorAbs(a) {
|
|
316
|
+
AssertVector(a);
|
|
317
|
+
const result = [];
|
|
318
|
+
for (const av of a) {
|
|
319
|
+
AssertVectorValue(av, {});
|
|
320
|
+
result.push(Math.abs(av));
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Checks if a vector is a zero vector (all components are zero).
|
|
326
|
+
* Important for validating input vectors and avoiding division by zero in calculations.
|
|
327
|
+
*
|
|
328
|
+
* @param vector - Vector to check
|
|
329
|
+
* @returns True if all components are zero, false otherwise
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* const zero = [0, 0, 0];
|
|
333
|
+
* const isZero = VectorIsZero(zero); // true
|
|
334
|
+
*
|
|
335
|
+
* const notZero = [0, 0.001, 0];
|
|
336
|
+
* const isNotZero = VectorIsZero(notZero); // false
|
|
337
|
+
*/
|
|
338
|
+
export function VectorIsZero(vector) {
|
|
339
|
+
return vector.every((v) => v === 0);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Calculates the angle between two vectors in radians.
|
|
343
|
+
* Essential for determining angular relationships, rotations, and orientations.
|
|
344
|
+
* Always returns a positive angle between 0 and π radians.
|
|
345
|
+
*
|
|
346
|
+
* @param a - First vector
|
|
347
|
+
* @param b - Second vector
|
|
348
|
+
* @returns Angle between vectors in radians (0 to π)
|
|
349
|
+
* @throws {VectorError} If either vector is zero
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* const right = [1, 0, 0];
|
|
353
|
+
* const up = [0, 1, 0];
|
|
354
|
+
* const angle = VectorAngle(right, up); // π/2 (90 degrees)
|
|
355
|
+
*
|
|
356
|
+
* const forward = [0, 0, 1];
|
|
357
|
+
* const backward = [0, 0, -1];
|
|
358
|
+
* const oppositeAngle = VectorAngle(forward, backward); // π (180 degrees)
|
|
359
|
+
*/
|
|
360
|
+
export function VectorAngle(a, b) {
|
|
361
|
+
AssertVectors([a, b]);
|
|
362
|
+
if (VectorIsZero(a) || VectorIsZero(b))
|
|
363
|
+
throw new VectorError('Cannot Calculate Angle with Zero Vectors');
|
|
364
|
+
const dot = VectorDot(a, b);
|
|
365
|
+
const magProduct = VectorMagnitude(a) * VectorMagnitude(b);
|
|
366
|
+
const cosTheta = Clamp(dot / magProduct, -1, 1);
|
|
367
|
+
return Math.acos(cosTheta);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Rotates a 2D vector by the specified angle in radians.
|
|
371
|
+
* Essential for 2D transformations, sprite rotations, and directional calculations.
|
|
372
|
+
*
|
|
373
|
+
* @param vector - 2D vector to rotate
|
|
374
|
+
* @param radians - Rotation angle in radians (positive = counterclockwise)
|
|
375
|
+
* @returns New rotated 2D vector
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* const right = [1, 0];
|
|
379
|
+
* const rotated90 = Vector2Rotate(right, Math.PI / 2); // [0, 1] (up)
|
|
380
|
+
* const rotated180 = Vector2Rotate(right, Math.PI); // [-1, 0] (left)
|
|
381
|
+
*/
|
|
382
|
+
export function Vector2Rotate(vector, radians) {
|
|
383
|
+
AssertVector2(vector);
|
|
384
|
+
const cos = Math.cos(radians);
|
|
385
|
+
const sin = Math.sin(radians);
|
|
386
|
+
const [v0, v1] = vector;
|
|
387
|
+
return [
|
|
388
|
+
(v0 * cos) - (v1 * sin),
|
|
389
|
+
(v0 * sin) + (v1 * cos),
|
|
390
|
+
];
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Creates a 2D unit vector from an angle in radians.
|
|
394
|
+
* Useful for creating directional vectors from angular measurements.
|
|
395
|
+
*
|
|
396
|
+
* @param radians - Angle in radians (0 = right, π/2 = up)
|
|
397
|
+
* @returns Unit vector pointing in the specified direction
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* const right = Vector2FromAngle(0); // [1, 0]
|
|
401
|
+
* const up = Vector2FromAngle(Math.PI / 2); // [0, 1]
|
|
402
|
+
* const diagonal = Vector2FromAngle(Math.PI / 4); // [0.707, 0.707]
|
|
403
|
+
*/
|
|
404
|
+
export function Vector2FromAngle(radians) {
|
|
405
|
+
return [Math.cos(radians), Math.sin(radians)];
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Calculates the 2D cross product (returns a scalar).
|
|
409
|
+
* In 2D, the cross product represents the signed area of the parallelogram formed by the vectors.
|
|
410
|
+
* Useful for determining relative orientation and winding order.
|
|
411
|
+
*
|
|
412
|
+
* @param a - First 2D vector
|
|
413
|
+
* @param b - Second 2D vector
|
|
414
|
+
* @returns Scalar cross product (positive = counterclockwise, negative = clockwise)
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* const right = [1, 0];
|
|
418
|
+
* const up = [0, 1];
|
|
419
|
+
* const cross = Vector2Cross(right, up); // 1 (counterclockwise)
|
|
420
|
+
* const crossReverse = Vector2Cross(up, right); // -1 (clockwise)
|
|
421
|
+
*/
|
|
422
|
+
export function Vector2Cross(a, b) {
|
|
423
|
+
AssertVector2(a);
|
|
424
|
+
AssertVector2(b);
|
|
425
|
+
return (a[0] * b[1]) - (a[1] * b[0]);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Calculates the 3D rejection of vector a from vector b.
|
|
429
|
+
* Returns the component of vector a that is perpendicular to vector b.
|
|
430
|
+
* Useful for separating parallel and perpendicular components.
|
|
431
|
+
*
|
|
432
|
+
* @param a - Vector to reject from
|
|
433
|
+
* @param b - Vector to reject onto
|
|
434
|
+
* @returns Component of a perpendicular to b
|
|
435
|
+
* @throws {VectorError} If vector b is zero
|
|
436
|
+
*
|
|
437
|
+
* @example
|
|
438
|
+
* const force = [5, 3, 0];
|
|
439
|
+
* const surface = [1, 0, 0];
|
|
440
|
+
* const perpendicular = Vector3Reject(force, surface); // [0, 3, 0]
|
|
441
|
+
*/
|
|
442
|
+
export function Vector3Reject(a, b) {
|
|
443
|
+
AssertVector3(a);
|
|
444
|
+
AssertVector3(b);
|
|
445
|
+
if (VectorIsZero(b))
|
|
446
|
+
throw new VectorError('Cannot compute rejection with a zero vector');
|
|
447
|
+
const projection = VectorProject(a, b);
|
|
448
|
+
return VectorSubtract(a, projection);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Projects vector a onto vector b.
|
|
452
|
+
* Returns the component of vector a that lies parallel to vector b.
|
|
453
|
+
* Essential for shadow calculations, force decomposition, and geometric projections.
|
|
454
|
+
*
|
|
455
|
+
* @template T - The vector type extending TVector
|
|
456
|
+
* @param a - Vector to project
|
|
457
|
+
* @param b - Vector to project onto
|
|
458
|
+
* @returns Component of a parallel to b
|
|
459
|
+
* @throws {VectorError} If vector b is zero
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* const force = [5, 3, 0];
|
|
463
|
+
* const surface = [1, 0, 0];
|
|
464
|
+
* const parallel = VectorProject(force, surface); // [5, 0, 0]
|
|
465
|
+
*/
|
|
466
|
+
export function VectorProject(a, b) {
|
|
467
|
+
AssertVectors([a, b]);
|
|
468
|
+
if (VectorIsZero(b))
|
|
469
|
+
throw new VectorError('Cannot project onto a zero vector');
|
|
470
|
+
const dot = VectorDot(a, b);
|
|
471
|
+
const magSquared = Math.pow(VectorMagnitude(b), 2);
|
|
472
|
+
const scalar = dot / magSquared;
|
|
473
|
+
const result = [];
|
|
474
|
+
for (const bv of b) {
|
|
475
|
+
AssertVectorValue(bv, {});
|
|
476
|
+
result.push(scalar * bv);
|
|
477
|
+
}
|
|
478
|
+
return result;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Reflects an incident vector across a 3D normal (specialized version).
|
|
482
|
+
* This is a specialized version of VectorReflect for 3D vectors.
|
|
483
|
+
* Automatically normalizes the normal vector for consistent results.
|
|
484
|
+
*
|
|
485
|
+
* @param incident - The incoming vector to reflect
|
|
486
|
+
* @param normal - The surface normal (will be normalized automatically)
|
|
487
|
+
* @returns The reflected vector
|
|
488
|
+
* @throws {VectorError} If the normal is a zero vector
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* const incoming = [1, -1, 0];
|
|
492
|
+
* const normal = [0, 1, 0]; // surface normal (upward)
|
|
493
|
+
* const reflected = Vector3Reflect(incoming, normal); // [1, 1, 0]
|
|
494
|
+
*/
|
|
495
|
+
export function Vector3Reflect(incident, normal) {
|
|
496
|
+
AssertVector3(incident);
|
|
497
|
+
AssertVector3(normal);
|
|
498
|
+
if (VectorIsZero(normal))
|
|
499
|
+
throw new VectorError('Cannot reflect across a zero normal');
|
|
500
|
+
const normalizedNormal = VectorNormalize(normal);
|
|
501
|
+
return VectorReflect(incident, normalizedNormal);
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Calculates the 3D cross product of two vectors.
|
|
505
|
+
* Returns a vector perpendicular to both input vectors.
|
|
506
|
+
* Essential for surface normals, torque calculations, and 3D rotations.
|
|
507
|
+
*
|
|
508
|
+
* @param a - First 3D vector
|
|
509
|
+
* @param b - Second 3D vector
|
|
510
|
+
* @returns Vector perpendicular to both a and b (following right-hand rule)
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* const right = [1, 0, 0];
|
|
514
|
+
* const forward = [0, 0, 1];
|
|
515
|
+
* const up = Vector3Cross(right, forward); // [0, 1, 0]
|
|
516
|
+
*
|
|
517
|
+
* const normal = Vector3Cross([1, 0, 0], [0, 1, 0]); // [0, 0, 1]
|
|
518
|
+
*/
|
|
519
|
+
export function Vector3Cross(a, b) {
|
|
520
|
+
AssertVector3(a);
|
|
521
|
+
AssertVector3(b);
|
|
522
|
+
return [
|
|
523
|
+
(a[1] * b[2]) - (a[2] * b[1]),
|
|
524
|
+
(a[2] * b[0]) - (a[0] * b[2]),
|
|
525
|
+
(a[0] * b[1]) - (a[1] * b[0]),
|
|
526
|
+
];
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Calculates the magnitude of the 3D cross product.
|
|
530
|
+
* Equivalent to the area of the parallelogram formed by the two vectors.
|
|
531
|
+
* Useful for area calculations and determining vector orthogonality.
|
|
532
|
+
*
|
|
533
|
+
* @param a - First 3D vector
|
|
534
|
+
* @param b - Second 3D vector
|
|
535
|
+
* @returns Magnitude of the cross product
|
|
536
|
+
*
|
|
537
|
+
* @example
|
|
538
|
+
* const side1 = [3, 0, 0];
|
|
539
|
+
* const side2 = [0, 4, 0];
|
|
540
|
+
* const area = VectorCrossMagnitude(side1, side2); // 12 (area of rectangle)
|
|
541
|
+
*/
|
|
542
|
+
export function VectorCrossMagnitude(a, b) {
|
|
543
|
+
AssertVector3(a);
|
|
544
|
+
AssertVector3(b);
|
|
545
|
+
const c = Vector3Cross(a, b);
|
|
546
|
+
return Math.sqrt((c[0] * c[0]) + (c[1] * c[1]) + (c[2] * c[2]));
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Calculates the scalar triple product of three 3D vectors.
|
|
550
|
+
* Returns the signed volume of the parallelepiped formed by the three vectors.
|
|
551
|
+
* Useful for determining orientation and volume calculations.
|
|
552
|
+
*
|
|
553
|
+
* @param a - First 3D vector
|
|
554
|
+
* @param b - Second 3D vector
|
|
555
|
+
* @param c - Third 3D vector
|
|
556
|
+
* @returns Signed volume (positive = right-handed orientation)
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* const x = [1, 0, 0];
|
|
560
|
+
* const y = [0, 1, 0];
|
|
561
|
+
* const z = [0, 0, 1];
|
|
562
|
+
* const volume = Vector3ScalarTripleProduct(x, y, z); // 1 (unit cube)
|
|
563
|
+
*/
|
|
564
|
+
export function Vector3ScalarTripleProduct(a, b, c) {
|
|
565
|
+
AssertVector3(a);
|
|
566
|
+
AssertVector3(b);
|
|
567
|
+
AssertVector3(c);
|
|
568
|
+
const crossProduct = Vector3Cross(b, c);
|
|
569
|
+
return VectorDot(a, crossProduct);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Calculates the vector triple product of three 3D vectors.
|
|
573
|
+
* Implements the formula: a × (b × c)
|
|
574
|
+
* Useful for advanced geometric calculations and physics simulations.
|
|
575
|
+
*
|
|
576
|
+
* @param a - First 3D vector
|
|
577
|
+
* @param b - Second 3D vector
|
|
578
|
+
* @param c - Third 3D vector
|
|
579
|
+
* @returns Vector result of a × (b × c)
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* const a = [1, 0, 0];
|
|
583
|
+
* const b = [0, 1, 0];
|
|
584
|
+
* const c = [0, 0, 1];
|
|
585
|
+
* const result = Vector3TripleProduct(a, b, c); // [0, 0, 0]
|
|
586
|
+
*/
|
|
587
|
+
export function Vector3TripleProduct(a, b, c) {
|
|
588
|
+
AssertVector3(a);
|
|
589
|
+
AssertVector3(b);
|
|
590
|
+
AssertVector3(c);
|
|
591
|
+
const crossProduct = Vector3Cross(b, c);
|
|
592
|
+
return Vector3Cross(a, crossProduct);
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Reflects a vector across a normal surface.
|
|
596
|
+
* Simulates perfect reflection like light bouncing off a mirror.
|
|
597
|
+
* The normal vector is automatically normalized for consistent results.
|
|
598
|
+
*
|
|
599
|
+
* @template T - The vector type extending TVector
|
|
600
|
+
* @param incident - The incoming vector to reflect
|
|
601
|
+
* @param normal - The surface normal vector
|
|
602
|
+
* @returns The reflected vector
|
|
603
|
+
*
|
|
604
|
+
* @example
|
|
605
|
+
* const incoming = [1, -1, 0];
|
|
606
|
+
* const wall = [0, 1, 0]; // vertical wall normal
|
|
607
|
+
* const bounced = VectorReflect(incoming, wall); // [1, 1, 0]
|
|
608
|
+
*/
|
|
609
|
+
export function VectorReflect(incident, normal) {
|
|
610
|
+
AssertVectors([incident, normal]);
|
|
611
|
+
const normalizedNormal = VectorNormalize(normal);
|
|
612
|
+
const dot = VectorDot(incident, normalizedNormal);
|
|
613
|
+
const result = [];
|
|
614
|
+
for (let i = 0; i < incident.length; i++) {
|
|
615
|
+
const iv = incident[i];
|
|
616
|
+
AssertVectorValue(iv, {});
|
|
617
|
+
const nnv = normalizedNormal[i];
|
|
618
|
+
AssertVectorValue(nnv, {});
|
|
619
|
+
result.push(iv - (2 * dot * nnv));
|
|
620
|
+
}
|
|
621
|
+
return result;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Negates all components of a vector (multiplies by -1).
|
|
625
|
+
* Creates a vector pointing in the exact opposite direction.
|
|
626
|
+
* Handles special case of zero to avoid negative zero (-0).
|
|
627
|
+
*
|
|
628
|
+
* @template T - The vector type extending TVector
|
|
629
|
+
* @param a - Vector to negate
|
|
630
|
+
* @returns Vector with all components negated
|
|
631
|
+
*
|
|
632
|
+
* @example
|
|
633
|
+
* const forward = [0, 0, 1];
|
|
634
|
+
* const backward = VectorNegate(forward); // [0, 0, -1]
|
|
635
|
+
*
|
|
636
|
+
* const velocity = [5, -3, 2];
|
|
637
|
+
* const opposite = VectorNegate(velocity); // [-5, 3, -2]
|
|
638
|
+
*/
|
|
639
|
+
export function VectorNegate(a) {
|
|
640
|
+
const result = [];
|
|
641
|
+
for (const av of a) {
|
|
642
|
+
AssertVectorValue(av, {});
|
|
643
|
+
// Special handling for zero to avoid negative zero (-0)
|
|
644
|
+
if (av === 0) {
|
|
645
|
+
result.push(0);
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
result.push(-1 * av);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return result;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Divides a vector by a scalar or performs component-wise division with another vector.
|
|
655
|
+
* Scalar division scales the vector magnitude down; component-wise division is the inverse of component-wise multiplication.
|
|
656
|
+
*
|
|
657
|
+
* @template T - The vector type extending TVector
|
|
658
|
+
* @param a - Vector to divide (dividend)
|
|
659
|
+
* @param b - Scalar number or vector for component-wise division (divisor)
|
|
660
|
+
* @returns New vector with divided components
|
|
661
|
+
* @throws {VectorError} If any divisor component is zero
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* const velocity = [20, 10, 0];
|
|
665
|
+
* const halved = VectorDivide(velocity, 2); // [10, 5, 0] - scalar division
|
|
666
|
+
* const factors = [2, 5, 1];
|
|
667
|
+
* const componentWise = VectorDivide(velocity, factors); // [10, 2, 0] - component-wise
|
|
668
|
+
*/
|
|
669
|
+
export function VectorDivide(a, b) {
|
|
670
|
+
const result = [];
|
|
671
|
+
if (Array.isArray(b)) {
|
|
672
|
+
if (b.length !== a.length)
|
|
673
|
+
throw new VectorError('Vector Size Mismatch');
|
|
674
|
+
for (let i = 0; i < a.length; i++) {
|
|
675
|
+
const av = a[i];
|
|
676
|
+
AssertVectorValue(av, {});
|
|
677
|
+
const bv = b[i];
|
|
678
|
+
AssertVectorValue(bv, {});
|
|
679
|
+
if (bv === 0)
|
|
680
|
+
throw new VectorError(`Division by zero at component [${i}]`);
|
|
681
|
+
const quot = av / bv;
|
|
682
|
+
result.push(Object.is(quot, -0) ? 0 : quot);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
else if (typeof b === 'number') {
|
|
686
|
+
if (b === 0)
|
|
687
|
+
throw new VectorError('Division by zero scalar');
|
|
688
|
+
for (const av of a) {
|
|
689
|
+
AssertVectorValue(av, {});
|
|
690
|
+
const quot = av / b;
|
|
691
|
+
result.push(Object.is(quot, -0) ? 0 : quot);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return result;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Clamps each component of a vector between the corresponding min and max values.
|
|
698
|
+
* Can accept scalar min/max (same bounds for all components) or vectors for per-component bounds.
|
|
699
|
+
* Mirrors the scalar `Clamp` function for vector operations.
|
|
700
|
+
*
|
|
701
|
+
* @template T - The vector type extending TVector
|
|
702
|
+
* @param a - Vector whose components are to be clamped
|
|
703
|
+
* @param min - Minimum value (scalar applied to all components, or vector for per-component bounds)
|
|
704
|
+
* @param max - Maximum value (scalar applied to all components, or vector for per-component bounds)
|
|
705
|
+
* @returns New vector with each component clamped between min and max
|
|
706
|
+
*
|
|
707
|
+
* @example
|
|
708
|
+
* const v = [5, -3, 12, 0];
|
|
709
|
+
* VectorClamp(v, 0, 10); // [5, 0, 10, 0] - scalar bounds
|
|
710
|
+
*
|
|
711
|
+
* const mins = [0, -5, 0, -1];
|
|
712
|
+
* const maxs = [10, 5, 8, 1];
|
|
713
|
+
* VectorClamp(v, mins, maxs); // [5, -3, 8, 0] - per-component bounds
|
|
714
|
+
*/
|
|
715
|
+
export function VectorClamp(a, min, max) {
|
|
716
|
+
AssertVector(a);
|
|
717
|
+
const result = [];
|
|
718
|
+
for (let i = 0; i < a.length; i++) {
|
|
719
|
+
const av = a[i];
|
|
720
|
+
AssertVectorValue(av, {});
|
|
721
|
+
const minV = Array.isArray(min) ? min[i] : min;
|
|
722
|
+
const maxV = Array.isArray(max) ? max[i] : max;
|
|
723
|
+
result.push(Math.max(minV, Math.min(av, maxV)));
|
|
724
|
+
}
|
|
725
|
+
return result;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Limits the magnitude of a vector to a maximum value.
|
|
729
|
+
* If the vector's magnitude exceeds the limit, scales it down proportionally.
|
|
730
|
+
* Preserves direction while constraining magnitude.
|
|
731
|
+
*
|
|
732
|
+
* @template T - The vector type extending TVector
|
|
733
|
+
* @param a - Vector to limit
|
|
734
|
+
* @param max - Maximum allowed magnitude
|
|
735
|
+
* @returns Vector with magnitude limited to max
|
|
736
|
+
* @throws {VectorError} If max is negative
|
|
737
|
+
*
|
|
738
|
+
* @example
|
|
739
|
+
* const velocity = [15, 20, 0]; // magnitude ≈ 25
|
|
740
|
+
* const limited = VectorLimit(velocity, 10); // magnitude = 10, same direction
|
|
741
|
+
*
|
|
742
|
+
* const small = [1, 1, 0]; // magnitude ≈ 1.414
|
|
743
|
+
* const unchanged = VectorLimit(small, 5); // unchanged since already under limit
|
|
744
|
+
*/
|
|
745
|
+
export function VectorLimit(a, max) {
|
|
746
|
+
if (max < 0)
|
|
747
|
+
throw new VectorError('Maximum magnitude cannot be negative');
|
|
748
|
+
const magnitude = VectorMagnitude(a);
|
|
749
|
+
if (magnitude <= max || magnitude === 0)
|
|
750
|
+
return VectorClone(a);
|
|
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 {
|
|
770
|
+
AssertVector(vector);
|
|
771
|
+
return true;
|
|
772
|
+
}
|
|
773
|
+
catch {
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Performs Gram-Schmidt orthogonalization on a set of vectors.
|
|
779
|
+
* Converts a set of linearly independent vectors into an orthogonal (or orthonormal) set.
|
|
780
|
+
* Essential for creating coordinate systems and orthogonal bases.
|
|
781
|
+
*
|
|
782
|
+
* @template T - The vector type extending TVector
|
|
783
|
+
* @param vectors - Array of vectors to orthogonalize
|
|
784
|
+
* @param normalize - Whether to normalize the resulting vectors (default: false)
|
|
785
|
+
* @returns Array of orthogonal (or orthonormal) vectors
|
|
786
|
+
* @throws {VectorError} If vectors are linearly dependent or invalid
|
|
787
|
+
*
|
|
788
|
+
* @example
|
|
789
|
+
* const vectors = [[1, 1, 0], [1, 0, 1], [0, 1, 1]];
|
|
790
|
+
* const orthogonal = VectorGramSchmidt(vectors); // Orthogonal set
|
|
791
|
+
* const orthonormal = VectorGramSchmidt(vectors, true); // Orthonormal set
|
|
792
|
+
*/
|
|
793
|
+
export function VectorGramSchmidt(vectors, normalize = false) {
|
|
794
|
+
if (vectors.length === 0)
|
|
795
|
+
throw new VectorError('GramSchmidt: Empty Vector Set');
|
|
796
|
+
const [firstVector] = vectors;
|
|
797
|
+
if (!firstVector)
|
|
798
|
+
throw new VectorError('GramSchmidt: Undefined First Vector');
|
|
799
|
+
const dimension = firstVector.length;
|
|
800
|
+
for (const [i, vector] of vectors.entries()) {
|
|
801
|
+
AssertVector(vector);
|
|
802
|
+
if (vector.length !== dimension)
|
|
803
|
+
throw new VectorError(`GramSchmidt: Vector at index ${i} has different dimension than first vector. Expected ${dimension}, got ${vector.length}`);
|
|
804
|
+
if (VectorIsZero(vector))
|
|
805
|
+
throw new VectorError(`GramSchmidt: Vector at index ${i} is a zero vector. Cannot orthogonalize zero vectors.`);
|
|
806
|
+
}
|
|
807
|
+
const result = [];
|
|
808
|
+
for (const [i, currentVector] of vectors.entries()) {
|
|
809
|
+
AssertVector(currentVector);
|
|
810
|
+
let orthogonalVector = VectorClone(currentVector);
|
|
811
|
+
for (let j = 0; j < i; j++) {
|
|
812
|
+
const previousVector = result[j];
|
|
813
|
+
AssertVector(previousVector);
|
|
814
|
+
const projection = VectorProject(currentVector, previousVector);
|
|
815
|
+
orthogonalVector = VectorSubtract(orthogonalVector, projection);
|
|
816
|
+
}
|
|
817
|
+
if (VectorIsZero(orthogonalVector))
|
|
818
|
+
throw new VectorError(`GramSchmidt: Vector at index ${i} is linearly dependent on previous vectors. Cannot orthogonalize linearly dependent vectors.`);
|
|
819
|
+
if (normalize)
|
|
820
|
+
orthogonalVector = VectorNormalize(orthogonalVector);
|
|
821
|
+
result.push(orthogonalVector);
|
|
822
|
+
}
|
|
823
|
+
return result;
|
|
824
|
+
}
|
|
825
|
+
//# sourceMappingURL=core.js.map
|