use cadrum::{Boolean, Error, Shape, Solid};
use glam::DVec3;
use std::path::Path;
fn extrude_tool_faces(result: &Boolean, delta: DVec3) -> Result<Vec<Solid>, Error> {
let mut filler: Option<Vec<Solid>> = None;
for face in result.solids.faces().filter(|f| result.is_tool_face(f)) {
let extruded: Vec<Solid> = vec![face.extrude(delta)?];
filler = Some(match filler {
None => extruded,
Some(f) => cadrum::Boolean::union(&f, &extruded)?.into(),
});
}
Ok(filler.unwrap_or_default())
}
fn stretch_vector(shape: &[Solid], origin: DVec3, delta: DVec3) -> Result<Vec<Solid>, Error> {
let half: Vec<Solid> = vec![Solid::half_space(origin, -delta.normalize())];
let intersect_result = cadrum::Boolean::intersect(&shape, &half)?;
let part_pos: Vec<Solid> = cadrum::Boolean::subtract(&shape, &half)?.into();
let part_pos = part_pos.translate(delta);
let filler = extrude_tool_faces(&intersect_result, delta)?;
let part_neg: Vec<Solid> = intersect_result.into();
let combined: Vec<Solid> = cadrum::Boolean::union(&part_neg, &filler)?.into();
cadrum::Boolean::union(&combined, &part_pos).map(Vec::from)
}
fn stretch(shape: Vec<Solid>, cx: f64, cy: f64, cz: f64, dx: f64, dy: f64, dz: f64) -> Result<Vec<Solid>, Error> {
let eps = 1e-10;
let shape = if dx > eps { stretch_vector(&shape, DVec3::new(cx, 0.0, 0.0), DVec3::new(dx, 0.0, 0.0))? } else { shape };
let shape = if dy > eps { stretch_vector(&shape, DVec3::new(0.0, cy, 0.0), DVec3::new(0.0, dy, 0.0))? } else { shape };
let shape = if dz > eps { stretch_vector(&shape, DVec3::new(0.0, 0.0, cz), DVec3::new(0.0, 0.0, dz))? } else { shape };
shape.clean()
}
fn main() {
let radius = 20.0_f64;
let height = 80.0_f64;
let base = DVec3::ZERO;
let cylinder: Vec<Solid> = vec![Solid::cylinder(base, radius, DVec3::Z, height)];
let center = DVec3::new(0.0, 0.0, height / 2.0);
let (dx, dy, dz) = (30.0, 20.0, 40.0);
println!(
"シリンダー: 底面中心={base:?}, 半径={radius}mm, 高さ={height}mm"
);
println!(
"切断位置: {center:?} / 伸縮量: X={dx}mm Y={dy}mm Z={dz}mm"
);
let result = stretch(cylinder, center.x, center.y, center.z, dx, dy, dz)
.expect("ストレッチに失敗");
let out_path = "out/stretched.brep";
std::fs::create_dir_all(Path::new(out_path).parent().unwrap()).unwrap();
let mut buf = Vec::new();
cadrum::write_brep_text(&result, &mut buf)
.expect("BRep 書き込みに失敗");
std::fs::write(out_path, &buf).expect("ファイル書き込みに失敗");
let mesh = result
.mesh_with_tolerance(0.5)
.expect("メッシュ生成に失敗");
println!(
"完了: {out_path} ({} bytes) — 頂点数: {}, 三角形数: {}",
buf.len(),
mesh.vertices.len(),
mesh.indices.len() / 3,
);
}