@woosh/meep-engine 2.95.0 → 2.96.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.
Files changed (35) hide show
  1. package/build/meep.cjs +175 -140
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +175 -140
  4. package/package.json +1 -2
  5. package/src/core/collection/array/arrayPickBestElement.d.ts.map +1 -1
  6. package/src/core/collection/array/arrayPickBestElement.js +3 -3
  7. package/src/core/collection/array/arrayPickBestElements.d.ts +2 -2
  8. package/src/core/collection/array/arrayPickBestElements.d.ts.map +1 -1
  9. package/src/core/collection/array/arrayPickBestElements.js +3 -3
  10. package/src/core/geom/2d/hash-grid/SpatialHashGrid.spec.js +1 -1
  11. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.spec.js +1 -1
  12. package/src/core/geom/Quaternion.d.ts.map +1 -1
  13. package/src/core/geom/Quaternion.js +14 -8
  14. package/src/core/localization/Localization.d.ts.map +1 -1
  15. package/src/core/localization/Localization.js +11 -11
  16. package/src/core/math/epsilonEquals.d.ts.map +1 -1
  17. package/src/core/math/epsilonEquals.js +1 -0
  18. package/src/core/math/epsilonEquals.spec.d.ts +2 -0
  19. package/src/core/math/epsilonEquals.spec.d.ts.map +1 -0
  20. package/src/core/math/epsilonEquals.spec.js +17 -0
  21. package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
  22. package/src/core/model/node-graph/node/NodeInstance.js +8 -2
  23. package/src/core/primitives/strings/string_compute_similarity.d.ts +6 -0
  24. package/src/core/primitives/strings/string_compute_similarity.d.ts.map +1 -0
  25. package/src/core/primitives/strings/string_compute_similarity.js +7 -0
  26. package/src/core/primitives/strings/string_jaro_winkler.d.ts +8 -0
  27. package/src/core/primitives/strings/string_jaro_winkler.d.ts.map +1 -0
  28. package/src/core/primitives/strings/string_jaro_winkler.js +153 -0
  29. package/src/core/primitives/strings/string_jaro_winkler.spec.d.ts +2 -0
  30. package/src/core/primitives/strings/string_jaro_winkler.spec.d.ts.map +1 -0
  31. package/src/core/primitives/strings/string_jaro_winkler.spec.js +39 -0
  32. package/src/engine/graphics/ecs/mesh/SkeletonUtils.d.ts.map +1 -1
  33. package/src/engine/graphics/ecs/mesh/SkeletonUtils.js +5 -14
  34. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.js +3 -3
  35. package/src/engine/graphics/texture/sampler/HarmonicDiffusionGrid.spec.js +2 -2
