7.6 KiB
Native OCCT history provider
This provider is compiled from the cached OCCT checkout selected by
OCCT_SOURCE_DIR and exposes native Boolean and PartDesign history APIs through
Emscripten Embind. The provider keeps TopoDS_Shape handles and history queries in one
WASM instance. A handle from @bitbybit-dev/occt must never be passed directly
to this module because WebAssembly linear memories are independent.
Build and verify it with the project wrapper:
./npmw run build:occt-history
./npmw run test:occt-history
The build also publishes the JS/WASM pair to
public/native/occt-history/, which is the default URL used by
NativeOcctHistoryWorkerProvider. The generated artifacts remain ignored; a
clean checkout must run the build after restoring the pinned OCCT source and
Emscripten toolchain.
FreeCAD private naming build boundary
The default build is intentionally OCCT-only. It does not export
freecadNamingAbiVersion, freecadNamingCapabilitiesJson, or
freecadNamingEvidenceJson, and it must not be described as exact FreeCAD
naming support.
A separate fail-closed build lane is available for an actual FreeCAD WASM SDK:
FREECAD_WASM_SDK_DIR=/absolute/path/to/sdk ./npmw run check:freecad-naming-sdk
FREECAD_WASM_SDK_DIR=/absolute/path/to/sdk ./npmw run build:freecad-naming-worker
./npmw run check:occt-history-artifact
The SDK layout is defined by freecad-wasm-sdk-manifest.example.json. The
checker requires the locked FreeCAD 1.1.1 commit, Emscripten 3.1.69, wasm Qt
and Python targets, private App headers, hashed static FreeCAD/Part/Qt/Python
libraries, and a hashed bridge source exporting all three callbacks. If any
input is absent, build:freecad-naming-worker exits before rebuilding or
publishing the OCCT-only artifact. A successful artifact probe still only
establishes ABI linkage; exact promotion additionally requires valid
MappedNameRef, StringHasher, ElementMap2, stage history, and round-trip evidence.
The repository also carries a prerequisite-only source probe. It builds QtBase
6.8.2 Qt6Core for wasm, then compiles the locked FreeCAD IndexedName.cpp and
MappedName.cpp sources without exporting the production naming callbacks:
./npmw run build:qt6-wasm-core
./npmw run build:freecad-naming-source-probe
./npmw run test:freecad-naming-source-probe
./npmw run check:freecad-private-naming-boundary
Passing this probe establishes that the private source subset and toolchain are
cross-compilable. It does not link the production OCCT Worker, does not close
EX-TSN-02, and does not change systemExact=false.
The versioned JSON request carries document objectId, stable positive
objectTag, prior naming evidence, result object identity, result tag, stage
DAG, STEP/BRep, and OCCT Generated/Modified/Deleted history. No Web fallback is
allowed to synthesize a FreeCAD private token.
The exported booleanHistory(object, tool, operation) function supports
fuse, cut, and common. It returns the native result shape, per-input
modified/generated/deleted records, a validity/topology/quality summary,
and capability flags. prismHistory(profile, dx, dy, dz) adds the first
PartDesign Pad contract: profile vertices can generate edges and profile edges
can generate faces, while the profile face is preserved as a result face.
booleanProbe and booleanResult are intentionally smaller operations for
Worker stress/ownership gates; callers must delete every returned Embind shape
handle. Primitive constructors cover positioned boxes, cylinders, spheres,
cones and a test rectangle Face. The provider also exports shapeToStep(shape),
booleanHistoryFromStep(objectStep, toolStep, operation) and
prismHistoryFromStep(profileStep, dx, dy, dz). The STEP functions are the
cross-WASM transport: Bitbybit exports STEP text, the native provider reads it
with STEPControl_Reader, returns the result again as resultStep, and no
linear-memory pointer crosses the boundary. Pad history currently requires a
valid planar Face profile; solids are rejected by OCCT rather than silently
treated as sketches. loftHistoryFromStep(firstSectionStep, secondSectionStep, ruled) adds a verified two-section solid loft using BRepOffsetAPI_ThruSections.
It records generated edges/faces for both source profiles; more than two
sections, closed lofts, and PartDesign base fusion/cut stay on the signature
history path until their multi-source contract is implemented.
pipeHistoryFromStep(profileStep, spineStep) adds a verified single-edge
open-spine solid sweep using BRepOffsetAPI_MakePipe. It records profile
vertex/edge generation, profile end caps, and spine edge/endpoint provenance;
multi-edge spines, Frenet/transition modes, and hollow profiles remain explicit
unsupported cases.
filletHistoryFromStep(baseStep, radius) enables the first
native dress-up slice: OCCT BRepFilletAPI_MakeFillet applies a fixed radius to
all source edges and returns per-edge/face Modified, Generated, and Deleted
relations with result-kind mapping. The native build enables TKFillet and its
TKBool dependency.
chamferHistoryFromStep(baseStep, distance) uses the same native history
collector with BRepFilletAPI_MakeChamfer for a symmetric, fixed-distance,
all-edge chamfer.
holeHistoryFromStep(baseStep, radius, depth, px, py, pz, dx, dy, dz) composes
an OCCT cylinder and BRepAlgoAPI_Cut for a straight cylindrical hole with
explicit position and direction, returning the Boolean source history. Thread,
counterbore, countersink, and face-attached hole semantics remain outside this
minimal native contract.
draftHistoryFromStep(baseStep, faceIndex, angle, direction, neutralPlane, reversed) uses BRepOffsetAPI_DraftAngle from TKOffset for one explicitly
selected source face. It returns native per-subshape history and rejects an
invalid face index, zero direction, zero angle, or invalid neutral plane before
publishing a result. Multi-face propagation and STEP files whose imported face
orientation OCCT cannot draft remain explicit unsupported/error cases.
thicknessHistoryFromStep(baseStep, faceIndex, offset, intersectionJoin) uses
BRepOffsetAPI_MakeThickSolid for one explicitly removed source face and
returns native offset history. Zero offsets and invalid face indexes are
rejected before execution.
linearPatternHistoryFromStep(baseStep, dx, dy, dz) creates one transformed
copy and fuses it with the source, preserving both Boolean input histories.
The contract intentionally covers exactly two whole-shape instances.
polarPatternHistoryFromStep(baseStep, axis, angle) creates one rotated copy
and fuses it with the source. It likewise covers exactly two whole-shape
instances around an explicit finite axis.
mirroredHistoryFromStep(baseStep, planeOrigin, planeNormal) creates one plane
reflected copy and fuses it with the source. The native contract is limited to
one whole-shape base, one standard document plane, and a fused result.
The multiTransformHistoryFromStep(baseStep, steps) binding accepts two to six
ordered two-instance linear, polar, or mirrored whole-shape steps. Each created
instance retains its transformed Base subshape mapping; one multi-argument Fuse
then aggregates every instance history back to the original Base indexes. The
single-step protocol continues to reuse the individual verified bindings.
The TypeScript boundary mapper is mapNativeOcctHistoryRecords; the reusable
createNativeOcctStepHistoryBridge exports Bitbybit ShapeHandles to STEP and
converts provider source names into document object IDs before calling
captureNativeTopologyHistory. The direct handle API remains for calls that
stay inside this single native WASM instance.