#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ExtrudedPolygon {
pub verts: Vec<[f32; 3]>,
pub tris: Vec<[u32; 3]>,
pub base_n: usize,
pub height: f32,
}
pub fn build_extruded_polygon(base: &[[f32; 2]], height: f32) -> ExtrudedPolygon {
let n = base.len();
if n < 3 {
return ExtrudedPolygon {
verts: vec![],
tris: vec![],
base_n: 0,
height: 0.0,
};
}
let mut verts = Vec::with_capacity(2 * n + 2);
for &[x, z] in base {
verts.push([x, 0.0, z]);
}
for &[x, z] in base {
verts.push([x, height, z]);
}
let bot_center = (2 * n) as u32;
let top_center = (2 * n + 1) as u32;
let mut cx = 0.0f32;
let mut cz = 0.0f32;
for &[x, z] in base {
cx += x;
cz += z;
}
cx /= n as f32;
cz /= n as f32;
verts.push([cx, 0.0, cz]);
verts.push([cx, height, cz]);
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, d]);
tris.push([a, d, c]);
}
for i in 0..n {
let next = (i + 1) % n;
tris.push([bot_center, next as u32, i as u32]);
}
for i in 0..n {
let next = (i + 1) % n;
tris.push([top_center, (n + i) as u32, (n + next) as u32]);
}
ExtrudedPolygon {
verts,
tris,
base_n: n,
height,
}
}
pub fn extruded_vertex_count(ep: &ExtrudedPolygon) -> usize {
ep.verts.len()
}
pub fn extruded_tri_count(ep: &ExtrudedPolygon) -> usize {
ep.tris.len()
}
pub fn validate_extruded_polygon(ep: &ExtrudedPolygon) -> bool {
let n = ep.verts.len() as u32;
ep.tris.iter().all(|t| t[0] < n && t[1] < n && t[2] < n)
}
pub fn lateral_area(ep: &ExtrudedPolygon) -> f32 {
let n = ep.base_n;
(0..n)
.map(|i| {
let a = ep.verts[i];
let b = ep.verts[(i + 1) % n];
let dx = b[0] - a[0];
let dz = b[2] - a[2];
(dx * dx + dz * dz).sqrt() * ep.height.abs()
})
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
fn square() -> Vec<[f32; 2]> {
vec![[1.0, 1.0], [-1.0, 1.0], [-1.0, -1.0], [1.0, -1.0]]
}
fn triangle() -> Vec<[f32; 2]> {
vec![[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0]]
}
#[test]
fn test_extruded_vertex_count_square() {
let ep = build_extruded_polygon(&square(), 1.0);
assert_eq!(extruded_vertex_count(&ep), 10);
}
#[test]
fn test_extruded_tri_count_square() {
let ep = build_extruded_polygon(&square(), 1.0);
assert_eq!(extruded_tri_count(&ep), 16);
}
#[test]
fn test_extruded_tri_count_triangle() {
let ep = build_extruded_polygon(&triangle(), 2.0);
assert_eq!(extruded_tri_count(&ep), 12);
}
#[test]
fn test_validate_extruded_polygon() {
let ep = build_extruded_polygon(&square(), 1.0);
assert!(validate_extruded_polygon(&ep));
}
#[test]
fn test_empty_on_too_few_verts() {
let ep = build_extruded_polygon(&[[0.0, 0.0], [1.0, 0.0]], 1.0);
assert_eq!(extruded_vertex_count(&ep), 0);
}
#[test]
fn test_lateral_area_square_unit() {
let ep = build_extruded_polygon(&square(), 1.0);
assert!((lateral_area(&ep) - 8.0).abs() < 1e-4);
}
#[test]
fn test_height_stored() {
let ep = build_extruded_polygon(&square(), 3.5);
assert!((ep.height - 3.5).abs() < 1e-6);
}
#[test]
fn test_base_n_stored() {
let ep = build_extruded_polygon(&triangle(), 1.0);
assert_eq!(ep.base_n, 3);
}
}