mirror of
https://github.com/flash555588/ai-model-workbench.git
synced 2026-07-22 06:56:38 +00:00
Cap measurement corner snap radius
This commit is contained in:
parent
daadb83c23
commit
30c8037574
6 changed files with 625 additions and 586 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.
|
||||
- UI: keep the measurement strip in Free pick status while Alt/Option previewing the backup free ruler path, even when the pointer is over empty canvas space.
|
||||
- UI: cap selected-object corner snapping by target edge scale so large grouped selections do not over-prioritize distant vertices when the pointer is closer to an edge.
|
||||
- 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.
|
||||
|
|
|
|||
1168
main.js
1168
main.js
File diff suppressed because one or more lines are too long
|
|
@ -108,6 +108,7 @@ import {
|
|||
createMeasurementReading as buildMeasurementReading,
|
||||
createMeasurementState,
|
||||
createMeasurementTrianglesFromIndices,
|
||||
createMeasurementVertexSnapRadius,
|
||||
drawMeasurementLabelCanvas,
|
||||
MEASUREMENT_LABEL_CANVAS,
|
||||
normalizeMeasurementUnit,
|
||||
|
|
@ -2039,7 +2040,7 @@ export class BabylonModelPreview implements WorkbenchPreview {
|
|||
vertices,
|
||||
edges,
|
||||
targetId,
|
||||
vertexRadius: Math.max(size.x, size.y, size.z, 0.001) * 0.045,
|
||||
vertexRadius: createMeasurementVertexSnapRadius(size, edges),
|
||||
};
|
||||
this.measurementSnapInputCache = input;
|
||||
this.measurementSnapInputCacheTargetId = target.uniqueId;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
createMeasurementReading,
|
||||
createMeasurementState,
|
||||
createMeasurementTrianglesFromIndices,
|
||||
createMeasurementVertexSnapRadius,
|
||||
createReferenceMeasurementScale,
|
||||
drawMeasurementLabelCanvas,
|
||||
formatMeasurementNumber,
|
||||
|
|
@ -176,6 +177,18 @@ describe("measurement helpers", () => {
|
|||
expect(snapped).toBeNull();
|
||||
});
|
||||
|
||||
it("caps the vertex snap radius by selected-target edge scale", () => {
|
||||
expect(createMeasurementVertexSnapRadius(
|
||||
{ x: 10, y: 1, z: 1 },
|
||||
[{ start: { x: 0, y: 0, z: 0 }, end: { x: 1, y: 0, z: 0 } }],
|
||||
)).toBeCloseTo(0.1);
|
||||
expect(createMeasurementVertexSnapRadius(
|
||||
{ x: 1, y: 1, z: 1 },
|
||||
[{ start: { x: 0, y: 0, z: 0 }, end: { x: 1, y: 0, z: 0 } }],
|
||||
)).toBeCloseTo(0.045);
|
||||
expect(createMeasurementVertexSnapRadius({ x: 10, y: 1, z: 1 }, [])).toBeCloseTo(0.45);
|
||||
});
|
||||
|
||||
it("creates geometry snap edges from indexed and non-indexed triangles without face diagonals", () => {
|
||||
const squareVertices = [
|
||||
{ x: 0, y: 0, z: 0 },
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ const UNIT_FACTORS_TO_METERS: Record<MeasurementUnit, number> = {
|
|||
const MIN_MEASUREMENT_SIZE = 1e-9;
|
||||
const MEASUREMENT_EDGE_KEY_SCALE = 1_000_000;
|
||||
const MEASUREMENT_COPLANAR_EDGE_DOT = 0.9995;
|
||||
const MEASUREMENT_VERTEX_RADIUS_SPAN_FACTOR = 0.045;
|
||||
const MEASUREMENT_VERTEX_RADIUS_EDGE_FACTOR = 0.1;
|
||||
|
||||
export interface MeasurementSnapVertexCandidate {
|
||||
point: PreviewWorldPoint;
|
||||
|
|
@ -211,6 +213,27 @@ export function snapMeasurementPointToGeometry(
|
|||
};
|
||||
}
|
||||
|
||||
export function createMeasurementVertexSnapRadius(
|
||||
boundsSize: PreviewWorldPoint,
|
||||
edges: readonly MeasurementSnapEdgeCandidate[],
|
||||
): number {
|
||||
const span = Math.max(boundsSize.x, boundsSize.y, boundsSize.z, 0.001);
|
||||
const spanRadius = span * MEASUREMENT_VERTEX_RADIUS_SPAN_FACTOR;
|
||||
const edgeLengths = edges
|
||||
.map((edge) => distanceMeasurementPoints(edge.start, edge.end))
|
||||
.filter((length) => Number.isFinite(length) && length > MIN_MEASUREMENT_SIZE)
|
||||
.sort((left, right) => left - right);
|
||||
if (edgeLengths.length === 0) {
|
||||
return spanRadius;
|
||||
}
|
||||
|
||||
const referenceEdgeLength = edgeLengths[Math.floor(edgeLengths.length / 2)];
|
||||
return Math.max(
|
||||
Math.min(spanRadius, referenceEdgeLength * MEASUREMENT_VERTEX_RADIUS_EDGE_FACTOR),
|
||||
MIN_MEASUREMENT_SIZE,
|
||||
);
|
||||
}
|
||||
|
||||
export function createMeasurementGeometryEdgesFromTriangles(
|
||||
vertices: readonly PreviewWorldPoint[],
|
||||
triangles: readonly [number, number, number][],
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ import {
|
|||
createMeasurementReading as buildMeasurementReading,
|
||||
createMeasurementState,
|
||||
createMeasurementTrianglesFromIndices,
|
||||
createMeasurementVertexSnapRadius,
|
||||
drawMeasurementLabelCanvas,
|
||||
MEASUREMENT_LABEL_CANVAS,
|
||||
normalizeMeasurementUnit,
|
||||
|
|
@ -2752,7 +2753,7 @@ export class ThreeModelPreview implements WorkbenchPreview {
|
|||
vertices,
|
||||
edges,
|
||||
targetId,
|
||||
vertexRadius: Math.max(size.x, size.y, size.z, 0.001) * 0.045,
|
||||
vertexRadius: createMeasurementVertexSnapRadius(size, edges),
|
||||
};
|
||||
this.measurementSnapInputCache = input;
|
||||
this.measurementSnapInputCacheTarget = target;
|
||||
|
|
|
|||
Loading…
Reference in a new issue