@@ -0,0 +1,17 @@
1
+ import { epsilonEquals } from "./epsilonEquals.js";
2
+
3
+ test("basics", () => {
4
+
5
+ expect(epsilonEquals(0, 0, 0)).toBe(true);
6
+ expect(epsilonEquals(0, 1, 0)).toBe(false);
7
+ expect(epsilonEquals(1, 0, 0)).toBe(false);
8
+ expect(epsilonEquals(-1, 0, 0)).toBe(false);
9
+ expect(epsilonEquals(-1, 1, 0)).toBe(false);
10
+ expect(epsilonEquals(1, -1, 0)).toBe(false);
11
+
12
+ expect(epsilonEquals(1, 1.1, 0)).toBe(false);
13
+ expect(epsilonEquals(1, 1, 0.1)).toBe(true);
14
+ expect(epsilonEquals(1, 1.09, 0.1)).toBe(true);
15
+ expect(epsilonEquals(1, 1.11, 0.1)).toBe(false);
16
+
17
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"NodeInstance.d.ts","sourceRoot":"","sources":["../../../../../../src/core/model/node-graph/node/NodeInstance.js"],"names":[],"mappings":"AAcA;IAEI;;;OAGG;IACH,IAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,6BAAmB;IAEnB;;;OAGG;IACH,WAFU,yBAAyB,EAAE,CAEtB;IAEf;;;OAGG;IACH,gBAAgB;IAEhB;;;OAGG;IACH,qBAAmB;IAEnB;;;OAGG;IACH,aAFU,gBAAgB,CAED;IAEzB;;;;;;OAMG;IACH,wBAFU,MAAM,CAEE;IAElB;;OAEG;IACH;QACI;;;WAGG;mCADO,OAAO,MAAM,WAAO;QAG9B;;;WAGG;iCADO,OAAO,MAAM,MAAI;QAG3B;;;WAGG;mCADO,OAAO,MAAM,MAAI;QAI3B;;;;WAIG;qCADO,wCAAwC;MAGpD;IAEF;;;;;;OAMG;IACH,yBALW,MAAM,aACN,aAAa,UACb,YAAY,GACV,MAAM,CAsBlB;IAED;;;OAGG;IACH,gDAEC;IAED;;;OAGG;IACH,+CAEC;IAGD;;;OAGG;IACH,mCAEC;IAED;;;;OAIG;IACH,kCAEC;IAED;;;;OAIG;IACH,mBAHW,MAAM,oBAKhB;IAED;;;;OAIG;IACH,mBAHW,MAAM,OAKhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,KAOhB;IAED;;;;OAIG;IACH,2BAHW,MAAM,oBAmChB;IAED;;;;OAIG;IACH,oBAHW,MAAM,GACJ,OAAO,CAkBnB;IAED;;;OAGG;IACH,uCAQC;IAED,wBAIC;IAED;;;OAGG;IACH,mDAqCC;IAED;;;;OAIG;IACH,kBAHW,MAAM,GACJ,yBAAyB,GAAC,SAAS,CAe/C;IAED,eAEC;IAED;;;;OAIG;IACH,cAHW,YAAY,GACV,OAAO,CAQnB;IAED,mBAEC;IAIL;;;OAGG;IACH,yBAFU,OAAO,CAEoB;CAPpC;0CArVyC,gCAAgC;iBAHzD,kCAAkC;mBAChC,kCAAkC;8BAGvB,oBAAoB"}
1
+ {"version":3,"file":"NodeInstance.d.ts","sourceRoot":"","sources":["../../../../../../src/core/model/node-graph/node/NodeInstance.js"],"names":[],"mappings":"AAcA;;;;GAIG;AACH;IAEI;;;;OAIG;IACH,aAFU,MAAM,CAEE;IAElB;;;OAGG;IACH,6BAAmB;IAEnB;;;OAGG;IACH,WAFU,yBAAyB,EAAE,CAEtB;IAEf;;;OAGG;IACH,gBAAgB;IAEhB;;;OAGG;IACH,qBAAmB;IAEnB;;;OAGG;IACH,aAFU,gBAAgB,CAED;IAEzB;;;;;;OAMG;IACH,wBAFU,MAAM,CAEE;IAElB;;OAEG;IACH;QACI;;;WAGG;mCADO,OAAO,MAAM,WAAO;QAG9B;;;WAGG;iCADO,OAAO,MAAM,MAAI;QAG3B;;;WAGG;mCADO,OAAO,MAAM,MAAI;QAI3B;;;;WAIG;qCADO,wCAAwC;MAGpD;IAEF;;;;;;OAMG;IACH,yBALW,MAAM,aACN,aAAa,UACb,YAAY,GACV,MAAM,CAsBlB;IAED;;;OAGG;IACH,gDAEC;IAED;;;OAGG;IACH,+CAEC;IAGD;;;OAGG;IACH,mCAEC;IAED;;;;OAIG;IACH,kCAEC;IAED;;;;OAIG;IACH,mBAHW,MAAM,oBAKhB;IAED;;;;OAIG;IACH,mBAHW,MAAM,OAKhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,KAOhB;IAED;;;;OAIG;IACH,2BAHW,MAAM,oBAmChB;IAED;;;;OAIG;IACH,oBAHW,MAAM,GACJ,OAAO,CAkBnB;IAED;;;OAGG;IACH,uCAQC;IAED,wBAIC;IAED;;;OAGG;IACH,mDAqCC;IAED;;;;OAIG;IACH,kBAHW,MAAM,GACJ,yBAAyB,GAAC,SAAS,CAe/C;IAED,eAEC;IAED;;;;OAIG;IACH,cAHW,YAAY,GACV,OAAO,CAQnB;IAED,mBAEC;IAIL;;;OAGG;IACH,yBAFU,OAAO,CAEoB;CAPpC;0CA3VyC,gCAAgC;iBAHzD,kCAAkC;mBAChC,kCAAkC;8BAGvB,oBAAoB"}
@@ -12,10 +12,16 @@ import { PortDirection } from "./PortDirection.js";
12
12
  */
13
13
  let id_counter = 0;
14
14
 
15
+ /**
16
+ * Represents a node instance in a graph, its main purpose is to provide connection medium for the graph.
17
+ * A useful analogy is that of a "class" and an "object", there can be multiple instances (objects) of the same class. In this analogy `NodeInstance` is the object, and `NodeDescription` is a class.
18
+ * There can be multiple `NodeInstance`s referencing the same `NodeDescription`.
19
+ */
15
20
  export class NodeInstance {
16
21
 
17
22
  /**
18
- *
23
+ * Unique identifier
24
+ * @readonly
19
25
  * @type {number}
20
26
  */
21
27
  id = id_counter++;
@@ -342,7 +348,7 @@ export class NodeInstance {
342
348
  }
343
349
 
344
350
  toString() {
345
- return `NodeInstance{ id = ${this.id}, description = ${this.description.id} }`
351
+ return `NodeInstance{ id = ${this.id}, description = ${this.description?.id} }`
346
352
  }
347
353
  }
348
354
 
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Higher value means string are more similar
3
+ * @type {(function(string, string): number)}
4
+ */
5
+ export const string_compute_similarity: ((arg0: string, arg1: string) => number);
6
+ //# sourceMappingURL=string_compute_similarity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string_compute_similarity.d.ts","sourceRoot":"","sources":["../../../../../src/core/primitives/strings/string_compute_similarity.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wCAFU,QAAU,MAAM,QAAE,MAAM,KAAG,MAAM,CAAC,CAEiB"}
@@ -0,0 +1,7 @@
1
+ import { string_jaro_winkler } from "./string_jaro_winkler.js";
2
+
3
+ /**
4
+ * Higher value means string are more similar
5
+ * @type {(function(string, string): number)}
6
+ */
7
+ export const string_compute_similarity = string_jaro_winkler;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Calculate the Jaro-Winkler distance between two strings
3
+ * @param {string} first The string to compare
4
+ * @param {string} second The string to compare with
5
+ * @returns {number} similarity score, higher value means strings are more similar
6
+ */
7
+ export function string_jaro_winkler(first: string, second: string): number;
8
+ //# sourceMappingURL=string_jaro_winkler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string_jaro_winkler.d.ts","sourceRoot":"","sources":["../../../../../src/core/primitives/strings/string_jaro_winkler.js"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,2CAJW,MAAM,UACN,MAAM,GACJ,MAAM,CA6BlB"}
@@ -0,0 +1,153 @@
1
+ import { BitSet } from "../../binary/BitSet.js";
2
+ import { max2 } from "../../math/max2.js";
3
+ import { min2 } from "../../math/min2.js";
4
+ import { min3 } from "../../math/min3.js";
5
+
6
+ /**
7
+ * Calculate the Jaro-Winkler distance between two strings
8
+ * @param {string} first The string to compare
9
+ * @param {string} second The string to compare with
10
+ * @returns {number} similarity score, higher value means strings are more similar
11
+ */
12
+ export function string_jaro_winkler(first, second) {
13
+ const l1 = first.length;
14
+ const l2 = second.length;
15
+
16
+ if (l1 === 0 && l2 === 0) {
17
+ // special case for empty string
18
+ return 1;
19
+ }
20
+
21
+ const matches1 = BitSet.fixedSize(l1);
22
+ const matches2 = BitSet.fixedSize(l2);
23
+
24
+ const matches = getMatching(first, second, matches1, matches2);
25
+
26
+ if (matches <= 0) {
27
+ return 0;
28
+ }
29
+
30
+ // Calculate the Jaro distance:
31
+ const transpositions = getTranspositions(first, second, matches1, matches2);
32
+ const similarity = (matches / l1 + matches / l2 + (matches - transpositions) / matches) / 3;
33
+
34
+ // Transform to Jaro-Winkler:
35
+ // Prefix scale gives more favorable ratings to strings that share common prefixes:
36
+ const prefix_scale = 0.1;
37
+ const prefix = getPrefix(first, second, min3(l1, l2, 4));
38
+ return similarity + prefix * prefix_scale * (1 - similarity);
39
+ }
40
+
41
+ /**
42
+ * Find matching characters in both strings according to Jaro algorithm
43
+ * @param {string} a1
44
+ * @param {string} a2
45
+ * @param {BitSet} matches1
46
+ * @param {BitSet} matches2
47
+ * @return {number}
48
+ */
49
+ function getMatching(a1, a2, matches1, matches2) {
50
+ const a1_length = a1.length;
51
+ const a2_length = a2.length;
52
+
53
+ // Window is modified to work with string of length 1
54
+ const matchWindow = max2(
55
+ 0,
56
+ Math.floor(max2(a1_length, a2_length) * 0.5) - 1
57
+ );
58
+
59
+ let matches = 0;
60
+
61
+ // Loop to find matched characters:
62
+ for (let index1 = 0; index1 < a1_length; index1++) {
63
+
64
+ // Use the highest of the window diff and the min of the window and string 2 length:
65
+ const start = max2(0, index1 - matchWindow);
66
+ const end = min2(index1 + matchWindow + 1, a2_length);
67
+
68
+ // Iterate second string index:
69
+ for (let index2 = start; index2 < end; index2++) {
70
+
71
+ // If second string character already matched, skip:
72
+ if (matches2.get(index2)) {
73
+ continue;
74
+ }
75
+
76
+ // If the characters don't match, skip:
77
+ if (a1.charAt(index1) !== a2.charAt(index2)) {
78
+ continue;
79
+ }
80
+
81
+ // Assume match if the above 2 checks don't continue:
82
+ matches1.set(index1, true);
83
+ matches2.set(index2, true);
84
+
85
+ // Add matches by 1, break inner loop:
86
+ ++matches;
87
+ break;
88
+ }
89
+ }
90
+
91
+ return matches;
92
+ }
93
+
94
+ /**
95
+ * Calculate the number of transpositions between the two words
96
+ * @param {string} a1 The first string to compare
97
+ * @param {string} a2 The second string to compare
98
+ * @param {BitSet} matches1
99
+ * @param {BitSet} matches2
100
+ */
101
+ function getTranspositions(a1, a2, matches1, matches2) {
102
+ let transpositions = 0;
103
+
104
+ // Loop to find transpositions:
105
+ const a1_length = a1.length;
106
+ const a2_length = a2.length;
107
+
108
+ for (let i1 = 0, i2 = 0; i1 < a1_length; i1++) {
109
+ // If a non-matching character was found, skip:
110
+ if (matches1.get(i1) === false) {
111
+ continue;
112
+ }
113
+
114
+ // Move i2 index to the next match:
115
+ while (
116
+ i2 < a2_length
117
+ && matches2.get(i2) === false
118
+ ) {
119
+ i2++;
120
+ }
121
+
122
+ // If the characters don't match, increase transposition:
123
+ if (a1.charAt(i1) !== a2.charAt(i2)) {
124
+ transpositions++;
125
+ }
126
+
127
+ // Iterate i2 index normally:
128
+ i2++;
129
+ }
130
+
131
+ return Math.floor(transpositions * 0.5);
132
+ }
133
+
134
+ /**
135
+ * Counts the number of common characters at the beginning
136
+ * of each word up to a maximum of 4
137
+ * @param {string} a1 The first string to compare
138
+ * @param {string} a2 The second string to compare
139
+ * @param {number} character_limit
140
+ * @returns {number}
141
+ */
142
+ function getPrefix(a1, a2, character_limit) {
143
+
144
+ let p = 0;
145
+
146
+ for (; p < character_limit; p++) {
147
+ if (a1.charAt(p) !== a2.charAt(p)) {
148
+ return p;
149
+ }
150
+ }
151
+
152
+ return ++p;
153
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=string_jaro_winkler.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string_jaro_winkler.spec.d.ts","sourceRoot":"","sources":["../../../../../src/core/primitives/strings/string_jaro_winkler.spec.js"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ import { string_jaro_winkler } from "./string_jaro_winkler.js";
2
+
3
+ test("empty strings", () => {
4
+
5
+ expect(string_jaro_winkler("", "")).toBe(1)
6
+
7
+ });
8
+
9
+ test("whitespace", () => {
10
+ expect(string_jaro_winkler(" ", " ")).toBe(1);
11
+
12
+ expect(string_jaro_winkler("\n", "\n")).toBe(1);
13
+ expect(string_jaro_winkler("\t", "\t")).toBe(1);
14
+
15
+ expect(string_jaro_winkler(" ", " ")).toBeGreaterThan(0);
16
+ });
17
+
18
+ test("negative cases", () => {
19
+
20
+
21
+ expect(string_jaro_winkler("a", "")).toBe(0);
22
+ expect(string_jaro_winkler("", "a")).toBe(0);
23
+
24
+ expect(string_jaro_winkler("a", "b")).toBe(0);
25
+ expect(string_jaro_winkler("b", "a")).toBe(0);
26
+
27
+ });
28
+
29
+ test("known cases", () => {
30
+
31
+
32
+ expect(string_jaro_winkler("a", "a")).toBeCloseTo(1);
33
+ expect(string_jaro_winkler("aa", "aa")).toBeCloseTo(1);
34
+ expect(string_jaro_winkler("abc", "abc")).toBeCloseTo(1);
35
+
36
+ expect(string_jaro_winkler("DwAyNE", "DuANE")).toBeCloseTo(0.84);
37
+ expect(string_jaro_winkler("TRATE", "TRACE")).toBeCloseTo(0.906667);
38
+
39
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"SkeletonUtils.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh/SkeletonUtils.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,2DAHW,MAAM,GACJ,UAAU,GAAG,IAAI,CAiD7B;AAiCD;;;;GAIG;AACH,mEAFa,WAAS,SAAS,CAgB9B;AAED;;;;;GAKG;AACH,qEAHW,yBAAuB,GACtB,IAAI,GAAC,IAAI,CAkCpB;AAED;;;;;GAKG;AACH,iEAHW,yBAAuB,GACrB,IAAI,GAAG,IAAI,CAUvB;AAGD;;;;;GAKG;AACH,0EAFa,IAAI,GAAG,IAAI,CA+BvB;AAID;;;;;GAKG;AACH,sEAFa,IAAI,GAAG,IAAI,CA8BvB;qBAlPoB,OAAO"}
1
+ {"version":3,"file":"SkeletonUtils.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/mesh/SkeletonUtils.js"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,2DAHW,MAAM,GACJ,UAAU,GAAG,IAAI,CAuC7B;AAiCD;;;;GAIG;AACH,mEAFa,WAAS,SAAS,CAgB9B;AAED;;;;;GAKG;AACH,qEAHW,yBAAuB,GACtB,IAAI,GAAC,IAAI,CAkCpB;AAED;;;;;GAKG;AACH,iEAHW,yBAAuB,GACrB,IAAI,GAAG,IAAI,CAUvB;AAGD;;;;;GAKG;AACH,0EAFa,IAAI,GAAG,IAAI,CA+BvB;AAID;;;;;GAKG;AACH,sEAFa,IAAI,GAAG,IAAI,CA8BvB;qBA1OoB,OAAO"}
@@ -1,7 +1,8 @@
1
- import { distance as levenshtein_distance } from "fastest-levenshtein";
2
1
  import { Bone } from "three";
3
- import { BoneMapping } from "./skeleton/BoneMapping.js";
2
+ import { arrayPickBestElement } from "../../../../core/collection/array/arrayPickBestElement.js";
3
+ import { string_compute_similarity } from "../../../../core/primitives/strings/string_compute_similarity.js";
4
4
  import { extractName } from "../../../../extractName.js";
5
+ import { BoneMapping } from "./skeleton/BoneMapping.js";
5
6
 
6
7
 
7
8
  /**
@@ -42,20 +43,10 @@ export function getSkeletonBone(component, boneName) {
42
43
  //bone not found
43
44
 
44
45
  //try to find similar bones
45
- const similarities = bones.map(function (bone) {
46
- const distance = levenshtein_distance(bone.name, boneName);
47
- return {
48
- bone: bone,
49
- distance: distance
50
- };
46
+ const bestMatch = arrayPickBestElement(bones, function (bone) {
47
+ return string_compute_similarity(bone.name, boneName);
51
48
  });
52
49
 
53
- similarities.sort(function (a, b) {
54
- return a.distance - b.distance;
55
- });
56
-
57
- const bestMatch = similarities[0].bone;
58
-
59
50
  throw new Error("Bone '" + boneName + "' not found, did you mean '" + bestMatch.name + "'");
60
51
  }
61
52
 
@@ -1,7 +1,7 @@
1
- import { HumanoidBoneType } from "./HumanoidBoneType.js";
2
- import { distance as levenshtein_distance } from "fastest-levenshtein";
3
1
  import { assert } from "../../../../../core/assert.js";
4
2
  import { string_compute_common_prefix } from "../../../../../core/primitives/strings/string_compute_common_prefix.js";
3
+ import { string_compute_similarity } from "../../../../../core/primitives/strings/string_compute_similarity.js";
4
+ import { HumanoidBoneType } from "./HumanoidBoneType.js";
5
5
 
6
6
 
7
7
  /**
@@ -40,7 +40,7 @@ export class BoneMapping {
40
40
  boneValues.forEach(function (boneName, boneIndex) {
41
41
 
42
42
  conditionedNames.forEach(function (name, inputIndex) {
43
- const distance = levenshtein_distance(name, boneName);
43
+ const distance = string_compute_similarity(name, boneName);
44
44
  const match = {
45
45
  boneIndex,
46
46
  inputIndex,
@@ -1,6 +1,6 @@
1
+ import { randomIntegerBetween } from "../../../../core/math/random/randomIntegerBetween.js";
1
2
  import { seededRandom } from "../../../../core/math/random/seededRandom.js";
2
3
  import { HarmonicDiffusionGrid } from "./HarmonicDiffusionGrid.js";
3
- import { randomIntegerBetween } from "../../../../core/math/random/randomIntegerBetween.js";
4
4
 
5
5
  test("constructor doesn't throw", () => {
6
6
  new HarmonicDiffusionGrid([], 0, 0);
@@ -77,7 +77,7 @@ test("20 step 4x1, corners assigned", () => {
77
77
  expect(grid.data[3]).toBe(-7);
78
78
  });
79
79
 
80
- test("performance 512x512", () => {
80
+ test.skip("performance 512x512", () => {
81
81
  const w = 139;
82
82
  const h = 139;
83
83