From 79ef7130d4194e5ff5bea9ef06a936d7a3f4d08a Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Mon, 2 Mar 2026 19:06:18 -0500 Subject: [PATCH] void update boundary provenance --- src/void/api/solids.js | 73 +++++++++++++++++++++++++++++++-------- src/void/sketch/create.js | 8 +++-- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/void/api/solids.js b/src/void/api/solids.js index 35f19c5c..0f39f435 100644 --- a/src/void/api/solids.js +++ b/src/void/api/solids.js @@ -2307,8 +2307,9 @@ function edgeKey(a, b) { }; }, - resolveEdgeFromSource(source = {}) { + resolveEdgeFromSource(source = {}, options = {}) { if (source?.type !== 'solid-edge') return null; + const allowGlobalFallback = options?.allowGlobalFallback !== false; const targetSolidId = String(source?.solid_id || ''); const targetFeatureId = String(source?.solid_feature_id || ''); const sourceFaceId = Number(source?.face_id); @@ -2380,11 +2381,13 @@ function edgeKey(a, b) { } if (byFeature.length) searchSets.push(byFeature); } - const all = []; - for (const solid of solids) { - if (solid?.id) all.push(String(solid.id)); + if (allowGlobalFallback) { + const all = []; + for (const solid of solids) { + if (solid?.id) all.push(String(solid.id)); + } + if (all.length) searchSets.push(all); } - if (all.length) searchSets.push(all); let best = null; let bestScore = Infinity; const scanSet = (wanted = []) => { @@ -2418,7 +2421,7 @@ function edgeKey(a, b) { return best; }, - resolvePointFromSource(source = {}) { + resolvePointFromSource(source = {}, options = {}) { if (source?.type !== 'solid-edge') return null; const targetSolidId = String(source?.solid_id || ''); const sourceFaceId = Number(source?.face_id); @@ -2432,7 +2435,7 @@ function edgeKey(a, b) { if (world) return world; } } - const seg = this.resolveEdgeFromSource(source); + const seg = this.resolveEdgeFromSource(source, options); if (!seg) return null; const kind = source?.point_kind || 'mid'; if (kind === 'a') return seg.aWorld; @@ -2946,9 +2949,10 @@ function edgeKey(a, b) { }; }, - resolveSketchFrameForSource(source, preferredFrame = null) { + resolveSketchFrameForSource(source, preferredFrame = null, options = {}) { const sourceType = String(source?.type || ''); if (sourceType !== 'solid-face' && sourceType !== 'face') return null; + const allowGlobalFallback = options?.allowGlobalFallback !== false; const solidId = String(source?.solid_id || ''); const preferredSolidId = solidId || null; const view = solidId ? this._meshViews.get(solidId) : null; @@ -3060,7 +3064,7 @@ function edgeKey(a, b) { evalView(c.sid, c.meshView, 0.06); } } - if (!best) { + if (!best && allowGlobalFallback) { for (const c of candidates) { const bias = preferredSolidId && c.sid === preferredSolidId ? 0.02 : 0; evalView(c.sid, c.meshView, bias); @@ -3075,12 +3079,14 @@ function edgeKey(a, b) { }; }, - refreshSketchFaceAttachments() { + refreshSketchFaceAttachments(options = {}) { const api = getApi(); const features = api.features.list() || []; + const eligible = options?.eligibleSketchIds instanceof Set ? options.eligibleSketchIds : null; let changed = false; for (const feature of features) { if (feature?.type !== 'sketch') continue; + if (eligible && !eligible.has(String(feature?.id || ''))) continue; const target = feature?.target || {}; let source = target?.source || null; let resolved = null; @@ -3134,7 +3140,11 @@ function edgeKey(a, b) { } if (source?.type !== 'solid-face' && source?.type !== 'face') continue; if (!resolved) { - resolved = this.resolveSketchFrameForSource(source, feature.plane || null); + // Auto-refresh path must not drift to unrelated/newer solids when + // the original source solid/face no longer exists. + resolved = this.resolveSketchFrameForSource(source, feature.plane || null, { + allowGlobalFallback: false + }); } if (!resolved?.frame) continue; const frame = this.applyOffsetToFrame(resolved.frame, Number(feature?.target?.offset || 0)); @@ -3371,14 +3381,49 @@ function edgeKey(a, b) { } this._meshCache = result?.meshCache || new Map(); this.syncRuntime(); - let derivedChanged = false; - for (const feature of (api.features.list() || [])) { + const allFeatures = api.features.list() || []; + const featureIndexById = new Map(allFeatures.map((f, i) => [String(f?.id || ''), i])); + const eligibleSketchIds = new Set(); + const getFeatureIndex = (fid) => { + const key = String(fid || ''); + if (!key) return -1; + const idx = featureIndexById.get(key); + return Number.isFinite(idx) ? Number(idx) : -1; + }; + const hasFutureSourceDependency = (sketchFeature) => { + const sketchIndex = getFeatureIndex(sketchFeature?.id); + if (sketchIndex < 0) return false; + const sourceFeatureIds = new Set(); + const targetSource = sketchFeature?.target?.source || null; + const targetSourceFeatureId = String(targetSource?.solid_feature_id || ''); + if (targetSourceFeatureId) sourceFeatureIds.add(targetSourceFeatureId); + const entities = Array.isArray(sketchFeature?.entities) ? sketchFeature.entities : []; + for (const entity of entities) { + if (!entity?.derived) continue; + const src = entity?.source || null; + const srcFeatureId = String(src?.solid_feature_id || ''); + if (srcFeatureId) sourceFeatureIds.add(srcFeatureId); + } + for (const srcId of sourceFeatureIds) { + const srcIndex = getFeatureIndex(srcId); + if (srcIndex > sketchIndex) return true; + } + return false; + }; + for (const feature of allFeatures) { if (feature?.type !== 'sketch') continue; + if (hasFutureSourceDependency(feature)) continue; + eligibleSketchIds.add(String(feature?.id || '')); + } + let derivedChanged = false; + for (const feature of allFeatures) { + if (feature?.type !== 'sketch') continue; + if (!eligibleSketchIds.has(String(feature?.id || ''))) continue; if (api.interact?.refreshDerivedSketchGeometry?.(feature)) { derivedChanged = true; } } - const rebound = this.refreshSketchFaceAttachments(); + const rebound = this.refreshSketchFaceAttachments({ eligibleSketchIds }); if (rebound || derivedChanged) { if (persist) { await api.document.save({ diff --git a/src/void/sketch/create.js b/src/void/sketch/create.js index cec10416..faa23335 100644 --- a/src/void/sketch/create.js +++ b/src/void/sketch/create.js @@ -2063,7 +2063,9 @@ function refreshDerivedSketchGeometry(feature) { let changed = false; const updatePointFromSource = (point, source) => { - const world = api.solids?.resolvePointFromSource?.(source) || null; + const world = api.solids?.resolvePointFromSource?.(source, { + allowGlobalFallback: false + }) || null; if (!world) return; const local = this.worldToSketchLocal(world, basis); if (!local) return; @@ -2078,7 +2080,9 @@ function refreshDerivedSketchGeometry(feature) { updatePointFromSource(point, point.source || null); } for (const line of derivedLines) { - const seg = api.solids?.resolveEdgeFromSource?.(line.source || null); + const seg = api.solids?.resolveEdgeFromSource?.(line.source || null, { + allowGlobalFallback: false + }); if (!seg) continue; const p1 = byId.get(line.a); const p2 = byId.get(line.b);