#![allow(dead_code)]
use std::f32::consts::PI;
#[allow(dead_code)]
pub fn cylinder_vert_count(segs: u32, capped: bool) -> usize {
if capped {
(2 * segs + 2) as usize
} else {
(2 * segs) as usize
}
}
#[allow(dead_code)]
pub fn cylinder_surface_area(radius: f32, height: f32) -> f32 {
2.0 * PI * radius * (height + radius)
}
#[allow(dead_code)]
pub fn cylinder_volume(radius: f32, height: f32) -> f32 {
PI * radius * radius * height
}
#[allow(dead_code)]
pub fn make_cylinder(
radius: f32,
height: f32,
segments: u32,
capped: bool,
) -> (Vec<[f32; 3]>, Vec<[u32; 3]>) {
if segments < 3 {
return (vec![], vec![]);
}
let mut verts: Vec<[f32; 3]> = Vec::new();
let half_h = height * 0.5;
for i in 0..segments {
let angle = 2.0 * PI * i as f32 / segments as f32;
verts.push([radius * angle.cos(), -half_h, radius * angle.sin()]);
}
for i in 0..segments {
let angle = 2.0 * PI * i as f32 / segments as f32;
verts.push([radius * angle.cos(), half_h, radius * angle.sin()]);
}
let mut tris: Vec<[u32; 3]> = Vec::new();
for i in 0..segments {
let next_i = (i + 1) % segments;
let a = i;
let b = next_i;
let c = segments + i;
let d = segments + next_i;
tris.push([a, b, c]);
tris.push([b, d, c]);
}
if capped {
let bottom_center_idx = verts.len() as u32;
verts.push([0.0, -half_h, 0.0]);
let top_center_idx = verts.len() as u32;
verts.push([0.0, half_h, 0.0]);
for i in 0..segments {
let next_i = (i + 1) % segments;
tris.push([bottom_center_idx, next_i, i]);
tris.push([top_center_idx, segments + i, segments + next_i]);
}
}
(verts, tris)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vert_count_uncapped() {
assert_eq!(cylinder_vert_count(8, false), 16);
}
#[test]
fn test_vert_count_capped() {
assert_eq!(cylinder_vert_count(8, true), 18);
}
#[test]
fn test_make_cylinder_uncapped_verts() {
let (verts, _) = make_cylinder(1.0, 2.0, 8, false);
assert_eq!(verts.len(), 16);
}
#[test]
fn test_make_cylinder_capped_verts() {
let (verts, _) = make_cylinder(1.0, 2.0, 8, true);
assert_eq!(verts.len(), 18);
}
#[test]
fn test_make_cylinder_few_segs() {
let (verts, tris) = make_cylinder(1.0, 2.0, 2, false);
assert!(verts.is_empty());
assert!(tris.is_empty());
}
#[test]
fn test_surface_area_positive() {
let area = cylinder_surface_area(1.0, 2.0);
assert!(area > 0.0);
}
#[test]
fn test_volume_formula() {
let vol = cylinder_volume(1.0, 1.0);
assert!((vol - PI).abs() < 1e-4);
}
#[test]
fn test_indices_in_range() {
let (verts, tris) = make_cylinder(1.0, 2.0, 10, true);
let nv = verts.len() as u32;
for tri in &tris {
assert!(tri[0] < nv);
assert!(tri[1] < nv);
assert!(tri[2] < nv);
}
}
#[test]
fn test_uncapped_tri_count() {
let (_, tris) = make_cylinder(1.0, 2.0, 8, false);
assert_eq!(tris.len(), 16);
}
#[test]
fn test_capped_tri_count() {
let (_, tris) = make_cylinder(1.0, 2.0, 8, true);
assert_eq!(tris.len(), 32);
}
}