@woosh/meep-engine 2.134.3 → 2.134.5

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Pure JavaScript game engine. Fully featured and production ready.",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.134.3",
8
+ "version": "2.134.5",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Closed-form solution for the rotation that best aligns two sets of unit
3
+ * vectors, via Horn (1987) "Closed-form solution of absolute orientation using
4
+ * unit quaternions".
5
+ *
6
+ * Given paired unit vectors {a_i} and {b_i}, finds the unit quaternion q such
7
+ * that rotating each b_i by q minimizes Σ |a_i − R(q)·b_i|².
8
+ *
9
+ * The matrix N is built so that the eigenvector of its largest eigenvalue
10
+ * IS the optimal rotation quaternion (in scalar-last form, matching meep's
11
+ * `Quaternion`).
12
+ *
13
+ * Inputs are unit vectors so no centroid subtraction is needed — the rotation
14
+ * is recovered from the cross-correlations alone.
15
+ *
16
+ * @param {Float32Array|number[]} a_xyz Source vectors — Length: count*3, unit length per triple
17
+ * @param {Float32Array|number[]} b_xyz Target vectors — Length: count*3, unit length per triple
18
+ * @param {number} count
19
+ * @param {Float32Array|number[]} out_quaternion Length 4 (x, y, z, w)
20
+ * @returns {number} The maximum eigenvalue ≈ Σ a_i · R·b_i. For a perfect alignment this equals `count`.
21
+ */
22
+ export function v3_rigid_align_paired_unit_vectors(a_xyz: Float32Array | number[], b_xyz: Float32Array | number[], count: number, out_quaternion: Float32Array | number[]): number;
23
+ //# sourceMappingURL=v3_rigid_align_paired_unit_vectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v3_rigid_align_paired_unit_vectors.d.ts","sourceRoot":"","sources":["../../../../../src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,0DANW,YAAY,GAAC,MAAM,EAAE,SACrB,YAAY,GAAC,MAAM,EAAE,SACrB,MAAM,kBACN,YAAY,GAAC,MAAM,EAAE,GACnB,MAAM,CAsElB"}
@@ -0,0 +1,96 @@
1
+ import { BinaryDataType } from "../../binary/type/BinaryDataType.js";
2
+ import { matrix_top_eigenvector_power_iteration } from "../../graph/eigen/matrix_top_eigenvector_power_iteration.js";
3
+ import { SquareMatrix } from "../../math/matrix/SquareMatrix.js"
4
+
5
+ const scratch_horn_n = new SquareMatrix(4, BinaryDataType.Float64);
6
+
7
+ /**
8
+ * Closed-form solution for the rotation that best aligns two sets of unit
9
+ * vectors, via Horn (1987) "Closed-form solution of absolute orientation using
10
+ * unit quaternions".
11
+ *
12
+ * Given paired unit vectors {a_i} and {b_i}, finds the unit quaternion q such
13
+ * that rotating each b_i by q minimizes Σ |a_i − R(q)·b_i|².
14
+ *
15
+ * The matrix N is built so that the eigenvector of its largest eigenvalue
16
+ * IS the optimal rotation quaternion (in scalar-last form, matching meep's
17
+ * `Quaternion`).
18
+ *
19
+ * Inputs are unit vectors so no centroid subtraction is needed — the rotation
20
+ * is recovered from the cross-correlations alone.
21
+ *
22
+ * @param {Float32Array|number[]} a_xyz Source vectors — Length: count*3, unit length per triple
23
+ * @param {Float32Array|number[]} b_xyz Target vectors — Length: count*3, unit length per triple
24
+ * @param {number} count
25
+ * @param {Float32Array|number[]} out_quaternion Length 4 (x, y, z, w)
26
+ * @returns {number} The maximum eigenvalue ≈ Σ a_i · R·b_i. For a perfect alignment this equals `count`.
27
+ */
28
+ export function v3_rigid_align_paired_unit_vectors(a_xyz, b_xyz, count, out_quaternion) {
29
+
30
+ // Cross-correlation matrix S_ij = Σ b_i_component * a_j_component
31
+ // Note: S is built as Σ b ⊗ aᵀ (Horn 1987 convention) — the rotation
32
+ // recovered will take b onto a.
33
+ let Sxx = 0, Sxy = 0, Sxz = 0;
34
+ let Syx = 0, Syy = 0, Syz = 0;
35
+ let Szx = 0, Szy = 0, Szz = 0;
36
+
37
+ for (let i = 0; i < count; i++) {
38
+ const i3 = i * 3;
39
+ const ax = a_xyz[i3], ay = a_xyz[i3 + 1], az = a_xyz[i3 + 2];
40
+ const bx = b_xyz[i3], by = b_xyz[i3 + 1], bz = b_xyz[i3 + 2];
41
+
42
+ Sxx += bx * ax;
43
+ Sxy += bx * ay;
44
+ Sxz += bx * az;
45
+ Syx += by * ax;
46
+ Syy += by * ay;
47
+ Syz += by * az;
48
+ Szx += bz * ax;
49
+ Szy += bz * ay;
50
+ Szz += bz * az;
51
+ }
52
+
53
+ // Horn's 4x4 symmetric matrix N (scalar-last quaternion ordering: x, y, z, w).
54
+ //
55
+ // From the paper, ordered for scalar-FIRST quaternion (w, x, y, z):
56
+ // N00 = Sxx + Syy + Szz N01 = Syz - Szy N02 = Szx - Sxz N03 = Sxy - Syx
57
+ // N11 = Sxx - Syy - Szz N12 = Sxy + Syx N13 = Szx + Sxz
58
+ // N22 = -Sxx + Syy - Szz N23 = Syz + Szy
59
+ // N33 = -Sxx - Syy + Szz
60
+ //
61
+ // We rebind to (x, y, z, w):
62
+ // row/col 0 = x, 1 = y, 2 = z, 3 = w
63
+ // i.e. swap original index 0 with 3 and shift others down.
64
+ const Nxx = Sxx - Syy - Szz;
65
+ const Nyy = -Sxx + Syy - Szz;
66
+ const Nzz = -Sxx - Syy + Szz;
67
+ const Nww = Sxx + Syy + Szz;
68
+ const Nxy = Sxy + Syx;
69
+ const Nxz = Szx + Sxz;
70
+ const Nxw = Syz - Szy;
71
+ const Nyz = Syz + Szy;
72
+ const Nyw = Szx - Sxz;
73
+ const Nzw = Sxy - Syx;
74
+
75
+ const N = scratch_horn_n;
76
+ const d = N.data;
77
+ // SquareMatrix is column-major: d[col * 4 + row]
78
+ d[0] = Nxx;
79
+ d[5] = Nyy;
80
+ d[10] = Nzz;
81
+ d[15] = Nww;
82
+ d[1] = Nxy;
83
+ d[4] = Nxy;
84
+ d[2] = Nxz;
85
+ d[8] = Nxz;
86
+ d[3] = Nxw;
87
+ d[12] = Nxw;
88
+ d[6] = Nyz;
89
+ d[9] = Nyz;
90
+ d[7] = Nyw;
91
+ d[13] = Nyw;
92
+ d[11] = Nzw;
93
+ d[14] = Nzw;
94
+
95
+ return matrix_top_eigenvector_power_iteration(N, out_quaternion);
96
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Find the eigenvector corresponding to the largest-magnitude eigenvalue of a
3
+ * symmetric square matrix using power iteration.
4
+ *
5
+ * Designed for small symmetric matrices where the dominant eigenvalue is
6
+ * well-separated from the rest (Horn's quaternion method on a 4x4, PCA on a
7
+ * 3x3 covariance, etc.). Unsuitable when the top two eigenvalues have nearly
8
+ * equal magnitude — convergence stalls in that regime.
9
+ *
10
+ * NOTE: intended to live in @woosh/meep-engine under core/graph/eigen/. Kept
11
+ * local for now.
12
+ *
13
+ * @param {SquareMatrix} matrix Symmetric, column-major as per SquareMatrix
14
+ * @param {number[]|Float32Array|Float64Array} out Eigenvector is written here, length >= matrix.size
15
+ * @param {number} [max_iterations=64]
16
+ * @param {number} [tolerance=1e-8] Convergence stops when ||v_next - v|| < tolerance
17
+ * @returns {number} The Rayleigh quotient (estimated eigenvalue)
18
+ */
19
+ export function matrix_top_eigenvector_power_iteration(matrix: SquareMatrix, out: number[] | Float32Array | Float64Array, max_iterations?: number, tolerance?: number): number;
20
+ //# sourceMappingURL=matrix_top_eigenvector_power_iteration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix_top_eigenvector_power_iteration.d.ts","sourceRoot":"","sources":["../../../../../src/core/graph/eigen/matrix_top_eigenvector_power_iteration.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;GAiBG;AACH,kFALW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,mBAClC,MAAM,cACN,MAAM,GACJ,MAAM,CAoFlB"}
@@ -0,0 +1,110 @@
1
+ import { assert } from "@woosh/meep-engine/src/core/assert.js";
2
+
3
+ let scratch_next = new Float64Array(16);
4
+
5
+ function ensure_scratch(n) {
6
+ if (scratch_next.length < n) scratch_next = new Float64Array(n);
7
+ return scratch_next;
8
+ }
9
+
10
+ /**
11
+ * Find the eigenvector corresponding to the largest-magnitude eigenvalue of a
12
+ * symmetric square matrix using power iteration.
13
+ *
14
+ * Designed for small symmetric matrices where the dominant eigenvalue is
15
+ * well-separated from the rest (Horn's quaternion method on a 4x4, PCA on a
16
+ * 3x3 covariance, etc.). Unsuitable when the top two eigenvalues have nearly
17
+ * equal magnitude — convergence stalls in that regime.
18
+ *
19
+ * NOTE: intended to live in @woosh/meep-engine under core/graph/eigen/. Kept
20
+ * local for now.
21
+ *
22
+ * @param {SquareMatrix} matrix Symmetric, column-major as per SquareMatrix
23
+ * @param {number[]|Float32Array|Float64Array} out Eigenvector is written here, length >= matrix.size
24
+ * @param {number} [max_iterations=64]
25
+ * @param {number} [tolerance=1e-8] Convergence stops when ||v_next - v|| < tolerance
26
+ * @returns {number} The Rayleigh quotient (estimated eigenvalue)
27
+ */
28
+ export function matrix_top_eigenvector_power_iteration(
29
+ matrix,
30
+ out,
31
+ max_iterations = 64,
32
+ tolerance = 1e-8
33
+ ) {
34
+ assert.defined(matrix, "matrix");
35
+ assert.defined(out, "out");
36
+
37
+ const n = matrix.size;
38
+ const data = matrix.data;
39
+
40
+ // Deterministic asymmetric initial vector. A uniform init (e.g. 1/√n in
41
+ // every slot) can be orthogonal to the dominant eigenvector when the matrix
42
+ // has block structure, stalling iteration on a sub-dominant eigenvalue.
43
+ // Irrational-component cosines avoid this for any reasonable n.
44
+ let init_norm_sq = 0;
45
+ for (let i = 0; i < n; i++) {
46
+ const v = Math.cos(i * 1.7 + 0.3);
47
+ out[i] = v;
48
+ init_norm_sq += v * v;
49
+ }
50
+ const init_inv = 1 / Math.sqrt(init_norm_sq);
51
+ for (let i = 0; i < n; i++) out[i] *= init_inv;
52
+
53
+ const next = ensure_scratch(n);
54
+ let eigenvalue = 0;
55
+
56
+ for (let iter = 0; iter < max_iterations; iter++) {
57
+ // next = matrix * out
58
+ // Column-major: data[col * n + row] is element at (row, col)
59
+ for (let row = 0; row < n; row++) {
60
+ let sum = 0;
61
+ for (let col = 0; col < n; col++) {
62
+ sum += data[col * n + row] * out[col];
63
+ }
64
+ next[row] = sum;
65
+ }
66
+
67
+ // Rayleigh quotient = out . next (since out is unit length and matrix is symmetric)
68
+ let rayleigh = 0;
69
+ for (let i = 0; i < n; i++) {
70
+ rayleigh += out[i] * next[i];
71
+ }
72
+
73
+ // Normalize next
74
+ let length_sqr = 0;
75
+ for (let i = 0; i < n; i++) {
76
+ length_sqr += next[i] * next[i];
77
+ }
78
+
79
+ if (length_sqr === 0) {
80
+ // Degenerate input — bail out, leave `out` as-is
81
+ return 0;
82
+ }
83
+
84
+ const inv_length = 1 / Math.sqrt(length_sqr);
85
+
86
+ // Sign-align next with out so we can measure convergence by raw difference.
87
+ // (Power iteration has a sign ambiguity per step when eigenvalue is negative.)
88
+ let dot = 0;
89
+ for (let i = 0; i < n; i++) {
90
+ dot += next[i] * out[i];
91
+ }
92
+ const sign = dot < 0 ? -inv_length : inv_length;
93
+
94
+ let delta_sqr = 0;
95
+ for (let i = 0; i < n; i++) {
96
+ const v = next[i] * sign;
97
+ const d = v - out[i];
98
+ delta_sqr += d * d;
99
+ out[i] = v;
100
+ }
101
+
102
+ eigenvalue = rayleigh;
103
+
104
+ if (delta_sqr < tolerance * tolerance) {
105
+ break;
106
+ }
107
+ }
108
+
109
+ return eigenvalue;
110
+ }
@@ -136,12 +136,15 @@ export class AnimationCurve implements Iterable<Keyframe> {
136
136
  */
137
137
  alignTangents(index: number): void;
138
138
  /**
139
- *
139
+ * @deprecated
140
140
  * @param {number} index Index of keyframe to be affected
141
141
  * @param {number} weight How much smoothing to apply, 1 will be fully smoothed out and 0 will have no effect at all. Value between 0 and 1
142
142
  */
143
143
  smoothTangents(index: number, weight: number): void;
144
- smoothAllTangents(): void;
144
+ /**
145
+ * Smooth out the curve
146
+ */
147
+ alignAllTangents(): void;
145
148
  /**
146
149
  * The copy is deep
147
150
  * @param {AnimationCurve} other
@@ -175,6 +178,11 @@ export class AnimationCurve implements Iterable<Keyframe> {
175
178
  * @type {boolean}
176
179
  */
177
180
  readonly isAnimationCurve: boolean;
181
+ /**
182
+ * Smooths out the curve.
183
+ * Alias to {@link alignAllTangents}.
184
+ */
185
+ smooth: () => void;
178
186
  /**
179
187
  * @deprecated use `getKeyIndexLow` instead
180
188
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AnimationCurve.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/curve/AnimationCurve.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,gDANwB,QAAQ;IAsZ5B;;;;OAIG;IACH,kBAHW,QAAQ,EAAE,GACR,cAAc,CAQ1B;IAED;;;;;;;;;OASG;IACH,6BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAUzB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,YACN,MAAM,UACN,MAAM,GACL,cAAc,CAOzB;IAED;;;;;;;OAOG;IACH,0BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAezB;IAndD;;;;;OAKG;IACH,eAFU,QAAQ,EAAE,CAEV;IAEV;;;;;OAKG;IACH,SAHW,QAAQ,GACN,MAAM,CAuClB;IAED;;;OAGG;IACH,cAFW,QAAQ,EAAE,QAUpB;IAED;;;;OAIG;IACH,YAHW,QAAQ,GACN,OAAO,CAYnB;IAED;;OAEG;IACH,cAEC;IAGD;;;OAGG;IACH,WAFY,OAAO,CAIlB;IAED;;;OAGG;IACH,qBAEC;IAED;;;;OAIG;IACH,yBAUC;IAED;;;;OAIG;IACH,uBAUC;IAED;;;;OAIG;IACH,uBAcC;IAED;;;;;;OAMG;IACH,qBAHW,MAAM,GACJ,MAAM,CAmDlB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACL,MAAM,CAoCjB;IAED;;;;OAIG;IACH,qBAFW,MAAM,QAmChB;IAED;;;;OAIG;IACH,sBAHW,MAAM,UACN,MAAM,QAWhB;IAED,0BAKC;IAGD;;;OAGG;IACH,YAFW,cAAc,QAIxB;IAED;;;OAGG;IACH,SAFY,cAAc,CAQzB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACb,OAAO,CAIlB;IAED;;;OAGG;IACH,QAFY,MAAM,CAIjB;IAED;;MAIC;IAED;;aAkBC;IAoFL;;;;OAIG;IACH,2BAFU,OAAO,CAEwB;IAGzC;;OAEG;IACH,0BA3Te,MAAM,KACJ,MAAM,CA0TmB;IA7FtC,wDAQC;CAuEJ;yBAhfwB,eAAe"}
1
+ {"version":3,"file":"AnimationCurve.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/curve/AnimationCurve.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,gDANwB,QAAQ;IAqZ5B;;;;OAIG;IACH,kBAHW,QAAQ,EAAE,GACR,cAAc,CAQ1B;IAED;;;;;;;;;OASG;IACH,6BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAUzB;IAED;;;;;;OAMG;IACH,4BALW,MAAM,YACN,MAAM,UACN,MAAM,GACL,cAAc,CAOzB;IAED;;;;;;;OAOG;IACH,0BANW,MAAM,eACN,MAAM,YACN,MAAM,aACN,MAAM,GACL,cAAc,CAezB;IAldD;;;;;OAKG;IACH,eAFU,QAAQ,EAAE,CAEV;IAEV;;;;;OAKG;IACH,SAHW,QAAQ,GACN,MAAM,CAuClB;IAED;;;OAGG;IACH,cAFW,QAAQ,EAAE,QAUpB;IAED;;;;OAIG;IACH,YAHW,QAAQ,GACN,OAAO,CAYnB;IAED;;OAEG;IACH,cAEC;IAGD;;;OAGG;IACH,WAFY,OAAO,CAIlB;IAED;;;OAGG;IACH,qBAEC;IAED;;;;OAIG;IACH,yBAUC;IAED;;;;OAIG;IACH,uBAUC;IAED;;;;OAIG;IACH,uBAcC;IAED;;;;;;OAMG;IACH,qBAHW,MAAM,GACJ,MAAM,CAmDlB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACL,MAAM,CAoCjB;IAED;;;;OAIG;IACH,qBAFW,MAAM,QAmChB;IAED;;;;OAIG;IACH,sBAHW,MAAM,UACN,MAAM,QAIhB;IAED;;OAEG;IACH,yBAQC;IAGD;;;OAGG;IACH,YAFW,cAAc,QAIxB;IAED;;;OAGG;IACH,SAFY,cAAc,CAQzB;IAED;;;;OAIG;IACH,cAHW,cAAc,GACb,OAAO,CAIlB;IAED;;;OAGG;IACH,QAFY,MAAM,CAIjB;IAED;;MAIC;IAED;;aAkBC;IAoFL;;;;OAIG;IACH,2BAFU,OAAO,CAEwB;IAGzC;;;OAGG;IACH,mBAA+B;IAE/B;;OAEG;IACH,0BAhUe,MAAM,KACJ,MAAM,CA+TmB;IAnGtC,wDAQC;CAuEJ;yBA/ewB,eAAe"}
@@ -1,7 +1,6 @@
1
1
  import { assert } from "../../../core/assert.js";
2
2
  import { computeHashArray } from "../../../core/collection/array/computeHashArray.js";
3
3
  import { isArrayEqual } from "../../../core/collection/array/isArrayEqual.js";
4
- import { lerp } from "../../../core/math/lerp.js";
5
4
  import { invokeObjectClone } from "../../../core/model/object/invokeObjectClone.js";
6
5
  import { invokeObjectHash } from "../../../core/model/object/invokeObjectHash.js";
7
6
  import { invokeObjectToJSON } from "../../../core/model/object/invokeObjectToJSON.js";
@@ -337,25 +336,24 @@ export class AnimationCurve {
337
336
  }
338
337
 
339
338
  /**
340
- *
339
+ * @deprecated
341
340
  * @param {number} index Index of keyframe to be affected
342
341
  * @param {number} weight How much smoothing to apply, 1 will be fully smoothed out and 0 will have no effect at all. Value between 0 and 1
343
342
  */
344
343
  smoothTangents(index, weight) {
345
- const keys = this.keys;
346
-
347
- const key = keys[index];
348
-
349
- const average = lerp(key.inTangent, key.outTangent, 0.5);
350
-
351
- key.inTangent = lerp(key.inTangent, average, weight);
352
- key.outTangent = lerp(key.outTangent, average, weight);
344
+ throw new Error('Deprecated, use alignTagents() instead');
353
345
  }
354
346
 
355
- smoothAllTangents() {
347
+ /**
348
+ * Smooth out the curve
349
+ */
350
+ alignAllTangents() {
356
351
  const n = this.length;
352
+
353
+ // TODO add support for looping curves
354
+
357
355
  for (let i = 0; i < n; i++) {
358
- this.smoothTangents(i, 1);
356
+ this.alignTangents(i);
359
357
  }
360
358
  }
361
359
 
@@ -513,6 +511,12 @@ export class AnimationCurve {
513
511
  AnimationCurve.prototype.isAnimationCurve = true;
514
512
 
515
513
 
514
+ /**
515
+ * Smooths out the curve.
516
+ * Alias to {@link alignAllTangents}.
517
+ */
518
+ AnimationCurve.prototype.smooth = AnimationCurve.prototype.alignAllTangents;
519
+
516
520
  /**
517
521
  * @deprecated use `getKeyIndexLow` instead
518
522
  */
@@ -81,6 +81,6 @@ for (let i = 0; i < keys.length; i++) {
81
81
 
82
82
  curve.alignTangents(i);
83
83
  }
84
- curve.smoothAllTangents();
84
+ curve.alignAllTangents();
85
85
 
86
86
  addCurve(curve)