meshmeshmesh/
mesh.rs

1use crate::point::Point;
2use crate::triangle::Triangle;
3
4/// Represents a Mesh object in three-dimensional space.
5///
6/// This Mesh contains triangle faces only.
7///
8/// It is described by coordinates and indices.
9///
10/// *Coordinates* is a flat list of `f64` describing the vertices (points) like this:
11///
12/// [x0, y0, z0, x1, y1, z1, ... , xN, yN, zN]
13///
14/// *Indices* is a flat list of `usize` describing the faces (triangles) like this:
15///
16/// [face0_start_index, face0_middle_index, face0_end_index, face1_start_index, face1_middle_index, face1_end_index, ... , faceN_start_index, faceN_middle_index, faceN_end_index]
17///
18/// It tells you information which points construct which face.
19///
20/// The orientation of a face is described by a right hand thumb.
21///
22/// # Example
23///
24/// Here is an example with simple 1-triangle Mesh
25///
26/// ```
27/// use meshmeshmesh::mesh::Mesh;
28///
29/// let result = Mesh::new(vec![0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0, -15.0, 0.0], vec![0, 1, 2]);
30/// assert_eq!(result.coordinates, vec![0.0, 0.0, 0.0,
31///                                    10.0, 0.0, 0.0,
32///                                    10.0, -15.0, 0.0]); // We have 3 vertices there.
33/// assert_eq!(result.indices, vec![0, 1, 2]); // We create 1 face there using point0, point1 and point2.
34/// ```
35///
36pub struct Mesh {
37    /// The list of coordinates for the mesh vertices.
38    pub coordinates: Vec<f64>,
39    /// The list of indices for the mesh triangles.
40    pub indices: Vec<usize>,
41}
42
43impl PartialEq for Mesh {
44    fn eq(&self, other: &Self) -> bool {
45
46        if self.coordinates.len() != other.coordinates.len() {
47            return false;
48        }
49        for i in 0..self.coordinates.len() {
50            if self.coordinates[i] != other.coordinates[i] {
51                return false;
52            }
53        }
54        if self.indices.len() != other.indices.len() {
55            return false;
56        }
57        for i in 0..self.indices.len() {
58            if self.indices[i] != other.indices[i] {
59                return false;
60            }
61        }
62
63        true
64    }
65}
66
67impl Mesh {
68    /// Creates a new [Mesh]
69    ///
70    /// # Example
71    ///
72    /// Here is an example with simple 1-triangle Mesh
73    ///
74    /// ```
75    /// use meshmeshmesh::mesh::Mesh;
76    ///
77    /// let result = Mesh::new(vec![0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0, -15.0, 0.0], vec![0, 1, 2]);
78    /// assert_eq!(result.coordinates, vec![0.0, 0.0, 0.0,
79    ///                                    10.0, 0.0, 0.0,
80    ///                                    10.0, -15.0, 0.0]);
81    /// assert_eq!(result.indices, vec![0, 1, 2]);
82    /// ```
83    pub fn new(coordinates: Vec<f64>, indices: Vec<usize>) -> Mesh {Mesh {coordinates, indices}}
84
85    /// Converts [Mesh] into list of [Point]s
86    ///
87    /// # Example
88    ///
89    /// Here is an example with simple 1-triangle Mesh being converted to 3 Points
90    ///
91    /// ```
92    /// use meshmeshmesh::mesh::Mesh;
93    /// use meshmeshmesh::point::Point;
94    ///
95    /// let input = Mesh::new(vec![0.0, 0.0, 0.0,
96    ///                            10.0, 0.0, 0.0,
97    ///                            10.0, -15.0, 0.0],
98    ///                       vec![0, 1, 2]);
99    /// let actual = input.to_points();
100    /// let expected = vec![Point::new(0.0, 0.0, 0.0),
101    ///                     Point::new(10.0, 0.0, 0.0),
102    ///                     Point::new(10.0, -15.0, 0.0)];
103    /// assert_eq!(expected.len(), actual.len());
104    /// for i in 0..expected.len() {
105    ///     assert_eq!(expected[i].eq(&actual[i]), true);
106    /// }
107    /// ```
108    pub fn to_points(&self) -> Vec<Point> {
109        let mut points = Vec::<Point>::new();
110        let coordinates_length: usize = self.coordinates.len();
111        let mut i = 0;
112        while i < coordinates_length {
113            points.push(Point::new(self.coordinates[i], self.coordinates[i+1], self.coordinates[i+2]));
114            i = i + 3;
115        }
116        points
117    }
118
119    /// Converts [Mesh] into list of [Triangle]s
120    ///
121    /// # Example
122    ///
123    /// Here is an example with simple 1-triangle Mesh being converted to 1 Triangle
124    ///
125    /// ```
126    /// use meshmeshmesh::mesh::Mesh;
127    /// use meshmeshmesh::point::Point;
128    /// use meshmeshmesh::triangle::Triangle;
129    ///
130    /// let input = Mesh::new(vec![0.0, 0.0, 0.0,
131    ///                            10.0, 0.0, 0.0,
132    ///                            10.0, -15.0, 0.0],
133    /// vec![0, 1, 2]);
134    /// let actual = input.to_triangles();
135    /// let expected = vec![Triangle::new(
136    ///     Point::new(0.0, 0.0, 0.0),
137    ///     Point::new(10.0, 0.0, 0.0),
138    ///     Point::new(10.0, -15.0, 0.0))];
139    /// assert_eq!(expected.len(), actual.len());
140    /// for i in 0..expected.len() {
141    ///     assert_eq!(expected[i].eq(&actual[i]), true);
142    /// }
143    /// ```
144    pub fn to_triangles(&self) -> Vec<Triangle> {
145        let mut triangles = Vec::<Triangle>::new();
146        let indices_length: usize = self.indices.len();
147        let mut i = 0;
148        while i < indices_length {
149            let offset0 = self.indices[i] * 3;
150            let index00 = usize::try_from(offset0).unwrap();
151            let index01 = usize::try_from(offset0 + 1).unwrap();
152            let index02 = usize::try_from(offset0 + 2).unwrap();
153            let point0: Point = Point::new(self.coordinates[index00], self.coordinates[index01], self.coordinates[index02]);
154
155            let offset1 = self.indices[i+1] * 3;
156            let index10 = usize::try_from(offset1).unwrap();
157            let index11 = usize::try_from(offset1 + 1).unwrap();
158            let index12 = usize::try_from(offset1 + 2).unwrap();
159            let point1: Point = Point::new(self.coordinates[index10], self.coordinates[index11], self.coordinates[index12]);
160
161            let offset2 = self.indices[i+2] * 3;
162            let index20 = usize::try_from(offset2).unwrap();
163            let index21 = usize::try_from(offset2 + 1).unwrap();
164            let index22 = usize::try_from(offset2 + 2).unwrap();
165            let point2: Point = Point::new(self.coordinates[index20], self.coordinates[index21], self.coordinates[index22]);
166
167            triangles.push(Triangle::new(point0, point1, point2));
168            i = i + 3;
169        }
170
171        triangles
172    }
173
174    /// Creates [Mesh] from list of [Triangle]s
175    ///
176    /// # Example
177    ///
178    /// Here is an example with creating a simple 1-triangle Mesh using a Triangle
179    ///
180    /// ```
181    /// use meshmeshmesh::mesh::Mesh;
182    /// use meshmeshmesh::point::Point;
183    /// use meshmeshmesh::triangle::Triangle;
184    ///
185    /// let input = vec![Triangle::new(
186    ///     Point::new(0.0, 0.0, 0.0),
187    ///     Point::new(10.0, 0.0, 0.0),
188    ///     Point::new(10.0, -15.0, 0.0))];
189    /// let actual = Mesh::from_triangles(input);
190    /// let expected = Mesh::new(vec![0.0, 0.0, 0.0,
191    ///                               10.0, 0.0, 0.0,
192    ///                               10.0, -15.0, 0.0], vec![0, 1, 2]);
193    ///
194    /// assert_eq!(expected.eq(&actual), true);
195    /// ```
196    pub fn from_triangles(triangles: Vec<Triangle>) -> Mesh {
197        let number_of_triangles: usize = triangles.len();
198        let number_of_indices: usize = number_of_triangles * 3;
199        let mut indices: Vec<usize> = Vec::<usize>::new();
200        for i in 0..number_of_indices {
201            indices.push(i);
202        }
203        let mut coordinates: Vec<f64> = Vec::<f64>::new();
204        for i in 0..number_of_triangles {
205            let current_triangle = &triangles[i];
206            coordinates.push(current_triangle.first_point.x);
207            coordinates.push(current_triangle.first_point.y);
208            coordinates.push(current_triangle.first_point.z);
209
210            coordinates.push(current_triangle.second_point.x);
211            coordinates.push(current_triangle.second_point.y);
212            coordinates.push(current_triangle.second_point.z);
213
214            coordinates.push(current_triangle.third_point.x);
215            coordinates.push(current_triangle.third_point.y);
216            coordinates.push(current_triangle.third_point.z);
217        }
218
219        Mesh::new(coordinates, indices)
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226
227    #[test]
228    fn test_new() {
229        let result = Mesh::new(vec![0.0, 0.0, 0.0,
230                                    10.0, 0.0, 0.0,
231                                    10.0, -15.0, 0.0],
232                               vec![0, 1, 2]);
233        assert_eq!(result.coordinates, vec![0.0, 0.0, 0.0,
234                                            10.0, 0.0, 0.0,
235                                            10.0, -15.0, 0.0]);
236        assert_eq!(result.indices, vec![0, 1, 2]);
237    }
238
239    #[test]
240    fn test_to_points() {
241        let input = Mesh::new(vec![0.0, 0.0, 0.0,
242                                   10.0, 0.0, 0.0,
243                                   10.0, -15.0, 0.0],
244                              vec![0, 1, 2]);
245        let actual = input.to_points();
246        let expected = vec![Point::new(0.0, 0.0, 0.0),
247                            Point::new(10.0, 0.0, 0.0),
248                            Point::new(10.0, -15.0, 0.0)];
249        assert_eq!(expected.len(), actual.len());
250        for i in 0..expected.len() {
251            assert_eq!(expected[i].eq(&actual[i]), true);
252        }
253    }
254
255    #[test]
256    fn test_to_triangles_1face() {
257        let input = Mesh::new(vec![0.0, 0.0, 0.0,
258                                   10.0, 0.0, 0.0,
259                                   10.0, -15.0, 0.0],
260                              vec![0, 1, 2]);
261        let actual = input.to_triangles();
262        let expected = vec![Triangle::new(
263                            Point::new(0.0, 0.0, 0.0),
264                            Point::new(10.0, 0.0, 0.0),
265                            Point::new(10.0, -15.0, 0.0))];
266        assert_eq!(expected.len(), actual.len());
267        for i in 0..expected.len() {
268            assert_eq!(expected[i].eq(&actual[i]), true);
269        }
270    }
271
272    #[test]
273    fn test_to_triangles_pyramid() {
274        let input = Mesh::new(
275            vec![
276                // Base
277                0.0,0.0,0.0,
278                10.0,0.0,0.0,
279                10.0,10.0,0.0,
280                0.0,10.0,0.0,
281
282                // Top
283                5.0,5.0,4.0
284            ],
285            vec![
286                // Base faces
287                0,1,2,
288                0,2,3,
289
290                // Side faces
291                0,1,4,
292                1,2,4,
293                2,3,4,
294                3,0,4
295            ]
296        );
297        let actual = input.to_triangles();
298        let expected = vec![
299            Triangle::new(
300                Point::new(0.0, 0.0, 0.0),
301                Point::new(10.0, 0.0, 0.0),
302                Point::new(10.0,10.0,0.0)),
303            Triangle::new(
304                Point::new(0.0, 0.0, 0.0),
305                Point::new(10.0,10.0,0.0),
306                Point::new(0.0,10.0,0.0)),
307
308            Triangle::new(
309                Point::new(0.0, 0.0, 0.0),
310                Point::new(10.0, 0.0, 0.0),
311                Point::new(5.0,5.0,4.0)),
312            Triangle::new(
313                Point::new(10.0, 0.0, 0.0),
314                Point::new(10.0,10.0,0.0),
315                Point::new(5.0,5.0,4.0)),
316            Triangle::new(
317                Point::new(10.0,10.0,0.0),
318                Point::new(0.0,10.0,0.0),
319                Point::new(5.0,5.0,4.0)),
320            Triangle::new(
321                Point::new(0.0,10.0,0.0),
322                Point::new(0.0,0.0,0.0),
323                Point::new(5.0,5.0,4.0)),
324        ];
325        assert_eq!(expected.len(), actual.len());
326        for i in 0..expected.len() {
327            assert_eq!(expected[i].eq(&actual[i]), true);
328        }
329    }
330
331    #[test]
332    fn test_from_triangles_1face() {
333        let input = vec![Triangle::new(
334            Point::new(0.0, 0.0, 0.0),
335            Point::new(10.0, 0.0, 0.0),
336            Point::new(10.0, -15.0, 0.0))];
337        let actual = Mesh::from_triangles(input);
338        let expected = Mesh::new(vec![0.0, 0.0, 0.0,
339                                   10.0, 0.0, 0.0,
340                                   10.0, -15.0, 0.0],
341                              vec![0, 1, 2]);
342        assert_eq!(expected.eq(&actual), true);
343    }
344
345    #[test]
346    fn test_from_triangles_pyramid() {
347        let input = vec![
348            Triangle::new(
349                Point::new(0.0, 0.0, 0.0),
350                Point::new(10.0, 0.0, 0.0),
351                Point::new(10.0,10.0,0.0)),
352            Triangle::new(
353                Point::new(0.0, 0.0, 0.0),
354                Point::new(10.0,10.0,0.0),
355                Point::new(0.0,10.0,0.0)),
356
357            Triangle::new(
358                Point::new(0.0, 0.0, 0.0),
359                Point::new(10.0, 0.0, 0.0),
360                Point::new(5.0,5.0,4.0)),
361            Triangle::new(
362                Point::new(10.0, 0.0, 0.0),
363                Point::new(10.0,10.0,0.0),
364                Point::new(5.0,5.0,4.0)),
365            Triangle::new(
366                Point::new(10.0,10.0,0.0),
367                Point::new(0.0,10.0,0.0),
368                Point::new(5.0,5.0,4.0)),
369            Triangle::new(
370                Point::new(0.0,10.0,0.0),
371                Point::new(0.0,0.0,0.0),
372                Point::new(5.0,5.0,4.0)),
373        ];
374
375        let actual = Mesh::from_triangles(input);
376        let expected= Mesh::new(
377            vec![
378                0.0, 0.0, 0.0,
379                10.0, 0.0, 0.0,
380                10.0,10.0,0.0,
381
382                0.0, 0.0, 0.0,
383                10.0,10.0,0.0,
384                0.0,10.0,0.0,
385
386
387                0.0, 0.0, 0.0,
388                10.0, 0.0, 0.0,
389                5.0,5.0,4.0,
390
391                10.0, 0.0, 0.0,
392                10.0,10.0,0.0,
393                5.0,5.0,4.0,
394
395                10.0,10.0,0.0,
396                0.0,10.0,0.0,
397                5.0,5.0,4.0,
398
399                0.0,10.0,0.0,
400                0.0,0.0,0.0,
401                5.0,5.0,4.0,
402            ],
403            vec![
404                // Base faces
405                0,1,2,
406                3,4,5,
407
408                // Side faces
409                6,7,8,
410                9,10,11,
411                12,13,14,
412                15,16,17
413            ]
414        );
415
416        assert_eq!(expected.eq(&actual), true);
417    }
418
419    #[test]
420    fn test_partialeq_true() {
421        let a = Mesh::new(vec![0.0, 0.0, 0.0,
422                               10.0, 0.0, 0.0,
423                               10.0, -15.0, 0.0],
424                          vec![0, 1, 2]);
425        let b = Mesh::new(vec![0.0, 0.0, 0.0,
426                               10.0, 0.0, 0.0,
427                               10.0, -15.0, 0.0],
428                          vec![0, 1, 2]);
429        assert_eq!(a.eq(&b), true);
430        assert_eq!(b.eq(&a), true);
431    }
432
433    #[test]
434    fn test_partialeq_coordinates_count_false() {
435        let a = Mesh::new(vec![0.0, 0.0, 0.0,
436                               10.0, 0.0, 0.0,
437                               10.0, -15.0, 0.0,
438                               5.0, 1.0, 0.0],
439                          vec![0, 1, 2]);
440        let b = Mesh::new(vec![0.0, 0.0, 0.0,
441                               10.0, 0.0, 0.0,
442                               10.0, -15.0, 0.0],
443                          vec![0, 1, 2]);
444        assert_eq!(a.eq(&b), false);
445        assert_eq!(b.eq(&a), false);
446    }
447
448    #[test]
449    fn test_partialeq_different_coordinates_false() {
450        let a = Mesh::new(vec![0.0, 0.0, 0.0,
451                               10.0, 2.0, 0.0,
452                               10.0, -15.0, 0.0],
453                          vec![0, 1, 2]);
454        let b = Mesh::new(vec![0.0, 0.0, 0.0,
455                               10.0, 0.0, 0.0,
456                               10.0, -15.0, 0.0],
457                          vec![0, 1, 2]);
458        assert_eq!(a.eq(&b), false);
459        assert_eq!(b.eq(&a), false);
460    }
461
462    #[test]
463    fn test_partialeq_indices_count_false() {
464        let a = Mesh::new(vec![0.0, 0.0, 0.0,
465                               10.0, 0.0, 0.0,
466                               10.0, -15.0, 0.0],
467                          vec![0, 1, 2, 2, 1, 0]);
468        let b = Mesh::new(vec![0.0, 0.0, 0.0,
469                               10.0, 0.0, 0.0,
470                               10.0, -15.0, 0.0],
471                          vec![0, 1, 2]);
472        assert_eq!(a.eq(&b), false);
473        assert_eq!(b.eq(&a), false);
474    }
475
476    #[test]
477    fn test_partialeq_different_indices_false() {
478        let a = Mesh::new(vec![0.0, 0.0, 0.0,
479                               10.0, 0.0, 0.0,
480                               10.0, -15.0, 0.0],
481                          vec![0, 2, 1]);
482        let b = Mesh::new(vec![0.0, 0.0, 0.0,
483                               10.0, 0.0, 0.0,
484                               10.0, -15.0, 0.0],
485                          vec![0, 1, 2]);
486        assert_eq!(a.eq(&b), false);
487        assert_eq!(b.eq(&a), false);
488    }
489}