Boundary surface preparation (weld, manifold/orientation, exact self-intersection, feature edges) and mesh.surface.check (#15)

* mesh: boundary surface preparation (weld, manifold and orientation checks, exact self-intersection, feature edges)

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

* engine: mesh.surface.check on an open design's body or an imported surface

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

* engine: struct-init the test session

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

* surface: weld at an absolute distance too; the engine welds CAD tessellations at twice SolidCraft's linear tolerance

Faces of a SolidCraft tessellation carry their own copies of shared boundary points, which agree
only to within the kernel's tolerance (up to ~2e-6 mm on the test corpus).

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

* docs: surface preparation in the literature survey, architecture and roadmap

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

* surface: simplify after review

- The weld distance travels with the mesh (SurfaceMesh::weld_distance, set by Shape::tessellate),
  so every consumer welds a tessellation correctly without opting in.
- Exact tests are infallible on predicates::orient2d_projected (shared with generic_orient2d), and
  compute each vertex's plane side once per pair with an early reject.
- One Box3 for the weld, the BVH and shells; a Half struct for edges; the weld's two lookups share
  one loop, with chained grid cells; cached normals for feature edges; shared parameter helpers.

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

* corpus: boundary surface preparation as a corpus stage

20 of 21 parts are valid boundaries with their expected genus; cross-cylinders' tessellation has
cracks and flipped triangles where its two intersection curves meet.

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

---------

Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-10-13 16:01:42 -04:00
1 parent 94dc50bb0c
commit 02cc9dab57
24 files changed
+1987 -60

No files matched your search

+14 -1
View File
@@ -47,6 +47,9 @@ impl From<KernelError> for Error {
}
}
/// SolidCraft's linear modelling tolerance (mm): points closer than this are the same point.
const LINEAR_TOLERANCE: f64 = solidcraft_geom::LINEAR_TOL;
/// A solid body.
#[derive(Debug, Clone)]
pub struct Shape {
@@ -86,6 +89,11 @@ pub struct SurfaceMesh {
pub triangles: Vec<[u32; 3]>,
/// The B-rep face each triangle lies on.
pub tri_face: Vec<u32>,
/// Copies of one point closer than this are the same point (0: only identical coordinates).
/// A [`Shape::tessellate`] result is a triangle soup whose faces each carry their own copy of
/// the boundary points they share, accurate to the kernel's linear tolerance, so two copies
/// can differ by up to twice it; boundary surface preparation welds at this distance.
pub weld_distance: f64,
}
fn xyz(v: solidcraft_geom::Vec3) -> [f64; 3] {
@@ -129,7 +137,12 @@ impl Shape {
return Err(Error::Invalid(format!("tessellation tolerance must be a positive number, got {tolerance}")));
}
let m = guard("tessellate", || self.body.tessellate(tolerance))?;
Ok(SurfaceMesh { positions: m.positions.into_iter().map(xyz).collect(), triangles: m.triangles, tri_face: m.tri_face })
Ok(SurfaceMesh {
positions: m.positions.into_iter().map(xyz).collect(),
triangles: m.triangles,
tri_face: m.tri_face,
weld_distance: 2.0 * LINEAR_TOLERANCE,
})
}
}