@woosh/meep-engine 2.79.0 → 2.80.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 (45) hide show
  1. package/build/meep.cjs +178 -198
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +178 -198
  4. package/package.json +1 -1
  5. package/src/core/geom/2d/aabb/AABB2.js +6 -18
  6. package/src/core/geom/3d/SurfacePoint3.spec.js +1 -1
  7. package/src/core/geom/3d/{matrix → mat4}/m4_multiply.spec.js +3 -4
  8. package/src/core/geom/3d/{matrix → mat4}/m4_multiply_alphatensor.spec.js +3 -3
  9. package/src/core/geom/3d/morton/v3_morton_encode_transformed.spec.js +1 -1
  10. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.spec.js +1 -1
  11. package/src/core/geom/Vector3.js +2 -2
  12. package/src/core/geom/Vector3.spec.js +2 -2
  13. package/src/core/geom/packing/max-rect/{MaxRectangles.js → MaxRectanglesPacker.js} +25 -32
  14. package/src/core/geom/packing/max-rect/MaxRectanglesPacker.spec.js +60 -0
  15. package/src/core/geom/packing/max-rect/packMaxRectangles.js +19 -0
  16. package/src/core/graph/cluster_mesh_metis.js +3 -3
  17. package/src/core/graph/metis/metis.js +16 -1
  18. package/src/core/graph/metis/metis_options.js +32 -29
  19. package/src/core/math/interval/overlap1D.js +7 -0
  20. package/src/core/math/noise/create_simplex_noise_2d.js +4 -0
  21. package/src/core/math/spline/computeCatmullRomSplineUniformDistance.js +3 -3
  22. package/src/core/math/spline/v3_computeCatmullRomSplineUniformDistance.js +42 -0
  23. package/src/core/model/node-graph/node/NodeDescription.js +12 -10
  24. package/src/core/model/node-graph/node/NodeDescription.spec.js +14 -1
  25. package/src/core/model/object/objectKeyByValue.js +3 -2
  26. package/src/engine/ecs/renderable/Renderable.js +1 -1
  27. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +1 -1
  28. package/src/engine/ecs/terrain/tiles/TerrainTile.spec.js +2 -2
  29. package/src/engine/ecs/transform/Transform.js +3 -3
  30. package/src/engine/ecs/transform/Transform.spec.js +3 -3
  31. package/src/engine/graphics/ecs/path/entity/testEntityPath.js +16 -10
  32. package/src/engine/graphics/material/optimization/MaterialOptimizationContext.js +1 -1
  33. package/src/engine/graphics/texture/atlas/TextureAtlas.js +1 -1
  34. package/src/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +3 -3
  35. package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.js +1 -1
  36. package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.spec.js +2 -2
  37. package/src/engine/navigation/ecs/components/Path.js +5 -12
  38. package/src/engine/simulation/Ticker.js +40 -61
  39. package/src/core/geom/LineSegment.js +0 -207
  40. /package/src/core/geom/3d/{matrix → mat4}/MATRIX_4_IDENTITY.js +0 -0
  41. /package/src/core/geom/3d/{matrix → mat4}/MATRIX_4_IDENTITY.spec.js +0 -0
  42. /package/src/core/geom/3d/{matrix → mat4}/allocate_transform_m4.js +0 -0
  43. /package/src/core/geom/3d/{matrix → mat4}/m4_make_translation.js +0 -0
  44. /package/src/core/geom/3d/{matrix → mat4}/m4_multiply.js +0 -0
  45. /package/src/core/geom/3d/{matrix → mat4}/m4_multiply_alphatensor.js +0 -0
@@ -1,15 +1,19 @@
1
- import BinaryHeap from "../../../collection/heap/FastBinaryHeap.js";
2
1
  import { assert } from "../../../assert.js";
2
+ import BinaryHeap from "../../../collection/heap/FastBinaryHeap.js";
3
+ import AABB2 from "../../2d/aabb/AABB2.js";
3
4
  import { QuadTreeDatum } from "../../2d/quad-tree/QuadTreeDatum.js";
4
5
  import { QuadTreeNode } from "../../2d/quad-tree/QuadTreeNode.js";
