@woosh/meep-engine 2.163.7 → 2.163.9

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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.d.ts +23 -0
  3. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.d.ts.map +1 -0
  4. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.js +44 -0
  5. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.d.ts +2 -2
  6. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.d.ts.map +1 -1
  7. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js +120 -179
  8. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts +9 -10
  9. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
  10. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +12 -13
  11. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.d.ts +17 -0
  12. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.d.ts.map +1 -0
  13. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.js +45 -0
  14. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_euclidean_distance_field.d.ts +40 -0
  15. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_euclidean_distance_field.d.ts.map +1 -0
  16. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_euclidean_distance_field.js +84 -0
  17. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_compute_face_islands.d.ts.map +1 -1
  18. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_compute_face_islands.js +53 -78
  19. package/src/core/geom/vec3/v3_matrix3_rotate.d.ts +16 -0
  20. package/src/core/geom/vec3/v3_matrix3_rotate.d.ts.map +1 -0
  21. package/src/core/geom/vec3/v3_matrix3_rotate.js +49 -0
  22. package/src/core/geom/vec3/v3_orthonormal_matrix_from_normal.d.ts +2 -2
  23. package/src/core/geom/vec3/v3_orthonormal_matrix_from_normal.d.ts.map +1 -1
  24. package/src/core/geom/vec3/v3_orthonormal_matrix_from_normal.js +46 -46
  25. package/src/engine/graphics/sh3/path_tracer/sampling/getBiasedNormalSample.d.ts.map +1 -1
  26. package/src/engine/graphics/sh3/path_tracer/sampling/getBiasedNormalSample.js +6 -28
  27. package/src/engine/navigation/mesh/NavigationMesh.d.ts +6 -0
  28. package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
  29. package/src/engine/navigation/mesh/NavigationMesh.js +145 -234
  30. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +229 -0
  31. package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts +11 -0
  32. package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts.map +1 -1
  33. package/src/engine/navigation/mesh/bt_mesh_face_find_path.js +623 -100
  34. package/src/engine/navigation/mesh/bt_mesh_face_find_path_polyanya.d.ts +17 -0
  35. package/src/engine/navigation/mesh/bt_mesh_face_find_path_polyanya.d.ts.map +1 -0
  36. package/src/engine/navigation/mesh/bt_mesh_face_find_path_polyanya.js +682 -0
  37. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.d.ts.map +1 -1
  38. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.js +354 -138
  39. package/src/engine/navigation/mesh/bvh_segment_penetrates_mesh.d.ts +21 -0
  40. package/src/engine/navigation/mesh/bvh_segment_penetrates_mesh.d.ts.map +1 -0
  41. package/src/engine/navigation/mesh/bvh_segment_penetrates_mesh.js +133 -0
