diff --git a/crates/smlib/SMLIB_REV b/crates/smlib/SMLIB_REV index c214fc77fe..a52a30d734 100644 --- a/crates/smlib/SMLIB_REV +++ b/crates/smlib/SMLIB_REV @@ -1 +1 @@ -1934b5799653dd205182456943bfb29beccaae92 +c46946993db8e757ed6f4cc1983ab277a7891b1d diff --git a/crates/smlib/src/ffi/ops.rs b/crates/smlib/src/ffi/ops.rs index f79977eade..248086e4b5 100644 --- a/crates/smlib/src/ffi/ops.rs +++ b/crates/smlib/src/ffi/ops.rs @@ -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 { 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 { + new_brep(|out| unsafe { smlib_boolean2d(a.raw(), b.raw(), op, out) }) +} + #[cfg(feature = "native")] pub fn imprint(body: &Handle, tool: &Handle) -> Result { new_brep(|out| unsafe { smlib_imprint(body.raw(), tool.raw(), out) }) @@ -309,6 +315,11 @@ pub fn boolean(_: &Handle, _: &Handle, _: i32) -> Result { Err(NOT_BUILT) } +#[cfg(not(feature = "native"))] +pub fn boolean2d(_: &Handle, _: &Handle, _: i32) -> Result { + Err(NOT_BUILT) +} + #[cfg(not(feature = "native"))] pub fn imprint(_: &Handle, _: &Handle) -> Result { Err(NOT_BUILT) diff --git a/crates/smlib/src/ffi/sweeps.rs b/crates/smlib/src/ffi/sweeps.rs index 12d547b89a..d3b9476050 100644 --- a/crates/smlib/src/ffi/sweeps.rs +++ b/crates/smlib/src/ffi/sweeps.rs @@ -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 { + 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 { let (k, nk, r, nr) = raw(profile)?; @@ -206,6 +213,11 @@ pub fn sweep_stations(profile: &List, maps: &[f64], ends: i32) -> Result Result { + Err(NOT_BUILT) +} + #[cfg(not(feature = "native"))] pub fn extrude(_: &List, _: &[f64; 3], _: f64, _: f64, _: bool) -> Result { Err(NOT_BUILT) diff --git a/crates/smlib/src/ops.rs b/crates/smlib/src/ops.rs index 449d686a66..866d65b891 100644 --- a/crates/smlib/src/ops.rs +++ b/crates/smlib/src/ops.rs @@ -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> { + 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). diff --git a/crates/smlib/src/sweeps.rs b/crates/smlib/src/sweeps.rs index cd082f0143..bc6e016b61 100644 --- a/crates/smlib/src/sweeps.rs +++ b/crates/smlib/src/sweeps.rs @@ -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 { + 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).