Commit Graph
15 Commits
Author SHA1 Message Date
phanoob 9bb65b4d68 Booleans: a prism cut beside the target's other faces takes the exact 2D route in a column (#1629)
Thanks @phanoob.
2026-10-16 03:26:13 -04:00
Erikas 17b48d9e7e Booleans: planar cuts beside rounds take the exact route before the retries (#1197) (#1445)
Planar cuts beside rounds take the exact route before the boolean retries (#1197).
2026-10-15 13:31:41 -04:00
bherbruckandClaude Opus 5.5 4b3b48388c Modelled threads: shuffle the faceted boolean's polygons before the BSP (#1250) (#1395)
The groove's facets came in sweep order, and the BSP takes each list's first
polygon as its splitter, so the tree was as deep as the list: quadratic time and
memory. An M8 x 60 mm thread ran out of tree depth after 12.9 GB. A fixed shuffle
gives a shallow tree and the same result (volume and faces equal to 1e-9).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:53:15 -04:00
bherbruckandClaude Opus 5.5 a3dfbaa0b0 Booleans build the same body every time: face order no longer follows heap addresses (#748)
truck's face and edge IDs are their addresses, so walking maps keyed by them followed heap layout, and the ribbed lid's side-wall hole passed or failed by chance. The planar boolean's rebuild and glue now take truck's connected components in the shell's order, and the planar boolean's own maps are ordered. Healing's union-find keeps the lesser root and takes a run's ends in order of use. The face classification after an intersection orders each component's faces by the shell first. The lid now builds the same body on every run, with a test that builds it six times in one process. Its 0.5 mm side-wall holes, and one sensor enclosure hole of the same kind, now fail every time and are marked failing in the baseline.

Fixes #707.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:31:23 -04:00
bherbruckandClaude Opus 5.5 add4a18961 fix: fuse bodies that touch back to back over part of a face (#679, #674) (#704)
Two L's extruded up and down from one 2 x 2 grid now join into one solid (the planar rebuild gives each fan of faces around a pinched vertex its own vertex copy), and a pad whose end lies half past the edge of the face it stands on fuses exactly: contact faces are imprinted with each other's outline and the common faces glued away, still held to the retry guard. Face splitting handles a line crossing an edge twice; glue matches differently parametrised curves and keeps several pieces apart. Robustness seed 16 now fuses with the exact volume.

Fixes #679, fixes #674.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:02:44 -04:00
bherbruckandClaude Opus 5.5 29258767ce fix: refuse Boolean retries that change the part away from the tool (#616) (#644)
Joining ribs flush with a lid's window left a zero-thickness slit far from the rib (the planar fallback glued back only one of the faces its pieces shared) and displaced the tool on the other joins. Gluing now joins every shared face pair, coincident-face separation checks there is material behind a pushed face for every join, and any join or cut that needed a retry must be closed, keep volume monotonic and leave the part unchanged outside the tool's box, or it is refused with an error. Feature command replies carry the feature's warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 07:10:29 -04:00
bherbruckandClaude Opus 5.5 296683229d Rename SolveCraft to SolidCraft everywhere, with compatibility shims (#389)
* WIP deep rename (not for push)

* WIP2

* WIP3

* WIP4 wxs fix

* rustfmt

* Rename the remaining identifiers in merged crash-report code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:17:01 -04:00
Iraklis KourtisandClaude Opus 5.5 43ddde4a5d feat(kernel): an edge's meeting sides are sets of origins (merged faces)
EdgeOrigin::Meet now names each side as a Side: the sorted, de-duplicated
origins of the face there. substitute maps a side to the union of the inner
faces' origins, so a meeting with a face an inner operation merged keeps its
lineage; meeting() derives sides from whole faces. Fillets after box cuts
that leave coplanar pieces now report exact history. Prism lineage meets a
cap of several origins and resolves wall junctions away from shared
vertices by the operand's one edge between the walls. bore_union's recut
reports history only for a one-face bore (pieces of a two-arc bore's recut
wall were given both arcs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J53sR6gEaVt56soFDpTck8
2026-10-12 11:52:53 -04:00
Iraklis KourtisandClaude Opus 5.5 d5cb276965 feat(kernel): every boolean path reports exact face and edge history
ops::boolean's result carries its history over [a, b] whichever path made
it, recorded by the code that builds the faces:

- truck path (incl. jitter retries): shapeops history mapped through the
  order-preserving copies and the cut's turned tool, then through healing
- heal records which input faces each healed face merges and which input
  edges each joined or exact edge replaces (HealMap); opt-in, so heal_keep
  callers pay nothing
- trivial shortcuts, the void, glue, faces pushed apart (push_faces records
  its own history; the slab cut back on a union maps to the operands'
  faces in that plane), the nudged retry, by_lumps and join composition
- prism booleans: section segments carry tags (operand cap edge, the wall
  beside it, its vertices) through the 2D boolean; walls, caps and edges of
  the extruded or sewn result follow from them
- planar and faceted polygon booleans: polygons carry their operand face;
  faces join the pieces across edges, edges come from the pieces either side

History gains renumber/over (and consuming forms) for composition;
record gains regions/traced/build helpers. truck-shapeops
*_with_history now return the solid with an Option history. Paths that
cannot report (bore narrowing via offset, inexpressible lineage) leave the
result without history. Boolean results, tolerances and fallback order are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J53sR6gEaVt56soFDpTck8
2026-10-12 11:52:53 -04:00
bherbruck 4e595deff2 feat: preserve adaptive sketch profiles and curved modeling workflows 2026-10-11 09:06:25 -04:00
CypherNaugh_0x 5073f5dd72 A failed boolean no longer blames "coincident faces on curved bodies" whatever the cause: the exact polygon fallback runs after any failed B-rep boolean (faces that touch, or cross at a shallow angle) and takes planar faces only, but its refusal named coincident faces and curved bodies regardless. It now says which operand is in the way and why: "the tool has 2 curved faces (cylinder)" (kinds: cylinder, cone, sphere, torus, freeform), a face that could not be meshed, a planar face whose mesh is not flat, or a mesh too detailed. Test: planar_fallback_names_the_curved_faces 2026-10-11 10:25:10 +02:00
CypherNaugh_0xandClaude Opus 5.5 3086c32a9a A round hole elsewhere on a body no longer breaks a loft cut beside it: a loft cut from a pocket floor (556.68 x 99 down 4 mm to 80 x 80), with a 35 mm hole 66 mm away that it never touches, failed with a kernel panic in TroughFall, while the same cut without the hole, or with the hole made afterwards, worked
The loft's top lies in the pocket floor. truck's boolean cannot take coincident faces, and the exact polygon fallback (planar_boolean) only takes bodies whose faces are all planar, so the hole's cylinder ruled out the only path that handles this cut. planar_boolean now first tries a sliced form: when an axis-aligned slab holds the tool and none of the body's curved faces, the body is split on the slab's planes (planes clear of the body's own faces), the planar middle piece takes the exact boolean, and the pieces outside are glued back on along the cut faces (the middle piece is healed first so its edges match theirs). Pieces in several parts are refused rather than glued into one shell. split_by_plane's half-space code is now ops::half_space, which this uses.

Tests: loft_cut_beside_a_round_hole replays examples/regressions/loft_cut_beside_round_hole.json and checks the exact volume (slab - pocket - prismatoid - hole; fails on main). With the hole made after the loft, the body is the same (volume, area, 19 faces, 42 edges).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:57:34 -04:00
bherbruckandClaude Opus 5.5 141a5fea8a Modelled threads (Thread with modeled: true): the ISO 68-1 profile cut along a helix, M3 to M20, on shafts and in bores; running out past a free end of the face, stopping square at a set length. The groove is a watertight screw-sweep mesh (kernel::sweep_helix_mesh) cut by kernel::faceted_boolean (BSP on the faceted body, tolerance ladder checked by A−B + A∩B = A); the polygon rebuild welds vertices across grid cells, splits pinched loops, finds T-junctions through a grid, and takes the group's plane for a loop a hair off flat
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
2026-10-09 12:47:56 +00:00
bherbruckandClaude Opus 5.5 ea3dd0ed6e 3MF: export, and 3MF/STL import as mesh bodies
Export: ExportCommand/CLI --out/MCP export with .3mf write a 3MF Core package
([Content_Types].xml, _rels/.rels, 3D/3dmodel.model; millimetres), one
mesh object and build item per body, named after it, vertices shared and
welded watertight (T-junctions between faces split), base-material colours
when bodies carry one (STEP colours now ride on bodies). Tessellation as
for STL. File > Export 3MF.

Import: doc.open/drag-drop/CLI/MCP open accept .3mf and .stl; Insert Mesh
(ParaMeshInsertAlignCommand) adds them to a design as a MeshImport feature.
Kernel mesh bodies render, measure exactly, move and export; solid
features refuse them with a clear error. 3MF reading flattens components
and build transforms, converts units, reads colours; sizes, entries,
nesting and element counts are capped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
2026-10-07 21:30:38 +00:00
bherbruckandClaude Opus 5.5 d585afd006 M2: exact planar boolean fallback for coincident faces (BSP polygons rebuilt into B-rep)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
2026-10-07 19:22:27 +00:00