1#[allow(unused_imports)]
6use super::functions::*;
7#[allow(unused_imports)]
8use super::functions_2::*;
9use std::collections::{HashMap, HashSet};
10
11#[allow(dead_code)]
13#[derive(Debug, Clone)]
14pub struct EdgeCollapseRecord {
15 pub removed: usize,
17 pub target: usize,
19 pub deleted_triangles: Vec<[usize; 3]>,
21}
22#[allow(dead_code)]
24pub struct ProgressiveMeshSimple {
25 pub current: SimpleMesh,
27 pub history: Vec<EdgeCollapseRecord>,
29}
30impl ProgressiveMeshSimple {
31 pub fn new(mesh: SimpleMesh) -> Self {
33 Self {
34 current: mesh,
35 history: Vec::new(),
36 }
37 }
38 pub fn collapse_edge(&mut self, src: usize, dst: usize) {
43 let mut deleted = Vec::new();
44 let mut remaining = Vec::new();
45 for tri in &self.current.triangles {
46 let has_src = tri.contains(&src);
47 let has_dst = tri.contains(&dst);
48 if has_src && has_dst {
49 deleted.push(*tri);
50 } else if has_src {
51 let new_tri = tri.map(|v| if v == src { dst } else { v });
52 remaining.push(new_tri);
53 } else {
54 remaining.push(*tri);
55 }
56 }
57 self.history.push(EdgeCollapseRecord {
58 removed: src,
59 target: dst,
60 deleted_triangles: deleted,
61 });
62 self.current.triangles = remaining;
63 }
64 pub fn n_collapses(&self) -> usize {
66 self.history.len()
67 }
68 pub fn n_triangles(&self) -> usize {
70 self.current.triangle_count()
71 }
72}
73pub struct ProgressiveMesh {
76 pub mesh: SimpleMesh,
78 pub history: Vec<CollapseRecord>,
80}
81impl ProgressiveMesh {
82 pub fn new(mesh: SimpleMesh) -> Self {
84 Self {
85 mesh,
86 history: Vec::new(),
87 }
88 }
89 pub fn collapse_one(&mut self) -> bool {
94 if self.mesh.triangle_count() <= 3 {
95 return false;
96 }
97 let quadrics = compute_vertex_quadrics(&self.mesh);
98 let mut edge_set: std::collections::HashSet<(usize, usize)> =
99 std::collections::HashSet::new();
100 for &[a, b, c] in &self.mesh.triangles {
101 edge_set.insert((a.min(b), a.max(b)));
102 edge_set.insert((b.min(c), b.max(c)));
103 edge_set.insert((a.min(c), a.max(c)));
104 }
105 let mut best_cost = f64::MAX;
106 let mut best_v1 = 0usize;
107 let mut best_v2 = 0usize;
108 let mut best_pos = [0.0f64; 3];
109 for (v1, v2) in &edge_set {
110 let (cost, pos) = edge_collapse_cost(
111 self.mesh.vertices[*v1],
112 self.mesh.vertices[*v2],
113 &quadrics[*v1],
114 &quadrics[*v2],
115 );
116 if cost < best_cost {
117 best_cost = cost;
118 best_v1 = *v1;
119 best_v2 = *v2;
120 best_pos = pos;
121 }
122 }
123 let old_pos = self.mesh.vertices[best_v1];
124 let record = CollapseRecord {
125 v_kept: best_v1,
126 v_removed: best_v2,
127 old_pos,
128 new_pos: best_pos,
129 };
130 collapse_edge(&mut self.mesh, best_v1, best_v2, best_pos);
131 self.history.push(record);
132 true
133 }
134 pub fn decimate_to(&mut self, target_triangles: usize) {
136 while self.mesh.triangle_count() > target_triangles {
137 if !self.collapse_one() {
138 break;
139 }
140 }
141 }
142}
143#[derive(Debug, Clone)]
145pub struct CollapseRecord {
146 pub v_kept: usize,
148 pub v_removed: usize,
150 pub old_pos: [f64; 3],
152 pub new_pos: [f64; 3],
154}
155#[allow(dead_code)]
157#[derive(Debug, Clone, Copy, PartialEq)]
158pub struct MeshEdge {
159 pub v0: usize,
161 pub v1: usize,
163 pub cost: f64,
165}
166#[allow(dead_code)]
168pub struct EdgePriorityQueue {
169 pub(super) heap: std::collections::BinaryHeap<MeshEdge>,
170}
171impl EdgePriorityQueue {
172 pub fn new() -> Self {
174 Self {
175 heap: std::collections::BinaryHeap::new(),
176 }
177 }
178 pub fn push(&mut self, edge: MeshEdge) {
180 self.heap.push(edge);
181 }
182 pub fn pop(&mut self) -> Option<MeshEdge> {
184 self.heap.pop()
185 }
186 pub fn len(&self) -> usize {
188 self.heap.len()
189 }
190 pub fn is_empty(&self) -> bool {
192 self.heap.is_empty()
193 }
194 pub fn from_mesh(mesh: &SimpleMesh) -> Self {
196 let mut q = Self::new();
197 let mut seen: HashSet<(usize, usize)> = HashSet::new();
198 for tri in &mesh.triangles {
199 for &(a, b) in &[(tri[0], tri[1]), (tri[1], tri[2]), (tri[0], tri[2])] {
200 let key = if a < b { (a, b) } else { (b, a) };
201 if seen.insert(key) {
202 let va = mesh.vertices[a];
203 let vb = mesh.vertices[b];
204 let cost =
205 (va[0] - vb[0]).powi(2) + (va[1] - vb[1]).powi(2) + (va[2] - vb[2]).powi(2);
206 q.push(MeshEdge {
207 v0: key.0,
208 v1: key.1,
209 cost,
210 });
211 }
212 }
213 }
214 q
215 }
216}
217#[derive(Clone)]
219pub struct SimpleMesh {
220 pub vertices: Vec<[f64; 3]>,
222 pub triangles: Vec<[usize; 3]>,
224}
225impl SimpleMesh {
226 pub fn new() -> Self {
228 Self {
229 vertices: Vec::new(),
230 triangles: Vec::new(),
231 }
232 }
233 pub fn add_vertex(&mut self, v: [f64; 3]) -> usize {
235 let idx = self.vertices.len();
236 self.vertices.push(v);
237 idx
238 }
239 pub fn add_triangle(&mut self, a: usize, b: usize, c: usize) {
241 self.triangles.push([a, b, c]);
242 }
243 pub fn vertex_count(&self) -> usize {
245 self.vertices.len()
246 }
247 pub fn triangle_count(&self) -> usize {
249 self.triangles.len()
250 }
251 pub fn triangle_normal(&self, t_idx: usize) -> [f64; 3] {
253 let [a, b, c] = self.triangles[t_idx];
254 let va = self.vertices[a];
255 let vb = self.vertices[b];
256 let vc = self.vertices[c];
257 let ab = [vb[0] - va[0], vb[1] - va[1], vb[2] - va[2]];
258 let ac = [vc[0] - va[0], vc[1] - va[1], vc[2] - va[2]];
259 let n = cross(ab, ac);
260 normalize(n)
261 }
262 pub fn triangle_area(&self, t_idx: usize) -> f64 {
264 let [a, b, c] = self.triangles[t_idx];
265 let va = self.vertices[a];
266 let vb = self.vertices[b];
267 let vc = self.vertices[c];
268 let ab = [vb[0] - va[0], vb[1] - va[1], vb[2] - va[2]];
269 let ac = [vc[0] - va[0], vc[1] - va[1], vc[2] - va[2]];
270 let cp = cross(ab, ac);
271 0.5 * length(cp)
272 }
273 pub fn surface_area(&self) -> f64 {
275 (0..self.triangle_count())
276 .map(|i| self.triangle_area(i))
277 .sum()
278 }
279}
280pub struct QuadricMatrix {
282 pub q: [[f64; 4]; 4],
284}
285impl QuadricMatrix {
286 pub fn zero() -> Self {
288 Self { q: [[0.0; 4]; 4] }
289 }
290 pub fn from_plane(a: f64, b: f64, c: f64, d: f64) -> Self {
293 let p = [a, b, c, d];
294 let mut q = [[0.0f64; 4]; 4];
295 for i in 0..4 {
296 for j in 0..4 {
297 q[i][j] = p[i] * p[j];
298 }
299 }
300 Self { q }
301 }
302 pub fn add(&self, other: &Self) -> Self {
304 let mut result = Self::zero();
305 for i in 0..4 {
306 for j in 0..4 {
307 result.q[i][j] = self.q[i][j] + other.q[i][j];
308 }
309 }
310 result
311 }
312 pub fn vertex_error(&self, v: [f64; 3]) -> f64 {
314 let h = [v[0], v[1], v[2], 1.0];
315 let mut result = 0.0;
316 for i in 0..4 {
317 for j in 0..4 {
318 result += h[i] * self.q[i][j] * h[j];
319 }
320 }
321 result
322 }
323}
324#[allow(dead_code)]
328#[derive(Debug, Clone, Copy)]
329pub struct NormalCone {
330 pub axis: [f64; 3],
332 pub half_angle: f64,
334}
335impl NormalCone {
336 pub fn from_normal(n: [f64; 3]) -> Self {
338 Self {
339 axis: normalize3(n),
340 half_angle: 0.0,
341 }
342 }
343 pub fn merge(&self, other: &NormalCone) -> NormalCone {
345 let axis_new = normalize3(add3(self.axis, other.axis));
346 let angle1 = dot3(self.axis, axis_new).clamp(-1.0, 1.0).acos() + self.half_angle;
347 let angle2 = dot3(other.axis, axis_new).clamp(-1.0, 1.0).acos() + other.half_angle;
348 NormalCone {
349 axis: axis_new,
350 half_angle: angle1.max(angle2),
351 }
352 }
353 pub fn contains(&self, n: [f64; 3], tol: f64) -> bool {
355 let n_hat = normalize3(n);
356 let cos_angle = dot3(self.axis, n_hat).clamp(-1.0, 1.0);
357 let angle = cos_angle.acos();
358 angle <= self.half_angle + tol
359 }
360 pub fn half_angle_deg(&self) -> f64 {
362 self.half_angle.to_degrees()
363 }
364}
365#[allow(dead_code)]
367#[derive(Debug, Clone, Copy, PartialEq)]
368pub enum EdgeFeature {
369 Smooth,
371 Crease,
373 Boundary,
375}
376#[allow(dead_code)]
378#[derive(Debug, Clone, Default)]
379pub struct DecimationMetrics {
380 pub original_vertices: usize,
382 pub original_triangles: usize,
384 pub reduced_vertices: usize,
386 pub reduced_triangles: usize,
388 pub n_collapses: usize,
390 pub total_qem_cost: f64,
392 pub max_qem_cost: f64,
394}
395impl DecimationMetrics {
396 pub fn vertex_reduction_ratio(&self) -> f64 {
398 if self.original_vertices == 0 {
399 return 0.0;
400 }
401 1.0 - self.reduced_vertices as f64 / self.original_vertices as f64
402 }
403 pub fn triangle_reduction_ratio(&self) -> f64 {
405 if self.original_triangles == 0 {
406 return 0.0;
407 }
408 1.0 - self.reduced_triangles as f64 / self.original_triangles as f64
409 }
410 pub fn avg_qem_cost(&self) -> f64 {
412 if self.n_collapses == 0 {
413 return 0.0;
414 }
415 self.total_qem_cost / self.n_collapses as f64
416 }
417}
418pub struct QemDecimation {
421 pub mesh: SimpleMesh,
423 pub(super) quadrics: Vec<QuadricMatrix>,
425}
426impl QemDecimation {
427 pub fn new(mesh: SimpleMesh) -> Self {
429 let quadrics = compute_vertex_quadrics(&mesh);
430 Self { mesh, quadrics }
431 }
432 pub fn recompute_quadrics(&mut self) {
434 self.quadrics = compute_vertex_quadrics(&self.mesh);
435 }
436 pub fn compute_error_threshold(&self, scale_factor: f64) -> f64 {
445 let avg_edge = average_edge_length(&self.mesh);
446 if avg_edge < 1e-12 {
447 return 0.0;
448 }
449 let scale_sq = avg_edge * avg_edge;
450 let n_verts = self.mesh.vertex_count();
451 if n_verts < 2 {
452 return scale_factor * scale_sq;
453 }
454 let mut sampled_cost = 0.0f64;
455 let mut sampled_count = 0usize;
456 let step = (n_verts / 32).max(1);
457 for tri in self.mesh.triangles.iter().step_by(step) {
458 let v0 = tri[0];
459 let v1 = tri[1];
460 if v0 >= self.quadrics.len() || v1 >= self.quadrics.len() {
461 continue;
462 }
463 let (cost, _) = edge_collapse_cost(
464 self.mesh.vertices[v0],
465 self.mesh.vertices[v1],
466 &self.quadrics[v0],
467 &self.quadrics[v1],
468 );
469 sampled_cost += cost;
470 sampled_count += 1;
471 }
472 let mean_cost = if sampled_count > 0 {
473 sampled_cost / sampled_count as f64
474 } else {
475 1.0
476 };
477 (scale_factor * scale_sq * mean_cost).max(1e-12)
478 }
479 pub fn preserve_boundary(&mut self, threshold: f64) -> usize {
487 let boundary_edges = find_boundary_edges(&self.mesh);
488 let boundary_set: HashSet<(usize, usize)> = boundary_edges
489 .iter()
490 .flat_map(|&(a, b)| [(a.min(b), a.max(b)), (a.min(b), a.max(b))])
491 .collect();
492 let mut n_collapses = 0usize;
493 let mut keep_going = true;
494 while keep_going {
495 keep_going = false;
496 self.recompute_quadrics();
497 let mut best: Option<(f64, [f64; 3], usize, usize)> = None;
498 for tri in &self.mesh.triangles {
499 for k in 0..3 {
500 let v0 = tri[k];
501 let v1 = tri[(k + 1) % 3];
502 let key = (v0.min(v1), v0.max(v1));
503 if boundary_set.contains(&key) {
504 continue;
505 }
506 if v0 >= self.quadrics.len() || v1 >= self.quadrics.len() {
507 continue;
508 }
509 let (cost, opt) = edge_collapse_cost(
510 self.mesh.vertices[v0],
511 self.mesh.vertices[v1],
512 &self.quadrics[v0],
513 &self.quadrics[v1],
514 );
515 if cost <= threshold && best.as_ref().is_none_or(|b| cost < b.0) {
516 best = Some((cost, opt, v0, v1));
517 }
518 }
519 }
520 if let Some((_cost, opt, v0, v1)) = best {
521 self.mesh.vertices[v0] = opt;
522 for tri in &mut self.mesh.triangles {
523 for idx in tri.iter_mut() {
524 if *idx == v1 {
525 *idx = v0;
526 }
527 }
528 }
529 self.mesh
530 .triangles
531 .retain(|tri| tri[0] != tri[1] && tri[1] != tri[2] && tri[0] != tri[2]);
532 n_collapses += 1;
533 keep_going = true;
534 }
535 }
536 n_collapses
537 }
538 pub fn compute_feature_score(&self) -> HashMap<(usize, usize), f64> {
547 let mut edge_faces: HashMap<(usize, usize), Vec<usize>> = HashMap::new();
548 for (fi, tri) in self.mesh.triangles.iter().enumerate() {
549 for k in 0..3 {
550 let a = tri[k];
551 let b = tri[(k + 1) % 3];
552 let key = (a.min(b), a.max(b));
553 edge_faces.entry(key).or_default().push(fi);
554 }
555 }
556 let mut scores: HashMap<(usize, usize), f64> = HashMap::new();
557 for (&edge, faces) in &edge_faces {
558 if faces.len() != 2 {
559 scores.insert(edge, f64::INFINITY);
560 continue;
561 }
562 let n0 = self.mesh.triangle_normal(faces[0]);
563 let n1 = self.mesh.triangle_normal(faces[1]);
564 let cos_a = (dot3(n0, n1)).clamp(-1.0, 1.0);
565 let score = 1.0 - cos_a;
566 scores.insert(edge, score);
567 }
568 scores
569 }
570}
571#[derive(Debug, Clone)]
573pub struct DecimationStats {
574 pub original_vertices: usize,
576 pub original_triangles: usize,
578 pub result_vertices: usize,
580 pub result_triangles: usize,
582 pub reduction_ratio: f64,
584 pub total_qem_error: f64,
586}
587impl DecimationStats {
588 pub fn compute(
590 original_v: usize,
591 original_t: usize,
592 result: &SimpleMesh,
593 total_qem_error: f64,
594 ) -> Self {
595 let reduction_ratio = if original_t > 0 {
596 1.0 - result.triangle_count() as f64 / original_t as f64
597 } else {
598 0.0
599 };
600 Self {
601 original_vertices: original_v,
602 original_triangles: original_t,
603 result_vertices: result.vertex_count(),
604 result_triangles: result.triangle_count(),
605 reduction_ratio,
606 total_qem_error,
607 }
608 }
609}