Commit Graph

4 Commits

Author SHA1 Message Date
8175b8aff3 docs
Signed-off-by: stroblme <stroblme@posteo.de>
2026-08-11 15:07:47 +02:00
2c2c4e4712 10C Inc 1: core modeling
Binds the modeling core the app builds every feature out of — 93 of its 138
symbols now resolve, up from 34. New modules: GeomAbs, Geom2d, Geom,
TCollection, TColgp, TColStd, GProp, BRepGProp, Bnd, BRepBndLib, Adaptor3d,
BRepAdaptor, GeomLProp, GeomAPI, BRepBuilderAPI, BOPAlgo, BRepAlgoAPI,
BRepPrimAPI, GC, BRepMesh; gp and BRep_Tool completed.

Three structural decisions:

- BRepBuilderAPI_MakeShape carries Build/Shape/Generated/Modified/IsDeleted for
  every maker in the binding, so the booleans, the primitives and (later) the
  fillet builders all answer the app's duck-typed provenance layer through
  ordinary virtual dispatch. History lists come back copied, so they outlive
  the builder.
- The executing two-argument BRepAlgoAPI constructors stay unbound; operands go
  in through SetArguments/SetTools. Section keeps Init1/Init2, which are plain
  setters. BOPAlgo moved up from Inc 2 — SetGlue needs its enum.
- Adaptor3d is registered although the app never imports it: every method it
  calls on BRepAdaptor_Curve/Surface is a virtual declared there, so binding
  them once on the bases leaves mod_BRepAdaptor.cpp with just constructors.

Gate: tests/test_inc1_modeling.py against reference values gen_fixtures.py now
records from the stock wheel — measurements, per-face area/centroid in map
order, mesh counts, and the boolean history map compared exactly, since that is
the substrate the app's topological naming is built on.

tools/sigdiff.py compares our bound surface against stock's, because a wrong
nb::init<> is silent: MakePrism's five-argument form bound OCCT's semi-infinite
gp_Dir overload (gp_Dir converts from gp_Vec), producing a valid solid of the
wrong shape with the flags shifted along. The fixture digest caught it; sigdiff
finds the class of bug directly, and now reports only one deliberate deviation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfriM8XUkn7uYf5Dwe2xo6
2026-08-10 19:52:58 +02:00
091a2ad0cf Housekeeping ahead of the Inc 1-4 coverage work
- inventory.py --methods: report the instance methods the app calls per class,
  plus chained calls that constrain a return type. --check says which classes
  to bind; this says what to bind on them, which is what writing ~38 module
  TUs needs.
- Drop StlAPI from the inventory: StlAPI_Writer has no app call site (the only
  use was a test fixture, now on the app's own STL writer). 138 symbols / 47
  modules.
- adding-symbols.md: scope the executing-constructor ban to the BRepAlgoAPI
  booleans, which are the only classes with a deferred Set*/Build form —
  BRepMesh_IncrementalMesh, GeomAPI_*, BRepCheck_Analyzer and friends compute
  in their constructor by design and bind as stock. Replace the per-increment
  app-test guidance: backend/tests/conftest.py imports n3xd.main, so no app
  test can collect until the last module is bound. Increments gate on
  stock-recorded fixtures here; the app suite is the Inc 4 gate.
- parity_venv.sh: run the ocp suite in the swapped venv (it imports only
  OCP/n3xd_ocp, so it works throughout).
- Fix a stale macro name in occt_handle.h (ocp_new, not OCP_TRANSIENT_NEW) and
  drop the unused ocp_transient_class helper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfriM8XUkn7uYf5Dwe2xo6
2026-08-10 19:23:27 +02:00
6139852768 Phase 10A/10B Inc 0: build system, handle model, first module surface
Builds n3xd-ocp end to end and publishes 7.9.3.1.dev1 to the Gitea registry,
where it installs anonymously and passes its suite.

- occt/Dockerfile: OCCT 7.9.3 compiled once into a manylinux_2_28 builder
  image (base digest + tarball sha256 pinned), Draw/VTK/Tk/Xlib/OpenGL off,
  FreeType on, -O2 without fast-math or march=native. A final layer asserts
  TKService/TKV3d exist with no libGL/libX11 DT_NEEDED, which is what lets the
  app image drop libgl1/libx11-6. Mounted into, never built FROM.
- scikit-build-core + nanobind STABLE_ABI -> one cp312-abi3 extension that
  registers every OCP.* submodule via PyImport_AddModule, so `import
  OCP.TopoDS` needs no shim and cls.__module__ is right. Version <occt>.N is
  asserted against the OCCT found, keeping occt_version() truthful.
- occt_handle.h: type caster for opencascade::handle<T> over OCCT's intrusive
  refcount. Wrappers are non-owning instances holding exactly one handle in
  their keep-alive list, reusing an existing wrapper so identity survives a
  round trip. Transient constructors go through ocp_new (never nb::init<>,
  which would let OCCT delete nanobind's storage); the caster refuses a
  refcount-0 object rather than corrupt the heap. Verified under ASAN with no
  memory-safety errors, plus an RSS bound over 50k create/destroy cycles.
- Sub-shapes are returned by value everywhere, making the TShape lifetime class
  that segfaulted a process-global face memo unrepresentable.
- Standard_Failure derives RuntimeError, with ~20 concrete types dispatched on
  the dynamic OCCT type (cad_pool marshals failures home by type name).
- Inc 0 surface: gp subset, TopAbs, TopoDS (+ downcasts), TopExp, TopLoc,
  TopTools, BRep, BinTools, Poly, Standard. 34 of the app's 139 symbols.
- n3xd_ocp: additive APIs kept out of the OCP namespace so parity testing stays
  meaningful. bintools (shape <-> bytes, GIL-free, byte-identical) and _debug.

Two findings worth the record, both verified against the stock wheel rather
than assumed: upstream binds __hash__ but leaves __eq__ at identity, which is
exactly what geom_memo.py's hash-bucket + IsSame scan is built around, so we
match it instead of "fixing" it; and BinTools can release the GIL after all, by
slurping the file-like object instead of bridging a streambuf that would call
back into Python.

Gate: BREP round-trips are byte-identical to cadquery-ocp-novtk across six
fixtures (the generator asserts stock idempotency first). That matters beyond
IPC — derive.py content-addresses BREP payloads by sha256 and stores the ref.
2026-08-10 16:10:28 +02:00