Skip to content

v0.2.0

Latest

Choose a tag to compare

@gsdali gsdali released this 19 Aug 20:58
· 15 commits to main since this release
0b2ce07

Consolidates identity-table construction, which phase 2 left duplicated three ways (#7, PR #8).

No API break. New stored property with a default and new defaulted parameters only.

What is new

  • ShapeIdentity, a public type that builds all three identity tables from a shape and an optional BRepGraph. Previously this lived as three private helpers on CADFileLoader, reachable only through paths that tessellate.
  • CADLoadResult.identity, keyed by body id, built during the load, behind includeIdentity: Bool = false.

The two are complementary rather than alternatives, which is why both landed. Tables on CADLoadResult cannot serve CADViewportService.load(_:id:transform:), loadShape(_:id:), or OCCTSwiftUX's loadShape, none of which produces a CADLoadResult. A public builder alone cannot remove the shape-to-body pairing hazard.

includeIdentity defaults to false because it is not free: BRepGraph(shape:) measures 5.0ms against 9.6ms for the mesh on a 14-face solid, 3.8ms of that inside toBREPString(). OCCTDesignLoop calls load/loadFromManifest from seven sites that never pick.

Why it mattered

The three copies agreed on every success path and diverged on every failure path. Same enumerations, same uid minting, same ordinal space. What differed was behaviour on a nil graph, on the edge-polyline-only path, and above all on a shapes/bodies count mismatch, where one copy did not detect it, one wiped all identity including correctly-paired bodies, and one nil'd every body's shape.

None of those three answers was right. The mismatch is a symptom, visible only from outside, of a pairing the loader knows exactly: CADFileLoader's STL/IGES robust reload appends a shape even when that input produced no body. Building identity inside the loader keyed by body id removes the pairing rather than guarding it. CADViewportService had implemented that guard three times for the one hazard, including once against dictionaries emptied on the line above.

Also in this release

  • shapeToBodyAndMetadata no longer builds three identity tables and discards them, so three fewer shape-map walks per body on the path every load takes.
  • The edge-polyline-only branch now builds an ordinary face table instead of forcing an empty one.

Verification

357 tests in 32 suites, up from 343, with zero deletions. The new pairing test was mutation-checked: deliberately mispairing identity inside the loader fails it. Worth recording that the pick test alongside it did not catch that mutation, since both fixture bodies have six faces and both mint a uid, which is why the pairing test compares bounding boxes rather than indices.

swift-format lint --strict and swiftlint lint --strict clean.

Known issue carried forward

#9: ShapeIdentity builds its face and edge tables with compactMap, so a single failed Shape.fromFace shifts every later ordinal and the table names the wrong sub-shape. This was carried identically by all three original copies, so it is not a regression, and consolidating it into one place is what makes it fixable. It is not fixed here.

For consumers

OCCTSwiftUX's own ShapeIdentity copy becomes fully removable against this release, including the shape-to-body pairing guard added in OCCTSwiftUX#30, which now has nothing left to guard. Note when migrating that OCCTSwiftUX drops the BRepGraph it builds while this type retains it.