@@ -0,0 +1,133 @@
1
+ import {
2
+ COLUMN_CHILD_1,
3
+ COLUMN_CHILD_2,
4
+ COLUMN_USER_DATA,
5
+ ELEMENT_WORD_COUNT,
6
+ NULL_NODE
7
+ } from "../../../core/bvh2/bvh3/BVH.js";
8
+ import { NULL_POINTER } from "../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
9
+
10
+ // Plane-side slack and barycentric slack. Mesh vertices are float32, so a segment endpoint that lies ON
11
+ // a triangle sits within ~coord*2^-23 of its plane; PLANE_EPS keeps those (and grazing/coplanar pieces)
12
+ // from registering as a crossing. Only a genuinely transversal piece -- strictly on opposite sides of a
13
+ // triangle's plane and crossing its interior away from its own endpoints -- counts as a penetration.
14
+ const PLANE_EPS = 1e-3;
15
+ const BARY_EPS = 1e-6;
16
+
17
+ const _coords = new Float32Array(3);
18
+ const _stack = new Uint32Array(1024); // DFS node stack; navmesh BVHs are shallow (depth ~ log2(faces))
19
+
20
+ /** Standard slab test: does the segment p + t*d, t in [0,1], intersect the AABB [min,max]? */
21
+ function segment_intersects_aabb(minx, miny, minz, maxx, maxy, maxz, px, py, pz, dx, dy, dz) {
22
+ let tmin = 0, tmax = 1;
23
+
24
+ if (dx > -1e-12 && dx < 1e-12) { if (px < minx || px > maxx) return false; }
25
+ else { let t1 = (minx - px) / dx, t2 = (maxx - px) / dx; if (t1 > t2) { const t = t1; t1 = t2; t2 = t; } if (t1 > tmin) tmin = t1; if (t2 < tmax) tmax = t2; if (tmin > tmax) return false; }
26
+
27
+ if (dy > -1e-12 && dy < 1e-12) { if (py < miny || py > maxy) return false; }
28
+ else { let t1 = (miny - py) / dy, t2 = (maxy - py) / dy; if (t1 > t2) { const t = t1; t1 = t2; t2 = t; } if (t1 > tmin) tmin = t1; if (t2 < tmax) tmax = t2; if (tmin > tmax) return false; }
29
+
30
+ if (dz > -1e-12 && dz < 1e-12) { if (pz < minz || pz > maxz) return false; }
31
+ else { let t1 = (minz - pz) / dz, t2 = (maxz - pz) / dz; if (t1 > t2) { const t = t1; t1 = t2; t2 = t; } if (t1 > tmin) tmin = t1; if (t2 < tmax) tmax = t2; if (tmin > tmax) return false; }
32
+
33
+ return true;
34
+ }
35
+
36
+ /** True if segment (px,py,pz)->(qx,qy,qz) crosses the interior of triangle (a,b,c) transversally. */
37
+ function segment_crosses_triangle(px, py, pz, qx, qy, qz, ax, ay, az, bx, by, bz, cx, cy, cz) {
38
+ const ux = bx - ax, uy = by - ay, uz = bz - az;
39
+ const vx = cx - ax, vy = cy - ay, vz = cz - az;
40
+ const nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
41
+ const nlen = Math.hypot(nx, ny, nz);
42
+ if (nlen < 1e-12) return false; // degenerate triangle
43
+
44
+ const dP = ((px - ax) * nx + (py - ay) * ny + (pz - az) * nz) / nlen;
45
+ const dQ = ((qx - ax) * nx + (qy - ay) * ny + (qz - az) * nz) / nlen;
46
+
47
+ // must cross the plane strictly (not coplanar, not endpoint-on-plane)
48
+ if (!((dP > PLANE_EPS && dQ < -PLANE_EPS) || (dP < -PLANE_EPS && dQ > PLANE_EPS))) return false;
49
+
50
+ const t = dP / (dP - dQ);
51
+ if (t <= PLANE_EPS || t >= 1 - PLANE_EPS) return false; // crossing at/near an endpoint (on the surface)
52
+
53
+ // crossing point, tested for containment via barycentric coordinates in the triangle plane
54
+ const wx = px + (qx - px) * t - ax, wy = py + (qy - py) * t - ay, wz = pz + (qz - pz) * t - az;
55
+ const d00 = ux * ux + uy * uy + uz * uz, d01 = ux * vx + uy * vy + uz * vz, d11 = vx * vx + vy * vy + vz * vz;
56
+ const d20 = wx * ux + wy * uy + wz * uz, d21 = wx * vx + wy * vy + wz * vz;
57
+ const denom = d00 * d11 - d01 * d01;
58
+ if (denom > -1e-18 && denom < 1e-18) return false;
59
+ const s = (d11 * d20 - d01 * d21) / denom;
60
+ const w = (d00 * d21 - d01 * d20) / denom;
61
+
62
+ return s >= -BARY_EPS && w >= -BARY_EPS && s + w <= 1 + BARY_EPS;
63
+ }
64
+
65
+ /**
66
+ * Does the segment (ax,ay,az)->(bx,by,bz) pass THROUGH the mesh surface -- cross the interior of any
67
+ * triangle transversally (entering one side, exiting the other) strictly between its endpoints?
68
+ *
69
+ * This is the "penetration" test for a navmesh path piece. A piece that hugs the surface (coplanar with
70
+ * it) or flies over / under it -- a corner-only waypoint chord on a non-planar surface -- does NOT
71
+ * penetrate; a piece that tunnels through a wall or floor does. Endpoints lying on the surface (every
72
+ * path waypoint) are not penetrations.
73
+ *
74
+ * @param {BVH} bvh built by bvh_build_from_bt_mesh over `mesh`
75
+ * @param {BinaryTopology} mesh triangle mesh
76
+ * @param {number} ax
77
+ * @param {number} ay
78
+ * @param {number} az
79
+ * @param {number} bx
80
+ * @param {number} by
81
+ * @param {number} bz
82
+ * @returns {boolean}
83
+ */
84
+ export function bvh_segment_penetrates_mesh(bvh, mesh, ax, ay, az, bx, by, bz) {
85
+ const root = bvh.root;
86
+ if (root === NULL_NODE) return false;
87
+
88
+ const float32 = bvh.__data_float32;
89
+ const uint32 = bvh.__data_uint32;
90
+ const dx = bx - ax, dy = by - ay, dz = bz - az;
91
+
92
+ let sp = 0;
93
+ _stack[sp++] = root;
94
+
95
+ while (sp > 0) {
96
+ const node = _stack[--sp];
97
+ const address = node * ELEMENT_WORD_COUNT;
98
+
99
+ if (!segment_intersects_aabb(
100
+ float32[address], float32[address + 1], float32[address + 2],
101
+ float32[address + 3], float32[address + 4], float32[address + 5],
102
+ ax, ay, az, dx, dy, dz
103
+ )) {
104
+ continue;
105
+ }
106
+
107
+ const child_1 = uint32[address + COLUMN_CHILD_1];
108
+ if (child_1 !== NULL_NODE) {
109
+ _stack[sp++] = child_1;
110
+ _stack[sp++] = uint32[address + COLUMN_CHILD_2];
111
+ continue;
112
+ }
113
+
114
+ const face_id = uint32[address + COLUMN_USER_DATA];
115
+ const loop_a = mesh.face_read_loop(face_id);
116
+ if (loop_a === NULL_POINTER) continue;
117
+ const loop_b = mesh.loop_read_next(loop_a);
118
+ const loop_c = mesh.loop_read_next(loop_b);
119
+
120
+ mesh.vertex_read_coordinate(_coords, 0, mesh.loop_read_vertex(loop_a));
121
+ const tax = _coords[0], tay = _coords[1], taz = _coords[2];
122
+ mesh.vertex_read_coordinate(_coords, 0, mesh.loop_read_vertex(loop_b));
123
+ const tbx = _coords[0], tby = _coords[1], tbz = _coords[2];
124
+ mesh.vertex_read_coordinate(_coords, 0, mesh.loop_read_vertex(loop_c));
125
+ const tcx = _coords[0], tcy = _coords[1], tcz = _coords[2];
126
+
127
+ if (segment_crosses_triangle(ax, ay, az, bx, by, bz, tax, tay, taz, tbx, tby, tbz, tcx, tcy, tcz)) {
128
+ return true;
129
+ }
130
+ }
131
+
132
+ return false;
133
+ }