alum/decimate/
edge_length.rs1use crate::{DotProductAdaptor, Error, HH, PolyMeshT, VH};
2use std::ops::{Mul, Sub};
3
4use super::Decimater;
5
6pub struct EdgeLengthDecimater<const DIM: usize, A>
8where
9 A: DotProductAdaptor<DIM>,
10 A::Vector: Sub<Output = A::Vector>,
11 A::Scalar: PartialOrd,
12{
13 max_length: A::Scalar,
14}
15
16impl<const DIM: usize, A> EdgeLengthDecimater<DIM, A>
17where
18 A: DotProductAdaptor<DIM>,
19 A::Vector: Sub<Output = A::Vector>,
20 A::Scalar: PartialOrd + Mul<Output = A::Scalar>,
21{
22 pub fn new(max_length: A::Scalar) -> Self {
26 EdgeLengthDecimater {
27 max_length: max_length * max_length,
28 }
29 }
30}
31
32impl<const DIM: usize, A> Decimater<PolyMeshT<DIM, A>> for EdgeLengthDecimater<DIM, A>
33where
34 A: DotProductAdaptor<DIM>,
35 A::Vector: Sub<Output = A::Vector>,
36 A::Scalar: PartialOrd + Mul<Output = A::Scalar>,
37{
38 type Cost = A::Scalar;
39
40 fn collapse_cost(&self, mesh: &PolyMeshT<DIM, A>, h: HH) -> Option<Self::Cost> {
42 let points = mesh.points();
43 let points = points.try_borrow().ok()?;
44 let elen = mesh.calc_edge_length_sqr(h.edge(), &points);
45 if elen < self.max_length {
46 Some(elen)
47 } else {
48 None
49 }
50 }
51
52 fn before_collapse(&mut self, _mesh: &PolyMeshT<DIM, A>, _h: HH) -> Result<(), Error> {
53 Ok(()) }
55
56 fn after_collapse(&mut self, _mesh: &PolyMeshT<DIM, A>, _v: VH) -> Result<(), Error> {
57 Ok(()) }
59}
60
61#[cfg(test)]
62mod test {
63 use super::EdgeLengthDecimater;
64 use crate::{HasDecimation, HasIterators, HasTopology, obj::test::bunny_mesh};
65
66 #[test]
67 fn t_bunny_edge_length_decimate() {
68 let mut mesh = bunny_mesh();
69 let (nv, ne, nf) = (mesh.num_vertices(), mesh.num_edges(), mesh.num_faces());
70 let nloops_before = {
71 let mut visited = mesh.create_halfedge_prop(false);
72 let mut visited = visited.try_borrow_mut().unwrap();
73 mesh.halfedges().fold(0usize, |count, h| {
74 if !h.is_boundary(&mesh) || visited[h] {
75 count
76 } else {
77 for h2 in mesh.loop_ccw_iter(h) {
78 visited[h2] = true;
79 }
80 count + 1
81 }
82 })
83 };
84 let mut decimater = EdgeLengthDecimater::new(0.1);
85 mesh.decimate(&mut decimater, 2000)
86 .expect("Cannot decimate");
87 mesh.garbage_collection()
88 .expect("Failed to garbage collect");
89 mesh.check_topology().expect("Topological errors found");
90 assert_eq!(nv - 2000, mesh.num_vertices());
91 assert!(mesh.num_edges() < ne);
92 assert!(mesh.num_faces() < nf);
93 let nloops_after = {
94 let mut visited = mesh.create_halfedge_prop(false);
95 let mut visited = visited.try_borrow_mut().unwrap();
96 mesh.halfedges().fold(0usize, |count, h| {
97 if !h.is_boundary(&mesh) || visited[h] {
98 count
99 } else {
100 for h2 in mesh.loop_ccw_iter(h) {
101 visited[h2] = true;
102 }
103 count + 1
104 }
105 })
106 };
107 assert_eq!(nloops_before, nloops_after);
108 }
109}