1use super::generators::{IndexedPolygon, SharedVertex};
2use super::{Polygon, Quad, Triangle};
3use std::f32::consts::PI;
4use {Normal, Position, Vertex};
5
6#[derive(Clone, Copy)]
9pub struct Cylinder {
10 u: usize,
11 h: isize,
12 sub_u: usize,
13 sub_h: isize,
14}
15
16const TOP: Vertex = Vertex {
17 pos: Position {
18 x: 0.,
19 y: 0.,
20 z: 1.,
21 },
22 normal: Normal {
23 x: 0.,
24 y: 0.,
25 z: 1.,
26 },
27};
28
29const BOT: Vertex = Vertex {
30 pos: Position {
31 x: 0.,
32 y: 0.,
33 z: -1.,
34 },
35 normal: Normal {
36 x: 0.,
37 y: 0.,
38 z: -1.,
39 },
40};
41
42impl Cylinder {
43 pub fn new(u: usize) -> Self {
46 assert!(u > 1);
47 Cylinder {
48 u: 0,
49 h: -1,
50 sub_u: u,
51 sub_h: 1,
52 }
53 }
54
55 pub fn subdivide(u: usize, h: usize) -> Self {
59 assert!(u > 1 && h > 0);
60 Cylinder {
61 u: 0,
62 h: -1,
63 sub_u: u,
64 sub_h: h as isize,
65 }
66 }
67
68 fn vert(&self, u: usize, h: isize) -> Vertex {
69 debug_assert!(u <= self.sub_u);
70 let a = (u as f32 / self.sub_u as f32) * PI * 2.;
71 let n = [a.cos(), a.sin(), 0.];
72 let (hc, normal) = if h < 0 {
73 debug_assert_eq!(h, -1);
74 (0, [0., 0., -1.])
75 } else if h > self.sub_h {
76 debug_assert_eq!(h, self.sub_h + 1);
77 (self.sub_h, [0., 0., 1.])
78 } else {
79 (h, n)
80 };
81 let z = (hc as f32 / self.sub_h as f32) * 2. - 1.;
82 Vertex {
83 pos: [n[0], n[1], z].into(),
84 normal: normal.into(),
85 }
86 }
87}
88
89impl Iterator for Cylinder {
90 type Item = Polygon<Vertex>;
91
92 fn next(&mut self) -> Option<Self::Item> {
93 if self.u == self.sub_u {
94 if self.h >= self.sub_h {
95 return None;
96 }
97 self.u = 0;
98 self.h += 1;
99 }
100
101 let u = self.u;
102 self.u += 1;
103 let u1 = self.u % self.sub_u;
106
107 Some(if self.h < 0 {
108 let x = self.vert(u, self.h);
109 let y = self.vert(u1, self.h);
110 Polygon::PolyTri(Triangle::new(x, BOT, y))
111 } else if self.h == self.sub_h {
112 let x = self.vert(u, self.h + 1);
113 let y = self.vert(u1, self.h + 1);
114 Polygon::PolyTri(Triangle::new(x, y, TOP))
115 } else {
116 let x = self.vert(u, self.h);
117 let y = self.vert(u1, self.h);
118 let z = self.vert(u1, self.h + 1);
119 let w = self.vert(u, self.h + 1);
120 Polygon::PolyQuad(Quad::new(x, y, z, w))
121 })
122 }
123
124 fn size_hint(&self) -> (usize, Option<usize>) {
125 let n = self.sub_u * (1 + self.sub_h - self.h) as usize - self.u;
126 (n, Some(n))
127 }
128}
129
130impl SharedVertex<Vertex> for Cylinder {
131 fn shared_vertex(&self, idx: usize) -> Vertex {
132 if idx == 0 {
133 BOT
134 } else if idx == self.shared_vertex_count() - 1 {
135 TOP
136 } else {
137 let idx = idx - 1;
139 let u = idx % self.sub_u;
140 let h = (idx / self.sub_u) as isize - 1;
141 self.vert(u, h)
142 }
143 }
144
145 fn shared_vertex_count(&self) -> usize {
146 (3 + self.sub_h) as usize * self.sub_u + 2
147 }
148}
149
150impl IndexedPolygon<Polygon<usize>> for Cylinder {
151 fn indexed_polygon(&self, idx: usize) -> Polygon<usize> {
152 let u = idx % self.sub_u;
153 let u1 = (idx + 1) % self.sub_u;
154 let h = (idx / self.sub_u) as isize - 1;
155 let base = 1 + idx - u;
156 if h < 0 {
157 let start = 0;
158 Polygon::PolyTri(Triangle::new(base + u, start, base + u1))
159 } else if h == self.sub_h {
160 let base = base + self.sub_u;
163 let end = self.shared_vertex_count() - 1;
164 Polygon::PolyTri(Triangle::new(base + u, base + u1, end))
165 } else {
166 Polygon::PolyQuad(Quad::new(
167 base + u,
168 base + u1,
169 base + u1 + self.sub_u,
170 base + u + self.sub_u,
171 ))
172 }
173 }
174
175 fn indexed_polygon_count(&self) -> usize {
176 (2 + self.sub_h) as usize * self.sub_u
177 }
178}