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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline(always)]
151 pub const fn positions(&self) -> &Vec<Vec<Point3>> { &self.positions }
152
153 #[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 #[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 #[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 #[inline(always)]
175 pub const fn normals(&self) -> Option<&Vec<Vec<Vector3>>> { self.normals.as_ref() }
176
177 #[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 #[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}