xl-public-utils 1.0.11 → 1.0.13

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.
@@ -0,0 +1,584 @@
1
+ import * as MathUtils from './MathUtils.js';
2
+
3
+ class Quaternion {
4
+ constructor(x = 0, y = 0, z = 0, w = 1) {
5
+ this.isQuaternion = true;
6
+
7
+ this._x = x;
8
+ this._y = y;
9
+ this._z = z;
10
+ this._w = w;
11
+ }
12
+
13
+ static slerp(qa, qb, qm, t) {
14
+ console.warn('THREE.Quaternion: Static .slerp() has been deprecated. Use qm.slerpQuaternions( qa, qb, t ) instead.');
15
+ return qm.slerpQuaternions(qa, qb, t);
16
+ }
17
+
18
+ static slerpFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t) {
19
+ // fuzz-free, array-based Quaternion SLERP operation
20
+
21
+ let x0 = src0[srcOffset0 + 0],
22
+ y0 = src0[srcOffset0 + 1],
23
+ z0 = src0[srcOffset0 + 2],
24
+ w0 = src0[srcOffset0 + 3];
25
+
26
+ const x1 = src1[srcOffset1 + 0],
27
+ y1 = src1[srcOffset1 + 1],
28
+ z1 = src1[srcOffset1 + 2],
29
+ w1 = src1[srcOffset1 + 3];
30
+
31
+ if (t === 0) {
32
+ dst[dstOffset + 0] = x0;
33
+ dst[dstOffset + 1] = y0;
34
+ dst[dstOffset + 2] = z0;
35
+ dst[dstOffset + 3] = w0;
36
+ return;
37
+ }
38
+
39
+ if (t === 1) {
40
+ dst[dstOffset + 0] = x1;
41
+ dst[dstOffset + 1] = y1;
42
+ dst[dstOffset + 2] = z1;
43
+ dst[dstOffset + 3] = w1;
44
+ return;
45
+ }
46
+
47
+ if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1) {
48
+ let s = 1 - t;
49
+ const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
50
+ dir = cos >= 0 ? 1 : -1,
51
+ sqrSin = 1 - cos * cos;
52
+
53
+ // Skip the Slerp for tiny steps to avoid numeric problems:
54
+ if (sqrSin > Number.EPSILON) {
55
+ const sin = Math.sqrt(sqrSin),
56
+ len = Math.atan2(sin, cos * dir);
57
+
58
+ s = Math.sin(s * len) / sin;
59
+ t = Math.sin(t * len) / sin;
60
+ }
61
+
62
+ const tDir = t * dir;
63
+
64
+ x0 = x0 * s + x1 * tDir;
65
+ y0 = y0 * s + y1 * tDir;
66
+ z0 = z0 * s + z1 * tDir;
67
+ w0 = w0 * s + w1 * tDir;
68
+
69
+ // Normalize in case we just did a lerp:
70
+ if (s === 1 - t) {
71
+ const f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0);
72
+
73
+ x0 *= f;
74
+ y0 *= f;
75
+ z0 *= f;
76
+ w0 *= f;
77
+ }
78
+ }
79
+
80
+ dst[dstOffset] = x0;
81
+ dst[dstOffset + 1] = y0;
82
+ dst[dstOffset + 2] = z0;
83
+ dst[dstOffset + 3] = w0;
84
+ }
85
+
86
+ static multiplyQuaternionsFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1) {
87
+ const x0 = src0[srcOffset0];
88
+ const y0 = src0[srcOffset0 + 1];
89
+ const z0 = src0[srcOffset0 + 2];
90
+ const w0 = src0[srcOffset0 + 3];
91
+
92
+ const x1 = src1[srcOffset1];
93
+ const y1 = src1[srcOffset1 + 1];
94
+ const z1 = src1[srcOffset1 + 2];
95
+ const w1 = src1[srcOffset1 + 3];
96
+
97
+ dst[dstOffset] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
98
+ dst[dstOffset + 1] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
99
+ dst[dstOffset + 2] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
100
+ dst[dstOffset + 3] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
101
+
102
+ return dst;
103
+ }
104
+
105
+ get x() {
106
+ return this._x;
107
+ }
108
+
109
+ set x(value) {
110
+ this._x = value;
111
+ this._onChangeCallback();
112
+ }
113
+
114
+ get y() {
115
+ return this._y;
116
+ }
117
+
118
+ set y(value) {
119
+ this._y = value;
120
+ this._onChangeCallback();
121
+ }
122
+
123
+ get z() {
124
+ return this._z;
125
+ }
126
+
127
+ set z(value) {
128
+ this._z = value;
129
+ this._onChangeCallback();
130
+ }
131
+
132
+ get w() {
133
+ return this._w;
134
+ }
135
+
136
+ set w(value) {
137
+ this._w = value;
138
+ this._onChangeCallback();
139
+ }
140
+
141
+ set(x, y, z, w) {
142
+ this._x = x;
143
+ this._y = y;
144
+ this._z = z;
145
+ this._w = w;
146
+
147
+ this._onChangeCallback();
148
+
149
+ return this;
150
+ }
151
+
152
+ clone() {
153
+ return new this.constructor(this._x, this._y, this._z, this._w);
154
+ }
155
+
156
+ copy(quaternion) {
157
+ this._x = quaternion.x;
158
+ this._y = quaternion.y;
159
+ this._z = quaternion.z;
160
+ this._w = quaternion.w;
161
+
162
+ this._onChangeCallback();
163
+
164
+ return this;
165
+ }
166
+
167
+ setFromEuler(euler, update) {
168
+ if (!(euler && euler.isEuler)) {
169
+ throw new Error('THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.');
170
+ }
171
+
172
+ const x = euler._x,
173
+ y = euler._y,
174
+ z = euler._z,
175
+ order = euler._order;
176
+
177
+ // http://www.mathworks.com/matlabcentral/fileexchange/
178
+ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
179
+ // content/SpinCalc.m
180
+
181
+ const cos = Math.cos;
182
+ const sin = Math.sin;
183
+
184
+ const c1 = cos(x / 2);
185
+ const c2 = cos(y / 2);
186
+ const c3 = cos(z / 2);
187
+
188
+ const s1 = sin(x / 2);
189
+ const s2 = sin(y / 2);
190
+ const s3 = sin(z / 2);
191
+
192
+ switch (order) {
193
+ case 'XYZ':
194
+ this._x = s1 * c2 * c3 + c1 * s2 * s3;
195
+ this._y = c1 * s2 * c3 - s1 * c2 * s3;
196
+ this._z = c1 * c2 * s3 + s1 * s2 * c3;
197
+ this._w = c1 * c2 * c3 - s1 * s2 * s3;
198
+ break;
199
+
200
+ case 'YXZ':
201
+ this._x = s1 * c2 * c3 + c1 * s2 * s3;
202
+ this._y = c1 * s2 * c3 - s1 * c2 * s3;
203
+ this._z = c1 * c2 * s3 - s1 * s2 * c3;
204
+ this._w = c1 * c2 * c3 + s1 * s2 * s3;
205
+ break;
206
+
207
+ case 'ZXY':
208
+ this._x = s1 * c2 * c3 - c1 * s2 * s3;
209
+ this._y = c1 * s2 * c3 + s1 * c2 * s3;
210
+ this._z = c1 * c2 * s3 + s1 * s2 * c3;
211
+ this._w = c1 * c2 * c3 - s1 * s2 * s3;
212
+ break;
213
+
214
+ case 'ZYX':
215
+ this._x = s1 * c2 * c3 - c1 * s2 * s3;
216
+ this._y = c1 * s2 * c3 + s1 * c2 * s3;
217
+ this._z = c1 * c2 * s3 - s1 * s2 * c3;
218
+ this._w = c1 * c2 * c3 + s1 * s2 * s3;
219
+ break;
220
+
221
+ case 'YZX':
222
+ this._x = s1 * c2 * c3 + c1 * s2 * s3;
223
+ this._y = c1 * s2 * c3 + s1 * c2 * s3;
224
+ this._z = c1 * c2 * s3 - s1 * s2 * c3;
225
+ this._w = c1 * c2 * c3 - s1 * s2 * s3;
226
+ break;
227
+
228
+ case 'XZY':
229
+ this._x = s1 * c2 * c3 - c1 * s2 * s3;
230
+ this._y = c1 * s2 * c3 - s1 * c2 * s3;
231
+ this._z = c1 * c2 * s3 + s1 * s2 * c3;
232
+ this._w = c1 * c2 * c3 + s1 * s2 * s3;
233
+ break;
234
+
235
+ default:
236
+ console.warn('THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order);
237
+ }
238
+
239
+ if (update !== false) this._onChangeCallback();
240
+
241
+ return this;
242
+ }
243
+
244
+ setFromAxisAngle(axis, angle) {
245
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
246
+
247
+ // assumes axis is normalized
248
+
249
+ const halfAngle = angle / 2,
250
+ s = Math.sin(halfAngle);
251
+
252
+ this._x = axis.x * s;
253
+ this._y = axis.y * s;
254
+ this._z = axis.z * s;
255
+ this._w = Math.cos(halfAngle);
256
+
257
+ this._onChangeCallback();
258
+
259
+ return this;
260
+ }
261
+
262
+ setFromRotationMatrix(m) {
263
+ // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
264
+
265
+ // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
266
+
267
+ const te = m.elements,
268
+ m11 = te[0],
269
+ m12 = te[4],
270
+ m13 = te[8],
271
+ m21 = te[1],
272
+ m22 = te[5],
273
+ m23 = te[9],
274
+ m31 = te[2],
275
+ m32 = te[6],
276
+ m33 = te[10],
277
+ trace = m11 + m22 + m33;
278
+
279
+ if (trace > 0) {
280
+ const s = 0.5 / Math.sqrt(trace + 1.0);
281
+
282
+ this._w = 0.25 / s;
283
+ this._x = (m32 - m23) * s;
284
+ this._y = (m13 - m31) * s;
285
+ this._z = (m21 - m12) * s;
286
+ } else if (m11 > m22 && m11 > m33) {
287
+ const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
288
+
289
+ this._w = (m32 - m23) / s;
290
+ this._x = 0.25 * s;
291
+ this._y = (m12 + m21) / s;
292
+ this._z = (m13 + m31) / s;
293
+ } else if (m22 > m33) {
294
+ const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
295
+
296
+ this._w = (m13 - m31) / s;
297
+ this._x = (m12 + m21) / s;
298
+ this._y = 0.25 * s;
299
+ this._z = (m23 + m32) / s;
300
+ } else {
301
+ const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
302
+
303
+ this._w = (m21 - m12) / s;
304
+ this._x = (m13 + m31) / s;
305
+ this._y = (m23 + m32) / s;
306
+ this._z = 0.25 * s;
307
+ }
308
+
309
+ this._onChangeCallback();
310
+
311
+ return this;
312
+ }
313
+
314
+ setFromUnitVectors(vFrom, vTo) {
315
+ // assumes direction vectors vFrom and vTo are normalized
316
+
317
+ let r = vFrom.dot(vTo) + 1;
318
+
319
+ if (r < Number.EPSILON) {
320
+ // vFrom and vTo point in opposite directions
321
+
322
+ r = 0;
323
+
324
+ if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
325
+ this._x = -vFrom.y;
326
+ this._y = vFrom.x;
327
+ this._z = 0;
328
+ this._w = r;
329
+ } else {
330
+ this._x = 0;
331
+ this._y = -vFrom.z;
332
+ this._z = vFrom.y;
333
+ this._w = r;
334
+ }
335
+ } else {
336
+ // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
337
+
338
+ this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
339
+ this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
340
+ this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
341
+ this._w = r;
342
+ }
343
+
344
+ return this.normalize();
345
+ }
346
+
347
+ angleTo(q) {
348
+ return 2 * Math.acos(Math.abs(MathUtils.clamp(this.dot(q), -1, 1)));
349
+ }
350
+
351
+ rotateTowards(q, step) {
352
+ const angle = this.angleTo(q);
353
+
354
+ if (angle === 0) return this;
355
+
356
+ const t = Math.min(1, step / angle);
357
+
358
+ this.slerp(q, t);
359
+
360
+ return this;
361
+ }
362
+
363
+ identity() {
364
+ return this.set(0, 0, 0, 1);
365
+ }
366
+
367
+ invert() {
368
+ // quaternion is assumed to have unit length
369
+
370
+ return this.conjugate();
371
+ }
372
+
373
+ conjugate() {
374
+ this._x *= -1;
375
+ this._y *= -1;
376
+ this._z *= -1;
377
+
378
+ this._onChangeCallback();
379
+
380
+ return this;
381
+ }
382
+
383
+ dot(v) {
384
+ return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
385
+ }
386
+
387
+ lengthSq() {
388
+ return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
389
+ }
390
+
391
+ length() {
392
+ return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w);
393
+ }
394
+
395
+ normalize() {
396
+ let l = this.length();
397
+
398
+ if (l === 0) {
399
+ this._x = 0;
400
+ this._y = 0;
401
+ this._z = 0;
402
+ this._w = 1;
403
+ } else {
404
+ l = 1 / l;
405
+
406
+ this._x = this._x * l;
407
+ this._y = this._y * l;
408
+ this._z = this._z * l;
409
+ this._w = this._w * l;
410
+ }
411
+
412
+ this._onChangeCallback();
413
+
414
+ return this;
415
+ }
416
+
417
+ multiply(q, p) {
418
+ if (p !== undefined) {
419
+ console.warn('THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.');
420
+ return this.multiplyQuaternions(q, p);
421
+ }
422
+
423
+ return this.multiplyQuaternions(this, q);
424
+ }
425
+
426
+ premultiply(q) {
427
+ return this.multiplyQuaternions(q, this);
428
+ }
429
+
430
+ multiplyQuaternions(a, b) {
431
+ // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
432
+
433
+ const qax = a._x,
434
+ qay = a._y,
435
+ qaz = a._z,
436
+ qaw = a._w;
437
+ const qbx = b._x,
438
+ qby = b._y,
439
+ qbz = b._z,
440
+ qbw = b._w;
441
+
442
+ this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
443
+ this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
444
+ this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
445
+ this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
446
+
447
+ this._onChangeCallback();
448
+
449
+ return this;
450
+ }
451
+
452
+ slerp(qb, t) {
453
+ if (t === 0) return this;
454
+ if (t === 1) return this.copy(qb);
455
+
456
+ const x = this._x,
457
+ y = this._y,
458
+ z = this._z,
459
+ w = this._w;
460
+
461
+ // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
462
+
463
+ let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
464
+
465
+ if (cosHalfTheta < 0) {
466
+ this._w = -qb._w;
467
+ this._x = -qb._x;
468
+ this._y = -qb._y;
469
+ this._z = -qb._z;
470
+
471
+ cosHalfTheta = -cosHalfTheta;
472
+ } else {
473
+ this.copy(qb);
474
+ }
475
+
476
+ if (cosHalfTheta >= 1.0) {
477
+ this._w = w;
478
+ this._x = x;
479
+ this._y = y;
480
+ this._z = z;
481
+
482
+ return this;
483
+ }
484
+
485
+ const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
486
+
487
+ if (sqrSinHalfTheta <= Number.EPSILON) {
488
+ const s = 1 - t;
489
+ this._w = s * w + t * this._w;
490
+ this._x = s * x + t * this._x;
491
+ this._y = s * y + t * this._y;
492
+ this._z = s * z + t * this._z;
493
+
494
+ this.normalize();
495
+ this._onChangeCallback();
496
+
497
+ return this;
498
+ }
499
+
500
+ const sinHalfTheta = Math.sqrt(sqrSinHalfTheta);
501
+ const halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta);
502
+ const ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
503
+ ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
504
+
505
+ this._w = w * ratioA + this._w * ratioB;
506
+ this._x = x * ratioA + this._x * ratioB;
507
+ this._y = y * ratioA + this._y * ratioB;
508
+ this._z = z * ratioA + this._z * ratioB;
509
+
510
+ this._onChangeCallback();
511
+
512
+ return this;
513
+ }
514
+
515
+ slerpQuaternions(qa, qb, t) {
516
+ return this.copy(qa).slerp(qb, t);
517
+ }
518
+
519
+ random() {
520
+ // Derived from http://planning.cs.uiuc.edu/node198.html
521
+ // Note, this source uses w, x, y, z ordering,
522
+ // so we swap the order below.
523
+
524
+ const u1 = Math.random();
525
+ const sqrt1u1 = Math.sqrt(1 - u1);
526
+ const sqrtu1 = Math.sqrt(u1);
527
+
528
+ const u2 = 2 * Math.PI * Math.random();
529
+
530
+ const u3 = 2 * Math.PI * Math.random();
531
+
532
+ return this.set(sqrt1u1 * Math.cos(u2), sqrtu1 * Math.sin(u3), sqrtu1 * Math.cos(u3), sqrt1u1 * Math.sin(u2));
533
+ }
534
+
535
+ equals(quaternion) {
536
+ return quaternion._x === this._x && quaternion._y === this._y && quaternion._z === this._z && quaternion._w === this._w;
537
+ }
538
+
539
+ fromArray(array, offset = 0) {
540
+ this._x = array[offset];
541
+ this._y = array[offset + 1];
542
+ this._z = array[offset + 2];
543
+ this._w = array[offset + 3];
544
+
545
+ this._onChangeCallback();
546
+
547
+ return this;
548
+ }
549
+
550
+ toArray(array = [], offset = 0) {
551
+ array[offset] = this._x;
552
+ array[offset + 1] = this._y;
553
+ array[offset + 2] = this._z;
554
+ array[offset + 3] = this._w;
555
+
556
+ return array;
557
+ }
558
+
559
+ fromBufferAttribute(attribute, index) {
560
+ this._x = attribute.getX(index);
561
+ this._y = attribute.getY(index);
562
+ this._z = attribute.getZ(index);
563
+ this._w = attribute.getW(index);
564
+
565
+ return this;
566
+ }
567
+
568
+ _onChange(callback) {
569
+ this._onChangeCallback = callback;
570
+
571
+ return this;
572
+ }
573
+
574
+ _onChangeCallback() {}
575
+
576
+ *[Symbol.iterator]() {
577
+ yield this._x;
578
+ yield this._y;
579
+ yield this._z;
580
+ yield this._w;
581
+ }
582
+ }
583
+
584
+ export { Quaternion };