engine: mesh.hex.octree command

Replaces the mesh with the octree all-hex mesh of a body, an imported surface or every body
of the open design, and tags boundary element faces with their B-rep faces so sets by
geometry resolve. Size, tolerance, refinement depth, element cap, attempts and optimiser
sweeps are validated and capped; the element cap defaults to the session limit
(`Limits::max_hex_elements`), which the hostile-params test keeps small. Body input and face
tagging are shared with mesh.hex.generate. The catalogue's Automatic Hex entry is ready.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-14 07:38:11 -04:00
1 parent 3587b0de74
commit 7d2696057f
8 files changed
+221 -21

No files matched your search

+12 -3
View File
@@ -135,6 +135,8 @@ pub struct Limits {
pub max_steiner: usize,
/// `mesh.tet.generate`'s `max_tets`.
pub max_tets: usize,
/// `mesh.hex.octree`'s `max_elements`.
pub max_hex_elements: usize,
/// Threads the solvers use (the `solve.*` commands' `threads`): by default
/// `FIELDCRAFT_THREADS` or the available cores, 1 to [`fieldcraft_parallel::MAX_THREADS`].
/// Results do not depend on it.
@@ -144,7 +146,12 @@ pub struct Limits {
impl Default for Limits {
fn default() -> Self {
let cdt = fieldcraft_mesh::cdt::CdtOptions::default();
Limits { max_steiner: cdt.max_steiner, max_tets: cdt.max_tets, threads: fieldcraft_parallel::default_threads() }
Limits {
max_steiner: cdt.max_steiner,
max_tets: cdt.max_tets,
max_hex_elements: cmd::octree::DEFAULT_MAX_ELEMENTS,
threads: fieldcraft_parallel::default_threads(),
}
}
}
@@ -471,9 +478,11 @@ mod tests {
json!({"geometry": {"body": "Bar", "vertex": "v"}, "nodes": [1], "edges": [{"element": 1, "edge": 0}]}),
];
// Small work caps, so input that would mesh up to the production caps (needle triangles
// need Steiner points all along them) is refused at once. The caps themselves are what
// need Steiner points all along them, an octree hex mesh is fitted and untangled) is
// refused at once. The caps themselves are what
// `tet_generate_honours_the_session_caps` checks.
let capped = || Session { limits: Limits { max_steiner: 64, max_tets: 100_000, ..Limits::default() }, ..Session::default() };
let capped =
|| Session { limits: Limits { max_steiner: 64, max_tets: 100_000, max_hex_elements: 500, ..Limits::default() }, ..Session::default() };
for spec in commands() {
for p in &hostile {
let mut s = capped();