//! Abutment geometry — PureRustKernel. //! Breast wall + footing + wing walls (simplified rectangular shapes). use cimery_ir::AbutmentIR; use crate::{KernelError, Mesh, sweep}; pub fn build_abutment_mesh(ir: &AbutmentIR) -> Result { if ir.breast_wall_height <= 0.0 { return Err(KernelError::InvalidInput( format!("breast_wall_height must be > 0, got {}", ir.breast_wall_height), )); } let bw_h = ir.breast_wall_height as f32; let bw_t = ir.breast_wall_thickness as f32; let bw_w = ir.breast_wall_width as f32; let ft_l = ir.footing_length as f32; let ft_w = ir.footing_width as f32; let ft_t = ir.footing_thickness as f32; let mut parts: Vec = Vec::new(); // Breast wall: along transverse (Z), thickness along span (X), height (Y) parts.push(sweep::centred_box(0.0, bw_h * 0.5, bw_t * 0.5, bw_h * 0.5, bw_w)); // Footing: below grade, spans along X (span direction) { let profile = vec![ [-ft_l * 0.5, -ft_t], [ ft_l * 0.5, -ft_t], [ ft_l * 0.5, 0.0 ], [-ft_l * 0.5, 0.0 ], ]; parts.push(sweep::sweep_profile_flat(&profile, ft_w)); } // Wing walls (left and right) for side in [&ir.wing_wall_left, &ir.wing_wall_right] { let wl = side.length as f32; let wh = side.height as f32; let wt = side.thickness as f32; // Simplified: vertical rectangle, oriented in XY, length along Z parts.push(sweep::centred_box(0.0, wh * 0.5, wt * 0.5, wh * 0.5, wl)); } Ok(sweep::merge_meshes(parts)) } #[cfg(test)] mod tests { use super::*; use cimery_core::{AbutmentType, MaterialGrade}; use cimery_ir::{AbutmentIR, FeatureId, WingWallIR}; fn test_ir() -> AbutmentIR { let wing = WingWallIR { length: 4000.0, height: 3000.0, thickness: 500.0 }; AbutmentIR { id: FeatureId::new(), station: 0.0, skew_angle: 0.0, abutment_type: AbutmentType::ReverseT, breast_wall_height: 5000.0, breast_wall_thickness: 800.0, breast_wall_width: 12000.0, footing_length: 4000.0, footing_width: 13000.0, footing_thickness: 1000.0, wing_wall_left: wing.clone(), wing_wall_right: wing, material: MaterialGrade::C40, } } #[test] fn produces_mesh() { let mesh = build_abutment_mesh(&test_ir()).unwrap(); assert!(mesh.triangle_count() > 0); } #[test] fn zero_height_fails() { let mut ir = test_ir(); ir.breast_wall_height = 0.0; assert!(build_abutment_mesh(&ir).is_err()); } }