#![allow(clippy::unwrap_used, clippy::expect_used)]
use brepkit_math::mat::Mat4;
use brepkit_math::vec::{Point3, Vec3};
use brepkit_topology::Topology;
use brepkit_topology::face::FaceSurface;
fn face_normal(topo: &Topology, face: brepkit_topology::face::FaceId) -> Vec3 {
match topo.face(face).unwrap().surface() {
FaceSurface::Plane { normal, .. } => *normal,
_ => Vec3::new(0.0, 0.0, 0.0),
}
}
#[test]
fn example_box_with_fillet() {
let mut topo = Topology::new();
let solid = brepkit_operations::primitives::make_box(&mut topo, 20.0, 10.0, 5.0).unwrap();
let edges = brepkit_topology::explorer::solid_edges(&topo, solid).unwrap();
#[allow(deprecated)]
let filleted =
brepkit_operations::fillet::fillet_rolling_ball(&mut topo, solid, &edges, 1.0).unwrap();
let shell = topo.solid(filleted).unwrap().outer_shell();
let face_count = topo.shell(shell).unwrap().faces().len();
assert!(
face_count > 6,
"filleted box should have more than 6 faces, got {face_count}"
);
}
#[test]
fn example_gridfinity_bin() {
let mut topo = Topology::new();
let solid = brepkit_operations::primitives::make_box(&mut topo, 42.0, 42.0, 21.0).unwrap();
let shell_id = topo.solid(solid).unwrap().outer_shell();
let faces: Vec<_> = topo.shell(shell_id).unwrap().faces().to_vec();
let top_face = faces
.iter()
.copied()
.max_by(|&a, &b| {
let na = face_normal(&topo, a);
let nb = face_normal(&topo, b);
na.z().partial_cmp(&nb.z()).unwrap()
})
.unwrap();
let hollowed = brepkit_operations::shell_op::shell(&mut topo, solid, 1.5, &[top_face]).unwrap();
let bottom_edges = brepkit_topology::explorer::solid_edges(&topo, hollowed).unwrap();
let _chamfered =
brepkit_operations::chamfer::chamfer(&mut topo, hollowed, &bottom_edges[..4], 0.8).unwrap();
let vol = brepkit_operations::measure::solid_volume(&topo, hollowed, 0.1).unwrap();
assert!(vol > 0.0, "bin should have positive volume");
}
#[test]
fn example_boolean_operations() {
use brepkit_operations::boolean::{BooleanOp, boolean};
let mut topo = Topology::new();
let box_a = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 10.0).unwrap();
let box_b = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 10.0).unwrap();
let translate = Mat4::translation(5.0, 5.0, 5.0);
brepkit_operations::transform::transform_solid(&mut topo, box_b, &translate).unwrap();
let fused = boolean(&mut topo, BooleanOp::Fuse, box_a, box_b).unwrap();
let fused_vol = brepkit_operations::measure::solid_volume(&topo, fused, 0.1).unwrap();
assert!(
(fused_vol - 1875.0).abs() < 10.0,
"fused volume should be ~1875, got {fused_vol}"
);
let box_a2 = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 10.0).unwrap();
let box_b2 = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 10.0).unwrap();
brepkit_operations::transform::transform_solid(&mut topo, box_b2, &translate).unwrap();
let cut = boolean(&mut topo, BooleanOp::Cut, box_a2, box_b2).unwrap();
let cut_vol = brepkit_operations::measure::solid_volume(&topo, cut, 0.1).unwrap();
assert!(
(cut_vol - 875.0).abs() < 10.0,
"cut volume should be ~875, got {cut_vol}"
);
}
#[test]
fn example_extrude_profile() {
let mut topo = Topology::new();
let profile_box = brepkit_operations::primitives::make_box(&mut topo, 2.0, 2.0, 0.1).unwrap();
let shell_id = topo.solid(profile_box).unwrap().outer_shell();
let faces: Vec<_> = topo.shell(shell_id).unwrap().faces().to_vec();
let bottom_face = faces
.iter()
.copied()
.min_by(|&a, &b| {
let na = face_normal(&topo, a);
let nb = face_normal(&topo, b);
na.z().partial_cmp(&nb.z()).unwrap()
})
.unwrap();
let extruded = brepkit_operations::extrude::extrude(
&mut topo,
bottom_face,
Vec3::new(0.0, 0.0, 1.0),
10.0,
)
.unwrap();
let vol = brepkit_operations::measure::solid_volume(&topo, extruded, 0.1).unwrap();
assert!(
(vol - 40.0).abs() < 1.0,
"extruded volume should be ~40, got {vol}"
);
}
#[test]
fn example_validate_and_heal() {
let mut topo = Topology::new();
let solid = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 10.0).unwrap();
let report = brepkit_operations::validate::validate_solid(&topo, solid).unwrap();
assert!(
report.issues.is_empty(),
"fresh box should have no validation errors"
);
let repair = brepkit_operations::heal::repair_solid(&mut topo, solid, 1e-7).unwrap();
assert!(
repair.after.issues.is_empty(),
"repaired box should still have no errors"
);
}
#[test]
fn example_linear_and_circular_pattern() {
let mut topo = Topology::new();
let cyl = brepkit_operations::primitives::make_cylinder(&mut topo, 2.0, 5.0).unwrap();
let row = brepkit_operations::pattern::linear_pattern(
&mut topo,
cyl,
Vec3::new(1.0, 0.0, 0.0),
10.0, 5, )
.unwrap();
let count = topo.compound(row).unwrap().solids().len();
assert_eq!(count, 5, "linear pattern should have 5 copies");
let pin = brepkit_operations::primitives::make_cylinder(&mut topo, 1.0, 3.0).unwrap();
let offset = Mat4::translation(10.0, 0.0, 0.0);
brepkit_operations::transform::transform_solid(&mut topo, pin, &offset).unwrap();
let ring = brepkit_operations::pattern::circular_pattern(
&mut topo,
pin,
Vec3::new(0.0, 0.0, 1.0),
6, )
.unwrap();
let ring_count = topo.compound(ring).unwrap().solids().len();
assert_eq!(ring_count, 6, "circular pattern should have 6 copies");
}
#[test]
fn example_measurement() {
let mut topo = Topology::new();
let solid = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 10.0).unwrap();
let volume = brepkit_operations::measure::solid_volume(&topo, solid, 0.1).unwrap();
assert!(
(volume - 1000.0).abs() < 1.0,
"box volume should be ~1000, got {volume}"
);
let com = brepkit_operations::measure::solid_center_of_mass(&topo, solid, 0.1).unwrap();
assert!(
(com.x() - 5.0).abs() < 0.1,
"CoM x should be ~5, got {}",
com.x()
);
assert!(
(com.y() - 5.0).abs() < 0.1,
"CoM y should be ~5, got {}",
com.y()
);
assert!(
(com.z() - 5.0).abs() < 0.1,
"CoM z should be ~5, got {}",
com.z()
);
}
#[test]
fn example_transform_and_mirror() {
let mut topo = Topology::new();
let solid = brepkit_operations::primitives::make_box(&mut topo, 10.0, 5.0, 3.0).unwrap();
let translate = Mat4::translation(100.0, 0.0, 0.0);
brepkit_operations::transform::transform_solid(&mut topo, solid, &translate).unwrap();
let com = brepkit_operations::measure::solid_center_of_mass(&topo, solid, 0.1).unwrap();
assert!(
(com.x() - 105.0).abs() < 0.5,
"translated CoM x should be ~105, got {}",
com.x()
);
let mirrored = brepkit_operations::mirror::mirror(
&mut topo,
solid,
Point3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
)
.unwrap();
let mirror_com =
brepkit_operations::measure::solid_center_of_mass(&topo, mirrored, 0.1).unwrap();
assert!(
(mirror_com.x() + 105.0).abs() < 0.5,
"mirrored CoM x should be ~-105, got {}",
mirror_com.x()
);
}
#[test]
fn example_multi_solid_assembly() {
let mut topo = Topology::new();
let base = brepkit_operations::primitives::make_box(&mut topo, 100.0, 100.0, 5.0).unwrap();
let mut posts = Vec::new();
for (dx, dy) in [(5.0, 5.0), (85.0, 5.0), (5.0, 85.0), (85.0, 85.0)] {
let post = brepkit_operations::primitives::make_cylinder(&mut topo, 3.0, 30.0).unwrap();
let t = Mat4::translation(dx, dy, 5.0);
brepkit_operations::transform::transform_solid(&mut topo, post, &t).unwrap();
posts.push(post);
}
let base_vol = brepkit_operations::measure::solid_volume(&topo, base, 0.1).unwrap();
assert!(base_vol > 0.0, "base should have positive volume");
for &post in &posts {
let post_vol = brepkit_operations::measure::solid_volume(&topo, post, 0.1).unwrap();
assert!(post_vol > 0.0, "post should have positive volume");
}
}
#[test]
fn example_custom_profile_extrusion() {
use brepkit_operations::boolean::{BooleanOp, boolean};
let mut topo = Topology::new();
let outer = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 20.0).unwrap();
let cutout = brepkit_operations::primitives::make_box(&mut topo, 5.0, 5.0, 20.0).unwrap();
let t = Mat4::translation(5.0, 5.0, 0.0);
brepkit_operations::transform::transform_solid(&mut topo, cutout, &t).unwrap();
let l_shape = boolean(&mut topo, BooleanOp::Cut, outer, cutout).unwrap();
let vol = brepkit_operations::measure::solid_volume(&topo, l_shape, 0.1).unwrap();
assert!(
(vol - 1500.0).abs() < 10.0,
"L-shape volume should be ~1500, got {vol}"
);
let s = topo.solid(l_shape).unwrap();
let sh = topo.shell(s.outer_shell()).unwrap();
assert!(
sh.faces().len() >= 6,
"L-shape should have at least 6 faces, got {}",
sh.faces().len()
);
}
#[test]
fn example_checkpoint_restore() {
let mut topo = Topology::new();
let box_id = brepkit_operations::primitives::make_box(&mut topo, 10.0, 10.0, 10.0).unwrap();
let box_vol = brepkit_operations::measure::solid_volume(&topo, box_id, 0.1).unwrap();
assert!((box_vol - 1000.0).abs() < 1.0);
let snapshot = topo.clone();
let snapshot_vertex_count = snapshot.vertices().len();
let cyl_id = brepkit_operations::primitives::make_cylinder(&mut topo, 3.0, 20.0).unwrap();
let transform = Mat4::translation(5.0, 5.0, -5.0);
brepkit_operations::transform::transform_solid(&mut topo, cyl_id, &transform).unwrap();
let _result = brepkit_operations::boolean::boolean(
&mut topo,
brepkit_operations::boolean::BooleanOp::Cut,
box_id,
cyl_id,
)
.unwrap();
assert!(topo.vertices().len() > snapshot_vertex_count + 10);
topo = snapshot;
assert_eq!(topo.vertices().len(), snapshot_vertex_count);
let restored_vol = brepkit_operations::measure::solid_volume(&topo, box_id, 0.1).unwrap();
assert!((restored_vol - 1000.0).abs() < 1.0);
}