Skip to content

Faster curved subtracts and a call to release idle display geometry - #46

Merged
aka-blackboots merged 3 commits into
mainfrom
feature/display-bounds-and-subtract-speed
Nov 3, 2026
Merged

aka-blackboots merged 3 commits into
mainfrom
feature/display-bounds-and-subtract-speed

Conversation

@aka-blackboots

Copy link
Copy Markdown
Contributor

Summary

Three changes on top of the display bounds cache that is already on main (#45):

  1. Faster subtract on small curved solids. A face trim is now built once per face pair instead of on every point probe; the body intersection graph validates both bodies once instead of once per face pair; and the non-intersecting handler stops at the first coincident or branching pair instead of finishing the whole graph.
  2. Point-in-trim test skips far segments. The exact point-to-segment distance is skipped for a trim segment whose bounding box, widened by twice the tolerance plus a rounding margin, cannot reach the probe. The crossing count still visits every segment, and non-finite values take the exact path.
  3. OpenGeometry.releaseIdleGeometry(). A new call that disposes every idle display record (records kept for a quick level-of-detail switch back) and returns { records, bytes }. A three.js renderer leaves a dispose listener on every geometry it draws. After an app disposes a renderer, that renderer's buffer state stays reachable through the idle records until they are evicted. This call frees it at once. Records used by displayed bodies are kept.

Results

Exact B-rep results do not change: no golden key moved, and the kernel snapshot is identical to main.

Subtract times, in ms, median of 5, through the SDK in node (inline kernel):

Case Before (3.0.0) After
Shelled D-shaped solid minus a six-arc cutter (16 − 8 faces) 419.6 16.5
Arc-edged seat minus its cut-out (8 − 4 faces) 135.8 30.6
Basin rim 97.8 24.2
Second D-shaped solid minus cutter 106.1 15.5
Second seat minus cut-out 136.3 30.3
Same first case, native release build 172.9 3.9

Orbit with the display bounds cache from #45 together with this branch: a four-storey architectural model in a three.js app, hardware WebGL (Apple M2 Max), median of 3 orbits of 3 s. Frame time goes from 116.7 ms (p90 125) to 16.6 ms (p90 17.2, at the refresh limit). The level-of-detail pass goes from 78 % to 1.2 % of CPU time.

Behaviour notes

  • One error kind changes, in a rare double failure. Take a subtract where a later face pair would raise a real error (not a coverage gap) after a first branch, and the prismatic curved handler then declines. Before, the call returned that pair's error. Now it returns the generic coverage gap "generic analytic solid". No corpus case reaches this path. Success paths, handlers and attempted are unchanged.
  • New API, additive. One added line in the public surface: static releaseIdleGeometry(): { records: number; bytes: number; }. The README "Display" row lists it.

Tests

  • WC-style subtracts: The pan-like and seat-like subtracts are pinned to their handlers, attempted list, topology (22/78/60 and 10/24/16), volumes and result digest. These values were recorded before the change.
  • Face trim grid: The grid test is pinned to answers recorded from the old trim query on a holed arc-edged solid and a bored tube. The tube has a cylinder face with one hole, so the test runs the band path.
  • Boundary band: A boundary test checks probes at half a tolerance and at three tolerances from a trim edge and corner. It runs on every platform.
  • Early stop: The until-branch body graph stops at the first branching pair. A face pair query still refuses an invalid body.
  • releaseIdleGeometry: Node tests show that idle records are disposed and counted, installed records survive, a released bucket is requested again, and the call returns zero after reset(). A browser spec shows that every idle record keeps a disposed renderer's listener, and that after the call none is left.
  • Mutant proof: The speed-only changes were proven with planted mutants in a scratch copy of the crate. Each mutant turns a named test red.

Checks

  • npm run check: 18 of 18 steps passed.
  • Browser steps on three 0.168 and 0.184: passed.
  • Kernel snapshot: diff against main is empty.

…t the first branch

Small curved subtracts, such as a WC pan cut from its shelled body, spent
almost all their time rebuilding the same trim polygons on every
membership probe, revalidating both bodies for every face pair, and
finishing the whole body intersection graph in the non-intersecting
handler after the first branch had already decided it. A face trim now
holds the sampled loops and band limits of one face and answers the same
tests in the same order, rebuilding a loop only where the old code would
have failed; the clip builds the two trims once per branch, the body graph
validates both bodies once, and the non-intersecting handler stops at the
first coincident or branching pair. Results, handlers and attempted lists
are unchanged; the WC pan and seat subtracts and the face trim answers are
pinned to values recorded before the change.
The record pool keeps up to two unreferenced display records per shape so
a level-of-detail switch back is instant. A renderer that drew those
records leaves its dispose listener on each one, so after an app disposes a
renderer, its buffer state stays reachable through the idle records until
they are evicted. The new call disposes every idle record and reports how
many records and bytes it released, so an app that replaces its renderer
can drop that state at once. Records in use by displayed bodies are kept.
After the face trims were cached, the WC pan subtract still spent about half
its time in the point-in-trim loop, measuring every probe's exact distance
to every trim segment through the software fused multiply-add and hypot of
the wasm build. A segment whose bounding box, widened by twice the
tolerance plus a rounding margin, does not reach the probe cannot be within
tolerance of it, so its exact distance is skipped; the crossing count still
visits every segment and non-finite values take the exact path. Every
answer is unchanged, and a test pins the boundary band on both sides of a
trim edge and corner.
@aka-blackboots
aka-blackboots merged commit 326e0de into main Nov 3, 2026
0 of 4 checks passed
@aka-blackboots
aka-blackboots deleted the feature/display-bounds-and-subtract-speed branch November 3, 2026 23:02
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