geometry: partition cuts and the projection mesher report progress and stop when cancelled

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-17 08:12:04 -04:00
1 parent 8dce4b14ce
commit b2fcf2c5bc
4 files changed
+20 -1

No files matched your search

+1
View File
@@ -87,6 +87,7 @@ impl EngineError {
matches!( matches!(
self, self,
EngineError::Model(Cancelled) EngineError::Model(Cancelled)
| EngineError::Geometry(fieldcraft_geometry::Error::Model(Cancelled))
| EngineError::Mesh(fieldcraft_mesh::Error::Model(Cancelled)) | EngineError::Mesh(fieldcraft_mesh::Error::Model(Cancelled))
| EngineError::Solver(fieldcraft_solver::Error::Model(Cancelled)) | EngineError::Solver(fieldcraft_solver::Error::Model(Cancelled))
| EngineError::Explicit(fieldcraft_explicit::Error::Model(Cancelled)) | EngineError::Explicit(fieldcraft_explicit::Error::Model(Cancelled))
+3
View File
@@ -46,6 +46,9 @@ pub enum Error {
Invalid(String), Invalid(String),
#[error("the geometry operation failed: {0}")] #[error("the geometry operation failed: {0}")]
Failed(String), Failed(String),
/// From the model layer: a cancelled job ([`fieldcraft_model::progress::check`]).
#[error(transparent)]
Model(#[from] fieldcraft_model::Error),
} }
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+7 -1
View File
@@ -103,7 +103,12 @@ impl Design {
let mut bodies: Vec<Shape> = self.source.as_ref().clone(); let mut bodies: Vec<Shape> = self.source.as_ref().clone();
let mut errors: Vec<FeatureError> = self.errors.iter().filter(|e| !crate::virtual_faces::derived(&e.feature)).cloned().collect(); let mut errors: Vec<FeatureError> = self.errors.iter().filter(|e| !crate::virtual_faces::derived(&e.feature)).cloned().collect();
let mut reports = Vec::with_capacity(cuts.len()); let mut reports = Vec::with_capacity(cuts.len());
for (cut, (plane, n)) in cuts.iter().zip(&planes) { // Each cut is a kernel boolean per body it reaches, seconds each on a large part: the
// job's progress counts them, and a cancelled job stops between them.
fieldcraft_model::progress::stage("Partition cuts", Some(cuts.len() as f64), "cuts");
for (k, (cut, (plane, n))) in cuts.iter().zip(&planes).enumerate() {
fieldcraft_model::progress::count(k as f64);
fieldcraft_model::progress::check()?;
let feature = format!("partition {}", cut.name); let feature = format!("partition {}", cut.name);
// A listed name is the body of that name, or the cells earlier partitions cut it into. // A listed name is the body of that name, or the cells earlier partitions cut it into.
let names = |name: &str, b: &str| name == b || name.strip_prefix(b).is_some_and(|rest| rest.starts_with('/')); let names = |name: &str, b: &str| name == b || name.strip_prefix(b).is_some_and(|rest| rest.starts_with('/'));
@@ -122,6 +127,7 @@ impl Design {
next.push(body); next.push(body);
continue; continue;
} }
fieldcraft_model::progress::check()?;
match split(&body, plane, *n, cut)? { match split(&body, plane, *n, cut)? {
Split::Cells(cells, faces, warnings) => { Split::Cells(cells, faces, warnings) => {
for &i in &listed { for &i in &listed {
+9
View File
@@ -454,6 +454,8 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
let edge_c = |e: [u32; 2]| Constraint::of(&as_vec(edge_on.get(&e))); let edge_c = |e: [u32; 2]| Constraint::of(&as_vec(edge_on.get(&e)));
// 1. Vertices. // 1. Vertices.
fieldcraft_model::progress::stage("Projection: block vertices", None, "");
fieldcraft_model::progress::check()?;
let mut vpos: Vec<P> = t.vertices.clone(); let mut vpos: Vec<P> = t.vertices.clone();
for (v, p) in vpos.iter_mut().enumerate() { for (v, p) in vpos.iter_mut().enumerate() {
*p = place(g, &targets, vertex_c(v as u32), *p, tol); *p = place(g, &targets, vertex_c(v as u32), *p, tol);
@@ -697,6 +699,8 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
} }
} }
// 3. Edge nodes: even by arc length along their curve or surface. // 3. Edge nodes: even by arc length along their curve or surface.
fieldcraft_model::progress::stage("Projection: edge nodes", None, "");
fieldcraft_model::progress::check()?;
for (b, block) in t.blocks.iter().enumerate() { for (b, block) in t.blocks.iter().enumerate() {
let nd = lat.divisions[b]; let nd = lat.divisions[b];
let bn = &lat.block_nodes[b]; let bn = &lat.block_nodes[b];
@@ -740,6 +744,8 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
} }
} }
// 4. Faces (projected when outside), then 5. the interior. // 4. Faces (projected when outside), then 5. the interior.
fieldcraft_model::progress::stage("Projection: faces and interior", None, "");
fieldcraft_model::progress::check()?;
for (b, block) in t.blocks.iter().enumerate() { for (b, block) in t.blocks.iter().enumerate() {
let nd = lat.divisions[b]; let nd = lat.divisions[b];
let bn = &lat.block_nodes[b]; let bn = &lat.block_nodes[b];
@@ -798,6 +804,8 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
} }
// Nodes on a sheet slide along it among their neighbours on it, as boundary nodes do. // Nodes on a sheet slide along it among their neighbours on it, as boundary nodes do.
let boundary_quads: Vec<[u32; 4]> = quads.iter().map(|q| q.0).chain(sheet_quads).collect(); let boundary_quads: Vec<[u32; 4]> = quads.iter().map(|q| q.0).chain(sheet_quads).collect();
fieldcraft_model::progress::stage("Projection: smoothing", None, "");
fieldcraft_model::progress::check()?;
let smoothing = smooth::smooth( let smoothing = smooth::smooth(
smooth::Mesh { nodes: &mut nodes, hexes: &lat.hexes, constraint: &constraint, held: &held, boundary: &boundary_quads }, smooth::Mesh { nodes: &mut nodes, hexes: &lat.hexes, constraint: &constraint, held: &held, boundary: &boundary_quads },
g, g,
@@ -807,6 +815,7 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
1e-4 * opts.size, 1e-4 * opts.size,
); );
fieldcraft_model::progress::check()?;
// Certified quality, the gap to the geometry and the tags. // Certified quality, the gap to the geometry and the tags.
let (mut min_sj, mut sum_sj, mut volume) = (f64::INFINITY, 0.0, 0.0); let (mut min_sj, mut sum_sj, mut volume) = (f64::INFINITY, 0.0, 0.0);
let mut invalid: Vec<usize> = Vec::new(); let mut invalid: Vec<usize> = Vec::new();