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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use glam::{Mat3, Vec3};
use crate::subdivision::triangle::Triangle;
#[derive(Clone)]
enum Face {
Base(Triangle<Vec3>),
Symmetry(usize, Mat3)
}
pub struct Seed<const N: u32> {
faces: Vec<Face>,
}
impl<const N: u32> Seed<N> {
/*
Outputs the faces of a regular icosahedron in spherical coordinates.
Source for Cartesian coordinates and faces: github.com/virtualritz/polyhedron-ops
*/
/// Initializes a seed icosahedron. Currently, this is the only seed option.
pub fn icosahedron() -> Self {
macro_rules! vertex {
($x: expr, $y: expr, $z: expr) => {
Vec3::new($x, $y, $z).normalize()
};
}
let c0 = 0.809_017;
// It's not really unused
#[allow(unused_variables)]
let vertices = vec![
vertex!( 0.5, 0.0, c0), // 0
vertex!( 0.5, 0.0, -c0), // 1
vertex!( -0.5, 0.0, c0), // 2
vertex!( -0.5, 0.0, -c0), // 3
vertex!( c0, 0.5, 0.0), // 4
vertex!( c0, -0.5, 0.0), // 5
vertex!( -c0, 0.5, 0.0), // 6
vertex!( -c0, -0.5, 0.0), // 7
vertex!( 0.0, c0, 0.5), // 8
vertex!( 0.0, c0, -0.5), // 9
vertex!( 0.0, -c0, 0.5), // 10
vertex!( 0.0, -c0, -0.5), // 11
];
// Shorthand macro for explicitly defining a triangular face.
macro_rules! triangle {
($u: expr, $v: expr, $w: expr) => {
Face::Base(Triangle::new(vertices[$u], vertices[$v], vertices[$w]))
};
}
// Shorthand macro for defining a face which is the same as another face rotated about some axis.
macro_rules! rotation {
($i: expr, $j: expr, $r: expr) => {
Face::Symmetry($i, Mat3::from_axis_angle(
vertices[$j],
(($r) as f32).to_radians()
))
};
}
// ((0.5, 0, c0), (c0, -0.5, 0), (0, -c0, 0.5)) -> ((0, -c0, -0.5), (0, -c0, 0.5), (c0, -0.5, 0))
let faces = vec![
// Top
triangle!( 0, 5, 10 ), // 0
rotation!( 0, 3, 72 ), // 1
rotation!( 0, 3, 144 ), // 2
rotation!( 0, 3, 216 ), // 3
rotation!( 0, 3, 288 ), // 4
// Upper middle
triangle!( 11, 10, 5 ), // 5
rotation!( 5, 3, 72 ), // 6
rotation!( 5, 3, 144 ), // 7
rotation!( 5, 3, 216 ), // 8
rotation!( 5, 3, 288 ), // 9
// Lower middle
triangle!( 10, 11, 7 ), // 10
rotation!( 10, 3, 72 ), // 11
rotation!( 10, 3, 144 ), // 12
rotation!( 10, 3, 216 ), // 13
rotation!( 10, 3, 288 ), // 14
// Bottom
triangle!( 3, 7, 11 ), // 15
rotation!( 15, 3, 72 ), // 16
rotation!( 15, 3, 144 ), // 17
rotation!( 15, 3, 216 ), // 18
rotation!( 15, 3, 288 ), // 19
];
Self {
faces,
}
}
/// Get the faces which are defined as transformed versions of other faces.
///
/// Returns a [Vec] of `(usize, usize, Mat3)` where the first entry is the index of the face being defined, the
/// second is the index of the face being transformed, and the third is a matrix representing the transformation
/// to turn the base face into the current face.
pub fn symmetries(&self) -> Vec<(usize, usize, Mat3)> {
self.faces.iter()
.enumerate()
.filter_map(|(i, face)| match face {
Face::Base(_) => None,
Face::Symmetry(f, t) => Some((i, f.clone(), t.clone()))
})
.collect::<Vec<_>>()
}
/// Get the faces which are defined explicitly.
///
/// Returns a [Vec] of `(usize, Triangle<Vec3>)` where the first entry is the index of the given face and the second
/// is the representation of that face in Euclidean space.
pub fn base_faces(&self) -> Vec<(usize, Triangle<Vec3>)> {
self.faces.iter()
.enumerate()
.filter_map(|(i, face)| match face {
Face::Base(t) => Some((i, t.clone())),
Face::Symmetry(_, _) => None
})
.collect::<Vec<_>>()
}
}