@woosh/meep-engine 2.76.4 → 2.78.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 (28) hide show
  1. package/build/meep.cjs +236 -616
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +236 -616
  4. package/editor/view/ecs/components/TerrainController.js +9 -16
  5. package/package.json +1 -1
  6. package/src/core/collection/heap/Uint32Heap.js +10 -1
  7. package/src/core/graph/Edge.js +20 -0
  8. package/src/core/graph/SquareMatrix.js +4 -2
  9. package/src/core/graph/WeightedEdge.js +5 -9
  10. package/src/core/graph/coloring/colorizeGraphGreedy.spec.js +1 -1
  11. package/src/core/graph/coloring/validateGraphColoring.js +1 -1
  12. package/src/core/graph/eigen/matrix_eigenvalues_in_place.js +21 -0
  13. package/src/core/graph/eigen/{eigen.spec.js → matrix_eigenvalues_in_place.spec.js} +2 -2
  14. package/src/core/graph/eigen/matrix_householder_in_place.js +92 -0
  15. package/src/core/graph/eigen/{eigen.js → matrix_qr_in_place.js} +2 -113
  16. package/src/core/graph/layout/CircleLayout.js +6 -11
  17. package/src/core/graph/v2/Graph.js +39 -9
  18. package/src/core/graph/v2/NodeContainer.js +136 -22
  19. package/src/engine/ecs/storage/binary/BinarySerializationRegistry.js +8 -6
  20. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleRegistry.js +1 -1
  21. package/src/engine/navigation/grid/find_path_on_grid_astar.js +25 -22
  22. package/src/engine/navigation/grid/find_path_on_grid_astar.spec.js +2 -2
  23. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +17 -33
  24. package/src/core/graph/Graph.js +0 -564
  25. package/src/core/graph/GraphUtils.js +0 -284
  26. package/src/engine/ecs/terrain/ecs/splat/SplatMapMaterialPatch.js +0 -464
  27. package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js +0 -622
  28. package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +0 -383
@@ -1,29 +1,37 @@
1
1
  import { EdgeDirectionType } from "../Edge.js";
2
2
 
