Skip to content

fix(geometry): cut what stands in layers, so lips, aprons and stairs are reported - #363

Open
ManuelStaggl wants to merge 4 commits into
mainfrom
fix/print-check-layers
Open

ManuelStaggl wants to merge 4 commits into
mainfrom
fix/print-check-layers

Conversation

@ManuelStaggl

@ManuelStaggl ManuelStaggl commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Approach

Decision of 2026-11-12 after three reviews of #353: only what stands comes from layers; bridges, spans and the lying-hole rule stay on the faces as they were.

  • packages/geometry/src/layers.ts (new): a closed body is cut every 0.2 mm from the bed up (clipper2-ts 2.0.1-18, the version the desktop app already uses). Of each cut only that is carried which lies over carried material of the cut below, or reaches out no further than the overhang angle (limit + 1° tolerance) allows. So being carried grows upwards at that angle and no faster.
  • overhang.ts: a rim of an overhang patch is an anchor where the material just below it is carried in the layers. This is asked along the rim (every half reach) and the rim is split where the answer changes, so a lip held by a cheek is an anchor at the cheek only.
  • Patches are taken lowest first. Triangles that are bridged carry what is built on them; small overhangs and reported ones carry no more than the angle gives.
  • A surface that is not closed has no outline to cut and keeps the old flood over vertices (standingVertices).
  • Public interface and result fields (area, supportByFace, vertices) are unchanged.

Cases (overhangCases.test.ts, 178 shapes, each in nine turns and mirrored)

before after
right 151 161
overhang passes as printable 10 0
printable shape reported 17 17

Now right: the drip edge with a cheek (30 and 100 long), the apron with a cheek at the back, the apron between two cheeks, and the six stairs. None of the 151 changed. No expected value was changed.

Still in OPEN (all reported though printable, untouched by this change): L, T, cross and ring channels, the channel round a post (3.5–8 wide), tunnels 9 and 10 with R 4, tunnels cut at 30°, lying nut pockets M4–M6 with a corner up.

New in layers.test.ts: a head on a post on a bridge (free on a bridge of 8, reported on a ceiling of 12), and a closed bolt of 260 ribs.

Run time

  • Suite of the package: 6.0 s before, 7.9–8.9 s after, of which 2.9 s are the new bolt test.
  • Closed bolt, 100 224 triangles, 1 300 layers: 0.9 s per pass.

Known limits

  • Layer height is fixed at 0.2 mm, not taken from the profile. What is thinner than a layer below a rim is not seen as carrying it.
  • The reach of carried material is exact to about 0.1–0.2 mm: a stair just steeper than the limit (about 50°) still stands.
  • Carried material grows sideways into the material above a reported overhang (a tube lying on the bed needs that for its hole). So what is built on a reported overhang close to standing material can count as standing after a few millimetres of height.
  • A sloped bridge carries only from the layer above its highest point.
  • Open surfaces (the revolved test shapes, the threads of overhangSpeed.test.ts) use the old flood, with its known errors.
  • Every layer up to the highest overhang is cut, so tall parts with a detailed outline cost time in proportion to their height.

Checked

pnpm run typecheck, eslint and vitest for packages/geometry, vitest (unit) for apps/desktop. No E2E, no contract tests.

Second round (head 42c4de1), after the review of this pull request

finding now
1 Run time explodes on angular bodies with 45° faces fixed: the carried outline grows mitred, no arcs pile up; test "cuts a funnel of four flat sides at 45°/50° four times as high …" (layers.test.ts)
2 Material that begins in the air on steep flanks passes fixed: leaning faces that begin from below are followed and reported where the layers below them are not carried; cases "a V rib …" (two), "a keel …", "a blade …", counter cases "the same rib with a flat bottom" (132) and "a wedge standing on its edge on the bed" (free)
3 Thin wall on a small ledge reported fixed: a small overhang carries what stands on it once the material has risen as far as the angle needs to reach its tip (reach / tan limit, 1.7 mm); cases "walls 1 mm thick that step 1.8 out …" and "a wall that steps 1.8 out … with a lip"
4 Ledge over a 45° funnel of 6 or 8 sides reported fixed with the mitre; cases "ledge 1.5 over a funnel of 6 / 8 / 96 sides at 45°"
5 One mesh error switches the layers off silently partly: a triangle that comes twice is taken; a missing triangle still falls back to the flood (shortcut: in layers.ts), and the new field layered of the overhang map says which way was taken; test "takes a triangle that comes twice …". Nothing reads layered yet.
6 Run time in general cuts are worked out only where a face hangs over, a leaning face begins or an overhang below carries; test "cuts only where something hangs or begins …"

