void update boundary provenance

This commit is contained in:
Stewart Allen 2026-03-02 19:06:18 -05:00
commit 79ef7130d4
2 changed files with 64 additions and 15 deletions

View file

@ -2307,8 +2307,9 @@ function edgeKey(a, b) {
}; };
}, },
resolveEdgeFromSource(source = {}) { resolveEdgeFromSource(source = {}, options = {}) {
if (source?.type !== 'solid-edge') return null; if (source?.type !== 'solid-edge') return null;
const allowGlobalFallback = options?.allowGlobalFallback !== false;
const targetSolidId = String(source?.solid_id || ''); const targetSolidId = String(source?.solid_id || '');
const targetFeatureId = String(source?.solid_feature_id || ''); const targetFeatureId = String(source?.solid_feature_id || '');
const sourceFaceId = Number(source?.face_id); const sourceFaceId = Number(source?.face_id);
@ -2380,11 +2381,13 @@ function edgeKey(a, b) {
} }
if (byFeature.length) searchSets.push(byFeature); if (byFeature.length) searchSets.push(byFeature);
} }
if (allowGlobalFallback) {
const all = []; const all = [];
for (const solid of solids) { for (const solid of solids) {
if (solid?.id) all.push(String(solid.id)); if (solid?.id) all.push(String(solid.id));
} }
if (all.length) searchSets.push(all); if (all.length) searchSets.push(all);
}
let best = null; let best = null;
let bestScore = Infinity; let bestScore = Infinity;
const scanSet = (wanted = []) => { const scanSet = (wanted = []) => {
@ -2418,7 +2421,7 @@ function edgeKey(a, b) {
return best; return best;
}, },
resolvePointFromSource(source = {}) { resolvePointFromSource(source = {}, options = {}) {
if (source?.type !== 'solid-edge') return null; if (source?.type !== 'solid-edge') return null;
const targetSolidId = String(source?.solid_id || ''); const targetSolidId = String(source?.solid_id || '');
const sourceFaceId = Number(source?.face_id); const sourceFaceId = Number(source?.face_id);
@ -2432,7 +2435,7 @@ function edgeKey(a, b) {
if (world) return world; if (world) return world;
} }
} }
const seg = this.resolveEdgeFromSource(source); const seg = this.resolveEdgeFromSource(source, options);
if (!seg) return null; if (!seg) return null;
const kind = source?.point_kind || 'mid'; const kind = source?.point_kind || 'mid';
if (kind === 'a') return seg.aWorld; 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 || ''); const sourceType = String(source?.type || '');
if (sourceType !== 'solid-face' && sourceType !== 'face') return null; if (sourceType !== 'solid-face' && sourceType !== 'face') return null;
const allowGlobalFallback = options?.allowGlobalFallback !== false;
const solidId = String(source?.solid_id || ''); const solidId = String(source?.solid_id || '');
const preferredSolidId = solidId || null; const preferredSolidId = solidId || null;
const view = solidId ? this._meshViews.get(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); evalView(c.sid, c.meshView, 0.06);
} }
} }
if (!best) { if (!best && allowGlobalFallback) {
for (const c of candidates) { for (const c of candidates) {
const bias = preferredSolidId && c.sid === preferredSolidId ? 0.02 : 0; const bias = preferredSolidId && c.sid === preferredSolidId ? 0.02 : 0;
evalView(c.sid, c.meshView, bias); evalView(c.sid, c.meshView, bias);
@ -3075,12 +3079,14 @@ function edgeKey(a, b) {
}; };
}, },
refreshSketchFaceAttachments() { refreshSketchFaceAttachments(options = {}) {
const api = getApi(); const api = getApi();
const features = api.features.list() || []; const features = api.features.list() || [];
const eligible = options?.eligibleSketchIds instanceof Set ? options.eligibleSketchIds : null;
let changed = false; let changed = false;
for (const feature of features) { for (const feature of features) {
if (feature?.type !== 'sketch') continue; if (feature?.type !== 'sketch') continue;
if (eligible && !eligible.has(String(feature?.id || ''))) continue;
const target = feature?.target || {}; const target = feature?.target || {};
let source = target?.source || null; let source = target?.source || null;
let resolved = null; let resolved = null;
@ -3134,7 +3140,11 @@ function edgeKey(a, b) {
} }
if (source?.type !== 'solid-face' && source?.type !== 'face') continue; if (source?.type !== 'solid-face' && source?.type !== 'face') continue;
if (!resolved) { 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; if (!resolved?.frame) continue;
const frame = this.applyOffsetToFrame(resolved.frame, Number(feature?.target?.offset || 0)); 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._meshCache = result?.meshCache || new Map();
this.syncRuntime(); this.syncRuntime();
let derivedChanged = false; const allFeatures = api.features.list() || [];
for (const feature of (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 (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)) { if (api.interact?.refreshDerivedSketchGeometry?.(feature)) {
derivedChanged = true; derivedChanged = true;
} }
} }
const rebound = this.refreshSketchFaceAttachments(); const rebound = this.refreshSketchFaceAttachments({ eligibleSketchIds });
if (rebound || derivedChanged) { if (rebound || derivedChanged) {
if (persist) { if (persist) {
await api.document.save({ await api.document.save({

View file

@ -2063,7 +2063,9 @@ function refreshDerivedSketchGeometry(feature) {
let changed = false; let changed = false;
const updatePointFromSource = (point, source) => { const updatePointFromSource = (point, source) => {
const world = api.solids?.resolvePointFromSource?.(source) || null; const world = api.solids?.resolvePointFromSource?.(source, {
allowGlobalFallback: false
}) || null;
if (!world) return; if (!world) return;
const local = this.worldToSketchLocal(world, basis); const local = this.worldToSketchLocal(world, basis);
if (!local) return; if (!local) return;
@ -2078,7 +2080,9 @@ function refreshDerivedSketchGeometry(feature) {
updatePointFromSource(point, point.source || null); updatePointFromSource(point, point.source || null);
} }
for (const line of derivedLines) { 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; if (!seg) continue;
const p1 = byId.get(line.a); const p1 = byId.get(line.a);
const p2 = byId.get(line.b); const p2 = byId.get(line.b);