truck_polymesh/
expand.rs

1use crate::*;
2use std::fmt::Debug;
3use std::hash::Hash;
4use truck_base::entry_map::FxEntryMap as EntryMap;
5
6impl<V: Copy + Hash + Debug + Eq, A: Attributes<V>> PolygonMesh<V, A> {
7    /// Contract attributes and expand polygon.
8    ///
9    /// # Examples
10    /// ```
11    /// use truck_polymesh::*;
12    /// let polygon = PolygonMesh::new(
13    ///     StandardAttributes {
14    ///         positions: vec![
15    ///             Point3::new(0.0, 0.0, 0.0),
16    ///             Point3::new(1.0, 0.0, 0.0),
17    ///             Point3::new(0.0, 1.0, 0.0),
18    ///             Point3::new(1.0, 1.0, 0.0),
19    ///         ],
20    ///         normals: vec![
21    ///             Vector3::new(0.0, 0.0, 1.0),
22    ///             Vector3::new(0.0, 0.0, -1.0),
23    ///         ],
24    ///         ..Default::default()
25    ///     },
26    ///     Faces::from_iter(&[
27    ///         &[(0, None, Some(0)), (1, None, Some(0)), (2, None, Some(0))],
28    ///         &[(3, None, Some(1)), (1, None, Some(1)), (2, None, Some(1))],
29    ///     ])
30    /// );
31    /// let expands = polygon.expands(|attr| (attr.position, attr.normal.unwrap()));
32    /// assert_eq!(
33    ///     expands,
34    ///     PolygonMesh::<usize, Vec<(Point3, Vector3)>>::new(
35    ///         vec![
36    ///            (Point3::new(0.0, 0.0, 0.0), Vector3::new(0.0, 0.0, 1.0)),
37    ///            (Point3::new(1.0, 0.0, 0.0), Vector3::new(0.0, 0.0, 1.0)),
38    ///            (Point3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 0.0, 1.0)),
39    ///            (Point3::new(1.0, 1.0, 0.0), Vector3::new(0.0, 0.0, -1.0)),
40    ///            (Point3::new(1.0, 0.0, 0.0), Vector3::new(0.0, 0.0, -1.0)),
41    ///            (Point3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 0.0, -1.0)),
42    ///         ],
43    ///         Faces::from_iter(&[[0, 1, 2], [3, 4, 5]]),
44    ///     )
45    /// );
46    /// ```
47    pub fn expands<T: Copy>(
48        &self,
49        contraction: impl Fn(A::Output) -> T,
50    ) -> PolygonMesh<usize, Vec<T>> {
51        let mut vec = Vec::<T>::new();
52        let mut vertex_map = EntryMap::new(
53            |x| x,
54            |vertex| {
55                let idx = vec.len();
56                vec.push(contraction(self.attributes.get(vertex).unwrap()));
57                idx
58            },
59        );
60        let faces: Faces<usize> = self
61            .face_iter()
62            .map(|face| {
63                face.iter()
64                    .cloned()
65                    .map(|vertex| *vertex_map.entry_or_insert(vertex))
66                    .collect::<Vec<_>>()
67            })
68            .collect();
69        PolygonMesh::new(vec, faces)
70    }
71}