1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use crate::*;
use rustc_hash::FxHashMap as HashMap;
use std::fmt::Debug;
use std::hash::Hash;

impl<V: Copy + Hash + Debug + Eq, A: Attributes<V>> PolygonMesh<V, A> {
	/// Contract attributes and expand polygon.
	///
	/// # Examples
	/// ```
	/// use truck_polymesh::*;
	/// let polygon = PolygonMesh::new(
	///     StandardAttributes {
	///         positions: vec![
	///             Point3::new(0.0, 0.0, 0.0),
	///             Point3::new(1.0, 0.0, 0.0),
	///             Point3::new(0.0, 1.0, 0.0),
	///             Point3::new(1.0, 1.0, 0.0),
	///         ],
	///         normals: vec![
	///             Vector3::new(0.0, 0.0, 1.0),
	///             Vector3::new(0.0, 0.0, -1.0),
	///         ],
	///         ..Default::default()
	///     },
	///     Faces::from_iter(&[
	///         &[(0, None, Some(0)), (1, None, Some(0)), (2, None, Some(0))],
	///         &[(3, None, Some(1)), (1, None, Some(1)), (2, None, Some(1))],
	///     ])
	/// );
	/// let expands = polygon.expands(|attr| (attr.position, attr.normal.unwrap()));
	/// assert_eq!(
	///     expands,
	///     PolygonMesh::<usize, Vec<(Point3, Vector3)>>::new(
	///         vec![
	///            (Point3::new(0.0, 0.0, 0.0), Vector3::new(0.0, 0.0, 1.0)),
	///            (Point3::new(1.0, 0.0, 0.0), Vector3::new(0.0, 0.0, 1.0)),
	///            (Point3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 0.0, 1.0)),
	///            (Point3::new(1.0, 1.0, 0.0), Vector3::new(0.0, 0.0, -1.0)),
	///            (Point3::new(1.0, 0.0, 0.0), Vector3::new(0.0, 0.0, -1.0)),
	///            (Point3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 0.0, -1.0)),
	///         ],
	///         Faces::from_iter(&[[0, 1, 2], [3, 4, 5]]),
	///     )
	/// );
	/// ```
	pub fn expands<T: Copy>(
		&self,
		contraction: impl Fn(A::Output) -> T,
	) -> PolygonMesh<usize, Vec<T>> {
		let mut vec = Vec::<T>::new();
		let mut vertex_map = HashMap::<V, usize>::default();
		let faces: Faces<usize> = self
			.face_iter()
			.map(|face| {
				face.iter()
					.cloned()
					.map(|vertex| {
						*vertex_map.entry(vertex).or_insert_with(|| {
							let idx = vec.len();
							vec.push(contraction(self.attributes.get(vertex).unwrap()));
							idx
						})
					})
					.collect::<Vec<_>>()
			})
			.collect();
		PolygonMesh::new(vec, faces)
	}
}