stroblme 0ce43a94aa 10C Inc 2: feature tail
119 of the app's 138 symbols now resolve; only the I/O modules and the Inc 4
tail are left. New: GCE2d, GCPnts, BRepFilletAPI, BRepOffsetAPI,
ShapeAnalysis, ShapeFix, ShapeUpgrade, BRepCheck, BRepTools, BRepLib,
BRepExtrema, BRepClass3d, IntCurvesFace, plus TopTools_HSequenceOfShape.

The fillet and chamfer builders derive BRepBuilderAPI_MakeShape, so their
history comes from the base bound in Inc 1 — which is what lets the app read a
blend's provenance the same way it reads a boolean's. The Inc 2 gate compares
that history exactly, alongside the splitter's, which is what sketch-region
attribution depends on.

Two shapes of deviation, both commented where they are bound:

- Trailing enum arguments are left off four constructors (fillet's
  ChFi3d_FilletShape, MakeThickSolidByJoin's mode/join pair, BRepExtrema's
  Extrema flags, and Inc 1's GeomAPI_ProjectPointOnSurf). An unregistered enum
  cannot serve as a default argument — nanobind converts defaults at binding
  time, so it fails the whole module's import with std::bad_cast. The app never
  overrides any of them, so OCCT's own defaults apply and behaviour is
  unchanged.
- ShapeAnalysis_FreeBounds.ConnectEdgesToWires reassigns a Handle& out
  parameter, which the caster cannot honour because it hands C++ a copy of the
  handle. The lambda splices the result into the sequence the caller passed, so
  the pass-empty-then-read shape the app uses still works. This is the one
  place upstream's holder semantics and ours differ observably.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfriM8XUkn7uYf5Dwe2xo6
2026-08-10 20:09:29 +02:00
2026-08-10 19:52:58 +02:00
2026-08-10 20:09:29 +02:00
2026-08-10 20:09:29 +02:00
2026-08-10 20:09:29 +02:00
2026-08-10 19:52:58 +02:00
up
2026-08-10 17:18:21 +02:00
2026-08-10 20:09:29 +02:00
2026-08-10 19:52:58 +02:00
2026-08-10 20:09:29 +02:00

n3xd-ocp

Hand-written 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.

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).

Start with docs/design.md for the decisions, docs/building.md to build one, and docs/adding-symbols.md to extend the surface. The phase plan lives in the app repo at docs-private/reference/roadmap.md (Phase 10).

Why

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:

  • 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).
  • Executing constructors (the two-argument BRepAlgoAPI_* forms) are not bound, so the double-execution footgun is unrepresentable.

It also releases the GIL around kernel calls and ships type stubs, neither of which upstream does.

Build

OCCT is compiled once into a builder image and reused; it is never built on the production host (4 cores, and a kernel build is multi-hour). Wheels are built here on a dev box and published to the Gitea package registry.

make image    # once, ~40 min: compiles OCCT 7.9.3 into the builder image
make dev      # inner loop: incremental compile + tests
make wheel    # compile, stubs, auditwheel, self-containment smoke test
make publish  # -> https://git.stroblme.de/api/packages/N3XD/pypi

Credentials go in .secrets (gitignored) as UV_PUBLISH_USERNAME / UV_PUBLISH_PASSWORD. Consumers read anonymously — the package is public:

uv pip install --index-url https://git.stroblme.de/api/packages/N3XD/pypi/simple/ \
    --prerelease=allow n3xd-ocp

Versions are <occt-version>.N, enforced at configure time against the OCCT actually found, so the kernel a wheel wraps is readable from its version alone. The registry refuses to republish a version; iteration builds therefore carry a .devN suffix and are the only ones the registry's cleanup rule collects.

Description
No description provided
Readme 273 KiB
Languages
C++ 59.6%
Python 34.2%
Shell 3.2%
Dockerfile 1.2%
CMake 0.9%
Other 0.9%