Commit Graph
20 Commits
Author SHA1 Message Date
jyvikoandClaude Opus 5.5 b62be1ada6 engine: mesh.size.* commands, honoured by every mesher (#435)
mesh.size.set adds a size control on faces, bodies, a box or a sphere;
mesh.size.growth sets the growth rate; mesh.size.clear and
mesh.size.list. The tet mesher bakes the controls into its graded field,
the hex meshers, cells and the octree take the graded RegionSize, and
the block projection and mesh plans divide their edges by it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 17:08:27 -04:00
jyvikoandClaude Opus 5.5 a2e747b9ba mesh: projection and relaxation keep to a merged face's B-rep pieces
A merged face on several surfaces (a sliver absorbed into its neighbour)
had no exact surface, so the projection target fell back to its
triangles: flat curvature probes gave fewer divisions round the boss and
the enclosure base's symmetric mesh dropped from 0.70 to 0.51 once its
absorbs reached the cells. The target now projects a point of such a
face onto the exact surface of the B-rep piece it is on, trimmed to that
piece (Tessellation::with_pieces, Shape::tessellate_pieces); node
relaxation slides on it the same way.

Test from commands: the enclosure base's four slivers absorbed, meshed
whole and by symmetry, the absorbs kept in every cell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 15:25:37 -04:00
jyvikoandClaude Opus 5.5 cb4141d0f0 testkit: run the meshing skill on the corpus and samples (cargo xtask skill-results)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 14:57:51 -04:00
jyvikoandClaude Opus 5.5 bb3def1cf5 mesh.plan: decomposition proposals for unmapped features
For a body with features the sweep cannot mesh, mesh.plan replies a
decomposition: the cuts that box those features into one cell, the region,
and the commands that make the cuts and mesh the cells with pyramids. A plate
with a joined dome: 5 cuts, 17 hex cells swept together, the dome cell tet,
valid and conforming, end displacement in tension within 0.4% of all-tet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 14:57:41 -04:00
jyvikoandClaude Opus 5.5 793fbe3b71 mesh: corner copy keeps the best of several cuts, its corner taken from the whole cell's mesh
The whole cell is meshed with its layout split at each candidate cut and
the sheets there held planar (ProjectOptions::planes); the corner of the
best is added as the low cell's mesh with the whole mesh's face tags,
mirrored, and the middle meshed round it. Accepted only when the corner
and the middle are no worse than the cell meshed whole; else the cell is
meshed whole and corners.skipped says why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 12:07:04 -04:00
jyvikoandClaude Opus 5.5 db0f0567a0 mesh: the corner copy takes the corner from the whole cell's mesh, sheets at the cuts held planar
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 12:07:04 -04:00
jyvikoandClaude Opus 5.5 fea61fb180 mesh: a symmetric plan copies one corner onto the other (#474, #491)
With symmetry, when the fundamental cell's two ends along another in-plane
axis are alike (layout planes and surface mirror-symmetric), the cell is
cut midway into the next block sheet and at its image; the low corner is
meshed with its blocks, mirrored onto the high one, and the middle meshed
with both cut faces fixed (#490). A plan cell's cut faces another cell's
mesh covers are taken as given. corners: false opts out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 12:07:04 -04:00
jyvikoandClaude Opus 5.5 ce02d263c7 engine: geometry.faces.merge, faces meshed as one (virtual topology, #505)
geometry.faces.merge {name, faces} records a face merge in the model;
it is applied after the partitions whenever the design is opened or cut
again, undoes through the journal and is saved with the model. Meshers,
mesh.plan (features and rings see merge:<name>; a merged face is
prismatic when its B-rep faces are), checks and the viewport see one
face, drawn in the warm colour. geometry.faces.merge.delete removes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 11:09:11 -04:00
jyvikoandClaude Opus 5.5 d5fb100182 mesh.plan.apply: name the faces of the meshed bodies left untagged
The reply's untagged_faces lists every face of the plan's bodies no
element face carries; the acceptance checks require it empty, and a
symmetric filleted base checks a set by every face of every cell (#494).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 10:38:31 -04:00
jyvikoandClaude Opus 5.5 7c3107dec0 mesh: a crank arm's plan takes rings round its bosses and a pillow from a carved grid (#455, #190)
When the grid layout does not fit a swept body (sides at an angle to the axes, root arcs where
an arm meets its bosses), mesh.plan tries the ring-and-pillow layout (cmd/plan/pillow.rs): each
boss is an annulus from its bore or pedal hole to its circle through every level, the arm a grid
carved a margin inside the outline and the bosses, with a pillow layer of blocks to the wall each
boundary face faces; a grid corner facing a boss and the outline gets a corner block reaching the
kink where the outline leaves the boss's circle. The old crank test (frame cuts) becomes the
heavy acceptance test at sizes 2.5, 3 and 4; the moved frame cut keeps a unit test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 10:38:26 -04:00
jyvikoandClaude Opus 5.5 eae709b3c0 mesh: a body the user's partitions cut is not meshed by symmetry (#473)
With a user's partition on a symmetric body, applying the whole body's plan cut it again by its
symmetry plane and mirrored one cell, leaving the other half unmeshed ("the mirror images do not
reach cell Base/b/a"). Such a body is its cells: the symmetry is not used and the plan is refused
with the cells named, as the replay of the saved Pi 5 model shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 07:56:10 -04:00
jyvikoandClaude Opus 5.5 80da2d968b mesh: applying a whole body's plan to a body partitions cut says to plan a cell (#473)
After geometry.partition cuts a body, the body is its cells: a projection plan of the whole body
could not open it and failed with "no body `Base` (open a design first)". It now names the cells
and says to plan and apply a cell (mesh.plan {"body": "Base/a"}) or delete the partitions. Tests
cover a design opened directly and a saved model opened again, partitioned after opening.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 07:56:10 -04:00
jyvikoandClaude Opus 5.5 b905f1bc89 mesh: a projection plan meshes a symmetric body by its symmetry; partitioned bodies and cells plan (#473)
mesh.plan.apply finds the planes a projection plan's body is its own mirror image across
(through the middle of its extent, square to the sweep's in-plane axes, through no ring: every
triangle middle of its tessellation, a little inside and outside, has its mirror image inside and
outside alike). It cuts the body by them, plans and meshes the cell on their negative side, and
mirrors that mesh across each plane in turn (mesh.mirror, joined node to node on the planes), so
mirror-image regions mesh exactly alike. `symmetry: false` meshes the whole body.

A cell of a partitioned body is planned from the features that built its body, with the rings it
holds; a partitioned body is planned whole as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 07:26:28 -04:00
jyvikoandClaude Opus 5.5 47e92eebb1 mesh: a plan's frame cut on an opening's end face moves one element out of it (#455)
The crank arm's back pocket ends on the planes x = 48 and x = 130, its frame sides. The plan
put its frame cuts there; the kernel cannot cut along a face (#427), so both were skipped and
the cell between the bosses swept the pocket's rounded ends into fans. A frame side on a face
of the body now moves one element out of the opening (away from the rectangle's middle),
leaving a strip one element wide; both cuts are made.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 03:59:29 -04:00
jyvikoandClaude Opus 5.5 bf61ae8406 mesh: smoothing visits nodes in their own order again (#402)
#462 visited nodes by a mirror-invariant key (distance from the centroid). On the cup with a
handle that order sweeps ring by ring round the axis and converges worse in its 100 sweeps: the
refined cup fell to a scaled Jacobian of 0.481 (needs 0.5, #440). In the lattice's own order
it holds, and the order gained the enclosure base little (its corners differ by 0.02 either
way), so it goes; the compass search's lift to 0.7 stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 03:42:47 -04:00
jyvikoandClaude Opus 5.5 4d6d69ee6d mesh: smoothing lifts elements up to 0.7 and visits mirror twins alike (#402)
The compass search after the sweeps only lifted elements below 0.5 (the quality floor), so a
mesh whose worst elements sat just above it stayed there: every corner of an enclosure base
stopped at a scaled Jacobian of 0.50-0.52 where its walls meet the corner bosses. It now lifts
every element below 0.7, never lowering another below the lower of its own value and 0.5.

The sweeps and the search are Gauss-Seidel, so the node order shaped the result and mirror
image corners smoothed differently. Nodes are now visited by a key that a mirror or a quarter
turn about the nodes' centroid keeps (distance from it, then the sorted offsets along the
axes). What spread is left between mirrored corners (0.686 vs 0.702 on the test base) is most likely the projection onto the body's
tessellation, which the kernel does not make mirror symmetric (not yet proven).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 03:05:43 -04:00
jyvikoandClaude Opus 5.5 0b7dda95f7 mesh: an enclosure's corner bosses are ringed where its walls join them (#402)
A boss the body's walls run into had its circle crossed by the walls' planes, so the projection
layout refused it and the plan fell back to swept cells, fanning round the boss and its hole.
Such a boss is now framed by the square round its whole circle, subdivided by the planes that
cross it; every square inside (the hole's, the core) is divided alike, so the ring's blocks meet
the walls node to node. On the walls' side the frame stops at their inner plane and its corner
projects onto the middle of the inner fillet, which the ring takes in (a boss just touching the
fillet included: no sliver). Cylinders a fillet's history names but that are a ring's circle are
the ring's faces. Rings are built per patch of grid cells, the one-cell O-grid being the
simplest patch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 00:29:24 -04:00
jyvikoandClaude Opus 5.5 92d49debec mesh: a screw hole's ring takes in the fillet of its rounded corner; frames centred on the hole (#402)
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
2026-10-15 22:43:02 -04:00
jyvikoandClaude Opus 5.5 d29334a7a7 mesh: mesh.plan.apply builds rings and fillet/chamfer blend layers as one projected block layout (#402)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 18:59:02 -04:00
jyvikoandClaude Opus 5.5 efe90ec50e mesh: geometry.features, mesh.plan and mesh.plan.apply from the feature graph (#402)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 16:38:51 -04:00