use std::f32::consts::PI;
use cgmath::{InnerSpace, Vector3};
use super::generators::{IndexedPolygon, SharedVertex};
use super::{MapVertex, Quad, Vertex};
#[derive(Clone, Copy)]
pub struct Torus {
idx: usize,
radius: f32,
tubular_radius: f32,
radial_segments: usize,
tubular_segments: usize,
}
impl Torus {
pub fn new(
radius: f32,
tubular_radius: f32,
radial_segments: usize,
tubular_segments: usize,
) -> Self {
assert!(tubular_segments > 2 && radial_segments > 2);
Torus {
idx: 0,
radius,
tubular_radius,
radial_segments,
tubular_segments,
}
}
}
impl Iterator for Torus {
type Item = Quad<Vertex>;
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.indexed_polygon_count() {
let idx = self.idx;
self.idx += 1;
Some(
self.indexed_polygon(idx)
.map_vertex(|i| self.shared_vertex(i)),
)
} else {
None
}
}
}
impl SharedVertex<Vertex> for Torus {
fn shared_vertex(&self, idx: usize) -> Vertex {
let (h, u) = (
(idx / self.tubular_segments) as f32,
(idx % self.tubular_segments) as f32,
);
let alpha = u * 2. * PI / self.tubular_segments as f32;
let beta = h * 2. * PI / self.radial_segments as f32;
let gamma = self.radius + self.tubular_radius * alpha.cos();
Vertex {
pos: [
gamma * beta.cos(),
self.tubular_radius * alpha.sin(),
-gamma * beta.sin(),
].into(),
normal: Vector3::new(
alpha.cos() * beta.cos(),
alpha.sin(),
-alpha.cos() * beta.sin(),
).normalize()
.into(),
}
}
fn shared_vertex_count(&self) -> usize {
self.tubular_segments * self.radial_segments + 1
}
}
impl IndexedPolygon<Quad<usize>> for Torus {
fn indexed_polygon(&self, idx: usize) -> Quad<usize> {
let ncol = if self.indexed_polygon_count() - idx > self.tubular_segments {
self.tubular_segments as isize
} else {
-((self.indexed_polygon_count() - self.tubular_segments) as isize)
};
let nrow = if idx % self.tubular_segments != self.tubular_segments - 1 {
1isize
} else {
1isize - (self.tubular_segments as isize)
};
let idx = idx as isize;
Quad::new(idx, idx + ncol, idx + nrow + ncol, idx + nrow).map_vertex(|x| x as usize)
}
fn indexed_polygon_count(&self) -> usize {
self.tubular_segments * self.radial_segments
}
}