#![allow(dead_code)]
use std::f32::consts::TAU;
#[derive(Debug, Clone)]
pub struct Antiprism {
pub verts: Vec<[f32; 3]>,
pub tris: Vec<[u32; 3]>,
pub sides: usize,
}
pub fn build_antiprism(sides: usize, r_bot: f32, r_top: f32, height: f32) -> Antiprism {
if sides < 3 {
return Antiprism {
verts: vec![],
tris: vec![],
sides: 0,
};
}
let n = sides;
let offset = TAU / (2.0 * n as f32);
let mut verts = Vec::with_capacity(2 * n + 2);
for i in 0..n {
let a = TAU * i as f32 / n as f32;
verts.push([r_bot * a.cos(), 0.0, r_bot * a.sin()]);
}
for i in 0..n {
let a = TAU * i as f32 / n as f32 + offset;
verts.push([r_top * a.cos(), height, r_top * a.sin()]);
}
let bot_c = (2 * n) as u32;
let top_c = (2 * n + 1) as u32;
verts.push([0.0, 0.0, 0.0]);
verts.push([0.0, height, 0.0]);
let mut tris = Vec::new();
for i in 0..n {
let next = (i + 1) % n;
let a = i as u32;
let b = next as u32;
let c = (n + i) as u32;
let d = (n + next) as u32;
tris.push([a, b, c]);
tris.push([b, d, c]);
}
for i in 0..n {
tris.push([bot_c, ((i + 1) % n) as u32, i as u32]);
}
for i in 0..n {
tris.push([top_c, (n + i) as u32, (n + (i + 1) % n) as u32]);
}
Antiprism {
verts,
tris,
sides: n,
}
}
pub fn antiprism_vertex_count(a: &Antiprism) -> usize {
a.verts.len()
}
pub fn antiprism_tri_count(a: &Antiprism) -> usize {
a.tris.len()
}
pub fn validate_antiprism(a: &Antiprism) -> bool {
let n = a.verts.len() as u32;
a.tris.iter().all(|t| t[0] < n && t[1] < n && t[2] < n)
}
pub fn antiprism_expected_tris(sides: usize) -> usize {
4 * sides
}
pub fn has_alternating_strip(a: &Antiprism) -> bool {
!a.tris.is_empty()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_antiprism_vertex_count() {
let a = build_antiprism(5, 1.0, 1.0, 1.0);
assert_eq!(antiprism_vertex_count(&a), 12);
}
#[test]
fn test_antiprism_tri_count() {
let a = build_antiprism(5, 1.0, 1.0, 1.0);
assert_eq!(antiprism_tri_count(&a), 20);
}
#[test]
fn test_antiprism_expected_tris() {
assert_eq!(antiprism_expected_tris(5), 20);
}
#[test]
fn test_validate_antiprism() {
let a = build_antiprism(6, 1.0, 0.5, 2.0);
assert!(validate_antiprism(&a));
}
#[test]
fn test_antiprism_empty_on_too_few_sides() {
let a = build_antiprism(2, 1.0, 1.0, 1.0);
assert_eq!(antiprism_vertex_count(&a), 0);
}
#[test]
fn test_antiprism_sides_stored() {
let a = build_antiprism(8, 1.0, 1.0, 1.0);
assert_eq!(a.sides, 8);
}
#[test]
fn test_antiprism_triangular() {
let a = build_antiprism(3, 1.0, 1.0, 1.0);
assert_eq!(antiprism_tri_count(&a), 12);
}
#[test]
fn test_has_alternating_strip() {
let a = build_antiprism(4, 1.0, 1.0, 1.0);
assert!(has_alternating_strip(&a));
}
#[test]
fn test_antiprism_square() {
let a = build_antiprism(4, 1.0, 1.0, 1.0);
assert_eq!(antiprism_vertex_count(&a), 10);
}
}