All new cases run in nine turns and mirrored in overhangCases.test.ts: 189 cases, 172 right, 17 in OPEN (unchanged, none added). No expected value of an existing case was changed.

Run times on the build server (one pass, ms): before this round / now / main

body before now main
funnel of 4 flat sides at 45°, 5 mm 488 9 3
the same, 10 / 15 / 20 mm 3 195 / 9 450 / 17 057 4 / 4 / 5 – / – / 1
funnel of 6 sides, 15 mm 4 083 5 –
column R 10, 300 mm, lip at the top 807 50 16
closed bolt, 500 000 triangles 4 900 4 100 7 600

Suite of the package: 10.4 s before this round, 11.5 s now (15 more tests).

New limits:

  • Material that begins in the air is not added where it hangs together with an overhang that is reported already (the drip edge of a reported shelf stays at the shelf's 240 mm²). The body is reported either way; the area and the faces named leave the lip out.
  • Only faces that lean at least 3° are followed; a hanging blade with a knife edge of vertical sides and no bottom face has none.
  • A wall on a small ledge counts as standing only 1.7 mm above the ledge; a bridge or lip right above it is still reported.

Not changed, as the review named them small: a T beam with a cap 10 mm thick and a lip on top gives 360 (405 on main), since carried material grows sideways above a reported overhang; a wall at exactly 46° gives 0 to 432 mm² depending on the turn, as on main.

The desktop flow "a sketch without a body is drawn in the view" has no body, so the print check cuts nothing there; its timeout does not come from this change. The check does run on the renderer's thread (usePrintCheck.ts), so the run time of finding 1 would have frozen the window on angular parts.

Third round, after the second review

finding now
B1 / S3 A tiny reported patch swallows a large find; shelf and rib on one body give only the shelf fixed: the rule "what hangs together with a reported overhang is not counted again" is gone. A face that looks down is reported for the share under which nothing is carried even with every overhang propped up. Cases "the same with a ridge 0.8 wide … beside the rib" (313.9) and "the same rib on a body with a shelf 8 out" (513.9)
B2 A hanging blade with flanks under 3° stands and carries the ceiling fixed: where something begins comes from the layers (lowest points of every face that looks down, ridges that run out faster than the angle), not from a lean of 3°. Cases "a blade 1 wide and 20 deep …" (940.2), "a blade 0.6 wide and 10 deep" (548.2), "a rib 1 wide with a flat bottom and sides drafted 2°" (231.6), and the existing "a rib along under a 9 mm bridge, hanging free" (270)
S1 A rising edge is missed depending on its height against the layers fixed with the ridges; cases "a V rib whose edge rises 5° from an end wall, beginning 0 / 1 / 1.08 / 1.12 / 1.2 / 1.28 over the bed": 75–92 % of the flanks in every position (the wall carries a wedge of each flank). From the bed it is reported too: only the first millimetres lie on the bed
S2 A slope at 45° from the tip of a small ledge is reported fixed: on a small overhang material stands at once and what goes on within the angle with it; it is sound only once it has risen as far as the angle needs, and an overhang hanging from material that is not sound has that much less reach (so stairs are still reported). Cases "a slope at 45° from the tip of a ledge 0.3 / 0.5 / 1 / 1.5 out", "a countersunk head …"
S4 Run time quadratic with the height of stepped bodies fixed: the cut is made of the rims of flat faces, not of every triangle; test "cuts a stair of 740 steps in no more than twelve times the time of one of 185"
small Mitre at corners under 29° the limit is 2.05 instead of 4 (a slope of three flat sides needs 2): carried material jumps 0.42 mm at most. Cases "a wedge floating 0.6 mm from the sharp corner of a column" (fails with the old limit) and "a funnel in the outline of a star"
small V rib across from wall to wall, 8 mm long left reported, as the keel: the bridge rule works on faces that hang over, an edge has none. A known false warning

Cases: 208 (178 of the reviews, 30 from the reviews of this pull request), 191 right, 17 in OPEN (unchanged).

Expected values changed, all because the lip under a shelf begins in the air and needs its own support, whatever props the shelf (its faces at 45° are now counted beside the shelf's 240 mm²):

case before now
shelf 8 with a drip edge; the same as triangles 240 324.9
… with a hook curled back to the wall 240 409.7
… with a lip with a step of 0.5 240 346.1
… with a bead whose back looks up 240 367.3
drip edge with a cheek, 30 long 200–245 280–330
the same, 100 long 750–805 1 030–1 090
bridges.test.ts: the four lips (area and faces named), and two bodies of the turn test 240 as above

Run times on the build server (second pass, ms): previous head / now / main

body previous now main
stair 740 steps 0.5/0.4, turned 15° 4 525 86 44
stair 370 steps 1 067 16 13
stair 148 steps 1.7/2 697 37 5
column R 10, 300 mm, lip at the top 44 77 20
funnel of 4 flat sides at 45°, 20 mm 4 10 2
closed bolt, 500 000 triangles 4 157 4 762 7 975

Limits added in this round:

  • The area of a face that begins in the air is counted in quarters (four probes per triangle).
  • A face that looks down by less than 0.06° counts as a wall and is not reported itself; the ceiling beside such a blade is.
  • The lowest edge of a rib that spans less than a bridge between two walls is reported although its first layer would bridge.
  • The review's knob of 0.8 × 0.8 × 1 mm is tested as a ridge 0.8 wide along the body; a hanging cylinder is not among the cases.

🤖 Generated with Claude Code

ManuelStaggl and others added 4 commits November 12, 2026 20:08
…are reported

The print check decided on the mesh which rims of an overhang hang from
material that stands: a flood over vertices from the bed. A lip or an apron
held by a cheek at one end stood all along, and a stair of small steps stood
step on step, so ten overhangs of the review cases passed as printable.

Closed bodies are now cut every 0.2 mm (layers.ts, clipper2-ts): of each cut
only that is carried which lies over carried material below or reaches out
no further than the overhang angle allows. A rim is asked along its length
and split where the answer changes. Bridged triangles carry what is built on
them; small and reported overhangs carry no more than the angle gives.
Bridges, spans and the lying-hole rule stay on the faces as they were.

Surfaces that are not closed have no outline to cut and keep the flood.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…not in seconds

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
… only where needed

Review of pull request 363.

- The carried outline grew rounded, and every corner left an arc that was
  never taken out: a funnel of four flat sides took 33 s at 20 mm. It now
  grows mitred, as a slope of flat sides does, so a ledge over such a funnel
  hangs from its corners too.
- A cut is worked out only where a face hangs over, a leaning face begins
  or an overhang below carries; elsewhere it is carried as a whole if the
  cut below is. A column 300 mm high costs what one of 30 mm does.
- Material that begins in the air on faces that only lean (a rib with a
  pointed edge under a bridge, a keel, a blade) is reported: its leaning
  faces, as far as the layers below them are not carried. What hangs
  together with an overhang that is reported already is not counted twice.
- A small overhang carries what stands on it once the material has risen as
  far as the angle needs to reach its tip: a wall on a small ledge stands, a
  stair of ledges still does not.
- A triangle that comes twice no longer makes the body open. A mesh with a
  hole still falls back to the flood along the faces; the new field
  `layered` of the overhang map says which way was taken.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
… cut along face rims

Second review of pull request 363.

- What begins in the air no longer depends on the angle of its faces: the
  heights where the angle alone does not carry a layer now include every
  lowest point of a face that looks down and every ridge that runs out
  faster than the angle. A blade with flanks at 1.4° holds no ceiling, and
  a rib whose edge rises from a wall is found wherever it lies against the
  layers.
- Faces that look down are reported for the share under which nothing is
  carried even with every overhang of the part propped up. This replaces
  the rule that left out whatever hung together with a reported overhang:
  a tiny reported patch could swallow a large find. The lips under a shelf
  are now counted beside the shelf; seven expected values rise by the area
  of those faces.
- Two readings of the cuts: on a small overhang material stands at once,
  but is sound only once it has risen as far as the angle needs. An
  overhang hanging from material that is not sound has that much less
  reach. A slope from the tip of a small ledge is free, a stair of ledges
  is still reported.
- The cut is made of the rims of flat faces, not of every triangle: a
  stair of 740 steps took 4.5 s and takes 0.09 s.
- The corner of carried material runs ahead of its sides by 2.05 layers'
  reach at most (was 4), enough for a slope of three flat sides.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant