truck_polymesh/
polygon_mesh.rs

1use crate::errors::Error;
2use crate::*;
3use std::fmt::Debug;
4
5impl<V: Copy + Debug, A: Attributes<V>> PolygonMesh<V, A> {
6    /// complete constructor
7    /// # Panics
8    /// Panic occurs if there is an index is out of range.
9    /// # Remarks
10    /// This method does not check whether the normal is normalized or not.
11    pub fn new(attributes: A, faces: Faces<V>) -> Self {
12        Self::try_new(attributes, faces).unwrap_or_else(|e| panic!("{e:?}"))
13    }
14
15    /// complete constructor
16    /// # Errors
17    /// Returns [`Error::OutOfRange`] if there is an index is out of range.
18    ///
19    /// [`Error::OutOfRange`]: ./errors/enum.Error.html#variant.OutOfRange
20    ///
21    /// # Remarks
22    /// This method does not check whether the normal is normalized or not.
23    pub fn try_new(attributes: A, faces: Faces<V>) -> Result<Self, Error<V>> {
24        faces
25            .is_compatible(&attributes)
26            .map(|_| Self::new_unchecked(attributes, faces))
27    }
28
29    /// constructor without boundary check
30    #[inline(always)]
31    pub const fn new_unchecked(attributes: A, faces: Faces<V>) -> Self {
32        Self { attributes, faces }
33    }
34
35    /// constructor, boundary check is acrivated only in debug mode.
36    #[inline(always)]
37    pub fn debug_new(attributes: A, faces: Faces<V>) -> Self {
38        match cfg!(debug_assertions) {
39            true => Self::new(attributes, faces),
40            false => Self::new_unchecked(attributes, faces),
41        }
42    }
43
44    /// Returns attributes
45    #[inline(always)]
46    pub const fn attributes(&self) -> &A { &self.attributes }
47
48    /// Returns the faces of the polygon.
49    #[inline(always)]
50    pub const fn faces(&self) -> &Faces<V> { &self.faces }
51
52    /// Returns the vector of all triangles of the polygon.
53    #[inline(always)]
54    pub const fn tri_faces(&self) -> &Vec<[V; 3]> { &self.faces.tri_faces }
55
56    /// Returns the vector of all quadrangles.
57    #[inline(always)]
58    pub const fn quad_faces(&self) -> &Vec<[V; 4]> { &self.faces.quad_faces }
59
60    /// Returns the vector of n-gons (n > 4).
61    #[inline(always)]
62    pub const fn other_faces(&self) -> &Vec<Vec<V>> { &self.faces.other_faces }
63
64    /// Returns the iterator of the slice.
65    ///
66    /// By the internal optimization, this iterator does not runs in the simple order
67    /// in which they are registered, but runs order: triangle, square, and the others.
68    /// cf: [`Faces::face_iter`](./struct.Faces.html#method.face_iter)
69    #[inline(always)]
70    pub fn face_iter(&self) -> impl Iterator<Item = &[V]> { self.faces.face_iter() }
71
72    /// Returns the iterator of the slice.
73    ///
74    /// By the internal optimization, this iterator does not runs in the simple order
75    /// in which they are registered, but runs order: triangle, square, and the others.
76    /// cf: [`Faces::face_iter`](./struct.Faces.html#method.face_iter)
77    #[inline(always)]
78    pub fn face_iter_mut(&mut self) -> impl Iterator<Item = &mut [V]> { self.faces.face_iter_mut() }
79    /// Creates an editor that performs boundary checking on dropped.
80    #[inline(always)]
81    pub fn editor(&mut self) -> PolygonMeshEditor<'_, V, A> {
82        PolygonMeshEditor {
83            attributes: &mut self.attributes,
84            faces: &mut self.faces,
85            bound_check: true,
86        }
87    }
88    /// Creates an editor that does NOT perform boundary checking on dropped.
89    #[inline(always)]
90    pub fn uncheck_editor(&mut self) -> PolygonMeshEditor<'_, V, A> {
91        PolygonMeshEditor {
92            attributes: &mut self.attributes,
93            faces: &mut self.faces,
94            bound_check: false,
95        }
96    }
97    /// Creates an editor that performs boundary checking on dropped ONLY in debug build.
98    #[inline(always)]
99    pub fn debug_editor(&mut self) -> PolygonMeshEditor<'_, V, A> {
100        PolygonMeshEditor {
101            attributes: &mut self.attributes,
102            faces: &mut self.faces,
103            bound_check: cfg!(debug_assertions),
104        }
105    }
106}
107
108impl PolygonMesh {
109    /// Returns a polygon mesh merged `self` and `mesh`.
110    pub fn merge(&mut self, mut mesh: PolygonMesh) {
111        let n_pos = self.positions().len();
112        let n_uv = self.uv_coords().len();
113        let n_nor = self.normals().len();
114        mesh.faces.face_iter_mut().for_each(move |face| {
115            face.iter_mut().for_each(|v| {
116                v.pos += n_pos;
117                v.uv = v.uv.map(|uv| uv + n_uv);
118                v.nor = v.nor.map(|nor| nor + n_nor);
119            })
120        });
121        self.attributes.positions.extend(mesh.attributes.positions);
122        self.attributes.uv_coords.extend(mesh.attributes.uv_coords);
123        self.attributes.normals.extend(mesh.attributes.normals);
124        self.faces.naive_concat(mesh.faces);
125    }
126    /// Creates the bounding box of the polygon mesh.
127    #[inline(always)]
128    pub fn bounding_box(&self) -> BoundingBox<Point3> { self.positions().iter().collect() }
129    /// Returns a polygon mesh with only positions information.
130    #[inline(always)]
131    pub fn to_positions_mesh(&self) -> PolygonMesh<usize, Vec<Point3>> {
132        let faces = self.faces();
133        let tri_faces = faces
134            .tri_faces()
135            .iter()
136            .map(|face| [face[0].pos, face[1].pos, face[2].pos])
137            .collect::<Vec<_>>();
138        let quad_faces = faces
139            .quad_faces()
140            .iter()
141            .map(|face| [face[0].pos, face[1].pos, face[2].pos, face[3].pos])
142            .collect::<Vec<_>>();
143        let other_faces = faces
144            .other_faces()
145            .iter()
146            .map(|face| face.iter().map(|x| x.pos).collect::<Vec<_>>())
147            .collect::<Vec<_>>();
148        PolygonMesh {
149            attributes: self.positions().clone(),
150            faces: Faces {
151                tri_faces,
152                quad_faces,
153                other_faces,
154            },
155        }
156    }
157}
158
159impl Invertible for PolygonMesh {
160    #[inline(always)]
161    fn invert(&mut self) {
162        self.attributes.normals.iter_mut().for_each(|n| *n = -*n);
163        self.faces.invert();
164    }
165    #[inline(always)]
166    fn inverse(&self) -> Self {
167        Self {
168            attributes: StandardAttributes {
169                positions: self.attributes.positions.clone(),
170                uv_coords: self.attributes.uv_coords.clone(),
171                normals: self.attributes.normals.iter().map(|n| -*n).collect(),
172            },
173            faces: self.faces.inverse(),
174        }
175    }
176}
177
178impl PolygonMesh {
179    /// Returns the vector of all positions.
180    #[inline(always)]
181    pub const fn positions(&self) -> &Vec<Point3> { &self.attributes.positions }
182
183    /// Returns the mutable slice of all positions.
184    #[inline(always)]
185    pub fn positions_mut(&mut self) -> &mut [Point3] { &mut self.attributes.positions }
186
187    /// Adds a position.
188    #[inline(always)]
189    pub fn push_position(&mut self, position: Point3) { self.attributes.positions.push(position) }
190
191    /// Extend positions by iterator.
192    #[inline(always)]
193    pub fn extend_positions<I: IntoIterator<Item = Point3>>(&mut self, iter: I) {
194        self.attributes.positions.extend(iter)
195    }
196
197    /// Returns the vector of all uv (texture) coordinates.
198    #[inline(always)]
199    pub const fn uv_coords(&self) -> &Vec<Vector2> { &self.attributes.uv_coords }
200
201    /// Returns the mutable slice of all uv (texture) coordinates.
202    #[inline(always)]
203    pub fn uv_coords_mut(&mut self) -> &mut [Vector2] { &mut self.attributes.uv_coords }
204
205    /// Adds a uv (texture) coordinate.
206    #[inline(always)]
207    pub fn push_uv_coord(&mut self, uv_coord: Vector2) { self.attributes.uv_coords.push(uv_coord) }
208
209    /// Extend uv (texture) coordinates by iterator.
210    #[inline(always)]
211    pub fn extend_uv_coords<I: IntoIterator<Item = Vector2>>(&mut self, iter: I) {
212        self.attributes.uv_coords.extend(iter)
213    }
214
215    /// Returns the vector of all normals.
216    #[inline(always)]
217    pub const fn normals(&self) -> &Vec<Vector3> { &self.attributes.normals }
218
219    /// Returns the mutable slice of all normals.
220    #[inline(always)]
221    pub fn normals_mut(&mut self) -> &mut [Vector3] { &mut self.attributes.normals }
222
223    /// Extend normals by iterator
224    #[inline(always)]
225    pub fn extend_normals<I: IntoIterator<Item = Vector3>>(&mut self, iter: I) {
226        self.attributes.normals.extend(iter)
227    }
228}
229
230impl<V, A: Default> Default for PolygonMesh<V, A> {
231    fn default() -> Self {
232        Self {
233            attributes: A::default(),
234            faces: Faces::default(),
235        }
236    }
237}
238
239impl<'de, V, A> Deserialize<'de> for PolygonMesh<V, A>
240where
241    V: Copy + Debug + Deserialize<'de>,
242    A: Attributes<V> + Deserialize<'de>,
243{
244    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
245    where D: serde::Deserializer<'de> {
246        #[derive(Deserialize)]
247        struct PolygonMesh_<V, A> {
248            attributes: A,
249            faces: Faces<V>,
250        }
251        let PolygonMesh_ { attributes, faces } = PolygonMesh_::<V, A>::deserialize(deserializer)?;
252        Self::try_new(attributes, faces).map_err(serde::de::Error::custom)
253    }
254}
255
256/// Editor of polygon mesh
257///
258/// It has mutable references to all member variables of the polygon mesh as public variables,
259/// allowing for any destructive changes for optimization.
260/// At drop time, the indices of each vertex are judged to be within the range of
261/// the array of attributes, and a panic occurs if there is one outside the range (boundary check).
262///
263/// # Examples
264/// ```
265/// use truck_polymesh::*;
266///
267/// let positions = vec![
268///     Point3::new(1.0, 0.0, 0.0),
269///     Point3::new(0.0, 1.0, 0.0),
270///     Point3::new(0.0, 0.0, 1.0),
271/// ];
272/// let faces = Faces::from_iter(&[[0, 1, 2]]);
273/// let mut mesh = PolygonMesh::new(
274///     StandardAttributes {
275///         positions,
276///         ..Default::default()
277///     },
278///     faces,
279/// );
280///
281/// // create editor
282/// let editor = mesh.editor();
283///
284/// // destructive changes
285/// editor.attributes.uv_coords.push(Vector2::new(0.0, 0.0));
286/// editor.faces.tri_faces_mut()[0][0].uv = Some(0);
287/// ```
288/// ```should_panic
289/// use truck_polymesh::*;
290///
291/// let positions = vec![
292///     Point3::new(1.0, 0.0, 0.0),
293///     Point3::new(0.0, 1.0, 0.0),
294///     Point3::new(0.0, 0.0, 1.0),
295/// ];
296/// let faces = Faces::from_iter(&[[0, 1, 2]]);
297/// let mut mesh = PolygonMesh::new(
298///     StandardAttributes {
299///         positions,
300///         ..Default::default()    
301///     },
302///     faces,
303/// );
304///
305/// // create editor
306/// let editor = mesh.editor();
307///
308/// // destructive changes
309/// editor.faces.tri_faces_mut()[0][0].uv = Some(0);
310///
311/// // Panic occurs since no uv coord is added.
312/// ```
313#[derive(Debug)]
314pub struct PolygonMeshEditor<'a, V: Copy + Debug, A: Attributes<V>> {
315    /// attributions
316    pub attributes: &'a mut A,
317    /// mutable reference to the faces of the polygon mesh
318    pub faces: &'a mut Faces<V>,
319    bound_check: bool,
320}
321
322impl<'a, V: Copy + Debug, A: Attributes<V>> PolygonMeshEditor<'a, V, A> {
323    #[inline(always)]
324    fn is_compatible(&self) -> Result<(), Error<V>> { self.faces.is_compatible(&*self.attributes) }
325
326    /// Drops with boundary check and returns `Result`.
327    #[inline(always)]
328    pub fn try_drop(mut self) -> Result<(), Error<V>> {
329        self.bound_check = false;
330        self.is_compatible()
331    }
332}
333
334impl<'a, V: Copy + Debug, A: Attributes<V>> Drop for PolygonMeshEditor<'a, V, A> {
335    #[inline(always)]
336    fn drop(&mut self) {
337        if self.bound_check {
338            self.is_compatible().unwrap_or_else(|e| panic!("{e:?}"));
339        }
340    }
341}