Files
MarkusRe 6a3cc682fa Mirror: a mirrored body's straight edges stay lines, so booleans with it no longer take the wrong side (#15862) (#16104)
* Claim #15862: interference and booleans of a loft against a mirrored box

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

* solidcore-ops: test a box mirrored into an opening of a spline loft (#15862)

A box extruded from a rectangle, read back from its record and mirrored
across x = 0 sits 0.2 mm clear of a loft through two cubic splines. On main
the loft minus the box is nothing, the loft and the box intersect in the
whole loft, and their union is refused, because the mirror turns every
straight edge into the degree 1 B-spline of the whole line.

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

* solidcore: a mirrored line stays a line (#15862)

Mirroring a body (SmBrep::Mirror, and SmBrep::Transform with a left-handed
matrix) turned each straight edge into the plain degree 1 B-spline of the
line's NURB. A line read from a record is infinite, so that B-spline ran over
knots -1234567..1234567 with control points some 1.8e7 mm out. A boolean of
such a body with a spline face it does not touch took the wrong side: a box
mirrored into an opening of a spline loft, 0.2 mm clear, cut the whole loft
away, intersected it in the whole loft, and its union was refused (1001).

Line::create_mirror_curve mirrors the line's point and unit vector and keeps
its domain, scale and sides; an existing NURB is mirrored with it, so each
parameter maps to the mirror of the same point and edge intervals stay valid.
Recorded as WR-784.

Golden topology.brep_mirror blessed: 147 of 341 cases move, none in status,
topology (graph) or the geometry digest.
- 133 mirror and mirror-matrix cases: each straight edge's curve is now a line;
  every record block drops by a whole multiple of 23 (the B-spline type code
  minus the line's), e.g. Solids_box_smb_* by 12 lines, the cylinder's seam by 1
  (gen0017/0030/0033/0036/0077, mat0027/0045 within 1e-9 besides: the old
  samples came from control points near 1e7).
- 14 matrix cases with a reflection and an unequal scale (box, cylinder and cone
  mirror_rotated_scaled; mat0003/0004/0009/0017/0029/0036/0049/0050/0056/0057/
  0090): the scale turns the edges into NURBS as before, now over the edge's own
  interval instead of the whole line, so the record is shorter and the uses keep
  no stored UV trims, exactly as main gives for an unequal scale without a
  reflection (Solids_box_smb_non_uniform_2_1_1). Measured on box, cylinder, cone, extrusion, l_shape_with_boss
  and OffsetBoxCylOnCorner with that matrix: valid at CheckLevel::All and the same
  volume to the last bit on main and with this change.

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

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-11-13 18:24:03 +00:00
..
…
…
…
…

solidcore is developed inside SolidCraft, at solidcore/. The tangency-labs/solidcore repository is an automatic, read-only mirror of that folder. Open issues and pull requests in tangency-labs/solidcraft: kernel-only work against the kernel branch.

solidcore logo: an isometric solid with one filleted edge and a NURBS curve on its top face

solidcore

📊 Live progress: tangency-labs.github.io/solidcore: every unit's port status, the upstream-issues log, and the surface/surface intersection corpus scores, regenerated on every merge.

solidcore is a boundary-representation (B-rep) solid modeling kernel in safe Rust. It is based on NVIDIA's SMLib (from USD BRep, Apache-2.0) and goes its own way from there: it started as a port, and its new constructions, such as the generic rolling-ball blend (docs/generic-blend.md), are designed and built here as clean, procedural constructions that replace the code they supersede. Contributing: CONTRIBUTING.md. Design discussion: the #solidcore-dev channel on Discord.

Solids are exact: shells, faces, loops, edges and vertices bound to analytic and NURBS curves and surfaces. solidcore's first consumer is SolidCraft.

Scope

In scope: the SMLib kernel and the SM_API operation layer of upstream — NURBS math, curve and surface geometry, B-rep topology, intersections, booleans, fillets and chamfers, offset/shell, sweeps and skins, primitives, healing/stitching, mass properties and queries.

Out of scope: upstream's OCCT translators, USD/Hydra integration and Python bindings. See ATTRIBUTION.md.

Goals: no unsafe in the kernel, no panics on bad input, deterministic results, no global state (one Kernel per thread), builds for wasm32-unknown-unknown, and exact or certified geometry. The gate is its own tests, SolidCraft's operation cases and the goldens: every unit's cases checked against their committed expected outputs (AGENTS.md §1).

Status

Every SMLib kernel module has a Rust counterpart, and primitive construction is exercised end to end. Integration remains in progress: deferred paths still limit coverage. The API is experimental (0.0.x).

Use the live unit results for each unit's status and blockers, and the primitive checks for whole-solid results. Per-unit plans and notes live in plan/units/; the generated checklist is PROGRESS.md on the site, with handoff notes in plan/STATUS.md. The progress site is built by site/build.py (python3 site/build.py -> bin/site/).

Reference docs

How the kernel's constructions work, the theory behind them and the invariants they keep, with schematics. Start with the first; each ends with "If you're stuck".

Doc What it covers
Definitions and certificates A surface is its definition and its B-spline a certified approximation; the certificate; exactness classes; the exact extension; the invariants every construction keeps
The generic blend Fillets, chamfers, corners and setbacks
The procedural sweep Swept surfaces, their rotation-minimizing frames, threads
Surface-surface intersection The SSI pipeline, its exact classes, and what the boolean takes from it
Layers Which layer each job lives in

Layout

Path Contents
crates/solidcore The kernel library
crates/goldens Every unit's cases, checked against their goldens
crates/diagnostics solidcore-diag: a shaded picture and a tolerance report of one .smb body
plan/ Unit list, port order, status, findings
site/ Generator for the GitHub Pages progress site
upstream/ Local clone of usd-brep v1.0.1 at 3fd5b95, read only (gitignored)
bin/ All build output (gitignored)

Building

Requires the stable toolchain (pinned by rust-toolchain.toml, which also installs rustfmt, clippy and the wasm32-unknown-unknown target). Cargo output goes to bin/ (see .cargo/config.toml).

cargo build -p solidcore
cargo test -p solidcore
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo check -p solidcore --target wasm32-unknown-unknown   # wasm check

Optional: export RUSTC_WRAPPER=sccache to share compilation caches.

WebAssembly stack size

On wasm32-unknown-unknown the Rust stack lives in linear memory without a guard page, so an overflow corrupts memory instead of aborting. solidcore bounds input-driven recursion, but kernel algorithms (subdivision, intersection, filleting) still recurse legitimately. Link wasm consumers with a larger stack than the ~1 MB default, e.g. in the consumer's .cargo/config.toml:

[target.wasm32-unknown-unknown]
rustflags = ["-C", "link-arg=-zstack-size=8388608"]   # 8 MiB, as a native main thread

Goldens

Every unit's cases (fixtures/<unit>/, upstream's TestFiles, seeded generators) run on solidcore and are checked against the unit's golden, crates/goldens/expected/<unit>.jsonl: the outputs recorded when it was blessed. CI fails on any changed, added, missing or broken case. Many cases read upstream's test files, so clone upstream/ first:

git clone https://github.com/NVIDIA-Omniverse/usd-brep upstream
git -C upstream checkout 3fd5b95   # v1.0.1; the pin is in scripts/upstream-pin.env
cargo run --profile goldens -p goldens -- --all --goldens --jobs 0   # every unit (CI)
cargo run --profile goldens -p goldens -- --unit <unit id> --goldens   # one unit
cargo run --profile goldens -p goldens -- --unit <unit id> --bless     # record a change on purpose

A golden proves a result unchanged, not correct. A change that moves one is blessed and justified in its pull request: the cases that changed, their numbers, and pictures for geometry (crates/goldens/README.md). upstream's C++ is a reading reference only: nothing here builds, links or runs it.

Contributing

Contributions go through pull requests, and AI agents are welcome. Useful work includes connecting ported units, resolving deferred cases, adding operation regressions and fixing bugs.

  1. Check the live unit results, open issues and open PRs. Choose an unclaimed unit or a specific completion task: a missing function, back-edge, exact import, coverage gap or bug. A passing golden does not prove every branch is exercised.
  2. Search PR titles and bodies for the unit, symbols and paths. Claim the specific work in a draft PR; initial ports use port: <unit id>. A claim covers its stated scope, leaving independent tasks in the same unit available. Coordinate overlapping functions or shared interfaces in the existing PR before editing them.
  3. Describe the intended behavior, affected paths, related PRs and validation, and list independent follow-ups others can take. Check the affected units against their goldens and justify every golden you bless. CI is the merge gate. See AGENTS.md §4 for the claim template, handoffs and inactivity rules.

To keep parallel PRs from conflicting: edit only your unit's plan/units/<unit id>.toml, and put each finding or upstream issue in its own new file under plan/findings/ or plan/upstream-issues/ (never append to a shared file). A branch started before the per-unit split migrates with git fetch origin && git merge origin/main; scripts/units-migrate-branch.sh && git commit --no-edit.

The full rules, style and step-by-step workflow are in AGENTS.md (point your agent at it).

Releasing

solidcore is published to crates.io from CI: bump version in crates/solidcore/Cargo.toml in a PR, merge it, then push a tag solidcore-v<version> (.github/workflows/release.yml, needs the CARGO_REGISTRY_TOKEN repository secret). Only solidcore is published; goldens is test-only. It stays at 0.0.x until it is usable end to end.

Sponsors

CI powered by Blacksmith

solidcore's continuous integration runs on Blacksmith, which sponsors its CI minutes.

Licence

Apache-2.0. See LICENSE, NOTICE and ATTRIBUTION.md. solidcore is an independent project, not affiliated with or endorsed by NVIDIA.