mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 18:45:55 +00:00
solidcraft-smlib: Brep::imprint
Imprint cuts each face of a body where a tool body meets it (the fork's smlib_imprint, SMLib's imprinting boolean) and gives None where the tool crosses no face. Trim builds on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//! The operations block of `capi/include/smlib.h` (`smlib_boolean`, `smlib_fillet`,
|
||||
//! `smlib_chamfer`, `smlib_blend`, `smlib_fillet_variable`, `smlib_shell`, `smlib_offset_faces`,
|
||||
//! `smlib_thicken`, `smlib_brep_solid_count`; the fork's `capi/src/smlib_ops.cpp`), declared by
|
||||
//! `smlib_thicken`, `smlib_brep_solid_count`, `smlib_imprint`; the fork's `capi/src/smlib_ops.cpp`), declared by
|
||||
//! hand. Part of the FFI boundary, like its parent: called only through
|
||||
//! [`crate::ops`].
|
||||
|
||||
@@ -16,6 +16,7 @@ pub const ERR_NOT_SOLID: i32 = -1100;
|
||||
pub const ERR_PICK_NONE: i32 = -1101;
|
||||
pub const ERR_PICK_AMBIGUOUS: i32 = -1102;
|
||||
pub const ERR_NO_ROOM: i32 = -1103;
|
||||
pub const ERR_NO_CUT: i32 = -1104;
|
||||
|
||||
pub const BOOLEAN_UNION: i32 = 0;
|
||||
pub const BOOLEAN_SUBTRACT: i32 = 1;
|
||||
@@ -46,6 +47,7 @@ type PickFn = unsafe extern "C" fn(*const RawBrep, *const f64, i64, f64, f64, *m
|
||||
unsafe extern "C" {
|
||||
fn smlib_boolean(a: *const RawBrep, b: *const RawBrep, op: i32, out: *mut *mut RawBrep) -> i32;
|
||||
fn smlib_brep_solid_count(brep: *const RawBrep, out: *mut i64) -> i32;
|
||||
fn smlib_imprint(body: *const RawBrep, tool: *const RawBrep, out: *mut *mut RawBrep) -> i32;
|
||||
fn smlib_fillet(
|
||||
brep: *const RawBrep,
|
||||
points: *const f64,
|
||||
@@ -112,6 +114,11 @@ pub fn boolean(a: &Handle, b: &Handle, op: i32) -> Result<Handle, i32> {
|
||||
new_brep(|out| unsafe { smlib_boolean(a.raw(), b.raw(), op, out) })
|
||||
}
|
||||
|
||||
#[cfg(feature = "native")]
|
||||
pub fn imprint(body: &Handle, tool: &Handle) -> Result<Handle, i32> {
|
||||
new_brep(|out| unsafe { smlib_imprint(body.raw(), tool.raw(), out) })
|
||||
}
|
||||
|
||||
#[cfg(feature = "native")]
|
||||
pub fn solid_count(b: &Handle) -> Result<i64, i32> {
|
||||
let mut n = 0i64;
|
||||
@@ -197,6 +204,11 @@ pub fn boolean(_: &Handle, _: &Handle, _: i32) -> Result<Handle, i32> {
|
||||
Err(NOT_BUILT)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn imprint(_: &Handle, _: &Handle) -> Result<Handle, i32> {
|
||||
Err(NOT_BUILT)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn solid_count(_: &Handle) -> Result<i64, i32> {
|
||||
Err(NOT_BUILT)
|
||||
|
||||
@@ -62,6 +62,18 @@ impl Brep {
|
||||
}
|
||||
}
|
||||
|
||||
/// `self` with each face `tool` meets cut along the intersection, the pieces kept as faces of
|
||||
/// one body: `None` when the tool meets no face. Tagged operands give the pieces' history
|
||||
/// (each piece is a split of the face it was cut from).
|
||||
pub fn imprint(&self, tool: &Brep) -> Result<Option<Brep>> {
|
||||
init()?;
|
||||
match ffi::ops::imprint(&self.0, &tool.0) {
|
||||
Ok(h) => Ok(Some(Brep(h))),
|
||||
Err(ffi::ops::ERR_NO_CUT) => Ok(None),
|
||||
Err(s) => Err(error(s)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of separate solid regions (voids not counted).
|
||||
pub fn solid_count(&self) -> Result<usize> {
|
||||
ffi::ops::solid_count(&self.0).map(|n| usize::try_from(n).unwrap_or(0)).map_err(error)
|
||||
|
||||
@@ -275,3 +275,17 @@ fn a_variable_round_follows_its_law() {
|
||||
assert!(c.fillet_variable([10.0, 20.0, 20.0], 0.1, [0.0, 20.0, 20.0], 1, &[0.0, 0.5, 1.0, 1.0], &[3.0, 1.0]).is_err());
|
||||
assert!(matches!(c.fillet_variable([90.0, 90.0, 90.0], 0.1, [0.0; 3], 1, &knots, &[3.0, 1.0]), Err(Error::NoMatch { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imprint_cuts_faces_where_a_tool_meets_them() {
|
||||
// A box half sunk into the cube cuts the four side faces it crosses and the top it lies in.
|
||||
let cube = cube(20.0);
|
||||
let tool = Brep::make_box([5.0, -1.0, 10.0], [10.0, 22.0, 15.0]).unwrap();
|
||||
let cut = cube.imprint(&tool).unwrap().unwrap();
|
||||
assert!(cut.counts().unwrap()[0] > 6);
|
||||
assert!((cut.volume(1e-7).unwrap() - 8000.0).abs() < 1e-6);
|
||||
assert_eq!(cube.counts().unwrap()[0], 6);
|
||||
// A tool that misses cuts nothing.
|
||||
let far = Brep::make_box([50.0, 0.0, 0.0], [10.0, 10.0, 10.0]).unwrap();
|
||||
assert!(cube.imprint(&far).unwrap().is_none());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user