mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 10:35:58 +00:00
smlib: Brep::classify_point says exactly where a point lies against a body
Binds the fork's smlib_brep_classify_point (SmBrep::Point3DClassify at the body's own zone tolerance): inside, outside, or on the boundary within that tolerance of a face, an edge or a vertex. A box and a cylinder just off its curved wall in measure's tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NvoxKQ2rEZvcXNQnhE3Sgs
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//! `smlib_brep_mass_properties`, `smlib_brep_area`, `smlib_brep_bounds` and
|
||||
//! `smlib_brep_edge_face_distance` (the fork's `capi/src/smlib_measure.cpp`), declared by
|
||||
//! `smlib_brep_mass_properties`, `smlib_brep_area`, `smlib_brep_bounds`,
|
||||
//! `smlib_brep_edge_face_distance` and `smlib_brep_classify_point` (the fork's `capi/src/smlib_measure.cpp`), declared by
|
||||
//! hand. Part of the FFI boundary, like its parent: called only through [`crate::measure`].
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
@@ -16,8 +16,14 @@ unsafe extern "C" {
|
||||
pub fn smlib_brep_area(brep: *const RawBrep, relative_accuracy: f64, out: *mut f64) -> i32;
|
||||
pub fn smlib_brep_bounds(brep: *const RawBrep, lo: *mut f64, hi: *mut f64) -> i32;
|
||||
pub fn smlib_brep_edge_face_distance(brep: *const RawBrep, edge: i64, face: i64, out: *mut f64) -> i32;
|
||||
pub fn smlib_brep_classify_point(brep: *const RawBrep, x: f64, y: f64, z: f64, out: *mut i32) -> i32;
|
||||
}
|
||||
|
||||
/// `SMLIB_POINT_OUTSIDE`, `SMLIB_POINT_INSIDE` and `SMLIB_POINT_ON_BOUNDARY`.
|
||||
pub const POINT_OUTSIDE: i32 = 0;
|
||||
pub const POINT_INSIDE: i32 = 1;
|
||||
pub const POINT_ON_BOUNDARY: i32 = 2;
|
||||
|
||||
#[cfg(feature = "native")]
|
||||
pub fn mass_properties(b: &Handle, relative_accuracy: f64) -> Result<[f64; 11], i32> {
|
||||
let mut m = [0.0; 11];
|
||||
@@ -54,6 +60,20 @@ pub fn edge_face_distance(b: &Handle, edge: i64, face: i64) -> Result<f64, i32>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "native")]
|
||||
pub fn classify_point(b: &Handle, p: [f64; 3]) -> Result<i32, i32> {
|
||||
let mut c = -1;
|
||||
match unsafe { smlib_brep_classify_point(b.raw(), p[0], p[1], p[2], &mut c) } {
|
||||
OK => Ok(c),
|
||||
s => Err(s),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn classify_point(_: &Handle, _: [f64; 3]) -> Result<i32, i32> {
|
||||
Err(NOT_BUILT)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "native"))]
|
||||
pub fn edge_face_distance(_: &Handle, _: i64, _: i64) -> Result<f64, i32> {
|
||||
Err(NOT_BUILT)
|
||||
|
||||
@@ -31,7 +31,7 @@ pub mod sweeps;
|
||||
pub mod trim;
|
||||
|
||||
pub use check::{CheckLevel, CheckReport};
|
||||
pub use measure::{MEASURE_ACCURACY, MassProperties};
|
||||
pub use measure::{MEASURE_ACCURACY, MassProperties, PointClass};
|
||||
pub use ops::{Blend, BooleanOp, ChamferSecond, Hole, HoleEdge, MAX_POINTS, MAX_UNION_BREPS};
|
||||
|
||||
/// Why an SMLib call failed.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Exact mass properties from SMLib: area, volume, centroid and inertia, integrated on the exact
|
||||
//! surfaces rather than a tessellation; the exact box; how far an edge lies from a face's surface.
|
||||
//! surfaces rather than a tessellation; the exact box; how far an edge lies from a face's surface;
|
||||
//! where a point lies against a body.
|
||||
|
||||
use crate::{Brep, Result, error, ffi};
|
||||
|
||||
@@ -31,7 +32,33 @@ impl MassProperties {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where a point lies against a body ([`Brep::classify_point`]).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum PointClass {
|
||||
/// In a void region: outside the material, or in a cavity.
|
||||
Outside,
|
||||
/// In a material region.
|
||||
Inside,
|
||||
/// Within the body's tolerance of a face, an edge or a vertex.
|
||||
OnBoundary,
|
||||
}
|
||||
|
||||
impl Brep {
|
||||
/// Where `p` (mm) lies against this body, decided exactly on its curves and surfaces (no
|
||||
/// tessellation) by SMLib's `SmBrep::Point3DClassify` at the body's own zone tolerance: on
|
||||
/// the boundary when within that tolerance of a face, an edge or a vertex (sheet faces too),
|
||||
/// else inside a material region or outside. A body with no material (a sheet, an open shell)
|
||||
/// has no inside. A non-finite coordinate is [`Error::Argument`](crate::Error::Argument).
|
||||
pub fn classify_point(&self, p: [f64; 3]) -> Result<PointClass> {
|
||||
match ffi::measure::classify_point(&self.0, p).map_err(error)? {
|
||||
ffi::measure::POINT_OUTSIDE => Ok(PointClass::Outside),
|
||||
ffi::measure::POINT_INSIDE => Ok(PointClass::Inside),
|
||||
ffi::measure::POINT_ON_BOUNDARY => Ok(PointClass::OnBoundary),
|
||||
// The C API writes only the three above; any other value is passed on as it came.
|
||||
other => Err(crate::Error::Status(other)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mass properties at `relative_accuracy` (clamped to [1e-8, 1e-1]; [`MEASURE_ACCURACY`] is
|
||||
/// the finest): the sum over the body's material regions, so several lumps, or lumps
|
||||
/// touching along edges or at points, measure too. A body with no material (a sheet, an open
|
||||
@@ -243,6 +270,26 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// A 10 × 20 × 30 box: inside, outside, on a face, an edge and a vertex; a cylinder of radius
|
||||
/// 5 just off its curved wall, within the tolerance (on it) and beyond (inside or outside).
|
||||
#[test]
|
||||
fn points_classify_exactly() {
|
||||
let b = Brep::make_box([0.0; 3], [10.0, 20.0, 30.0]).unwrap();
|
||||
assert_eq!(b.classify_point([5.0, 10.0, 15.0]).unwrap(), PointClass::Inside);
|
||||
assert_eq!(b.classify_point([5.0, 10.0, 30.0 + 1e-4]).unwrap(), PointClass::Outside);
|
||||
assert_eq!(b.classify_point([5.0, 10.0, 30.0 - 1e-4]).unwrap(), PointClass::Inside);
|
||||
assert_eq!(b.classify_point([5.0, 10.0, 30.0]).unwrap(), PointClass::OnBoundary);
|
||||
assert_eq!(b.classify_point([10.0, 10.0, 30.0]).unwrap(), PointClass::OnBoundary);
|
||||
assert_eq!(b.classify_point([10.0, 20.0, 30.0]).unwrap(), PointClass::OnBoundary);
|
||||
assert_eq!(b.classify_point([5.0, 10.0, f64::NAN]).unwrap_err(), Error::Argument);
|
||||
let c = Brep::make_cylinder([0.0; 3], 5.0, 10.0).unwrap();
|
||||
let at = |r: f64| [r * std::f64::consts::FRAC_1_SQRT_2, r * std::f64::consts::FRAC_1_SQRT_2, 5.0];
|
||||
assert_eq!(c.classify_point(at(5.0 + 1e-8)).unwrap(), PointClass::OnBoundary);
|
||||
assert_eq!(c.classify_point(at(5.0 - 1e-8)).unwrap(), PointClass::OnBoundary);
|
||||
assert_eq!(c.classify_point(at(5.0 + 1e-4)).unwrap(), PointClass::Outside);
|
||||
assert_eq!(c.classify_point(at(5.0 - 1e-4)).unwrap(), PointClass::Inside);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_accuracies_are_errors() {
|
||||
let b = Brep::make_box([0.0; 3], [1.0; 3]).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user