use std::f32::consts::{self, FRAC_1_SQRT_2};
use super::generators::{IndexedPolygon, SharedVertex};
use super::{MapVertex, Triangle, Vertex};
const TWO_PI: f32 = consts::PI * 2.;
#[derive(Debug)]
enum VertexSection {
Tip(usize),
TopRadius(usize),
BottomRadius(usize),
BottomCenter,
}
pub struct Cone {
u: usize,
sub_u: usize,
}
impl Cone {
pub fn new(u: usize) -> Self {
assert!(u >= 2);
Cone { u: 0, sub_u: u }
}
fn vertex(&self, sec: VertexSection) -> Vertex {
let divisions = TWO_PI / self.sub_u as f32;
match sec {
VertexSection::Tip(i) => {
let pos = divisions * i as f32 + divisions / 2.;
Vertex {
pos: [0., 0., 1.].into(),
normal: [
pos.cos() * FRAC_1_SQRT_2,
pos.sin() * FRAC_1_SQRT_2,
-FRAC_1_SQRT_2,
].into(),
}
}
VertexSection::TopRadius(i) => {
let pos = divisions * i as f32;
Vertex {
pos: [pos.cos(), pos.sin(), -1.].into(),
normal: [
pos.cos() * FRAC_1_SQRT_2,
pos.sin() * FRAC_1_SQRT_2,
-FRAC_1_SQRT_2,
].into(),
}
}
VertexSection::BottomRadius(i) => {
let pos = divisions * i as f32;
Vertex {
pos: [pos.cos(), pos.sin(), -1.].into(),
normal: [0., 0., -1.].into(),
}
}
VertexSection::BottomCenter => Vertex {
pos: [0., 0., -1.].into(),
normal: [0., 0., -1.].into(),
},
}
}
fn index(&self, sec: VertexSection) -> usize {
match sec {
VertexSection::Tip(i) => i,
VertexSection::TopRadius(i) => i + self.sub_u,
VertexSection::BottomRadius(i) => i + self.sub_u * 2,
VertexSection::BottomCenter => self.sub_u * 3,
}
}
fn rev_index(&self, idx: usize) -> VertexSection {
if idx < self.sub_u {
VertexSection::Tip(idx)
} else if idx < self.sub_u * 2 {
VertexSection::TopRadius(idx - self.sub_u)
} else if idx < self.sub_u * 3 {
VertexSection::BottomRadius(idx - self.sub_u * 2)
} else {
VertexSection::BottomCenter
}
}
}
impl Iterator for Cone {
type Item = Triangle<Vertex>;
fn next(&mut self) -> Option<Self::Item> {
if self.u < self.sub_u * 2 {
let idx = self.u;
self.u += 1;
Some(
self.indexed_polygon(idx)
.map_vertex(|i| self.shared_vertex(i)),
)
} else {
None
}
}
}
impl SharedVertex<Vertex> for Cone {
fn shared_vertex(&self, idx: usize) -> Vertex {
self.vertex(self.rev_index(idx))
}
fn shared_vertex_count(&self) -> usize {
self.sub_u * 3 + 1
}
}
impl IndexedPolygon<Triangle<usize>> for Cone {
fn indexed_polygon(&self, idx: usize) -> Triangle<usize> {
if idx < self.sub_u {
let next = if idx != self.sub_u - 1 { idx + 1 } else { 0 };
Triangle::new(
self.index(VertexSection::Tip(idx)),
self.index(VertexSection::TopRadius(idx)),
self.index(VertexSection::TopRadius(next)),
)
} else {
let idx = idx - self.sub_u;
let next = if idx != self.sub_u - 1 { idx + 1 } else { 0 };
Triangle::new(
self.index(VertexSection::BottomCenter),
self.index(VertexSection::BottomRadius(next)),
self.index(VertexSection::BottomRadius(idx)),
)
}
}
fn indexed_polygon_count(&self) -> usize {
self.sub_u * 2
}
}