mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 18:45:55 +00:00
solidcraft-smlib: Brep::union_all, the union of many bodies in one SMLib call
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
//! The operations block of `capi/include/smlib.h` (`smlib_boolean`, `smlib_boolean2d`, `smlib_fillet`,
|
||||
//! The operations block of `capi/include/smlib.h` (`smlib_boolean`, `smlib_boolean_union_all`, `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_boolean_union_all(breps: *const *const RawBrep, n: i64, 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;
|
||||
@@ -149,6 +150,13 @@ 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 boolean_union_all(breps: &[&Handle]) -> Result<Handle, i32> {
|
||||
let raw: Vec<*const RawBrep> = breps.iter().map(|h| h.raw()).collect();
|
||||
let n = i64::try_from(raw.len()).map_err(|_| ERR_ARG)?;
|
||||
new_brep(|out| unsafe { smlib_boolean_union_all(raw.as_ptr(), n, 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) })
|
||||
@@ -315,6 +323,11 @@ pub fn boolean(_: &Handle, _: &Handle, _: i32) -> Result<Handle, i32> {
|
||||
Err(NOT_BUILT)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn boolean_union_all(_: &[&Handle]) -> Result<Handle, i32> {
|
||||
Err(NOT_BUILT)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn boolean2d(_: &Handle, _: &Handle, _: i32) -> Result<Handle, i32> {
|
||||
Err(NOT_BUILT)
|
||||
|
||||
@@ -31,7 +31,7 @@ pub mod trim;
|
||||
|
||||
pub use check::{CheckLevel, CheckReport};
|
||||
pub use measure::{MEASURE_ACCURACY, MassProperties};
|
||||
pub use ops::{Blend, BooleanOp, ChamferSecond, MAX_POINTS};
|
||||
pub use ops::{Blend, BooleanOp, ChamferSecond, MAX_POINTS, MAX_UNION_BREPS};
|
||||
|
||||
/// Why an SMLib call failed.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
||||
@@ -41,6 +41,9 @@ pub enum ChamferSecond {
|
||||
Angle(f64),
|
||||
}
|
||||
|
||||
/// Most bodies [`Brep::union_all`] takes (the C API's limit).
|
||||
pub const MAX_UNION_BREPS: usize = 100_000;
|
||||
|
||||
/// Most points one selection may hold (the C API's limit).
|
||||
pub const MAX_POINTS: usize = 4096;
|
||||
|
||||
@@ -71,6 +74,19 @@ impl Brep {
|
||||
}
|
||||
}
|
||||
|
||||
/// The union of `breps` in one call: they are unioned pairwise, level by level, so none takes
|
||||
/// part in more than about log2(n) unions. The result is as [`Brep::boolean`]'s; operands
|
||||
/// tagged each with its own number ([`Brep::tagged`]) give a result whose [`Brep::history`]
|
||||
/// names them. At least one body and at most [`MAX_UNION_BREPS`].
|
||||
pub fn union_all(breps: &[&Brep]) -> Result<Brep> {
|
||||
init()?;
|
||||
if breps.is_empty() || breps.len() > MAX_UNION_BREPS {
|
||||
return Err(error(ffi::ERR_ARG));
|
||||
}
|
||||
let handles: Vec<&ffi::Handle> = breps.iter().map(|b| &b.0).collect();
|
||||
ffi::ops::boolean_union_all(&handles).map(Brep).map_err(error)
|
||||
}
|
||||
|
||||
/// `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.
|
||||
|
||||
Reference in New Issue
Block a user