Skip to main content

draco_oxide_core/mesh/
mod.rs

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