5
- import AABB2 from "../../2d/aabb/AABB2.js";
6
6
  import Vector2 from "../../Vector2.js";
7
- import { removeRedundantBoxes } from "./removeRedundantBoxes.js";
8
7
  import { costByRemainingArea } from "./cost/costByRemainingArea.js";
9
8
  import { findBestContainer } from "./findBestContainer.js";
10
9
  import { packOneBox } from "./packOneBox.js";
10
+ import { removeRedundantBoxes } from "./removeRedundantBoxes.js";
11
11
 
12
-
12
+ /**
13
+ * Packs rectangles into a finite area, packer is incremental and supports both insertions and removals of rectangles
14
+ * Implementation of "max rectangles" packing algorithm.
15
+ * Useful for packing texture atlases
16
+ */
13
17
  export class MaxRectanglesPacker {
14
18
  /**
15
19
  *
@@ -24,6 +28,8 @@ export class MaxRectanglesPacker {
24
28
  * @type {QuadTreeNode}
25
29
  */
26
30
  this.free = new QuadTreeNode(0, 0, width, height);
31
+
32
+ // initialize a with a free space occupying the entire area
27
33
  this.free.add(null, 0, 0, width, height);
28
34
 
29
35
  /**
@@ -98,7 +104,8 @@ export class MaxRectanglesPacker {
98
104
  }
99
105
 
100
106
  /**
101
- *
107
+ * Tests whether a rectangle of given dimensions can be packed into remaining space
108
+ * Essentially, if this method succeeds - insertion will succeed as well, and if it fails - insertion will fail too
102
109
  * @param {number} w
103
110
  * @param {number} h
104
111
  * @return {boolean}
@@ -184,9 +191,10 @@ export class MaxRectanglesPacker {
184
191
  }
185
192
 
186
193
  /**
187
- * Resize the packer canvas
194
+ * Resize the packer canvas, may trigger repacking if new dimensions are smaller than the existing ones
188
195
  * @param {number} width
189
196
  * @param {number} height
197
+ * @returns {boolean} false if packing fails after resize, true otherwise
190
198
  */
191
199
  resize(width, height) {
192
200
 
@@ -199,18 +207,20 @@ export class MaxRectanglesPacker {
199
207
 
200
208
  if (oldWidth > width || oldHeight > height) {
201
209
  //canvas was made smaller in at least one dimension, re-pack is required
202
- this.repack();
203
- } else {
204
- //canvas was enlarged, we can simply add new free areas
205
- if (width > oldWidth) {
206
- this.free.insertDatum(new QuadTreeDatum(oldWidth, 0, width, height));
207
- }
208
- if (height > oldHeight) {
209
- this.free.insertDatum(new QuadTreeDatum(0, oldHeight, width, height))
210
- }
210
+ return this.repack();
211
+ }
212
+
213
+ //canvas was enlarged, we can simply add new free areas
214
+ if (width > oldWidth) {
215
+ this.free.insertDatum(new QuadTreeDatum(oldWidth, 0, width, height));
216
+ }
217
+ if (height > oldHeight) {
218
+ this.free.insertDatum(new QuadTreeDatum(0, oldHeight, width, height))
211
219
  }
212
220
 
213
221
  // assert.ok(this.validate());
222
+
223
+ return true;
214
224
  }
215
225
 
216
226
  validate() {
@@ -239,20 +249,3 @@ export class MaxRectanglesPacker {
239
249
  }
240
250
 
241
251
 
242
- /**
243
- * Packs {@link AABB2} boxes into defined bounds
244
- *
245
- * Based on paper "A Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin Packing" 2010 Jukka Jylänki
246
- * Method presented called Maximal Rectangles
247
- *
248
- * @param {number} width
249
- * @param {number} height
250
- * @param {AABB2[]} boxes
251
- * @returns {boolean} true if packing was successful, false otherwise
252
- */
253
- export function packMaxRectangles(width, height, boxes) {
254
-
255
- const packer = new MaxRectanglesPacker(width, height);
256
-
257
- return packer.addMany(boxes);
258
- }
@@ -0,0 +1,60 @@
1
+ import AABB2 from "../../2d/aabb/AABB2.js";
2
+ import { MaxRectanglesPacker } from "./MaxRectanglesPacker.js";
3
+
4
+ test("constructor does not throw", () => {
5
+ new MaxRectanglesPacker(1, 1)
6
+ });
7
+
8
+ test("pack 1 box that takes up entire available area", () => {
9
+ const packer = new MaxRectanglesPacker(1, 1);
10
+
11
+ const box = new AABB2(3, 5, 4, 6);
12
+
13
+ expect(packer.add(box)).toBe(true);
14
+
15
+ expect(box.x0).toBe(0);
16
+ expect(box.y0).toBe(0);
17
+ });
18
+
19
+ test("packing a box larger than available area", () => {
20
+
21
+ const packer = new MaxRectanglesPacker(1, 1);
22
+
23
+ const box = new AABB2(0, 0, 2, 1);
24
+
25
+ expect(packer.add(box)).toBe(false);
26
+
27
+ box.set(0, 0, 1, 2);
28
+
29
+ expect(packer.add(box)).toBe(false);
30
+
31
+ box.set(0, 0, 2, 2)
32
+
33
+ expect(packer.add(box)).toBe(false);
34
+ });
35
+
36
+ test("pack 4 squares that fit exactly", () => {
37
+
38
+ const packer = new MaxRectanglesPacker(2, 2);
39
+
40
+ const boxes = [
41
+ new AABB2(0, 0, 1, 1),
42
+ new AABB2(0, 0, 1, 1),
43
+ new AABB2(0, 0, 1, 1),
44
+ new AABB2(0, 0, 1, 1)
45
+ ];
46
+
47
+ for (let i = 0; i < boxes.length; i++) {
48
+ expect(packer.add(boxes[i])).toBe(true);
49
+ }
50
+
51
+ // validate overlap constraints
52
+ for (let i = 0; i < boxes.length; i++) {
53
+ const box_0 = boxes[i];
54
+ for (let j = i + 1; j < boxes.length; j++) {
55
+ const box_1 = boxes[j];
56
+
57
+ expect(box_0.overlapExists(box_1)).toBe(false);
58
+ }
59
+ }
60
+ });
@@ -0,0 +1,19 @@
1
+ import { MaxRectanglesPacker } from "./MaxRectanglesPacker.js";
2
+
3
+ /**
4
+ * Packs {@link AABB2} boxes into defined bounds
5
+ *
6
+ * Based on paper "A Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin Packing" 2010 Jukka Jylänki
7
+ * Method presented called Maximal Rectangles
8
+ *
9
+ * @param {number} width
10
+ * @param {number} height
11
+ * @param {AABB2[]} boxes
12
+ * @returns {boolean} true if packing was successful, false otherwise
13
+ */
14
+ export function packMaxRectangles(width, height, boxes) {
15
+
16
+ const packer = new MaxRectanglesPacker(width, height);
17
+
18
+ return packer.addMany(boxes);
19
+ }
@@ -12,12 +12,12 @@ const MAX_STEPS = 50;
12
12
  * @param {Uint32Array} result
13
13
  * @param {number} node_count
14
14
  * @param {Uint32Array} edge_addresses
15
- * @param {Uint32Array} adjecency_uint32
15
+ * @param {Uint32Array} adjacency_uint32
16
16
  * @param {Uint32Array} edge_weights_uint32
17
17
  * @param {number} patch_size
18
18
  * @returns {Promise<number>}
19
19
  */
20
- export async function metis_cluster_bs(result, node_count, edge_addresses, adjecency_uint32, edge_weights_uint32, patch_size) {
20
+ export async function metis_cluster_bs(result, node_count, edge_addresses, adjacency_uint32, edge_weights_uint32, patch_size) {
21
21
 
22
22
  const metis = Metis.INSTANCE;
23
23
 
@@ -46,7 +46,7 @@ export async function metis_cluster_bs(result, node_count, edge_addresses, adjec
46
46
  node_count,
47
47
  partition_count,
48
48
  edge_addresses,
49
- adjecency_uint32,
49
+ adjacency_uint32,
50
50
  edge_weights_uint32,
51
51
  metisOptions
52
52
  );
@@ -1,5 +1,5 @@
1
- import WorkerBuilder from "../../process/worker/WorkerBuilder.js";
2
1
  import { OnDemandWorkerManager } from "../../process/worker/OnDemandWorkerManager.js";
2
+ import WorkerBuilder from "../../process/worker/WorkerBuilder.js";
3
3
 
4
4
 
5
5
  export class Metis {
@@ -13,6 +13,16 @@ export class Metis {
13
13
  this.service = manager;
14
14
  }
15
15
 
16
+ /**
17
+ *
18
+ * @param {number} n_vertices
19
+ * @param {number} n_parts
20
+ * @param {Uint32Array} edge_addresses
21
+ * @param {Uint32Array} adjacency
22
+ * @param {Uint32Array} edge_weights
23
+ * @param {metis_options} options
24
+ * @returns {Promise<T>}
25
+ */
16
26
  partition(
17
27
  n_vertices,
18
28
  n_parts,
@@ -32,4 +42,9 @@ export class Metis {
32
42
  }
33
43
  }
34
44
 
45
+ /**
46
+ * Singleton instance
47
+ * @readonly
48
+ * @type {Metis}
49
+ */
35
50
  Metis.INSTANCE = new Metis();
@@ -1,33 +1,36 @@
1
+
2
+ /**
3
+ * See metis.h for more details
4
+ * -1 is the used to signal absence of value, in which case a default will be used
5
+ */
1
6
  export class metis_options {
7
+ ptype = -1;
8
+ objtype = -1;
2
9
  /**
3
- * See metis.h for more details
4
- * -1 is the used to signal absence of value, in which case a default will be used
10
+ * Coarsening scheme
11
+ * 0 - METIS_CTYPE_RM
12
+ * 1 - METIS_CTYPE_SHEM
13
+ * @type {number}
5
14
  */
6
- constructor() {
7
- this.ptype = -1;
8
- this.objtype = -1;
9
- /**
10
- * Coarsening scheme
11
- * 0 - METIS_CTYPE_RM
12
- * 1 - METIS_CTYPE_SHEM
13
- * @type {number}
14
- */
15
- this.ctype = -1;
16
- this.iptype = -1;
17
- this.rtype = -1;
18
- this.dbglvl = -1;
19
- this.niter = -1;
20
- this.ncuts = -1;
21
- this.seed = -1;
22
- this.no2hop = -1;
23
- this.minconn = -1;
24
- this.contig = -1;
25
- this.compress - 1;
26
- this.ccorder = -1;
27
- this.pfactor = -1;
28
- this.nseps = -1;
29
- this.ufactor = -1;
30
- this.numbering = -1;
31
-
32
- }
15
+ ctype = -1;
16
+ iptype = -1;
17
+ rtype = -1;
18
+ dbglvl = -1;
19
+ niter = -1;
20
+ ncuts = -1;
21
+ /**
22
+ * Random seed
23
+ * Integer
24
+ * @type {number}
25
+ */
26
+ seed = -1;
27
+ no2hop = -1;
28
+ minconn = -1;
29
+ contig = -1;
30
+ ccorder = -1;
31
+ pfactor = -1;
32
+ nseps = -1;
33
+ ufactor = -1;
34
+ numbering = -1;
35
+ compress = - 1;
33
36
  }
@@ -12,8 +12,15 @@ import { assert } from "../../assert.js";
12
12
  export function overlap1D(a0, a1, b0, b1) {
13
13
  assert.isNumber(a0, "a0");
14
14
  assert.isNumber(a1, "a1");
15
+
15
16
  assert.isNumber(b0, "b0");
16
17
  assert.isNumber(b1, "b1");
17
18
 
19
+ assert.notNaN(a0, 'a0');
20
+ assert.notNaN(a1, 'a1');
21
+
22
+ assert.notNaN(b0, 'b0');
23
+ assert.notNaN(b1, 'b1');
24
+
18
25
  return a1 > b0 && b1 > a0;
19
26
  }
@@ -73,6 +73,10 @@ export function create_simplex_noise_2d(random = Math.random) {
73
73
  permMod12[i] = (perm[i] % 12) * 2;
74
74
  }
75
75
 
76
+ /**
77
+ * @param {number} x
78
+ * @param {number} y
79
+ */
76
80
  return function noise2D(x, y) {
77
81
  // if(!isFinite(x) || !isFinite(y)) return 0;
78
82
  let n0 = 0; // Noise contributions from the three corners
@@ -30,9 +30,9 @@ const p2 = [];
30
30
  const p3 = [];
31
31
 
32
32
  /**
33
- * Takes distances between points into account and samples at equal intervals along linear distance along the point sequence. Computationally slightly more expensive, but produces very predictable and sable results
34
- * @param {number[]} result
35
- * @param {number[]} input
33
+ * Takes distances between points into account and samples at equal intervals along linear distance along the point sequence. Computationally slightly more expensive, but produces very predictable and stable results
34
+ * @param {number[]|Float32Array} result
35
+ * @param {number[]|Float32Array} input
36
36
  * @param {number} input_length number of points in the input
37
37
  * @param {number} dimensions number of dimensions per vertex
38
38
  * @param {number} sample_count number of discrete points to be generated
@@ -0,0 +1,42 @@
1
+ import Vector3 from "../../geom/Vector3.js";
2
+ import { computeCatmullRomSplineUniformDistance } from "./computeCatmullRomSplineUniformDistance.js";
3
+
4
+ /**
5
+ *
6
+ * @param {Vector3[]} inputs
7
+ * @param {number} samples
8
+ * @returns {Vector3[]}
9
+ */
10
+ export function v3_computeCatmullRomSplineUniformDistance(
11
+ inputs, samples
12
+ ) {
13
+
14
+ const input_count = inputs.length;
15
+
16
+ const inputs_array = new Float32Array(3 * input_count);
17
+ const result_array = new Float32Array(3 * samples);
18
+
19
+ for (let i = 0; i < input_count; i++) {
20
+ const v3 = inputs[i];
21
+
22
+ v3.writeToArray(inputs_array, i * 3);
23
+ }
24
+
25
+ computeCatmullRomSplineUniformDistance(
26
+ result_array, inputs_array, input_count, 3, samples
27
+ );
28
+
29
+ // convert numeric result to array of Vector3 objects
30
+ const result = [];
31
+
32
+ for (let i = 0; i < samples; i++) {
33
+ const v3 = new Vector3();
34
+
35
+ v3.readFromArray(result_array, i * 3);
36
+
37
+ result[i] = v3;
38
+
39
+ }
40
+
41
+ return result;
42
+ }
@@ -1,16 +1,17 @@
1
- import {assert} from "../../../assert.js";
2
- import {isArrayEqual} from "../../../collection/array/isArrayEqual.js";
1
+ import { assert } from "../../../assert.js";
2
+ import { isArrayEqual } from "../../../collection/array/isArrayEqual.js";
3
3
  import Signal from "../../../events/signal/Signal.js";
4
- import {invokeObjectToJSON} from "../../object/invokeObjectToJSON.js";
5
- import {NodeParameterDataType} from "./parameter/NodeParameterDataType.js";
6
- import {NodeParameterDescription} from "./parameter/NodeParameterDescription.js";
7
- import {Port} from "./Port.js";
8
- import {PortDirection} from "./PortDirection.js";
4
+ import { invokeObjectToJSON } from "../../object/invokeObjectToJSON.js";
5
+ import { NodeParameterDataType } from "./parameter/NodeParameterDataType.js";
6
+ import { NodeParameterDescription } from "./parameter/NodeParameterDescription.js";
7
+ import { Port } from "./Port.js";
8
+ import { PortDirection } from "./PortDirection.js";
9
9
 
10
10
 
11
11
  /**
12
+ * @template T
12
13
  * @private
13
- * @param {{id:number}[]} things
14
+ * @param {T[]} things
14
15
  * @returns {number}
15
16
  */
16
17
  function pickNewSetId(things) {
@@ -181,7 +182,7 @@ export class NodeDescription {
181
182
 
182
183
  /**
183
184
  *
184
- * @param {BinaryDataType} type
185
+ * @param {DataType} type
185
186
  * @param {String} name
186
187
  * @param {PortDirection} direction
187
188
  */
@@ -338,6 +339,7 @@ export class NodeDescription {
338
339
  }
339
340
  }
340
341
 
342
+ // port not found
341
343
  return undefined;
342
344
  }
343
345
 
@@ -380,7 +382,7 @@ export class NodeDescription {
380
382
  * @param name
381
383
  * @param {NodeRegistry} registry
382
384
  */
383
- fromJSON({ports, id, name}, registry) {
385
+ fromJSON({ ports, id, name }, registry) {
384
386
  this.id = id;
385
387
  this.name = name;
386
388
  this.ports = ports.map(p => Port.fromJSON(p, registry));
@@ -1,5 +1,5 @@
1
- import { NodeDescription } from "./NodeDescription.js";
2
1
  import { DataType } from "../DataType.js";
2
+ import { NodeDescription } from "./NodeDescription.js";
3
3
  import { PortDirection } from "./PortDirection.js";
4
4
 
5
5
  const DUMMY_TYPE = DataType.from(0, 'dummy');
@@ -12,3 +12,16 @@ test('ports are assigned unique IDs', () => {
12
12
 
13
13
  expect(id_a).not.toEqual(id_b);
14
14
  });
15
+
16
+ test("get port by ID", () => {
17
+ const node = new NodeDescription();
18
+
19
+ expect(node.getPortById(1)).toBeNull();
20
+
21
+ const id = node.createPort(DUMMY_TYPE, "a", PortDirection.In);
22
+
23
+ const port = node.getPortById(id);
24
+
25
+ expect(port).not.toBeNull();
26
+ expect(port.name).toBe("a");
27
+ });
@@ -1,8 +1,9 @@
1
1
  /**
2
- *
2
+ * Given an object and a value, find the first property with matching value and returns name of that property
3
+ * Useful for working with ENUM-like objects
3
4
  * @param {Object<T>} object
4
5
  * @param {T} value
5
- * @returns {string|undefined}
6
+ * @returns {string|undefined} name of the property, or undefined if property not found
6
7
  */
7
8
  export function objectKeyByValue(object, value) {
8
9
  for (let i in object) {
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { BvhClient } from "../../../core/bvh2/bvh3/BvhClient.js";
7
7
  import { AABB3 } from "../../../core/geom/3d/aabb/AABB3.js";
8
- import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
8
+ import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/mat4/MATRIX_4_IDENTITY.js";
9
9
  import {
10
10
  expand_aabb_by_transformed_three_object
11
11
  } from "../../graphics/three/expand_aabb_by_transformed_three_object.js";
@@ -5,7 +5,7 @@ import {
5
5
  } from "../../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_frustum.js";
6
6
  import { noop } from "../../../../core/function/Functions.js";
7
7
  import { read_three_planes_to_array } from "../../../../core/geom/3d/frustum/read_three_planes_to_array.js";
8
- import { MATRIX_4_IDENTITY } from "../../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
8
+ import { MATRIX_4_IDENTITY } from "../../../../core/geom/3d/mat4/MATRIX_4_IDENTITY.js";
9
9
  import { ImageRGBADataLoader } from "../../../asset/loaders/image/ImageRGBADataLoader.js";
10
10
  import { CameraSystem } from '../../../graphics/ecs/camera/CameraSystem.js';
11
11
  import { System } from '../../System.js';
@@ -1,5 +1,5 @@
1
+ import { MATRIX_4_IDENTITY } from "../../../../core/geom/3d/mat4/MATRIX_4_IDENTITY.js";
1
2
  import TerrainTile from "./TerrainTile.js";
2
- import { MATRIX_4_IDENTITY } from "../../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
3
3
 
4
4
  test("constructor does not throw", () => {
5
5
  new TerrainTile();
@@ -21,5 +21,5 @@ test("using 'dispose' method on newly created tile", () => {
21
21
  const tile = new TerrainTile();
22
22
 
23
23
  expect(() => tile.dispose()).not.toThrow();
24
-
24
+
25
25
  });
@@ -5,9 +5,9 @@
5
5
  import { assert } from "../../../core/assert.js";
6
6
  import { compose_matrix4_array } from "../../../core/geom/3d/compose_matrix4_array.js";
7
7
  import { decompose_matrix_4_array } from "../../../core/geom/3d/decompose_matrix_4_array.js";
8
- import { allocate_transform_m4 } from "../../../core/geom/3d/matrix/allocate_transform_m4.js";
9
- import { m4_multiply } from "../../../core/geom/3d/matrix/m4_multiply.js";
10
- import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
8
+ import { allocate_transform_m4 } from "../../../core/geom/3d/mat4/allocate_transform_m4.js";
9
+ import { m4_multiply } from "../../../core/geom/3d/mat4/m4_multiply.js";
10
+ import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/mat4/MATRIX_4_IDENTITY.js";
11
11
  import Quaternion from "../../../core/geom/Quaternion.js";
12
12
  import Vector3 from "../../../core/geom/Vector3.js";
13
13
  import { TransformFlags } from "./TransformFlags.js";
@@ -1,7 +1,7 @@
1
- import { Transform } from "./Transform.js";
2
- import Vector3 from "../../../core/geom/Vector3.js";
1
+ import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/mat4/MATRIX_4_IDENTITY.js";
3
2
  import Quaternion from "../../../core/geom/Quaternion.js";
4
- import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
3
+ import Vector3 from "../../../core/geom/Vector3.js";
4
+ import { Transform } from "./Transform.js";
5
5
  import { TransformFlags } from "./TransformFlags.js";
6
6
 
7
7
  test("constructor does not throw", () => {
@@ -1,16 +1,19 @@
1
- import RenderSystem from "../../../../ecs/systems/RenderSystem.js";
2
- import { makeEngineOptionsModel } from "../../../../../../../model/game/options/makeEngineOptionsModel.js";
3
1
  import { makeMirEngineConfig } from "../../../../../../../model/game/makeMirEngineConfig.js";
4
- import { EngineHarness } from "../../../../EngineHarness.js";
5
- import { EntityPath } from "./EntityPath.js";
6
- import Path from "../../../../navigation/ecs/components/Path.js";
2
+ import { makeEngineOptionsModel } from "../../../../../../../model/game/options/makeEngineOptionsModel.js";
7
3
  import Vector3 from "../../../../../core/geom/Vector3.js";
8
- import { EntityPathStyle } from "./EntityPathStyle.js";
9
- import { EntityPathMarkerDefinition } from "./EntityPathMarkerDefinition.js";
4
+ import {
5
+ v3_computeCatmullRomSplineUniformDistance
6
+ } from "../../../../../core/math/spline/v3_computeCatmullRomSplineUniformDistance.js";
7
+ import { Animation } from "../../../../ecs/animation/Animation.js";
10
8
  import { EntityBlueprint } from "../../../../ecs/EntityBlueprint.js";
9
+ import RenderSystem from "../../../../ecs/systems/RenderSystem.js";
11
10
  import { Transform } from "../../../../ecs/transform/Transform.js";
11
+ import { EngineHarness } from "../../../../EngineHarness.js";
12
+ import Path from "../../../../navigation/ecs/components/Path.js";
12
13
  import Mesh from "../../mesh/Mesh.js";
13
- import { Animation } from "../../../../ecs/animation/Animation.js";
14
+ import { EntityPath } from "./EntityPath.js";
15
+ import { EntityPathMarkerDefinition } from "./EntityPathMarkerDefinition.js";
16
+ import { EntityPathStyle } from "./EntityPathStyle.js";
14
17
 
15
18
  const engineHarness = new EngineHarness();
16
19
 
@@ -38,12 +41,15 @@ function main(engine) {
38
41
 
39
42
  const path = new EntityPath();
40
43
  const _p = new Path();
41
- _p.setPositionsFromVectorArray(Path.smoothPath([
44
+
45
+ const curve_points = v3_computeCatmullRomSplineUniformDistance([
42
46
  new Vector3(3, 0, 3),
43
47
  new Vector3(7, 0, 3),
44
48
  new Vector3(7, 0, 7),
45
49
  new Vector3(3, 0, 7)
46
- ], 50));
50
+ ], 50);
51
+
52
+ _p.setPositionsFromVectorArray(curve_points);
47
53
 
48
54
  const style = new EntityPathStyle();
49
55
  style.spacing = 1;
@@ -16,7 +16,7 @@ import { typedArrayToDataType } from "../../../../core/collection/array/typed/ty
16
16
  import { collectIteratorValueToArray } from "../../../../core/collection/collectIteratorValueToArray.js";
17
17
  import { HashMap } from "../../../../core/collection/map/HashMap.js";
18
18
  import AABB2 from "../../../../core/geom/AABB2.js";
19
- import { MaxRectanglesPacker } from "../../../../core/geom/packing/max-rect/MaxRectangles.js";
19
+ import { MaxRectanglesPacker } from "../../../../core/geom/packing/max-rect/MaxRectanglesPacker.js";
20
20
  import { computeMaterialEquality } from "../../../asset/loaders/material/computeMaterialEquality.js";
21
21
  import { computeMaterialHash } from "../../../asset/loaders/material/computeMaterialHash.js";
22
22
  import { TextureAttachmentsByMaterialType } from "../../../asset/loaders/material/TextureAttachmensByMaterialType.js";
@@ -5,7 +5,7 @@ import {
5
5
  DataType2TypedArrayConstructorMapping
6
6
  } from "../../../../core/binary/type/DataType2TypedArrayConstructorMapping.js";
7
7
  import Signal from "../../../../core/events/signal/Signal.js";
8
- import { MaxRectanglesPacker } from "../../../../core/geom/packing/max-rect/MaxRectangles.js";
8
+ import { MaxRectanglesPacker } from "../../../../core/geom/packing/max-rect/MaxRectanglesPacker.js";
9
9
  import Vector2 from "../../../../core/geom/Vector2.js";
10
10
  import IdPool from "../../../../core/IdPool.js";
11
11
  import { max2 } from "../../../../core/math/max2.js";
@@ -1,6 +1,3 @@
1
- import { AtlasPatch } from "../AtlasPatch.js";
2
- import IdPool from "../../../../../core/IdPool.js";
3
- import { MaxRectanglesPacker } from "../../../../../core/geom/packing/max-rect/MaxRectangles.js";
4
1
  import {
5
2
  ClampToEdgeWrapping,
6
3
  DataTexture,
@@ -11,7 +8,10 @@ import {
11
8
  UnsignedByteType,
12
9
  UVMapping
13
10
  } from "three";
11
+ import { MaxRectanglesPacker } from "../../../../../core/geom/packing/max-rect/MaxRectanglesPacker.js";
12
+ import IdPool from "../../../../../core/IdPool.js";
14
13
  import { formatToChannelCount } from "../../formatToChannelCount.js";
14
+ import { AtlasPatch } from "../AtlasPatch.js";
15
15
 
16
16
  export class WebGLTextureAtlas {
17
17
  constructor({
@@ -1,7 +1,7 @@
1
1
  import { aabb3_array_combine } from "../../../core/geom/3d/aabb/aabb3_array_combine.js";
2
2
  import { aabb3_from_threejs_geometry } from "../../../core/geom/3d/aabb/aabb3_from_threejs_geometry.js";
3
3
  import { aabb3_matrix4_project } from "../../../core/geom/3d/aabb/aabb3_matrix4_project.js";
4
- import { m4_multiply } from "../../../core/geom/3d/matrix/m4_multiply.js";
4
+ import { m4_multiply } from "../../../core/geom/3d/mat4/m4_multiply.js";
5
5
  import { ensureGeometryBoundingBox } from "../util/ensureGeometryBoundingBox.js";
6
6
 
7
7
  const scratch_aabb3_array_0 = new Float32Array(6);
@@ -1,6 +1,6 @@
1
- import { expand_aabb_by_transformed_three_object } from "./expand_aabb_by_transformed_three_object.js";
2
- import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
3
1
  import { BufferAttribute, BufferGeometry, Group, Mesh } from "three";
2
+ import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/mat4/MATRIX_4_IDENTITY.js";
3
+ import { expand_aabb_by_transformed_three_object } from "./expand_aabb_by_transformed_three_object.js";
4
4
 
5
5
  /**
6
6
  *