@vyr/engine 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/package.json +19 -0
  2. package/src/ArrayUtils.ts +65 -0
  3. package/src/AsyncTask.ts +72 -0
  4. package/src/Category.ts +119 -0
  5. package/src/Color.ts +111 -0
  6. package/src/Engine.ts +101 -0
  7. package/src/Generate.ts +40 -0
  8. package/src/InputSystem.ts +108 -0
  9. package/src/Listener.ts +59 -0
  10. package/src/ObjectPool.ts +84 -0
  11. package/src/ObjectUtils.ts +49 -0
  12. package/src/Scriptable.ts +27 -0
  13. package/src/Serialization.ts +49 -0
  14. package/src/Traverser.ts +39 -0
  15. package/src/actor/Actor.ts +28 -0
  16. package/src/actor/AnimationUnitActor.ts +289 -0
  17. package/src/actor/DivActor.ts +70 -0
  18. package/src/actor/FragmentActor.ts +56 -0
  19. package/src/actor/HTMActor.ts +166 -0
  20. package/src/actor/HTMServiceActor.ts +57 -0
  21. package/src/actor/HTMTransformControllerActor.ts +404 -0
  22. package/src/actor/StyleActor.ts +96 -0
  23. package/src/actor/index.ts +8 -0
  24. package/src/asset/Asset.ts +271 -0
  25. package/src/asset/AssetGraph.ts +246 -0
  26. package/src/asset/index.ts +2 -0
  27. package/src/descriptor/AnimationUnitDescriptor.ts +65 -0
  28. package/src/descriptor/CameraDescriptor.ts +12 -0
  29. package/src/descriptor/ControllerDescriptor.ts +16 -0
  30. package/src/descriptor/DatasetDescriptor.ts +92 -0
  31. package/src/descriptor/Descriptor.ts +415 -0
  32. package/src/descriptor/DivDescriptor.ts +18 -0
  33. package/src/descriptor/DynamicDescriptor.ts +27 -0
  34. package/src/descriptor/HTMLDescriptor.ts +87 -0
  35. package/src/descriptor/HTMLServiceDescriptor.ts +19 -0
  36. package/src/descriptor/HTMLTransformControllerDescriptor.ts +34 -0
  37. package/src/descriptor/NodeDescriptor.ts +32 -0
  38. package/src/descriptor/PrefabDescriptor.ts +53 -0
  39. package/src/descriptor/PrefabInstanceDescriptor.ts +32 -0
  40. package/src/descriptor/RoutineDescriptor.ts +54 -0
  41. package/src/descriptor/ServiceDescriptor.ts +32 -0
  42. package/src/descriptor/ServiceSchedulerDescriptor.ts +32 -0
  43. package/src/descriptor/StyleDescriptor.ts +213 -0
  44. package/src/descriptor/index.ts +17 -0
  45. package/src/graphics/Collection.ts +25 -0
  46. package/src/graphics/Compilation.ts +82 -0
  47. package/src/graphics/Graphics.ts +475 -0
  48. package/src/graphics/Observer.ts +36 -0
  49. package/src/graphics/Unit.ts +83 -0
  50. package/src/graphics/VariableProxy.ts +92 -0
  51. package/src/graphics/index.ts +5 -0
  52. package/src/index.ts +26 -0
  53. package/src/interpreter/AnimationUnitInterpreter.ts +53 -0
  54. package/src/interpreter/DatasetInterpreter.ts +11 -0
  55. package/src/interpreter/DivInterpreter.ts +44 -0
  56. package/src/interpreter/DynamicInterpreter.ts +207 -0
  57. package/src/interpreter/FragmentInterpreter.ts +34 -0
  58. package/src/interpreter/HTMLServiceInterpreter.ts +47 -0
  59. package/src/interpreter/HTMLTransformControllerInterpreter.ts +40 -0
  60. package/src/interpreter/Interpreter.ts +69 -0
  61. package/src/interpreter/PrefaInterpreter.ts +11 -0
  62. package/src/interpreter/PrefabInstanceInterpreter.ts +12 -0
  63. package/src/interpreter/RoutineInterpreter.ts +88 -0
  64. package/src/interpreter/ServiceInterpreter.ts +24 -0
  65. package/src/interpreter/ServiceSchedulerInterpreter.ts +42 -0
  66. package/src/interpreter/StyleInterpreter.ts +66 -0
  67. package/src/interpreter/index.ts +14 -0
  68. package/src/locale/Language.ts +10 -0
  69. package/src/locale/LanguageProvider.ts +48 -0
  70. package/src/locale/index.ts +2 -0
  71. package/src/math/Euler.ts +303 -0
  72. package/src/math/Matrix4.ts +1123 -0
  73. package/src/math/Quaternion.ts +737 -0
  74. package/src/math/Vector2.ts +680 -0
  75. package/src/math/Vector3.ts +1062 -0
  76. package/src/math/index.ts +5 -0
  77. package/src/math/utils.ts +17 -0
  78. package/src/preset/execute/dataset/index.ts +1 -0
  79. package/src/preset/execute/dataset/update.ts +52 -0
  80. package/src/preset/execute/graphics/index.ts +1 -0
  81. package/src/preset/execute/graphics/invoke.ts +49 -0
  82. package/src/preset/execute/index.ts +4 -0
  83. package/src/preset/execute/net/index.ts +1 -0
  84. package/src/preset/execute/net/request.ts +103 -0
  85. package/src/preset/execute/scheduler/index.ts +1 -0
  86. package/src/preset/execute/scheduler/switch.ts +46 -0
  87. package/src/preset/index.ts +7 -0
  88. package/src/preset/routine/graphics/index.ts +1 -0
  89. package/src/preset/routine/graphics/invoke.ts +27 -0
  90. package/src/preset/routine/index.ts +2 -0
  91. package/src/preset/routine/scheduler/index.ts +1 -0
  92. package/src/preset/routine/scheduler/switch.ts +27 -0
  93. package/src/setup/index.ts +17 -0
  94. package/src/utils/AssetProvider.ts +72 -0
  95. package/src/utils/index.ts +1 -0
