@woosh/meep-engine 2.133.3 → 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 +2 -2
- 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/binary/BitSet.d.ts +6 -0
- package/src/core/binary/BitSet.d.ts.map +1 -1
- package/src/core/binary/BitSet.js +38 -1
- package/src/core/binary/operations/bitCount.d.ts.map +1 -1
- package/src/core/binary/operations/bitCount.js +11 -6
- package/src/core/geom/3d/aabb/AABB3.d.ts +7 -1
- package/src/core/geom/3d/aabb/AABB3.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/AABB3.js +14 -1
- 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/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/Terrain.js +6 -1
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +10 -9
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +14 -11
- package/src/engine/graphics/ecs/water/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterSystem.js +3 -0
- package/src/engine/graphics/material/SplatMaterial.d.ts.map +1 -1
- package/src/engine/graphics/material/SplatMaterial.js +2 -4
- package/src/engine/graphics/shaders/TerrainShader.js +4 -11
- 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/engine/physics/gjk/gjk.d.ts +16 -0
- package/src/engine/physics/gjk/gjk.d.ts.map +1 -0
- package/src/engine/physics/gjk/gjk.js +378 -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,378 @@
|
|
|
1
|
+
import { v3_dot } from "../../../core/geom/vec3/v3_dot.js";
|
|
2
|
+
import { v3_length } from "../../../core/geom/vec3/v3_length.js";
|
|
3
|
+
|
|
4
|
+
const GJK_MAX_ITERATIONS = 64;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Module-level scratch buffers to avoid per-call allocations.
|
|
8
|
+
*/
|
|
9
|
+
const scratch_support_a = new Float32Array(3);
|
|
10
|
+
const scratch_support_b = new Float32Array(3);
|
|
11
|
+
const scratch_dir = new Float32Array(3);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Compute the Minkowski difference support point for two shapes.
|
|
15
|
+
* support(A-B, d) = support(A, d) - support(B, -d)
|
|
16
|
+
*
|
|
17
|
+
* The direction is normalized before being passed to the shape support
|
|
18
|
+
* functions, since {@link AbstractShape3D#support} assumes a unit vector.
|
|
19
|
+
*
|
|
20
|
+
* @param {number[]|Float32Array} result
|
|
21
|
+
* @param {number} result_offset
|
|
22
|
+
* @param {AbstractShape3D} shape_a
|
|
23
|
+
* @param {AbstractShape3D} shape_b
|
|
24
|
+
* @param {number} dir_x
|
|
25
|
+
* @param {number} dir_y
|
|
26
|
+
* @param {number} dir_z
|
|
27
|
+
*/
|
|
28
|
+
function minkowski_support(
|
|
29
|
+
result, result_offset,
|
|
30
|
+
shape_a,
|
|
31
|
+
shape_b,
|
|
32
|
+
dir_x, dir_y, dir_z
|
|
33
|
+
) {
|
|
34
|
+
// Normalize direction — support() contract requires a unit vector
|
|
35
|
+
const len = v3_length(dir_x, dir_y, dir_z);
|
|
36
|
+
|
|
37
|
+
if (len > 0) {
|
|
38
|
+
const inv = 1 / len;
|
|
39
|
+
dir_x *= inv;
|
|
40
|
+
dir_y *= inv;
|
|
41
|
+
dir_z *= inv;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
shape_a.support(scratch_support_a, 0, dir_x, dir_y, dir_z);
|
|
45
|
+
shape_b.support(scratch_support_b, 0, -dir_x, -dir_y, -dir_z);
|
|
46
|
+
|
|
47
|
+
result[result_offset] = scratch_support_a[0] - scratch_support_b[0];
|
|
48
|
+
result[result_offset + 1] = scratch_support_a[1] - scratch_support_b[1];
|
|
49
|
+
result[result_offset + 2] = scratch_support_a[2] - scratch_support_b[2];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* GJK intersection test for two convex shapes.
|
|
54
|
+
*
|
|
55
|
+
* Determines whether two convex shapes overlap by iteratively building a simplex
|
|
56
|
+
* in the Minkowski difference space. If the origin is enclosed by the simplex,
|
|
57
|
+
* the shapes intersect.
|
|
58
|
+
*
|
|
59
|
+
* Adapted from https://github.com/kevinmoran/GJK/blob/master/GJK.h
|
|
60
|
+
*
|
|
61
|
+
* @param {number[]|Float32Array} simplex Working buffer for simplex vertices (4 vec3s). Must have length >= 12.
|
|
62
|
+
* @param {AbstractShape3D} shape_a
|
|
63
|
+
* @param {AbstractShape3D} shape_b
|
|
64
|
+
* @returns {boolean} true if the shapes intersect
|
|
65
|
+
*/
|
|
66
|
+
export function gjk(simplex, shape_a, shape_b) {
|
|
67
|
+
|
|
68
|
+
const dir = scratch_dir;
|
|
69
|
+
|
|
70
|
+
// Initial search direction — arbitrary, (1,0,0)
|
|
71
|
+
|
|
72
|
+
// Get initial support point (simplex point C)
|
|
73
|
+
minkowski_support(
|
|
74
|
+
simplex, 6,
|
|
75
|
+
shape_a, shape_b,
|
|
76
|
+
1, 0, 0
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Search toward the origin from C
|
|
80
|
+
dir[0] = -simplex[6];
|
|
81
|
+
dir[1] = -simplex[7];
|
|
82
|
+
dir[2] = -simplex[8];
|
|
83
|
+
|
|
84
|
+
if (dir[0] === 0 && dir[1] === 0 && dir[2] === 0) {
|
|
85
|
+
// Origin is exactly on the first support point — intersection
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Get second support point (simplex point B)
|
|
90
|
+
minkowski_support(simplex, 3, shape_a, shape_b, dir[0], dir[1], dir[2]);
|
|
91
|
+
|
|
92
|
+
// B didn't pass the origin — no intersection possible
|
|
93
|
+
if (v3_dot(simplex[3], simplex[4], simplex[5], dir[0], dir[1], dir[2]) < 0) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Line case: compute direction perpendicular to line segment BC toward origin
|
|
98
|
+
// CB = C - B
|
|
99
|
+
const cb_x = simplex[6] - simplex[3];
|
|
100
|
+
const cb_y = simplex[7] - simplex[4];
|
|
101
|
+
const cb_z = simplex[8] - simplex[5];
|
|
102
|
+
|
|
103
|
+
// BO = -B (origin - B)
|
|
104
|
+
const bo_x = -simplex[3];
|
|
105
|
+
const bo_y = -simplex[4];
|
|
106
|
+
const bo_z = -simplex[5];
|
|
107
|
+
|
|
108
|
+
// dir = CB × BO × CB (triple cross product)
|
|
109
|
+
triple_cross_product(dir, cb_x, cb_y, cb_z, bo_x, bo_y, bo_z);
|
|
110
|
+
|
|
111
|
+
// Handle degenerate case where origin is on the line segment
|
|
112
|
+
if (dir[0] === 0 && dir[1] === 0 && dir[2] === 0) {
|
|
113
|
+
// Origin is on the line segment — pick any perpendicular direction
|
|
114
|
+
// Use the cross product of CB with an arbitrary axis
|
|
115
|
+
// CB × (1,0,0)
|
|
116
|
+
dir[0] = cb_y;
|
|
117
|
+
dir[1] = -cb_x;
|
|
118
|
+
dir[2] = 0;
|
|
119
|
+
|
|
120
|
+
if (dir[0] === 0 && dir[1] === 0 && dir[2] === 0) {
|
|
121
|
+
// CB is parallel to (1,0,0), use (0,1,0)
|
|
122
|
+
dir[0] = -cb_z;
|
|
123
|
+
dir[1] = 0;
|
|
124
|
+
dir[2] = cb_x;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let simplex_size = 2; // we have B and C
|
|
129
|
+
|
|
130
|
+
for (let iterations = 0; iterations < GJK_MAX_ITERATIONS; iterations++) {
|
|
131
|
+
// Get new support point A
|
|
132
|
+
minkowski_support(simplex, 0, shape_a, shape_b, dir[0], dir[1], dir[2]);
|
|
133
|
+
|
|
134
|
+
const a_x = simplex[0];
|
|
135
|
+
const a_y = simplex[1];
|
|
136
|
+
const a_z = simplex[2];
|
|
137
|
+
|
|
138
|
+
// Check if A passed the origin
|
|
139
|
+
if (v3_dot(a_x, a_y, a_z, dir[0], dir[1], dir[2]) < 0) {
|
|
140
|
+
return false; // no intersection
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
simplex_size++;
|
|
144
|
+
|
|
145
|
+
if (simplex_size === 3) {
|
|
146
|
+
// Triangle case
|
|
147
|
+
update_simplex_triangle(dir, simplex);
|
|
148
|
+
} else {
|
|
149
|
+
// Tetrahedron case
|
|
150
|
+
if (update_simplex_tetrahedron(dir, simplex)) {
|
|
151
|
+
// Origin is inside the tetrahedron — intersection!
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// The simplex was reduced to a triangle, so keep size at 3
|
|
156
|
+
simplex_size = 3;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Did not converge — assume no intersection
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Compute the triple cross product: (a × b) × a
|
|
166
|
+
*
|
|
167
|
+
* @param {number[]|Float32Array} result output vec3
|
|
168
|
+
* @param {number} ax
|
|
169
|
+
* @param {number} ay
|
|
170
|
+
* @param {number} az
|
|
171
|
+
* @param {number} bx
|
|
172
|
+
* @param {number} by
|
|
173
|
+
* @param {number} bz
|
|
174
|
+
*/
|
|
175
|
+
function triple_cross_product(result, ax, ay, az, bx, by, bz) {
|
|
176
|
+
// First: t = a × b
|
|
177
|
+
const tx = ay * bz - az * by;
|
|
178
|
+
const ty = az * bx - ax * bz;
|
|
179
|
+
const tz = ax * by - ay * bx;
|
|
180
|
+
|
|
181
|
+
// Then: t × a
|
|
182
|
+
result[0] = ty * az - tz * ay;
|
|
183
|
+
result[1] = tz * ax - tx * az;
|
|
184
|
+
result[2] = tx * ay - ty * ax;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Update simplex for the triangle case (3 points: A, B, C).
|
|
189
|
+
*
|
|
190
|
+
* Determines the Voronoi region of the origin relative to triangle ABC
|
|
191
|
+
* and updates the search direction accordingly.
|
|
192
|
+
*
|
|
193
|
+
* simplex layout: [A(0-2), B(3-5), C(6-8)]
|
|
194
|
+
*
|
|
195
|
+
* @param {number[]|Float32Array} search_dir output: next search direction
|
|
196
|
+
* @param {Float32Array} simplex
|
|
197
|
+
*/
|
|
198
|
+
function update_simplex_triangle(search_dir, simplex) {
|
|
199
|
+
const a_x = simplex[0], a_y = simplex[1], a_z = simplex[2];
|
|
200
|
+
const b_x = simplex[3], b_y = simplex[4], b_z = simplex[5];
|
|
201
|
+
const c_x = simplex[6], c_y = simplex[7], c_z = simplex[8];
|
|
202
|
+
|
|
203
|
+
// AB = B - A
|
|
204
|
+
const ab_x = b_x - a_x;
|
|
205
|
+
const ab_y = b_y - a_y;
|
|
206
|
+
const ab_z = b_z - a_z;
|
|
207
|
+
|
|
208
|
+
// AC = C - A
|
|
209
|
+
const ac_x = c_x - a_x;
|
|
210
|
+
const ac_y = c_y - a_y;
|
|
211
|
+
const ac_z = c_z - a_z;
|
|
212
|
+
|
|
213
|
+
// AO = -A (origin - A)
|
|
214
|
+
const ao_x = -a_x;
|
|
215
|
+
const ao_y = -a_y;
|
|
216
|
+
const ao_z = -a_z;
|
|
217
|
+
|
|
218
|
+
// Normal of triangle ABC
|
|
219
|
+
const abc_x = ab_y * ac_z - ab_z * ac_y;
|
|
220
|
+
const abc_y = ab_z * ac_x - ab_x * ac_z;
|
|
221
|
+
const abc_z = ab_x * ac_y - ab_y * ac_x;
|
|
222
|
+
|
|
223
|
+
// Test edge AC
|
|
224
|
+
// ABC × AC
|
|
225
|
+
const abc_cross_ac_x = abc_y * ac_z - abc_z * ac_y;
|
|
226
|
+
const abc_cross_ac_y = abc_z * ac_x - abc_x * ac_z;
|
|
227
|
+
const abc_cross_ac_z = abc_x * ac_y - abc_y * ac_x;
|
|
228
|
+
|
|
229
|
+
if (v3_dot(abc_cross_ac_x, abc_cross_ac_y, abc_cross_ac_z, ao_x, ao_y, ao_z) > 0) {
|
|
230
|
+
// Origin is on the AC side
|
|
231
|
+
// Reduce simplex to line AC (A stays as A, C moves to B position)
|
|
232
|
+
simplex[3] = c_x;
|
|
233
|
+
simplex[4] = c_y;
|
|
234
|
+
simplex[5] = c_z;
|
|
235
|
+
|
|
236
|
+
// New direction: AC × AO × AC
|
|
237
|
+
triple_cross_product(search_dir, ac_x, ac_y, ac_z, ao_x, ao_y, ao_z);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Test edge AB
|
|
242
|
+
// AB × ABC
|
|
243
|
+
const ab_cross_abc_x = ab_y * abc_z - ab_z * abc_y;
|
|
244
|
+
const ab_cross_abc_y = ab_z * abc_x - ab_x * abc_z;
|
|
245
|
+
const ab_cross_abc_z = ab_x * abc_y - ab_y * abc_x;
|
|
246
|
+
|
|
247
|
+
if (v3_dot(ab_cross_abc_x, ab_cross_abc_y, ab_cross_abc_z, ao_x, ao_y, ao_z) > 0) {
|
|
248
|
+
// Origin is on the AB side
|
|
249
|
+
// Keep simplex as line AB (C slot is cleared by not using it)
|
|
250
|
+
simplex[6] = simplex[3];
|
|
251
|
+
simplex[7] = simplex[4];
|
|
252
|
+
simplex[8] = simplex[5];
|
|
253
|
+
|
|
254
|
+
// New direction: AB × AO × AB
|
|
255
|
+
triple_cross_product(search_dir, ab_x, ab_y, ab_z, ao_x, ao_y, ao_z);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Origin is above or below the triangle
|
|
260
|
+
if (v3_dot(abc_x, abc_y, abc_z, ao_x, ao_y, ao_z) > 0) {
|
|
261
|
+
// Origin is above — search in normal direction
|
|
262
|
+
// Simplex stays as A, B, C
|
|
263
|
+
search_dir[0] = abc_x;
|
|
264
|
+
search_dir[1] = abc_y;
|
|
265
|
+
search_dir[2] = abc_z;
|
|
266
|
+
} else {
|
|
267
|
+
// Origin is below — swap B and C, search in -normal
|
|
268
|
+
const tmp_x = simplex[3], tmp_y = simplex[4], tmp_z = simplex[5];
|
|
269
|
+
simplex[3] = simplex[6];
|
|
270
|
+
simplex[4] = simplex[7];
|
|
271
|
+
simplex[5] = simplex[8];
|
|
272
|
+
simplex[6] = tmp_x;
|
|
273
|
+
simplex[7] = tmp_y;
|
|
274
|
+
simplex[8] = tmp_z;
|
|
275
|
+
|
|
276
|
+
search_dir[0] = -abc_x;
|
|
277
|
+
search_dir[1] = -abc_y;
|
|
278
|
+
search_dir[2] = -abc_z;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Update simplex for the tetrahedron case (4 points: A, B, C, D).
|
|
284
|
+
*
|
|
285
|
+
* Tests which face of the tetrahedron is closest to the origin and
|
|
286
|
+
* reduces the simplex accordingly. Returns true if the origin is
|
|
287
|
+
* inside the tetrahedron.
|
|
288
|
+
*
|
|
289
|
+
* simplex layout: [A(0-2), B(3-5), C(6-8), D(9-11)]
|
|
290
|
+
*
|
|
291
|
+
* @param {number[]|Float32Array} search_dir output: next search direction (only written when returning false)
|
|
292
|
+
* @param {Float32Array} simplex
|
|
293
|
+
* @returns {boolean} true if origin is inside the tetrahedron
|
|
294
|
+
*/
|
|
295
|
+
function update_simplex_tetrahedron(search_dir, simplex) {
|
|
296
|
+
const a_x = simplex[0], a_y = simplex[1], a_z = simplex[2];
|
|
297
|
+
const b_x = simplex[3], b_y = simplex[4], b_z = simplex[5];
|
|
298
|
+
const c_x = simplex[6], c_y = simplex[7], c_z = simplex[8];
|
|
299
|
+
const d_x = simplex[9], d_y = simplex[10], d_z = simplex[11];
|
|
300
|
+
|
|
301
|
+
// AB, AC, AD vectors
|
|
302
|
+
const ab_x = b_x - a_x, ab_y = b_y - a_y, ab_z = b_z - a_z;
|
|
303
|
+
const ac_x = c_x - a_x, ac_y = c_y - a_y, ac_z = c_z - a_z;
|
|
304
|
+
const ad_x = d_x - a_x, ad_y = d_y - a_y, ad_z = d_z - a_z;
|
|
305
|
+
|
|
306
|
+
// AO = origin - A = -A
|
|
307
|
+
const ao_x = -a_x, ao_y = -a_y, ao_z = -a_z;
|
|
308
|
+
|
|
309
|
+
// Face normals (outward-facing from A's perspective)
|
|
310
|
+
// ABC normal
|
|
311
|
+
const abc_x = ab_y * ac_z - ab_z * ac_y;
|
|
312
|
+
const abc_y = ab_z * ac_x - ab_x * ac_z;
|
|
313
|
+
const abc_z = ab_x * ac_y - ab_y * ac_x;
|
|
314
|
+
|
|
315
|
+
// ACD normal
|
|
316
|
+
const acd_x = ac_y * ad_z - ac_z * ad_y;
|
|
317
|
+
const acd_y = ac_z * ad_x - ac_x * ad_z;
|
|
318
|
+
const acd_z = ac_x * ad_y - ac_y * ad_x;
|
|
319
|
+
|
|
320
|
+
// ADB normal
|
|
321
|
+
const adb_x = ad_y * ab_z - ad_z * ab_y;
|
|
322
|
+
const adb_y = ad_z * ab_x - ad_x * ab_z;
|
|
323
|
+
const adb_z = ad_x * ab_y - ad_y * ab_x;
|
|
324
|
+
|
|
325
|
+
// Test each face to see if the origin is on the outside
|
|
326
|
+
|
|
327
|
+
// Check face ABC (opposite to D)
|
|
328
|
+
const abc_test = v3_dot(abc_x, abc_y, abc_z, ao_x, ao_y, ao_z);
|
|
329
|
+
// Make sure normal points away from D
|
|
330
|
+
const abc_d_side = v3_dot(abc_x, abc_y, abc_z, ad_x, ad_y, ad_z);
|
|
331
|
+
|
|
332
|
+
if (abc_test * abc_d_side < 0) {
|
|
333
|
+
// Origin is on the opposite side of ABC from D
|
|
334
|
+
// Reduce to triangle ABC: D is dropped
|
|
335
|
+
// simplex = [A, B, C] — A(0), B(3), C(6) already in place
|
|
336
|
+
update_simplex_triangle(search_dir, simplex);
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Check face ACD (opposite to B)
|
|
341
|
+
const acd_test = v3_dot(acd_x, acd_y, acd_z, ao_x, ao_y, ao_z);
|
|
342
|
+
const acd_b_side = v3_dot(acd_x, acd_y, acd_z, ab_x, ab_y, ab_z);
|
|
343
|
+
|
|
344
|
+
if (acd_test * acd_b_side < 0) {
|
|
345
|
+
// Origin is outside face ACD
|
|
346
|
+
// Reduce to triangle ACD: replace B with D
|
|
347
|
+
simplex[3] = c_x;
|
|
348
|
+
simplex[4] = c_y;
|
|
349
|
+
simplex[5] = c_z;
|
|
350
|
+
simplex[6] = d_x;
|
|
351
|
+
simplex[7] = d_y;
|
|
352
|
+
simplex[8] = d_z;
|
|
353
|
+
|
|
354
|
+
update_simplex_triangle(search_dir, simplex);
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Check face ADB (opposite to C)
|
|
359
|
+
const adb_test = v3_dot(adb_x, adb_y, adb_z, ao_x, ao_y, ao_z);
|
|
360
|
+
const adb_c_side = v3_dot(adb_x, adb_y, adb_z, ac_x, ac_y, ac_z);
|
|
361
|
+
|
|
362
|
+
if (adb_test * adb_c_side < 0) {
|
|
363
|
+
// Origin is outside face ADB
|
|
364
|
+
// Reduce to triangle ADB: replace C with B, B with D
|
|
365
|
+
simplex[6] = b_x;
|
|
366
|
+
simplex[7] = b_y;
|
|
367
|
+
simplex[8] = b_z;
|
|
368
|
+
simplex[3] = d_x;
|
|
369
|
+
simplex[4] = d_y;
|
|
370
|
+
simplex[5] = d_z;
|
|
371
|
+
|
|
372
|
+
update_simplex_triangle(search_dir, simplex);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Origin is inside the tetrahedron
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Quadratic3.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/geom/3d/topology/simplify/quadratic/Quadratic3.js"],"names":[],"mappings":"AASA;;;GAGG;AACH;IAGI,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IAGP,WAAO;IACP,WAAO;IACP,WAAO;IAGP,WAAO;IACP,WAAO;IAGP,WAAO;IAGP;;;OAGG;IACH,kBAFW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,QAMjD;IAED;;;OAGG;IACH,eAFW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,QAcjD;IAED;;;;;OAKG;IACH,sBAJW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,WACvC,MAAM,GACJ,OAAO,CAkCnB;IAED;;;;;;OAMG;IACH,kBALW,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,QAgBhB;IAED;;;OAGG;IACH,sCAmBC;IAED;;;;;;OAMG;IACH,YALW,MAAM,KACN,MAAM,KACN,MAAM,GACJ,MAAM,CASlB;IAED;;;;;;;OAOG;IACH,cAHW,MAAM,EAAE,GACN,OAAO,CAgBnB;IAED;;;OAGG;IACH,OAFW,UAAU,QAuBpB;IAED;;;OAGG;IACH,kBAFW,MAAM,QAoBhB;IAED;;;OAGG;IACH,SAFa,UAAU,CAQtB;IAED;;;OAGG;IACH,YAFW,UAAU,QAqBpB;IAED;;OAEG;IACH,cAmBC;CACJ"}
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import { vec3 } from "gl-matrix";
|
|
2
|
-
import { EPSILON } from "../../../../../math/EPSILON.js";
|
|
3
|
-
import { fabsf } from "../../../../../math/fabsf.js";
|
|
4
|
-
import { v3_dot } from "../../../../vec3/v3_dot.js";
|
|
5
|
-
import { compute_triangle_normal } from "../../../triangle/compute_triangle_normal.js";
|
|
6
|
-
|
|
7
|
-
const scratch_v3 = new Float32Array(3);
|
|
8
|
-
const scratch_m3 = new Float32Array(9);
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Quadric Error Metric
|
|
12
|
-
* Triangular 4x4 matrix, see https://en.wikipedia.org/wiki/Triangular_matrix
|
|
13
|
-
*/
|
|
14
|
-
export class Quadratic3 {
|
|
15
|
-
|
|
16
|
-
// Row 0
|
|
17
|
-
a2 = 0;
|
|
18
|
-
ab = 0;
|
|
19
|
-
ac = 0;
|
|
20
|
-
ad = 0;
|
|
21
|
-
|
|
22
|
-
// Row 1
|
|
23
|
-
b2 = 0;
|
|
24
|
-
bc = 0;
|
|
25
|
-
bd = 0;
|
|
26
|
-
|
|
27
|
-
// Row 2
|
|
28
|
-
c2 = 0;
|
|
29
|
-
cd = 0;
|
|
30
|
-
|
|
31
|
-
// Row 3
|
|
32
|
-
d2 = 0;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
* @param {ArrayLike<number>|number[]|Float32Array} result
|
|
38
|
-
*/
|
|
39
|
-
toVector3(result) {
|
|
40
|
-
result[0] = this.ad;
|
|
41
|
-
result[1] = this.bd;
|
|
42
|
-
result[2] = this.cd;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
*
|
|
47
|
-
* @param {ArrayLike<number>|number[]|Float32Array} m3
|
|
48
|
-
*/
|
|
49
|
-
toTensorM3(m3) {
|
|
50
|
-
m3[0] = this.a2;
|
|
51
|
-
m3[1] = this.ab;
|
|
52
|
-
m3[2] = this.ac;
|
|
53
|
-
|
|
54
|
-
m3[3] = this.ab;
|
|
55
|
-
m3[4] = this.b2;
|
|
56
|
-
m3[5] = this.bc;
|
|
57
|
-
|
|
58
|
-
m3[6] = this.ac;
|
|
59
|
-
m3[7] = this.bc;
|
|
60
|
-
m3[8] = this.c2;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Equivalent to taking a tensor followed by matrix inversion
|
|
65
|
-
* @param {ArrayLike<number>|number[]|Float32Array} m3
|
|
66
|
-
* @param {number} epsilon
|
|
67
|
-
* @returns {boolean} whether operation was successful or not
|
|
68
|
-
*/
|
|
69
|
-
toTensorM3Inverse(m3, epsilon) {
|
|
70
|
-
const a2 = this.a2;
|
|
71
|
-
const b2 = this.b2;
|
|
72
|
-
const c2 = this.c2;
|
|
73
|
-
const bc = this.bc;
|
|
74
|
-
const ab = this.ab;
|
|
75
|
-
const ac = this.ac;
|
|
76
|
-
|
|
77
|
-
const det = a2 * (b2 * c2 - bc * bc) -
|
|
78
|
-
ab * (ab * c2 - ac * bc) +
|
|
79
|
-
ac * (ab * bc - ac * b2);
|
|
80
|
-
|
|
81
|
-
if (fabsf(det) > epsilon) {
|
|
82
|
-
|
|
83
|
-
const invdet = 1.0 / det;
|
|
84
|
-
|
|
85
|
-
m3[0] = (b2 * c2 - bc * bc) * invdet;
|
|
86
|
-
m3[3] = (bc * ac - ab * c2) * invdet;
|
|
87
|
-
m3[6] = (ab * bc - b2 * ac) * invdet;
|
|
88
|
-
|
|
89
|
-
m3[1] = (ac * bc - ab * c2) * invdet;
|
|
90
|
-
m3[4] = (a2 * c2 - ac * ac) * invdet;
|
|
91
|
-
m3[7] = (ab * ac - a2 * bc) * invdet;
|
|
92
|
-
|
|
93
|
-
m3[2] = (ab * bc - ac * b2) * invdet;
|
|
94
|
-
m3[5] = (ac * ab - a2 * bc) * invdet;
|
|
95
|
-
m3[8] = (a2 * b2 - ab * ab) * invdet;
|
|
96
|
-
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Set from plane expressed as a 4 component vector
|
|
105
|
-
* @param {number} x plane normal
|
|
106
|
-
* @param {number} y plane normal
|
|
107
|
-
* @param {number} z plane normal
|
|
108
|
-
* @param {number} w plane offset
|
|
109
|
-
*/
|
|
110
|
-
setFromVector4(x, y, z, w) {
|
|
111
|
-
this.a2 = x * x;
|
|
112
|
-
this.ab = x * y;
|
|
113
|
-
this.ac = x * z;
|
|
114
|
-
this.ad = x * w;
|
|
115
|
-
|
|
116
|
-
this.b2 = y * y;
|
|
117
|
-
this.bc = y * z;
|
|
118
|
-
this.bd = y * w;
|
|
119
|
-
|
|
120
|
-
this.c2 = z * z;
|
|
121
|
-
this.cd = z * w;
|
|
122
|
-
|
|
123
|
-
this.d2 = w * w;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
*
|
|
128
|
-
* @param {TopoTriangle} face
|
|
129
|
-
*/
|
|
130
|
-
setFromFace(face) {
|
|
131
|
-
const v0 = face.vertices[0];
|
|
132
|
-
|
|
133
|
-
// compute triangle's plane
|
|
134
|
-
compute_triangle_normal(scratch_v3, v0, face.vertices[1], face.vertices[2]);
|
|
135
|
-
|
|
136
|
-
// compute plane offset
|
|
137
|
-
|
|
138
|
-
const normal_x = scratch_v3[0];
|
|
139
|
-
const normal_y = scratch_v3[1];
|
|
140
|
-
const normal_z = scratch_v3[2];
|
|
141
|
-
|
|
142
|
-
const plane_constant = -v3_dot(
|
|
143
|
-
normal_x, normal_y, normal_z,
|
|
144
|
-
|
|
145
|
-
v0.x, v0.y, v0.z
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
this.setFromVector4(normal_x, normal_y, normal_z, plane_constant);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Squared distance from the given point to plane encoded by the quadratic
|
|
153
|
-
* @param {number} x
|
|
154
|
-
* @param {number} y
|
|
155
|
-
* @param {number} z
|
|
156
|
-
* @returns {number}
|
|
157
|
-
*/
|
|
158
|
-
evaluate(x, y, z) {
|
|
159
|
-
// Evaluate vAv + 2bv + c
|
|
160
|
-
|
|
161
|
-
return (x * x * this.a2) + (2 * x * y * this.ab) + (2 * x * z * this.ac) + (2 * x * this.ad) // A
|
|
162
|
-
+ (y * y * this.b2) + (2 * y * z * this.bc) + (2 * y * this.bd) // B
|
|
163
|
-
+ (z * z * this.c2) + (2 * z * this.cd) // C
|
|
164
|
-
+ this.d2; // D
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Find optimal vertex position based on the quadratic
|
|
169
|
-
*
|
|
170
|
-
* Based on Blender's implementation: https://github.com/blender/blender/blob/594f47ecd2d5367ca936cf6fc6ec8168c2b360d0/source/blender/blenlib/intern/quadric.c
|
|
171
|
-
*
|
|
172
|
-
* @param {number[]} out
|
|
173
|
-
* @returns {boolean}
|
|
174
|
-
*/
|
|
175
|
-
optimize(out) {
|
|
176
|
-
|
|
177
|
-
if (this.toTensorM3Inverse(scratch_m3, EPSILON)) {
|
|
178
|
-
|
|
179
|
-
this.toVector3(out);
|
|
180
|
-
|
|
181
|
-
vec3.transformMat3(out, out, scratch_m3);
|
|
182
|
-
vec3.negate(out, out);
|
|
183
|
-
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return false;
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
*
|
|
193
|
-
* @param {Quadratic3} Q
|
|
194
|
-
*/
|
|
195
|
-
add(Q) {
|
|
196
|
-
|
|
197
|
-
// Accumulate coefficients
|
|
198
|
-
|
|
199
|
-
// R0
|
|
200
|
-
this.a2 += Q.a2;
|
|
201
|
-
this.ab += Q.ab;
|
|
202
|
-
this.ac += Q.ac;
|
|
203
|
-
this.ad += Q.ad;
|
|
204
|
-
|
|
205
|
-
// R1
|
|
206
|
-
this.b2 += Q.b2;
|
|
207
|
-
this.bc += Q.bc;
|
|
208
|
-
this.bd += Q.bd;
|
|
209
|
-
|
|
210
|
-
// R2
|
|
211
|
-
this.c2 += Q.c2;
|
|
212
|
-
this.cd += Q.cd;
|
|
213
|
-
|
|
214
|
-
// R3
|
|
215
|
-
this.d2 += Q.d2;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
*
|
|
220
|
-
* @param {number} v
|
|
221
|
-
*/
|
|
222
|
-
multiplyScalar(v) {
|
|
223
|
-
// R0
|
|
224
|
-
this.a2 *= v;
|
|
225
|
-
this.ab *= v;
|
|
226
|
-
this.ac *= v;
|
|
227
|
-
this.ad *= v;
|
|
228
|
-
|
|
229
|
-
// R1
|
|
230
|
-
this.b2 *= v;
|
|
231
|
-
this.bc *= v;
|
|
232
|
-
this.bd *= v;
|
|
233
|
-
|
|
234
|
-
// R2
|
|
235
|
-
this.c2 *= v;
|
|
236
|
-
this.cd *= v;
|
|
237
|
-
|
|
238
|
-
// R3
|
|
239
|
-
this.d2 *= v;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
*
|
|
244
|
-
* @returns {Quadratic3}
|
|
245
|
-
*/
|
|
246
|
-
clone() {
|
|
247
|
-
const r = new Quadratic3();
|
|
248
|
-
|
|
249
|
-
r.copy(this);
|
|
250
|
-
|
|
251
|
-
return r;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
*
|
|
256
|
-
* @param {Quadratic3} other
|
|
257
|
-
*/
|
|
258
|
-
copy(other) {
|
|
259
|
-
|
|
260
|
-
// R0
|
|
261
|
-
this.a2 = other.a2;
|
|
262
|
-
this.ab = other.ab;
|
|
263
|
-
this.ac = other.ac;
|
|
264
|
-
this.ad = other.ad;
|
|
265
|
-
|
|
266
|
-
// R1
|
|
267
|
-
this.b2 = other.b2;
|
|
268
|
-
this.bc = other.bc;
|
|
269
|
-
this.bd = other.bd;
|
|
270
|
-
|
|
271
|
-
// R2
|
|
272
|
-
this.c2 = other.c2;
|
|
273
|
-
this.cd = other.cd;
|
|
274
|
-
|
|
275
|
-
// R3
|
|
276
|
-
this.d2 = other.d2;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Set all matrix values to 0
|
|
281
|
-
*/
|
|
282
|
-
clear() {
|
|
283
|
-
// Row 0
|
|
284
|
-
this.a2 = 0;
|
|
285
|
-
this.ab = 0;
|
|
286
|
-
this.ac = 0;
|
|
287
|
-
this.ad = 0;
|
|
288
|
-
|
|
289
|
-
// Row 1
|
|
290
|
-
this.b2 = 0;
|
|
291
|
-
this.bc = 0;
|
|
292
|
-
this.bd = 0;
|
|
293
|
-
|
|
294
|
-
// Row 2
|
|
295
|
-
this.c2 = 0;
|
|
296
|
-
this.cd = 0;
|
|
297
|
-
|
|
298
|
-
// Row 3
|
|
299
|
-
this.d2 = 0;
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
}
|