solidcraft-smlib: Brep::planar_faces and Brep::boolean2d

Wrappers of the fork's smlib_planar_faces (a sheet of planar faces from closed curve loops in
one plane, nested by SMLib) and smlib_boolean2d (two such sheets combined as regions of the
plane by SM_API's 2D boolean, the inputs' own curves split where they cross; an empty result
is None). SMLIB_REV moves to the fork commit that adds them (78617dd).

clippy -p solidcraft-smlib --features native --all-targets -D warnings: clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
This commit is contained in:
jyviko
2026-10-22 00:59:46 -04:00
parent 3ef93b3630
commit cfb5dc3ba3
5 changed files with 51 additions and 3 deletions
+1 -1
View File
@@ -1 +1 @@
1934b5799653dd205182456943bfb29beccaae92
c46946993db8e757ed6f4cc1983ab277a7891b1d
+12 -1
View File
@@ -1,4 +1,4 @@
//! The operations block of `capi/include/smlib.h` (`smlib_boolean`, `smlib_fillet`,
//! The operations block of `capi/include/smlib.h` (`smlib_boolean`, `smlib_boolean2d`, `smlib_fillet`,
//! `smlib_chamfer`, `smlib_blend`, `smlib_fillet_variable`, `smlib_chamfer_sides`, `smlib_shell`, `smlib_offset_faces`,
//! `smlib_thicken`, `smlib_draft`, `smlib_merge_faces`, `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
@@ -48,6 +48,7 @@ type PickFn = unsafe extern "C" fn(*const RawBrep, *const f64, i64, f64, f64, *m
#[cfg(feature = "native")]
unsafe extern "C" {
fn smlib_boolean(a: *const RawBrep, b: *const RawBrep, op: i32, out: *mut *mut RawBrep) -> i32;
fn smlib_boolean2d(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(
@@ -148,6 +149,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 boolean2d(a: &Handle, b: &Handle, op: i32) -> Result<Handle, i32> {
new_brep(|out| unsafe { smlib_boolean2d(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) })
@@ -309,6 +315,11 @@ pub fn boolean(_: &Handle, _: &Handle, _: i32) -> Result<Handle, i32> {
Err(NOT_BUILT)
}
#[cfg(not(feature = "native"))]
pub fn boolean2d(_: &Handle, _: &Handle, _: i32) -> Result<Handle, i32> {
Err(NOT_BUILT)
}
#[cfg(not(feature = "native"))]
pub fn imprint(_: &Handle, _: &Handle) -> Result<Handle, i32> {
Err(NOT_BUILT)
+13 -1
View File
@@ -1,5 +1,5 @@
//! The sweeps block of `capi/include/smlib.h` (`smlib_extrude`, `smlib_revolve`, `smlib_sweep`,
//! `smlib_sweep_placed`, `smlib_loft`, `smlib_loft_to_point`, `smlib_screw_sweep`, `smlib_sweep_stations`; the fork's
//! `smlib_sweep_placed`, `smlib_loft`, `smlib_loft_to_point`, `smlib_screw_sweep`, `smlib_sweep_stations`, `smlib_planar_faces`; the fork's
//! `capi/src/smlib_sweeps.cpp`), declared by hand.
//! Part of the FFI boundary, like its parent: called only through [`crate::sweeps`], which builds
//! the curve lists.
@@ -54,6 +54,7 @@ impl<'a> List<'a> {
#[cfg(feature = "native")]
unsafe extern "C" {
fn smlib_planar_faces(kinds: *const i64, n_kinds: i64, reals: *const f64, n_reals: i64, out: *mut *mut RawBrep) -> i32;
fn smlib_extrude(
kinds: *const i64,
n_kinds: i64,
@@ -147,6 +148,12 @@ fn raw(l: &List) -> Result<(*const i64, i64, *const f64, i64), i32> {
Ok((l.kinds.as_ptr(), nk, l.reals.as_ptr(), nr))
}
#[cfg(feature = "native")]
pub fn planar_faces(loops: &List) -> Result<Handle, i32> {
let (k, nk, r, nr) = raw(loops)?;
new_brep(|out| unsafe { smlib_planar_faces(k, nk, r, nr, out) })
}
#[cfg(feature = "native")]
pub fn extrude(profile: &List, direction: &[f64; 3], distance: f64, draft: f64, cap: bool) -> Result<Handle, i32> {
let (k, nk, r, nr) = raw(profile)?;
@@ -206,6 +213,11 @@ pub fn sweep_stations(profile: &List, maps: &[f64], ends: i32) -> Result<Handle,
new_brep(|out| unsafe { smlib_sweep_stations(k, nk, r, nr, maps.as_ptr(), n, ends, out) })
}
#[cfg(not(feature = "native"))]
pub fn planar_faces(_: &List) -> Result<Handle, i32> {
Err(NOT_BUILT)
}
#[cfg(not(feature = "native"))]
pub fn extrude(_: &List, _: &[f64; 3], _: f64, _: f64, _: bool) -> Result<Handle, i32> {
Err(NOT_BUILT)
+17
View File
@@ -71,6 +71,23 @@ impl Brep {
}
}
/// `self` and `other`, sheets of planar faces on one plane ([`Brep::planar_faces`]), combined
/// as regions of that plane by `op`: `None` when the result is empty. The result's edges are
/// the inputs' own curves, split where they cross.
pub fn boolean2d(&self, other: &Brep, op: BooleanOp) -> Result<Option<Brep>> {
init()?;
let op = match op {
BooleanOp::Union => ffi::ops::BOOLEAN_UNION,
BooleanOp::Subtract => ffi::ops::BOOLEAN_SUBTRACT,
BooleanOp::Intersect => ffi::ops::BOOLEAN_INTERSECT,
};
match ffi::ops::boolean2d(&self.0, &other.0, op) {
Ok(h) => Ok(Some(Brep(h))),
Err(ffi::ERR_EMPTY) => Ok(None),
Err(s) => Err(error(s)),
}
}
/// `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).
+8
View File
@@ -130,6 +130,14 @@ impl List {
}
impl Brep {
/// A sheet of planar faces bounded by `loops`: closed loops of curves in one plane, in any
/// order, nested as outer loops, their holes and islands in the holes.
pub fn planar_faces(loops: &[Curve]) -> Result<Brep> {
init()?;
let l = List::of(loops)?;
ffi::sweeps::planar_faces(&l.raw()).map(Brep).map_err(error)
}
/// The planar `profile` extruded `distance` along the unit `direction` (square to its plane).
/// `draft` (radians) leans the walls: positive inward, negative outward; a drafted profile is
/// one closed loop, its curves in order, and `direction` is its normal (either way round).