Commit Graph
284 Commits
Author SHA1 Message Date
Irakli Kourtis 5fa8e7d60a Sweep: orientation, twist and end scale (#1269)
Part of #771 and #772. solid.sweep and surface.sweep take orientation (perpendicular, parallel or a direction), twist (up to 4 turns) and end scale (0.01 to 100), applied about the profile's normal through the path's start; default options run the old sweep, so existing sweeps are unchanged. New fields are optional, left out when unset and noted under format 21; twist and scale are model parameters. Both sweep dialogs get Orientation, Twist and End Scale rows; labels in every catalog. Checked on main + this branch: cargo check --workspace, kernel/engine/UI sweep tests, the doc suite and the robustness goldens.
2026-10-15 06:24:31 -04:00
NOWN-DEV d824d36821 Convert to Sheet Metal takes bent parts as modelled: radius and chamfer bends, holes (#1314)
A Convert to Sheet Metal bend point can now lie on a bend modelled with its radius (a cylinder tangent to two flat faces) or in the middle of a chamfer; either becomes one bend at the faces' virtual sharp, with the rule's radius. Holes and engravings carry over. Bend points on edges convert as before. Recorded under format 21. Tests in cmd::sheet::convert_tests; the sheet-metal guide is updated.
2026-10-15 02:54:09 -04:00
bherbruckandClaude Opus 5.5 9eddb1cbd3 Preferences ▸ Graphics ▸ Display quality (Coarse/Normal/Fine/Ultra) (#1287) (#1319)
* Preferences ▸ Graphics ▸ Display quality: Coarse, Normal, Fine, Ultra (#1287)

A viewing preference that sets how finely the viewport tessellates curved faces and edges:
chord tolerance relative to each body's size (3e-3, 1e-3, 3e-4, 1e-4) and the most a facet may
turn (30, 20, 12, 7 degrees). Normal is the tolerance the viewport has always used.

Bodies keep a display plan per level, so switching is a re-plan the first time and instant
after; the reference mesh the model reads (picks, holes, measuring) and exports are unchanged.
Away from Normal the model scene builds edges, and faces on the CPU path, from the plan at that
level, so silhouettes and edges get finer with the faces and a highlight still lies on the
displayed triangles.

The preference is saved with the others, set over the control channel (`ui.prefs`
`display_quality`), labelled in en/de/ja/ko/zh. `solidcraft-cli bench-open --display LEVEL
[--edit NAME EXPR]` times the plans at a level and after a parameter edit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Highlighted edges follow the display quality too

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 02:06:49 -04:00
Karl Von RichterandKarl-VonRichter 1ec33fcdc7 Extrude: a symmetric distance is the total thickness (#1260)
A symmetric solid extrude of 10 mm is now 10 mm thick, 5 mm each side of the sketch plane, and switching from One Side to Symmetric keeps the thickness entered. Under format 21 the extent records its convention; designs saved without it keep the per-side reading, so their geometry and parameters don't change. Fixes #1236.

Co-authored-by: Karl-VonRichter <Karl-VonRichter@users.noreply.github.com>
2026-10-15 01:19:55 -04:00
bherbruckandClaude Opus 5.5 5c2fa3e9ca Action matrix regressions of #1255: knuckle rounds, thin holes, a 45° flange hole, an axis after an edit (#1280)
* Action matrix regressions of #1255: knuckle rounds, thin holes, a 45° flange hole, an axis after an edit

- Curve blends: past the end of a curved edge the run of sections along the end
  tangent wrapped round the ring of centres; it is shortened while it still
  crosses the end face (the hinge knuckle's cap rounds at 0.728 mm).
- Boolean retry guard: each body's volume is measured finer than its smallest
  radius, and a volume out of bounds is measured again ten times finer before
  it refuses (a 0.133 mm drill measured -30272 mm³; a plastic part's coarse
  mesh was off by more than the slack).
- Sheet metal: a drill cap's certificate allows the evaluation noise its fitted
  tilt shows (a hole square to a 45° flange).
- Construction geometry on a named face uses the face found by name, not a
  second pick at its nearest point (an axis through a corner round after a
  parameter moved it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Retry guard: measure the target, tool and result at one tolerance

Measured at different tolerances, the chords' error on the faces they share
didn't cancel: a blind hole in a long D-profile bar measured 20 mm³ more than
the bar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Action matrix baseline from this branch's full run: 37 actions pass again, none fewer

Blessed with cargo xtask action-matrix --from DIR --bless from the 16 shards of
run 38673859774.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 00:24:27 -04:00
JIJINBEIandjijinbei 464a6dfad4 Feature walks: generate them from field roles with #[derive(Walk)] (#1251)
The three walks over a feature (expressions, references, geometry) are generated from FeatureKind by #[derive(Walk)] in a new proc-macro crate, solidcraft-derive, from #[walk(...)] attributes written next to each field. The hand-written walks in params.rs, feature_refs.rs and feature_geometry.rs are gone; Ruled Surface and Extend have their attributes, and the three golden walk records are unchanged.

Co-authored-by: jijinbei <jijinbei@users.noreply.github.com>
2026-10-15 00:13:53 -04:00
Irakli Kourtis b4edf05373 Extend any surface: natural, tangent and curvature, up to a target (#760) (#1166)
Extend works on any surface: natural (continuing the face's own surface), tangent (G1 run-off) or curvature (G2 run-off), by a distance, up to a plane or face, or back to the surface's bounds, with neighbouring edges lengthened to meet. Untrim and Extend share face parameter-loop helpers. The new SurfaceExtend fields are noted under format 21. Closes #760.
2026-10-14 22:46:29 -04:00
DuBearte 784648af2a Loft: refuse a section with a hole instead of filling it (#1184) (#1254)
A loft section with a hole is refused with a clear message instead of being lofted as if filled, in both section-to-section and section-to-point lofts. Fixes #1184.
2026-10-14 22:34:43 -04:00
Irakli Kourtis 2a4907884b Ruled Surface: strips off an edge chain, exact where possible (#762) (#1151)
Ruled Surface: strips off an edge chain in normal, tangent, angle or direction mode, exact planes/cylinders/cones where possible, mitred or round corners, stitched into one surface body. SurfaceRuled is noted under format 21. Closes #762.
2026-10-14 21:44:56 -04:00
Irakli Kourtis 16c49c3e86 Untrim: holes removed and a face restored to its natural bounds (#1150)
Adds surface.untrim (#761); the SurfaceUntrim feature is first saved in format 21.
2026-10-14 20:29:25 -04:00
NOWN-DEV 5c6f70cc00 Faces by name in the face commands; model.faces gives a point on each face (#1243) 2026-10-14 20:18:13 -04:00
NOWN-DEV 2cab09f65b Join keeps its tool exact where the tool ends in the part's faces (#1244) 2026-10-14 20:18:09 -04:00
selune a261aaa841 Render: integrated workspace, preview image jobs and opaque PBR (#1046)
Lands the Render workspace (R3), bounded preview-image jobs with cancellation and atomic PNG export (R4a), and opaque PBR looks as one change.

- Render workspace: an overlay-free product preview on the installed GPU device. Returning to Design restores its camera. render.scene and render.settings.apply are added.
- Image jobs: render.preflight/start/status/cancel/export run bounded CPU preview jobs. Export captures the job, overwrite choice and document, and checks the caller's file scope before writing.
- Opaque PBR: looks can carry metal fraction, roughness and dielectric IOR. The product viewport and preview PNG use them; geometry and mass are unchanged. The v1 catalog export refuses PBR rather than dropping it.
- Render setups and PBR looks are saved under design format 21. Labels are in en/de/ja/ko/zh/ru.

Supersedes #706 and #800. Refs #620, #673, #756, #1004.

Contributed by @0xlillith.

Co-authored-by: lillith <35337584+0xlillith@users.noreply.github.com>
2026-10-14 19:24:36 -04:00
Mateusz Sych 099d7e298a Degrees of freedom count closed loops (#1206)
Degrees of freedom count closed loops.
2026-10-14 18:46:46 -04:00
Lasse Lian a4a8b48567 Design properties: project, author and licence in the design, its exports and inspect_design (#1015) (#1189)
A design carries metadata (format 21): project, part number, revision, author, organization, description and license, plus other tools' data under reverse-DNS keys, kept as written. Edited in the Design Properties window (Document Settings), set by document.metadata.set, reported by inspect_design, and written into STEP, IGES and 3MF where the format has a place for them. Translated, with tests.
2026-10-14 18:25:35 -04:00
phanoob beb3ea01e7 Taper: the review of #1014 (spline sides follow their offset, no silent limits, face names kept) (#1204)
Taper: the review of #1014 (spline sides follow their offset, no silent limits, face names kept).
2026-10-14 17:55:58 -04:00
Mateusz Sych c715986a2a Motion links carry a value through a chain stored in any order (#1203)
Motion links carry a value through a chain stored in any order.
2026-10-14 17:55:54 -04:00
CamWight b6e87f0c44 Two tests pass on a Windows checkout: a CRLF parse and an 8.3 TEMP path (#1186) (#1211)
Make two tests pass on a Windows checkout: a CRLF parse and an 8.3 TEMP path.
2026-10-14 17:36:07 -04:00
selune 289b521a65 Render R2: persist named render setups without re-evaluating geometry (#667)
render.settings.set saves validated named render setups (camera, output size, exposure, environment) as one undo step, and render.settings.get reads them back without applying a camera. When validated render settings are the only change, the engine keeps the evaluated model instead of rebuilding it. Setups are saved under design format 21; format-20 designs read as having none. Fixes #658; refs #620.

Contributed by @0xlillith.

Co-authored-by: lillith <35337584+0xlillith@users.noreply.github.com>
2026-10-14 17:11:39 -04:00
bherbruck 229de1484c Hide and show joints in the browser, like other items (#1168)
Fixes #1160.
2026-10-14 15:04:57 -04:00
bherbruckandClaude Opus 5.5 a6fbc63746 Opening a design shows the model built so far (#1158)
A large design showed nothing but a progress bar until it had rebuilt completely. While
it rebuilds, the evaluation now offers the model built so far (placed as the design
places it) every 1.5 s to a window that asks, and the open card draws it as a small
picture on a thread of its own, the way it shows a saved preview. The bodies' meshes
made for it are the ones the finished model shows, so little is done twice. A design
that opens within the first interval shows none.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:45:14 -04:00
Karl Von Richter 9a4e8fbd19 Sketch: associative, editable sketch patterns (#1103)
Rectangular and circular sketch patterns stay linked to their source: editing the pattern's count, spacing or the source geometry updates the copies, and the copies keep their point and radius relations. Patterns are saved under format 20; older designs keep their independent copies.
2026-10-14 14:09:37 -04:00
NOWN-DEV c3aae64a63 Sheet metal: a cut-out with a corner a hair beside a bend line refolds (#1095)
Edges shorter than the model tolerance are dropped from the flat cells, and the refold sews touching corners, so a cut-out across a bend line no longer fails with a degenerate edge.
2026-10-14 13:59:07 -04:00
bherbruckandClaude Opus 5.5 6de8f6db95 Agent-built designs: stop redoing whole-design work on every command (#1148)
A design built over MCP is many small commands, and each one did work over the
whole design, so building or showing a 1,300-body design took minutes:

- moved components were transformed and meshed again after every change; world_state
  now reuses each placed body whose definition and placement are unchanged
- next_d_name searched the design once per candidate number
- Document::eval evaluated every parameter for every expression; now only when the
  expression names one
- param_rows' used_by was quadratic; the desktop no longer gathers completions on every
  change while no text box has focus

solidcraft-cli bench-agent builds a generated ~1,300-body bicycle command by command
and times it (241 s -> 16 s here). Eval output is unchanged apart from timings.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:48:39 -04:00
Mateusz Sych 94faf9ce1b Close kinematic loops: driven joints move four-bars and sliders (#1141)
Driven joints now solve closed kinematic loops, so a four-bar or slider-crank moves as a whole when one joint is driven.
2026-10-14 13:40:16 -04:00
JIJINBEI 1a456d2d1f One walk over the geometry a feature holds (3/3, #876) (#1028)
Moves the per-feature geometry handling (transforms, face points, profile selections, point expressions) into one geometry walk in feature_geometry.rs, with a golden record of what each feature kind moves. sheet.perforate holds no world geometry and joins the no-op arm.
2026-10-14 13:29:31 -04:00
Jonas Wrede 54a8c807bf Sheet metal: sheet.perforate, a perforation field exported to the flat pattern and DXF (#732) (#1041)
Adds sheet.perforate: round holes on a staggered or square grid over the flat sheet, kept clear of edges, cut-outs and bend zones. The holes go to the flat pattern, the DXF and the measured volume rather than the B-rep, so a panel can carry many thousands of them.
2026-10-14 12:43:31 -04:00
Lasse Lian 6df69e9def Thin Extrude: walls of a set thickness along sketch curves (#721) (#991)
Thin Extrude builds walls of a set thickness along sketch curves, open chains and closed loops, with the wall centred, inside, outside or on both sides at two thicknesses. Saved under format 20 (thin on an Extrude); an extrude without thin saves as before. Closes #721.
2026-10-14 11:46:16 -04:00
JIJINBEI 86ea018d05 One walk over a feature's references (2/3, #876) (#988)
Part 2 of #876: one walk over the references a feature holds (the sketches it's built from, the features it names, the bodies it works on) replaces three hand-written matches, with a golden record covering every variant.
2026-10-14 11:14:25 -04:00
Thodoris Tsagkogeorgas 110d00d07e A fillet of a vanished edge says the name is gone (#775) (#1066)
A fillet or chamfer whose picked edge no longer exists now says the edge's name is gone instead of failing on an unrelated edge (#775).
2026-10-14 11:06:11 -04:00
Yuu 1e1722b7e1 doc: keep a level piece's number when its centre's low bits move (#1073)
Pieces that share a name are numbered by where their centres lie. Two pieces lying almost level along the sort axis no longer swap numbers between runs because of noise in their centres' last bits, so a saved name keeps pointing at the same piece. Closes #569.
2026-10-14 10:58:04 -04:00
Lasse Lianandnekomario28 1ac8bf4aa8 Repair next_id and reject duplicate ids on load (#1050)
Loading a design raises next_id above the largest feature, component and occurrence id, so a missing or stale value can't hand a new item an id already in use, and duplicate ids are rejected as a damaged design. Id allocation uses checked_add, so an exhausted id space is an error instead of a wrap or a panic.

Part of #1016 (points 1, 2 and 4). nekomario28's #1061 reached the same fix independently; thanks to both.

Co-authored-by: nekomario28 <nekomario28@users.noreply.github.com>
2026-10-14 09:55:53 -04:00
phanoob 4dbc0efff9 Taper any profile, sketch text included (#1014)
A tapered extrude now offsets spline and conic curves as well as lines and arcs, so sketch text and any other profile can take a taper, and the join of tapered letters onto a face finds its boolean result.
2026-10-14 09:47:44 -04:00
Lasse LianandSychPL ec8e739aad Export a design's timeline as a replayable command script (#1045)
timeline.export_script (and solidcraft-cli script) writes a design's history as a command script that solidcraft-cli eval replays into the same design, so a bug that only shows on one design becomes a one-file repro. timeline.add restores one stored feature with its id, names and references, through the same checks a design file gets when it opens.

Closes #886. SychPL's #1078 approached the same issue independently; thanks to both.

Co-authored-by: SychPL <SychPL@users.noreply.github.com>
2026-10-14 09:06:24 -04:00
bherbruckandClaude Opus 5.5 75f1cdd4c9 Hovered and selected faces light solidly again over GPU-drawn bodies (#1064)
Since the model's mesh went back to the reference mesher (#940), the GPU viewport drew
opaque bodies from their display plans while hover and selection lit faces with the
reference mesh's triangles. Two triangulations of the same face at equal depth fought, so
a hovered face shimmered in wedges instead of lighting whole.

Faces lit over a body drawn from its plan now use the plan's own triangles
(ModelBody::plan_mesh, evaluated once on the CPU), and the highlight pass gets a small
depth bias toward the eye so f32 rounding between the GPU and CPU evaluations of the same
triangles cannot speckle it either.

Test: every face of a box with a pocket and a round boss, hovered and rendered offscreen
through the viewport's real pipelines on the GPU path, lights the same pixels as on the
CPU path (skipped without a GPU adapter).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:56:35 -04:00
seluneandbherbruck 52fb5ac0e6 feat: query directional elastic modulus from validated material cards (#998)
* feat: validate physical material cards with sources and conditions

* feat: query directional elastic modulus from physical material cards

* fix: register physical material validation labels in complete locales

* fix: register directional elasticity labels in complete locales

* Add German and Korean labels for the material property commands

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-10-14 08:17:00 -04:00
377e12a059 A modelled thread that would cut nothing is refused (#995) (#1018)
* fix: a modelled thread that would cut nothing is refused (#995)

An M5 modelled thread in a 5 mm hole cut nothing into the nut: the
internal groove runs from the minor diameter out to the major one, so
with the hole as wide as the thread it lay entirely in the hole, and the
faceted cut only left the wall faceted with slivers ("the thread goes the
wrong way"). The fit check takes a 5 mm hole as an M5 hole.

- thread_groove measures how deep the groove cuts into the material
  (hole wall out to the major radius, or shaft surface in to the root);
  under a quarter of the basic depth 5H/8 the modelled thread is refused
  with the measured depth, the tap drill (as solid.hole drills it) or
  shaft size to use, and the size that fits the face, e.g. "this 5.00 mm
  hole is too wide for a modelled M5 thread: it would cut 0.00 mm of the
  thread's 0.43 mm depth; drill 4.2 mm for M5, or thread this hole M6".
- Cosmetic threads and their fit check are unchanged.

* test: pin the cut-nothing limit for coarse and fine pitch; show the hole size with show_mm

---------

Co-authored-by: MateuszSychXpl <151755914+MateuszSychXpl@users.noreply.github.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-10-14 08:16:55 -04:00
NOWN-DEV 0f4cda0510 Convert to Sheet Metal takes a long thin plate (#1040)
Convert to Sheet Metal without bend edges refused every plate whose bounding-box diagonal reached a thousand times its thickness ("no outline on that face"), and just under that limit a hole smaller than the mesh's sag fell out of the outline and the DXF. The outline's tolerance is now at most a tenth of the thickness: a thin plate is meshed again at that tolerance. Nothing new is stored. Tests: long thin strips, sheets thousands of times longer than thick, and a strip keeping holes down to 1 mm.
2026-10-14 08:12:41 -04:00
JIJINBEI 3341e2d60b One walk over a feature's expressions (1/3, #876) (#902)
inputs_mut, inputs and expressions are now built on one exhaustive walk (walk_exprs / walk_exprs_mut) instead of two hand-written matches over FeatureKind. inputs() no longer clones the feature, plane chains are walked with the same nesting cap for inputs as for expressions, and a new variant without a walk arm does not compile. A golden record of every variant's expressions guards the walk.
2026-10-14 08:11:03 -04:00
selune 01f2c78cd1 Validate sourced physical material property cards and elastic stability (#934)
Adds the read-only material.properties.validate command: schema_version 1 engineering material cards in SI units are checked for numerical consistency and elastic stability, with derived isotropic moduli, missing conditions and sources needing review. Nothing is assigned or saved.

Thanks @0xlillith.
2026-10-14 05:28:18 -04:00
bherbruck 2f91338d3d Large STEP imports: no more multi-minute hang, shared STEP text, cancel and progress (#925) 2026-10-14 05:01:12 -04:00
Mateusz SychandSychPL cf9d7772f1 To / From Object finds a target in another, moved component (#993)
Fixes #928. Extrude To / From Object and Revolve To Object now resolve their target in the feature's own component frame, so a face in another component whose occurrence is moved is found where it is shown instead of the extrude stopping at a flat plane through the picked point. The point is named after the nearest face, a named point keeps its named face when another component touches it there, and such features re-evaluate when a placement changes, so they follow the target when it moves later.

Co-authored-by: SychPL <SychPL@users.noreply.github.com>
2026-10-14 04:41:59 -04:00
midasdfandmidasdf 6e84c03946 Curvature-continuous (G2) fillets for straight planar edges (#862)
Fillet gets a Curvature (G2) radius type (type: "curvature", alias "g2"): a quintic blend whose size is the equivalent circular setback, for convex and concave straight edges between planar faces with a perpendicular planar end face at each end. Unsupported cases are refused rather than falling back to a circular fillet, and a blend that would cross a loop in its end face is refused. Persisted as a fillet style under format 19; labels in en/de/ja/ko/zh.

Co-authored-by: midasdf <midasdf@users.noreply.github.com>
2026-10-14 04:26:53 -04:00
NOWN-DEV 6a67cc8f1e An edge flange folds beside a ledge as tall as its setback (#978)
Trimming the base at an edge flange's setback snaps corners within tolerance onto the trim line and merges away the zero-width run a ledge as tall as the setback left along it, so the ledge goes with the strip as a lower one does. Splitting outline edges at other cells' corners now skips points within the model's tolerance of an end, so a ledge a little taller keeps its sliver and the bend runs under it, also off the axes. Both used to fail with "sew: a degenerate edge". Nothing new is stored.
2026-10-14 02:51:29 -04:00
bherbruckandClaude Opus 5.5 6cb3025b72 Sheet metal: a hole drilled into a rim is a bore its panel keeps (#560) (#955)
A hole drilled along a panel, into its rim, has no place in the flat pattern
as a cut-out, so every such hole was refused. It is now kept as a bore of that
panel, in flat coordinates, and cut only from that panel's material when the
folded part and its flat pattern are built, so the sheet still unfolds and
folds back with it. A hole that would run into a bend, or cross a panel at an
angle, is still refused. The flat pattern lists the bores.

The action matrix worker takes ACTION_MATRIX_ONLY (just these actions) and
ACTION_MATRIX_UNFOLD (unfold and refold every sheet after each action) for
rechecking one group by hand.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 02:31:19 -04:00
bherbruckandClaude Opus 5.5 b34d45233d Holes on round faces from the app, and Flip for holes at sketch points (#980)
* Holes on round faces from the app, one hole per pick, and Flip for holes at sketch points (#967)

The Hole dialog takes any face: a hole on a round face drills against the face's normal where it
was picked, and its arrow shows that. A round face split at its seam is picked whole, but makes
one hole where it was clicked. Holes at sketch points get Flip (saved as flip in the hole's points,
under format 18), in the command and in the dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Holes at sketch points show their arrow: into the part, or away with Flip (#967)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 02:10:09 -04:00
Karl Von Richter 47a7f29485 Guide sketch patterns with live previews and editable offsets (#966)
Sketch Mirror, rectangular and circular Pattern, and Offset now show a green live preview that follows the selection and settings; OK commits, Cancel leaves the sketch unchanged. The shared dialogs show the current selection step and source counts, sources can be toggled with Ctrl/Cmd-click, cleared and reselected.

Offsets keep editable driving distance dimensions (One Side, Two Sides, Symmetric) that update the derived curves without moving the source, with undo/redo and save/reopen. Format 19: older files keep their fixed offsets.

New dialog labels in en, zh, ja, de and ko.

Fixes #696. Fixes #517.
2026-10-14 01:58:01 -04:00
NOWN-DEV 4687e3b073 Convert to Sheet Metal keeps a plate's round holes round (#977)
The plate check compared the face outline's area (from the tessellation, so each hole was a polygon of chords) with the exact volume, and refused plates with a few small holes. Where the outline runs along a cylinder about the plate's normal it is now an arc of that circle; coaxial pieces of one radius are one wall, so a hole split into two, three or four faces is one circle. The check passes with its tolerance unchanged, and the flat pattern and its DXF carry one CIRCLE per hole (ARC for rounded corners and slot ends).

A round blank now converts too, so unfold_cut_refold_and_convert checks the refusal with a block thicker at one end instead of a rod.
2026-10-14 01:47:40 -04:00
bherbruckandClaude Opus 5.5 1ff16cc72b A hole on a face drills into the material, also in older designs (#950) (#952)
* Hole matrix: placement, types, extents, edits and 0.9.0 designs, with today's failures listed

Each case checks the drill goes into the material, the bore sits on its axis, a blind hole stops
where it should, the removed volume against its analytic value, the face count and that every
body is still one closed valid solid. Failing cases are listed in tests/hole_matrix/known_failures.txt
as a ratchet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* A hole on a face drills into the material, also in older designs (#950)

Without a direction, solid.hole took the direction from any face whose infinite plane passed
within ten tolerances of the point, the last one found winning: the far side of a thin plate or a
face of another body at the same height could set it, and the wrong direction was saved. It now
uses the face nearest the point, against its outward normal (exact for planes, cylinders and
spheres, so holes on curved faces work without a direction). When a design is evaluated, a face
hole whose saved direction leaves the face it starts on is mirrored into it, so designs saved
with the wrong direction drill into the part.

Fixes #950.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole at a point on no face (a planar face's centroid outside it) keeps the plane it lies in

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Record the hole direction fix in the goldens and the action matrix baseline (#950)

Seeds 7, 21, 81 and 85 drill their holes straight into their faces now. In the action matrix,
holes on four faces that used to go the wrong way now build, and two whose correct direction
meets a cut the kernel refuses are marked failing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Goldens: seeds 7, 21 and 85 drill their holes straight in (#950)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:45:11 -04:00
7bed28752e Sheet metal: fold a second tab on a line, and a tab on an L's inside edge (#638, #639) (#963)
- A fold's zone clipped across the root of a tab folded before on the same
  line kept a sliver of no width there, which made the zone look like it
  crossed a slanted edge. The one real piece is the zone now (#638).
- When the tabs a fold line spans can't take the side beyond them along,
  because it joins the side that stays through other material (a tab on the
  inside edge of an L, the fixed point on the far leg), the tabs' own ends fold
  instead, the same part as with the fixed point on the near leg (#639).

Co-authored-by: jonaswre <3731681+jonaswre@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:16:04 -04:00