3
+ /**
4
+ * Supplementary structure to `Graph`, holds edges and neighbour nodes for fast access
5
+ * Used internally by `Graph`
6
+ * @template N
7
+ */
3
8
  export class NodeContainer {
4
9
  /**
5
- * @template N
10
+ * Node being described
11
+ * @type {N}
6
12
  */
7
- constructor() {
8
- /**
9
- *
10
- * @type {N}
11
- */
12
- this.node = null;
13
+ node = null;
13
14
 
14
- /**
15
- *
16
- * @type {Edge<N>[]}
17
- * @private
18
- */
19
- this.__edges = [];
15
+ /**
16
+ * Attached edges
17
+ * @type {Edge<N>[]}
18
+ * @private
19
+ */
20
+ __edges = [];
20
21
 
21
- /**
22
- *
23
- * @type {Map<N,number>}
24
- * @private
25
- */
26
- this.__neighbors = new Map();
22
+ /**
23
+ *
24
+ * @type {Map<N,number>}
25
+ * @private
26
+ */
27
+ __neighbors = new Map();
28
+
29
+ /**
30
+ * NOTE: this method allocates memory internally
31
+ * @returns {N[]}
32
+ */
33
+ get neighbours() {
34
+ return Array.from(this.__neighbors.keys());
27
35
  }
28
36
 
29
37
  /**
@@ -42,6 +50,110 @@ export class NodeContainer {
42
50
  return this.__edges;
43
51
  }
44
52
 
53
+ /**
54
+ * NOTE: this method allocates memory internally
55
+ * @returns {N[]}
56
+ */
57
+ get inNodes() {
58
+ return this.inEdges.map(e => e.other(this.node));
59
+ }
60
+
61
+ /**
62
+ * NOTE: this method allocates memory internally
63
+ * @returns {N[]}
64
+ */
65
+ get outNodes() {
66
+ return this.outEdges.map(e => e.other(this.node));
67
+ }
68
+
69
+
70
+ /**
71
+ * NOTE: this method allocates memory internally
72
+ * @returns {Edge<N>[]}
73
+ */
74
+ get outEdges() {
75
+ /**
76
+ *
77
+ * @type {Edge<N>[]}
78
+ */
79
+ const result = [];
80
+
81
+ this.getOutgoingEdges(result);
82
+
83
+ return result;
84
+ }
85
+
86
+ /**
87
+ * NOTE: this method allocates memory internally
88
+ * @returns {Edge<N>[]}
89
+ */
90
+ get inEdges() {
91
+ /**
92
+ *
93
+ * @type {Edge<N>[]}
94
+ */
95
+ const result = [];
96
+
97
+ this.getIncomingEdges(result);
98
+
99
+ return result;
100
+ }
101
+
102
+
103
+ /**
104
+ *
105
+ * @param {Edge<N>[]} result
106
+ * @returns {number}
107
+ */
108
+ getIncomingEdges(result) {
109
+ const edges = this.__edges;
110
+
111
+ const edge_count = edges.length;
112
+
113
+ let result_count = 0;
114
+
115
+ for (let i = 0; i < edge_count; i++) {
116
+ const edge = edges[i];
117
+
118
+ if (edge.isDirectedTowards(this.node)) {
119
+
120
+ result.push(edge);
121
+ result_count++;
122
+
123
+ }
124
+
125
+ }
126
+
127
+ return result_count;
128
+ }
129
+
130
+ /**
131
+ *
132
+ * @param {Edge<N>[]} result
133
+ * @returns {number}
134
+ */
135
+ getOutgoingEdges(result) {
136
+ const edges = this.__edges;
137
+
138
+ const edge_count = edges.length;
139
+
140
+ let result_count = 0;
141
+
142
+ for (let i = 0; i < edge_count; i++) {
143
+ const edge = edges[i];
144
+
145
+ if (edge.isDirectedAwayFrom(this.node)) {
146
+
147
+ result.push(edge);
148
+ result_count++;
149
+
150
+ }
151
+
152
+ }
153
+
154
+ return result_count;
155
+ }
156
+
45
157
  /**
46
158
  *
47
159
  * @return {number}
@@ -52,12 +164,14 @@ export class NodeContainer {
52
164
  const edges = this.__edges;
53
165
  const edge_count = edges.length;
54
166
 
167
+ const current_node = this.node;
168
+
55
169
  for (let i = 0; i < edge_count; i++) {
56
170
  const edge = edges[i];
57
171
 
58
172
  if (
59
- (edge.first === this.node && edge.direction === EdgeDirectionType.Forward)
60
- || (edge.second === this.node && edge.direction === EdgeDirectionType.Backward)
173
+ (edge.first === current_node && edge.direction === EdgeDirectionType.Forward)
174
+ || (edge.second === current_node && edge.direction === EdgeDirectionType.Backward)
61
175
 
62
176
  ) {
63
177
  r++;
@@ -81,7 +195,7 @@ export class NodeContainer {
81
195
 
82
196
  /**
83
197
  *
84
- * @param {function(Edge)} visitor
198
+ * @param {function(Edge<N>)} visitor
85
199
  * @param {*} [thisArg]
86
200
  * @returns {number}
87
201
  */
@@ -1,5 +1,5 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
- import { Graph } from "../../../../core/graph/Graph.js";
2
+ import { Graph } from "../../../../core/graph/v2/Graph.js";
3
3
 
4
4
  /**
5
5
  * Contains serializers for various data types as well as data upgraders which enable support for serialization format changes
@@ -39,25 +39,27 @@ export class BinarySerializationRegistry {
39
39
  assert.defined(adapter, 'adapter');
40
40
  assert.ok(adapter.isBinaryClassSerializationAdapter, 'adapter is not a BinaryClassSerializationAdapter');
41
41
 
42
- if (className === undefined) {
42
+ let _className = className;
43
+
44
+ if (_className === undefined) {
43
45
  const klass = adapter.getClass();
44
46
 
45
47
  if (typeof klass.typeName === "string") {
46
- className = klass.typeName;
48
+ _className = klass.typeName;
47
49
  } else {
48
50
  throw new Error(`className not specified, could not infer class name from the class itself`);
49
51
  }
50
52
  }
51
53
 
52
- if (this.serializers.has(className)) {
54
+ if (this.serializers.has(_className)) {
53
55
  //a serializer already exists
54
56
 
55
- console.warn(`Serializer for class '${className}' already exists, ignoring request`);
57
+ console.warn(`Serializer for class '${_className}' already exists, ignoring request`);
56
58
 
57
59
  return false;
58
60
  }
59
61
 
60
- this.serializers.set(className, adapter);
62
+ this.serializers.set(_className, adapter);
61
63
 
62
64
  return true;
63
65
  }
@@ -1,6 +1,6 @@
1
1
  import { assert } from "../../../../../../core/assert.js";
2
- import Graph from "../../../../../../core/graph/Graph.js";
3
2
  import { Edge, EdgeDirectionType } from "../../../../../../core/graph/Edge.js";
3
+ import { Graph } from "../../../../../../core/graph/v2/Graph.js";
4
4
  import { FunctionModuleReference } from "./FunctionModuleReference.js";
5
5
 
6
6
  export class FunctionModuleRegistry {
@@ -26,7 +26,7 @@ function index2point(result, index, width) {
26
26
  * @param {number} height
27
27
  * @returns {number}
28
28
  */
29
- function computeNeighbors(result, index, width, height) {
29
+ function compute_neighbors(result, index, width, height) {
30
30
  const x = index % width;
31
31
  const y = (index / width) | 0;
32
32
 
@@ -36,14 +36,17 @@ function computeNeighbors(result, index, width, height) {
36
36
  result[neighbour_count] = index - width;
37
37
  neighbour_count++
38
38
  }
39
+
39
40
  if (x > 0) {
40
41
  result[neighbour_count] = index - 1;
41
42
  neighbour_count++;
42
43
  }
44
+
43
45
  if (x < width - 1) {
44
46
  result[neighbour_count] = index + 1;
45
47
  neighbour_count++;
46
48
  }
49
+
47
50
  if (y < height - 1) {
48
51
  result[neighbour_count] = index + width;
49
52
  neighbour_count++
@@ -60,7 +63,7 @@ function computeNeighbors(result, index, width, height) {
60
63
  * @param {number} height
61
64
  * @returns {number[]}
62
65
  */
63
- function pathTo(node, g_score, width, height) {
66
+ function compute_path(node, g_score, width, height) {
64
67
  let v_previous = new Vector2(-1, -1);
65
68
  let v_current = new Vector2();
66
69
 
@@ -111,7 +114,7 @@ function pathTo(node, g_score, width, height) {
111
114
  v_current = t;
112
115
 
113
116
  // find next point
114
- const neighbour_count = computeNeighbors(neighbors, current, width, height);
117
+ const neighbour_count = compute_neighbors(neighbors, current, width, height);
115
118
 
116
119
  current = -1;
117
120
 
@@ -190,16 +193,16 @@ closed.preventShrink();
190
193
  * @param {number} height
191
194
  * @param {number} start
192
195
  * @param {number} goal
193
- * @param {number} crossingPenalty
194
- * @param {number} blockValue value in the field that signifies impassible obstacle
196
+ * @param {number} crossing_penalty
197
+ * @param {number} block_value value in the field that signifies impassible obstacle
195
198
  * @returns {Array.<number>} array of indices representing path from start to end
196
199
  */
197
200
  export function find_path_on_grid_astar(
198
201
  field,
199
202
  width, height,
200
203
  start, goal,
201
- crossingPenalty,
202
- blockValue
204
+ crossing_penalty,
205
+ block_value
203
206
  ) {
204
207
 
205
208
  assert.defined(field, 'field');
@@ -208,8 +211,8 @@ export function find_path_on_grid_astar(
208
211
  assert.isNonNegativeInteger(start, "start");
209
212
  assert.isNonNegativeInteger(goal, "goal");
210
213
 
211
- assert.isNumber(crossingPenalty, 'crossingPenalty');
212
- assert.isNumber(blockValue, 'blockValue');
214
+ assert.isNumber(crossing_penalty, 'crossingPenalty');
215
+ assert.isNumber(block_value, 'blockValue');
213
216
 
214
217
  // prepare sets
215
218
  open.clear();
@@ -232,15 +235,15 @@ export function find_path_on_grid_astar(
232
235
  const currentNode = open.pop_min();
233
236
 
234
237
  if (currentNode === goal) {
235
- // End case -- result has been found, return the traced path.
236
- return pathTo(currentNode, g_score, width, height);
238
+ // End case - result has been found, return the traced path.
239
+ return compute_path(currentNode, g_score, width, height);
237
240
  }
238
241
 
239
242
  // Normal case -- move currentNode from open to closed, process each of its neighbors.
240
243
  closed.set(currentNode, true);
241
244
 
242
245
  // Find all neighbors for the current node.
243
- const neighbour_count = computeNeighbors(neighbors, currentNode, width, height);
246
+ const neighbour_count = compute_neighbors(neighbors, currentNode, width, height);
244
247
 
245
248
  for (let i = 0; i < neighbour_count; ++i) {
246
249
  const neighbor = neighbors[i];
@@ -252,39 +255,39 @@ export function find_path_on_grid_astar(
252
255
 
253
256
  // The g score is the shortest distance from start to current node.
254
257
  // We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet.
255
- const neighborValue = field[neighbor];
258
+ const neighbor_value = field[neighbor];
256
259
 
257
- if (neighborValue === blockValue) {
260
+ if (neighbor_value === block_value) {
258
261
  //cell is blocked, close and continue
259
262
  closed.set(neighbor, true);
260
263
  continue;
261
264
  }
262
265
 
263
266
  // Cost of traversing to this neighbour
264
- const transition_cost = neighborValue * crossingPenalty + 1;
267
+ const transition_cost = neighbor_value * crossing_penalty + 1;
265
268
 
266
269
  // updated path cost
267
- const gScore = g_score[currentNode] + transition_cost;
270
+ const cost_so_far = g_score[currentNode] + transition_cost;
268
271
 
269
272
  const index_in_open_set = open.find_index_by_id(neighbor);
270
273
 
271
274
  const not_in_open_set = index_in_open_set === -1;
272
275
 
273
- if (not_in_open_set || gScore < g_score[neighbor]) {
276
+ if (not_in_open_set || cost_so_far < g_score[neighbor]) {
274
277
 
275
278
  // update refined score
276
- g_score[neighbor] = gScore;
279
+ g_score[neighbor] = cost_so_far;
277
280
 
278
- const h = heuristic(neighbor, goal, width);
281
+ const remaining_heuristic = heuristic(neighbor, goal, width);
279
282
 
280
- const fScore = gScore + h;
283
+ const refined_heuristic = cost_so_far + remaining_heuristic;
281
284
 
282
285
  if (not_in_open_set) {
283
286
  // Pushing to heap will put it in proper place based on the 'f' value.
284
- open.insert(neighbor, fScore);
287
+ open.insert(neighbor, refined_heuristic);
285
288
  } else {
286
289
  // Already seen the node, but since it has been re-scored we need to reorder it in the heap
287
- open.__update_score_by_index(index_in_open_set, fScore);
290
+ open.__update_score_by_index(index_in_open_set, refined_heuristic);
288
291
  }
289
292
  }
290
293
  }
@@ -36,7 +36,7 @@ test("path on open 3x3 grid", () => {
36
36
  expect(path).toEqual([0, 3, 5, 8]);
37
37
  });
38
38
 
39
- test.skip("performance, 256x256 random", () => {
39
+ test("performance, 256x256 random", () => {
40
40
  const FIELD_SIZE = 256;
41
41
 
42
42
  const field = new Uint8Array(FIELD_SIZE * FIELD_SIZE);
@@ -45,7 +45,7 @@ test.skip("performance, 256x256 random", () => {
45
45
 
46
46
  const last_field_index = field.length - 1;
47
47
 
48
- for (let i = 0; i < field.length * 0.05; i++) {
48
+ for (let i = 0; i < field.length * 0.15; i++) {
49
49
  const index = randomIntegerBetween(random, 0, last_field_index);
50
50
 
51
51
  field[index] = 255;
@@ -1,46 +1,30 @@
1
+ import { GridTags } from "../../../../../samples/generation/grid/GridTags.js";
2
+ import { MirGridLayers } from "../../../../../samples/generation/grid/MirGridLayers.js";
3
+ import { matcher_tag_traversable } from "../../../../../samples/generation/rules/matcher_tag_traversable.js";
4
+ import { BitSet } from "../../../../core/binary/BitSet.js";
5
+ import { groupArrayBy } from "../../../../core/collection/array/groupArrayBy.js";
6
+ import { collectIteratorValueToArray } from "../../../../core/collection/collectIteratorValueToArray.js";
7
+ import BinaryHeap from "../../../../core/collection/heap/FastBinaryHeap.js";
8
+ import { QuadTreeNode } from "../../../../core/geom/2d/quad-tree/QuadTreeNode.js";
9
+ import { Graph } from "../../../../core/graph/v2/Graph.js";
1
10
  import { seededRandom } from "../../../../core/math/random/seededRandom.js";
2
- import { GridTaskGenerator } from "../../GridTaskGenerator.js";
11
+ import { remap } from "../../../../core/math/remap.js";
3
12
  import TaskGroup from "../../../../core/process/task/TaskGroup.js";
4
- import Graph from "../../../../core/graph/Graph.js";
5
- import BinaryHeap from "../../../../core/collection/heap/FastBinaryHeap.js";
6
- import { BitSet } from "../../../../core/binary/BitSet.js";
7
- import { matcher_tag_traversable } from "../../../../../samples/generation/rules/matcher_tag_traversable.js";
8
- import { buildPathFromDistanceMap } from "../util/buildPathFromDistanceMap.js";
13
+ import { actionTask } from "../../../../core/process/task/util/actionTask.js";
14
+ import { countTask } from "../../../../core/process/task/util/countTask.js";
9
15
  import { GridCellActionPlaceTags } from "../../../placement/action/GridCellActionPlaceTags.js";
10
- import { GridTags } from "../../../../../samples/generation/grid/GridTags.js";
11
16
  import { CellMatcher } from "../../../rules/CellMatcher.js";
12
- import { collectIteratorValueToArray } from "../../../../core/collection/collectIteratorValueToArray.js";
13
- import { QuadTreeNode } from "../../../../core/geom/2d/quad-tree/QuadTreeNode.js";
14
- import AABB2 from "../../../../core/geom/2d/aabb/AABB2.js";
17
+ import { CellMatcherNot } from "../../../rules/logic/CellMatcherNot.js";
18
+ import { GridTaskGenerator } from "../../GridTaskGenerator.js";
19
+ import { buildPathFromDistanceMap } from "../util/buildPathFromDistanceMap.js";
20
+ import { buildUnsignedDistanceField } from "../util/buildUnsignedDistanceField.js";
15
21
  import { PathEndPoint } from "./PathEndPoint.js";
16
- import { RoadConnection } from "./RoadConnection.js";
17
22
  import { readMarkerNodeGroupId } from "./readMarkerNodeGroupId.js";
18
- import { buildUnsignedDistanceField } from "../util/buildUnsignedDistanceField.js";
19
- import { CellMatcherNot } from "../../../rules/logic/CellMatcherNot.js";
23
+ import { RoadConnection } from "./RoadConnection.js";
20
24
  import { RoadConnectionNetwork } from "./RoadConnectionNetwork.js";
21
- import { MirGridLayers } from "../../../../../samples/generation/grid/MirGridLayers.js";
22
- import { actionTask } from "../../../../core/process/task/util/actionTask.js";
23
- import { countTask } from "../../../../core/process/task/util/countTask.js";
24
- import { groupArrayBy } from "../../../../core/collection/array/groupArrayBy.js";
25
- import { remap } from "../../../../core/math/remap.js";
26
25
 
27
26
  const NODE_TYPE_ROAD_CONNECTOR = 'Road Connector';
28
27
 
29
-
30
- /**
31
- *
32
- * @param {QuadTreeNode} tree
33
- * @param {RoadConnection} path
34
- * @param {number} gridWidth
35
- */
36
- function addPathToQuadTree(tree, path, gridWidth) {
37
- const bounds = new AABB2();
38
-
39
- path.computeBounds(bounds, gridWidth);
40
-
41
- tree.add(path, bounds.x0, bounds.y0, bounds.x1, bounds.y1);
42
- }
43
-
44
28
  /**
45
29
  *
46
30
  * @param {MarkerNode[]} array