@fluixi/utils 1.0.0-alpha.83 → 1.0.0-alpha.84
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/dist/index.cjs +2858 -1
- package/dist/index.mjs +2838 -1
- package/dist/lib/array/advanced.cjs +2227 -1
- package/dist/lib/array/advanced.mjs +2204 -1
- package/dist/lib/array/array.cjs +57 -1
- package/dist/lib/array/array.mjs +36 -1
- package/dist/lib/array/index.cjs +2344 -1
- package/dist/lib/array/index.mjs +2322 -1
- package/dist/lib/array/utils.cjs +103 -1
- package/dist/lib/array/utils.mjs +82 -1
- package/dist/lib/color/color.cjs +2190 -1
- package/dist/lib/color/color.mjs +2167 -1
- package/dist/lib/color/constants.cjs +380 -1
- package/dist/lib/color/constants.mjs +359 -1
- package/dist/lib/color/conversions.cjs +629 -1
- package/dist/lib/color/conversions.mjs +608 -1
- package/dist/lib/color/helpers.cjs +2534 -1
- package/dist/lib/color/helpers.mjs +2511 -1
- package/dist/lib/color/index.cjs +2641 -1
- package/dist/lib/color/index.mjs +2619 -1
- package/dist/lib/color/types.cjs +18 -1
- package/dist/lib/color/utils.cjs +962 -1
- package/dist/lib/color/utils.mjs +939 -1
- package/dist/lib/compare/comparators.cjs +171 -1
- package/dist/lib/compare/comparators.mjs +150 -1
- package/dist/lib/compare/index.cjs +172 -1
- package/dist/lib/compare/index.mjs +152 -1
- package/dist/lib/crypto/hash.cjs +83 -1
- package/dist/lib/crypto/hash.mjs +62 -1
- package/dist/lib/crypto/index.cjs +85 -1
- package/dist/lib/crypto/index.mjs +62 -1
- package/dist/lib/dom/events.cjs +40 -1
- package/dist/lib/dom/events.mjs +19 -1
- package/dist/lib/dom/index.cjs +78 -1
- package/dist/lib/dom/index.mjs +56 -1
- package/dist/lib/dom/utils.cjs +57 -1
- package/dist/lib/dom/utils.mjs +36 -1
- package/dist/lib/functions/functions.cjs +366 -1
- package/dist/lib/functions/functions.mjs +345 -1
- package/dist/lib/functions/index.cjs +369 -1
- package/dist/lib/functions/index.mjs +347 -1
- package/dist/lib/functions/types.cjs +18 -1
- package/dist/lib/helpers.cjs +78 -1
- package/dist/lib/helpers.mjs +59 -1
- package/dist/lib/index.cjs +2857 -1
- package/dist/lib/index.mjs +2836 -1
- package/dist/lib/maths/constants.cjs +70 -1
- package/dist/lib/maths/constants.mjs +50 -1
- package/dist/lib/maths/fn/advanced.cjs +231 -1
- package/dist/lib/maths/fn/advanced.mjs +208 -1
- package/dist/lib/maths/fn/basic.cjs +212 -1
- package/dist/lib/maths/fn/basic.mjs +191 -1
- package/dist/lib/maths/fn/complex.cjs +268 -1
- package/dist/lib/maths/fn/complex.mjs +247 -1
- package/dist/lib/maths/fn/index.cjs +877 -1
- package/dist/lib/maths/fn/index.mjs +855 -1
- package/dist/lib/maths/fn/trigo.cjs +179 -1
- package/dist/lib/maths/fn/trigo.mjs +156 -1
- package/dist/lib/maths/fn/vector.cjs +728 -1
- package/dist/lib/maths/fn/vector.mjs +707 -1
- package/dist/lib/maths/formatter.cjs +61 -1
- package/dist/lib/maths/formatter.mjs +40 -1
- package/dist/lib/maths/guards.cjs +164 -1
- package/dist/lib/maths/guards.mjs +144 -1
- package/dist/lib/maths/index.cjs +1152 -1
- package/dist/lib/maths/index.mjs +1130 -1
- package/dist/lib/maths/parser.cjs +75 -1
- package/dist/lib/maths/parser.mjs +54 -1
- package/dist/lib/maths/random.cjs +49 -1
- package/dist/lib/maths/random.mjs +28 -1
- package/dist/lib/maths/types/advanced.cjs +18 -1
- package/dist/lib/maths/types/basic.cjs +18 -1
- package/dist/lib/maths/types/index.cjs +19 -1
- package/dist/lib/maths/types/index.mjs +1 -0
- package/dist/lib/maths/types/negative.cjs +18 -1
- package/dist/lib/maths/types/operations.cjs +18 -1
- package/dist/lib/object/clone.cjs +88 -1
- package/dist/lib/object/clone.mjs +65 -1
- package/dist/lib/object/diff.cjs +573 -1
- package/dist/lib/object/diff.mjs +550 -1
- package/dist/lib/object/getter-setter.cjs +2351 -1
- package/dist/lib/object/getter-setter.mjs +2330 -1
- package/dist/lib/object/index.cjs +3956 -6
- package/dist/lib/object/index.mjs +3936 -6
- package/dist/lib/object/merge.cjs +1029 -1
- package/dist/lib/object/merge.mjs +1006 -1
- package/dist/lib/object/object.cjs +280 -1
- package/dist/lib/object/object.mjs +257 -1
- package/dist/lib/object/omit.cjs +2022 -1
- package/dist/lib/object/omit.mjs +1999 -1
- package/dist/lib/object/reconcile.cjs +126 -1
- package/dist/lib/object/reconcile.mjs +105 -1
- package/dist/lib/object/selector.cjs +303 -1
- package/dist/lib/object/selector.mjs +282 -1
- package/dist/lib/object/sort.cjs +209 -1
- package/dist/lib/object/sort.mjs +186 -1
- package/dist/lib/object/transform.cjs +2211 -1
- package/dist/lib/object/transform.mjs +2190 -1
- package/dist/lib/object/types.cjs +18 -1
- package/dist/lib/object/utils.cjs +326 -6
- package/dist/lib/object/utils.mjs +305 -6
- package/dist/lib/primitive/boolean/boolean.cjs +407 -1
- package/dist/lib/primitive/boolean/boolean.mjs +386 -1
- package/dist/lib/primitive/boolean/index.cjs +382 -1
- package/dist/lib/primitive/boolean/index.mjs +359 -1
- package/dist/lib/primitive/boolean/types.cjs +18 -1
- package/dist/lib/primitive/date/date.cjs +1126 -1
- package/dist/lib/primitive/date/date.mjs +1105 -1
- package/dist/lib/primitive/date/index.cjs +1128 -1
- package/dist/lib/primitive/date/index.mjs +1105 -1
- package/dist/lib/primitive/date/types.cjs +18 -1
- package/dist/lib/primitive/index.cjs +2338 -5
- package/dist/lib/primitive/index.mjs +2316 -5
- package/dist/lib/primitive/string/index.cjs +875 -5
- package/dist/lib/primitive/string/index.mjs +852 -5
- package/dist/lib/primitive/string/parser-2.cjs +543 -8
- package/dist/lib/primitive/string/parser-2.mjs +522 -8
- package/dist/lib/primitive/string/parser.cjs +236 -3
- package/dist/lib/primitive/string/parser.mjs +215 -3
- package/dist/lib/primitive/string/string.cjs +926 -5
- package/dist/lib/primitive/string/string.mjs +903 -5
- package/dist/lib/primitive/string/types.cjs +18 -1
- package/dist/lib/primitive/types.cjs +18 -1
- package/dist/lib/url/index.cjs +327 -1
- package/dist/lib/url/index.mjs +304 -1
- package/dist/lib/url/parser.cjs +325 -1
- package/dist/lib/url/parser.mjs +304 -1
- package/dist/lib/url/types.cjs +18 -1
- package/package.json +5 -5
|
@@ -1 +1,707 @@
|
|
|
1
|
-
|
|
1
|
+
// src/lib/maths/fn/vector.ts
|
|
2
|
+
function validateNumber(value, name) {
|
|
3
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
4
|
+
throw new Error(`${name} must be a finite number, got ${value}`);
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function isApproximatelyZero(value) {
|
|
8
|
+
return Math.abs(value) < 1e-9;
|
|
9
|
+
}
|
|
10
|
+
function approximatelyEqual(a, b) {
|
|
11
|
+
return Math.abs(a - b) < 1e-6;
|
|
12
|
+
}
|
|
13
|
+
function validateVector2D(vector, name = "Vector2D") {
|
|
14
|
+
if (!vector || typeof vector !== "object") {
|
|
15
|
+
throw new Error(`${name} must be an object`);
|
|
16
|
+
}
|
|
17
|
+
validateNumber(vector.x, `${name}.x`);
|
|
18
|
+
validateNumber(vector.y, `${name}.y`);
|
|
19
|
+
}
|
|
20
|
+
function validateVector3D(vector, name = "Vector3D") {
|
|
21
|
+
if (!vector || typeof vector !== "object") {
|
|
22
|
+
throw new Error(`${name} must be an object`);
|
|
23
|
+
}
|
|
24
|
+
validateNumber(vector.x, `${name}.x`);
|
|
25
|
+
validateNumber(vector.y, `${name}.y`);
|
|
26
|
+
validateNumber(vector.z, `${name}.z`);
|
|
27
|
+
}
|
|
28
|
+
function validateVector4D(vector, name = "Vector4D") {
|
|
29
|
+
if (!vector || typeof vector !== "object") {
|
|
30
|
+
throw new Error(`${name} must be an object`);
|
|
31
|
+
}
|
|
32
|
+
validateNumber(vector.x, `${name}.x`);
|
|
33
|
+
validateNumber(vector.y, `${name}.y`);
|
|
34
|
+
validateNumber(vector.z, `${name}.z`);
|
|
35
|
+
validateNumber(vector.w, `${name}.w`);
|
|
36
|
+
}
|
|
37
|
+
function createVector2D(x, y) {
|
|
38
|
+
validateNumber(x, "x");
|
|
39
|
+
validateNumber(y, "y");
|
|
40
|
+
return { x, y };
|
|
41
|
+
}
|
|
42
|
+
function createVector3D(x, y, z) {
|
|
43
|
+
validateNumber(x, "x");
|
|
44
|
+
validateNumber(y, "y");
|
|
45
|
+
validateNumber(z, "z");
|
|
46
|
+
return { x, y, z };
|
|
47
|
+
}
|
|
48
|
+
function createVector4D(x, y, z, w) {
|
|
49
|
+
validateNumber(x, "x");
|
|
50
|
+
validateNumber(y, "y");
|
|
51
|
+
validateNumber(z, "z");
|
|
52
|
+
validateNumber(w, "w");
|
|
53
|
+
return { x, y, z, w };
|
|
54
|
+
}
|
|
55
|
+
function magnitude2D(vector) {
|
|
56
|
+
validateVector2D(vector);
|
|
57
|
+
const magnitude = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
|
|
58
|
+
return isApproximatelyZero(magnitude) ? 0 : magnitude;
|
|
59
|
+
}
|
|
60
|
+
function magnitudeSquared2D(vector) {
|
|
61
|
+
validateVector2D(vector);
|
|
62
|
+
return vector.x * vector.x + vector.y * vector.y;
|
|
63
|
+
}
|
|
64
|
+
function magnitude3D(vector) {
|
|
65
|
+
validateVector3D(vector);
|
|
66
|
+
const magnitude = Math.sqrt(
|
|
67
|
+
vector.x * vector.x + vector.y * vector.y + vector.z * vector.z
|
|
68
|
+
);
|
|
69
|
+
return isApproximatelyZero(magnitude) ? 0 : magnitude;
|
|
70
|
+
}
|
|
71
|
+
function magnitudeSquared3D(vector) {
|
|
72
|
+
validateVector3D(vector);
|
|
73
|
+
return vector.x * vector.x + vector.y * vector.y + vector.z * vector.z;
|
|
74
|
+
}
|
|
75
|
+
function magnitude4D(vector) {
|
|
76
|
+
validateVector4D(vector);
|
|
77
|
+
const magnitude = Math.sqrt(
|
|
78
|
+
vector.x * vector.x + vector.y * vector.y + vector.z * vector.z + vector.w * vector.w
|
|
79
|
+
);
|
|
80
|
+
return isApproximatelyZero(magnitude) ? 0 : magnitude;
|
|
81
|
+
}
|
|
82
|
+
function magnitudeSquared4D(vector) {
|
|
83
|
+
validateVector4D(vector);
|
|
84
|
+
return vector.x * vector.x + vector.y * vector.y + vector.z * vector.z + vector.w * vector.w;
|
|
85
|
+
}
|
|
86
|
+
function normalize2D(vector) {
|
|
87
|
+
validateVector2D(vector);
|
|
88
|
+
const mag = magnitude2D(vector);
|
|
89
|
+
if (isApproximatelyZero(mag)) {
|
|
90
|
+
throw new Error("Cannot normalize zero or near-zero vector");
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
x: vector.x / mag,
|
|
94
|
+
y: vector.y / mag
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function safeNormalize2D(vector) {
|
|
98
|
+
validateVector2D(vector);
|
|
99
|
+
const mag = magnitude2D(vector);
|
|
100
|
+
if (isApproximatelyZero(mag)) {
|
|
101
|
+
return { x: 0, y: 0 };
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
x: vector.x / mag,
|
|
105
|
+
y: vector.y / mag
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function normalize3D(vector) {
|
|
109
|
+
validateVector3D(vector);
|
|
110
|
+
const mag = magnitude3D(vector);
|
|
111
|
+
if (isApproximatelyZero(mag)) {
|
|
112
|
+
throw new Error("Cannot normalize zero or near-zero vector");
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
x: vector.x / mag,
|
|
116
|
+
y: vector.y / mag,
|
|
117
|
+
z: vector.z / mag
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function safeNormalize3D(vector) {
|
|
121
|
+
validateVector3D(vector);
|
|
122
|
+
const mag = magnitude3D(vector);
|
|
123
|
+
if (isApproximatelyZero(mag)) {
|
|
124
|
+
return { x: 0, y: 0, z: 0 };
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
x: vector.x / mag,
|
|
128
|
+
y: vector.y / mag,
|
|
129
|
+
z: vector.z / mag
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function normalize4D(vector) {
|
|
133
|
+
validateVector4D(vector);
|
|
134
|
+
const mag = magnitude4D(vector);
|
|
135
|
+
if (isApproximatelyZero(mag)) {
|
|
136
|
+
throw new Error("Cannot normalize zero or near-zero vector");
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
x: vector.x / mag,
|
|
140
|
+
y: vector.y / mag,
|
|
141
|
+
z: vector.z / mag,
|
|
142
|
+
w: vector.w / mag
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function safeNormalize4D(vector) {
|
|
146
|
+
validateVector4D(vector);
|
|
147
|
+
const mag = magnitude4D(vector);
|
|
148
|
+
if (isApproximatelyZero(mag)) {
|
|
149
|
+
return { x: 0, y: 0, z: 0, w: 0 };
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
x: vector.x / mag,
|
|
153
|
+
y: vector.y / mag,
|
|
154
|
+
z: vector.z / mag,
|
|
155
|
+
w: vector.w / mag
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function dotProduct2D(a, b) {
|
|
159
|
+
validateVector2D(a, "First vector");
|
|
160
|
+
validateVector2D(b, "Second vector");
|
|
161
|
+
return a.x * b.x + a.y * b.y;
|
|
162
|
+
}
|
|
163
|
+
function dotProduct3D(a, b) {
|
|
164
|
+
validateVector3D(a, "First vector");
|
|
165
|
+
validateVector3D(b, "Second vector");
|
|
166
|
+
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
167
|
+
}
|
|
168
|
+
function dotProduct4D(a, b) {
|
|
169
|
+
validateVector4D(a, "First vector");
|
|
170
|
+
validateVector4D(b, "Second vector");
|
|
171
|
+
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
|
172
|
+
}
|
|
173
|
+
function crossProduct3D(a, b) {
|
|
174
|
+
validateVector3D(a, "First vector");
|
|
175
|
+
validateVector3D(b, "Second vector");
|
|
176
|
+
return {
|
|
177
|
+
x: a.y * b.z - a.z * b.y,
|
|
178
|
+
y: a.z * b.x - a.x * b.z,
|
|
179
|
+
z: a.x * b.y - a.y * b.x
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function addVectors2D(a, b) {
|
|
183
|
+
validateVector2D(a, "First vector");
|
|
184
|
+
validateVector2D(b, "Second vector");
|
|
185
|
+
return {
|
|
186
|
+
x: a.x + b.x,
|
|
187
|
+
y: a.y + b.y
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function addVectors3D(a, b) {
|
|
191
|
+
validateVector3D(a, "First vector");
|
|
192
|
+
validateVector3D(b, "Second vector");
|
|
193
|
+
return {
|
|
194
|
+
x: a.x + b.x,
|
|
195
|
+
y: a.y + b.y,
|
|
196
|
+
z: a.z + b.z
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function addVectors4D(a, b) {
|
|
200
|
+
validateVector4D(a, "First vector");
|
|
201
|
+
validateVector4D(b, "Second vector");
|
|
202
|
+
return {
|
|
203
|
+
x: a.x + b.x,
|
|
204
|
+
y: a.y + b.y,
|
|
205
|
+
z: a.z + b.z,
|
|
206
|
+
w: a.w + b.w
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function subtractVectors2D(a, b) {
|
|
210
|
+
validateVector2D(a, "First vector");
|
|
211
|
+
validateVector2D(b, "Second vector");
|
|
212
|
+
return {
|
|
213
|
+
x: a.x - b.x,
|
|
214
|
+
y: a.y - b.y
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function subtractVectors3D(a, b) {
|
|
218
|
+
validateVector3D(a, "First vector");
|
|
219
|
+
validateVector3D(b, "Second vector");
|
|
220
|
+
return {
|
|
221
|
+
x: a.x - b.x,
|
|
222
|
+
y: a.y - b.y,
|
|
223
|
+
z: a.z - b.z
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function subtractVectors4D(a, b) {
|
|
227
|
+
validateVector4D(a, "First vector");
|
|
228
|
+
validateVector4D(b, "Second vector");
|
|
229
|
+
return {
|
|
230
|
+
x: a.x - b.x,
|
|
231
|
+
y: a.y - b.y,
|
|
232
|
+
z: a.z - b.z,
|
|
233
|
+
w: a.w - b.w
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function scaleVector2D(vector, scalar) {
|
|
237
|
+
validateVector2D(vector);
|
|
238
|
+
validateNumber(scalar, "scalar");
|
|
239
|
+
return {
|
|
240
|
+
x: vector.x * scalar,
|
|
241
|
+
y: vector.y * scalar
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function scaleVector3D(vector, scalar) {
|
|
245
|
+
validateVector3D(vector);
|
|
246
|
+
validateNumber(scalar, "scalar");
|
|
247
|
+
return {
|
|
248
|
+
x: vector.x * scalar,
|
|
249
|
+
y: vector.y * scalar,
|
|
250
|
+
z: vector.z * scalar
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function scaleVector4D(vector, scalar) {
|
|
254
|
+
validateVector4D(vector);
|
|
255
|
+
validateNumber(scalar, "scalar");
|
|
256
|
+
return {
|
|
257
|
+
x: vector.x * scalar,
|
|
258
|
+
y: vector.y * scalar,
|
|
259
|
+
z: vector.z * scalar,
|
|
260
|
+
w: vector.w * scalar
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function angleBetween2D(a, b) {
|
|
264
|
+
validateVector2D(a, "First vector");
|
|
265
|
+
validateVector2D(b, "Second vector");
|
|
266
|
+
const dot = dotProduct2D(a, b);
|
|
267
|
+
const magA = magnitude2D(a);
|
|
268
|
+
const magB = magnitude2D(b);
|
|
269
|
+
if (isApproximatelyZero(magA) || isApproximatelyZero(magB)) {
|
|
270
|
+
throw new Error("Cannot calculate angle with zero or near-zero vector");
|
|
271
|
+
}
|
|
272
|
+
const cosTheta = Math.max(-1, Math.min(1, dot / (magA * magB)));
|
|
273
|
+
return Math.acos(cosTheta);
|
|
274
|
+
}
|
|
275
|
+
function angleBetween3D(a, b) {
|
|
276
|
+
validateVector3D(a, "First vector");
|
|
277
|
+
validateVector3D(b, "Second vector");
|
|
278
|
+
const dot = dotProduct3D(a, b);
|
|
279
|
+
const magA = magnitude3D(a);
|
|
280
|
+
const magB = magnitude3D(b);
|
|
281
|
+
if (isApproximatelyZero(magA) || isApproximatelyZero(magB)) {
|
|
282
|
+
throw new Error("Cannot calculate angle with zero or near-zero vector");
|
|
283
|
+
}
|
|
284
|
+
const cosTheta = Math.max(-1, Math.min(1, dot / (magA * magB)));
|
|
285
|
+
return Math.acos(cosTheta);
|
|
286
|
+
}
|
|
287
|
+
function signedAngleBetween2D(a, b) {
|
|
288
|
+
validateVector2D(a, "First vector");
|
|
289
|
+
validateVector2D(b, "Second vector");
|
|
290
|
+
const angle = angleBetween2D(a, b);
|
|
291
|
+
const cross = a.x * b.y - a.y * b.x;
|
|
292
|
+
return cross >= 0 ? angle : -angle;
|
|
293
|
+
}
|
|
294
|
+
function distance2D(a, b) {
|
|
295
|
+
validateVector2D(a, "First point");
|
|
296
|
+
validateVector2D(b, "Second point");
|
|
297
|
+
const dx = b.x - a.x;
|
|
298
|
+
const dy = b.y - a.y;
|
|
299
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
300
|
+
return isApproximatelyZero(distance) ? 0 : distance;
|
|
301
|
+
}
|
|
302
|
+
function distanceSquared2D(a, b) {
|
|
303
|
+
validateVector2D(a, "First point");
|
|
304
|
+
validateVector2D(b, "Second point");
|
|
305
|
+
const dx = b.x - a.x;
|
|
306
|
+
const dy = b.y - a.y;
|
|
307
|
+
return dx * dx + dy * dy;
|
|
308
|
+
}
|
|
309
|
+
function distance3D(a, b) {
|
|
310
|
+
validateVector3D(a, "First point");
|
|
311
|
+
validateVector3D(b, "Second point");
|
|
312
|
+
const dx = b.x - a.x;
|
|
313
|
+
const dy = b.y - a.y;
|
|
314
|
+
const dz = b.z - a.z;
|
|
315
|
+
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
316
|
+
return isApproximatelyZero(distance) ? 0 : distance;
|
|
317
|
+
}
|
|
318
|
+
function distanceSquared3D(a, b) {
|
|
319
|
+
validateVector3D(a, "First point");
|
|
320
|
+
validateVector3D(b, "Second point");
|
|
321
|
+
const dx = b.x - a.x;
|
|
322
|
+
const dy = b.y - a.y;
|
|
323
|
+
const dz = b.z - a.z;
|
|
324
|
+
return dx * dx + dy * dy + dz * dz;
|
|
325
|
+
}
|
|
326
|
+
function distance4D(a, b) {
|
|
327
|
+
validateVector4D(a, "First point");
|
|
328
|
+
validateVector4D(b, "Second point");
|
|
329
|
+
const dx = b.x - a.x;
|
|
330
|
+
const dy = b.y - a.y;
|
|
331
|
+
const dz = b.z - a.z;
|
|
332
|
+
const dw = b.w - a.w;
|
|
333
|
+
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
|
|
334
|
+
return isApproximatelyZero(distance) ? 0 : distance;
|
|
335
|
+
}
|
|
336
|
+
function distanceSquared4D(a, b) {
|
|
337
|
+
validateVector4D(a, "First point");
|
|
338
|
+
validateVector4D(b, "Second point");
|
|
339
|
+
const dx = b.x - a.x;
|
|
340
|
+
const dy = b.y - a.y;
|
|
341
|
+
const dz = b.z - a.z;
|
|
342
|
+
const dw = b.w - a.w;
|
|
343
|
+
return dx * dx + dy * dy + dz * dz + dw * dw;
|
|
344
|
+
}
|
|
345
|
+
function lerp2D(start, end, t) {
|
|
346
|
+
validateVector2D(start, "Start vector");
|
|
347
|
+
validateVector2D(end, "End vector");
|
|
348
|
+
validateNumber(t, "t");
|
|
349
|
+
return {
|
|
350
|
+
x: start.x + (end.x - start.x) * t,
|
|
351
|
+
y: start.y + (end.y - start.y) * t
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function lerpClamped2D(start, end, t) {
|
|
355
|
+
validateVector2D(start, "Start vector");
|
|
356
|
+
validateVector2D(end, "End vector");
|
|
357
|
+
validateNumber(t, "t");
|
|
358
|
+
const clampedT = Math.max(0, Math.min(1, t));
|
|
359
|
+
return {
|
|
360
|
+
x: start.x + (end.x - start.x) * clampedT,
|
|
361
|
+
y: start.y + (end.y - start.y) * clampedT
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function lerp3D(start, end, t) {
|
|
365
|
+
validateVector3D(start, "Start vector");
|
|
366
|
+
validateVector3D(end, "End vector");
|
|
367
|
+
validateNumber(t, "t");
|
|
368
|
+
return {
|
|
369
|
+
x: start.x + (end.x - start.x) * t,
|
|
370
|
+
y: start.y + (end.y - start.y) * t,
|
|
371
|
+
z: start.z + (end.z - start.z) * t
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function lerpClamped3D(start, end, t) {
|
|
375
|
+
validateVector3D(start, "Start vector");
|
|
376
|
+
validateVector3D(end, "End vector");
|
|
377
|
+
validateNumber(t, "t");
|
|
378
|
+
const clampedT = Math.max(0, Math.min(1, t));
|
|
379
|
+
return {
|
|
380
|
+
x: start.x + (end.x - start.x) * clampedT,
|
|
381
|
+
y: start.y + (end.y - start.y) * clampedT,
|
|
382
|
+
z: start.z + (end.z - start.z) * clampedT
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function lerp4D(start, end, t) {
|
|
386
|
+
validateVector4D(start, "Start vector");
|
|
387
|
+
validateVector4D(end, "End vector");
|
|
388
|
+
validateNumber(t, "t");
|
|
389
|
+
return {
|
|
390
|
+
x: start.x + (end.x - start.x) * t,
|
|
391
|
+
y: start.y + (end.y - start.y) * t,
|
|
392
|
+
z: start.z + (end.z - start.z) * t,
|
|
393
|
+
w: start.w + (end.w - start.w) * t
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function lerpClamped4D(start, end, t) {
|
|
397
|
+
validateVector4D(start, "Start vector");
|
|
398
|
+
validateVector4D(end, "End vector");
|
|
399
|
+
validateNumber(t, "t");
|
|
400
|
+
const clampedT = Math.max(0, Math.min(1, t));
|
|
401
|
+
return {
|
|
402
|
+
x: start.x + (end.x - start.x) * clampedT,
|
|
403
|
+
y: start.y + (end.y - start.y) * clampedT,
|
|
404
|
+
z: start.z + (end.z - start.z) * clampedT,
|
|
405
|
+
w: start.w + (end.w - start.w) * clampedT
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function slerp3D(start, end, t) {
|
|
409
|
+
validateVector3D(start, "Start vector");
|
|
410
|
+
validateVector3D(end, "End vector");
|
|
411
|
+
validateNumber(t, "t");
|
|
412
|
+
const startMag = magnitude3D(start);
|
|
413
|
+
const endMag = magnitude3D(end);
|
|
414
|
+
if (Math.abs(startMag - 1) > 1e-8 || Math.abs(endMag - 1) > 1e-8) {
|
|
415
|
+
throw new Error("SLERP requires unit vectors");
|
|
416
|
+
}
|
|
417
|
+
const clampedT = Math.max(0, Math.min(1, t));
|
|
418
|
+
const dot = dotProduct3D(start, end);
|
|
419
|
+
const clampedDot = Math.max(-1, Math.min(1, dot));
|
|
420
|
+
if (clampedDot > 0.9995) {
|
|
421
|
+
return normalize3D(lerp3D(start, end, clampedT));
|
|
422
|
+
}
|
|
423
|
+
const theta = Math.acos(clampedDot);
|
|
424
|
+
const sinTheta = Math.sin(theta);
|
|
425
|
+
const factor1 = Math.sin((1 - clampedT) * theta) / sinTheta;
|
|
426
|
+
const factor2 = Math.sin(clampedT * theta) / sinTheta;
|
|
427
|
+
return addVectors3D(
|
|
428
|
+
scaleVector3D(start, factor1),
|
|
429
|
+
scaleVector3D(end, factor2)
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
function smoothstep2D(start, end, t) {
|
|
433
|
+
validateVector2D(start, "Start vector");
|
|
434
|
+
validateVector2D(end, "End vector");
|
|
435
|
+
validateNumber(t, "t");
|
|
436
|
+
const smoothedT = t * t * (3 - 2 * t);
|
|
437
|
+
return {
|
|
438
|
+
x: start.x + (end.x - start.x) * smoothedT,
|
|
439
|
+
y: start.y + (end.y - start.y) * smoothedT
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function smoothstepClamped2D(start, end, t) {
|
|
443
|
+
validateVector2D(start, "Start vector");
|
|
444
|
+
validateVector2D(end, "End vector");
|
|
445
|
+
validateNumber(t, "t");
|
|
446
|
+
const clampedT = Math.max(0, Math.min(1, t));
|
|
447
|
+
const smoothedT = clampedT * clampedT * (3 - 2 * clampedT);
|
|
448
|
+
return {
|
|
449
|
+
x: start.x + (end.x - start.x) * smoothedT,
|
|
450
|
+
y: start.y + (end.y - start.y) * smoothedT
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function smootherstep2D(start, end, t) {
|
|
454
|
+
validateVector2D(start, "Start vector");
|
|
455
|
+
validateVector2D(end, "End vector");
|
|
456
|
+
validateNumber(t, "t");
|
|
457
|
+
const smootherT = t * t * t * (t * (t * 6 - 15) + 10);
|
|
458
|
+
return {
|
|
459
|
+
x: start.x + (end.x - start.x) * smootherT,
|
|
460
|
+
y: start.y + (end.y - start.y) * smootherT
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function quadraticBezier2D(p0, p1, p2, t) {
|
|
464
|
+
validateVector2D(p0, "Start point");
|
|
465
|
+
validateVector2D(p1, "Control point");
|
|
466
|
+
validateVector2D(p2, "End point");
|
|
467
|
+
validateNumber(t, "t");
|
|
468
|
+
const oneMinusT = 1 - t;
|
|
469
|
+
const x = oneMinusT * oneMinusT * p0.x + 2 * oneMinusT * t * p1.x + t * t * p2.x;
|
|
470
|
+
const y = oneMinusT * oneMinusT * p0.y + 2 * oneMinusT * t * p1.y + t * t * p2.y;
|
|
471
|
+
return { x, y };
|
|
472
|
+
}
|
|
473
|
+
function cubicBezier2D(p0, p1, p2, p3, t) {
|
|
474
|
+
validateVector2D(p0, "Start point");
|
|
475
|
+
validateVector2D(p1, "First control point");
|
|
476
|
+
validateVector2D(p2, "Second control point");
|
|
477
|
+
validateVector2D(p3, "End point");
|
|
478
|
+
validateNumber(t, "t");
|
|
479
|
+
const oneMinusT = 1 - t;
|
|
480
|
+
const oneMinusT2 = oneMinusT * oneMinusT;
|
|
481
|
+
const oneMinusT3 = oneMinusT2 * oneMinusT;
|
|
482
|
+
const t2 = t * t;
|
|
483
|
+
const t3 = t2 * t;
|
|
484
|
+
const x = oneMinusT3 * p0.x + 3 * oneMinusT2 * t * p1.x + 3 * oneMinusT * t2 * p2.x + t3 * p3.x;
|
|
485
|
+
const y = oneMinusT3 * p0.y + 3 * oneMinusT2 * t * p1.y + 3 * oneMinusT * t2 * p2.y + t3 * p3.y;
|
|
486
|
+
return { x, y };
|
|
487
|
+
}
|
|
488
|
+
function mapRange(value, inMin, inMax, outMin, outMax) {
|
|
489
|
+
validateNumber(value, "value");
|
|
490
|
+
validateNumber(inMin, "inMin");
|
|
491
|
+
validateNumber(inMax, "inMax");
|
|
492
|
+
validateNumber(outMin, "outMin");
|
|
493
|
+
validateNumber(outMax, "outMax");
|
|
494
|
+
if (approximatelyEqual(inMin, inMax)) {
|
|
495
|
+
return outMin;
|
|
496
|
+
}
|
|
497
|
+
return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
|
|
498
|
+
}
|
|
499
|
+
function mapRangeClamped(value, inMin, inMax, outMin, outMax) {
|
|
500
|
+
validateNumber(value, "value");
|
|
501
|
+
validateNumber(inMin, "inMin");
|
|
502
|
+
validateNumber(inMax, "inMax");
|
|
503
|
+
validateNumber(outMin, "outMin");
|
|
504
|
+
validateNumber(outMax, "outMax");
|
|
505
|
+
if (approximatelyEqual(inMin, inMax)) {
|
|
506
|
+
return outMin;
|
|
507
|
+
}
|
|
508
|
+
const t = (value - inMin) / (inMax - inMin);
|
|
509
|
+
const clampedT = Math.max(0, Math.min(1, t));
|
|
510
|
+
return outMin + (outMax - outMin) * clampedT;
|
|
511
|
+
}
|
|
512
|
+
function rotate2D(vector, angle) {
|
|
513
|
+
validateVector2D(vector);
|
|
514
|
+
validateNumber(angle, "angle");
|
|
515
|
+
const cos = Math.cos(angle);
|
|
516
|
+
const sin = Math.sin(angle);
|
|
517
|
+
return {
|
|
518
|
+
x: vector.x * cos - vector.y * sin,
|
|
519
|
+
y: vector.x * sin + vector.y * cos
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function rotate2DDegrees(vector, degrees) {
|
|
523
|
+
return rotate2D(vector, degrees * (Math.PI / 180));
|
|
524
|
+
}
|
|
525
|
+
function reflect2D(vector, normal) {
|
|
526
|
+
validateVector2D(vector, "Vector");
|
|
527
|
+
validateVector2D(normal, "Normal");
|
|
528
|
+
const normalMag = magnitude2D(normal);
|
|
529
|
+
if (Math.abs(normalMag - 1) > 1e-10) {
|
|
530
|
+
throw new Error("Normal vector must be unit length for reflection");
|
|
531
|
+
}
|
|
532
|
+
const dot = dotProduct2D(vector, normal);
|
|
533
|
+
return {
|
|
534
|
+
x: vector.x - 2 * dot * normal.x,
|
|
535
|
+
y: vector.y - 2 * dot * normal.y
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function project2D(a, b) {
|
|
539
|
+
validateVector2D(a, "First vector");
|
|
540
|
+
validateVector2D(b, "Second vector");
|
|
541
|
+
const bMagSquared = magnitudeSquared2D(b);
|
|
542
|
+
if (isApproximatelyZero(bMagSquared)) {
|
|
543
|
+
throw new Error("Cannot project onto zero or near-zero vector");
|
|
544
|
+
}
|
|
545
|
+
const scale = dotProduct2D(a, b) / bMagSquared;
|
|
546
|
+
return {
|
|
547
|
+
x: b.x * scale,
|
|
548
|
+
y: b.y * scale
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
function vectorsEqual2D(a, b) {
|
|
552
|
+
validateVector2D(a, "First vector");
|
|
553
|
+
validateVector2D(b, "Second vector");
|
|
554
|
+
return approximatelyEqual(a.x, b.x) && approximatelyEqual(a.y, b.y);
|
|
555
|
+
}
|
|
556
|
+
function vectorsEqual3D(a, b) {
|
|
557
|
+
validateVector3D(a, "First vector");
|
|
558
|
+
validateVector3D(b, "Second vector");
|
|
559
|
+
return approximatelyEqual(a.x, b.x) && approximatelyEqual(a.y, b.y) && approximatelyEqual(a.z, b.z);
|
|
560
|
+
}
|
|
561
|
+
function vectorsEqual4D(a, b) {
|
|
562
|
+
validateVector4D(a, "First vector");
|
|
563
|
+
validateVector4D(b, "Second vector");
|
|
564
|
+
return approximatelyEqual(a.x, b.x) && approximatelyEqual(a.y, b.y) && approximatelyEqual(a.z, b.z) && approximatelyEqual(a.w, b.w);
|
|
565
|
+
}
|
|
566
|
+
function midpoint2D(a, b) {
|
|
567
|
+
validateVector2D(a, "First point");
|
|
568
|
+
validateVector2D(b, "Second point");
|
|
569
|
+
return {
|
|
570
|
+
x: (a.x + b.x) / 2,
|
|
571
|
+
y: (a.y + b.y) / 2
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function centroid2D(points) {
|
|
575
|
+
if (!Array.isArray(points) || points.length === 0) {
|
|
576
|
+
throw new Error("Points array must not be empty");
|
|
577
|
+
}
|
|
578
|
+
let sumX = 0;
|
|
579
|
+
let sumY = 0;
|
|
580
|
+
for (let i = 0; i < points.length; i++) {
|
|
581
|
+
validateVector2D(points[i], `points[${i}]`);
|
|
582
|
+
sumX += points[i].x;
|
|
583
|
+
sumY += points[i].y;
|
|
584
|
+
}
|
|
585
|
+
return {
|
|
586
|
+
x: sumX / points.length,
|
|
587
|
+
y: sumY / points.length
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function negateVector2D(vector) {
|
|
591
|
+
validateVector2D(vector);
|
|
592
|
+
return { x: -vector.x, y: -vector.y };
|
|
593
|
+
}
|
|
594
|
+
function negateVector3D(vector) {
|
|
595
|
+
validateVector3D(vector);
|
|
596
|
+
return { x: -vector.x, y: -vector.y, z: -vector.z };
|
|
597
|
+
}
|
|
598
|
+
function negateVector4D(vector) {
|
|
599
|
+
validateVector4D(vector);
|
|
600
|
+
return { x: -vector.x, y: -vector.y, z: -vector.z, w: -vector.w };
|
|
601
|
+
}
|
|
602
|
+
function perpendicular2D(vector, clockwise = true) {
|
|
603
|
+
validateVector2D(vector);
|
|
604
|
+
if (clockwise) {
|
|
605
|
+
return { x: vector.y, y: -vector.x };
|
|
606
|
+
} else {
|
|
607
|
+
return { x: -vector.y, y: vector.x };
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
function zeroVector2D() {
|
|
611
|
+
return { x: 0, y: 0 };
|
|
612
|
+
}
|
|
613
|
+
function zeroVector3D() {
|
|
614
|
+
return { x: 0, y: 0, z: 0 };
|
|
615
|
+
}
|
|
616
|
+
function zeroVector4D() {
|
|
617
|
+
return { x: 0, y: 0, z: 0, w: 0 };
|
|
618
|
+
}
|
|
619
|
+
function unitX2D() {
|
|
620
|
+
return { x: 1, y: 0 };
|
|
621
|
+
}
|
|
622
|
+
function unitY2D() {
|
|
623
|
+
return { x: 0, y: 1 };
|
|
624
|
+
}
|
|
625
|
+
function unitX3D() {
|
|
626
|
+
return { x: 1, y: 0, z: 0 };
|
|
627
|
+
}
|
|
628
|
+
function unitY3D() {
|
|
629
|
+
return { x: 0, y: 1, z: 0 };
|
|
630
|
+
}
|
|
631
|
+
function unitZ3D() {
|
|
632
|
+
return { x: 0, y: 0, z: 1 };
|
|
633
|
+
}
|
|
634
|
+
export {
|
|
635
|
+
addVectors2D,
|
|
636
|
+
addVectors3D,
|
|
637
|
+
addVectors4D,
|
|
638
|
+
angleBetween2D,
|
|
639
|
+
angleBetween3D,
|
|
640
|
+
centroid2D,
|
|
641
|
+
createVector2D,
|
|
642
|
+
createVector3D,
|
|
643
|
+
createVector4D,
|
|
644
|
+
crossProduct3D,
|
|
645
|
+
cubicBezier2D,
|
|
646
|
+
distance2D,
|
|
647
|
+
distance3D,
|
|
648
|
+
distance4D,
|
|
649
|
+
distanceSquared2D,
|
|
650
|
+
distanceSquared3D,
|
|
651
|
+
distanceSquared4D,
|
|
652
|
+
dotProduct2D,
|
|
653
|
+
dotProduct3D,
|
|
654
|
+
dotProduct4D,
|
|
655
|
+
lerp2D,
|
|
656
|
+
lerp3D,
|
|
657
|
+
lerp4D,
|
|
658
|
+
lerpClamped2D,
|
|
659
|
+
lerpClamped3D,
|
|
660
|
+
lerpClamped4D,
|
|
661
|
+
magnitude2D,
|
|
662
|
+
magnitude3D,
|
|
663
|
+
magnitude4D,
|
|
664
|
+
magnitudeSquared2D,
|
|
665
|
+
magnitudeSquared3D,
|
|
666
|
+
magnitudeSquared4D,
|
|
667
|
+
mapRange,
|
|
668
|
+
mapRangeClamped,
|
|
669
|
+
midpoint2D,
|
|
670
|
+
negateVector2D,
|
|
671
|
+
negateVector3D,
|
|
672
|
+
negateVector4D,
|
|
673
|
+
normalize2D,
|
|
674
|
+
normalize3D,
|
|
675
|
+
normalize4D,
|
|
676
|
+
perpendicular2D,
|
|
677
|
+
project2D,
|
|
678
|
+
quadraticBezier2D,
|
|
679
|
+
reflect2D,
|
|
680
|
+
rotate2D,
|
|
681
|
+
rotate2DDegrees,
|
|
682
|
+
safeNormalize2D,
|
|
683
|
+
safeNormalize3D,
|
|
684
|
+
safeNormalize4D,
|
|
685
|
+
scaleVector2D,
|
|
686
|
+
scaleVector3D,
|
|
687
|
+
scaleVector4D,
|
|
688
|
+
signedAngleBetween2D,
|
|
689
|
+
slerp3D,
|
|
690
|
+
smootherstep2D,
|
|
691
|
+
smoothstep2D,
|
|
692
|
+
smoothstepClamped2D,
|
|
693
|
+
subtractVectors2D,
|
|
694
|
+
subtractVectors3D,
|
|
695
|
+
subtractVectors4D,
|
|
696
|
+
unitX2D,
|
|
697
|
+
unitX3D,
|
|
698
|
+
unitY2D,
|
|
699
|
+
unitY3D,
|
|
700
|
+
unitZ3D,
|
|
701
|
+
vectorsEqual2D,
|
|
702
|
+
vectorsEqual3D,
|
|
703
|
+
vectorsEqual4D,
|
|
704
|
+
zeroVector2D,
|
|
705
|
+
zeroVector3D,
|
|
706
|
+
zeroVector4D
|
|
707
|
+
};
|