truck_polymesh/
structured_mesh.rs

1use crate::*;
2use errors::Error;
3type Result<T> = std::result::Result<T, Error>;
4
5impl StandardVertex {
6    #[inline(always)]
7    fn tuple(x: usize, uv: bool, nor: bool) -> StandardVertex {
8        let pos = x;
9        let uv = if uv { Some(x) } else { None };
10        let nor = if nor { Some(x) } else { None };
11        StandardVertex { pos, uv, nor }
12    }
13}
14
15impl StructuredMesh {
16    /// Creates a structured polygon without `uv_division` and `normal`.
17    #[inline(always)]
18    pub fn from_positions(positions: Vec<Vec<Point3>>) -> StructuredMesh {
19        StructuredMesh::try_from_positions(positions).unwrap_or_else(|e| panic!("{e:?}"))
20    }
21    /// Creates a structured polygon without `uv_division` and `normal`.
22    #[inline(always)]
23    pub fn try_from_positions(positions: Vec<Vec<Point3>>) -> Result<StructuredMesh> {
24        check_matrix_regularity(&positions)?;
25        Ok(StructuredMesh::from_positions_unchecked(positions))
26    }
27
28    /// Creates a structured polygon without `uv_division` and `normal`.
29    #[inline(always)]
30    pub const fn from_positions_unchecked(positions: Vec<Vec<Point3>>) -> StructuredMesh {
31        StructuredMesh {
32            positions,
33            uv_division: None,
34            normals: None,
35        }
36    }
37    /// Creates a structured polygon without normals.
38    #[inline(always)]
39    pub fn from_positions_and_uvs(
40        positions: Vec<Vec<Point3>>,
41        (u_div, v_div): (Vec<f64>, Vec<f64>),
42    ) -> StructuredMesh {
43        StructuredMesh::try_from_positions_and_uvs(positions, (u_div, v_div))
44            .unwrap_or_else(|e| panic!("{e:?}"))
45    }
46
47    /// Creates a structured polygon without normals.
48    #[inline(always)]
49    pub fn try_from_positions_and_uvs(
50        positions: Vec<Vec<Point3>>,
51        (u_div, v_div): (Vec<f64>, Vec<f64>),
52    ) -> Result<StructuredMesh> {
53        check_matrix_vectors_compatibility(&positions, &u_div, &v_div)?;
54        check_vectors_regularity(&u_div, &v_div)?;
55        Ok(StructuredMesh::from_positions_and_uvs_unchecked(
56            positions,
57            (u_div, v_div),
58        ))
59    }
60    /// Creates a structured polygon without normals.
61    #[inline(always)]
62    pub const fn from_positions_and_uvs_unchecked(
63        positions: Vec<Vec<Point3>>,
64        uv_divisions: (Vec<f64>, Vec<f64>),
65    ) -> StructuredMesh {
66        StructuredMesh {
67            positions,
68            uv_division: Some(uv_divisions),
69            normals: None,
70        }
71    }
72    /// Creates a structured polygon without uv divisions.
73    #[inline(always)]
74    pub fn from_positions_and_normals(
75        positions: Vec<Vec<Point3>>,
76        normals: Vec<Vec<Vector3>>,
77    ) -> StructuredMesh {
78        StructuredMesh::try_from_positions_and_normals(positions, normals)
79            .unwrap_or_else(|e| panic!("{e:?}"))
80    }
81    /// Creates a structured polygon without uv divisions.
82    #[inline(always)]
83    pub fn try_from_positions_and_normals(
84        positions: Vec<Vec<Point3>>,
85        normals: Vec<Vec<Vector3>>,
86    ) -> Result<StructuredMesh> {
87        check_matrix_regularity(&positions)?;
88        check_matrices_compatibility(&positions, &normals)?;
89        Ok(StructuredMesh::from_positions_and_normals_unchecked(
90            positions, normals,
91        ))
92    }
93    /// Creates a structured polygon without uv divisions.
94    #[inline(always)]
95    pub const fn from_positions_and_normals_unchecked(
96        positions: Vec<Vec<Point3>>,
97        normals: Vec<Vec<Vector3>>,
98    ) -> StructuredMesh {
99        StructuredMesh {
100            positions,
101            uv_division: None,
102            normals: Some(normals),
103        }
104    }
105
106    /// Creates new structured mesh.
107    /// Checks whether the size of vectors are compatible before creation.
108    #[inline(always)]
109    pub fn new(
110        positions: Vec<Vec<Point3>>,
111        uv_division: (Vec<f64>, Vec<f64>),
112        normals: Vec<Vec<Vector3>>,
113    ) -> StructuredMesh {
114        StructuredMesh::try_new(positions, uv_division, normals).unwrap_or_else(|e| panic!("{e:?}"))
115    }
116    /// Creates new structured mesh.
117    /// Checks whether the size of vectors are compatible before creation.
118    #[inline(always)]
119    pub fn try_new(
120        positions: Vec<Vec<Point3>>,
121        (u_div, v_div): (Vec<f64>, Vec<f64>),
122        normals: Vec<Vec<Vector3>>,
123    ) -> Result<StructuredMesh> {
124        check_matrix_vectors_compatibility(&positions, &u_div, &v_div)?;
125        check_matrix_vectors_compatibility(&normals, &u_div, &v_div)?;
126        check_vectors_regularity(&u_div, &v_div)?;
127        Ok(StructuredMesh::new_unchecked(
128            positions,
129            (u_div, v_div),
130            normals,
131        ))
132    }
133
134    /// Creates new structured mesh.
135    /// Does not check whether the size of vectors are compatible before creation.
136    #[inline(always)]
137    pub const fn new_unchecked(
138        positions: Vec<Vec<Point3>>,
139        uv_division: (Vec<f64>, Vec<f64>),
140        normals: Vec<Vec<Vector3>>,
141    ) -> StructuredMesh {
142        StructuredMesh {
143            positions,
144            uv_division: Some(uv_division),
145            normals: Some(normals),
146        }
147    }
148
149    /// Returns the matrix of all positions.
150    #[inline(always)]
151    pub const fn positions(&self) -> &Vec<Vec<Point3>> { &self.positions }
152
153    /// Returns the vector of the mutable references to the rows of the positions matrix.
154    #[inline(always)]
155    pub fn positions_mut(&mut self) -> Vec<&mut [Point3]> {
156        self.positions.iter_mut().map(|arr| arr.as_mut()).collect()
157    }
158
159    /// Returns the divisions of uv coordinates.
160    #[inline(always)]
161    pub fn uv_division(&self) -> Option<(&Vec<f64>, &Vec<f64>)> {
162        self.uv_division.as_ref().map(|tuple| (&tuple.0, &tuple.1))
163    }
164
165    /// Returns the mutable slice of uv coordinates division.
166    #[inline(always)]
167    pub fn uv_division_mut(&mut self) -> Option<(&mut [f64], &mut [f64])> {
168        self.uv_division
169            .as_mut()
170            .map(|tuple| (tuple.0.as_mut(), tuple.1.as_mut()))
171    }
172
173    /// Returns the matrix of all normals.
174    #[inline(always)]
175    pub const fn normals(&self) -> Option<&Vec<Vec<Vector3>>> { self.normals.as_ref() }
176
177    /// Returns the vector of the mutable references to the rows of the normals matrix.
178    #[inline(always)]
179    pub fn normals_mut(&mut self) -> Option<Vec<&mut [Vector3]>> {
180        self.normals
181            .as_mut()
182            .map(|normals| normals.iter_mut().map(|arr| arr.as_mut()).collect())
183    }
184
185    /// Creates new polygon mesh by destructing `self`.
186    #[inline(always)]
187    pub fn destruct(self) -> PolygonMesh {
188        let StructuredMesh {
189            positions,
190            uv_division,
191            normals,
192        } = self;
193        let m = positions.len();
194        let n = positions[0].len();
195        let positions = positions.into_iter().flatten().collect();
196        let uv_coords = uv_division
197            .map(move |(udiv, vdiv)| {
198                udiv.into_iter()
199                    .flat_map(|u| vdiv.iter().map(move |v| Vector2::new(u, *v)))
200                    .collect()
201            })
202            .unwrap_or_else(Vec::new);
203        let normals = normals
204            .map(|n| n.into_iter().flatten().collect())
205            .unwrap_or_else(Vec::new);
206        let uv = !uv_coords.is_empty();
207        let nor = !normals.is_empty();
208        let quad_faces: Vec<_> = itertools::iproduct!(1..m, 1..n)
209            .map(move |(i, j)| {
210                [
211                    StandardVertex::tuple((i - 1) * n + j - 1, uv, nor),
212                    StandardVertex::tuple(i * n + j - 1, uv, nor),
213                    StandardVertex::tuple(i * n + j, uv, nor),
214                    StandardVertex::tuple((i - 1) * n + j, uv, nor),
215                ]
216            })
217            .collect();
218        let faces = Faces {
219            quad_faces,
220            ..Default::default()
221        };
222        PolygonMesh {
223            attributes: StandardAttributes {
224                positions,
225                uv_coords,
226                normals,
227            },
228            faces,
229        }
230    }
231}
232
233impl<'de> Deserialize<'de> for StructuredMesh {
234    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
235    where D: serde::Deserializer<'de> {
236        #[derive(Deserialize)]
237        pub struct StructuredMesh_ {
238            positions: Vec<Vec<Point3>>,
239            uv_division: Option<(Vec<f64>, Vec<f64>)>,
240            normals: Option<Vec<Vec<Vector3>>>,
241        }
242        let StructuredMesh_ {
243            positions,
244            uv_division,
245            normals,
246        } = StructuredMesh_::deserialize(deserializer)?;
247        match (uv_division, normals) {
248            (Some(uv_division), Some(normals)) => Self::try_new(positions, uv_division, normals),
249            (Some(uv_division), None) => Self::try_from_positions_and_uvs(positions, uv_division),
250            (None, Some(normals)) => Self::try_from_positions_and_normals(positions, normals),
251            (None, None) => Self::try_from_positions(positions),
252        }
253        .map_err(serde::de::Error::custom)
254    }
255}
256
257#[inline(always)]
258fn check_matrix_regularity<T>(matrix: &[Vec<T>]) -> Result<()> {
259    for arr in matrix {
260        if arr.len() != matrix[0].len() {
261            return Err(Error::IrregularArray);
262        }
263    }
264    Ok(())
265}
266
267#[inline(always)]
268fn check_matrices_compatibility<S, T>(matrix0: &[Vec<S>], matrix1: &[Vec<T>]) -> Result<()> {
269    if matrix0.len() != matrix1.len() {
270        return Err(Error::DifferentLengthArrays);
271    }
272    for arr in matrix0 {
273        if arr.len() != matrix1[0].len() {
274            return Err(Error::DifferentLengthArrays);
275        }
276    }
277    Ok(())
278}
279
280#[inline(always)]
281fn check_vectors_regularity(vec0: &[f64], vec1: &[f64]) -> Result<()> {
282    for i in 1..vec0.len() {
283        if vec0[i - 1] > vec0[i] {
284            return Err(Error::UnsortedDivision);
285        }
286    }
287    for i in 1..vec1.len() {
288        if vec1[i - 1] > vec1[i] {
289            return Err(Error::UnsortedDivision);
290        }
291    }
292    Ok(())
293}
294
295#[inline(always)]
296fn check_matrix_vectors_compatibility<T>(
297    matrix: &[Vec<T>],
298    vec0: &[f64],
299    vec1: &[f64],
300) -> Result<()> {
301    if matrix.len() != vec0.len() {
302        return Err(Error::DifferentLengthArrays);
303    }
304    for arr in matrix {
305        if arr.len() != vec1.len() {
306            return Err(Error::DifferentLengthArrays);
307        }
308    }
309    Ok(())
310}