use std::f64::consts::TAU;
use crate::ids::VertexId;
use crate::storage::{MeshStorage, Vertex};
use crate::topology_ops::add_triangle;
pub fn build_cube(size: f64) -> MeshStorage {
let h = size / 2.0;
let verts = vec![
[-h, -h, -h],
[h, -h, -h],
[h, h, -h],
[-h, h, -h],
[-h, -h, h],
[h, -h, h],
[h, h, h],
[-h, h, h],
];
let faces: Vec<[u32; 3]> = vec![
[0, 3, 2],
[0, 2, 1], [4, 5, 6],
[4, 6, 7], [0, 1, 5],
[0, 5, 4], [3, 7, 6],
[3, 6, 2], [0, 4, 7],
[0, 7, 3], [1, 2, 6],
[1, 6, 5], ];
crate::io::build_mesh_from_vertices_and_faces(&verts, &faces)
.expect("hardcoded valid cube mesh")
}
pub fn build_uv_sphere(radius: f64, slices: usize, stacks: usize) -> MeshStorage {
let slices = slices.max(3);
let stacks = stacks.max(2);
let mut mesh = MeshStorage::new();
let cap = (slices + 1) * (stacks + 1);
mesh.reserve(cap, cap * 6, slices * stacks * 2);
let mut v_ids: Vec<Vec<VertexId>> = Vec::with_capacity(stacks + 1);
for i in 0..=stacks {
let phi = std::f64::consts::PI * i as f64 / stacks as f64; let y = radius * phi.cos();
let r = radius * phi.sin();
let mut row = Vec::with_capacity(slices + 1);
for j in 0..=slices {
let theta = TAU * j as f64 / slices as f64;
let x = r * theta.cos();
let z = r * theta.sin();
row.push(mesh.add_vertex(Vertex::new([x, y, z])));
}
v_ids.push(row);
}
for i in 0..stacks {
for j in 0..slices {
let a = v_ids[i][j];
let b = v_ids[i][j + 1];
let c = v_ids[i + 1][j];
let d = v_ids[i + 1][j + 1];
add_triangle(&mut mesh, a, b, c).expect("图元构建不应失败");
add_triangle(&mut mesh, c, b, d).expect("图元构建不应失败");
}
}
mesh
}
pub fn build_cylinder(radius: f64, height: f64, slices: usize) -> MeshStorage {
let slices = slices.max(3);
let h = height / 2.0;
let mut mesh = MeshStorage::new();
mesh.reserve(slices * 2 + 2, slices * 12, slices * 4);
let top_c = mesh.add_vertex(Vertex::new([0.0, h, 0.0]));
let bot_c = mesh.add_vertex(Vertex::new([0.0, -h, 0.0]));
let mut top_ring = Vec::with_capacity(slices);
let mut bot_ring = Vec::with_capacity(slices);
for i in 0..slices {
let theta = TAU * i as f64 / slices as f64;
let x = radius * theta.cos();
let z = radius * theta.sin();
top_ring.push(mesh.add_vertex(Vertex::new([x, h, z])));
bot_ring.push(mesh.add_vertex(Vertex::new([x, -h, z])));
}
for i in 0..slices {
let j = (i + 1) % slices;
add_triangle(&mut mesh, top_ring[i], bot_ring[i], bot_ring[j]).expect("图元构建不应失败");
add_triangle(&mut mesh, top_ring[i], bot_ring[j], top_ring[j]).expect("图元构建不应失败");
add_triangle(&mut mesh, top_c, top_ring[j], top_ring[i]).expect("图元构建不应失败");
add_triangle(&mut mesh, bot_c, bot_ring[i], bot_ring[j]).expect("图元构建不应失败");
}
mesh
}
pub fn build_torus(
major_radius: f64,
minor_radius: f64,
major_segments: usize,
minor_segments: usize,
) -> MeshStorage {
let mj = major_segments.max(3);
let mn = minor_segments.max(3);
let mut mesh = MeshStorage::new();
mesh.reserve(mj * mn, mj * mn * 6, mj * mn * 2);
let mut rings: Vec<Vec<VertexId>> = Vec::with_capacity(mj);
for i in 0..mj {
let theta = TAU * i as f64 / mj as f64;
let _cx = major_radius * theta.cos();
let _cz = major_radius * theta.sin();
let mut ring = Vec::with_capacity(mn);
for j in 0..mn {
let phi = TAU * j as f64 / mn as f64;
let r = major_radius + minor_radius * phi.cos();
let x = r * theta.cos();
let z = r * theta.sin();
let y = minor_radius * phi.sin();
ring.push(mesh.add_vertex(Vertex::new([x, y, z])));
}
rings.push(ring);
}
for i in 0..mj {
let ni = (i + 1) % mj;
for j in 0..mn {
let nj = (j + 1) % mn;
let a = rings[i][j];
let b = rings[ni][j];
let c = rings[ni][nj];
let d = rings[i][nj];
add_triangle(&mut mesh, a, b, c).expect("图元构建不应失败");
add_triangle(&mut mesh, a, c, d).expect("图元构建不应失败");
}
}
mesh
}
pub fn build_cone(radius: f64, height: f64, slices: usize) -> MeshStorage {
let slices = slices.max(3);
let h = height / 2.0;
let mut mesh = MeshStorage::new();
mesh.reserve(slices + 2, slices * 6, slices * 2);
let apex = mesh.add_vertex(Vertex::new([0.0, h, 0.0]));
let base_c = mesh.add_vertex(Vertex::new([0.0, -h, 0.0]));
let mut ring = Vec::with_capacity(slices);
for i in 0..slices {
let theta = TAU * i as f64 / slices as f64;
ring.push(mesh.add_vertex(Vertex::new([
radius * theta.cos(),
-h,
radius * theta.sin(),
])));
}
for i in 0..slices {
let j = (i + 1) % slices;
add_triangle(&mut mesh, apex, ring[j], ring[i]).expect("图元构建不应失败");
add_triangle(&mut mesh, base_c, ring[i], ring[j]).expect("图元构建不应失败");
}
mesh
}
pub fn build_grid(width: f64, depth: f64, segments_x: usize, segments_z: usize) -> MeshStorage {
let sx = segments_x.max(1);
let sz = segments_z.max(1);
let mut mesh = MeshStorage::new();
let nv = (sx + 1) * (sz + 1);
mesh.reserve(nv, sx * sz * 6, sx * sz * 2);
let mut v_ids: Vec<Vec<VertexId>> = Vec::with_capacity(sz + 1);
for iz in 0..=sz {
let z = -depth / 2.0 + depth * iz as f64 / sz as f64;
let mut row = Vec::with_capacity(sx + 1);
for ix in 0..=sx {
let x = -width / 2.0 + width * ix as f64 / sx as f64;
row.push(mesh.add_vertex(Vertex::new([x, 0.0, z])));
}
v_ids.push(row);
}
for iz in 0..sz {
for ix in 0..sx {
let a = v_ids[iz][ix];
let b = v_ids[iz][ix + 1];
let c = v_ids[iz + 1][ix];
let d = v_ids[iz + 1][ix + 1];
add_triangle(&mut mesh, a, b, c).expect("图元构建不应失败");
add_triangle(&mut mesh, c, b, d).expect("图元构建不应失败");
}
}
mesh
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cube_is_closed() {
let cube = build_cube(2.0);
assert_eq!(cube.vertex_count(), 8);
assert_eq!(cube.face_count(), 12);
crate::topology_ops::validate_mesh(&cube).unwrap();
}
#[test]
fn uv_sphere_is_closed() {
let sphere = build_uv_sphere(1.0, 16, 8);
assert!(sphere.face_count() > 0);
crate::topology_ops::validate_mesh(&sphere).unwrap();
}
#[test]
fn cylinder_counts() {
let cyl = build_cylinder(1.0, 2.0, 16);
assert_eq!(cyl.vertex_count(), 34); assert_eq!(cyl.face_count(), 64); crate::topology_ops::validate_mesh(&cyl).unwrap();
}
#[test]
fn torus_counts() {
let torus = build_torus(2.0, 0.5, 16, 8);
assert_eq!(torus.vertex_count(), 128);
assert_eq!(torus.face_count(), 256);
crate::topology_ops::validate_mesh(&torus).unwrap();
}
#[test]
fn cone_counts() {
let cone = build_cone(1.0, 2.0, 16);
assert_eq!(cone.vertex_count(), 18);
assert_eq!(cone.face_count(), 32);
crate::topology_ops::validate_mesh(&cone).unwrap();
}
#[test]
fn grid_counts() {
let grid = build_grid(2.0, 2.0, 4, 4);
assert_eq!(grid.vertex_count(), 25); assert_eq!(grid.face_count(), 32); }
#[test]
fn primitives_pass_validation() {
for mesh in [
build_cube(1.0),
build_uv_sphere(1.0, 8, 4),
build_cylinder(0.5, 1.0, 8),
build_torus(2.0, 0.3, 8, 4),
build_cone(1.0, 1.0, 8),
build_grid(1.0, 1.0, 2, 2),
] {
crate::topology_ops::validate_mesh(&mesh).unwrap();
}
}
}