plexus/primitive/
cube.rs

1//! Cube primitives.
2//!
3//! # Examples
4//!
5//! ```rust
6//! # extern crate nalgebra;
7//! # extern crate plexus;
8//! use nalgebra::Point3;
9//! use plexus::graph::MeshGraph;
10//! use plexus::prelude::*;
11//! use plexus::primitive::cube::Cube;
12//! use plexus::primitive::index::HashIndexer;
13//!
14//! # fn main() {
15//! let graph = Cube::new()
16//!     .polygons_with_position()
17//!     .collect_with_indexer::<MeshGraph<Point3<f32>>, _>(HashIndexer::default())
18//!     .unwrap();
19//! # }
20//! ```
21
22use 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),   // front
49            Plane::NXY => Triplet(zero, one, zero),  // right
50            Plane::ZY => Triplet(-one, zero, zero),  // top
51            Plane::NZY => Triplet(zero, -one, zero), // left
52            Plane::XZ => Triplet(one, zero, zero),   // bottom
53            Plane::XNZ => Triplet(zero, zero, -one), // back
54        }
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,  // front
112            1 => Plane::NZY, // right
113            2 => Plane::XNZ, // top
114            3 => Plane::ZY,  // left
115            4 => Plane::XZ,  // bottom
116            5 => Plane::NXY, // back
117            _ => 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        // There is a unique normal for each face (plane).
147        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), // front
222            1 => Quad::new(6, 7, 5, 4), // right
223            2 => Quad::new(3, 7, 6, 2), // top
224            3 => Quad::new(0, 1, 3, 2), // left
225            4 => Quad::new(4, 5, 1, 0), // bottom
226            5 => Quad::new(0, 2, 6, 4), // back
227            _ => 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), // front | bottom | back
246            1 => Quad::new(ul, ll, lu, uu),         // right
247            2 | 3 => Quad::new(lu, uu, ul, ll),     // top | left
248            _ => panic!(),
249        }
250    }
251}