@ntf/math 1.2.0 → 1.3.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/dist/index.cjs +2536 -0
- package/dist/index.d.cts +738 -0
- package/dist/index.d.mts +738 -0
- package/dist/index.mjs +2489 -0
- package/package.json +19 -12
- package/dist/cjs/algebra/function.js +0 -7
- package/dist/cjs/algebra/function.js.map +0 -1
- package/dist/cjs/algebra/linear.js +0 -49
- package/dist/cjs/algebra/linear.js.map +0 -1
- package/dist/cjs/algebra/quad.js +0 -62
- package/dist/cjs/algebra/quad.js.map +0 -1
- package/dist/cjs/color.js +0 -243
- package/dist/cjs/color.js.map +0 -1
- package/dist/cjs/common/error.js +0 -14
- package/dist/cjs/common/error.js.map +0 -1
- package/dist/cjs/common/sign.js +0 -14
- package/dist/cjs/common/sign.js.map +0 -1
- package/dist/cjs/common/types.js +0 -77
- package/dist/cjs/common/types.js.map +0 -1
- package/dist/cjs/geometry/angle.js +0 -11
- package/dist/cjs/geometry/angle.js.map +0 -1
- package/dist/cjs/geometry/bbox.js +0 -102
- package/dist/cjs/geometry/bbox.js.map +0 -1
- package/dist/cjs/geometry/circle.js +0 -87
- package/dist/cjs/geometry/circle.js.map +0 -1
- package/dist/cjs/geometry/object.js +0 -3
- package/dist/cjs/geometry/object.js.map +0 -1
- package/dist/cjs/geometry/rectangle.js +0 -98
- package/dist/cjs/geometry/rectangle.js.map +0 -1
- package/dist/cjs/geometry/square.js +0 -70
- package/dist/cjs/geometry/square.js.map +0 -1
- package/dist/cjs/geometry/triangle.js +0 -65
- package/dist/cjs/geometry/triangle.js.map +0 -1
- package/dist/cjs/index.js +0 -59
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/matrices/mat3.js +0 -202
- package/dist/cjs/matrices/mat3.js.map +0 -1
- package/dist/cjs/matrices/mat4.js +0 -292
- package/dist/cjs/matrices/mat4.js.map +0 -1
- package/dist/cjs/quaternion.js +0 -204
- package/dist/cjs/quaternion.js.map +0 -1
- package/dist/cjs/vectors/vec2.js +0 -168
- package/dist/cjs/vectors/vec2.js.map +0 -1
- package/dist/cjs/vectors/vec3.js +0 -177
- package/dist/cjs/vectors/vec3.js.map +0 -1
- package/dist/esm/algebra/function.js +0 -3
- package/dist/esm/algebra/function.js.map +0 -1
- package/dist/esm/algebra/linear.js +0 -45
- package/dist/esm/algebra/linear.js.map +0 -1
- package/dist/esm/algebra/quad.js +0 -58
- package/dist/esm/algebra/quad.js.map +0 -1
- package/dist/esm/color.js +0 -236
- package/dist/esm/color.js.map +0 -1
- package/dist/esm/common/error.js +0 -10
- package/dist/esm/common/error.js.map +0 -1
- package/dist/esm/common/sign.js +0 -10
- package/dist/esm/common/sign.js.map +0 -1
- package/dist/esm/common/types.js +0 -65
- package/dist/esm/common/types.js.map +0 -1
- package/dist/esm/geometry/angle.js +0 -5
- package/dist/esm/geometry/angle.js.map +0 -1
- package/dist/esm/geometry/bbox.js +0 -98
- package/dist/esm/geometry/bbox.js.map +0 -1
- package/dist/esm/geometry/circle.js +0 -83
- package/dist/esm/geometry/circle.js.map +0 -1
- package/dist/esm/geometry/object.js +0 -2
- package/dist/esm/geometry/object.js.map +0 -1
- package/dist/esm/geometry/rectangle.js +0 -94
- package/dist/esm/geometry/rectangle.js.map +0 -1
- package/dist/esm/geometry/square.js +0 -66
- package/dist/esm/geometry/square.js.map +0 -1
- package/dist/esm/geometry/triangle.js +0 -59
- package/dist/esm/geometry/triangle.js.map +0 -1
- package/dist/esm/index.js +0 -40
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/matrices/mat3.js +0 -198
- package/dist/esm/matrices/mat3.js.map +0 -1
- package/dist/esm/matrices/mat4.js +0 -288
- package/dist/esm/matrices/mat4.js.map +0 -1
- package/dist/esm/quaternion.js +0 -200
- package/dist/esm/quaternion.js.map +0 -1
- package/dist/esm/vectors/vec2.js +0 -164
- package/dist/esm/vectors/vec2.js.map +0 -1
- package/dist/esm/vectors/vec3.js +0 -173
- package/dist/esm/vectors/vec3.js.map +0 -1
- package/dist/types/algebra/function.d.ts +0 -6
- package/dist/types/algebra/function.d.ts.map +0 -1
- package/dist/types/algebra/linear.d.ts +0 -14
- package/dist/types/algebra/linear.d.ts.map +0 -1
- package/dist/types/algebra/quad.d.ts +0 -18
- package/dist/types/algebra/quad.d.ts.map +0 -1
- package/dist/types/color.d.ts +0 -90
- package/dist/types/color.d.ts.map +0 -1
- package/dist/types/common/error.d.ts +0 -6
- package/dist/types/common/error.d.ts.map +0 -1
- package/dist/types/common/sign.d.ts +0 -2
- package/dist/types/common/sign.d.ts.map +0 -1
- package/dist/types/common/types.d.ts +0 -26
- package/dist/types/common/types.d.ts.map +0 -1
- package/dist/types/geometry/angle.d.ts +0 -5
- package/dist/types/geometry/angle.d.ts.map +0 -1
- package/dist/types/geometry/bbox.d.ts +0 -38
- package/dist/types/geometry/bbox.d.ts.map +0 -1
- package/dist/types/geometry/circle.d.ts +0 -32
- package/dist/types/geometry/circle.d.ts.map +0 -1
- package/dist/types/geometry/object.d.ts +0 -5
- package/dist/types/geometry/object.d.ts.map +0 -1
- package/dist/types/geometry/rectangle.d.ts +0 -34
- package/dist/types/geometry/rectangle.d.ts.map +0 -1
- package/dist/types/geometry/square.d.ts +0 -28
- package/dist/types/geometry/square.d.ts.map +0 -1
- package/dist/types/geometry/triangle.d.ts +0 -42
- package/dist/types/geometry/triangle.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -23
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/matrices/mat3.d.ts +0 -62
- package/dist/types/matrices/mat3.d.ts.map +0 -1
- package/dist/types/matrices/mat4.d.ts +0 -89
- package/dist/types/matrices/mat4.d.ts.map +0 -1
- package/dist/types/quaternion.d.ts +0 -50
- package/dist/types/quaternion.d.ts.map +0 -1
- package/dist/types/vectors/vec2.d.ts +0 -60
- package/dist/types/vectors/vec2.d.ts.map +0 -1
- package/dist/types/vectors/vec3.d.ts +0 -58
- package/dist/types/vectors/vec3.d.ts.map +0 -1
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2489 @@
|
|
|
1
|
+
class MathFunction {
|
|
2
|
+
}
|
|
3
|
+
|
|
4
|
+
function sign_char(num) {
|
|
5
|
+
if (num == 0)
|
|
6
|
+
return undefined;
|
|
7
|
+
if (num < 0)
|
|
8
|
+
return "-";
|
|
9
|
+
if (num > 0)
|
|
10
|
+
return "+";
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function check_number(obj) {
|
|
15
|
+
return obj != null && typeof obj == "number" && !isNaN(obj) && isFinite(obj);
|
|
16
|
+
}
|
|
17
|
+
function check_hex_digit(obj) {
|
|
18
|
+
if (!check_string(obj) || obj.length != 1)
|
|
19
|
+
return false;
|
|
20
|
+
switch (obj.toUpperCase()) {
|
|
21
|
+
default:
|
|
22
|
+
return false;
|
|
23
|
+
case "0":
|
|
24
|
+
case "1":
|
|
25
|
+
case "2":
|
|
26
|
+
case "3":
|
|
27
|
+
case "4":
|
|
28
|
+
case "5":
|
|
29
|
+
case "6":
|
|
30
|
+
case "7":
|
|
31
|
+
case "8":
|
|
32
|
+
case "9":
|
|
33
|
+
case "A":
|
|
34
|
+
case "B":
|
|
35
|
+
case "C":
|
|
36
|
+
case "D":
|
|
37
|
+
case "E":
|
|
38
|
+
case "F":
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function get_hex_part(string) {
|
|
43
|
+
let offset = 0;
|
|
44
|
+
if (string.startsWith("#") || string.startsWith("$"))
|
|
45
|
+
offset = 1;
|
|
46
|
+
if (string.startsWith("0x"))
|
|
47
|
+
offset = 2;
|
|
48
|
+
return string.substring(offset);
|
|
49
|
+
}
|
|
50
|
+
function check_hex(obj) {
|
|
51
|
+
if (!check_string(obj))
|
|
52
|
+
return false;
|
|
53
|
+
const value = get_hex_part(obj).split("").map((char) => parseInt(char.toUpperCase(), 16));
|
|
54
|
+
return check_number_array(value);
|
|
55
|
+
}
|
|
56
|
+
function check_string(obj) {
|
|
57
|
+
return obj != null && typeof obj == "string" && obj.length > 0;
|
|
58
|
+
}
|
|
59
|
+
function check_array(obj, predicate, requiredLength) {
|
|
60
|
+
if (!Array.isArray(obj)) return false;
|
|
61
|
+
if (requiredLength && requiredLength != obj.length) return false;
|
|
62
|
+
for (const item of obj)
|
|
63
|
+
if (predicate && !predicate(item))
|
|
64
|
+
return false;
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
function check_number_array(obj, requiredLength) {
|
|
68
|
+
return check_array(obj, check_number, requiredLength);
|
|
69
|
+
}
|
|
70
|
+
function check_string_array(obj, requiredLength) {
|
|
71
|
+
return check_array(obj, check_string, requiredLength);
|
|
72
|
+
}
|
|
73
|
+
function has_property(obj, name, type) {
|
|
74
|
+
return obj != null && typeof obj == "object" && name in obj && typeof obj[name] == type;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class ResolveError extends Error {
|
|
78
|
+
constructor(target, value) {
|
|
79
|
+
super(`can't resolve ${value} to ${target}`);
|
|
80
|
+
this.target = target;
|
|
81
|
+
this.value = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class Size {
|
|
86
|
+
width;
|
|
87
|
+
height;
|
|
88
|
+
get aspectRatio() {
|
|
89
|
+
return this.height / this.width;
|
|
90
|
+
}
|
|
91
|
+
get area() {
|
|
92
|
+
return this.width * this.height;
|
|
93
|
+
}
|
|
94
|
+
get perimeter() {
|
|
95
|
+
return this.width + this.width + this.height + this.height;
|
|
96
|
+
}
|
|
97
|
+
static resolve(a) {
|
|
98
|
+
const value = this.cast(a);
|
|
99
|
+
if (typeof value != "undefined")
|
|
100
|
+
return value;
|
|
101
|
+
throw new ResolveError("Square", a);
|
|
102
|
+
}
|
|
103
|
+
static cast(a) {
|
|
104
|
+
if (a == null || typeof a == "undefined")
|
|
105
|
+
return undefined;
|
|
106
|
+
if (check_number_array(a, 2))
|
|
107
|
+
return new this(a[0], a[1]);
|
|
108
|
+
if (has_property(a, "width", "number") && has_property(a, "height", "number"))
|
|
109
|
+
return new this(a.width, a.height);
|
|
110
|
+
if (check_string(a)) {
|
|
111
|
+
const parts = a.split("x").map((v) => parseFloat(v));
|
|
112
|
+
if (check_number_array(parts, 2))
|
|
113
|
+
return this.cast(parts);
|
|
114
|
+
}
|
|
115
|
+
if (check_number(a))
|
|
116
|
+
return new this(a, a);
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
static is(a) {
|
|
120
|
+
return typeof this.cast(a) != "undefined";
|
|
121
|
+
}
|
|
122
|
+
constructor(width, height) {
|
|
123
|
+
if (!check_number(width))
|
|
124
|
+
throw new TypeError("expected number for width");
|
|
125
|
+
if (!check_number(height))
|
|
126
|
+
throw new TypeError("expected number for height");
|
|
127
|
+
this.width = width;
|
|
128
|
+
this.height = height;
|
|
129
|
+
}
|
|
130
|
+
toArray() {
|
|
131
|
+
return [this.width, this.height];
|
|
132
|
+
}
|
|
133
|
+
toString() {
|
|
134
|
+
return `${this.width}x${this.height}`;
|
|
135
|
+
}
|
|
136
|
+
toJSON() {
|
|
137
|
+
return {
|
|
138
|
+
width: this.width,
|
|
139
|
+
height: this.height
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
clone() {
|
|
143
|
+
return new Size(this.width, this.height);
|
|
144
|
+
}
|
|
145
|
+
equals(square) {
|
|
146
|
+
const s = Size.resolve(square);
|
|
147
|
+
return this.width == s.width && this.height == s.height;
|
|
148
|
+
}
|
|
149
|
+
toVec2() {
|
|
150
|
+
return [this.width, this.height];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function clamp(value, min, max) {
|
|
155
|
+
if (value <= min)
|
|
156
|
+
return min;
|
|
157
|
+
if (value >= max)
|
|
158
|
+
return max;
|
|
159
|
+
return value;
|
|
160
|
+
}
|
|
161
|
+
function log_hypot(a, b) {
|
|
162
|
+
const a_abs = Math.abs(a);
|
|
163
|
+
const b_abs = Math.abs(b);
|
|
164
|
+
if (a == 0)
|
|
165
|
+
return Math.log(b_abs);
|
|
166
|
+
if (b == 0)
|
|
167
|
+
return Math.log(a_abs);
|
|
168
|
+
if (a_abs < 3e3 && b_abs < 3e3)
|
|
169
|
+
return 0.5 * Math.log(a * a + b * b);
|
|
170
|
+
const _a = a / 2, _b = b / 2;
|
|
171
|
+
return 0.5 * Math.log(_a * _a + _b * _b) + Math.LN2;
|
|
172
|
+
}
|
|
173
|
+
const EPSILON = 1e-16;
|
|
174
|
+
|
|
175
|
+
class Vec3 {
|
|
176
|
+
x;
|
|
177
|
+
y;
|
|
178
|
+
z;
|
|
179
|
+
w;
|
|
180
|
+
static resolve(a) {
|
|
181
|
+
const value = this.cast(a);
|
|
182
|
+
if (typeof value != "undefined")
|
|
183
|
+
return value;
|
|
184
|
+
throw new ResolveError("Vec3", a);
|
|
185
|
+
}
|
|
186
|
+
static cast(a) {
|
|
187
|
+
if (a == null || typeof a == "undefined")
|
|
188
|
+
return undefined;
|
|
189
|
+
if (check_number_array(a, 3) || check_number_array(a, 4))
|
|
190
|
+
return new this(a[0], a[1], a[2], check_number(a[3]) ? a[3] : undefined);
|
|
191
|
+
if (has_property(a, "x", "number") && has_property(a, "y", "number") && has_property(a, "z", "number"))
|
|
192
|
+
return new this(a.x, a.y, a.z, has_property(a, "w", "number") ? a.w : undefined);
|
|
193
|
+
if (check_string(a)) {
|
|
194
|
+
const [sxyz, sw] = a.split(";");
|
|
195
|
+
if (check_string(sxyz)) {
|
|
196
|
+
const parts = sxyz.split(",");
|
|
197
|
+
if (check_string_array(parts, 3))
|
|
198
|
+
return new this(parseFloat(parts[0]), parseFloat(parts[1]), parseFloat(parts[2]), check_string(sw) ? parseFloat(sw) : undefined);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (check_number(a))
|
|
202
|
+
return new this(a, a, a);
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
static resolveArgs(args) {
|
|
206
|
+
if (check_number_array(args, 3))
|
|
207
|
+
return new this(args[0], args[1], args[2]);
|
|
208
|
+
return this.resolve(args[0]);
|
|
209
|
+
}
|
|
210
|
+
static is(a) {
|
|
211
|
+
return typeof this.cast(a) != "undefined";
|
|
212
|
+
}
|
|
213
|
+
static fromPoints(a, b) {
|
|
214
|
+
const veca = this.resolve(a);
|
|
215
|
+
const vecb = this.resolve(b);
|
|
216
|
+
return new this(vecb.x - veca.x, vecb.y - veca.y, vecb.z - veca.z);
|
|
217
|
+
}
|
|
218
|
+
static clamp(value, min, max) {
|
|
219
|
+
const a = this.resolve(value), b = this.resolve(min), c = this.resolve(max);
|
|
220
|
+
return new this(
|
|
221
|
+
clamp(a.x, b.x, c.x),
|
|
222
|
+
clamp(a.y, b.y, c.y),
|
|
223
|
+
clamp(a.z, b.z, c.z)
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
static intersectPlane(planeP, planeN, lineStart, lineEnd, t) {
|
|
227
|
+
planeN = this.resolve(planeN).normalize();
|
|
228
|
+
const plane_d = -this.resolve(planeN).dot(planeP);
|
|
229
|
+
const ad = this.resolve(lineStart).dot(planeN);
|
|
230
|
+
const bd = this.resolve(lineEnd).dot(planeN);
|
|
231
|
+
t = (-plane_d - ad) / (bd - ad);
|
|
232
|
+
const lineStartToEnd = this.resolve(lineEnd).subtract(lineStart);
|
|
233
|
+
const linetoIntersect = lineStartToEnd.multiply(t);
|
|
234
|
+
return Vec3.resolve(lineStart).add(linetoIntersect);
|
|
235
|
+
}
|
|
236
|
+
constructor(x = 0, y = 0, z = 0, w = 1) {
|
|
237
|
+
if (!check_number(x))
|
|
238
|
+
throw new TypeError("expected number for x");
|
|
239
|
+
if (!check_number(y))
|
|
240
|
+
throw new TypeError("expected number for y");
|
|
241
|
+
if (!check_number(z))
|
|
242
|
+
throw new TypeError("expected number for z");
|
|
243
|
+
if (!check_number(w))
|
|
244
|
+
throw new TypeError("expected number for w");
|
|
245
|
+
this.x = x;
|
|
246
|
+
this.y = y;
|
|
247
|
+
this.z = z;
|
|
248
|
+
this.w = w;
|
|
249
|
+
}
|
|
250
|
+
toArray(w = false) {
|
|
251
|
+
return w ? [this.x, this.y, this.z] : [this.x, this.y, this.z, this.w];
|
|
252
|
+
}
|
|
253
|
+
toJSON() {
|
|
254
|
+
return {
|
|
255
|
+
x: this.x,
|
|
256
|
+
y: this.y,
|
|
257
|
+
z: this.z,
|
|
258
|
+
w: this.w
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
toString(w = false) {
|
|
262
|
+
return w ? `${this.x},${this.y},${this.z}` : `${this.x},${this.y},${this.z};${this.w}`;
|
|
263
|
+
}
|
|
264
|
+
toVec2() {
|
|
265
|
+
return [this.x, this.y, this.w];
|
|
266
|
+
}
|
|
267
|
+
clone() {
|
|
268
|
+
return new Vec3(this.x, this.y, this.z, this.w);
|
|
269
|
+
}
|
|
270
|
+
equals(vec) {
|
|
271
|
+
const a = Vec3.resolve(vec);
|
|
272
|
+
return this.x == a.x && this.y == a.y && this.z == a.z;
|
|
273
|
+
}
|
|
274
|
+
setX(x) {
|
|
275
|
+
this.x = x;
|
|
276
|
+
return this;
|
|
277
|
+
}
|
|
278
|
+
setY(y) {
|
|
279
|
+
this.y = y;
|
|
280
|
+
return this;
|
|
281
|
+
}
|
|
282
|
+
setZ(z) {
|
|
283
|
+
this.z = z;
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
set(...args) {
|
|
287
|
+
const vec = Vec3.resolveArgs(args);
|
|
288
|
+
return this.setX(vec.x).setY(vec.y).setZ(vec.z);
|
|
289
|
+
}
|
|
290
|
+
add(...args) {
|
|
291
|
+
const vec = Vec3.resolveArgs(args);
|
|
292
|
+
return new Vec3(
|
|
293
|
+
this.x + vec.x,
|
|
294
|
+
this.y + vec.y,
|
|
295
|
+
this.z + vec.z
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
offset(...args) {
|
|
299
|
+
const vec = Vec3.resolveArgs(args);
|
|
300
|
+
this.x += vec.x;
|
|
301
|
+
this.y += vec.y;
|
|
302
|
+
this.z += vec.z;
|
|
303
|
+
return this;
|
|
304
|
+
}
|
|
305
|
+
subtract(...args) {
|
|
306
|
+
const vec = Vec3.resolveArgs(args);
|
|
307
|
+
return new Vec3(
|
|
308
|
+
this.x - vec.x,
|
|
309
|
+
this.y - vec.y,
|
|
310
|
+
this.z - vec.z
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
multiply(scalar) {
|
|
314
|
+
return new Vec3(
|
|
315
|
+
this.x * scalar,
|
|
316
|
+
this.y * scalar,
|
|
317
|
+
this.z * scalar
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
naiveMultiply(...args) {
|
|
321
|
+
const vec = Vec3.resolveArgs(args);
|
|
322
|
+
return new Vec3(
|
|
323
|
+
this.x * vec.x,
|
|
324
|
+
this.y * vec.y,
|
|
325
|
+
this.z * vec.z
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
divide(...args) {
|
|
329
|
+
if (check_number_array(args, 1))
|
|
330
|
+
return new Vec3(
|
|
331
|
+
this.x / args[0],
|
|
332
|
+
this.y / args[0],
|
|
333
|
+
this.z / args[0]
|
|
334
|
+
);
|
|
335
|
+
const vec = Vec3.resolveArgs(args);
|
|
336
|
+
return new Vec3(
|
|
337
|
+
this.x / vec.x,
|
|
338
|
+
this.y / vec.y,
|
|
339
|
+
this.z / vec.z
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
dot(...args) {
|
|
343
|
+
const vec = Vec3.resolveArgs(args);
|
|
344
|
+
return this.x * vec.x + this.y * vec.y + this.z * vec.z;
|
|
345
|
+
}
|
|
346
|
+
cross(...args) {
|
|
347
|
+
const vec = Vec3.resolveArgs(args);
|
|
348
|
+
return new Vec3(
|
|
349
|
+
this.y * vec.z - this.z * vec.y,
|
|
350
|
+
this.z * vec.x - this.x * vec.z,
|
|
351
|
+
this.x * vec.y - this.y * vec.x
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
distance(...args) {
|
|
355
|
+
const vec = Vec3.resolveArgs(args);
|
|
356
|
+
return Math.pow(vec.x - this.x, 2) + Math.pow(vec.y - this.y, 2) + Math.pow(vec.z - this.z, 2);
|
|
357
|
+
}
|
|
358
|
+
distanceSquare(...args) {
|
|
359
|
+
const vec = Vec3.resolveArgs(args);
|
|
360
|
+
return Math.sqrt(Math.pow(vec.x - this.x, 2) + Math.pow(vec.y - this.y, 2) + Math.pow(vec.z - this.z, 2));
|
|
361
|
+
}
|
|
362
|
+
length() {
|
|
363
|
+
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
|
364
|
+
}
|
|
365
|
+
normalize() {
|
|
366
|
+
const length = this.length();
|
|
367
|
+
if (length == 0) return new Vec3();
|
|
368
|
+
return new Vec3(
|
|
369
|
+
this.x / length,
|
|
370
|
+
this.y / length,
|
|
371
|
+
this.z / length
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
invert() {
|
|
375
|
+
return this.multiply(-1);
|
|
376
|
+
}
|
|
377
|
+
round() {
|
|
378
|
+
return new Vec3(Math.round(this.x), Math.round(this.y), Math.round(this.z), Math.round(this.w));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
class Vec2 {
|
|
383
|
+
x;
|
|
384
|
+
y;
|
|
385
|
+
w;
|
|
386
|
+
static resolve(a) {
|
|
387
|
+
const value = this.cast(a);
|
|
388
|
+
if (typeof value != "undefined")
|
|
389
|
+
return value;
|
|
390
|
+
throw new ResolveError("Vec2", a);
|
|
391
|
+
}
|
|
392
|
+
static cast(a) {
|
|
393
|
+
if (a == null || typeof a == "undefined")
|
|
394
|
+
return undefined;
|
|
395
|
+
if (check_number_array(a, 2) || check_number_array(a, 3))
|
|
396
|
+
return new this(a[0], a[1], check_number(a[2]) ? a[2] : undefined);
|
|
397
|
+
if (has_property(a, "x", "number") && has_property(a, "y", "number"))
|
|
398
|
+
return new this(a.x, a.y, has_property(a, "w", "number") ? a.w : undefined);
|
|
399
|
+
if (check_string(a)) {
|
|
400
|
+
const [sxy, sw] = a.split(";");
|
|
401
|
+
if (check_string(sxy)) {
|
|
402
|
+
const parts = sxy.split(",");
|
|
403
|
+
if (check_string_array(parts, 2))
|
|
404
|
+
return new this(parseFloat(parts[0]), parseFloat(parts[1]), check_string(sw) ? parseFloat(sw) : undefined);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (check_number(a))
|
|
408
|
+
return new this(a, a);
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
static resolveArgs(args) {
|
|
412
|
+
if (check_number_array(args, 2))
|
|
413
|
+
return new this(args[0], args[1]);
|
|
414
|
+
return this.resolve(args[0]);
|
|
415
|
+
}
|
|
416
|
+
static is(a) {
|
|
417
|
+
return typeof this.cast(a) != "undefined";
|
|
418
|
+
}
|
|
419
|
+
static fromPoints(a, b) {
|
|
420
|
+
const veca = this.resolve(a);
|
|
421
|
+
const vecb = this.resolve(b);
|
|
422
|
+
return new this(vecb.x - veca.x, vecb.y - veca.y);
|
|
423
|
+
}
|
|
424
|
+
static clamp(value, min, max) {
|
|
425
|
+
const a = this.resolve(value), b = this.resolve(min), c = this.resolve(max);
|
|
426
|
+
return new this(
|
|
427
|
+
clamp(a.x, b.x, c.x),
|
|
428
|
+
clamp(a.y, b.y, c.y)
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
constructor(x = 0, y = 0, w = 1) {
|
|
432
|
+
if (!check_number(x))
|
|
433
|
+
throw new TypeError("expected number for x");
|
|
434
|
+
if (!check_number(y))
|
|
435
|
+
throw new TypeError("expected number for y");
|
|
436
|
+
if (!check_number(w))
|
|
437
|
+
throw new TypeError("expected number for w");
|
|
438
|
+
this.x = x;
|
|
439
|
+
this.y = y;
|
|
440
|
+
this.w = w;
|
|
441
|
+
}
|
|
442
|
+
toArray(w = false) {
|
|
443
|
+
return w ? [this.x, this.y] : [this.x, this.y, this.w];
|
|
444
|
+
}
|
|
445
|
+
toJSON() {
|
|
446
|
+
return {
|
|
447
|
+
x: this.x,
|
|
448
|
+
y: this.y,
|
|
449
|
+
w: this.w
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
toString(w = false) {
|
|
453
|
+
return w ? `${this.x},${this.y}` : `${this.x},${this.y};${this.w}`;
|
|
454
|
+
}
|
|
455
|
+
toSquare() {
|
|
456
|
+
return new Size(this.x, this.y);
|
|
457
|
+
}
|
|
458
|
+
toVec3(z) {
|
|
459
|
+
return new Vec3(this.x, this.y, z, this.w);
|
|
460
|
+
}
|
|
461
|
+
clone() {
|
|
462
|
+
return new Vec2(this.x, this.y, this.w);
|
|
463
|
+
}
|
|
464
|
+
equals(vec) {
|
|
465
|
+
const a = Vec2.resolve(vec);
|
|
466
|
+
return this.x == a.x && this.y == a.y;
|
|
467
|
+
}
|
|
468
|
+
setX(x) {
|
|
469
|
+
this.x = x;
|
|
470
|
+
return this;
|
|
471
|
+
}
|
|
472
|
+
setY(y) {
|
|
473
|
+
this.y = y;
|
|
474
|
+
return this;
|
|
475
|
+
}
|
|
476
|
+
setW(w) {
|
|
477
|
+
this.w = w;
|
|
478
|
+
return this;
|
|
479
|
+
}
|
|
480
|
+
set(...args) {
|
|
481
|
+
const vec = Vec2.resolveArgs(args);
|
|
482
|
+
return this.setX(vec.x).setY(vec.y);
|
|
483
|
+
}
|
|
484
|
+
add(...args) {
|
|
485
|
+
const vec = Vec2.resolveArgs(args);
|
|
486
|
+
return new Vec2(
|
|
487
|
+
this.x + vec.x,
|
|
488
|
+
this.y + vec.y
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
offset(...args) {
|
|
492
|
+
const vec = Vec2.resolveArgs(args);
|
|
493
|
+
this.x += vec.x;
|
|
494
|
+
this.y += vec.y;
|
|
495
|
+
return this;
|
|
496
|
+
}
|
|
497
|
+
subtract(...args) {
|
|
498
|
+
const vec = Vec2.resolveArgs(args);
|
|
499
|
+
return new Vec2(
|
|
500
|
+
this.x - vec.x,
|
|
501
|
+
this.y - vec.y
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
multiply(scalar) {
|
|
505
|
+
return new Vec2(
|
|
506
|
+
this.x * scalar,
|
|
507
|
+
this.y * scalar
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
naiveMultiply(...args) {
|
|
511
|
+
const vec = Vec2.resolveArgs(args);
|
|
512
|
+
return new Vec2(
|
|
513
|
+
this.x * vec.x,
|
|
514
|
+
this.y * vec.y
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
divide(...args) {
|
|
518
|
+
if (check_number_array(args, 1))
|
|
519
|
+
return new Vec2(
|
|
520
|
+
this.x / args[0],
|
|
521
|
+
this.y / args[0]
|
|
522
|
+
);
|
|
523
|
+
const vec = Vec2.resolveArgs(args);
|
|
524
|
+
return new Vec2(
|
|
525
|
+
this.x / vec.x,
|
|
526
|
+
this.y / vec.y
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
dot(...args) {
|
|
530
|
+
const vec = Vec2.resolveArgs(args);
|
|
531
|
+
return this.x * vec.x + this.y * vec.y;
|
|
532
|
+
}
|
|
533
|
+
distance(...args) {
|
|
534
|
+
const vec = Vec2.resolveArgs(args);
|
|
535
|
+
return Math.pow(vec.x - this.x, 2) + Math.pow(vec.y - this.y, 2);
|
|
536
|
+
}
|
|
537
|
+
distanceSquare(...args) {
|
|
538
|
+
const vec = Vec2.resolveArgs(args);
|
|
539
|
+
return Math.sqrt(Math.pow(vec.x - this.x, 2) + Math.pow(vec.y - this.y, 2));
|
|
540
|
+
}
|
|
541
|
+
length() {
|
|
542
|
+
return Math.sqrt(this.x * this.x + this.y * this.y);
|
|
543
|
+
}
|
|
544
|
+
cartesianify() {
|
|
545
|
+
return new Vec2(
|
|
546
|
+
this.x * Math.cos(this.y),
|
|
547
|
+
this.x * Math.sin(this.y)
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
polarify() {
|
|
551
|
+
return new Vec2(
|
|
552
|
+
Math.sqrt(this.x * this.x + this.y * this.y),
|
|
553
|
+
Math.atan(this.y / this.x)
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
normalize() {
|
|
557
|
+
const length = this.length();
|
|
558
|
+
if (length == 0) return new Vec2();
|
|
559
|
+
return new Vec2(
|
|
560
|
+
this.x / length,
|
|
561
|
+
this.y / length
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
invert() {
|
|
565
|
+
return this.multiply(-1);
|
|
566
|
+
}
|
|
567
|
+
round() {
|
|
568
|
+
return new Vec2(Math.round(this.x), Math.round(this.y), Math.round(this.w));
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
class LinearFunction extends MathFunction {
|
|
573
|
+
/**
|
|
574
|
+
* The factor of the linear function
|
|
575
|
+
*/
|
|
576
|
+
m;
|
|
577
|
+
/**
|
|
578
|
+
* The height of the linear function
|
|
579
|
+
*/
|
|
580
|
+
b;
|
|
581
|
+
/**
|
|
582
|
+
* Create a linear function from two points
|
|
583
|
+
* @param a A point
|
|
584
|
+
* @param b A point
|
|
585
|
+
* @returns A linear function from two points
|
|
586
|
+
*/
|
|
587
|
+
static fromPoints(a, b) {
|
|
588
|
+
const veca = Vec2.resolve(a);
|
|
589
|
+
const vecb = Vec2.resolve(b);
|
|
590
|
+
const m = (vecb.y - veca.y) / (vecb.x - veca.x);
|
|
591
|
+
const h = -m * veca.x + veca.y;
|
|
592
|
+
return new this(m, h);
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Create a linear function with a factor and height
|
|
596
|
+
* @param m The factor
|
|
597
|
+
* @param b The height
|
|
598
|
+
*/
|
|
599
|
+
constructor(m, b) {
|
|
600
|
+
super();
|
|
601
|
+
if (!check_number(m))
|
|
602
|
+
throw new TypeError("expected number for m");
|
|
603
|
+
if (!check_number(b))
|
|
604
|
+
throw new TypeError("expected number for b");
|
|
605
|
+
this.m = m;
|
|
606
|
+
this.b = b;
|
|
607
|
+
}
|
|
608
|
+
get(x) {
|
|
609
|
+
if (!check_number(x))
|
|
610
|
+
throw new TypeError("expected number for x");
|
|
611
|
+
return this.m;
|
|
612
|
+
}
|
|
613
|
+
roots() {
|
|
614
|
+
const x = -this.b / this.m;
|
|
615
|
+
if (!isNaN(x))
|
|
616
|
+
return [new Vec2(x)];
|
|
617
|
+
return [];
|
|
618
|
+
}
|
|
619
|
+
toString() {
|
|
620
|
+
const bsign = sign_char(this.b);
|
|
621
|
+
if (bsign)
|
|
622
|
+
return `f(x) = ${this.m} * x ${bsign} ${Math.abs(this.b)}`;
|
|
623
|
+
return `f(x) = ${this.m} * x`;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
class QuadFunction extends MathFunction {
|
|
628
|
+
a;
|
|
629
|
+
b;
|
|
630
|
+
c;
|
|
631
|
+
static get(a, b, c, x) {
|
|
632
|
+
return new this(a, b, c).get(x);
|
|
633
|
+
}
|
|
634
|
+
constructor(a, b, c) {
|
|
635
|
+
super();
|
|
636
|
+
if (!check_number(a))
|
|
637
|
+
throw new TypeError("expected number for a");
|
|
638
|
+
if (a == 0)
|
|
639
|
+
throw new TypeError("a cannot be 0");
|
|
640
|
+
if (!check_number(b))
|
|
641
|
+
throw new TypeError("expected number for b");
|
|
642
|
+
if (!check_number(c))
|
|
643
|
+
throw new TypeError("expected number for c");
|
|
644
|
+
this.a = a;
|
|
645
|
+
this.b = b;
|
|
646
|
+
this.c = c;
|
|
647
|
+
}
|
|
648
|
+
get(x) {
|
|
649
|
+
if (!check_number(x))
|
|
650
|
+
throw new TypeError("expected number for x");
|
|
651
|
+
return this.a * x * x + this.b * x + this.c;
|
|
652
|
+
}
|
|
653
|
+
roots() {
|
|
654
|
+
const roots = new Array();
|
|
655
|
+
const discriminant = this.b * this.b - 4 * this.a * this.c;
|
|
656
|
+
const n0 = (-this.b + Math.sqrt(discriminant)) / (2 * this.a);
|
|
657
|
+
const n1 = (-this.b + Math.sqrt(discriminant)) / (2 * this.a);
|
|
658
|
+
if (!isNaN(n0))
|
|
659
|
+
roots.push(new Vec2(n0));
|
|
660
|
+
if (!isNaN(n1) && n0 != n1)
|
|
661
|
+
roots.push(new Vec2(n1));
|
|
662
|
+
return roots;
|
|
663
|
+
}
|
|
664
|
+
toString(type = "standard") {
|
|
665
|
+
switch (type) {
|
|
666
|
+
default:
|
|
667
|
+
case "standard": {
|
|
668
|
+
const bsign = sign_char(this.b);
|
|
669
|
+
const csign = sign_char(this.c);
|
|
670
|
+
if (bsign && csign)
|
|
671
|
+
return `f(x) = ${this.a}x^2 ${bsign} ${Math.abs(this.b)}x ${csign} ${Math.abs(this.c)}`;
|
|
672
|
+
if (bsign)
|
|
673
|
+
return `f(x) = ${this.a}x^2 ${bsign} ${Math.abs(this.b)}x`;
|
|
674
|
+
return `f(x) = ${this.a}x^2`;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function stringify(value) {
|
|
681
|
+
return value != null && typeof value == "object" && "toString" in value && typeof value.toString == "function" ? value.toString() : String(value);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const DJB2_OFFSET = 5381n;
|
|
685
|
+
function djb2(value) {
|
|
686
|
+
const string = stringify(value);
|
|
687
|
+
let hash = DJB2_OFFSET;
|
|
688
|
+
for (let i = 0; i < string.length; i++) {
|
|
689
|
+
hash = (hash << 5n) + hash + BigInt(string.charCodeAt(i));
|
|
690
|
+
}
|
|
691
|
+
return hash;
|
|
692
|
+
}
|
|
693
|
+
const FNV1_OFFSET = 14695981039346656037n;
|
|
694
|
+
const FNV1_PRIME = 1099511628211n;
|
|
695
|
+
function fnv1(value) {
|
|
696
|
+
const string = stringify(value);
|
|
697
|
+
let hash = FNV1_OFFSET;
|
|
698
|
+
for (let i = 0; i < string.length; i++) {
|
|
699
|
+
hash *= FNV1_PRIME;
|
|
700
|
+
hash ^= BigInt(string.charCodeAt(i));
|
|
701
|
+
}
|
|
702
|
+
return hash;
|
|
703
|
+
}
|
|
704
|
+
function sdbm(value) {
|
|
705
|
+
const string = stringify(value);
|
|
706
|
+
let hash = 0n;
|
|
707
|
+
for (let i = 0; i < string.length; i++) {
|
|
708
|
+
hash = BigInt(string.charCodeAt(i)) + (hash << 6n) + (hash << 16n) - hash;
|
|
709
|
+
}
|
|
710
|
+
return hash;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
const MAX_ANGLE_DEGREE = 360;
|
|
714
|
+
const cap_angle_degree = (angle) => angle % MAX_ANGLE_DEGREE;
|
|
715
|
+
const cap_angle_radian = (angle) => cap_angle_degree(degree_to_radian(angle));
|
|
716
|
+
const radian_to_degree = (angle) => angle * (180 / Math.PI);
|
|
717
|
+
const degree_to_radian = (angle) => angle * (Math.PI / 180);
|
|
718
|
+
|
|
719
|
+
class Circle {
|
|
720
|
+
radius;
|
|
721
|
+
get perimeter() {
|
|
722
|
+
return this.radius * Math.PI * 2;
|
|
723
|
+
}
|
|
724
|
+
get area() {
|
|
725
|
+
return Math.PI * Math.pow(this.radius, 2);
|
|
726
|
+
}
|
|
727
|
+
position;
|
|
728
|
+
get x() {
|
|
729
|
+
return this.position.x;
|
|
730
|
+
}
|
|
731
|
+
set x(val) {
|
|
732
|
+
this.position.x = val;
|
|
733
|
+
}
|
|
734
|
+
get y() {
|
|
735
|
+
return this.position.y;
|
|
736
|
+
}
|
|
737
|
+
set y(val) {
|
|
738
|
+
this.position.y = val;
|
|
739
|
+
}
|
|
740
|
+
get w() {
|
|
741
|
+
return this.position.w;
|
|
742
|
+
}
|
|
743
|
+
set w(val) {
|
|
744
|
+
this.position.w = val;
|
|
745
|
+
}
|
|
746
|
+
static resolve(a) {
|
|
747
|
+
const value = this.cast(a);
|
|
748
|
+
if (typeof value != "undefined")
|
|
749
|
+
return value;
|
|
750
|
+
throw new ResolveError("Circle", a);
|
|
751
|
+
}
|
|
752
|
+
static cast(a) {
|
|
753
|
+
if (a == null || typeof a == "undefined")
|
|
754
|
+
return undefined;
|
|
755
|
+
if (check_number_array(a, 3))
|
|
756
|
+
return new this([a[0], a[1]], a[2]);
|
|
757
|
+
if (check_number_array(a, 4)) {
|
|
758
|
+
const c = new this([a[0], a[1]], a[3]);
|
|
759
|
+
c.w = a[2];
|
|
760
|
+
return c;
|
|
761
|
+
}
|
|
762
|
+
if (has_property(a, "x", "number") && has_property(a, "y", "number") && has_property(a, "radius", "number"))
|
|
763
|
+
return new this(has_property(a, "w", "number") ? [a.x, a.y, a.w] : [a.x, a.y], a.radius);
|
|
764
|
+
if (check_string(a)) {
|
|
765
|
+
const [spos, sradius] = a.split("|");
|
|
766
|
+
const pos = Vec2.cast(spos);
|
|
767
|
+
if (typeof pos == "undefined")
|
|
768
|
+
return undefined;
|
|
769
|
+
const radius = parseFloat(sradius);
|
|
770
|
+
if (!isNaN(radius))
|
|
771
|
+
return new this(pos, radius);
|
|
772
|
+
}
|
|
773
|
+
return undefined;
|
|
774
|
+
}
|
|
775
|
+
static is(a) {
|
|
776
|
+
return typeof this.cast(a) != "undefined";
|
|
777
|
+
}
|
|
778
|
+
constructor(position, radius) {
|
|
779
|
+
this.position = Vec2.resolve(position);
|
|
780
|
+
if (!check_number(radius))
|
|
781
|
+
throw new TypeError("expected number for radius");
|
|
782
|
+
this.radius = radius;
|
|
783
|
+
}
|
|
784
|
+
toArray() {
|
|
785
|
+
return [...this.position.toArray(), this.radius];
|
|
786
|
+
}
|
|
787
|
+
toJSON() {
|
|
788
|
+
return {
|
|
789
|
+
...this.position.toJSON(),
|
|
790
|
+
radius: this.radius
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
toString() {
|
|
794
|
+
return `${this.position.toString()}|${this.radius}`;
|
|
795
|
+
}
|
|
796
|
+
clone() {
|
|
797
|
+
return new Circle(this.position.clone(), this.radius);
|
|
798
|
+
}
|
|
799
|
+
equals(circle) {
|
|
800
|
+
const c = Circle.resolve(circle);
|
|
801
|
+
return c.position.equals(c.position) && this.radius == c.radius;
|
|
802
|
+
}
|
|
803
|
+
inside(a) {
|
|
804
|
+
const circle = Circle.resolve(a);
|
|
805
|
+
const distX = circle.x - this.x;
|
|
806
|
+
const distY = circle.y - this.y;
|
|
807
|
+
const dist = Math.sqrt(distX * distX + (distY + distY));
|
|
808
|
+
return dist <= this.radius + circle.radius;
|
|
809
|
+
}
|
|
810
|
+
insidePoint(a) {
|
|
811
|
+
return this.position.distance(a) <= this.radius;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
class Rectangle {
|
|
816
|
+
position;
|
|
817
|
+
size;
|
|
818
|
+
get area() {
|
|
819
|
+
return this.width * this.height;
|
|
820
|
+
}
|
|
821
|
+
get perimeter() {
|
|
822
|
+
return this.width + this.width + this.height + this.height;
|
|
823
|
+
}
|
|
824
|
+
get x() {
|
|
825
|
+
return this.position.x;
|
|
826
|
+
}
|
|
827
|
+
set x(val) {
|
|
828
|
+
this.position.x = val;
|
|
829
|
+
}
|
|
830
|
+
get y() {
|
|
831
|
+
return this.position.y;
|
|
832
|
+
}
|
|
833
|
+
set y(val) {
|
|
834
|
+
this.position.y = val;
|
|
835
|
+
}
|
|
836
|
+
get w() {
|
|
837
|
+
return this.position.w;
|
|
838
|
+
}
|
|
839
|
+
set w(val) {
|
|
840
|
+
this.position.w = val;
|
|
841
|
+
}
|
|
842
|
+
get width() {
|
|
843
|
+
return this.size.width;
|
|
844
|
+
}
|
|
845
|
+
set width(val) {
|
|
846
|
+
this.size.width = val;
|
|
847
|
+
}
|
|
848
|
+
get height() {
|
|
849
|
+
return this.size.height;
|
|
850
|
+
}
|
|
851
|
+
set height(val) {
|
|
852
|
+
this.size.height = val;
|
|
853
|
+
}
|
|
854
|
+
static resolve(a) {
|
|
855
|
+
const value = this.cast(a);
|
|
856
|
+
if (typeof value != "undefined")
|
|
857
|
+
return value;
|
|
858
|
+
throw new ResolveError("Rectangle", a);
|
|
859
|
+
}
|
|
860
|
+
static cast(a) {
|
|
861
|
+
if (a == null || typeof a == "undefined")
|
|
862
|
+
return undefined;
|
|
863
|
+
if (check_number_array(a, 4))
|
|
864
|
+
return new this(a[0], a[1], a[2], a[3]);
|
|
865
|
+
if (check_number_array(a, 5)) {
|
|
866
|
+
const rect = new this(a[0], a[1], a[3], a[4]);
|
|
867
|
+
rect.w = a[2];
|
|
868
|
+
return rect;
|
|
869
|
+
}
|
|
870
|
+
if (check_string(a)) {
|
|
871
|
+
const [spos, ssize] = a.split("|");
|
|
872
|
+
const pos = Vec2.cast(spos);
|
|
873
|
+
const size = Size.cast(ssize);
|
|
874
|
+
if (typeof pos == "undefined" || typeof size == "undefined")
|
|
875
|
+
return undefined;
|
|
876
|
+
const rect = new this(pos.x, pos.y, size.width, size.height);
|
|
877
|
+
rect.w = pos.w;
|
|
878
|
+
return rect;
|
|
879
|
+
}
|
|
880
|
+
if (has_property(a, "x", "number") && has_property(a, "y", "number") && has_property(a, "width", "number") && has_property(a, "height", "number")) {
|
|
881
|
+
const rect = new this(a.x, a.y, a.width, a.height);
|
|
882
|
+
if (has_property(a, "w", "number"))
|
|
883
|
+
rect.w = a.w;
|
|
884
|
+
return rect;
|
|
885
|
+
}
|
|
886
|
+
return undefined;
|
|
887
|
+
}
|
|
888
|
+
static is(a) {
|
|
889
|
+
return typeof this.cast(a) != "undefined";
|
|
890
|
+
}
|
|
891
|
+
constructor(a, b, c, d) {
|
|
892
|
+
const vec = Vec2.is(a) ? Vec2.resolve(a) : undefined;
|
|
893
|
+
const size = Size.is(b) ? Size.resolve(b) : undefined;
|
|
894
|
+
const x = typeof a == "number" ? a : vec?.x;
|
|
895
|
+
if (!check_number(x))
|
|
896
|
+
throw new TypeError("expected number for x position");
|
|
897
|
+
const y = typeof b == "number" ? b : vec?.y;
|
|
898
|
+
if (!check_number(y))
|
|
899
|
+
throw new TypeError("expected number for y position");
|
|
900
|
+
const width = typeof c == "number" ? c : size?.width;
|
|
901
|
+
if (!check_number(width))
|
|
902
|
+
throw new TypeError("expected number for width");
|
|
903
|
+
const height = typeof d == "number" ? d : size?.height;
|
|
904
|
+
if (!check_number(height))
|
|
905
|
+
throw new TypeError("expected number for height");
|
|
906
|
+
this.position = new Vec2(x, y);
|
|
907
|
+
this.size = new Size(width, height);
|
|
908
|
+
}
|
|
909
|
+
toArray(w = false) {
|
|
910
|
+
return [...this.position.toArray(w), ...this.size.toArray()];
|
|
911
|
+
}
|
|
912
|
+
toString(w = false) {
|
|
913
|
+
return `${this.position.toString(w)}|${this.size.toString()}`;
|
|
914
|
+
}
|
|
915
|
+
toJSON() {
|
|
916
|
+
return { ...this.position.toJSON(), ...this.size.toJSON() };
|
|
917
|
+
}
|
|
918
|
+
toBoundingBox() {
|
|
919
|
+
return [this.x, this.x + this.width, this.y, this.y + this.height];
|
|
920
|
+
}
|
|
921
|
+
clone() {
|
|
922
|
+
return new Rectangle(this.position.clone(), this.size.clone());
|
|
923
|
+
}
|
|
924
|
+
equals(rectangle) {
|
|
925
|
+
const rect = Rectangle.resolve(rectangle);
|
|
926
|
+
return this.position.equals(rect.position) && this.size.equals(rect.size);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
class BoundingBox {
|
|
931
|
+
left;
|
|
932
|
+
right;
|
|
933
|
+
top;
|
|
934
|
+
bottom;
|
|
935
|
+
get width() {
|
|
936
|
+
return this.right - this.left;
|
|
937
|
+
}
|
|
938
|
+
set width(val) {
|
|
939
|
+
this.right = this.left + val;
|
|
940
|
+
}
|
|
941
|
+
get height() {
|
|
942
|
+
return this.bottom - this.top;
|
|
943
|
+
}
|
|
944
|
+
set height(val) {
|
|
945
|
+
this.bottom = this.top + val;
|
|
946
|
+
}
|
|
947
|
+
static resolve(a) {
|
|
948
|
+
const value = this.cast(a);
|
|
949
|
+
if (typeof value != "undefined")
|
|
950
|
+
return value;
|
|
951
|
+
throw new ResolveError("BoundingBox", a);
|
|
952
|
+
}
|
|
953
|
+
static cast(a) {
|
|
954
|
+
if (a == null || typeof a == "undefined")
|
|
955
|
+
return undefined;
|
|
956
|
+
if (check_number_array(a, 4))
|
|
957
|
+
return new this(a[0], a[1], a[2], a[3]);
|
|
958
|
+
if (has_property(a, "left", "number") && has_property(a, "right", "number") && has_property(a, "top", "number") && has_property(a, "bottom", "number"))
|
|
959
|
+
return new this(a.left, a.right, a.top, a.bottom);
|
|
960
|
+
if (check_string(a)) {
|
|
961
|
+
const parts = a.split(",");
|
|
962
|
+
if (check_string_array(parts, 4))
|
|
963
|
+
return this.cast(parts.map((v) => parseFloat(v)));
|
|
964
|
+
}
|
|
965
|
+
return undefined;
|
|
966
|
+
}
|
|
967
|
+
static is(a) {
|
|
968
|
+
return typeof this.cast(a) != "undefined";
|
|
969
|
+
}
|
|
970
|
+
constructor(left, right, top, bottom) {
|
|
971
|
+
if (!check_number(left))
|
|
972
|
+
throw new TypeError("expected number for left");
|
|
973
|
+
if (!check_number(right))
|
|
974
|
+
throw new TypeError("expected number for right");
|
|
975
|
+
if (!check_number(top))
|
|
976
|
+
throw new TypeError("expected number for top");
|
|
977
|
+
if (!check_number(bottom))
|
|
978
|
+
throw new TypeError("expected number for bottom");
|
|
979
|
+
this.left = left;
|
|
980
|
+
this.right = right;
|
|
981
|
+
this.top = top;
|
|
982
|
+
this.bottom = bottom;
|
|
983
|
+
}
|
|
984
|
+
toArray() {
|
|
985
|
+
return [this.left, this.right, this.top, this.bottom];
|
|
986
|
+
}
|
|
987
|
+
toString() {
|
|
988
|
+
return `${this.left},${this.right},${this.top},${this.bottom}`;
|
|
989
|
+
}
|
|
990
|
+
toJSON() {
|
|
991
|
+
return {
|
|
992
|
+
left: this.left,
|
|
993
|
+
top: this.top,
|
|
994
|
+
right: this.right,
|
|
995
|
+
bottom: this.bottom
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
clone() {
|
|
999
|
+
return new BoundingBox(this.left, this.right, this.top, this.bottom);
|
|
1000
|
+
}
|
|
1001
|
+
equals(bbox) {
|
|
1002
|
+
const b = BoundingBox.resolve(bbox);
|
|
1003
|
+
return this.left == b.left && this.right == b.right && this.top == b.top && this.bottom == b.bottom;
|
|
1004
|
+
}
|
|
1005
|
+
toSquare() {
|
|
1006
|
+
return new Size(this.width, this.height);
|
|
1007
|
+
}
|
|
1008
|
+
toRectangle() {
|
|
1009
|
+
return new Rectangle(this.left, this.top, this.width, this.height);
|
|
1010
|
+
}
|
|
1011
|
+
inside(a) {
|
|
1012
|
+
const bbox = BoundingBox.resolve(a);
|
|
1013
|
+
return this.right >= bbox.left && bbox.right >= this.left && this.bottom >= bbox.top && bbox.bottom >= this.top;
|
|
1014
|
+
}
|
|
1015
|
+
insidePoint(a) {
|
|
1016
|
+
const point = Vec2.resolve(a);
|
|
1017
|
+
return this.left <= point.x && this.right >= point.x && this.top >= point.y && this.bottom <= point.y;
|
|
1018
|
+
}
|
|
1019
|
+
insideCircle(a) {
|
|
1020
|
+
const circle = Circle.resolve(a);
|
|
1021
|
+
const center = Vec2.resolve(circle).add(circle.radius);
|
|
1022
|
+
const bboxhe = new Vec2(this.width / 2, this.height / 2);
|
|
1023
|
+
const bboxcenter = new Vec2(this.left + bboxhe.x, this.top + bboxhe.y);
|
|
1024
|
+
let diff = center.subtract(bboxcenter);
|
|
1025
|
+
const clamped = Vec2.clamp(diff, bboxhe.invert(), bboxhe);
|
|
1026
|
+
const closest = bboxcenter.add(clamped);
|
|
1027
|
+
diff = closest.subtract(center);
|
|
1028
|
+
return diff.length() < circle.radius;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
class ATriangle {
|
|
1033
|
+
constructor(A, B, C) {
|
|
1034
|
+
this.A = A;
|
|
1035
|
+
this.B = B;
|
|
1036
|
+
this.C = C;
|
|
1037
|
+
}
|
|
1038
|
+
get alpha() {
|
|
1039
|
+
return Math.acos((this.b * this.b + this.c * this.c - this.a * this.a) / (2 * this.b * this.c));
|
|
1040
|
+
}
|
|
1041
|
+
get beta() {
|
|
1042
|
+
return Math.acos((this.c * this.c + this.a * this.a - this.b * this.b) / (2 * this.c * this.a));
|
|
1043
|
+
}
|
|
1044
|
+
get gamma() {
|
|
1045
|
+
return Math.acos((this.a * this.a + this.b * this.b - this.c * this.c) / (2 * this.a * this.b));
|
|
1046
|
+
}
|
|
1047
|
+
get perimeter() {
|
|
1048
|
+
return this.a + this.b + this.c;
|
|
1049
|
+
}
|
|
1050
|
+
get semiperimeter() {
|
|
1051
|
+
return this.perimeter / 2;
|
|
1052
|
+
}
|
|
1053
|
+
get area() {
|
|
1054
|
+
return Math.sqrt(this.semiperimeter * (this.semiperimeter - this.a) * (this.semiperimeter - this.b) * (this.semiperimeter - this.c));
|
|
1055
|
+
}
|
|
1056
|
+
get base() {
|
|
1057
|
+
return 2 * (this.area / (this.a * Math.sin(this.gamma)));
|
|
1058
|
+
}
|
|
1059
|
+
get height() {
|
|
1060
|
+
return 2 * (this.area / this.base);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
class Triangle2D extends ATriangle {
|
|
1064
|
+
get a() {
|
|
1065
|
+
return Vec2.fromPoints(this.B, this.C).length();
|
|
1066
|
+
}
|
|
1067
|
+
get b() {
|
|
1068
|
+
return Vec2.fromPoints(this.A, this.C).length();
|
|
1069
|
+
}
|
|
1070
|
+
get c() {
|
|
1071
|
+
return Vec2.fromPoints(this.A, this.B).length();
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
class Triangle3D extends ATriangle {
|
|
1075
|
+
get a() {
|
|
1076
|
+
return Vec3.fromPoints(this.B, this.C).length();
|
|
1077
|
+
}
|
|
1078
|
+
get b() {
|
|
1079
|
+
return Vec3.fromPoints(this.A, this.C).length();
|
|
1080
|
+
}
|
|
1081
|
+
get c() {
|
|
1082
|
+
return Vec3.fromPoints(this.A, this.B).length();
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
class Mat3 {
|
|
1087
|
+
_raw;
|
|
1088
|
+
get m00() {
|
|
1089
|
+
return this._raw[0];
|
|
1090
|
+
}
|
|
1091
|
+
set m00(val) {
|
|
1092
|
+
this._raw[0] = val;
|
|
1093
|
+
}
|
|
1094
|
+
get m01() {
|
|
1095
|
+
return this._raw[1];
|
|
1096
|
+
}
|
|
1097
|
+
set m01(val) {
|
|
1098
|
+
this._raw[1] = val;
|
|
1099
|
+
}
|
|
1100
|
+
get m02() {
|
|
1101
|
+
return this._raw[2];
|
|
1102
|
+
}
|
|
1103
|
+
set m02(val) {
|
|
1104
|
+
this._raw[2] = val;
|
|
1105
|
+
}
|
|
1106
|
+
get m10() {
|
|
1107
|
+
return this._raw[3];
|
|
1108
|
+
}
|
|
1109
|
+
set m10(val) {
|
|
1110
|
+
this._raw[3] = val;
|
|
1111
|
+
}
|
|
1112
|
+
get m11() {
|
|
1113
|
+
return this._raw[4];
|
|
1114
|
+
}
|
|
1115
|
+
set m11(val) {
|
|
1116
|
+
this._raw[4] = val;
|
|
1117
|
+
}
|
|
1118
|
+
get m12() {
|
|
1119
|
+
return this._raw[5];
|
|
1120
|
+
}
|
|
1121
|
+
set m12(val) {
|
|
1122
|
+
this._raw[5] = val;
|
|
1123
|
+
}
|
|
1124
|
+
get m20() {
|
|
1125
|
+
return this._raw[6];
|
|
1126
|
+
}
|
|
1127
|
+
set m20(val) {
|
|
1128
|
+
this._raw[6] = val;
|
|
1129
|
+
}
|
|
1130
|
+
get m21() {
|
|
1131
|
+
return this._raw[7];
|
|
1132
|
+
}
|
|
1133
|
+
set m21(val) {
|
|
1134
|
+
this._raw[7] = val;
|
|
1135
|
+
}
|
|
1136
|
+
get m22() {
|
|
1137
|
+
return this._raw[8];
|
|
1138
|
+
}
|
|
1139
|
+
set m22(val) {
|
|
1140
|
+
this._raw[8] = val;
|
|
1141
|
+
}
|
|
1142
|
+
static resolve(a) {
|
|
1143
|
+
const value = this.cast(a);
|
|
1144
|
+
if (typeof value != "undefined")
|
|
1145
|
+
return value;
|
|
1146
|
+
throw new ResolveError("Mat3", a);
|
|
1147
|
+
}
|
|
1148
|
+
static cast(a) {
|
|
1149
|
+
if (a == null || typeof a == "undefined")
|
|
1150
|
+
return undefined;
|
|
1151
|
+
if (check_number_array(a, 9)) {
|
|
1152
|
+
return new this(a);
|
|
1153
|
+
}
|
|
1154
|
+
if (check_array(a, undefined, 3)) {
|
|
1155
|
+
const row0 = a[0], row1 = a[1], row2 = a[2];
|
|
1156
|
+
if (check_number_array(row0, 3) && check_number_array(row1, 3) && check_number_array(row2, 3))
|
|
1157
|
+
return new this([
|
|
1158
|
+
row0[0],
|
|
1159
|
+
row0[1],
|
|
1160
|
+
row0[2],
|
|
1161
|
+
row1[0],
|
|
1162
|
+
row1[1],
|
|
1163
|
+
row1[2],
|
|
1164
|
+
row2[0],
|
|
1165
|
+
row2[1],
|
|
1166
|
+
row2[2]
|
|
1167
|
+
]);
|
|
1168
|
+
}
|
|
1169
|
+
if (check_string(a)) {
|
|
1170
|
+
const parts = a.split(",");
|
|
1171
|
+
if (check_string_array(parts, 9))
|
|
1172
|
+
return this.cast(parts.map((i) => parseFloat(i)));
|
|
1173
|
+
}
|
|
1174
|
+
if (has_property(a, "m00", "number") && has_property(a, "m01", "number") && has_property(a, "m02", "number") && has_property(a, "m10", "number") && has_property(a, "m11", "number") && has_property(a, "m12", "number") && has_property(a, "m20", "number") && has_property(a, "m21", "number") && has_property(a, "m22", "number"))
|
|
1175
|
+
return new this([
|
|
1176
|
+
a.m00,
|
|
1177
|
+
a.m01,
|
|
1178
|
+
a.m02,
|
|
1179
|
+
a.m10,
|
|
1180
|
+
a.m11,
|
|
1181
|
+
a.m12,
|
|
1182
|
+
a.m20,
|
|
1183
|
+
a.m21,
|
|
1184
|
+
a.m22
|
|
1185
|
+
]);
|
|
1186
|
+
if (check_number(a)) {
|
|
1187
|
+
return new this([a, a, a, a, a, a, a, a, a]);
|
|
1188
|
+
}
|
|
1189
|
+
return undefined;
|
|
1190
|
+
}
|
|
1191
|
+
static is(a) {
|
|
1192
|
+
return typeof this.cast(a) != "undefined";
|
|
1193
|
+
}
|
|
1194
|
+
static projection(width, height) {
|
|
1195
|
+
return new this([
|
|
1196
|
+
2 / width,
|
|
1197
|
+
0,
|
|
1198
|
+
0,
|
|
1199
|
+
0,
|
|
1200
|
+
-2 / height,
|
|
1201
|
+
0,
|
|
1202
|
+
-1,
|
|
1203
|
+
1,
|
|
1204
|
+
1
|
|
1205
|
+
]);
|
|
1206
|
+
}
|
|
1207
|
+
constructor(init = [1, 0, 0, 0, 1, 0, 0, 0, 1]) {
|
|
1208
|
+
if (!check_number_array(init, 9))
|
|
1209
|
+
throw new TypeError("expected a number array with 9 elements");
|
|
1210
|
+
this._raw = init;
|
|
1211
|
+
}
|
|
1212
|
+
toArray() {
|
|
1213
|
+
return [
|
|
1214
|
+
this.m00,
|
|
1215
|
+
this.m01,
|
|
1216
|
+
this.m02,
|
|
1217
|
+
this.m10,
|
|
1218
|
+
this.m11,
|
|
1219
|
+
this.m12,
|
|
1220
|
+
this.m20,
|
|
1221
|
+
this.m21,
|
|
1222
|
+
this.m22
|
|
1223
|
+
];
|
|
1224
|
+
}
|
|
1225
|
+
toNestetArray() {
|
|
1226
|
+
return [
|
|
1227
|
+
[this.m00, this.m01, this.m02],
|
|
1228
|
+
[this.m10, this.m11, this.m12],
|
|
1229
|
+
[this.m20, this.m21, this.m22]
|
|
1230
|
+
];
|
|
1231
|
+
}
|
|
1232
|
+
toJSON() {
|
|
1233
|
+
return {
|
|
1234
|
+
m00: this.m00,
|
|
1235
|
+
m01: this.m01,
|
|
1236
|
+
m02: this.m02,
|
|
1237
|
+
m10: this.m10,
|
|
1238
|
+
m11: this.m11,
|
|
1239
|
+
m12: this.m12,
|
|
1240
|
+
m20: this.m20,
|
|
1241
|
+
m21: this.m21,
|
|
1242
|
+
m22: this.m22
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
toString() {
|
|
1246
|
+
return `${this.m00},${this.m01},${this.m02},${this.m10},${this.m11},${this.m12},${this.m20},${this.m21},${this.m22}`;
|
|
1247
|
+
}
|
|
1248
|
+
clone() {
|
|
1249
|
+
return new Mat3([
|
|
1250
|
+
this.m00,
|
|
1251
|
+
this.m01,
|
|
1252
|
+
this.m02,
|
|
1253
|
+
this.m10,
|
|
1254
|
+
this.m11,
|
|
1255
|
+
this.m12,
|
|
1256
|
+
this.m20,
|
|
1257
|
+
this.m21,
|
|
1258
|
+
this.m22
|
|
1259
|
+
]);
|
|
1260
|
+
}
|
|
1261
|
+
equals(mat) {
|
|
1262
|
+
const m = Mat3.resolve(mat);
|
|
1263
|
+
for (let index = 0; index < this._raw.length; index++)
|
|
1264
|
+
if (this._raw[index] != m._raw[index])
|
|
1265
|
+
return false;
|
|
1266
|
+
return true;
|
|
1267
|
+
}
|
|
1268
|
+
add(mat) {
|
|
1269
|
+
const b = Mat3.resolve(mat);
|
|
1270
|
+
const m = new Mat3();
|
|
1271
|
+
for (let index = 0; index < this._raw.length; index++)
|
|
1272
|
+
m._raw[index] = this._raw[index] + b._raw[index];
|
|
1273
|
+
return this;
|
|
1274
|
+
}
|
|
1275
|
+
subtract(mat) {
|
|
1276
|
+
const b = Mat3.resolve(mat);
|
|
1277
|
+
const m = new Mat3();
|
|
1278
|
+
for (let index = 0; index < this._raw.length; index++)
|
|
1279
|
+
m._raw[index] = this._raw[index] - b._raw[index];
|
|
1280
|
+
return this;
|
|
1281
|
+
}
|
|
1282
|
+
multiply(a) {
|
|
1283
|
+
if (check_number(a))
|
|
1284
|
+
return new Mat3([
|
|
1285
|
+
this.m00 * a,
|
|
1286
|
+
this.m01 * a,
|
|
1287
|
+
this.m02 * a,
|
|
1288
|
+
this.m10 * a,
|
|
1289
|
+
this.m11 * a,
|
|
1290
|
+
this.m12 * a,
|
|
1291
|
+
this.m20 * a,
|
|
1292
|
+
this.m21 * a,
|
|
1293
|
+
this.m22 * a
|
|
1294
|
+
]);
|
|
1295
|
+
const b = Mat3.resolve(a);
|
|
1296
|
+
return new Mat3([
|
|
1297
|
+
b.m00 * this.m00 + b.m01 * this.m10 + b.m02 * this.m20,
|
|
1298
|
+
b.m00 * this.m01 + b.m01 * this.m11 + b.m02 * this.m21,
|
|
1299
|
+
b.m00 * this.m02 + b.m01 * this.m12 + b.m02 * this.m22,
|
|
1300
|
+
b.m10 * this.m00 + b.m11 * this.m10 + b.m12 * this.m20,
|
|
1301
|
+
b.m10 * this.m01 + b.m11 * this.m11 + b.m12 * this.m21,
|
|
1302
|
+
b.m10 * this.m02 + b.m11 * this.m12 + b.m12 * this.m22,
|
|
1303
|
+
b.m20 * this.m00 + b.m21 * this.m10 + b.m22 * this.m20,
|
|
1304
|
+
b.m20 * this.m01 + b.m21 * this.m11 + b.m22 * this.m21,
|
|
1305
|
+
b.m20 * this.m02 + b.m21 * this.m12 + b.m22 * this.m22
|
|
1306
|
+
]);
|
|
1307
|
+
}
|
|
1308
|
+
translate(...args) {
|
|
1309
|
+
const vec = Vec2.resolveArgs(args);
|
|
1310
|
+
return this.multiply([
|
|
1311
|
+
1,
|
|
1312
|
+
0,
|
|
1313
|
+
0,
|
|
1314
|
+
0,
|
|
1315
|
+
1,
|
|
1316
|
+
0,
|
|
1317
|
+
vec.x,
|
|
1318
|
+
vec.y,
|
|
1319
|
+
1
|
|
1320
|
+
]);
|
|
1321
|
+
}
|
|
1322
|
+
rotate(angle) {
|
|
1323
|
+
const c = Math.cos(angle);
|
|
1324
|
+
const s = Math.sin(angle);
|
|
1325
|
+
return this.multiply([
|
|
1326
|
+
c,
|
|
1327
|
+
-s,
|
|
1328
|
+
0,
|
|
1329
|
+
s,
|
|
1330
|
+
c,
|
|
1331
|
+
0,
|
|
1332
|
+
0,
|
|
1333
|
+
0,
|
|
1334
|
+
1
|
|
1335
|
+
]);
|
|
1336
|
+
}
|
|
1337
|
+
scale(...args) {
|
|
1338
|
+
const vec = Vec2.resolve(args);
|
|
1339
|
+
return this.multiply([
|
|
1340
|
+
vec.x,
|
|
1341
|
+
0,
|
|
1342
|
+
0,
|
|
1343
|
+
0,
|
|
1344
|
+
vec.y,
|
|
1345
|
+
0,
|
|
1346
|
+
0,
|
|
1347
|
+
0,
|
|
1348
|
+
1
|
|
1349
|
+
]);
|
|
1350
|
+
}
|
|
1351
|
+
determinant() {
|
|
1352
|
+
return this.m00 * this.m11 * this.m22 - this.m21 * this.m12 - this.m01 * this.m10 * this.m22 - this.m12 * this.m20 + this.m02 * this.m10 * this.m21 - this.m11 * this.m20;
|
|
1353
|
+
}
|
|
1354
|
+
inverse() {
|
|
1355
|
+
const det = this.determinant();
|
|
1356
|
+
return new Mat3([
|
|
1357
|
+
(this.m11 * this.m22 - this.m21 * this.m12) * det,
|
|
1358
|
+
(this.m02 * this.m21 - this.m01 * this.m22) * det,
|
|
1359
|
+
(this.m01 * this.m12 - this.m02 * this.m11) * det,
|
|
1360
|
+
(this.m12 * this.m20 - this.m10 * this.m22) * det,
|
|
1361
|
+
(this.m00 * this.m22 - this.m02 * this.m20) * det,
|
|
1362
|
+
(this.m10 * this.m02 - this.m00 * this.m12) * det,
|
|
1363
|
+
(this.m10 * this.m21 - this.m20 * this.m11) * det,
|
|
1364
|
+
(this.m20 * this.m01 - this.m00 * this.m21) * det,
|
|
1365
|
+
(this.m00 * this.m11 - this.m10 * this.m01) * det
|
|
1366
|
+
]);
|
|
1367
|
+
}
|
|
1368
|
+
toMat4() {
|
|
1369
|
+
return [
|
|
1370
|
+
this.m00,
|
|
1371
|
+
this.m01,
|
|
1372
|
+
this.m02,
|
|
1373
|
+
0,
|
|
1374
|
+
this.m10,
|
|
1375
|
+
this.m11,
|
|
1376
|
+
this.m12,
|
|
1377
|
+
0,
|
|
1378
|
+
this.m20,
|
|
1379
|
+
this.m20,
|
|
1380
|
+
this.m22,
|
|
1381
|
+
0,
|
|
1382
|
+
0,
|
|
1383
|
+
0,
|
|
1384
|
+
0,
|
|
1385
|
+
1
|
|
1386
|
+
];
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
class Mat4 {
|
|
1391
|
+
_raw;
|
|
1392
|
+
get m00() {
|
|
1393
|
+
return this._raw[0];
|
|
1394
|
+
}
|
|
1395
|
+
set m00(val) {
|
|
1396
|
+
this._raw[0] = val;
|
|
1397
|
+
}
|
|
1398
|
+
get m01() {
|
|
1399
|
+
return this._raw[1];
|
|
1400
|
+
}
|
|
1401
|
+
set m01(val) {
|
|
1402
|
+
this._raw[1] = val;
|
|
1403
|
+
}
|
|
1404
|
+
get m02() {
|
|
1405
|
+
return this._raw[2];
|
|
1406
|
+
}
|
|
1407
|
+
set m02(val) {
|
|
1408
|
+
this._raw[2] = val;
|
|
1409
|
+
}
|
|
1410
|
+
get m03() {
|
|
1411
|
+
return this._raw[3];
|
|
1412
|
+
}
|
|
1413
|
+
set m03(val) {
|
|
1414
|
+
this._raw[3] = val;
|
|
1415
|
+
}
|
|
1416
|
+
get m10() {
|
|
1417
|
+
return this._raw[4];
|
|
1418
|
+
}
|
|
1419
|
+
set m10(val) {
|
|
1420
|
+
this._raw[4] = val;
|
|
1421
|
+
}
|
|
1422
|
+
get m11() {
|
|
1423
|
+
return this._raw[5];
|
|
1424
|
+
}
|
|
1425
|
+
set m11(val) {
|
|
1426
|
+
this._raw[5] = val;
|
|
1427
|
+
}
|
|
1428
|
+
get m12() {
|
|
1429
|
+
return this._raw[6];
|
|
1430
|
+
}
|
|
1431
|
+
set m12(val) {
|
|
1432
|
+
this._raw[6] = val;
|
|
1433
|
+
}
|
|
1434
|
+
get m13() {
|
|
1435
|
+
return this._raw[7];
|
|
1436
|
+
}
|
|
1437
|
+
set m13(val) {
|
|
1438
|
+
this._raw[7] = val;
|
|
1439
|
+
}
|
|
1440
|
+
get m20() {
|
|
1441
|
+
return this._raw[8];
|
|
1442
|
+
}
|
|
1443
|
+
set m20(val) {
|
|
1444
|
+
this._raw[8] = val;
|
|
1445
|
+
}
|
|
1446
|
+
get m21() {
|
|
1447
|
+
return this._raw[9];
|
|
1448
|
+
}
|
|
1449
|
+
set m21(val) {
|
|
1450
|
+
this._raw[9] = val;
|
|
1451
|
+
}
|
|
1452
|
+
get m22() {
|
|
1453
|
+
return this._raw[10];
|
|
1454
|
+
}
|
|
1455
|
+
set m22(val) {
|
|
1456
|
+
this._raw[10] = val;
|
|
1457
|
+
}
|
|
1458
|
+
get m23() {
|
|
1459
|
+
return this._raw[11];
|
|
1460
|
+
}
|
|
1461
|
+
set m23(val) {
|
|
1462
|
+
this._raw[11] = val;
|
|
1463
|
+
}
|
|
1464
|
+
get m30() {
|
|
1465
|
+
return this._raw[12];
|
|
1466
|
+
}
|
|
1467
|
+
set m30(val) {
|
|
1468
|
+
this._raw[12] = val;
|
|
1469
|
+
}
|
|
1470
|
+
get m31() {
|
|
1471
|
+
return this._raw[13];
|
|
1472
|
+
}
|
|
1473
|
+
set m31(val) {
|
|
1474
|
+
this._raw[13] = val;
|
|
1475
|
+
}
|
|
1476
|
+
get m32() {
|
|
1477
|
+
return this._raw[14];
|
|
1478
|
+
}
|
|
1479
|
+
set m32(val) {
|
|
1480
|
+
this._raw[14] = val;
|
|
1481
|
+
}
|
|
1482
|
+
get m33() {
|
|
1483
|
+
return this._raw[15];
|
|
1484
|
+
}
|
|
1485
|
+
set m33(val) {
|
|
1486
|
+
this._raw[15] = val;
|
|
1487
|
+
}
|
|
1488
|
+
static resolve(a) {
|
|
1489
|
+
const value = this.cast(a);
|
|
1490
|
+
if (typeof value != "undefined")
|
|
1491
|
+
return value;
|
|
1492
|
+
throw new ResolveError("Mat4", a);
|
|
1493
|
+
}
|
|
1494
|
+
static cast(a) {
|
|
1495
|
+
if (a == null || typeof a == "undefined")
|
|
1496
|
+
return undefined;
|
|
1497
|
+
if (check_number_array(a, 16)) {
|
|
1498
|
+
return new this(a);
|
|
1499
|
+
}
|
|
1500
|
+
if (check_array(a, undefined, 4)) {
|
|
1501
|
+
const row0 = a[0], row1 = a[1], row2 = a[2], row3 = a[3];
|
|
1502
|
+
if (check_number_array(row0, 4) && check_number_array(row1, 4) && check_number_array(row2, 4) && check_number_array(row3, 4))
|
|
1503
|
+
return new this([
|
|
1504
|
+
row0[0],
|
|
1505
|
+
row0[1],
|
|
1506
|
+
row0[2],
|
|
1507
|
+
row0[3],
|
|
1508
|
+
row1[0],
|
|
1509
|
+
row1[1],
|
|
1510
|
+
row1[2],
|
|
1511
|
+
row1[3],
|
|
1512
|
+
row2[0],
|
|
1513
|
+
row2[1],
|
|
1514
|
+
row2[2],
|
|
1515
|
+
row2[3],
|
|
1516
|
+
row3[0],
|
|
1517
|
+
row3[1],
|
|
1518
|
+
row3[2],
|
|
1519
|
+
row3[3]
|
|
1520
|
+
]);
|
|
1521
|
+
}
|
|
1522
|
+
if (check_string(a)) {
|
|
1523
|
+
const parts = a.split(",");
|
|
1524
|
+
if (check_string_array(parts, 16))
|
|
1525
|
+
return this.cast(parts.map((i) => parseFloat(i)));
|
|
1526
|
+
}
|
|
1527
|
+
if (has_property(a, "m00", "number") && has_property(a, "m01", "number") && has_property(a, "m02", "number") && has_property(a, "m03", "number") && has_property(a, "m10", "number") && has_property(a, "m11", "number") && has_property(a, "m12", "number") && has_property(a, "m13", "number") && has_property(a, "m20", "number") && has_property(a, "m21", "number") && has_property(a, "m22", "number") && has_property(a, "m23", "number") && has_property(a, "m30", "number") && has_property(a, "m31", "number") && has_property(a, "m32", "number") && has_property(a, "m33", "number"))
|
|
1528
|
+
return new this([
|
|
1529
|
+
a.m00,
|
|
1530
|
+
a.m01,
|
|
1531
|
+
a.m02,
|
|
1532
|
+
a.m03,
|
|
1533
|
+
a.m10,
|
|
1534
|
+
a.m11,
|
|
1535
|
+
a.m12,
|
|
1536
|
+
a.m13,
|
|
1537
|
+
a.m20,
|
|
1538
|
+
a.m21,
|
|
1539
|
+
a.m22,
|
|
1540
|
+
a.m23,
|
|
1541
|
+
a.m30,
|
|
1542
|
+
a.m31,
|
|
1543
|
+
a.m32,
|
|
1544
|
+
a.m33
|
|
1545
|
+
]);
|
|
1546
|
+
if (check_number(a)) {
|
|
1547
|
+
return new this([a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a]);
|
|
1548
|
+
}
|
|
1549
|
+
return undefined;
|
|
1550
|
+
}
|
|
1551
|
+
static is(a) {
|
|
1552
|
+
return typeof this.cast(a) != "undefined";
|
|
1553
|
+
}
|
|
1554
|
+
static orthographic(left, right, bottom, top, near, far) {
|
|
1555
|
+
return new this([
|
|
1556
|
+
2 / (right - left),
|
|
1557
|
+
0,
|
|
1558
|
+
0,
|
|
1559
|
+
0,
|
|
1560
|
+
0,
|
|
1561
|
+
2 / (top - bottom),
|
|
1562
|
+
0,
|
|
1563
|
+
0,
|
|
1564
|
+
0,
|
|
1565
|
+
0,
|
|
1566
|
+
2 / (near - far),
|
|
1567
|
+
0,
|
|
1568
|
+
(left + right) / (left - right),
|
|
1569
|
+
(bottom + top) / (bottom - top),
|
|
1570
|
+
(near + far) / (near - far),
|
|
1571
|
+
1
|
|
1572
|
+
]);
|
|
1573
|
+
}
|
|
1574
|
+
static perspective(fov, aspect, near, far) {
|
|
1575
|
+
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
|
|
1576
|
+
const rangeInv = 1 / (near - far);
|
|
1577
|
+
return new this([
|
|
1578
|
+
f / aspect,
|
|
1579
|
+
0,
|
|
1580
|
+
0,
|
|
1581
|
+
0,
|
|
1582
|
+
0,
|
|
1583
|
+
f,
|
|
1584
|
+
0,
|
|
1585
|
+
0,
|
|
1586
|
+
0,
|
|
1587
|
+
0,
|
|
1588
|
+
(near + far) * rangeInv,
|
|
1589
|
+
-1,
|
|
1590
|
+
0,
|
|
1591
|
+
0,
|
|
1592
|
+
near * far * rangeInv * 2,
|
|
1593
|
+
0
|
|
1594
|
+
]);
|
|
1595
|
+
}
|
|
1596
|
+
static pointAt(position, target, up) {
|
|
1597
|
+
const newForward = Vec3.resolve(target).subtract(position).normalize();
|
|
1598
|
+
const a = newForward.multiply(Vec3.resolve(up).dot(newForward));
|
|
1599
|
+
const newUp = Vec3.resolve(up).subtract(a).normalize();
|
|
1600
|
+
const newRight = newUp.cross(newForward);
|
|
1601
|
+
const pos = Vec3.resolve(position);
|
|
1602
|
+
return new this([
|
|
1603
|
+
newRight.x,
|
|
1604
|
+
newRight.y,
|
|
1605
|
+
newRight.z,
|
|
1606
|
+
0,
|
|
1607
|
+
newUp.x,
|
|
1608
|
+
newUp.y,
|
|
1609
|
+
newUp.z,
|
|
1610
|
+
0,
|
|
1611
|
+
newForward.x,
|
|
1612
|
+
newForward.y,
|
|
1613
|
+
newForward.z,
|
|
1614
|
+
0,
|
|
1615
|
+
pos.x,
|
|
1616
|
+
pos.y,
|
|
1617
|
+
pos.z,
|
|
1618
|
+
1
|
|
1619
|
+
]);
|
|
1620
|
+
}
|
|
1621
|
+
constructor(init = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) {
|
|
1622
|
+
if (!check_number_array(init, 16))
|
|
1623
|
+
throw new TypeError("expected a number array with 16 elements");
|
|
1624
|
+
this._raw = init;
|
|
1625
|
+
}
|
|
1626
|
+
toArray() {
|
|
1627
|
+
return [
|
|
1628
|
+
this.m00,
|
|
1629
|
+
this.m01,
|
|
1630
|
+
this.m02,
|
|
1631
|
+
this.m03,
|
|
1632
|
+
this.m10,
|
|
1633
|
+
this.m11,
|
|
1634
|
+
this.m12,
|
|
1635
|
+
this.m13,
|
|
1636
|
+
this.m20,
|
|
1637
|
+
this.m21,
|
|
1638
|
+
this.m22,
|
|
1639
|
+
this.m23,
|
|
1640
|
+
this.m30,
|
|
1641
|
+
this.m31,
|
|
1642
|
+
this.m32,
|
|
1643
|
+
this.m33
|
|
1644
|
+
];
|
|
1645
|
+
}
|
|
1646
|
+
toNestetArray() {
|
|
1647
|
+
return [
|
|
1648
|
+
[this.m00, this.m01, this.m02, this.m03],
|
|
1649
|
+
[this.m10, this.m11, this.m12, this.m13],
|
|
1650
|
+
[this.m20, this.m21, this.m22, this.m23],
|
|
1651
|
+
[this.m30, this.m31, this.m32, this.m33]
|
|
1652
|
+
];
|
|
1653
|
+
}
|
|
1654
|
+
toJSON() {
|
|
1655
|
+
return {
|
|
1656
|
+
m00: this.m00,
|
|
1657
|
+
m01: this.m01,
|
|
1658
|
+
m02: this.m02,
|
|
1659
|
+
m03: this.m03,
|
|
1660
|
+
m10: this.m10,
|
|
1661
|
+
m11: this.m11,
|
|
1662
|
+
m12: this.m12,
|
|
1663
|
+
m13: this.m13,
|
|
1664
|
+
m20: this.m20,
|
|
1665
|
+
m21: this.m21,
|
|
1666
|
+
m22: this.m22,
|
|
1667
|
+
m23: this.m23,
|
|
1668
|
+
m30: this.m20,
|
|
1669
|
+
m31: this.m21,
|
|
1670
|
+
m32: this.m22,
|
|
1671
|
+
m33: this.m23
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
toString() {
|
|
1675
|
+
return `${this.m00},${this.m01},${this.m02},${this.m03},${this.m10},${this.m11},${this.m12},${this.m13},${this.m20},${this.m21},${this.m22},${this.m23},${this.m30},${this.m31},${this.m32},${this.m33}`;
|
|
1676
|
+
}
|
|
1677
|
+
clone() {
|
|
1678
|
+
return new Mat4([
|
|
1679
|
+
this.m00,
|
|
1680
|
+
this.m01,
|
|
1681
|
+
this.m02,
|
|
1682
|
+
this.m03,
|
|
1683
|
+
this.m10,
|
|
1684
|
+
this.m11,
|
|
1685
|
+
this.m12,
|
|
1686
|
+
this.m13,
|
|
1687
|
+
this.m20,
|
|
1688
|
+
this.m21,
|
|
1689
|
+
this.m22,
|
|
1690
|
+
this.m23,
|
|
1691
|
+
this.m30,
|
|
1692
|
+
this.m31,
|
|
1693
|
+
this.m32,
|
|
1694
|
+
this.m33
|
|
1695
|
+
]);
|
|
1696
|
+
}
|
|
1697
|
+
equals(mat) {
|
|
1698
|
+
const m = Mat4.resolve(mat);
|
|
1699
|
+
for (let index = 0; index < this._raw.length; index++)
|
|
1700
|
+
if (this._raw[index] != m._raw[index])
|
|
1701
|
+
return false;
|
|
1702
|
+
return true;
|
|
1703
|
+
}
|
|
1704
|
+
add(mat) {
|
|
1705
|
+
const b = Mat4.resolve(mat);
|
|
1706
|
+
const m = new Mat4();
|
|
1707
|
+
for (let index = 0; index < this._raw.length; index++)
|
|
1708
|
+
m._raw[index] = this._raw[index] + b._raw[index];
|
|
1709
|
+
return m;
|
|
1710
|
+
}
|
|
1711
|
+
subtract(mat) {
|
|
1712
|
+
const b = Mat4.resolve(mat);
|
|
1713
|
+
const m = new Mat4();
|
|
1714
|
+
for (let index = 0; index < this._raw.length; index++)
|
|
1715
|
+
m._raw[index] = this._raw[index] - b._raw[index];
|
|
1716
|
+
return m;
|
|
1717
|
+
}
|
|
1718
|
+
multiply(a) {
|
|
1719
|
+
if (check_number(a)) {
|
|
1720
|
+
return new Mat4([
|
|
1721
|
+
this.m00 * a,
|
|
1722
|
+
this.m01 * a,
|
|
1723
|
+
this.m02 * a,
|
|
1724
|
+
this.m03 * a,
|
|
1725
|
+
this.m10 * a,
|
|
1726
|
+
this.m11 * a,
|
|
1727
|
+
this.m12 * a,
|
|
1728
|
+
this.m13 * a,
|
|
1729
|
+
this.m20 * a,
|
|
1730
|
+
this.m21 * a,
|
|
1731
|
+
this.m22 * a,
|
|
1732
|
+
this.m23 * a,
|
|
1733
|
+
this.m30 * a,
|
|
1734
|
+
this.m31 * a,
|
|
1735
|
+
this.m32 * a,
|
|
1736
|
+
this.m33 * a
|
|
1737
|
+
]);
|
|
1738
|
+
}
|
|
1739
|
+
if (Mat4.is(a)) {
|
|
1740
|
+
const b = Mat4.resolve(a);
|
|
1741
|
+
return new Mat4([
|
|
1742
|
+
b.m00 * this.m00 + b.m01 * this.m10 + b.m02 * this.m20 + b.m03 * this.m30,
|
|
1743
|
+
b.m00 * this.m01 + b.m01 * this.m11 + b.m02 * this.m21 + b.m03 * this.m31,
|
|
1744
|
+
b.m00 * this.m02 + b.m01 * this.m12 + b.m02 * this.m22 + b.m03 * this.m32,
|
|
1745
|
+
b.m00 * this.m03 + b.m01 * this.m13 + b.m02 * this.m23 + b.m03 * this.m33,
|
|
1746
|
+
b.m10 * this.m00 + b.m11 * this.m10 + b.m12 * this.m20 + b.m13 * this.m30,
|
|
1747
|
+
b.m10 * this.m01 + b.m11 * this.m11 + b.m12 * this.m21 + b.m13 * this.m31,
|
|
1748
|
+
b.m10 * this.m02 + b.m11 * this.m12 + b.m12 * this.m22 + b.m13 * this.m32,
|
|
1749
|
+
b.m10 * this.m03 + b.m11 * this.m13 + b.m12 * this.m23 + b.m13 * this.m33,
|
|
1750
|
+
b.m20 * this.m00 + b.m21 * this.m10 + b.m22 * this.m20 + b.m23 * this.m30,
|
|
1751
|
+
b.m20 * this.m01 + b.m21 * this.m11 + b.m22 * this.m21 + b.m23 * this.m31,
|
|
1752
|
+
b.m20 * this.m02 + b.m21 * this.m12 + b.m22 * this.m22 + b.m23 * this.m32,
|
|
1753
|
+
b.m20 * this.m03 + b.m21 * this.m13 + b.m22 * this.m23 + b.m23 * this.m33,
|
|
1754
|
+
b.m30 * this.m00 + b.m31 * this.m10 + b.m32 * this.m20 + b.m33 * this.m30,
|
|
1755
|
+
b.m30 * this.m01 + b.m31 * this.m11 + b.m32 * this.m21 + b.m33 * this.m31,
|
|
1756
|
+
b.m30 * this.m02 + b.m31 * this.m12 + b.m32 * this.m22 + b.m33 * this.m32,
|
|
1757
|
+
b.m30 * this.m03 + b.m31 * this.m13 + b.m32 * this.m23 + b.m33 * this.m33
|
|
1758
|
+
]);
|
|
1759
|
+
}
|
|
1760
|
+
if (Vec3.is(a)) {
|
|
1761
|
+
const b = Vec3.resolve(a);
|
|
1762
|
+
const vec = new Vec3(
|
|
1763
|
+
b.x * this.m00 + b.y * this.m10 + b.z * this.m20 + this.m30,
|
|
1764
|
+
b.x * this.m01 + b.y * this.m11 + b.z * this.m21 + this.m31,
|
|
1765
|
+
b.x * this.m02 + b.y * this.m12 + b.z * this.m22 + this.m32,
|
|
1766
|
+
b.x * this.m03 + b.y * this.m13 + b.z * this.m23 + this.m33
|
|
1767
|
+
);
|
|
1768
|
+
if (vec.w != 0)
|
|
1769
|
+
return vec.divide(vec.w);
|
|
1770
|
+
return vec;
|
|
1771
|
+
}
|
|
1772
|
+
throw new ResolveError("Mat4 or Vec3 or number", a);
|
|
1773
|
+
}
|
|
1774
|
+
translate(...args) {
|
|
1775
|
+
const vec = Vec3.resolveArgs(args);
|
|
1776
|
+
return this.multiply([
|
|
1777
|
+
1,
|
|
1778
|
+
0,
|
|
1779
|
+
0,
|
|
1780
|
+
0,
|
|
1781
|
+
0,
|
|
1782
|
+
1,
|
|
1783
|
+
0,
|
|
1784
|
+
0,
|
|
1785
|
+
0,
|
|
1786
|
+
0,
|
|
1787
|
+
1,
|
|
1788
|
+
0,
|
|
1789
|
+
vec.x,
|
|
1790
|
+
vec.y,
|
|
1791
|
+
vec.z,
|
|
1792
|
+
1
|
|
1793
|
+
]);
|
|
1794
|
+
}
|
|
1795
|
+
rotateX(angle) {
|
|
1796
|
+
const c = Math.cos(angle);
|
|
1797
|
+
const s = Math.sin(angle);
|
|
1798
|
+
return this.multiply([
|
|
1799
|
+
1,
|
|
1800
|
+
0,
|
|
1801
|
+
0,
|
|
1802
|
+
0,
|
|
1803
|
+
0,
|
|
1804
|
+
c,
|
|
1805
|
+
s,
|
|
1806
|
+
0,
|
|
1807
|
+
0,
|
|
1808
|
+
-s,
|
|
1809
|
+
c,
|
|
1810
|
+
0,
|
|
1811
|
+
0,
|
|
1812
|
+
0,
|
|
1813
|
+
0,
|
|
1814
|
+
1
|
|
1815
|
+
]);
|
|
1816
|
+
}
|
|
1817
|
+
rotateY(angle) {
|
|
1818
|
+
const c = Math.cos(angle);
|
|
1819
|
+
const s = Math.sin(angle);
|
|
1820
|
+
return this.multiply([
|
|
1821
|
+
c,
|
|
1822
|
+
0,
|
|
1823
|
+
-s,
|
|
1824
|
+
0,
|
|
1825
|
+
0,
|
|
1826
|
+
1,
|
|
1827
|
+
0,
|
|
1828
|
+
0,
|
|
1829
|
+
s,
|
|
1830
|
+
0,
|
|
1831
|
+
c,
|
|
1832
|
+
0,
|
|
1833
|
+
0,
|
|
1834
|
+
0,
|
|
1835
|
+
0,
|
|
1836
|
+
1
|
|
1837
|
+
]);
|
|
1838
|
+
}
|
|
1839
|
+
rotateZ(angle) {
|
|
1840
|
+
const c = Math.cos(angle);
|
|
1841
|
+
const s = Math.sin(angle);
|
|
1842
|
+
return this.multiply([
|
|
1843
|
+
c,
|
|
1844
|
+
s,
|
|
1845
|
+
0,
|
|
1846
|
+
0,
|
|
1847
|
+
-s,
|
|
1848
|
+
c,
|
|
1849
|
+
0,
|
|
1850
|
+
0,
|
|
1851
|
+
0,
|
|
1852
|
+
0,
|
|
1853
|
+
1,
|
|
1854
|
+
0,
|
|
1855
|
+
0,
|
|
1856
|
+
0,
|
|
1857
|
+
0,
|
|
1858
|
+
1
|
|
1859
|
+
]);
|
|
1860
|
+
}
|
|
1861
|
+
rotate(...args) {
|
|
1862
|
+
const vec = Vec3.resolveArgs(args);
|
|
1863
|
+
return this.rotateX(vec.x).rotateY(vec.y).rotateZ(vec.z);
|
|
1864
|
+
}
|
|
1865
|
+
scale(...args) {
|
|
1866
|
+
const vec = Vec3.resolveArgs(args);
|
|
1867
|
+
return this.multiply([
|
|
1868
|
+
vec.x,
|
|
1869
|
+
0,
|
|
1870
|
+
0,
|
|
1871
|
+
0,
|
|
1872
|
+
0,
|
|
1873
|
+
vec.y,
|
|
1874
|
+
0,
|
|
1875
|
+
0,
|
|
1876
|
+
0,
|
|
1877
|
+
0,
|
|
1878
|
+
vec.z,
|
|
1879
|
+
0,
|
|
1880
|
+
0,
|
|
1881
|
+
0,
|
|
1882
|
+
0,
|
|
1883
|
+
1
|
|
1884
|
+
]);
|
|
1885
|
+
}
|
|
1886
|
+
inverse() {
|
|
1887
|
+
return new Mat4([
|
|
1888
|
+
this.m00,
|
|
1889
|
+
this.m10,
|
|
1890
|
+
this.m20,
|
|
1891
|
+
0,
|
|
1892
|
+
this.m01,
|
|
1893
|
+
this.m11,
|
|
1894
|
+
this.m21,
|
|
1895
|
+
0,
|
|
1896
|
+
this.m02,
|
|
1897
|
+
this.m12,
|
|
1898
|
+
this.m22,
|
|
1899
|
+
0,
|
|
1900
|
+
-(this.m30 * this.m00 + this.m31 * this.m10 + this.m32 * this.m20),
|
|
1901
|
+
-(this.m30 * this.m01 + this.m31 * this.m11 + this.m32 * this.m21),
|
|
1902
|
+
-(this.m30 * this.m02 + this.m31 * this.m12 + this.m32 * this.m22),
|
|
1903
|
+
1
|
|
1904
|
+
]);
|
|
1905
|
+
}
|
|
1906
|
+
toMat3() {
|
|
1907
|
+
return [
|
|
1908
|
+
this.m00,
|
|
1909
|
+
this.m01,
|
|
1910
|
+
this.m03,
|
|
1911
|
+
this.m10,
|
|
1912
|
+
this.m11,
|
|
1913
|
+
this.m13,
|
|
1914
|
+
this.m30,
|
|
1915
|
+
this.m31,
|
|
1916
|
+
this.m33
|
|
1917
|
+
];
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
function _hex_to_array(hex) {
|
|
1922
|
+
if (!check_hex(hex))
|
|
1923
|
+
return undefined;
|
|
1924
|
+
const part = get_hex_part(hex);
|
|
1925
|
+
const a = parseInt(part.substring(0, 2), 16) / 255;
|
|
1926
|
+
const b = parseInt(part.substring(2, 4), 16) / 255;
|
|
1927
|
+
const c = parseInt(part.substring(4, 6), 16) / 255;
|
|
1928
|
+
const d = part.length == 8 ? parseInt(hex.substring(6, 8), 16) / 255 : 1;
|
|
1929
|
+
return [a, b, c, d];
|
|
1930
|
+
}
|
|
1931
|
+
function _number_to_rgb(number) {
|
|
1932
|
+
const blue = number & 255;
|
|
1933
|
+
const green = (number & 65280) >>> 8;
|
|
1934
|
+
const red = (number & 16711680) >>> 16;
|
|
1935
|
+
return [red / 255, green / 255, blue / 255];
|
|
1936
|
+
}
|
|
1937
|
+
function _number_to_rgba(number) {
|
|
1938
|
+
const alpha = number & 255;
|
|
1939
|
+
const blue = (number & 65280) >>> 8;
|
|
1940
|
+
const green = (number & 16711680) >>> 16;
|
|
1941
|
+
const red = (number & 4278190080) >>> 24;
|
|
1942
|
+
return [red / 255, green / 255, blue / 255, alpha / 255];
|
|
1943
|
+
}
|
|
1944
|
+
function _fix_integer(number) {
|
|
1945
|
+
return number * 255 | 0;
|
|
1946
|
+
}
|
|
1947
|
+
class RGBAColor {
|
|
1948
|
+
_red;
|
|
1949
|
+
get red() {
|
|
1950
|
+
return this._red;
|
|
1951
|
+
}
|
|
1952
|
+
set red(val) {
|
|
1953
|
+
this._red = clamp(val, 0, 1);
|
|
1954
|
+
}
|
|
1955
|
+
_green;
|
|
1956
|
+
get green() {
|
|
1957
|
+
return this._green;
|
|
1958
|
+
}
|
|
1959
|
+
set green(val) {
|
|
1960
|
+
this._green = clamp(val, 0, 1);
|
|
1961
|
+
}
|
|
1962
|
+
_blue;
|
|
1963
|
+
get blue() {
|
|
1964
|
+
return this._blue;
|
|
1965
|
+
}
|
|
1966
|
+
set blue(val) {
|
|
1967
|
+
this._blue = clamp(val, 0, 1);
|
|
1968
|
+
}
|
|
1969
|
+
_alpha;
|
|
1970
|
+
get alpha() {
|
|
1971
|
+
return this._alpha;
|
|
1972
|
+
}
|
|
1973
|
+
set alpha(val) {
|
|
1974
|
+
this._alpha = clamp(val, 0, 1);
|
|
1975
|
+
}
|
|
1976
|
+
static resolve(a) {
|
|
1977
|
+
const value = this.cast(a);
|
|
1978
|
+
if (typeof value != "undefined")
|
|
1979
|
+
return value;
|
|
1980
|
+
throw new ResolveError("RGBAColor", a);
|
|
1981
|
+
}
|
|
1982
|
+
static cast(a) {
|
|
1983
|
+
if (a == null || typeof a == "undefined")
|
|
1984
|
+
return undefined;
|
|
1985
|
+
if (check_number_array(a, 3) || check_number_array(a, 4))
|
|
1986
|
+
return new this(a[0], a[1], a[2], a[3]);
|
|
1987
|
+
if (has_property(a, "red", "number") && has_property(a, "green", "number") && has_property(a, "blue", "number"))
|
|
1988
|
+
return new this(a.red, a.green, a.blue, has_property(a, "alpha", "number") ? a.alpha : undefined);
|
|
1989
|
+
if (check_number(a)) {
|
|
1990
|
+
const hex = a.toString(16);
|
|
1991
|
+
const convert = hex.length <= 6 ? _number_to_rgb : _number_to_rgba;
|
|
1992
|
+
return this.cast(convert(a));
|
|
1993
|
+
}
|
|
1994
|
+
if (check_string(a)) {
|
|
1995
|
+
if (a.startsWith("rgb")) {
|
|
1996
|
+
const hasAlpha = a.startsWith("rgba");
|
|
1997
|
+
const offset = hasAlpha ? 5 : 4;
|
|
1998
|
+
const parts = a.substring(offset, a.indexOf(")", offset)).split(",");
|
|
1999
|
+
if (check_string_array(parts, hasAlpha ? 4 : 3))
|
|
2000
|
+
return this.cast(parts.map((v) => parseInt(v) / 255));
|
|
2001
|
+
}
|
|
2002
|
+
return this.cast(_hex_to_array(a));
|
|
2003
|
+
}
|
|
2004
|
+
return undefined;
|
|
2005
|
+
}
|
|
2006
|
+
static is(a) {
|
|
2007
|
+
return typeof this.cast(a) != "undefined";
|
|
2008
|
+
}
|
|
2009
|
+
constructor(red, green, blue, alpha = 1) {
|
|
2010
|
+
this._red = clamp(red, 0, 1);
|
|
2011
|
+
this._green = clamp(green, 0, 1);
|
|
2012
|
+
this._blue = clamp(blue, 0, 1);
|
|
2013
|
+
this._alpha = clamp(alpha, 0, 1);
|
|
2014
|
+
}
|
|
2015
|
+
toArray(withAlpha = false) {
|
|
2016
|
+
return withAlpha ? [this.red, this.green, this.blue, this.alpha] : this.alpha == 1 ? [this.red, this.green, this.blue] : this.toArray(true);
|
|
2017
|
+
}
|
|
2018
|
+
toJSON(withAlpha = false) {
|
|
2019
|
+
return withAlpha ? {
|
|
2020
|
+
red: this.red,
|
|
2021
|
+
green: this.green,
|
|
2022
|
+
blue: this.blue,
|
|
2023
|
+
alpha: this.alpha
|
|
2024
|
+
} : this.alpha == 1 ? { red: this.red, green: this.green, blue: this.blue } : this.toJSON(true);
|
|
2025
|
+
}
|
|
2026
|
+
toString(withAlpha = false) {
|
|
2027
|
+
return withAlpha ? `rgba(${_fix_integer(this.red)},${_fix_integer(this.green)},${_fix_integer(this.blue)},${_fix_integer(this.alpha)})` : this.alpha == 1 ? `rgb(${_fix_integer(this.red)},${_fix_integer(this.green)},${_fix_integer(this.blue)})` : this.toString(true);
|
|
2028
|
+
}
|
|
2029
|
+
toHSL(withAlpha = true) {
|
|
2030
|
+
const red = this.red, green = this.green, blue = this.blue;
|
|
2031
|
+
const min = Math.min(red, green, blue), max = Math.max(red, green, blue);
|
|
2032
|
+
const luminace = (min + max) / 2;
|
|
2033
|
+
if (min == max)
|
|
2034
|
+
return new HSLColor(0, 0, luminace, withAlpha ? this.alpha : undefined);
|
|
2035
|
+
const d = max - min;
|
|
2036
|
+
const saturation = luminace > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
2037
|
+
if (max == red)
|
|
2038
|
+
return new HSLColor(((green - blue) / d + (green < blue ? 6 : 0)) / 6, saturation, luminace);
|
|
2039
|
+
if (max == green)
|
|
2040
|
+
return new HSLColor(((blue - red) / d + 2) / 6, saturation, luminace);
|
|
2041
|
+
if (max == blue)
|
|
2042
|
+
return new HSLColor(((red - green) / d + 4) / 6, saturation, luminace);
|
|
2043
|
+
return new HSLColor(0, saturation, luminace, withAlpha ? this.alpha : undefined);
|
|
2044
|
+
}
|
|
2045
|
+
invert(withAlpha = false) {
|
|
2046
|
+
return new RGBAColor(
|
|
2047
|
+
1 - this.red,
|
|
2048
|
+
1 - this.green,
|
|
2049
|
+
1 - this.blue,
|
|
2050
|
+
withAlpha ? 1 - this.alpha : this.alpha
|
|
2051
|
+
);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
class HSLColor {
|
|
2055
|
+
_hue;
|
|
2056
|
+
get hue() {
|
|
2057
|
+
return this._hue;
|
|
2058
|
+
}
|
|
2059
|
+
set hue(val) {
|
|
2060
|
+
this._hue = clamp(val, 0, 1);
|
|
2061
|
+
}
|
|
2062
|
+
_saturation;
|
|
2063
|
+
get saturation() {
|
|
2064
|
+
return this._saturation;
|
|
2065
|
+
}
|
|
2066
|
+
set saturation(val) {
|
|
2067
|
+
this._saturation = clamp(val, 0, 1);
|
|
2068
|
+
}
|
|
2069
|
+
_luminace;
|
|
2070
|
+
get luminace() {
|
|
2071
|
+
return this._luminace;
|
|
2072
|
+
}
|
|
2073
|
+
set luminace(val) {
|
|
2074
|
+
this._luminace = clamp(val, 0, 1);
|
|
2075
|
+
}
|
|
2076
|
+
_alpha;
|
|
2077
|
+
get alpha() {
|
|
2078
|
+
return this._alpha;
|
|
2079
|
+
}
|
|
2080
|
+
set alpha(val) {
|
|
2081
|
+
this._alpha = clamp(val, 0, 1);
|
|
2082
|
+
}
|
|
2083
|
+
static resolve(a) {
|
|
2084
|
+
const value = this.cast(a);
|
|
2085
|
+
if (typeof value != "undefined")
|
|
2086
|
+
return value;
|
|
2087
|
+
throw new ResolveError("HSLColor", a);
|
|
2088
|
+
}
|
|
2089
|
+
static cast(a) {
|
|
2090
|
+
if (a == null || typeof a == "undefined")
|
|
2091
|
+
return undefined;
|
|
2092
|
+
if (check_number_array(a, 3) || check_number_array(a, 4))
|
|
2093
|
+
return new this(a[0], a[1], a[2], a[3]);
|
|
2094
|
+
if (has_property(a, "hue", "number") && has_property(a, "saturation", "number") && has_property(a, "luminace", "number"))
|
|
2095
|
+
return new this(a.hue, a.saturation, a.luminace, has_property(a, "alpha", "number") ? a.alpha : undefined);
|
|
2096
|
+
if (check_number(a)) {
|
|
2097
|
+
const hex = a.toString(16);
|
|
2098
|
+
const convert = hex.length <= 6 ? _number_to_rgb : _number_to_rgba;
|
|
2099
|
+
return this.cast(convert(a));
|
|
2100
|
+
}
|
|
2101
|
+
if (check_string(a)) {
|
|
2102
|
+
if (a.startsWith("hsl")) {
|
|
2103
|
+
const hasAlpha = a.startsWith("hsla");
|
|
2104
|
+
const offset = hasAlpha ? 5 : 4;
|
|
2105
|
+
const parts = a.substring(offset, a.indexOf(")", offset)).split(",");
|
|
2106
|
+
if (check_string_array(parts, hasAlpha ? 4 : 3))
|
|
2107
|
+
return this.cast(parts.map((v) => parseInt(v) / 255));
|
|
2108
|
+
}
|
|
2109
|
+
return this.cast(_hex_to_array(a));
|
|
2110
|
+
}
|
|
2111
|
+
return undefined;
|
|
2112
|
+
}
|
|
2113
|
+
static is(a) {
|
|
2114
|
+
return typeof this.cast(a) != "undefined";
|
|
2115
|
+
}
|
|
2116
|
+
constructor(hue, saturation, luminace, alpha = 1) {
|
|
2117
|
+
if (!check_number(hue))
|
|
2118
|
+
throw new TypeError("expected number for hue");
|
|
2119
|
+
if (!check_number(saturation))
|
|
2120
|
+
throw new TypeError("expected number for saturation");
|
|
2121
|
+
if (!check_number(luminace))
|
|
2122
|
+
throw new TypeError("expected number for luminace");
|
|
2123
|
+
if (!check_number(alpha))
|
|
2124
|
+
throw new TypeError("expected number for alpha");
|
|
2125
|
+
this._hue = clamp(hue, 0, 1);
|
|
2126
|
+
this._saturation = clamp(saturation, 0, 1);
|
|
2127
|
+
this._luminace = clamp(luminace, 0, 1);
|
|
2128
|
+
this._alpha = clamp(alpha, 0, 1);
|
|
2129
|
+
}
|
|
2130
|
+
toArray(withAlpha = false) {
|
|
2131
|
+
return withAlpha ? [this.hue, this.saturation, this.luminace, this.alpha] : this.alpha == 1 ? [this.hue, this.saturation, this.luminace] : this.toArray(true);
|
|
2132
|
+
}
|
|
2133
|
+
toJSON(withAlpha = false) {
|
|
2134
|
+
return withAlpha ? {
|
|
2135
|
+
hue: this.hue,
|
|
2136
|
+
saturation: this.saturation,
|
|
2137
|
+
luminace: this.luminace,
|
|
2138
|
+
alpha: this.alpha
|
|
2139
|
+
} : this.alpha == 1 ? { hue: this.hue, saturation: this.saturation, luminace: this.luminace } : this.toJSON(true);
|
|
2140
|
+
}
|
|
2141
|
+
toString(withAlpha = false) {
|
|
2142
|
+
return withAlpha ? `hsla(${_fix_integer(this.hue)},${_fix_integer(this.saturation)},${_fix_integer(this.luminace)},${_fix_integer(this.alpha)})` : this.alpha == 1 ? `hsl(${_fix_integer(this.hue)},${_fix_integer(this.saturation)},${_fix_integer(this.luminace)})` : this.toString(true);
|
|
2143
|
+
}
|
|
2144
|
+
toRGB(withAlpha = true) {
|
|
2145
|
+
if (this.saturation == 0)
|
|
2146
|
+
return new RGBAColor(this.luminace * 255, this.luminace * 255, this.luminace * 255, withAlpha ? this.alpha : undefined);
|
|
2147
|
+
const q = this.luminace < 0.5 ? this.luminace * (1 + this.saturation) : this.luminace + this.saturation - this.luminace * this.saturation;
|
|
2148
|
+
const p = 2 * this.luminace - q;
|
|
2149
|
+
function _hue_2_rgb(t) {
|
|
2150
|
+
let _t = t;
|
|
2151
|
+
if (_t < 0)
|
|
2152
|
+
_t++;
|
|
2153
|
+
if (_t > 1)
|
|
2154
|
+
_t--;
|
|
2155
|
+
if (_t < 1 / 6)
|
|
2156
|
+
return p + (q - p) * 6 * _t;
|
|
2157
|
+
if (_t < 1 / 2)
|
|
2158
|
+
return q;
|
|
2159
|
+
if (_t < 2 / 3)
|
|
2160
|
+
return p + (q - p) * (2 / 3 - _t) * 6;
|
|
2161
|
+
return p;
|
|
2162
|
+
}
|
|
2163
|
+
return new RGBAColor(_hue_2_rgb(this.hue + 1 / 3) * 255, _hue_2_rgb(this.hue) * 255, _hue_2_rgb(this.hue - 1 / 3) * 255, withAlpha ? this.alpha : undefined);
|
|
2164
|
+
}
|
|
2165
|
+
invert(withAlpha = false) {
|
|
2166
|
+
return new HSLColor(
|
|
2167
|
+
1 - this.hue,
|
|
2168
|
+
1 - this.saturation,
|
|
2169
|
+
1 - this.luminace,
|
|
2170
|
+
withAlpha ? 1 - this.alpha : this.alpha
|
|
2171
|
+
);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
function resolveColor(a, preferHSL = false) {
|
|
2175
|
+
const value = castColor(a, preferHSL);
|
|
2176
|
+
if (typeof value != "undefined")
|
|
2177
|
+
return value;
|
|
2178
|
+
throw new ResolveError("Color", a);
|
|
2179
|
+
}
|
|
2180
|
+
function castColor(a, preferHSL = false) {
|
|
2181
|
+
const results = [];
|
|
2182
|
+
try {
|
|
2183
|
+
const rgba = RGBAColor.resolve(a);
|
|
2184
|
+
results.push(rgba);
|
|
2185
|
+
} catch (e) {
|
|
2186
|
+
}
|
|
2187
|
+
try {
|
|
2188
|
+
const hsla = HSLColor.resolve(a);
|
|
2189
|
+
results.push(hsla);
|
|
2190
|
+
} catch (e) {
|
|
2191
|
+
}
|
|
2192
|
+
let offset = preferHSL ? 1 : 0;
|
|
2193
|
+
const firstItem = results[offset];
|
|
2194
|
+
if (firstItem)
|
|
2195
|
+
return firstItem;
|
|
2196
|
+
const secondItem = results[offset + 1];
|
|
2197
|
+
if (secondItem)
|
|
2198
|
+
return secondItem;
|
|
2199
|
+
return undefined;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
class Quaternion {
|
|
2203
|
+
w;
|
|
2204
|
+
x;
|
|
2205
|
+
y;
|
|
2206
|
+
z;
|
|
2207
|
+
static is(a) {
|
|
2208
|
+
return typeof this.cast(a) != "undefined";
|
|
2209
|
+
}
|
|
2210
|
+
static resolve(a) {
|
|
2211
|
+
const value = this.cast(a);
|
|
2212
|
+
if (typeof value != "undefined")
|
|
2213
|
+
return value;
|
|
2214
|
+
throw new ResolveError("Quaternion", a);
|
|
2215
|
+
}
|
|
2216
|
+
static cast(a) {
|
|
2217
|
+
if (a == null || typeof a == "undefined")
|
|
2218
|
+
return undefined;
|
|
2219
|
+
if (check_number_array(a, 4))
|
|
2220
|
+
return new this(a[0], a[1], a[2], a[3]);
|
|
2221
|
+
if (has_property(a, "w", "number") && has_property(a, "x", "number") && has_property(a, "y", "number") && has_property(a, "z", "number"))
|
|
2222
|
+
return new this(a.w, a.x, a.y, a.z);
|
|
2223
|
+
if (check_string(a)) {
|
|
2224
|
+
const parts = a.replaceAll(" ", "").split("+");
|
|
2225
|
+
if (check_string_array(parts, 4)) {
|
|
2226
|
+
const [sw, sxi, syj, szk] = parts;
|
|
2227
|
+
if (sxi.endsWith("i") && syj.endsWith("j") && szk.endsWith("k"))
|
|
2228
|
+
return this.cast([
|
|
2229
|
+
parseFloat(sw),
|
|
2230
|
+
parseFloat(sxi.substring(0, sxi.length - 1)),
|
|
2231
|
+
parseFloat(syj.substring(0, syj.length - 1)),
|
|
2232
|
+
parseFloat(szk.substring(0, szk.length - 1))
|
|
2233
|
+
]);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
return undefined;
|
|
2237
|
+
}
|
|
2238
|
+
static fromAxisAngle(axis, angle) {
|
|
2239
|
+
const vec = Vec3.resolve(axis);
|
|
2240
|
+
const hangle = angle * 0.5;
|
|
2241
|
+
const sin2 = Math.sin(hangle);
|
|
2242
|
+
const cos2 = Math.cos(hangle);
|
|
2243
|
+
const length = sin2 / Math.sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
|
|
2244
|
+
return new this(cos2, vec.x * length, vec.y * length, vec.z * length);
|
|
2245
|
+
}
|
|
2246
|
+
static fromEuler(...args) {
|
|
2247
|
+
const vec = Vec3.resolveArgs(args);
|
|
2248
|
+
const x2 = vec.x * 0.5, y2 = vec.y * 0.5, z2 = vec.z * 0.5;
|
|
2249
|
+
const cx = Math.cos(x2), cy = Math.cos(y2), cz = Math.cos(z2);
|
|
2250
|
+
const sx = Math.sin(x2), sy = Math.sin(y2), sz = Math.sin(z2);
|
|
2251
|
+
return new Quaternion(
|
|
2252
|
+
cx * cy * cz - sx * sy * sz,
|
|
2253
|
+
sx * cy * cz - sy * sz * cx,
|
|
2254
|
+
sy * cx * cz - sx * sz * cy,
|
|
2255
|
+
sx * sy * cz + sz * cx * cy
|
|
2256
|
+
);
|
|
2257
|
+
}
|
|
2258
|
+
constructor(w = 0, x = 0, y = 0, z = 0) {
|
|
2259
|
+
if (!check_number(w))
|
|
2260
|
+
throw new TypeError("expected number for w");
|
|
2261
|
+
if (!check_number(x))
|
|
2262
|
+
throw new TypeError("expected number for x");
|
|
2263
|
+
if (!check_number(y))
|
|
2264
|
+
throw new TypeError("expected number for x");
|
|
2265
|
+
if (!check_number(z))
|
|
2266
|
+
throw new TypeError("expected number for w");
|
|
2267
|
+
this.w = w;
|
|
2268
|
+
this.x = x;
|
|
2269
|
+
this.y = y;
|
|
2270
|
+
this.z = z;
|
|
2271
|
+
}
|
|
2272
|
+
toArray() {
|
|
2273
|
+
return [this.w, this.x, this.y, this.z];
|
|
2274
|
+
}
|
|
2275
|
+
toString() {
|
|
2276
|
+
return `${this.w} + ${this.x}i + ${this.y}j + ${this.z}k`;
|
|
2277
|
+
}
|
|
2278
|
+
toJSON() {
|
|
2279
|
+
return {
|
|
2280
|
+
w: this.w,
|
|
2281
|
+
x: this.x,
|
|
2282
|
+
y: this.y,
|
|
2283
|
+
z: this.z
|
|
2284
|
+
};
|
|
2285
|
+
}
|
|
2286
|
+
clone() {
|
|
2287
|
+
return new Quaternion(this.w, this.x, this.y, this.z);
|
|
2288
|
+
}
|
|
2289
|
+
add(a) {
|
|
2290
|
+
const quat = Quaternion.resolve(a);
|
|
2291
|
+
return new Quaternion(
|
|
2292
|
+
this.w + quat.w,
|
|
2293
|
+
this.x + quat.x,
|
|
2294
|
+
this.y + quat.y,
|
|
2295
|
+
this.z + quat.z
|
|
2296
|
+
);
|
|
2297
|
+
}
|
|
2298
|
+
offset(a) {
|
|
2299
|
+
const quat = Quaternion.resolve(a);
|
|
2300
|
+
this.w += quat.w;
|
|
2301
|
+
this.x += quat.x;
|
|
2302
|
+
this.y += quat.y;
|
|
2303
|
+
this.z += quat.z;
|
|
2304
|
+
return this;
|
|
2305
|
+
}
|
|
2306
|
+
subtract(a) {
|
|
2307
|
+
const quat = Quaternion.resolve(a);
|
|
2308
|
+
return new Quaternion(
|
|
2309
|
+
this.w - quat.w,
|
|
2310
|
+
this.x - quat.x,
|
|
2311
|
+
this.y - quat.y,
|
|
2312
|
+
this.z - quat.z
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
negative() {
|
|
2316
|
+
return new Quaternion(-this.w, -this.x, -this.y, -this.z);
|
|
2317
|
+
}
|
|
2318
|
+
length(sqrt = true) {
|
|
2319
|
+
const value = this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z;
|
|
2320
|
+
return sqrt ? Math.sqrt(value) : value;
|
|
2321
|
+
}
|
|
2322
|
+
normalize() {
|
|
2323
|
+
let length = this.length();
|
|
2324
|
+
if (length < EPSILON)
|
|
2325
|
+
return new Quaternion();
|
|
2326
|
+
length = 1 / length;
|
|
2327
|
+
return new Quaternion(this.w * length, this.x * length, this.y * length, this.z * length);
|
|
2328
|
+
}
|
|
2329
|
+
multiply(a) {
|
|
2330
|
+
const quat = Quaternion.resolve(a);
|
|
2331
|
+
return new Quaternion(
|
|
2332
|
+
this.w * quat.w - this.x * quat.x - this.y * quat.y - this.z * quat.z,
|
|
2333
|
+
this.w * quat.x + this.x * quat.w + this.y * quat.z - this.z * quat.y,
|
|
2334
|
+
this.w * quat.y + this.y * quat.w + this.z * quat.x - this.x * quat.z,
|
|
2335
|
+
this.w * quat.z + this.z * quat.w + this.x * quat.y - this.y * quat.x
|
|
2336
|
+
);
|
|
2337
|
+
}
|
|
2338
|
+
multiplyVector(...args) {
|
|
2339
|
+
const vec = Vec3.resolveArgs(args);
|
|
2340
|
+
const ix = this.w * vec.x + this.y * vec.y - this.z * vec.y;
|
|
2341
|
+
const iy = this.w * vec.y + this.z * vec.x - this.x * vec.z;
|
|
2342
|
+
const iz = this.w * vec.z + this.x * vec.y - this.y * vec.x;
|
|
2343
|
+
const iw = -this.w * vec.x - this.y * vec.y - this.z * vec.z;
|
|
2344
|
+
return new Vec3(
|
|
2345
|
+
ix * this.w + iw * -this.x + iy * -this.z - iz * -this.y,
|
|
2346
|
+
iy * this.w + iw * -this.y + iz * -this.x - ix * -this.z,
|
|
2347
|
+
iz * this.w + iw * -this.z + ix * -this.y - iy * -this.x
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
scale(scalar) {
|
|
2351
|
+
return new Quaternion(this.w * scalar, this.x * scalar, this.y * scalar, this.z * scalar);
|
|
2352
|
+
}
|
|
2353
|
+
dot(a) {
|
|
2354
|
+
const quat = Quaternion.resolve(a);
|
|
2355
|
+
return this.w * quat.w + this.x * quat.x + this.y * quat.y + this.z * quat.z;
|
|
2356
|
+
}
|
|
2357
|
+
inverse() {
|
|
2358
|
+
let length = this.length(false);
|
|
2359
|
+
if (length == 0)
|
|
2360
|
+
return new Quaternion();
|
|
2361
|
+
length = 1 / length;
|
|
2362
|
+
return new Quaternion(this.w * length, -this.x * length, -this.y * length, -this.z * length);
|
|
2363
|
+
}
|
|
2364
|
+
divide(a) {
|
|
2365
|
+
const quat = Quaternion.resolve(a);
|
|
2366
|
+
let length = quat.length(false);
|
|
2367
|
+
if (length == 0) return new Quaternion();
|
|
2368
|
+
length = 1 / length;
|
|
2369
|
+
return new Quaternion(
|
|
2370
|
+
(this.w * quat.w + this.x * quat.x + this.y * quat.y + this.z * quat.z) * length,
|
|
2371
|
+
(this.x * quat.w - this.w * quat.x - this.y * quat.z + this.z * quat.y) * length,
|
|
2372
|
+
(this.y * quat.w - this.w * quat.y - this.z * quat.x + this.x * quat.z) * length,
|
|
2373
|
+
(this.z * quat.w - this.w * quat.z - this.x * quat.y + this.y * quat.x) * length
|
|
2374
|
+
);
|
|
2375
|
+
}
|
|
2376
|
+
conjugate() {
|
|
2377
|
+
return new Quaternion(this.w, -this.x, -this.y, -this.z);
|
|
2378
|
+
}
|
|
2379
|
+
exp() {
|
|
2380
|
+
const length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
|
2381
|
+
const exp = Math.exp(this.w);
|
|
2382
|
+
const scale = exp * Math.sin(length) / length;
|
|
2383
|
+
if (length == 0)
|
|
2384
|
+
return new Quaternion(exp);
|
|
2385
|
+
return new Quaternion(
|
|
2386
|
+
exp * Math.cos(length),
|
|
2387
|
+
this.x * scale,
|
|
2388
|
+
this.y * scale,
|
|
2389
|
+
this.z * scale
|
|
2390
|
+
);
|
|
2391
|
+
}
|
|
2392
|
+
log() {
|
|
2393
|
+
if (this.x == 0 && this.z == 0)
|
|
2394
|
+
return new Quaternion(log_hypot(this.w, this.x), Math.atan2(this.x, this.w));
|
|
2395
|
+
const length = this.length(false);
|
|
2396
|
+
const length2 = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
|
2397
|
+
const scale = Math.atan2(length2, this.w) / length;
|
|
2398
|
+
return new Quaternion(Math.log(length) * 0.5, this.x * scale, this.y * scale, this.z * scale);
|
|
2399
|
+
}
|
|
2400
|
+
toVector() {
|
|
2401
|
+
return new Vec3(this.x, this.y, this.z, this.w);
|
|
2402
|
+
}
|
|
2403
|
+
toAxisAngle() {
|
|
2404
|
+
const sin2 = 1 - this.w * this.w;
|
|
2405
|
+
if (sin2 > EPSILON)
|
|
2406
|
+
return new Vec3(this.x, this.y, this.z, 0);
|
|
2407
|
+
const isin = 1 / Math.sqrt(sin2);
|
|
2408
|
+
const angle = 2 * Math.acos(this.w);
|
|
2409
|
+
return new Vec3(this.x * isin, this.y * isin, this.z * isin, angle);
|
|
2410
|
+
}
|
|
2411
|
+
toEuler() {
|
|
2412
|
+
function asin(t) {
|
|
2413
|
+
return t >= 1 ? Math.PI / 2 : t <= -1 ? -Math.PI / 2 : Math.asin(t);
|
|
2414
|
+
}
|
|
2415
|
+
return new Vec3(
|
|
2416
|
+
-Math.atan2(2 * (this.y * this.z - this.w * this.x), 1 - 2 * (this.x * this.x + this.y * this.y)),
|
|
2417
|
+
asin(2 * (this.x * this.z + this.w * this.y)),
|
|
2418
|
+
-Math.atan2(2 * (this.x * this.y - this.w * this.z), 1 - 2 * (this.y * this.y + this.z * this.z))
|
|
2419
|
+
);
|
|
2420
|
+
}
|
|
2421
|
+
toMat3() {
|
|
2422
|
+
return new Mat3([
|
|
2423
|
+
1 - 2 * (this.y * this.y + this.z * this.z),
|
|
2424
|
+
2 * (this.x * this.y - this.w * this.z),
|
|
2425
|
+
2 * (this.x * this.z + this.w * this.y),
|
|
2426
|
+
2 * (this.x * this.y + this.w * this.z),
|
|
2427
|
+
1 - 2 * (this.x * this.x + this.z * this.z),
|
|
2428
|
+
2 * (this.y * this.z - this.w * this.x),
|
|
2429
|
+
2 * (this.x * this.z - this.w * this.y),
|
|
2430
|
+
2 * (this.y * this.z + this.w * this.x),
|
|
2431
|
+
1 - 2 * (this.x * this.x + this.y * this.y)
|
|
2432
|
+
]);
|
|
2433
|
+
}
|
|
2434
|
+
toMat4() {
|
|
2435
|
+
return new Mat4([
|
|
2436
|
+
1 - 2 * (this.y * this.y + this.z * this.z),
|
|
2437
|
+
2 * (this.x * this.y - this.w * this.z),
|
|
2438
|
+
2 * (this.x * this.z + this.w * this.y),
|
|
2439
|
+
0,
|
|
2440
|
+
2 * (this.x * this.y + this.w * this.z),
|
|
2441
|
+
1 - 2 * (this.x * this.x + this.z * this.z),
|
|
2442
|
+
2 * (this.y * this.z - this.w * this.x),
|
|
2443
|
+
0,
|
|
2444
|
+
2 * (this.x * this.z - this.w * this.y),
|
|
2445
|
+
2 * (this.y * this.z + this.w * this.x),
|
|
2446
|
+
1 - 2 * (this.x * this.x + this.y * this.y),
|
|
2447
|
+
0,
|
|
2448
|
+
0,
|
|
2449
|
+
0,
|
|
2450
|
+
0,
|
|
2451
|
+
1
|
|
2452
|
+
]);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
class Transform {
|
|
2457
|
+
/**
|
|
2458
|
+
* The position of the object
|
|
2459
|
+
*/
|
|
2460
|
+
position;
|
|
2461
|
+
/**
|
|
2462
|
+
* The rotation of the object
|
|
2463
|
+
*/
|
|
2464
|
+
rotation;
|
|
2465
|
+
/**
|
|
2466
|
+
* The scale of the object
|
|
2467
|
+
*/
|
|
2468
|
+
scale;
|
|
2469
|
+
/**
|
|
2470
|
+
* Create a new transform with `position`, `rotation` and `scale`
|
|
2471
|
+
* @param position The position as a Vec3
|
|
2472
|
+
* @param rotation The rotation as a Quaternion
|
|
2473
|
+
* @param scale The scale as a Vec3
|
|
2474
|
+
*/
|
|
2475
|
+
constructor(position, rotation, scale) {
|
|
2476
|
+
this.position = Vec3.resolve(position);
|
|
2477
|
+
this.rotation = Quaternion.resolve(rotation);
|
|
2478
|
+
this.scale = Vec3.resolve(scale);
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* Convert the transform into a 4x3 matrix
|
|
2482
|
+
* @returns A 4x4 matrix from the transform
|
|
2483
|
+
*/
|
|
2484
|
+
toMat4() {
|
|
2485
|
+
return new Mat4().translate(this.position).multiply(this.rotation.toMat4()).scale(this.scale);
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
export { ATriangle, BoundingBox, Circle, DJB2_OFFSET, EPSILON, FNV1_OFFSET, FNV1_PRIME, HSLColor, LinearFunction, MAX_ANGLE_DEGREE, Mat3, Mat4, MathFunction, QuadFunction, Quaternion, RGBAColor, Rectangle, ResolveError, Size, Transform, Triangle2D, Triangle3D, Vec2, Vec3, cap_angle_degree, cap_angle_radian, castColor, check_array, check_hex, check_hex_digit, check_number, check_number_array, check_string, check_string_array, clamp, degree_to_radian, djb2, fnv1, get_hex_part, has_property, log_hypot, radian_to_degree, resolveColor, sdbm, sign_char, stringify };
|