1use crate::point::*;
4use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct TriangleMesh {
10 pub vertices: Vec<Point3f>,
11 pub faces: Vec<[usize; 3]>,
12 pub normals: Option<Vec<Vector3f>>,
13 pub colors: Option<Vec<[u8; 3]>>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ColoredTriangleMesh {
19 pub vertices: Vec<ColoredPoint3f>,
20 pub faces: Vec<[usize; 3]>,
21 pub normals: Option<Vec<Vector3f>>,
22}
23
24impl TriangleMesh {
25 pub fn new() -> Self {
27 Self {
28 vertices: Vec::new(),
29 faces: Vec::new(),
30 normals: None,
31 colors: None,
32 }
33 }
34
35 pub fn from_vertices_and_faces(vertices: Vec<Point3f>, faces: Vec<[usize; 3]>) -> Self {
37 Self {
38 vertices,
39 faces,
40 normals: None,
41 colors: None,
42 }
43 }
44
45 pub fn vertex_count(&self) -> usize {
47 self.vertices.len()
48 }
49
50 pub fn face_count(&self) -> usize {
52 self.faces.len()
53 }
54
55 pub fn is_empty(&self) -> bool {
57 self.vertices.is_empty() || self.faces.is_empty()
58 }
59
60 pub fn validate_faces(&self) -> crate::Result<()> {
63 let n = self.vertices.len();
64 match self.faces.iter().position(|f| f.iter().any(|&i| i >= n)) {
65 None => Ok(()),
66 Some(face) => Err(crate::Error::InvalidData(format!(
67 "face {face} uses vertex index {:?}, but the mesh has only {n} vertices",
68 self.faces[face]
69 ))),
70 }
71 }
72
73 pub fn add_vertex(&mut self, vertex: Point3f) -> usize {
75 let index = self.vertices.len();
76 self.vertices.push(vertex);
77 index
78 }
79
80 pub fn add_face(&mut self, face: [usize; 3]) {
82 self.faces.push(face);
83 }
84
85 pub fn calculate_face_normals(&self) -> Vec<Vector3f> {
87 self.faces
88 .iter()
89 .map(|face| {
90 let v0 = self.vertices[face[0]];
91 let v1 = self.vertices[face[1]];
92 let v2 = self.vertices[face[2]];
93
94 let edge1 = v1 - v0;
95 let edge2 = v2 - v0;
96
97 edge1.cross(&edge2).normalize()
98 })
99 .collect()
100 }
101
102 pub fn set_normals(&mut self, normals: Vec<Vector3f>) {
104 if normals.len() == self.vertices.len() {
105 self.normals = Some(normals);
106 }
107 }
108
109 pub fn set_colors(&mut self, colors: Vec<[u8; 3]>) {
111 if colors.len() == self.vertices.len() {
112 self.colors = Some(colors);
113 }
114 }
115
116 pub fn clear(&mut self) {
118 self.vertices.clear();
119 self.faces.clear();
120 self.normals = None;
121 self.colors = None;
122 }
123}
124
125impl Default for TriangleMesh {
126 fn default() -> Self {
127 Self::new()
128 }
129}
130
131impl ColoredTriangleMesh {
132 pub fn new() -> Self {
134 Self {
135 vertices: Vec::new(),
136 faces: Vec::new(),
137 normals: None,
138 }
139 }
140
141 pub fn vertex_count(&self) -> usize {
143 self.vertices.len()
144 }
145
146 pub fn face_count(&self) -> usize {
148 self.faces.len()
149 }
150
151 pub fn is_empty(&self) -> bool {
153 self.vertices.is_empty() || self.faces.is_empty()
154 }
155}
156
157impl Default for ColoredTriangleMesh {
158 fn default() -> Self {
159 Self::new()
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn validate_faces_rejects_out_of_range_indices() {
169 let vertices = vec![Point3f::origin(); 3];
170 assert!(
171 TriangleMesh::from_vertices_and_faces(vertices.clone(), vec![[0, 1, 2]])
172 .validate_faces()
173 .is_ok()
174 );
175 let err = TriangleMesh::from_vertices_and_faces(vertices, vec![[0, 1, 2], [0, 1, 99]])
176 .validate_faces()
177 .unwrap_err();
178 assert!(err.to_string().contains("face 1"), "{err}");
179 }
180}