Files
jyviko dc38349cbf Layer split stage 1: the B-rep record, native body file and Vec/Plane come from solidcore-record (#11496)
* Kernel: the B-rep record and the native body file come from solidcore-record

SolidCraft's portable B-rep record (`solidcraft_geom::brep`: brep.rs, topology, history,
envelope, part, curve2) and the native body file (`solidcraft_kernel::native`: the tagged binary
codec and the container) move to solidcore's `solidcore-record` crate: geometry as data, with
structural validation and no maths (solidcore's docs/layers.md, stage 1). Every caller uses
`solidcore_record::brep` and `solidcore_record::native`; the old copies are deleted.

What computes from coordinates stays with the kernel, in geom's `brep`:
- `brep::check`: the record's geometric checks (orthonormal frames, non-degenerate planes,
  unit revolution axes, non-singular placements). `check::validate` and
  `check::validate_built` are the record's validation and these together, and every caller of
  `Brep::validate` uses them, so what is accepted is unchanged;
- `brep::label`: a surface's natural ranges (a cone's apex), `curve_interval`,
  `edge_curve_interval` and `form_turns`;
- `brep::pcurve::eval`: a pcurve's point;
- `geometry::check`, `placement::moved` and `split_edges` become functions on the record.

The kernel's native module keeps the conversion between a body and its saved record
(metadata.rs) and checks the decoded record's geometry. `native/analytic.rs`, which no module
declared, is deleted.

solidcore-record is pinned to its rev on solidcore's `layer-record` branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NvoxKMbMFSQU8tzRtoJhtT

* Geometry: Vec2, Vec3, Plane and the profile types come from solidcore-record

The plain data of vectors and points, sketch planes and planar profiles (`Seg2`, `Loop2`,
`Region2`) moves to `solidcore-record`, with its constants and component-wise operators only
(owner decision, solidcore layer split). Their geometry stays in geom as traits:
`Vec2Geom`, `Vec3Geom`, `PlaneGeom`, `Seg2Geom`, `Loop2Geom`, `Region2Geom`, `Seg2ArcFit`,
`Loop2ArcFit` and `Region2ArcFit`, in scope with `use solidcraft_geom::prelude::*`. Every caller
names the types from `solidcore_record`; geom no longer defines or re-exports them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NvoxKMbMFSQU8tzRtoJhtT

* Kernel: pin solidcore-record to solidcore main f5e8e9a29

solidcore-record is merged on solidcore main (tangency-labs/solidcore#2519); its crate there is
identical to the rev pinned before but for its clippy configuration. The lock is regenerated
against the merged rev.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NvoxKMbMFSQU8tzRtoJhtT

---------

Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 09:04:26 -05:00

63 lines
2.3 KiB
Rust

//! Is a body one valid solid? The kernel regression rig (`tests/kernel-cases`) asks this of every
//! result: the schema 4 record's structure and geometry (`Brep::validate`, `check_geometry`),
//! and SMLib's own check of the same record.
use crate::{Body, brep_record};
/// What the validity checks found for one body. `Err` holds why a check failed.
#[derive(Clone, Debug)]
pub struct Validity {
/// The record: structure, then geometry against topology within tolerances.
pub record: Result<(), String>,
/// SMLib's `check(All)` of the record.
pub smlib: Option<SmlibCheck>,
}
/// SMLib's verdict on a body.
#[derive(Clone, Debug)]
pub enum SmlibCheck {
Valid,
Invalid(String),
/// The record can't be built in SMLib yet (a geometry kind the conversion doesn't take): no
/// verdict, and no fault of the body's.
NotSupported(String),
}
impl Validity {
pub fn ok(&self) -> bool {
self.record.is_ok() && !matches!(self.smlib, Some(SmlibCheck::Invalid(_)))
}
}
/// Runs every validity check this build has on `body`.
pub fn validity(body: &Body) -> Validity {
let record = brep_record(body).map_err(|e| e.to_string());
let checked = record.as_ref().map_err(Clone::clone).and_then(|r| {
solidcraft_geom::brep::check::validate_built(r).map_err(|e| format!("structure: {e}"))?;
solidcraft_geom::brep::geometry::check(r).map_err(|e| format!("geometry: {e}"))
});
Validity { record: checked, smlib: smlib_validity(body) }
}
fn smlib_validity(body: &Body) -> Option<SmlibCheck> {
let b = match crate::smlib_body(body) {
Ok(b) => b,
Err(e) => {
let e = e.to_string();
return Some(if e.contains("not supported yet") { SmlibCheck::NotSupported(e) } else { SmlibCheck::Invalid(e) });
}
};
Some(match b.check(solidcraft_smlib::CheckLevel::All) {
Ok(r) if r.is_valid() => SmlibCheck::Valid,
Ok(r) => SmlibCheck::Invalid(format!("SMLib check: {r}")),
Err(e) => SmlibCheck::Invalid(format!("SMLib check: {e}")),
})
}
/// Where every kernel call that fails from now on leaves its inputs for replay
/// (`solidcraft_smlib::set_dump_dir`: the call and its B-reps, which `Brep::read` reads back);
/// `None` stops it.
pub fn smlib_dump_dir(dir: Option<&std::path::Path>) {
solidcraft_smlib::set_dump_dir(dir);
}