Static, frequency (per mode), nonlinear and explicit (per frame, with a
.pvd collection) and heat results; fluid steps are refused. Wedges keep
the model's node order: VTK 9's wedge has the same orientation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
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 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
A node on the secondary surfaces of two ties (a chip's underside and its
sides, a cut face and an outer face) got one constraint per tie. When the
main nodes of one follow the other's main surface, the second constraint is
nearly the first again, and eliminating it divided by round-off: the Pi 5
heat model put 21.9 W more in than its 8 W. Such a node now follows the
main faces of all its ties together (balanced to 5e-11 of the power), a
node following a node that follows it back (a tie each way on one
interface) is an error naming both ties, and a tie row that still nearly
repeats the constraints before it is an error naming them.
mesh.cells ties one way by a fixed order of the cells (hex main to tet)
and makes one tie per tied cell, tie_<cell>, replacing the ties an earlier
run made, so its own ties never hold a node twice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
hex_mesh_swept_cells lays out one cross-section for several cells: every
cell's walls (its cut faces included) are imprinted together, every cell's
levels are levels of all, one interval assignment and one set of layers,
and each region of each level interval is filled by the cell it lies in.
Cells meet node for node across every cut, T-junctions included.
mesh.cells sweeps the cells of each design body together first and meshes
cell by cell only what does not sweep together (saying why); the reply
gives every cell's volume, scaled Jacobian and edge ratio.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
Four triangles round a point (a square cut along both diagonals) share their
free half-diagonals in pairs, so those alone cannot make every loop even when
the square's perimeter is odd; the parity repair kept raising them until the
step cap. A loop that keeps coming back now lets its coupled curves move.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo