185 lines
8.7 KiB
Markdown
185 lines
8.7 KiB
Markdown
|
|
# Void Geometry Graph Plan (Surfaces + Boundaries)
|
||
|
|
|
||
|
|
## Progress Checkpoint (2026-02-13)
|
||
|
|
|
||
|
|
1. Completed:
|
||
|
|
2. `GeometryStore` is persisted in document state and populated from solids runtime snapshots.
|
||
|
|
3. Selection pipeline was split to `interact/selection_resolver.js` and now emits typed candidates (`profile/solid-face/solid-edge`) with canonical entity descriptors.
|
||
|
|
4. Extrude targets carry `region_id`; chamfer edge refs carry `boundary_segment_id` + entity metadata.
|
||
|
|
5. New canonical mapping bridge is active in solids selection:
|
||
|
|
6. face key -> canonical `surface` id
|
||
|
|
7. edge key -> canonical `boundary-segment` id
|
||
|
|
8. loop edge key -> canonical `boundary` id
|
||
|
|
9. Resolver now consumes these mappings (`resolveCanonicalFaceEntity`, `resolveCanonicalEdgeEntity`) as primary IDs.
|
||
|
|
|
||
|
|
## Resume Pointers
|
||
|
|
|
||
|
|
1. Canonical mapping source:
|
||
|
|
2. `src/void/api/solids.js`:
|
||
|
|
3. `buildGeometryStoreSnapshot()` map population
|
||
|
|
4. `resolveCanonicalFaceEntity()`
|
||
|
|
5. `resolveCanonicalEdgeEntity()`
|
||
|
|
6. Canonical mapping consumer:
|
||
|
|
7. `src/void/interact/selection_resolver.js`
|
||
|
|
8. `resolvePrimarySurfaceHit()` entity assignment for face/edge candidates.
|
||
|
|
9. Canonical hard cutover completed:
|
||
|
|
10. Extrude profile refs resolve via `region_id` only.
|
||
|
|
11. Chamfer refs resolve via canonical `segment:*` / `boundary:*` ids only.
|
||
|
|
12. `input.solids` compatibility branches removed from solid-op edit paths.
|
||
|
|
13. Boundary-hover correction applied:
|
||
|
|
14. Face-edge resolution now prioritizes hovered-face boundary lookup before global solid edge intersections.
|
||
|
|
15. Boundary extraction uses the same crease threshold as rendered edges (`SOLID_CREASE_ANGLE_DEG`) to reduce partial/extra loop mismatches.
|
||
|
|
16. `getFaceEdgeHit()` now prefers closed-loop boundaries over open seam chains when both are near cursor.
|
||
|
|
17. Follow-up TODO:
|
||
|
|
18. During sketch editing, `Use (u)` should derive from other visible sketch entities (not only solids).
|
||
|
|
|
||
|
|
## Target Architecture
|
||
|
|
|
||
|
|
1. Adopt a single geometric graph centered on `surfaces` and `boundaries`, with solids as derived artifacts only.
|
||
|
|
2. Treat every selectable thing as one of:
|
||
|
|
3. `SurfaceRegion` (planar/non-planar bounded patch).
|
||
|
|
4. `Boundary` (closed loop on a surface).
|
||
|
|
5. `BoundarySegment` (line/arc/spline edge piece inside a boundary).
|
||
|
|
6. `BoundaryPoint` (segment endpoint, midpoint, center, intersection, projected point).
|
||
|
|
|
||
|
|
## Core Data Model
|
||
|
|
|
||
|
|
1. Add `GeometryStore` (document-persisted, versioned):
|
||
|
|
2. `surface_id`, `type` (`planar|curved`), `frame` (for planar), `source` provenance.
|
||
|
|
3. `boundary_id`, `surface_id`, ordered `segment_ids`, orientation, closure, area sign, nesting depth.
|
||
|
|
4. `segment_id`, `kind` (`line|arc|circle|polyline|nurbs`), param data, `owner_boundary_id`.
|
||
|
|
5. `point_id`, world/local coords, role (`endpoint|midpoint|center|derived|intersection`), references.
|
||
|
|
6. `region_id`, `surface_id`, boundary rings (`outer + holes`), selectable extrusion/chamfer profile token.
|
||
|
|
7. Add stable identity layer:
|
||
|
|
8. Every entity gets deterministic `geom_sig` + persistent `id`.
|
||
|
|
9. Derived entities keep `origin_ref` and dependency chain for rebind/rebuild.
|
||
|
|
10. Add `TopologyIndex` (runtime cache):
|
||
|
|
11. Maps solid mesh triangles/edges to source `surface_id` and `boundary_segment_id`.
|
||
|
|
12. Supports nearest-hit resolution with tolerance and tie-break rules.
|
||
|
|
|
||
|
|
## Selection and Hover System
|
||
|
|
|
||
|
|
1. Replace mode-specific picking with one `SelectionResolver` pipeline.
|
||
|
|
2. Input: ray hits + current mode + intent mask.
|
||
|
|
3. Output: ranked candidates of `point/segment/boundary/surface/region`.
|
||
|
|
4. Ranking rules:
|
||
|
|
5. Point proximity always wins near threshold.
|
||
|
|
6. Segment wins next when distance-to-curve below threshold.
|
||
|
|
7. Boundary/region wins when inside region and not near point/segment.
|
||
|
|
8. Surface wins otherwise.
|
||
|
|
9. Add per-mode intent masks:
|
||
|
|
10. Sketch mode: `point,segment,boundary,surface(region projection)`.
|
||
|
|
11. Extrude mode: `region` only.
|
||
|
|
12. Chamfer mode: `segment` only (plus face-to-edge expansion helper).
|
||
|
|
13. Boolean mode: `surface/body` selection groups.
|
||
|
|
14. Add consistent multi-select semantics:
|
||
|
|
15. Plain click toggles in active picker.
|
||
|
|
16. `space/esc` clear picker-local selection.
|
||
|
|
17. No cross-picker stealing while dialog active.
|
||
|
|
|
||
|
|
## Geometry Build Pipeline
|
||
|
|
|
||
|
|
1. Introduce staged rebuild in worker:
|
||
|
|
2. Stage A: Feature evaluation -> sketch geometry on target surfaces.
|
||
|
|
3. Stage B: Boundary graph build per surface (loop extraction, splitting, nesting).
|
||
|
|
4. Stage C: Region synthesis (`outer/holes`) with fill-rule consistency.
|
||
|
|
5. Stage D: Solid operations (extrude/boolean/chamfer) from region/surface references.
|
||
|
|
6. Stage E: Topology annotation back into `GeometryStore` for interaction.
|
||
|
|
7. Cache keys:
|
||
|
|
8. `feature_sig`, `surface_sig`, `boundary_sig`, `region_sig`.
|
||
|
|
9. Recompute only invalidated downstream stages.
|
||
|
|
|
||
|
|
## Sketch Integration
|
||
|
|
|
||
|
|
1. Sketches bind to `surface_id` + local frame, not transient face index.
|
||
|
|
2. `Use (u)` creates `derived segment/point` referencing source `segment_id/point_id`.
|
||
|
|
3. Derived geometry stores transform relation to host surface frame.
|
||
|
|
4. Midpoints become first-class `point_id` with constraint targetability.
|
||
|
|
5. Closed-area detection uses `boundary/region` graph directly (no separate ad-hoc fill path).
|
||
|
|
|
||
|
|
## Extrude Integration
|
||
|
|
|
||
|
|
1. Extrude input stores selected `region_id`s, not ad-hoc loops.
|
||
|
|
2. Region hover/selection always from boundary graph.
|
||
|
|
3. Live preview reads from current region snapshots.
|
||
|
|
4. Targets/tools in add/subtract reference resulting body ids, but source remains region-driven.
|
||
|
|
|
||
|
|
## Chamfer Integration
|
||
|
|
|
||
|
|
1. Chamfer input stores `boundary_segment_id`s (or section ids for partial edges).
|
||
|
|
2. Face click expands to boundary segments by adjacency policy.
|
||
|
|
3. No selection against regenerated transient mesh during edit.
|
||
|
|
4. Preview and final solve read same boundary refs to avoid drift.
|
||
|
|
|
||
|
|
## Projection / Derive Reliability
|
||
|
|
|
||
|
|
1. Stop pre-projecting everything.
|
||
|
|
2. Resolve hovered source entity first.
|
||
|
|
3. Project only selected/hovered entity into current sketch frame.
|
||
|
|
4. Keep source and projected visuals separate but linked by shared entity id.
|
||
|
|
|
||
|
|
## Planar/Non-Planar Classification
|
||
|
|
|
||
|
|
1. Surface classification at creation:
|
||
|
|
2. Planar stores orthonormal frame and scalar offset.
|
||
|
|
3. Curved stores param evaluator and principal directions where available.
|
||
|
|
4. Boundary segments on curved surfaces can still be selected/extruded/chamfered as references.
|
||
|
|
5. Sketch-on-face initially allowed only on planar surfaces; curved support can be staged later.
|
||
|
|
|
||
|
|
## Document Persistence
|
||
|
|
|
||
|
|
1. Persist `GeometryStore` plus feature list and timeline.
|
||
|
|
2. Persist only canonical geometry entities, not transient mesh selections.
|
||
|
|
3. Add schema version bump and hard reset path (allowed in this project stage).
|
||
|
|
4. Undo/redo stores deltas against `GeometryStore` entities for atomic operations.
|
||
|
|
|
||
|
|
## Migration Strategy
|
||
|
|
|
||
|
|
1. Phase 0: Add new store in parallel, keep existing runtime behavior.
|
||
|
|
2. Phase 1: Route hover/selection to `SelectionResolver` while existing builders stay.
|
||
|
|
3. Phase 2: Route sketch profiles/areas to `boundary/region`.
|
||
|
|
4. Phase 3: Route extrude inputs to `region_id`.
|
||
|
|
5. Phase 4: Route chamfer inputs to `segment_id`.
|
||
|
|
6. Phase 5: Remove legacy face/edge ad-hoc paths.
|
||
|
|
7. Forward-only: remove rollout toggles and legacy branching once parity is reached.
|
||
|
|
|
||
|
|
## Performance and Worker Plan
|
||
|
|
|
||
|
|
1. Keep all heavy geometry graph and topology steps in worker.
|
||
|
|
2. Main thread receives compact immutable snapshots and draw buffers.
|
||
|
|
3. Use incremental invalidation by dependency DAG from edited feature forward.
|
||
|
|
4. Add rebuild budget logging per stage to catch regressions early.
|
||
|
|
|
||
|
|
## Testing Plan
|
||
|
|
|
||
|
|
1. Unit tests:
|
||
|
|
2. Boundary extraction and nesting.
|
||
|
|
3. Region fill-rule behavior (self-intersecting + nested bulls-eye cases).
|
||
|
|
4. Selection ranking with tolerance.
|
||
|
|
5. Projection correctness for points/segments/surfaces.
|
||
|
|
6. Integration tests:
|
||
|
|
7. Sketch-on-face propagation after upstream edits.
|
||
|
|
8. Extrude profile row hover maps to produced solids.
|
||
|
|
9. Chamfer edit stability with multi-select.
|
||
|
|
10. Undo/redo atomicity in dialogs.
|
||
|
|
11. Fuzz tests:
|
||
|
|
12. Random sketch mutations + constraints + rebuild consistency checks.
|
||
|
|
13. Determinism check: same doc state yields same entity ids/topology signatures.
|
||
|
|
|
||
|
|
## Deliverables Sequence
|
||
|
|
|
||
|
|
1. `GeometryStore` + ids + schema.
|
||
|
|
2. `SelectionResolver` + mode masks.
|
||
|
|
3. `BoundaryGraphBuilder` + `RegionBuilder`.
|
||
|
|
4. Extrude refactor to `region_id`.
|
||
|
|
5. Chamfer refactor to `segment_id`.
|
||
|
|
6. Projection/use refactor to source-first selection.
|
||
|
|
7. Legacy path removal and cleanup docs.
|
||
|
|
|
||
|
|
## Acceptance Criteria
|
||
|
|
|
||
|
|
1. Hover/select behavior is identical and predictable across sketch/solid/chamfer modes.
|
||
|
|
2. Derived sketches follow upstream changes without requiring manual edit-open.
|
||
|
|
3. Extrude/chamfer operate on stable references, not transient mesh hits.
|
||
|
|
4. Nested/self-intersecting regions behave correctly for selection and extrusion.
|
||
|
|
5. No mode where selection silently switches entity class unexpectedly.
|