1use decorum::R64;
23use num::{One, Zero};
24
25use crate::geometry::{Duplet, Triplet};
26use crate::primitive::generate::{
27 Generate, NormalGenerator, NormalIndexGenerator, NormalPolygonGenerator, NormalVertexGenerator,
28 PolygonGenerator, PositionGenerator, PositionIndexGenerator, PositionPolygonGenerator,
29 PositionVertexGenerator, UvMapGenerator, UvMapPolygonGenerator,
30};
31use crate::primitive::topology::{Converged, Map, Quad};
32
33#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
34pub enum Plane {
35 XY,
36 NXY,
37 ZY,
38 NZY,
39 XZ,
40 XNZ,
41}
42
43impl Plane {
44 pub fn normal(&self) -> Triplet<R64> {
45 let zero = R64::zero();
46 let one = R64::one();
47 match *self {
48 Plane::XY => Triplet(zero, zero, one), Plane::NXY => Triplet(zero, one, zero), Plane::ZY => Triplet(-one, zero, zero), Plane::NZY => Triplet(zero, -one, zero), Plane::XZ => Triplet(one, zero, zero), Plane::XNZ => Triplet(zero, zero, -one), }
55 }
56}
57
58#[derive(Clone, Copy)]
59pub struct Bounds {
60 lower: R64,
61 upper: R64,
62}
63
64impl Bounds {
65 pub fn with_radius(radius: R64) -> Self {
66 Bounds {
67 lower: -radius,
68 upper: radius,
69 }
70 }
71
72 pub fn with_width(width: R64) -> Self {
73 Self::with_radius(width / 2.0)
74 }
75
76 pub fn unit_radius() -> Self {
77 Self::with_radius(One::one())
78 }
79
80 pub fn unit_width() -> Self {
81 Self::with_width(One::one())
82 }
83}
84
85impl Default for Bounds {
86 fn default() -> Self {
87 Self::unit_width()
88 }
89}
90
91#[derive(Clone, Copy)]
92pub struct Cube;
93
94impl Cube {
95 pub fn new() -> Self {
96 Cube
97 }
98
99 pub fn polygons_with_plane(&self) -> Generate<Self, (), Quad<Plane>> {
100 Generate::new(self, (), self.polygon_count(), |generator, _, index| {
101 generator.polygon_with_plane(index)
102 })
103 }
104
105 pub fn vertex_with_plane_count(&self) -> usize {
106 self.polygon_count()
107 }
108
109 pub fn vertex_with_plane(&self, index: usize) -> Plane {
110 match index {
111 0 => Plane::XY, 1 => Plane::NZY, 2 => Plane::XNZ, 3 => Plane::ZY, 4 => Plane::XZ, 5 => Plane::NXY, _ => panic!(),
118 }
119 }
120
121 pub fn polygon_with_plane(&self, index: usize) -> Quad<Plane> {
122 Quad::converged(self.vertex_with_plane(index))
123 }
124}
125
126impl Default for Cube {
127 fn default() -> Self {
128 Cube::new()
129 }
130}
131
132impl PolygonGenerator for Cube {
133 fn polygon_count(&self) -> usize {
134 6
135 }
136}
137
138impl NormalGenerator for Cube {
139 type State = ();
140}
141
142impl NormalVertexGenerator for Cube {
143 type Output = Triplet<R64>;
144
145 fn vertex_with_normal_from(&self, _: &Self::State, index: usize) -> Self::Output {
146 self.vertex_with_plane(index).normal()
148 }
149
150 fn vertex_with_normal_count(&self) -> usize {
151 self.polygon_count()
152 }
153}
154
155impl NormalPolygonGenerator for Cube {
156 type Output = Quad<<Self as NormalVertexGenerator>::Output>;
157
158 fn polygon_with_normal_from(&self, state: &Self::State, index: usize) -> Self::Output {
159 self.index_for_normal(index)
160 .map(|index| self.vertex_with_normal_from(state, index))
161 }
162}
163
164impl NormalIndexGenerator for Cube {
165 type Output = Quad<usize>;
166
167 fn index_for_normal(&self, index: usize) -> <Self as PositionIndexGenerator>::Output {
168 assert!(index < self.polygon_count());
169 Quad::converged(index)
170 }
171}
172
173impl PositionGenerator for Cube {
174 type State = Bounds;
175}
176
177impl PositionVertexGenerator for Cube {
178 type Output = Triplet<R64>;
179
180 fn vertex_with_position_from(&self, state: &Self::State, index: usize) -> Self::Output {
181 let x = if index & 0b100 == 0b100 {
182 state.upper
183 }
184 else {
185 state.lower
186 };
187 let y = if index & 0b010 == 0b010 {
188 state.upper
189 }
190 else {
191 state.lower
192 };
193 let z = if index & 0b001 == 0b001 {
194 state.upper
195 }
196 else {
197 state.lower
198 };
199 Triplet(x, y, z)
200 }
201
202 fn vertex_with_position_count(&self) -> usize {
203 8
204 }
205}
206
207impl PositionPolygonGenerator for Cube {
208 type Output = Quad<Triplet<R64>>;
209
210 fn polygon_with_position_from(&self, state: &Self::State, index: usize) -> Self::Output {
211 self.index_for_position(index)
212 .map(|index| self.vertex_with_position_from(state, index))
213 }
214}
215
216impl PositionIndexGenerator for Cube {
217 type Output = Quad<usize>;
218
219 fn index_for_position(&self, index: usize) -> <Self as PositionIndexGenerator>::Output {
220 match index {
221 0 => Quad::new(5, 7, 3, 1), 1 => Quad::new(6, 7, 5, 4), 2 => Quad::new(3, 7, 6, 2), 3 => Quad::new(0, 1, 3, 2), 4 => Quad::new(4, 5, 1, 0), 5 => Quad::new(0, 2, 6, 4), _ => panic!(),
228 }
229 }
230}
231
232impl UvMapGenerator for Cube {
233 type State = ();
234}
235
236impl UvMapPolygonGenerator for Cube {
237 type Output = Quad<Duplet<R64>>;
238
239 fn polygon_with_uv_map_from(&self, _: &Self::State, index: usize) -> Self::Output {
240 let uu = Duplet::one();
241 let ul = Duplet(One::one(), Zero::zero());
242 let ll = Duplet::zero();
243 let lu = Duplet(Zero::zero(), One::one());
244 match index {
245 0 | 4 | 5 => Quad::new(uu, ul, ll, lu), 1 => Quad::new(ul, ll, lu, uu), 2 | 3 => Quad::new(lu, uu, ul, ll), _ => panic!(),
249 }
250 }
251}