draco_oxide/core/mesh/
mod.rs1pub mod builder;
2
3use super::{
4 attribute::{Attribute, AttributeType, ComponentDataType},
5 shared::{Float, Vector},
6};
7use crate::core::shared::{NdVector, PointIdx};
8use crate::utils::geom::point_to_face_distance_3d;
9
10#[derive(Clone, Debug)]
14pub struct Mesh {
15 pub(crate) faces: Vec<[PointIdx; 3]>,
16 pub(crate) attributes: Vec<Attribute>,
17
18 name: String,
20}
21
22impl Mesh {
23 pub fn get_attributes(&self) -> &[Attribute] {
24 &self.attributes
25 }
26
27 pub fn get_faces(&self) -> &[[PointIdx; 3]] {
28 &self.faces
29 }
30
31 pub fn get_attributes_mut(&mut self) -> &mut [Attribute] {
32 &mut self.attributes
33 }
34
35 pub fn get_attributes_mut_by_indices<'a>(
36 &'a mut self,
37 indices: &[usize],
38 ) -> Vec<&'a mut Attribute> {
39 let out = indices
40 .iter()
41 .map(|i| &mut self.attributes[*i] as *mut Attribute)
42 .collect::<Vec<_>>();
43
44 unsafe {
45 let out = out.iter().map(|i| *i).collect::<Vec<_>>();
46 std::mem::transmute::<Vec<*mut Attribute>, Vec<&mut Attribute>>(out)
47 }
48 }
49
50 pub fn get_name(&self) -> &str {
51 &self.name
52 }
53
54 pub fn set_name(&mut self, name: &str) {
55 self.name = name.to_owned();
56 }
57
58 pub fn new() -> Self {
59 Self {
60 faces: Vec::new(),
61 attributes: Vec::new(),
62
63 name: String::new(),
64 }
65 }
66
67 pub fn diff_l2_norm(&self, other: &Self) -> f64 {
68 let pos_att_iter = self
69 .attributes
70 .iter()
71 .enumerate()
72 .filter(|(_, att)| att.get_attribute_type() == AttributeType::Position);
73 let other_pos_att_iter = other
74 .attributes
75 .iter()
76 .enumerate()
77 .filter(|(_, att)| att.get_attribute_type() == AttributeType::Position);
78
79 let mut num_points = 0;
80 let mut sum_of_squared_dist = 0.0;
81 for ((_, pos_att), (_, other_pos_att)) in pos_att_iter.zip(other_pos_att_iter) {
82 if pos_att.get_num_components() != 3 {
83 panic!("Position attribute must have 3 components, but the first mesh has {} components", pos_att.get_num_components());
84 }
85
86 let faces = &self.faces;
88 let other_faces = &other.faces;
89
90 num_points += pos_att.len();
91 num_points += other_pos_att.len();
92 sum_of_squared_dist +=
93 sum_of_squared_dist_unpack_datatype(pos_att, faces, other_pos_att, other_faces);
94 }
95
96 sum_of_squared_dist.sqrt() / num_points as f64
97 }
98}
99
100fn sum_of_squared_dist_unpack_datatype(
101 position_att: &Attribute,
102 faces: &[[PointIdx; 3]],
103 other_position_att: &Attribute,
104 other_faces: &[[PointIdx; 3]],
105) -> f64 {
106 unsafe {
110 match position_att.get_component_type() {
111 ComponentDataType::F32 => sum_of_squared_dist_impl::<f32>(
112 position_att,
113 faces,
114 other_position_att,
115 other_faces,
116 ) as f64,
117 ComponentDataType::F64 => sum_of_squared_dist_impl::<f64>(
118 position_att,
119 faces,
120 other_position_att,
121 other_faces,
122 ),
123 _ => panic!("Position Attribute is not of type f32 or f64"),
124 }
125 }
126}
127
128unsafe fn sum_of_squared_dist_impl<F>(
130 self_pos_att: &Attribute,
131 self_faces: &[[PointIdx; 3]],
132 other_pos_att: &Attribute,
133 other_faces: &[[PointIdx; 3]],
134) -> F
135where
136 F: Float,
137 NdVector<3, F>: Vector<3, Component = F>,
138{
139 assert!(
140 other_pos_att.get_component_type() == self_pos_att.get_component_type(),
141 "Component types must match, but the first mesh has {:?} and the second mesh has {:?}",
142 self_pos_att.get_component_type(),
143 other_pos_att.get_component_type()
144 );
145
146 if other_pos_att.get_num_components() != 3 {
147 panic!(
148 "Position attribute must have 3 components, but the second mesh has {} components",
149 other_pos_att.get_num_components()
150 );
151 }
152
153 let self_pos_att = self_pos_att.unique_vals_as_slice_unchecked::<NdVector<3, F>>();
155 let other_pos_att = unsafe { other_pos_att.unique_vals_as_slice_unchecked::<NdVector<3, F>>() };
157
158 let mut sum_of_squared_dist = F::zero();
159 for pos in self_pos_att.iter() {
160 let min_dist = min_dist_point_to_faces(*pos, other_faces, other_pos_att);
161 sum_of_squared_dist += min_dist * min_dist;
162 }
163 for pos in other_pos_att.iter() {
164 let min_dist = min_dist_point_to_faces(*pos, self_faces, self_pos_att);
165 sum_of_squared_dist += min_dist * min_dist;
166 }
167
168 sum_of_squared_dist.sqrt()
169}
170
171fn min_dist_point_to_faces<F>(
172 p: NdVector<3, F>,
173 faces: &[[PointIdx; 3]],
174 pos_att: &[NdVector<3, F>],
175) -> F
176where
177 F: Float,
178{
179 let mut min_dist = F::MAX_VALUE;
180 for face in faces {
181 let v0 = pos_att[usize::from(face[0])];
182 let v1 = pos_att[usize::from(face[1])];
183 let v2 = pos_att[usize::from(face[2])];
184 let dist = point_to_face_distance_3d(p, [v0, v1, v2]);
185 if dist < min_dist {
186 min_dist = dist;
187 }
188 }
189 min_dist
190}