mirror of
https://github.com/flash555588/ai-model-workbench.git
synced 2026-07-22 06:56:38 +00:00
Validate measurement snap cache signature
This commit is contained in:
parent
60060e7223
commit
ddd8417c1c
4 changed files with 477 additions and 418 deletions
|
|
@ -10,6 +10,7 @@
|
|||
- UI: require the locked measurement target to be the frontmost normal pick before snapping, preventing hidden target geometry behind another part from receiving ruler endpoints.
|
||||
- UI: clear stale measurement snap status after cancelling a pending endpoint so the selected-object ruler returns to a neutral ready state.
|
||||
- Performance: cache selected-target measurement snap candidates while measuring so hover previews do not repeatedly rebuild vertex and edge lists for the same object.
|
||||
- Performance: validate selected-target measurement snap caches against target mesh signatures so transformed or updated geometry rebuilds snap candidates instead of reusing stale vertex and edge lists.
|
||||
- UI: restyle distance measurements as orthographic drawing-style dimension callouts with extension lines, arrowheads, and compact drafting labels instead of thick freehand ruler lines.
|
||||
- UI: remove the preview canvas native hover tooltip while preserving keyboard shortcut metadata for accessibility.
|
||||
- UI: clarify render scale versus measurement scale by showing render resolution as percentages, syncing the toolbar to the active renderer budget, and applying the configured scale to `3dgrid`.
|
||||
|
|
|
|||
824
main.js
824
main.js
File diff suppressed because one or more lines are too long
|
|
@ -315,6 +315,7 @@ export class BabylonModelPreview implements WorkbenchPreview {
|
|||
private measurementTargetMeshes: AbstractMesh[] = [];
|
||||
private measurementSnapInputCache: MeasurementGeometrySnapInput | null = null;
|
||||
private measurementSnapInputCacheTargetId: number | null = null;
|
||||
private measurementSnapInputCacheSignature: string | null = null;
|
||||
private measurementSnapKind: MeasurementSnapKind | null = null;
|
||||
private readonly measurementObservers = new Set<() => void>();
|
||||
private pendingPoint: Vector3 | null = null;
|
||||
|
|
@ -1955,6 +1956,7 @@ export class BabylonModelPreview implements WorkbenchPreview {
|
|||
private invalidateMeasurementSnapInputCache(): void {
|
||||
this.measurementSnapInputCache = null;
|
||||
this.measurementSnapInputCacheTargetId = null;
|
||||
this.measurementSnapInputCacheSignature = null;
|
||||
}
|
||||
|
||||
private getMeasurementTargetName(): string | null {
|
||||
|
|
@ -1997,11 +1999,16 @@ export class BabylonModelPreview implements WorkbenchPreview {
|
|||
private createMeasurementGeometrySnapInput(): MeasurementGeometrySnapInput | null {
|
||||
const target = this.measurementTargetNode;
|
||||
if (!this.rootMesh || !target || isBabylonNodeDisposed(target)) return null;
|
||||
if (this.measurementSnapInputCache && this.measurementSnapInputCacheTargetId === target.uniqueId) {
|
||||
return this.measurementSnapInputCache;
|
||||
}
|
||||
const meshes = this.getMeasurementTargetMeshes(target);
|
||||
if (meshes.length === 0) return null;
|
||||
const signature = this.createMeasurementSnapInputSignature(meshes);
|
||||
if (
|
||||
this.measurementSnapInputCache &&
|
||||
this.measurementSnapInputCacheTargetId === target.uniqueId &&
|
||||
this.measurementSnapInputCacheSignature === signature
|
||||
) {
|
||||
return this.measurementSnapInputCache;
|
||||
}
|
||||
|
||||
const vertices: MeasurementSnapVertexCandidate[] = [];
|
||||
const edges: MeasurementSnapEdgeCandidate[] = [];
|
||||
|
|
@ -2036,9 +2043,25 @@ export class BabylonModelPreview implements WorkbenchPreview {
|
|||
};
|
||||
this.measurementSnapInputCache = input;
|
||||
this.measurementSnapInputCacheTargetId = target.uniqueId;
|
||||
this.measurementSnapInputCacheSignature = signature;
|
||||
return input;
|
||||
}
|
||||
|
||||
private createMeasurementSnapInputSignature(meshes: readonly AbstractMesh[]): string {
|
||||
return meshes.map((mesh) => {
|
||||
const geometryId = "geometry" in mesh && mesh.geometry
|
||||
? (mesh.geometry as { uniqueId?: number }).uniqueId ?? "geometry"
|
||||
: "none";
|
||||
return [
|
||||
mesh.uniqueId,
|
||||
geometryId,
|
||||
mesh.getTotalVertices(),
|
||||
mesh.getTotalIndices(),
|
||||
mesh.computeWorldMatrix(true).asArray().map(formatMeasurementSnapSignatureNumber).join(","),
|
||||
].join(":");
|
||||
}).join("|");
|
||||
}
|
||||
|
||||
private getMeasurementTargetMeshes(target = this.measurementTargetNode): AbstractMesh[] {
|
||||
if (!this.rootMesh || !target || isBabylonNodeDisposed(target)) return [];
|
||||
return this.getRenderableMeshes(this.rootMesh)
|
||||
|
|
@ -2333,6 +2356,10 @@ export class BabylonModelPreview implements WorkbenchPreview {
|
|||
}
|
||||
}
|
||||
|
||||
function formatMeasurementSnapSignatureNumber(value: number): string {
|
||||
return Number.isFinite(value) ? value.toPrecision(10) : String(value);
|
||||
}
|
||||
|
||||
export function createBabylonModelPreview(canvas: HTMLCanvasElement): WorkbenchPreview {
|
||||
return new BabylonModelPreview(canvas);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ export class ThreeModelPreview implements WorkbenchPreview {
|
|||
private measurementTargetHelper: BoxHelper | null = null;
|
||||
private measurementSnapInputCache: MeasurementGeometrySnapInput | null = null;
|
||||
private measurementSnapInputCacheTarget: Object3D | null = null;
|
||||
private measurementSnapInputCacheSignature: string | null = null;
|
||||
private measurementSnapKind: MeasurementSnapKind | null = null;
|
||||
private readonly measurementObservers = new Set<() => void>();
|
||||
private pendingPoint: Vector3 | null = null;
|
||||
|
|
@ -2648,6 +2649,7 @@ export class ThreeModelPreview implements WorkbenchPreview {
|
|||
private invalidateMeasurementSnapInputCache(): void {
|
||||
this.measurementSnapInputCache = null;
|
||||
this.measurementSnapInputCacheTarget = null;
|
||||
this.measurementSnapInputCacheSignature = null;
|
||||
}
|
||||
|
||||
private setMeasurementSnapKind(kind: MeasurementSnapKind | null, notify = true): void {
|
||||
|
|
@ -2712,11 +2714,16 @@ export class ThreeModelPreview implements WorkbenchPreview {
|
|||
private createMeasurementGeometrySnapInput(): MeasurementGeometrySnapInput | null {
|
||||
const target = this.measurementTargetObject;
|
||||
if (!target || !this.isObjectInLoadedRoot(target)) return null;
|
||||
if (this.measurementSnapInputCache && this.measurementSnapInputCacheTarget === target) {
|
||||
return this.measurementSnapInputCache;
|
||||
}
|
||||
const renderables = this.getMeasurementTargetRenderables();
|
||||
if (renderables.length === 0) return null;
|
||||
const signature = this.createMeasurementSnapInputSignature(renderables);
|
||||
if (
|
||||
this.measurementSnapInputCache &&
|
||||
this.measurementSnapInputCacheTarget === target &&
|
||||
this.measurementSnapInputCacheSignature === signature
|
||||
) {
|
||||
return this.measurementSnapInputCache;
|
||||
}
|
||||
const vertices: MeasurementSnapVertexCandidate[] = [];
|
||||
const edges: MeasurementSnapEdgeCandidate[] = [];
|
||||
const targetId = `three:${target.id}`;
|
||||
|
|
@ -2749,9 +2756,29 @@ export class ThreeModelPreview implements WorkbenchPreview {
|
|||
};
|
||||
this.measurementSnapInputCache = input;
|
||||
this.measurementSnapInputCacheTarget = target;
|
||||
this.measurementSnapInputCacheSignature = signature;
|
||||
return input;
|
||||
}
|
||||
|
||||
private createMeasurementSnapInputSignature(renderables: readonly ThreeRenderableObject[]): string {
|
||||
return renderables.map((object) => {
|
||||
const geometry = object.geometry;
|
||||
const position = geometry.getAttribute("position");
|
||||
const index = geometry.getIndex();
|
||||
const positionVersion = position && "version" in position ? (position as { version?: number }).version ?? 0 : 0;
|
||||
object.updateWorldMatrix(true, false);
|
||||
return [
|
||||
object.id,
|
||||
geometry.id,
|
||||
position?.count ?? 0,
|
||||
positionVersion,
|
||||
index?.count ?? 0,
|
||||
index?.version ?? 0,
|
||||
object.matrixWorld.elements.map(formatMeasurementSnapSignatureNumber).join(","),
|
||||
].join(":");
|
||||
}).join("|");
|
||||
}
|
||||
|
||||
private getMeasurementTargetRenderables(): ThreeRenderableObject[] {
|
||||
const target = this.measurementTargetObject;
|
||||
if (!this.rootObject || !target || !this.isObjectInLoadedRoot(target)) return [];
|
||||
|
|
@ -3092,6 +3119,10 @@ export class ThreeModelPreview implements WorkbenchPreview {
|
|||
|
||||
}
|
||||
|
||||
function formatMeasurementSnapSignatureNumber(value: number): string {
|
||||
return Number.isFinite(value) ? value.toPrecision(10) : String(value);
|
||||
}
|
||||
|
||||
export function createThreeModelPreview(canvas: HTMLCanvasElement): WorkbenchPreview {
|
||||
return new ThreeModelPreview(canvas);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue