diff --git a/README.md b/README.md index bc6eba7..bc79f82 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,19 @@ Hand-written [nanobind](https://github.com/wjakob/nanobind) bindings for the OpenCASCADE (OCCT) geometry kernel, covering exactly the surface the N3XD CAD -backend uses — 139 symbols across 48 `OCP.*` modules, not all of OCCT. +backend uses — 138 symbols across 47 `OCP.*` modules, not all of OCCT. The package installs as a top-level `OCP`, so it is a drop-in replacement for `cadquery-ocp-novtk` and the app's 442 import sites stay untouched. -Status: **Inc 0 (spike) shipped** — build system, OCCT builder image, handle -model, and the first module surface (`gp`, `TopAbs`, `TopoDS`, `TopExp`, -`TopLoc`, `TopTools`, `BRep`, `BinTools`, `Poly`, `Standard`), published as -`7.9.3.1.dev1`. BREP serialisation is byte-identical to the stock wheel, which -is the gate that mattered: the pools and the content-addressed derive payloads -both depend on it. Coverage is 34 of the 139 symbols the app imports; the rest -lands in increments 1-4 (roadmap 10C). +Status: **coverage complete** — all 138 symbols the app imports, across 53 +bound modules, published as `7.9.3.1.dev5`. The app's full backend suite passes +against it (1797 passed / 1 skipped, the same as the stock wheel), a sweep of +the whole project store reproduces every part's geometry exactly (4486 parts; +no change in statuses, volume, area, bbox, entity counts, triangles or anchor +digests), and BREP serialisation stays byte-identical, which the pools and the +content-addressed derive payloads depend on. The app is not swapped yet — that +is the cutover, roadmap 10C. Start with [docs/design.md](docs/design.md) for the decisions, [docs/building.md](docs/building.md) to build one, and @@ -25,9 +26,8 @@ phase plan lives in the app repo at `docs-private/reference/roadmap.md` `cadquery-ocp` lags OCCT (it wraps 7.9.3; OCCT 8.0 shipped 2026-05), builds Windows and macOS wheels we never use, and until recently forced a 638 MB VTK -dependency into the image. Binding *call* overhead is not a bottleneck — the -CAD hotspots live inside the C++ kernel — so this exists for version velocity, -footprint, and two defects that a binding we control prevents by construction: +dependency into the image. So this exists for version velocity, footprint, and +two defects that a binding we control prevents by construction: - OCCT sub-shapes are returned **by value**, so a wrapper can never alias a `TShape` whose owner has died (this segfaulted a process-global face memo). @@ -37,6 +37,16 @@ footprint, and two defects that a binding we control prevents by construction: It also releases the GIL around kernel calls and ships type stubs, neither of which upstream does. +**It is also considerably faster, which was not the point and turned out to +matter most.** With the app otherwise unchanged, its benchmark suite runs +194 s → 73 s, and rebuild time improves *superlinearly* with model complexity: +3.3x for a 4-feature part, 7.0x for a 32-feature one (13.4 s → 1.9 s). The +premise going in was that call overhead is irrelevant because the hotspots live +inside the kernel — true of any single call, false of the aggregate, because +this backend reaches OCCT once per face, per node and per edge. +`tools/bench_ext.py` has the numbers and the two places they contradicted the +plan. + ## Build OCCT is compiled once into a builder image and reused; it is never built on the