8.7 KiB
Void Face Provenance Plan (Boundary-First, Split Faces)
Goal
Track which portions of resulting solids come from which sketch extrude regions, including after union/subtract, while keeping storage compact and spline-ready.
Execution Status (2026-03-02)
Completed:
- Plan authored and staged into phased implementation.
- Debug visualization toggles added to preferences and wired to solids runtime:
- Boundary loop rendering from GeometryStore.
- Segment rendering from GeometryStore.
- Segment/surface/region ID labels (overlay text).
- Fixed world/local debug overlay transform bug:
- GeometryStore points are world-space; line geometry parented under solids root must convert world -> root local because
space.WORLDis rotated -90deg on X.
In progress:
- Converting this plan into code-level milestone execution with strict acceptance checks.
Next up:
- Add first
surface_patch_idselection plumbing (read-only pass-through). - Thread Manifold relation metadata through kernel adapters.
- Start mixed-face partition scaffold from seeded
surface_patches.
Decisions
- Primary provenance is
boundary/region/surface-patch, not raw triangle ownership. - Triangle ownership is derived runtime index only (
tri -> surface_patch_id) and can be rebuilt. - Multi-source output faces must be split into multiple bounded surface patches so each patch has one canonical source region.
- Line/arc support ships first; segment model must support future spline kinds without schema redesign.
Scope
In scope:
- Extrude + boolean provenance tracking through rebuild pipeline.
- Face splitting by source-region boundaries.
- GeometryStore schema extension for stable patch-level IDs and source refs.
- Runtime mapping from picks (
face/edge) to canonical patch and source region.
Out of scope (initial pass):
- Native spline feature authoring.
- Long-lived persisted triangle provenance tables.
- Non-planar sketch-on-surface expansion beyond current behavior.
Data Model Changes
Add/extend document geometry_store entities:
-
segments[] -
kind: line | arc | spline -
geom: kind-specific payload -
sampled_polyline(optional cache for hit testing/partitioning) -
boundaries[] -
Ordered
segment_ids -
closed, orientation, optional parent/child nesting -
regions[] -
outer_boundary_id -
hole_boundary_ids[] -
source: canonical source ref (profile:<sketch>:<profile>) -
New
surface_patches[] -
id -
surface_id(geometric carrier face) -
boundary_ids[](outer + holes) -
source_region_id(single canonical owner) -
source_feature_id(extrude feature) -
solid_id -
status(direct,boolean-derived,rebound) -
New runtime-only
topology.patch_tri_index -
Maps mesh triangles to
surface_patch_idfor selection/render acceleration.
Kernel Boundary Changes (Manifold)
Current kernel adapter only round-trips positions/indices; relation metadata is dropped.
Planned update:
- Preserve Manifold mesh relation fields where available (
runOriginalID,faceID, related run metadata). - Carry relation metadata through
extrudePolygons()andbooleanMeshes(). - Emit relation-aware intermediate records to rebuild stage (not directly persisted).
This enables deterministic attribution from boolean output back to input generated solids/regions before patch splitting.
Provenance Build Pipeline
Stage A: Sketch Region Capture
- Keep current closed-loop profile extraction for line/arc.
- Emit canonical
region_id = profile:<sketch>:<profile>. - Record region boundaries using generic segment schema (
line|arcnow,splinelater).
Stage B: Extrude Seed Patches
- Extrude each selected sketch region.
- Seed cap/side patch candidates with direct source region refs.
- Preserve manifold relation fields in intermediate mesh record.
Stage C: Boolean Attribution
- Perform add/subtract/intersect with relation-carrying meshes.
- Build attribution map from output primitives/runs to source seed patches.
- Mark ambiguous/mixed carrier surfaces for partitioning.
Stage D: Face Partitioning (Split Multi-Source Faces)
- For each mixed carrier surface, project contributing source boundaries to surface-local space.
- Build planar arrangement, split into disjoint bounded cells.
- Assign each cell a single
source_region_idby relation majority + geometric tie-break. - Emit one
surface_patchper bounded cell.
Stage E: Runtime Topology Index
- Build
tri -> surface_patch_idmap from patch partition output. - Use map for selection hit resolution and hover highlighting.
- Rebuild index each solids rebuild; do not persist large triangle maps.
Selection/Interaction Integration
- Face pick resolves to
surface_patch_idfirst, thensource_region_id. - Edge/boundary pick resolves to
boundary_id/segment_idthat belongs to a patch. - Extrude-profile hover/highlight uses
source_region_id -> surface_patch[]mapping. - Remove fallback heuristics that infer provenance only from coarse
source.profile_keys.
Storage and Performance
- Persist compact canonical graph (
segments/boundaries/regions/surface_patches). - Keep triangle-level maps runtime-only to avoid doc bloat and instability across remeshes.
- Cache partition signatures per carrier surface to avoid full repartition when unchanged.
Migration Plan
Phase 1: Schema and Adapters
- Add
surface_patchesschema and runtime index container. - Introduce generic segment schema (
kind + geom) with current line/arc emitters. - Add compatibility normalizer for older docs (missing
surface_patches).
Phase 2: Kernel Metadata Plumbing
- Extend solid kernel adapter to preserve manifold relation metadata.
- Pass relation metadata through worker/main rebuild paths.
Phase 3: Patch Builder
- Implement mixed-face detection.
- Implement local-space boundary arrangement and patch emission.
- Add deterministic patch IDs/signatures.
Phase 4: Resolver Cutover
- Switch face selection from coarse face groups to
surface_patchentities. - Update properties/tree hover mapping to patch/source-region links.
Phase 5: Cleanup
- Remove coarse provenance fallbacks once parity is validated.
- Keep compatibility reader for older docs without
surface_patches.
Validation Plan
Unit tests:
- Region extraction determinism (line/arc).
- Mixed-face partitioning into disjoint bounded patches.
- Single-owner assignment per patch.
- Deterministic patch IDs under stable input.
Integration tests:
- Two extrudes unioned: top face splits by source boundary and highlights per profile.
- Subtract operation: surviving walls/caps retain correct source region refs.
- Edit upstream sketch profile: downstream patch mapping updates without manual repair.
- Rebuild in worker vs main thread yields identical patch/source mapping.
Regression guardrails:
- No persisted triangle tables in doc snapshots.
- No schema changes required to add spline segment kind later.
- Selection never reports mixed-source face entities.
- Any debug/runtime geometry under solids root must explicitly convert GeometryStore world coordinates to root-local coordinates.
Implementation Checklist
Phase 1:
- Done: update
src/void/api/geometry_store.jsschema to includesurface_patchesand runtime topology patch map container. - Done: extend
buildGeometryStoreSnapshot()insrc/void/api/solids.jsto emit seededsurface_patchesper face-loop with source-region candidate fields. - In progress: keep current face-key canonical mapping intact while adding optional patch ID fields.
Phase 2:
- Update
src/void/solid/kernel.jsmesh conversion to preserve manifold relation fields: - Input pass-through where provided (
runOriginalID,runIndex,faceID, etc.). - Output pass-through into rebuild intermediate structures.
- Add worker payload support for relation arrays when present.
Phase 3:
- Implement mixed-source detection in
src/void/solid/rebuild.js. - Add per-surface local partition pass and emit patch boundaries.
- Assign one canonical
source_region_idper patch.
Phase 4:
- Extend selection resolver and solids hit mapping to prefer patch IDs over raw face IDs.
- Add properties/tree hover mapping from extrude profile -> patch IDs.
- Remove coarse fallback once parity checks pass.
Phase 5:
- Add deterministic integration tests for union/subtract split-face provenance.
- Remove temporary migration branches and finalize docs.
Acceptance Criteria
- Every selectable resulting face area maps to exactly one
source_region_id. - Multi-source carrier faces are visibly and topologically split at source boundaries.
- Extrude profile hover/select maps accurately to resulting solid patches after booleans.
- GeometryStore stays compact and stable; triangle mapping is derived at runtime.