@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.
- package/build/bundle-worker-image-decoder.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts +20 -0
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +50 -0
- package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts +4 -4
- package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.js +2 -2
- package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.js +1 -1
- package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.js +1 -1
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts +4 -4
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +3 -3
- package/src/core/geom/3d/topology/simplify/quadratic/{Quadratic3.d.ts → Quadric3.d.ts} +55 -29
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -0
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +307 -0
- package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts +7 -7
- package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.js +39 -13
- package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.js +1 -1
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.js +2 -2
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts +4 -4
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +5 -5
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts +8 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +56 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts +14 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.js +95 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +17 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +352 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts +21 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.js +52 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +16 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +90 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts +19 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js +83 -0
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts +22 -0
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js +148 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +4 -4
- package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts +15 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js +48 -0
- package/src/engine/navigation/mesh/NavigationMesh.d.ts +6 -4
- package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
- package/src/engine/navigation/mesh/NavigationMesh.js +212 -190
- package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
- package/src/engine/navigation/mesh/build/navmesh_build_topology.js +20 -7
- package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts +15 -0
- package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts.map +1 -0
- package/src/engine/navigation/mesh/bvh_query_nearest_face.js +131 -0
- package/src/core/geom/3d/topology/simplify/quadratic/Quadratic3.d.ts.map +0 -1
- 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
|
package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts.map
ADDED
|
@@ -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(
|
|
67
|
+
mesh.vertex_read_coordinate(scratch_coords, 0, vertex_id);
|
|
68
68
|
|
|
69
|
-
sum_x +=
|
|
70
|
-
sum_y +=
|
|
71
|
-
sum_z +=
|
|
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} [
|
|
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,
|
|
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":"
|
|
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"}
|