@woosh/meep-engine 2.133.5 → 2.134.1

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 (83) 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/core/graph/coloring/colorizeGraphMCS.js +1 -1
  59. package/src/core/graph/convert_graph_to_dot_string.d.ts.map +1 -1
  60. package/src/core/graph/convert_graph_to_dot_string.js +2 -1
  61. package/src/core/graph/graph_compute_distance_matrix.d.ts +18 -1
  62. package/src/core/graph/graph_compute_distance_matrix.d.ts.map +1 -1
  63. package/src/core/graph/graph_compute_distance_matrix.js +21 -2
  64. package/src/core/graph/graph_compute_laplacian_matrix.d.ts.map +1 -1
  65. package/src/core/graph/graph_compute_laplacian_matrix.js +2 -1
  66. package/src/core/graph/graph_k_means_cluster.d.ts +10 -3
  67. package/src/core/graph/graph_k_means_cluster.d.ts.map +1 -1
  68. package/src/core/graph/graph_k_means_cluster.js +250 -123
  69. package/src/core/graph/layout/CircleLayout.js +6 -6
  70. package/src/core/graph/layout/Connection.js +1 -1
  71. package/src/core/graph/layout/box/aabb2_force_into_container.d.ts.map +1 -1
  72. package/src/core/graph/layout/box/aabb2_force_into_container.js +4 -2
  73. package/src/core/math/statistics/computeStatisticalMedian.js +1 -1
  74. package/src/engine/navigation/mesh/NavigationMesh.d.ts +6 -4
  75. package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
  76. package/src/engine/navigation/mesh/NavigationMesh.js +212 -190
  77. package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
  78. package/src/engine/navigation/mesh/build/navmesh_build_topology.js +20 -7
  79. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts +15 -0
  80. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts.map +1 -0
  81. package/src/engine/navigation/mesh/bvh_query_nearest_face.js +131 -0
  82. package/src/core/geom/3d/topology/simplify/quadratic/Quadratic3.d.ts.map +0 -1
  83. 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
+ }
@@ -75,7 +75,7 @@ export function colorizeGraphMCS(graph) {
75
75
 
76
76
  // Remove the maximum weight node from the graph so that it won't
77
77
  // be accidentally added again
78
- closed.set(i, true);
78
+ closed.set(max_vertex, true);
79
79
  }
80
80
 
81
81
  return colorizeGraphGreedy(graph, ordering);
@@ -1 +1 @@
1
- {"version":3,"file":"convert_graph_to_dot_string.d.ts","sourceRoot":"","sources":["../../../../src/core/graph/convert_graph_to_dot_string.js"],"names":[],"mappings":"AAYA;;;;;;GAMG;AACH,0FAFa,MAAM,CAgElB"}
1
+ {"version":3,"file":"convert_graph_to_dot_string.d.ts","sourceRoot":"","sources":["../../../../src/core/graph/convert_graph_to_dot_string.js"],"names":[],"mappings":"AAaA;;;;;;GAMG;AACH,0FAFa,MAAM,CAgElB"}
@@ -1,5 +1,6 @@
1
1
  import LineBuilder from "../codegen/LineBuilder.js";
2
2
  import { EdgeDirectionType } from "./Edge.js";
3
+ import { graphviz_escape_string } from "./format/graphviz/graphviz_escape_string.js";
3
4
 
4
5
  /**
5
6
  * @template T
@@ -7,7 +8,7 @@ import { EdgeDirectionType } from "./Edge.js";
7
8
  * @return {string}
8
9
  */
9
10
  function defaultNodeToDot(node) {
10
- return `[label="${node.toString()}"]`;
11
+ return `[label="${graphviz_escape_string(node.toString())}"]`;
11
12
  }
12
13
 
