The kernel failure is reported as such since #381; the failure itself came
from split_by_plane's oversized boxes, which #384 replaced with body-sized
ones. The regression test now requires the cut (x = 110, 148, reversed
normal, the diagonal plane) from commands, with the cells' volumes adding up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
The projection layout gave every fillet a blend layer along the sides it runs between, so a
screw hole close to a rounded corner sat inside the layer and the plan fell back to frame cuts
and swept cells, which fan into the hole. A corner fillet that lies inside the square from the
hole to the two sides is now taken in by the hole's O-grid ring: the frame reaches both sides,
its outer corner projects onto the middle of the fillet, and no layer is needed. An O-grid's
frame is centred on its hole (a near side is the frame, the far side as far), and the plan
reports the layout's frames and drops the frame-cut notes when it does not cut.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
project_trimmed accepted the analytic projection within a fifth of the nearest
triangle's size; a plane face's triangles can span the whole face, so nodes in a
3 mm fillet landed on the untrimmed box planes (mesh volume = the unfilleted box).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
--section x|y|z[=VALUE] hides the elements on the camera's side of a plane
(at the mesh's middle by default) so the element faces inside show;
--field contours a nodal field of the solved step (results.contour). The
MCP server's headless screenshot draws with the viewport's pipeline on the
shared device and its reply, like snapshot's, names the renderer.
Refs #422
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
render::draw_labels draws a scene's labels over finished pixels in the CPU
rasterizer's font. capture::shared opens the process's device once by the
FIELDCRAFT_GPU policy; capture::png draws on it or on the CPU and reports
which (Renderer).
Refs #422
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
fieldcraft-cli snapshot script.json --out shot.png [--view] [--size WxH]
draws the engine's framed scene (engine::view::frame, shared with the CPU
render_png) with the viewport's GPU pipelines offscreen: hardware GPU, then
a software one, then the CPU rasterizer (FIELDCRAFT_GPU=auto|hardware|
software|cpu). CI installs lavapipe so the GPU path runs there.
Refs #422
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
Topology::split cuts a block at given fractions and every block chained to it
through parallel edges, orienting the fractions through the chain, so the
topology stays conforming. A certified-invalid element is reported with its
block, cell, centre and the block vertex and blocks meeting there; the mesh is
never emitted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
The release job (the only one that signs SHA256SUMS.txt or touches a GitHub Release) now needs
every verify and packaging job; packaging no longer waits for verify. Verify jobs restore
develop's CI caches through shared keys (same CARGO_* env as ci.yml); saving stays main-only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
The section comes from a set (a 2D mesh or element faces), the mesh already
on the source faces (tagged, or a neighbouring body's boundary lying on
them, whose nodes are shared so the meshes conform), or a fresh quad mesh
of one planar face. Target and side faces project through the tet mesher's
B-rep projection. Replaces the body's mesh like the other meshers, tags the
body's own source, target and side faces, and is on the MCP mesh tool as
hex_extrude.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
Each source node follows its own path (a direction or the section normal)
to the target, found by Newton on the target's tangent plane; layers are
graded by a bias; side faces, when given, hold the boundary nodes of every
layer (alternating projections at the target), and interior nodes take the
boundary-residual correction. Source nodes are kept, so a section taken from
a neighbouring mesh conforms with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
A block topology (carved grid, butterfly and seven-block sphere templates,
O-grid, extrude, connect) projected onto a body: outer block faces onto their
smooth face groups, edges onto the curve of two targets and vertices onto the
point of three by tangent-plane iteration, nodes by transfinite interpolation,
then Winslow smoothing with the boundary on the geometry and a compass search
on the worst elements.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
Every tied interface between cells of one design body carries `why`: the tet cell (and why
auto fell back), the reason the body's cells did not sweep together, or the cell meshed alone
by its method; so an agent knows which cut or method to change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
The swept cross-section's decomposition:
- An opening with concave corners gets a layout that continues its sides to the outer loop
(side strips and corner blocks, every corner near 90°). The thin air ring round the Pi
enclosure's square pedestal was left to the free mesher, which put a node 1e-5 from the
opening's corner: edge ratio 341,515.
- A piece's score is capped by its quadrilaterals' aspect against their longest edge or the
target size, so thin strips and pieces much smaller than the elements no longer score as
square blocks; the free mesh is scored alike for "do no harm".
- A disk is not cut into wedges round its centre (its O-grid is the scheme).
- Cuts whose pieces cannot be given division counts together (mapped pieces round a hole that
chain back to a longer side) are refused, instead of failing the whole cross-section.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
The 3MF reader's name_for_index now returns a Result in zip 9, and the
geometry test writer still wrapped last_modified_time in Some. Cargo.lock
gains zip 9.0.3 beside SolidCraft's zip 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
- last_modified_time takes DateTime directly, drop the Some() wrapper
- file_names() returns Result<Cow<str>, ZipError>: propagate errors, compare
the Cow<str>, and push the resolved name into seen
- test helper: ZipFile::name() now returns Result, unwrap it
- update the Cargo.toml comment explaining why we moved ahead of
SolidCraft (still on zip 3)
- update Cargo.lock to zip 9.0.3
Bump the zip crate from 3 to 9 in the workspace Cargo.toml and
adapt to the API change in 2.0+: last_modified_time now takes
Option<DateTime> instead of DateTime directly.
- crates/io/src/lib.rs: wrap DateTime::default() in Some(...)
- crates/geometry/src/tagged_mesh.rs: same fix in the 3MF writer
Closes#134
A partition intersects the body with a box on each side of the plane as
large as the body itself. SolidCraft's split_by_plane uses boxes several
times larger, and its boolean then put the cut up to 1.8 um off the plane
on the enclosure's air, so the cut faces were not recognized and the cells
did not close. A plane along a face of a body it cuts, or a cell whose
boundary does not tessellate into one a mesher takes (a cut through a
hole's axis), is a warning naming the partition, the body and where.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
Deleting, suppressing or editing a partition (or its datum), or cutting a
meshed body, removes the meshes of the bodies that are gone, reported as
replaced, in the same undo step. model.check lists meshes of partition
cells the open design no longer has (a model saved before the cut
changed), and mesh.clear removes them, or the meshes of named bodies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo