Skip to content

Hole-aware sketch profiles: multi-loop extrude + no-crossing boolean fast path#396

Open
ecto wants to merge 7 commits into
mainfrom
claude/extrude-holes
Open

Hole-aware sketch profiles: multi-loop extrude + no-crossing boolean fast path#396
ecto wants to merge 7 commits into
mainfrom
claude/extrude-holes

Conversation

@ecto

@ecto ecto commented Jul 4, 2026

Copy link
Copy Markdown
Owner

What

  • IR: Sketch2D gains optional interior holes loops (serde + ts-rs back-compat; ir:gen regenerated, ir:check clean).
  • Kernel: extrude_with_holes builds multi-loop BReps directly — outer + hole lateral faces and holed caps, no boolean pipeline. Volume/watertightness tests included.
  • Booleans: new no_crossing fast path — when boundaries provably don't cross, union/difference/intersection resolve by containment ray tests instead of full SSI.
  • Consumers: eval, vcode syntax + docs, to_loon, app materializer/migrate/document_api, kernel-wasm, engine evaluate.ts — the full New-IR-operation checklist.
  • vcad-gdsii: holed islands emit as single multi-loop extrudes; the per-island Difference path is deleted (picture-frame test: was 2 extrudes + 1 Difference → now 1 extrude, 0 Differences).
  • vcad-process: prisms use native holes.

Why

Merged GDS die layers (power grids: hundreds of interior holes per island) previously built giant 3D Difference trees that the boolean pipeline chewed on for tens of minutes. With profiles that carry their holes, the geometry is exact and the boolean pipeline never runs for them.

Gates

  • cargo test: all affected crates green (sketch 37, booleans 103, eval 33, gdsii 44, process 36, ir 27 + workspace suite)
  • clippy -D warnings: stable and nightly both clean (workspace, CI-matching)
  • npm run ir:check: generated TS up to date

Render benchmark of the 88k-polygon sky130 die through the new path is running; number to follow as a comment.

🤖 Generated with Claude Code

… booleans

Sketch2D gains interior hole loops (IR: optional holes field, serde/ts
back-compat via default); vcad-kernel-sketch extrude_with_holes builds
the multi-loop BRep directly (outer + hole laterals, holed caps) so a
polygon-with-holes extrudes in one operation with no boolean pipeline.

vcad-kernel-booleans grows a no_crossing fast path: when two solids'
boundaries provably do not cross (AABB + no face-pair intersection),
union/difference/intersection resolve by containment ray tests instead
of the full SSI pipeline.

Consumers wired per the IR checklist: eval (extrude/revolve reject holes
where unsupported with a typed error), vcode syntax + docs, to_loon,
app materializer/document_api/migrate, kernel-wasm, engine evaluate.ts,
ir:gen regenerated. vcad-gdsii bridge emits holed islands as single
multi-loop extrudes (the Difference path is gone); vcad-process prisms
use native holes too. New holed_islands example + tests across sketch
(volume, watertightness), booleans (containment), gdsii (picture-frame
ring now = 1 extrude, 0 Differences), eval.

Unblocks: fast rendering of merged GDS die layers (power grids with
hundreds of holes previously built giant 3D Difference trees).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vcad-mcp Building Building Preview, Comment Jul 4, 2026 4:13am
3 Skipped Deployments
Project Deployment Actions Updated (UTC)
mecheval Ignored Ignored Jul 4, 2026 4:13am
vcad Ignored Ignored Jul 4, 2026 4:13am
vcad-docs Ignored Ignored Jul 4, 2026 4:13am

Request Review

@chojiai

chojiai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Choji review — Looks good — 2 major

Choji review — Looks good

This PR adds hole-aware sketch profiles (multi-loop extrude) and a no-crossing boolean fast path to eliminate the expensive Difference-tree pipeline for chip-layer geometry. The implementation is thorough: IR, kernel, tessellator, eval, WASM, vcode, gdsii, and process bridges are all updated consistently. Both open findings from the prior review have been addressed by the owner with regression tests and explanations. The remaining code is well-structured and the correctness-critical paths (earcut fallback on failure, winding normalization, vcode H-marker guard) are handled correctly.

Live verification in progress — Choji is booting your app and running checks to confirm these changes. This comment updates with the result shortly.

Correctness

  • Major · Correctness — No-crossing fast path entry point is not visible in the diff, so the gate enforcing zero SSI crossings cannot be verified crates/vcad-kernel-booleans/src/no_crossing.rs:1
    The prior review flagged that the no-crossing fast path must be gated on SSI producing zero crossings, and the diff for no_crossing.rs shows only the implementation module. The call site in crates/vcad-kernel-booleans/src/pipeline.rs is listed as a partial diff (+55/-6) but not shown. Without seeing that file it is impossible to confirm the gate is correctly placed. The owner's PR_CONVERSATION response addressed a different concern (coordinate quantization). If the pipeline calls try_no_crossing_fast_path before running SSI rather than after, the fast path could incorrectly classify crossing operands as non-crossing. A human should verify that pipeline.rs calls the fast path only after SSI confirms zero intersection curves.
  • Major · Correctness — Vertex quantization at 1 nm may alias distinct outer and hole vertices that are legitimately close but not coincident crates/vcad-kernel-sketch/src/extrude.rs:700
    The quantize_pt closure rounds to 1e-9 (1 nm). For chip-layer geometry where hole boundaries may be placed at sub-nanometer precision relative to the outer profile, two distinct vertices could hash to the same key and be merged, producing a degenerate edge. The existing sew tolerance is 1e-6 (1 µm), so the quantization is 1000× finer — this is unlikely to fire in practice, but the mismatch between the quantization grid and the sew tolerance means a vertex pair that sew would treat as distinct could be collapsed here. Consider aligning the quantization to the sew tolerance (1e-6) or documenting the intentional mismatch.

Was this review useful? Rate the findings → — your thumbs up or down trains Choji on what's worth flagging.

Reviewed 33a433c · Choji keeps this comment up to date as you push.

chojiai[bot]
chojiai Bot previously approved these changes Jul 4, 2026
Comment thread crates/vcad-kernel-tessellate/src/lib.rs
…p on slotmap keys, vcode empty-outer error

- Winding normalization now sums signed area over ALL earcut output
  triangles instead of probing the first non-degenerate one — immune to
  per-triangle degeneracy and to assumptions about ring order.
- EARCUT_VERTEX_THRESHOLD 64 -> 256 with the quality/speed trade-off
  documented: ordinary curved caps stay on the Steiner path, chip-scale
  polygons take earcut.
- no_crossing test helper keys its half-edge pairing map on VertexId
  tuples directly (slotmap keys are Hash+Eq) instead of hashing Debug
  strings.
- planar_regions_touch doc now states why outer-region separation is
  sufficient (holes lie strictly inside their outer region), not merely
  conservative.
- vcode: targeted parse error for a sketch whose hole loops (H) precede
  any outer-loop segment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chojiai chojiai Bot dismissed their stale review July 4, 2026 03:57

Dismissing prior approval to re-evaluate 14952ea.

Comment thread crates/vcad-kernel-booleans/src/bbox.rs
Comment thread crates/vcad-kernel-tessellate/src/lib.rs
Comment thread crates/vcad-kernel-booleans/src/no_crossing.rs
Comment thread crates/vcad-ir/src/vcode.rs Outdated
chojiai[bot]
chojiai Bot previously approved these changes Jul 4, 2026
…ode H-first error placement

- bbox: regression test proving sweep_candidate_face_pairs equals the
  quadratic reference as an exact multiset even when A and B faces share
  min.x — each event scans only the opposite active list before pushing
  itself, so a pair is emitted exactly once, by whichever face enters
  second.
- tessellate: regression test on a symmetric square frame proving earcut
  output triangles share one winding and their signed areas sum to the
  frame area — the region between outer and holes is what gets
  triangulated, so cancellation to zero cannot occur; the total-area
  probe is well-defined.
- vcode: empty-outer guard moved into the H arm — errors at the H line
  itself and cannot be bypassed by early loop exits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chojiai chojiai Bot dismissed their stale review July 4, 2026 04:03

Dismissing prior approval to re-evaluate 4c95ae7.

chojiai[bot]
chojiai Bot previously approved these changes Jul 4, 2026
Comment thread crates/vcad-kernel-tessellate/src/lib.rs
planar_regions_touch was O(na·nb) twice over — every vertex of each
polygon ray-cast against the other, then every edge pair tested. The
gate runs for every coplanar candidate face pair in a union tree, and
chip-layer islands carry thousands of vertices: profiling the 88k-poly
die showed the contact gate itself dominating evaluation (>20 min).

Now: edge contact is swept over tolerance-padded x-intervals (same
pattern as the face broadphase), and when no edges touch the regions
are provably either disjoint or nested, so one boundary-inclusive
containment probe per side replaces the all-vertex scan.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chojiai chojiai Bot dismissed their stale review July 4, 2026 04:07

Dismissing prior approval to re-evaluate 8233bc8.

chojiai[bot]
chojiai Bot previously approved these changes Jul 4, 2026
Comment thread crates/vcad-kernel-booleans/src/bbox.rs
Comment thread crates/vcad-kernel-booleans/src/no_crossing.rs
earcut_polygon_with_holes returned an empty mesh on earcutr::Err,
silently dropping the cap face and leaving the tessellation
non-watertight. It now returns Option; both call sites fall through to
the bridge/ear-clip path on None, so a failed triangulation costs speed,
never a hole in the solid.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chojiai chojiai Bot dismissed their stale review July 4, 2026 04:10

Dismissing prior approval to re-evaluate 33a433c.

Comment thread crates/vcad-kernel-booleans/src/no_crossing.rs
Comment thread crates/vcad-kernel-sketch/src/extrude.rs
ecto and others added 2 commits July 3, 2026 23:11
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rance

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ecto

ecto commented Jul 4, 2026

Copy link
Copy Markdown
Owner Author

Render benchmark (88k-polygon sky130 die, merged per-layer solids with holes, top view 2000px):

pipeline stage before this PR with this PR
GDS import + 2D union → .vcad 4.5 s (183 MB doc) 4.5 s (105 MB — no hole-Difference trees)
render, merged-solid document never finishes (>20 min CPU, killed; stack-overflow before #394) completes: 58 min (3781 s CPU), output verified correct — power straps render as single continuous solids
render, flat per-polygon document 5.2 s 5.2 s (unchanged; remains the fast viewing path)

So: the merged-solid path goes from impossible to correct but slow. Profiling shows the remaining cost is the coplanar-contact gate on full-die power rails: their edges span the whole die in x, so the x-interval sweep (8233bc8) prunes nothing for exactly those faces and the gate degenerates toward quadratic for rail-vs-rail pairs.

Follow-up candidates, in rough order of leverage:

  1. Eval-level disjoint-union bypass: the gdsii bridge knows its islands are pairwise disjoint (guaranteed by the 2D union) — an IR-level disjoint-union node could skip boolean_op entirely and sew shells directly.
  2. Choose the sweep axis per pair from the operands' aspect ratio (rails are long in x, thin in y — a y-sweep prunes them perfectly).
  3. A proper 2D segment index (interval tree / R-tree) in planar_regions_touch.

None of these block this PR: correctness is proven, the flat path is untouched, and every merged-solid workload that previously hung now terminates.

🤖 Generated with Claude Code

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