13
14
  /**
@@ -1,5 +1,22 @@
1
1
  /**
2
- * Produce a distance matrix from an input graph, tracing distances from each node to every node specified in target vector
2
+ * Produce a distance matrix from an input graph, tracing distances from each
3
+ * node to every node specified in the target vector.
4
+ *
5
+ * Traversal is BFS and each neighbour is only visited once. As a consequence
6
+ * this implementation gives correct shortest-path distances only when every
7
+ * edge has the same weight (typically `edge.weight === 1`). On graphs with
8
+ * heterogeneous weights the returned distances are the weight sum along the
9
+ * BFS tree, which is not the shortest-path distance in general — use
10
+ * Dijkstra or Floyd–Warshall for those cases instead.
11
+ *
12
+ * Edge costs are read from `edge.weight`, so uniform non-1 weights still
13
+ * produce distances scaled by the common weight, but this remains correct
14
+ * only because every path of the same hop count has the same total weight.
15
+ *
16
+ * Output layout: `m[row, col]` is the distance from the node at index `row`
17
+ * to the target node at index `col`. Columns whose index is not in `targets`
18
+ * are left at `POSITIVE_INFINITY` (except the diagonal, which is 0).
19
+ *
3
20
  * @see "A Fast Algorithm to Find All-Pairs Shortest Paths in Complex Networks" by Wei Peng et Al. 2012
4
21
  * @template T
5
22
  * @param {Graph<T>} graph
@@ -1 +1 @@
1
- {"version":3,"file":"graph_compute_distance_matrix.d.ts","sourceRoot":"","sources":["../../../../src/core/graph/graph_compute_distance_matrix.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,4FAJW,MAAM,EAAE,mCAEN,YAAY,CAgExB;6BA1E4B,gCAAgC"}
1
+ {"version":3,"file":"graph_compute_distance_matrix.d.ts","sourceRoot":"","sources":["../../../../src/core/graph/graph_compute_distance_matrix.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,4FAJW,MAAM,EAAE,mCAEN,YAAY,CAkExB;6BA7F4B,gCAAgC"}
@@ -3,7 +3,24 @@ import { Deque } from "../collection/queue/Deque.js";
3
3
  import { SquareMatrix } from "../math/matrix/SquareMatrix.js";
4
4
 
5
5
  /**
6
- * Produce a distance matrix from an input graph, tracing distances from each node to every node specified in target vector
6
+ * Produce a distance matrix from an input graph, tracing distances from each
7
+ * node to every node specified in the target vector.
8
+ *
9
+ * Traversal is BFS and each neighbour is only visited once. As a consequence
10
+ * this implementation gives correct shortest-path distances only when every
11
+ * edge has the same weight (typically `edge.weight === 1`). On graphs with
12
+ * heterogeneous weights the returned distances are the weight sum along the
13
+ * BFS tree, which is not the shortest-path distance in general — use
14
+ * Dijkstra or Floyd–Warshall for those cases instead.
15
+ *
16
+ * Edge costs are read from `edge.weight`, so uniform non-1 weights still
17
+ * produce distances scaled by the common weight, but this remains correct
18
+ * only because every path of the same hop count has the same total weight.
19
+ *
20
+ * Output layout: `m[row, col]` is the distance from the node at index `row`
21
+ * to the target node at index `col`. Columns whose index is not in `targets`
22
+ * are left at `POSITIVE_INFINITY` (except the diagonal, which is 0).
23
+ *
7
24
  * @see "A Fast Algorithm to Find All-Pairs Shortest Paths in Complex Networks" by Wei Peng et Al. 2012
8
25
  * @template T
9
26
  * @param {Graph<T>} graph
@@ -60,7 +77,9 @@ export function graph_compute_distance_matrix(graph, node_array, targets, node_i
60
77
  // If we haven't visited this neighbor yet, its distance is the current distance + 1
61
78
  if (m_distances.getCellValue(index_0, target_index) === Number.POSITIVE_INFINITY) {
62
79
 
63
- const transition_cost = edge.weight;
80
+ // Fall back to unit weight when the edge has no explicit weight, so BFS
81
+ // produces meaningful hop-count distances on plain (non-weighted) edges.
82
+ const transition_cost = edge.weight !== undefined ? edge.weight : 1;
64
83
 
65
84
  const new_distance = m_distances.getCellValue(index_1, target_index) + transition_cost;
66
85
 
@@ -1 +1 @@
1
- {"version":3,"file":"graph_compute_laplacian_matrix.d.ts","sourceRoot":"","sources":["../../../../src/core/graph/graph_compute_laplacian_matrix.js"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,2EAHW,YAAY,sCAWtB;6BApB4B,gCAAgC"}
1
+ {"version":3,"file":"graph_compute_laplacian_matrix.d.ts","sourceRoot":"","sources":["../../../../src/core/graph/graph_compute_laplacian_matrix.js"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,2EAHW,YAAY,sCAYtB;6BArB4B,gCAAgC"}