Repository navigation
Sheet metal: a perforation field bounded by a sketch's outline (#732) - #10754
Merged
Merged
Conversation
…ncy-labs#732) `sheet.perforate` takes an optional `sketch` (and `profiles`): the field's outline. Holes go only inside its closed profiles, out of their inner loops, `margin` clear of its edges, on a grid from the outline's lower-left corner. On a folded sheet the outline maps through each panel the sketch lies on and is clipped to it, so it never reaches a flange in the flat; a sketch on no face of the sheet is refused. A mirrored copy mirrors the outline, and an edit that names no sketch (the Perforate dialog has no outline) keeps it. Without a sketch the field covers the whole sheet as before. The feature saves `sketch` and `profiles`, a sheet's perforation its outline in flat coordinates: one pending format note, no migration. Assisted-by: LLM
bherbruck
enabled auto-merge
November 1, 2026 23:56
Merged
via the queue into
tangency-labs:main
with commit Nov 2, 2026
d7a17de
106 of 119 checks passed
This was referenced Nov 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change
Part of #732.
sheet.perforate(#1041) covers the whole flat sheet: a panel that is perforated in one area and solid elsewhere (behind a connector, around a mounting area) can't be modelled, and an extruded cut can't take the holes either (about 500 per sheet). #732 asks for "a perforation feature on a sheet face: field outline + hole shape + pitch/pattern"; this adds the outline.sheet.perforatetakes an optionalsketch(id or name) andprofiles(as a base flange takes them; default: all of them). Holes go only inside the selected closed profiles and out of their inner loops, at leastmarginclear of the outline as of the sheet's edges, cut-outs and bends. The grid starts at the outline's lower-left corner (within the flat), so the pattern can be placed.profileswithoutsketchis refused.region_to_flat) and is clipped to that panel, so an outline drawn on one face never reaches a flange in the flat. On an unfolded sheet it is taken as drawn on the flat. A sketch on no face of the sheet is refused.sketchandprofiles(walked like any profile selection, so deleting the sketch deletes the feature); the sheet's perforation keeps the outline in flat coordinates (SheetPerforation::outline), so it follows fold, unfold, refold and reopen. A mirrored copy mirrors the outline with the field (from_right).timeline.redefinekeeps the outline when the new parameters name no sketch (as it keeps a frame member's names). An outline sketch counts as used (sketch_consumed), like a base flange's.format/pending/sheet-perforation-outline.rs; no migration: a field without an outline covers the whole sheet as before.Not in this PR: an outline picker in the Perforate dialog, and centring the grid in the outline.
Changes a default: no
Validation
New engine tests in
crates/engine/src/cmd/sheet_tests.rs, next to the #732 ones:perforation_outline_bounds_the_field_and_keeps_out_its_inner_loops: Rv 1.0-1.5, margin 1, on a 100 × 60 × 0.8 sheet bounded by a 50 × 30 rectangle at (10, 10) less a Ø10 circle (the ring picked by a point). Expected 594 holes: the documented grid over the rectangle less those within 6.5 of the circle's centre. Measured: 594 inflat_patternand in the DXF, the first at (11.5, 11.5), none outside 11.5…58.5 × 11.5…38.5 or nearer than 6.5 to (35, 25). Atimeline.redefinewithoutsketchkeeps the count.perforation_outline_on_a_folded_sheet_stays_in_its_panel: an outline reaching past the bend of a 90° flange puts every hole on the base side of the bend zone (centre at least r + margin beyond it); a sketch 10 mm above the sheet is refused ("must lie on a face of the sheet").a_mirrored_sheet_copy_mirrors_its_perforation_outline: the mirrored copy's holes are the original's mirrored, relative to the field's corner, to 1e-6 mm.golden_refs.txt,golden_geometry.txt) and the fixture record the newsketch/profiles; thePerforateParamskey test lists them.Run on Linux x86_64 (Fedora 44, Rust 1.99.1),
--profile ci, on this branch rebased onmainat 653bc00:cargo xtask ci: fmt, assets, icons, licences, lists, skills, layering, UI containers,clippy --workspace --all-targets -D warnings, the wasm check and the doc tests pass. 81 of the 83 test binaries pass, among themsolidcraft-enginelib (3094 passed, 0 failed),solidcraft-doclib (516 passed) and the UIscenariostest (146 passed). The two that fail have failures unrelated to this change:solidcraft-gpulib: 28 of 165 tests, all path-tracer tests on this machine's AMD Radeon 890M (RADV). Onmainat 653bc00, 28 fail as well.solidcraft-ui-eguilib: 3969 passed and 2 failed.render_workspace::tests::progressive_image_controls_route_to_the_registered_hostis a path-traced render ("inconsistent glass medium paths") and fails onmaintoo.op_auto::tests::primitives_and_revolves_join_cut_or_stand_apartfailed only inside the full run; run alone, it passes on this branch and onmain.Rebased again onto
mainat e77c555 (see below):cargo fmt --check, the assets, icons, layers, UI containers, skills, lists and licences gates, andclippy --workspace --all-targets -D warningspass there;cargo test -p solidcraft-doc --lib: 521 passed,-p solidcraft-engine --lib: 3102 passed, and-p solidcraft-ui-egui --lib sheet perforat: 56 passed, 0 failed.Reproduction with
solidcraft-cli run, built frommainat 653bc00 and from this branch: the setup below, thensheet.perforateØ4 on a 6 mm staggered pitch, margin 1, andsheet.flat_pattern.sheet.perforatemainsketchsketch: "Field", the ring picked--param-check strict: "invalid parameters forsheet.perforate: unknown keyprofiles")Script (with the outline)
{"commands": [ {"command": "sheet.manage_rules", "params": {"name": "Steel 1.0", "thickness": "1 mm", "active": true}}, {"command": "sketch.create", "params": {"plane": "XY", "name": "Blank"}}, {"command": "sketch.rectangle.two_point", "params": {"p0": [0, 0], "p1": [200, 120]}}, {"command": "sketch.finish", "params": {}}, {"command": "sheet.flange", "params": {"sketch": "Blank"}}, {"command": "sheet.flange", "params": {"edges": [[100, 0, 1]], "height": 25}}, {"command": "sketch.create", "params": {"plane": {"origin": [0, 0, 1], "x_dir": [1, 0, 0], "y_dir": [0, 1, 0]}, "name": "Field"}}, {"command": "sketch.rectangle.two_point", "params": {"p0": [20, 20], "p1": [180, 100]}}, {"command": "sketch.circle.center", "params": {"center": [100, 60], "radius": 18}}, {"command": "sketch.finish", "params": {}}, {"command": "sheet.perforate", "params": {"diameter": "4 mm", "pitch": "6 mm", "margin": "1 mm", "sketch": "Field", "profiles": [{"point": [30, 30]}]}}, {"command": "sheet.flat_pattern", "params": {}} ]}Screenshots of the behavior (when observable)
Steps: a 200 × 120 × 1 sheet (base flange) with a 25 mm flange on its front edge; on its top face a sketch "Field" with a 160 × 80 rectangle and a Ø36 circle; Sheet Metal → Perforate Ø4 on a 6 mm staggered pitch, margin 1; Sheet Metal → Flat Pattern. Then the same feature redefined with
sketch: "Field"and the ring picked (profiles: [{"point": [30, 30]}]).Setup: the folded sheet and the Field sketch on its top face.
Before (no outline, as on main): 845 holes over the whole flat, the flange below the bend line included.
After (outline): 345 holes, only in the ring: the circle and the flange stay solid, and the Field sketch is hidden as used.
Captured from this branch's desktop build (
--profile ci) on Linux x86_64 under Xvfb, driven through the control channel (engine.execute,ui.screenshot).Integration status
Rebased on
mainat 176c22a (2026-11-01); the checks above ran at e77c555, and the two commits since touch none of these files. One conflict: #10545 had turnedsketch_consumedincrates/engine/src/view.rsinto a set worked out once per design (consumed_sketches); the perforation outline is one more arm there. #732 is labelledarea:kernel, but this doesn't touchcrates/kernel: the outline is 2D work on the flat incrates/doc/src/sheet.rs. Open PRs touching the same files: #7652 (contour flange options) merges cleanly alongside it; #8397 (draft) and #6028 (draft) also changecrates/doc/src/sheet.rs, but both conflict withmainin other files at the moment, so I couldn't try them together with this; several PRs add lines to the walk goldens. None adds a perforation outline.Assisted-by: LLM