use cadrum::{Compound, DVec3, Edge, Error, ProfileOrient, Solid, Wire};
fn build_m2_screw() -> Result<Vec<Solid>, Error> {
let r = 1.0;
let h_pitch = 0.4;
let h_thread = 6.0;
let r_head = 1.75;
let h_head = 1.3;
let r_delta = 3f64.sqrt() / 2.0 * h_pitch;
let helix = Edge::helix(r - r_delta, h_pitch, h_thread, DVec3::Z, DVec3::X)?;
let profile = Edge::polygon(&[DVec3::new(0.0, -h_pitch / 2.0, 0.0), DVec3::new(r_delta, 0.0, 0.0), DVec3::new(0.0, h_pitch / 2.0, 0.0)])?;
let profile = profile.align_z(helix.start_tangent(), helix.start_point()).translate(helix.start_point());
let thread = Solid::sweep(&profile, &[helix], ProfileOrient::Up(DVec3::Z))?;
let shaft = Solid::cylinder(r - r_delta * 6.0 / 8.0, DVec3::Z, h_thread);
let crest = Solid::cylinder(r - r_delta / 8.0, DVec3::Z, h_thread);
let thread_shaft = thread.union([&shaft])?.intersect([&crest])?;
let head = Solid::cylinder(r_head, DVec3::Z, h_head).translate(DVec3::Z * h_thread);
Ok(thread_shaft.union([&head])?.color("red"))
}
fn build_u_pipe() -> Result<Vec<Solid>, Error> {
let pipe_radius = 0.4;
let leg_length = 6.0;
let gap = 3.0;
let half_gap = gap / 2.0;
let bend_radius = half_gap;
let a = DVec3::new(-half_gap, 0.0, 0.0);
let b = DVec3::new(-half_gap, 0.0, leg_length);
let arc_mid = DVec3::new(0.0, 0.0, leg_length + bend_radius);
let c = DVec3::new(half_gap, 0.0, leg_length);
let d = DVec3::new(half_gap, 0.0, 0.0);
let up_leg = Edge::line(a, b)?;
let bend = Edge::arc_3pts(b, arc_mid, c)?;
let down_leg = Edge::line(c, d)?;
let profile = Edge::circle(pipe_radius, DVec3::Z)?.translate(a);
let pipe = Solid::sweep(&[profile], &[up_leg, bend, down_leg], ProfileOrient::Up(DVec3::Y))?;
Ok(vec![pipe].translate(DVec3::X * 6.0).color("blue"))
}
fn build_twisted_ribbon() -> Result<Vec<Solid>, Error> {
let h = 8.0;
let aux_r = 3.0;
let spine = Edge::line(DVec3::ZERO, DVec3::Z * h)?;
let aux = Edge::helix(aux_r, h, h, DVec3::Z, DVec3::X)?;
let profile = Edge::polygon(&[DVec3::new(-2.0, -0.2, 0.0), DVec3::new(2.0, -0.2, 0.0), DVec3::new(2.0, 0.2, 0.0), DVec3::new(-2.0, 0.2, 0.0)])?;
let ribbon = Solid::sweep(&profile, &[spine], ProfileOrient::Auxiliary(&[aux]))?;
Ok(vec![ribbon].translate(DVec3::X * 12.0).color("green"))
}
fn main() -> Result<(), Error> {
let example_name = std::path::Path::new(file!()).file_stem().unwrap().to_str().unwrap();
let all: Vec<Solid> = [build_m2_screw()?, build_u_pipe()?, build_twisted_ribbon()?].concat();
let mut f = std::fs::File::create(format!("{example_name}.step")).expect("failed to create STEP file");
Solid::write_step(&all, &mut f)?;
let mut f_svg = std::fs::File::create(format!("{example_name}.svg")).expect("failed to create SVG file");
Solid::mesh(&all, 0.5)?.write_svg(DVec3::new(1.0, 1.0, -1.0), DVec3::Z, false, false, &mut f_svg)?;
println!("wrote {example_name}.step / {example_name}.svg ({} solids)", all.len());
Ok(())
}