@woosh/meep-engine 2.133.5 → 2.134.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 (67) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/binary/BinaryBuffer.d.ts +20 -0
  4. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  5. package/src/core/binary/BinaryBuffer.js +50 -0
  6. package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts +4 -4
  7. package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts.map +1 -1
  8. package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.js +2 -2
  9. package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts +2 -2
  10. package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts.map +1 -1
  11. package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.js +1 -1
  12. package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts +2 -2
  13. package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts.map +1 -1
  14. package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.js +1 -1
  15. package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts +4 -4
  16. package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts.map +1 -1
  17. package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +3 -3
  18. package/src/core/geom/3d/topology/simplify/quadratic/{Quadratic3.d.ts → Quadric3.d.ts} +55 -29
  19. package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -0
  20. package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +307 -0
  21. package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts +7 -7
  22. package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts.map +1 -1
  23. package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.js +39 -13
  24. package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts +2 -2
  25. package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts.map +1 -1
  26. package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.js +1 -1
  27. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts +2 -2
  28. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts.map +1 -1
  29. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.js +2 -2
  30. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts +4 -4
  31. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts.map +1 -1
  32. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +5 -5
  33. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts +8 -0
  34. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -0
  35. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +56 -0
  36. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts +14 -0
  37. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts.map +1 -0
  38. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.js +95 -0
  39. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +17 -0
  40. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -0
  41. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +352 -0
  42. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts +21 -0
  43. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts.map +1 -0
  44. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.js +52 -0
  45. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +16 -0
  46. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -0
  47. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +90 -0
  48. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts +19 -0
  49. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts.map +1 -0
  50. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js +83 -0
  51. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts +22 -0
  52. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts.map +1 -0
  53. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js +148 -0
  54. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +4 -4
  55. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts +15 -0
  56. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts.map +1 -0
  57. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js +48 -0
  58. package/src/engine/navigation/mesh/NavigationMesh.d.ts +6 -4
  59. package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
  60. package/src/engine/navigation/mesh/NavigationMesh.js +212 -190
  61. package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
  62. package/src/engine/navigation/mesh/build/navmesh_build_topology.js +20 -7
  63. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts +15 -0
  64. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts.map +1 -0
  65. package/src/engine/navigation/mesh/bvh_query_nearest_face.js +131 -0
  66. package/src/core/geom/3d/topology/simplify/quadratic/Quadratic3.d.ts.map +0 -1
  67. package/src/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +0 -302
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Collapses an edge by merging its two vertices into one, relocating the surviving
3
+ * vertex to the supplied coordinate.
4
+ *
5
+ * All faces incident to the collapse edge are removed (they would become degenerate),
6
+ * while faces that only share one of the endpoints are retained and re-stitched onto
7
+ * the surviving vertex. The victim vertex is released.
8
+ *
9
+ * NOTE: Does not perform a weld pass, so collapses that share "link" vertices between
10
+ * the two endpoints will produce duplicate (parallel) edges. The topology remains
11
+ * self-consistent (disk and radial cycles are intact), but callers doing mesh
12
+ * simplification typically want to run a cleanup pass afterward.
13
+ *
14
+ * @param {BinaryTopology} mesh
15
+ * @param {number} edge_id The edge to collapse
16
+ * @param {number[]|Float32Array} new_position New coordinate for the surviving vertex
17
+ * @param {number} [new_position_offset] Offset into `new_position`
18
+ * @returns {number} The surviving vertex ID
19
+ */
20
+ export function bt_edge_collapse(mesh: BinaryTopology, edge_id: number, new_position: number[] | Float32Array, new_position_offset?: number): number;
21
+ //# sourceMappingURL=bt_edge_collapse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bt_edge_collapse.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;GAkBG;AACH,gEALW,MAAM,gBACN,MAAM,EAAE,GAAC,YAAY,wBACrB,MAAM,GACJ,MAAM,CA6BlB"}
@@ -0,0 +1,52 @@
1
+ import { assert } from "../../../../../../../assert.js";
2
+ import { bt_vert_kill } from "../vertex/bt_vert_kill.js";
3
+ import { bt_vertex_replace } from "../vertex/bt_vertex_replace.js";
4
+ import { bt_edge_kill } from "./bt_edge_kill.js";
5
+
6
+ /**
7
+ * Collapses an edge by merging its two vertices into one, relocating the surviving
8
+ * vertex to the supplied coordinate.
9
+ *
10
+ * All faces incident to the collapse edge are removed (they would become degenerate),
11
+ * while faces that only share one of the endpoints are retained and re-stitched onto
12
+ * the surviving vertex. The victim vertex is released.
13
+ *
14
+ * NOTE: Does not perform a weld pass, so collapses that share "link" vertices between
15
+ * the two endpoints will produce duplicate (parallel) edges. The topology remains
16
+ * self-consistent (disk and radial cycles are intact), but callers doing mesh
17
+ * simplification typically want to run a cleanup pass afterward.
18
+ *
19
+ * @param {BinaryTopology} mesh
20
+ * @param {number} edge_id The edge to collapse
21
+ * @param {number[]|Float32Array} new_position New coordinate for the surviving vertex
22
+ * @param {number} [new_position_offset] Offset into `new_position`
23
+ * @returns {number} The surviving vertex ID
24
+ */
25
+ export function bt_edge_collapse(
26
+ mesh,
27
+ edge_id,
28
+ new_position,
29
+ new_position_offset = 0
30
+ ) {
31
+ assert.defined(mesh, 'mesh');
32
+ assert.notNull(mesh, 'mesh');
33
+ assert.isNonNegativeInteger(edge_id, 'edge_id');
34
+ assert.defined(new_position, 'new_position');
35
+
36
+ const v_survivor = mesh.edge_read_vertex1(edge_id);
37
+ const v_victim = mesh.edge_read_vertex2(edge_id);
38
+
39
+ // 1. Kill adjacent faces and remove the collapse edge itself.
40
+ bt_edge_kill(mesh, edge_id);
41
+
42
+ // 2. Re-point every remaining edge/loop from the victim onto the survivor.
43
+ bt_vertex_replace(mesh, v_victim, v_survivor);
44
+
45
+ // 3. Release the now-disconnected victim vertex.
46
+ bt_vert_kill(mesh, v_victim);
47
+
48
+ // 4. Move the survivor to the requested position.
49
+ mesh.vertex_write_coordinate(v_survivor, new_position, new_position_offset);
50
+
51
+ return v_survivor;
52
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Kill every edge that shares both endpoints with `keep_edge`, leaving `keep_edge`
3
+ * itself alive. Useful as a pre-pass before {@link bt_edge_collapse} so that
4
+ * {@link bt_vertex_replace} cannot produce a self-loop edge when a direct parallel
5
+ * exists.
6
+ *
7
+ * Adjacent faces of each killed parallel are removed as part of bt_edge_kill; the
8
+ * return value reports how many were taken down so callers doing face-count
9
+ * bookkeeping don't have to rescan.
10
+ *
11
+ * @param {BinaryTopology} mesh
12
+ * @param {number} keep_edge Edge ID to preserve; its other-parallels are killed.
13
+ * @returns {number} Number of faces killed as a side effect.
14
+ */
15
+ export function bt_edge_kill_parallels(mesh: BinaryTopology, keep_edge: number): number;
16
+ //# sourceMappingURL=bt_edge_kill_parallels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bt_edge_kill_parallels.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,wEAHW,MAAM,GACJ,MAAM,CAyElB"}
@@ -0,0 +1,90 @@
1
+ import { assert } from "../../../../../../../assert.js";
2
+ import { NULL_POINTER } from "../../BinaryTopology.js";
3
+ import { bt_edge_kill } from "./bt_edge_kill.js";
4
+
5
+ /**
6
+ * Kill every edge that shares both endpoints with `keep_edge`, leaving `keep_edge`
7
+ * itself alive. Useful as a pre-pass before {@link bt_edge_collapse} so that
8
+ * {@link bt_vertex_replace} cannot produce a self-loop edge when a direct parallel
9
+ * exists.
10
+ *
11
+ * Adjacent faces of each killed parallel are removed as part of bt_edge_kill; the
12
+ * return value reports how many were taken down so callers doing face-count
13
+ * bookkeeping don't have to rescan.
14
+ *
15
+ * @param {BinaryTopology} mesh
16
+ * @param {number} keep_edge Edge ID to preserve; its other-parallels are killed.
17
+ * @returns {number} Number of faces killed as a side effect.
18
+ */
19
+ export function bt_edge_kill_parallels(mesh, keep_edge) {
20
+ assert.defined(mesh, 'mesh');
21
+ assert.notNull(mesh, 'mesh');
22
+ assert.isNonNegativeInteger(keep_edge, 'keep_edge');
23
+
24
+ const a = mesh.edge_read_vertex1(keep_edge);
25
+ const b = mesh.edge_read_vertex2(keep_edge);
26
+
27
+ const start_e = mesh.vertex_read_edge(b);
28
+
29
+ if (start_e === NULL_POINTER) {
30
+ return 0;
31
+ }
32
+
33
+ // Collect parallels while walking b's disk cycle. We snapshot into an array
34
+ // so that subsequent bt_edge_kill calls (which mutate the disk cycle) can't
35
+ // invalidate the traversal.
36
+ const victims = [];
37
+ let curr_e = start_e;
38
+
39
+ do {
40
+ let next_e;
41
+ if (mesh.edge_read_vertex1(curr_e) === b) {
42
+ next_e = mesh.edge_read_v1_disk_next(curr_e);
43
+ } else {
44
+ next_e = mesh.edge_read_v2_disk_next(curr_e);
45
+ }
46
+
47
+ if (curr_e !== keep_edge) {
48
+ const v1 = mesh.edge_read_vertex1(curr_e);
49
+ const v2 = mesh.edge_read_vertex2(curr_e);
50
+
51
+ if ((v1 === a && v2 === b) || (v1 === b && v2 === a)) {
52
+ victims.push(curr_e);
53
+ }
54
+ }
55
+
56
+ curr_e = next_e;
57
+ } while (curr_e !== start_e && curr_e !== NULL_POINTER);
58
+
59
+ const edge_pool = mesh.edges;
60
+ const face_pool = mesh.faces;
61
+
62
+ let faces_killed = 0;
63
+
64
+ for (let i = 0; i < victims.length; i++) {
65
+ const e = victims[i];
66
+
67
+ if (!edge_pool.is_allocated(e)) {
68
+ continue;
69
+ }
70
+
71
+ // Count still-allocated faces in this edge's radial loop cycle before
72
+ // bt_edge_kill drops them. Orphan loops (face already dead) are skipped.
73
+ const l0 = mesh.edge_read_loop(e);
74
+
75
+ if (l0 !== NULL_POINTER) {
76
+ let l = l0;
77
+ do {
78
+ const f = mesh.loop_read_face(l);
79
+ if (f !== NULL_POINTER && face_pool.is_allocated(f)) {
80
+ faces_killed++;
81
+ }
82
+ l = mesh.loop_read_radial_next(l);
83
+ } while (l !== l0 && l !== NULL_POINTER);
84
+ }
85
+
86
+ bt_edge_kill(mesh, e);
87
+ }
88
+
89
+ return faces_killed;
90
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Walk the mesh and fuse any pair of edges that share the same endpoint pair into a single edge.
3
+ *
4
+ * When two edges connect the same vertices, all loops on the victim are moved into the master's
5
+ * radial cycle, the victim is removed from both endpoint disk cycles, and the victim edge is
6
+ * deallocated. This restores the topology invariant that a vertex pair is represented by at most
7
+ * one edge — which is what loop/face neighbour queries rely on.
8
+ *
9
+ * Degenerate edges (v1 === v2) are left alone; callers that want those removed should run a
10
+ * dedicated pass.
11
+ *
12
+ * Typically used after {@link bt_merge_verts_by_distance}, which re-points vertex references but
13
+ * can leave behind multiple edges sharing the same endpoint pair.
14
+ *
15
+ * @param {BinaryTopology} mesh
16
+ * @returns {number} number of edges fused away
17
+ */
18
+ export function bt_mesh_fuse_duplicate_edges(mesh: BinaryTopology): number;
19
+ //# sourceMappingURL=bt_mesh_fuse_duplicate_edges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bt_mesh_fuse_duplicate_edges.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AACH,oEAFa,MAAM,CA6DlB"}
@@ -0,0 +1,83 @@
1
+ import { NULL_POINTER } from "../../BinaryTopology.js";
2
+ import { bt_disk_edge_remove } from "../bt_disk_edge_remove.js";
3
+ import { bt_radial_loop_add } from "../bt_radial_loop_add.js";
4
+ import { bt_radial_loop_remove } from "../bt_radial_loop_remove.js";
5
+ import { bt_kill_only_edge } from "./bt_kill_only_edge.js";
6
+
7
+ /**
8
+ * Walk the mesh and fuse any pair of edges that share the same endpoint pair into a single edge.
9
+ *
10
+ * When two edges connect the same vertices, all loops on the victim are moved into the master's
11
+ * radial cycle, the victim is removed from both endpoint disk cycles, and the victim edge is
12
+ * deallocated. This restores the topology invariant that a vertex pair is represented by at most
13
+ * one edge — which is what loop/face neighbour queries rely on.
14
+ *
15
+ * Degenerate edges (v1 === v2) are left alone; callers that want those removed should run a
16
+ * dedicated pass.
17
+ *
18
+ * Typically used after {@link bt_merge_verts_by_distance}, which re-points vertex references but
19
+ * can leave behind multiple edges sharing the same endpoint pair.
20
+ *
21
+ * @param {BinaryTopology} mesh
22
+ * @returns {number} number of edges fused away
23
+ */
24
+ export function bt_mesh_fuse_duplicate_edges(mesh) {
25
+ const edges = mesh.edges;
26
+ const edge_count = edges.size;
27
+
28
+ let removed_count = 0;
29
+
30
+ for (let master = 0; master < edge_count; master++) {
31
+ if (edges.is_allocated(master) === false) {
32
+ continue;
33
+ }
34
+
35
+ const master_v1 = mesh.edge_read_vertex1(master);
36
+ const master_v2 = mesh.edge_read_vertex2(master);
37
+
38
+ if (master_v1 === master_v2) {
39
+ // degenerate edge; skip
40
+ continue;
41
+ }
42
+
43
+ // walk master_v1's disk cycle, fusing any edge that also connects to master_v2
44
+ let curr = mesh.edge_read_v1_disk_next(master);
45
+
46
+ while (curr !== master) {
47
+
48
+ const curr_v1 = mesh.edge_read_vertex1(curr);
49
+ const curr_v2 = mesh.edge_read_vertex2(curr);
50
+
51
+ const curr_on_v1 = curr_v1 === master_v1;
52
+
53
+ // capture next before we potentially splice curr out of the disk cycle
54
+ const next = curr_on_v1
55
+ ? mesh.edge_read_v1_disk_next(curr)
56
+ : mesh.edge_read_v2_disk_next(curr);
57
+
58
+ const other_endpoint = curr_on_v1 ? curr_v2 : curr_v1;
59
+
60
+ if (other_endpoint === master_v2) {
61
+
62
+ // move every loop on curr into master's radial cycle
63
+ let l = mesh.edge_read_loop(curr);
64
+ while (l !== NULL_POINTER) {
65
+ bt_radial_loop_remove(mesh, l, curr);
66
+ bt_radial_loop_add(mesh, l, master);
67
+ l = mesh.edge_read_loop(curr);
68
+ }
69
+
70
+ bt_disk_edge_remove(mesh, curr, master_v1);
71
+ bt_disk_edge_remove(mesh, curr, master_v2);
72
+
73
+ bt_kill_only_edge(mesh, curr);
74
+
75
+ removed_count++;
76
+ }
77
+
78
+ curr = next;
79
+ }
80
+ }
81
+
82
+ return removed_count;
83
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Localized counterpart to {@link bt_mesh_fuse_duplicate_edges} that inspects only
3
+ * `v`'s disk cycle. Any two edges in that cycle sharing the same other endpoint
4
+ * are fused: loops move from the victim to the master, the victim is untangled
5
+ * from both endpoint disk cycles, and its memory is released.
6
+ *
7
+ * If transferring a loop would leave the master edge with two loops on the same
8
+ * face (i.e. the face has collapsed to a degenerate two-edge polygon), that face
9
+ * is killed as well.
10
+ *
11
+ * Self-loops on `v` are left alone; the caller should handle them separately.
12
+ *
13
+ * Typical use: after an iterative edit that may have produced link-vertex
14
+ * duplicates around `v`, run this to restore the one-edge-per-vertex-pair
15
+ * invariant without the cost of a whole-mesh pass.
16
+ *
17
+ * @param {BinaryTopology} mesh
18
+ * @param {number} v
19
+ * @returns {number} Number of faces killed as a side effect.
20
+ */
21
+ export function bt_vert_fuse_duplicate_edges(mesh: BinaryTopology, v: number): number;
22
+ //# sourceMappingURL=bt_vert_fuse_duplicate_edges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bt_vert_fuse_duplicate_edges.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,sEAHW,MAAM,GACJ,MAAM,CAyHlB"}
@@ -0,0 +1,148 @@
1
+ import { assert } from "../../../../../../../assert.js";
2
+ import { NULL_POINTER } from "../../BinaryTopology.js";
3
+ import { bt_disk_edge_remove } from "../bt_disk_edge_remove.js";
4
+ import { bt_loop_kill } from "../bt_loop_kill.js";
5
+ import { bt_radial_loop_add } from "../bt_radial_loop_add.js";
6
+ import { bt_radial_loop_remove } from "../bt_radial_loop_remove.js";
7
+ import { bt_kill_only_edge } from "../edge/bt_kill_only_edge.js";
8
+
9
+ /**
10
+ * Localized counterpart to {@link bt_mesh_fuse_duplicate_edges} that inspects only
11
+ * `v`'s disk cycle. Any two edges in that cycle sharing the same other endpoint
12
+ * are fused: loops move from the victim to the master, the victim is untangled
13
+ * from both endpoint disk cycles, and its memory is released.
14
+ *
15
+ * If transferring a loop would leave the master edge with two loops on the same
16
+ * face (i.e. the face has collapsed to a degenerate two-edge polygon), that face
17
+ * is killed as well.
18
+ *
19
+ * Self-loops on `v` are left alone; the caller should handle them separately.
20
+ *
21
+ * Typical use: after an iterative edit that may have produced link-vertex
22
+ * duplicates around `v`, run this to restore the one-edge-per-vertex-pair
23
+ * invariant without the cost of a whole-mesh pass.
24
+ *
25
+ * @param {BinaryTopology} mesh
26
+ * @param {number} v
27
+ * @returns {number} Number of faces killed as a side effect.
28
+ */
29
+ export function bt_vert_fuse_duplicate_edges(mesh, v) {
30
+ assert.defined(mesh, 'mesh');
31
+ assert.notNull(mesh, 'mesh');
32
+ assert.isNonNegativeInteger(v, 'v');
33
+
34
+ const edge_pool = mesh.edges;
35
+
36
+ const start_e = mesh.vertex_read_edge(v);
37
+
38
+ if (start_e === NULL_POINTER) {
39
+ return 0;
40
+ }
41
+
42
+ // Snapshot v's disk cycle up front so that later fusion operations, which
43
+ // mutate that cycle, don't invalidate our traversal cursor.
44
+ const edges_in_disk = [];
45
+ let curr_e = start_e;
46
+
47
+ do {
48
+ edges_in_disk.push(curr_e);
49
+
50
+ if (mesh.edge_read_vertex1(curr_e) === v) {
51
+ curr_e = mesh.edge_read_v1_disk_next(curr_e);
52
+ } else {
53
+ curr_e = mesh.edge_read_v2_disk_next(curr_e);
54
+ }
55
+ } while (curr_e !== start_e && curr_e !== NULL_POINTER);
56
+
57
+ // Group edges by other endpoint to detect duplicates in a single pass.
58
+ const master_by_other = new Map();
59
+ const fusion_masters = [];
60
+ const fusion_victims = [];
61
+ const fusion_others = [];
62
+
63
+ for (let i = 0; i < edges_in_disk.length; i++) {
64
+ const e = edges_in_disk[i];
65
+
66
+ if (!edge_pool.is_allocated(e)) {
67
+ continue;
68
+ }
69
+
70
+ const v1 = mesh.edge_read_vertex1(e);
71
+ const v2 = mesh.edge_read_vertex2(e);
72
+ const other = v1 === v ? v2 : v1;
73
+
74
+ if (other === v) {
75
+ // Self-loop; not our concern here.
76
+ continue;
77
+ }
78
+
79
+ if (master_by_other.has(other)) {
80
+ fusion_masters.push(master_by_other.get(other));
81
+ fusion_victims.push(e);
82
+ fusion_others.push(other);
83
+ } else {
84
+ master_by_other.set(other, e);
85
+ }
86
+ }
87
+
88
+ const face_pool = mesh.faces;
89
+
90
+ let faces_killed = 0;
91
+
92
+ for (let i = 0; i < fusion_masters.length; i++) {
93
+ const master = fusion_masters[i];
94
+ const victim = fusion_victims[i];
95
+ const other = fusion_others[i];
96
+
97
+ if (!edge_pool.is_allocated(victim) || !edge_pool.is_allocated(master)) {
98
+ continue;
99
+ }
100
+
101
+ let l = mesh.edge_read_loop(victim);
102
+
103
+ while (l !== NULL_POINTER) {
104
+ bt_radial_loop_remove(mesh, l, victim);
105
+
106
+ const face = mesh.loop_read_face(l);
107
+ let collapse_face = false;
108
+
109
+ if (face !== NULL_POINTER && face_pool.is_allocated(face)) {
110
+ // If master already has a loop on the same face, transferring
111
+ // this loop would give that face two coincident edges -- a
112
+ // degenerate polygon that has to die.
113
+ let mast_l = mesh.edge_read_loop(master);
114
+ if (mast_l !== NULL_POINTER) {
115
+ const mast_start = mast_l;
116
+ do {
117
+ if (mesh.loop_read_face(mast_l) === face) {
118
+ collapse_face = true;
119
+ break;
120
+ }
121
+ mast_l = mesh.loop_read_radial_next(mast_l);
122
+ } while (mast_l !== mast_start && mast_l !== NULL_POINTER);
123
+ }
124
+ }
125
+
126
+ bt_radial_loop_add(mesh, l, master);
127
+
128
+ if (collapse_face) {
129
+ const face_to_kill = face;
130
+ let fl = mesh.face_read_loop(face_to_kill);
131
+ while (fl !== NULL_POINTER) {
132
+ bt_loop_kill(mesh, fl);
133
+ fl = mesh.face_read_loop(face_to_kill);
134
+ }
135
+ face_pool.release(face_to_kill);
136
+ faces_killed++;
137
+ }
138
+
139
+ l = mesh.edge_read_loop(victim);
140
+ }
141
+
142
+ bt_disk_edge_remove(mesh, victim, v);
143
+ bt_disk_edge_remove(mesh, victim, other);
144
+ bt_kill_only_edge(mesh, victim);
145
+ }
146
+
147
+ return faces_killed;
148
+ }
@@ -64,11 +64,11 @@ export function bt_face_get_incenter(
64
64
 
65
65
  do {
66
66
  const vertex_id = mesh.loop_read_vertex(current_loop_id);
67
- mesh.vertex_read_coordinate(scratch_coord, 0, vertex_id);
67
+ mesh.vertex_read_coordinate(scratch_coords, 0, vertex_id);
68
68
 
69
- sum_x += scratch_coord[0];
70
- sum_y += scratch_coord[1];
71
- sum_z += scratch_coord[2];
69
+ sum_x += scratch_coords[0];
70
+ sum_y += scratch_coords[1];
71
+ sum_z += scratch_coords[2];
72
72
 
73
73
  vertex_count++;
74
74
  current_loop_id = mesh.loop_read_next(current_loop_id);
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Find the loop in `face_a` whose edge is shared with `face_b`.
3
+ *
4
+ * The returned loop belongs to `face_a` and its edge is also used by a loop in `face_b`.
5
+ * Combined with {@link BinaryTopology#loop_read_vertex} and {@link BinaryTopology#loop_read_next},
6
+ * this is enough to read the two vertices of the shared edge in `face_a`'s winding order,
7
+ * which is useful for constructing directed portals.
8
+ *
9
+ * @param {BinaryTopology} mesh
10
+ * @param {number} face_a
11
+ * @param {number} face_b
12
+ * @returns {number} loop ID in `face_a` that shares an edge with `face_b`, or {@link NULL_POINTER} if no shared edge exists
13
+ */
14
+ export function bt_faces_shared_loop(mesh: BinaryTopology, face_a: number, face_b: number): number;
15
+ //# sourceMappingURL=bt_faces_shared_loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bt_faces_shared_loop.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,mEAJW,MAAM,UACN,MAAM,GACJ,MAAM,CAiClB"}
@@ -0,0 +1,48 @@
1
+ import { assert } from "../../../../../../assert.js";
2
+ import { NULL_POINTER } from "../BinaryTopology.js";
3
+
4
+ /**
5
+ * Find the loop in `face_a` whose edge is shared with `face_b`.
6
+ *
7
+ * The returned loop belongs to `face_a` and its edge is also used by a loop in `face_b`.
8
+ * Combined with {@link BinaryTopology#loop_read_vertex} and {@link BinaryTopology#loop_read_next},
9
+ * this is enough to read the two vertices of the shared edge in `face_a`'s winding order,
10
+ * which is useful for constructing directed portals.
11
+ *
12
+ * @param {BinaryTopology} mesh
13
+ * @param {number} face_a
14
+ * @param {number} face_b
15
+ * @returns {number} loop ID in `face_a` that shares an edge with `face_b`, or {@link NULL_POINTER} if no shared edge exists
16
+ */
17
+ export function bt_faces_shared_loop(mesh, face_a, face_b) {
18
+ assert.defined(mesh, "mesh");
19
+ assert.notNull(mesh, "mesh");
20
+ assert.equal(mesh.isBinaryTopology, true, "mesh.isBinaryTopology !== true");
21
+ assert.isNonNegativeInteger(face_a, "face_a");
22
+ assert.isNonNegativeInteger(face_b, "face_b");
23
+
24
+ const start_loop = mesh.face_read_loop(face_a);
25
+
26
+ if (start_loop === NULL_POINTER) {
27
+ return NULL_POINTER;
28
+ }
29
+
30
+ let current_loop = start_loop;
31
+
32
+ do {
33
+ // walk the radial cycle around the edge of this loop
34
+ let radial_loop = mesh.loop_read_radial_next(current_loop);
35
+
36
+ while (radial_loop !== current_loop) {
37
+ if (mesh.loop_read_face(radial_loop) === face_b) {
38
+ return current_loop;
39
+ }
40
+
41
+ radial_loop = mesh.loop_read_radial_next(radial_loop);
42
+ }
43
+
44
+ current_loop = mesh.loop_read_next(current_loop);
45
+ } while (current_loop !== start_loop);
46
+
47
+ return NULL_POINTER;
48
+ }
@@ -10,20 +10,22 @@ export class NavigationMesh {
10
10
  * @param {BinaryTopology} source
11
11
  * @param {number} [agent_radius]
12
12
  * @param {number} [agent_height]
13
- * @param {number} [agent_max_climb] In radians, how steep of an angle can the agent go up by
13
+ * @param {number} [agent_max_climb_angle] In radians, how steep of an angle can the agent go up by
14
14
  * @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
15
15
  */
16
- build({ source, agent_radius, agent_height, agent_max_climb, up, }: BinaryTopology): void;
16
+ build({ source, agent_radius, agent_height, agent_max_climb_angle, up, }: BinaryTopology): void;
17
17
  /**
18
+ * Compute a walkable path between the two points.
19
+ * The result is a sequence of 3d points written into `output`. First point matches start, last point matches goal (snapped onto the mesh).
18
20
  *
19
- * @param {Float32Array} output
21
+ * @param {Float32Array} output packed XYZ triples
20
22
  * @param {number} start_x
21
23
  * @param {number} start_y
22
24
  * @param {number} start_z
23
25
  * @param {number} goal_x
24
26
  * @param {number} goal_y
25
27
  * @param {number} goal_z
26
- * @returns {number}
28
+ * @returns {number} number of 3d points written to `output` (0 if no path was found)
27
29
  */
28
30
  find_path(output: Float32Array, start_x: number, start_y: number, start_z: number, goal_x: number, goal_y: number, goal_z: number): number;
29
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationMesh.d.ts","sourceRoot":"","sources":["../../../../../src/engine/navigation/mesh/NavigationMesh.js"],"names":[],"mappings":"AAmCA;IAEI,yBAAgC;IAEhC;;;OAGG;IACH,KAFU,GAAG,CAEG;IAEhB;;;;;;;OAOG;IACH,oEANW,cAAc,QAwBxB;IAGD;;;;;;;;;;OAUG;IACH,kBATW,YAAY,WACZ,MAAM,WACN,MAAM,WACN,MAAM,UACN,MAAM,UACN,MAAM,UACN,MAAM,GACJ,MAAM,CAwGlB;CAEJ;+BA3L4C,gEAAgE;oBAFzF,gCAAgC"}
1
+ {"version":3,"file":"NavigationMesh.d.ts","sourceRoot":"","sources":["../../../../../src/engine/navigation/mesh/NavigationMesh.js"],"names":[],"mappings":"AAgCA;IAEI,yBAAgC;IAEhC;;;OAGG;IACH,KAFU,GAAG,CAEG;IAEhB;;;;;;;OAOG;IACH,0EANW,cAAc,QAwBxB;IAGD;;;;;;;;;;;;OAYG;IACH,kBATW,YAAY,WACZ,MAAM,WACN,MAAM,WACN,MAAM,UACN,MAAM,UACN,MAAM,UACN,MAAM,GACJ,MAAM,CA+HlB;CAEJ;+BAlN4C,gEAAgE;oBADzF,gCAAgC"}