@@ -0,0 +1,737 @@
1
+ import { Euler } from './Euler';
2
+ import { Matrix4 } from './Matrix4';
3
+ import { clamp } from './utils';
4
+ import { Vector3 } from './Vector3';
5
+
6
+
7
+ /**
8
+ * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations.
9
+ *
10
+ * Iterating through a vector instance will yield its components `(x, y, z, w)` in
11
+ * the corresponding order.
12
+ *
13
+ * Note that three.js expects Quaternions to be normalized.
14
+ * ```js
15
+ * const quaternion = new Quaternion();
16
+ * quaternion.setFromAxisAngle( new Vector3( 0, 1, 0 ), Math.PI / 2 );
17
+ *
18
+ * const vector = new Vector3( 1, 0, 0 );
19
+ * vector.applyQuaternion( quaternion );
20
+ * ```
21
+ */
22
+ class Quaternion {
23
+ x: number;
24
+ y: number;
25
+ z: number;
26
+ w: number;
27
+ /**
28
+ * Constructs a new quaternion.
29
+ *
30
+ * @param x - The x value of this quaternion.
31
+ * @param y - The y value of this quaternion.
32
+ * @param z - The z value of this quaternion.
33
+ * @param w - The w value of this quaternion.
34
+ */
35
+ constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 1) {
36
+ this.x = x;
37
+ this.y = y;
38
+ this.z = z;
39
+ this.w = w;
40
+ }
41
+
42
+ /**
43
+ * Interpolates between two quaternions via SLERP. This implementation assumes the
44
+ * quaternion data are managed in flat arrays.
45
+ *
46
+ * @param dst - The destination array.
47
+ * @param dstOffset - An offset into the destination array.
48
+ * @param src0 - The source array of the first quaternion.
49
+ * @param srcOffset0 - An offset into the first source array.
50
+ * @param src1 - The source array of the second quaternion.
51
+ * @param srcOffset1 - An offset into the second source array.
52
+ * @param t - The interpolation factor in the range `[0,1]`.
53
+ * @see {@link Quaternion#slerp}
54
+ */
55
+ static slerpFlat(
56
+ dst: number[],
57
+ dstOffset: number,
58
+ src0: number[],
59
+ srcOffset0: number,
60
+ src1: number[],
61
+ srcOffset1: number,
62
+ t: number
63
+ ): void {
64
+ // fuzz-free, array-based Quaternion SLERP operation
65
+ let x0 = src0[srcOffset0 + 0],
66
+ y0 = src0[srcOffset0 + 1],
67
+ z0 = src0[srcOffset0 + 2],
68
+ w0 = src0[srcOffset0 + 3];
69
+
70
+ const x1 = src1[srcOffset1 + 0],
71
+ y1 = src1[srcOffset1 + 1],
72
+ z1 = src1[srcOffset1 + 2],
73
+ w1 = src1[srcOffset1 + 3];
74
+
75
+ if (t === 0) {
76
+ dst[dstOffset + 0] = x0;
77
+ dst[dstOffset + 1] = y0;
78
+ dst[dstOffset + 2] = z0;
79
+ dst[dstOffset + 3] = w0;
80
+ return;
81
+ }
82
+
83
+ if (t === 1) {
84
+ dst[dstOffset + 0] = x1;
85
+ dst[dstOffset + 1] = y1;
86
+ dst[dstOffset + 2] = z1;
87
+ dst[dstOffset + 3] = w1;
88
+ return;
89
+ }
90
+
91
+ if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1) {
92
+ let s = 1 - t;
93
+ const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
94
+ dir = cos >= 0 ? 1 : -1,
95
+ sqrSin = 1 - cos * cos;
96
+
97
+ // Skip the Slerp for tiny steps to avoid numeric problems:
98
+ if (sqrSin > Number.EPSILON) {
99
+ const sin = Math.sqrt(sqrSin),
100
+ len = Math.atan2(sin, cos * dir);
101
+
102
+ s = Math.sin(s * len) / sin;
103
+ t = Math.sin(t * len) / sin;
104
+ }
105
+
106
+ const tDir = t * dir;
107
+
108
+ x0 = x0 * s + x1 * tDir;
109
+ y0 = y0 * s + y1 * tDir;
110
+ z0 = z0 * s + z1 * tDir;
111
+ w0 = w0 * s + w1 * tDir;
112
+
113
+ // Normalize in case we just did a lerp:
114
+ if (s === 1 - t) {
115
+ const f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0);
116
+
117
+ x0 *= f;
118
+ y0 *= f;
119
+ z0 *= f;
120
+ w0 *= f;
121
+ }
122
+ }
123
+
124
+ dst[dstOffset] = x0;
125
+ dst[dstOffset + 1] = y0;
126
+ dst[dstOffset + 2] = z0;
127
+ dst[dstOffset + 3] = w0;
128
+ }
129
+
130
+ /**
131
+ * Multiplies two quaternions. This implementation assumes the quaternion data are managed
132
+ * in flat arrays.
133
+ *
134
+ * @param dst - The destination array.
135
+ * @param dstOffset - An offset into the destination array.
136
+ * @param src0 - The source array of the first quaternion.
137
+ * @param srcOffset0 - An offset into the first source array.
138
+ * @param src1 - The source array of the second quaternion.
139
+ * @param srcOffset1 - An offset into the second source array.
140
+ * @return The destination array.
141
+ * @see {@link Quaternion#multiplyQuaternions}.
142
+ */
143
+ static multiplyQuaternionsFlat(
144
+ dst: number[],
145
+ dstOffset: number,
146
+ src0: number[],
147
+ srcOffset0: number,
148
+ src1: number[],
149
+ srcOffset1: number
150
+ ): number[] {
151
+ const x0 = src0[srcOffset0];
152
+ const y0 = src0[srcOffset0 + 1];
153
+ const z0 = src0[srcOffset0 + 2];
154
+ const w0 = src0[srcOffset0 + 3];
155
+
156
+ const x1 = src1[srcOffset1];
157
+ const y1 = src1[srcOffset1 + 1];
158
+ const z1 = src1[srcOffset1 + 2];
159
+ const w1 = src1[srcOffset1 + 3];
160
+
161
+ dst[dstOffset] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
162
+ dst[dstOffset + 1] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
163
+ dst[dstOffset + 2] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
164
+ dst[dstOffset + 3] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
165
+
166
+ return dst;
167
+ }
168
+
169
+ /**
170
+ * Sets the quaternion components.
171
+ *
172
+ * @param x - The x value of this quaternion.
173
+ * @param y - The y value of this quaternion.
174
+ * @param z - The z value of this quaternion.
175
+ * @param w - The w value of this quaternion.
176
+ * @return A reference to this quaternion.
177
+ */
178
+ set(x: number, y: number, z: number, w: number): Quaternion {
179
+ this.x = x;
180
+ this.y = y;
181
+ this.z = z;
182
+ this.w = w;
183
+
184
+
185
+ return this;
186
+ }
187
+
188
+ /**
189
+ * Returns a new quaternion with copied values from this instance.
190
+ *
191
+ * @return A clone of this instance.
192
+ */
193
+ clone(): Quaternion {
194
+ return new (this.constructor as typeof Quaternion)(this.x, this.y, this.z, this.w);
195
+ }
196
+
197
+ /**
198
+ * Copies the values of the given quaternion to this instance.
199
+ *
200
+ * @param quaternion - The quaternion to copy.
201
+ * @return A reference to this quaternion.
202
+ */
203
+ copy(quaternion: Quaternion): Quaternion {
204
+ this.x = quaternion.x;
205
+ this.y = quaternion.y;
206
+ this.z = quaternion.z;
207
+ this.w = quaternion.w;
208
+
209
+
210
+ return this;
211
+ }
212
+
213
+ /**
214
+ * Sets this quaternion from the rotation specified by the given
215
+ * Euler angles.
216
+ *
217
+ * @param euler - The Euler angles.
218
+ * @return A reference to this quaternion.
219
+ */
220
+ setFromEuler(euler: Euler): Quaternion {
221
+ const x = euler.x,
222
+ y = euler.y,
223
+ z = euler.z,
224
+ order = euler.order;
225
+
226
+ // http://www.mathworks.com/matlabcentral/fileexchange/
227
+ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
228
+ // content/SpinCalc.m
229
+
230
+ const cos = Math.cos;
231
+ const sin = Math.sin;
232
+
233
+ const c1 = cos(x / 2);
234
+ const c2 = cos(y / 2);
235
+ const c3 = cos(z / 2);
236
+
237
+ const s1 = sin(x / 2);
238
+ const s2 = sin(y / 2);
239
+ const s3 = sin(z / 2);
240
+
241
+ switch (order) {
242
+ case 'XYZ':
243
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
244
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
245
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
246
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
247
+ break;
248
+
249
+ case 'YXZ':
250
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
251
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
252
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
253
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
254
+ break;
255
+
256
+ case 'ZXY':
257
+ this.x = s1 * c2 * c3 - c1 * s2 * s3;
258
+ this.y = c1 * s2 * c3 + s1 * c2 * s3;
259
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
260
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
261
+ break;
262
+
263
+ case 'ZYX':
264
+ this.x = s1 * c2 * c3 - c1 * s2 * s3;
265
+ this.y = c1 * s2 * c3 + s1 * c2 * s3;
266
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
267
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
268
+ break;
269
+
270
+ case 'YZX':
271
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
272
+ this.y = c1 * s2 * c3 + s1 * c2 * s3;
273
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
274
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
275
+ break;
276
+
277
+ case 'XZY':
278
+ this.x = s1 * c2 * c3 - c1 * s2 * s3;
279
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
280
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
281
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
282
+ break;
283
+
284
+ default:
285
+ console.warn('Quaternion: .setFromEuler() encountered an unknown order: ' + order);
286
+ }
287
+
288
+ return this;
289
+ }
290
+
291
+ /**
292
+ * Sets this quaternion from the given axis and angle.
293
+ *
294
+ * @param axis - The normalized axis.
295
+ * @param angle - The angle in radians.
296
+ * @return A reference to this quaternion.
297
+ */
298
+ setFromAxisAngle(axis: Vector3, angle: number): Quaternion {
299
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
300
+ const halfAngle = angle / 2,
301
+ s = Math.sin(halfAngle);
302
+
303
+ this.x = axis.x * s;
304
+ this.y = axis.y * s;
305
+ this.z = axis.z * s;
306
+ this.w = Math.cos(halfAngle);
307
+
308
+
309
+ return this;
310
+ }
311
+
312
+ /**
313
+ * Sets this quaternion from the given rotation matrix.
314
+ *
315
+ * @param m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled).
316
+ * @return A reference to this quaternion.
317
+ */
318
+ setFromRotationMatrix(m: Matrix4): Quaternion {
319
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
320
+ // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
321
+ const te = m.elements,
322
+ m11 = te[0],
323
+ m12 = te[4],
324
+ m13 = te[8],
325
+ m21 = te[1],
326
+ m22 = te[5],
327
+ m23 = te[9],
328
+ m31 = te[2],
329
+ m32 = te[6],
330
+ m33 = te[10],
331
+ trace = m11 + m22 + m33;
332
+
333
+ if (trace > 0) {
334
+ const s = 0.5 / Math.sqrt(trace + 1.0);
335
+
336
+ this.w = 0.25 / s;
337
+ this.x = (m32 - m23) * s;
338
+ this.y = (m13 - m31) * s;
339
+ this.z = (m21 - m12) * s;
340
+ } else if (m11 > m22 && m11 > m33) {
341
+ const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
342
+
343
+ this.w = (m32 - m23) / s;
344
+ this.x = 0.25 * s;
345
+ this.y = (m12 + m21) / s;
346
+ this.z = (m13 + m31) / s;
347
+ } else if (m22 > m33) {
348
+ const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
349
+
350
+ this.w = (m13 - m31) / s;
351
+ this.x = (m12 + m21) / s;
352
+ this.y = 0.25 * s;
353
+ this.z = (m23 + m32) / s;
354
+ } else {
355
+ const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
356
+
357
+ this.w = (m21 - m12) / s;
358
+ this.x = (m13 + m31) / s;
359
+ this.y = (m23 + m32) / s;
360
+ this.z = 0.25 * s;
361
+ }
362
+
363
+
364
+ return this;
365
+ }
366
+
367
+ /**
368
+ * Sets this quaternion to the rotation required to rotate the direction vector
369
+ * `vFrom` to the direction vector `vTo`.
370
+ *
371
+ * @param vFrom - The first (normalized) direction vector.
372
+ * @param vTo - The second (normalized) direction vector.
373
+ * @return A reference to this quaternion.
374
+ */
375
+ setFromUnitVectors(vFrom: Vector3, vTo: Vector3): Quaternion {
376
+ // assumes direction vectors vFrom and vTo are normalized
377
+ let r = vFrom.dot(vTo) + 1;
378
+
379
+ if (r < Number.EPSILON) {
380
+ // vFrom and vTo point in opposite directions
381
+ r = 0;
382
+
383
+ if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
384
+ this.x = -vFrom.y;
385
+ this.y = vFrom.x;
386
+ this.z = 0;
387
+ this.w = r;
388
+ } else {
389
+ this.x = 0;
390
+ this.y = -vFrom.z;
391
+ this.z = vFrom.y;
392
+ this.w = r;
393
+ }
394
+ } else {
395
+ // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
396
+ this.x = vFrom.y * vTo.z - vFrom.z * vTo.y;
397
+ this.y = vFrom.z * vTo.x - vFrom.x * vTo.z;
398
+ this.z = vFrom.x * vTo.y - vFrom.y * vTo.x;
399
+ this.w = r;
400
+ }
401
+
402
+ return this.normalize();
403
+ }
404
+
405
+ /**
406
+ * Returns the angle between this quaternion and the given one in radians.
407
+ *
408
+ * @param q - The quaternion to compute the angle with.
409
+ * @return The angle in radians.
410
+ */
411
+ angleTo(q: Quaternion): number {
412
+ return 2 * Math.acos(Math.abs(clamp(this.dot(q), -1, 1)));
413
+ }
414
+
415
+ /**
416
+ * Rotates this quaternion by a given angular step to the given quaternion.
417
+ * The method ensures that the final quaternion will not overshoot `q`.
418
+ *
419
+ * @param q - The target quaternion.
420
+ * @param step - The angular step in radians.
421
+ * @return A reference to this quaternion.
422
+ */
423
+ rotateTowards(q: Quaternion, step: number): Quaternion {
424
+ const angle = this.angleTo(q);
425
+
426
+ if (angle === 0) return this;
427
+
428
+ const t = Math.min(1, step / angle);
429
+
430
+ this.slerp(q, t);
431
+
432
+ return this;
433
+ }
434
+
435
+ /**
436
+ * Sets this quaternion to the identity quaternion; that is, to the
437
+ * quaternion that represents "no rotation".
438
+ *
439
+ * @return A reference to this quaternion.
440
+ */
441
+ identity(): Quaternion {
442
+ return this.set(0, 0, 0, 1);
443
+ }
444
+
445
+ /**
446
+ * Inverts this quaternion via {@link Quaternion#conjugate}. The
447
+ * quaternion is assumed to have unit length.
448
+ *
449
+ * @return A reference to this quaternion.
450
+ */
451
+ invert(): Quaternion {
452
+ return this.conjugate();
453
+ }
454
+
455
+ /**
456
+ * Returns the rotational conjugate of this quaternion. The conjugate of a
457
+ * quaternion represents the same rotation in the opposite direction about
458
+ * the rotational axis.
459
+ *
460
+ * @return A reference to this quaternion.
461
+ */
462
+ conjugate(): Quaternion {
463
+ this.x *= -1;
464
+ this.y *= -1;
465
+ this.z *= -1;
466
+
467
+
468
+ return this;
469
+ }
470
+
471
+ /**
472
+ * Calculates the dot product of this quaternion and the given one.
473
+ *
474
+ * @param v - The quaternion to compute the dot product with.
475
+ * @return The result of the dot product.
476
+ */
477
+ dot(v: Quaternion): number {
478
+ return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
479
+ }
480
+
481
+ /**
482
+ * Computes the squared Euclidean length (straight-line length) of this quaternion,
483
+ * considered as a 4 dimensional vector. This can be useful if you are comparing the
484
+ * lengths of two quaternions, as this is a slightly more efficient calculation than
485
+ * {@link Quaternion#length}.
486
+ *
487
+ * @return The squared Euclidean length.
488
+ */
489
+ lengthSq(): number {
490
+ return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
491
+ }
492
+
493
+ /**
494
+ * Computes the Euclidean length (straight-line length) of this quaternion,
495
+ * considered as a 4 dimensional vector.
496
+ *
497
+ * @return The Euclidean length.
498
+ */
499
+ length(): number {
500
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
501
+ }
502
+
503
+ /**
504
+ * Normalizes this quaternion - that is, calculated the quaternion that performs
505
+ * the same rotation as this one, but has a length equal to `1`.
506
+ *
507
+ * @return A reference to this quaternion.
508
+ */
509
+ normalize(): Quaternion {
510
+ let l = this.length();
511
+
512
+ if (l === 0) {
513
+ this.x = 0;
514
+ this.y = 0;
515
+ this.z = 0;
516
+ this.w = 1;
517
+ } else {
518
+ l = 1 / l;
519
+
520
+ this.x = this.x * l;
521
+ this.y = this.y * l;
522
+ this.z = this.z * l;
523
+ this.w = this.w * l;
524
+ }
525
+
526
+
527
+ return this;
528
+ }
529
+
530
+ /**
531
+ * Multiplies this quaternion by the given one.
532
+ *
533
+ * @param q - The quaternion.
534
+ * @return A reference to this quaternion.
535
+ */
536
+ multiply(q: Quaternion): Quaternion {
537
+ return this.multiplyQuaternions(this, q);
538
+ }
539
+
540
+ /**
541
+ * Pre-multiplies this quaternion by the given one.
542
+ *
543
+ * @param q - The quaternion.
544
+ * @return A reference to this quaternion.
545
+ */
546
+ premultiply(q: Quaternion): Quaternion {
547
+ return this.multiplyQuaternions(q, this);
548
+ }
549
+
550
+ /**
551
+ * Multiplies the given quaternions and stores the result in this instance.
552
+ *
553
+ * @param a - The first quaternion.
554
+ * @param b - The second quaternion.
555
+ * @return A reference to this quaternion.
556
+ */
557
+ multiplyQuaternions(a: Quaternion, b: Quaternion): Quaternion {
558
+ // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
559
+ const qax = a.x,
560
+ qay = a.y,
561
+ qaz = a.z,
562
+ qaw = a.w;
563
+ const qbx = b.x,
564
+ qby = b.y,
565
+ qbz = b.z,
566
+ qbw = b.w;
567
+
568
+ this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
569
+ this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
570
+ this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
571
+ this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
572
+
573
+
574
+ return this;
575
+ }
576
+
577
+ /**
578
+ * Performs a spherical linear interpolation between quaternions.
579
+ *
580
+ * @param qb - The target quaternion.
581
+ * @param t - The interpolation factor in the closed interval `[0, 1]`.
582
+ * @return A reference to this quaternion.
583
+ */
584
+ slerp(qb: Quaternion, t: number): Quaternion {
585
+ if (t === 0) return this;
586
+ if (t === 1) return this.copy(qb);
587
+
588
+ const x = this.x,
589
+ y = this.y,
590
+ z = this.z,
591
+ w = this.w;
592
+
593
+ // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
594
+ let cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
595
+
596
+ if (cosHalfTheta < 0) {
597
+ this.w = -qb.w;
598
+ this.x = -qb.x;
599
+ this.y = -qb.y;
600
+ this.z = -qb.z;
601
+
602
+ cosHalfTheta = -cosHalfTheta;
603
+ } else {
604
+ this.copy(qb);
605
+ }
606
+
607
+ if (cosHalfTheta >= 1.0) {
608
+ this.w = w;
609
+ this.x = x;
610
+ this.y = y;
611
+ this.z = z;
612
+
613
+ return this;
614
+ }
615
+
616
+ const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
617
+
618
+ if (sqrSinHalfTheta <= Number.EPSILON) {
619
+ const s = 1 - t;
620
+ this.w = s * w + t * this.w;
621
+ this.x = s * x + t * this.x;
622
+ this.y = s * y + t * this.y;
623
+ this.z = s * z + t * this.z;
624
+
625
+ this.normalize(); // normalize calls _onChangeCallback()
626
+ return this;
627
+ }
628
+
629
+ const sinHalfTheta = Math.sqrt(sqrSinHalfTheta);
630
+ const halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta);
631
+ const ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
632
+ ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
633
+
634
+ this.w = w * ratioA + this.w * ratioB;
635
+ this.x = x * ratioA + this.x * ratioB;
636
+ this.y = y * ratioA + this.y * ratioB;
637
+ this.z = z * ratioA + this.z * ratioB;
638
+
639
+
640
+ return this;
641
+ }
642
+
643
+ /**
644
+ * Performs a spherical linear interpolation between the given quaternions
645
+ * and stores the result in this quaternion.
646
+ *
647
+ * @param qa - The source quaternion.
648
+ * @param qb - The target quaternion.
649
+ * @param t - The interpolation factor in the closed interval `[0, 1]`.
650
+ * @return A reference to this quaternion.
651
+ */
652
+ slerpQuaternions(qa: Quaternion, qb: Quaternion, t: number): Quaternion {
653
+ return this.copy(qa).slerp(qb, t);
654
+ }
655
+
656
+ /**
657
+ * Sets this quaternion to a uniformly random, normalized quaternion.
658
+ *
659
+ * @return A reference to this quaternion.
660
+ */
661
+ random(): Quaternion {
662
+ // Ken Shoemake
663
+ // Uniform random rotations
664
+ // D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992.
665
+ const theta1 = 2 * Math.PI * Math.random();
666
+ const theta2 = 2 * Math.PI * Math.random();
667
+
668
+ const x0 = Math.random();
669
+ const r1 = Math.sqrt(1 - x0);
670
+ const r2 = Math.sqrt(x0);
671
+
672
+ return this.set(r1 * Math.sin(theta1), r1 * Math.cos(theta1), r2 * Math.sin(theta2), r2 * Math.cos(theta2));
673
+ }
674
+
675
+ /**
676
+ * Returns `true` if this quaternion is equal with the given one.
677
+ *
678
+ * @param quaternion - The quaternion to test for equality.
679
+ * @return Whether this quaternion is equal with the given one.
680
+ */
681
+ equals(quaternion: Quaternion): boolean {
682
+ return quaternion.x === this.x && quaternion.y === this.y && quaternion.z === this.z && quaternion.w === this.w;
683
+ }
684
+
685
+ /**
686
+ * Sets this quaternion's components from the given array.
687
+ *
688
+ * @param array - An array holding the quaternion component values.
689
+ * @param offset - The offset into the array.
690
+ * @return A reference to this quaternion.
691
+ */
692
+ fromArray(array: number[], offset: number = 0): Quaternion {
693
+ this.x = array[offset];
694
+ this.y = array[offset + 1];
695
+ this.z = array[offset + 2];
696
+ this.w = array[offset + 3];
697
+
698
+
699
+ return this;
700
+ }
701
+
702
+ /**
703
+ * Writes the components of this quaternion to the given array. If no array is provided,
704
+ * the method returns a new instance.
705
+ *
706
+ * @param array - The target array holding the quaternion components.
707
+ * @param offset - Index of the first element in the array.
708
+ * @return The quaternion components.
709
+ */
710
+ toArray(array: number[] = [], offset: number = 0): number[] {
711
+ array[offset] = this.x;
712
+ array[offset + 1] = this.y;
713
+ array[offset + 2] = this.z;
714
+ array[offset + 3] = this.w;
715
+
716
+ return array;
717
+ }
718
+
719
+ /**
720
+ * This methods defines the serialization result of this class. Returns the
721
+ * numerical elements of this quaternion in an array of format `[x, y, z, w]`.
722
+ *
723
+ * @return The serialized quaternion.
724
+ */
725
+ toJSON(): number[] {
726
+ return this.toArray();
727
+ }
728
+
729
+ *[Symbol.iterator](): Generator<number> {
730
+ yield this.x;
731
+ yield this.y;
732
+ yield this.z;
733
+ yield this.w;
734
+ }
735
+ }
736
+
737
+ export { Quaternion };