Changes
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
@@ -26,6 +26,15 @@ function isPickableModelMesh(o: THREE.Object3D): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getModelIdFromObject(o: THREE.Object3D): string | undefined {
|
||||
let cur: THREE.Object3D | null = o;
|
||||
while (cur) {
|
||||
if (cur.userData?.modelId) return cur.userData.modelId as string;
|
||||
cur = cur.parent;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Right-controller trigger driven measurement for AR.
|
||||
*
|
||||
@@ -60,6 +69,7 @@ export function XRControllerMeasure() {
|
||||
);
|
||||
const laserMat = useRef(new THREE.LineBasicMaterial({ color: '#22c55e', transparent: true, opacity: 0.7, depthTest: false }));
|
||||
const tipColor = useRef(new THREE.Color('#22c55e'));
|
||||
const lockedSnap = useRef<{ point: THREE.Vector3; kind: 'vertex' | 'edge' | 'hole'; modelId?: string; lastSeen: number } | null>(null);
|
||||
|
||||
// Dwell detection for hover-based smart measurement (1 s)
|
||||
const dwellPos = useRef(new THREE.Vector3(Infinity, Infinity, Infinity));
|
||||
@@ -118,11 +128,13 @@ export function XRControllerMeasure() {
|
||||
|
||||
let snappedPoint: THREE.Vector3 | null = null;
|
||||
let snapKind: 'vertex' | 'edge' | 'surface' | 'hole' = 'surface';
|
||||
let hoverDetected: { kind: 'hole' | 'edge'; value: number; position: THREE.Vector3; endpoints?: { a: THREE.Vector3; b: THREE.Vector3 } } | null = null;
|
||||
let hoverDetected: { kind: 'hole' | 'edge'; value: number; position: THREE.Vector3; modelId?: string; endpoints?: { a: THREE.Vector3; b: THREE.Vector3 } } | null = null;
|
||||
let hitModelId: string | undefined;
|
||||
|
||||
const hits = raycaster.current.intersectObjects(scene.children, true);
|
||||
const hit = hits.find((h) => {
|
||||
const o = h.object;
|
||||
if (!(o instanceof THREE.Mesh)) return false;
|
||||
if (!isPickableModelMesh(o)) return false;
|
||||
if (o.userData.__edgeLine) return false;
|
||||
if (o.geometry instanceof THREE.SphereGeometry) return false;
|
||||
@@ -132,9 +144,10 @@ export function XRControllerMeasure() {
|
||||
});
|
||||
|
||||
if (hit && hit.object instanceof THREE.Mesh) {
|
||||
hitModelId = getModelIdFromObject(hit.object);
|
||||
const dist = tmpOrigin.current.distanceTo(hit.point);
|
||||
const vertexThreshold = Math.max(0.06, dist * 0.08);
|
||||
const edgeThreshold = Math.max(0.08, dist * 0.10);
|
||||
const vertexThreshold = Math.max(0.08, dist * 0.12);
|
||||
const edgeThreshold = Math.max(0.10, dist * 0.14);
|
||||
|
||||
// Snap to existing registered hole centers first
|
||||
const existing = useModelStore.getState().measurements;
|
||||
@@ -158,7 +171,7 @@ export function XRControllerMeasure() {
|
||||
if (circle) {
|
||||
snappedPoint = circle.center;
|
||||
snapKind = 'hole';
|
||||
hoverDetected = { kind: 'hole', value: circle.diameterMM, position: circle.center };
|
||||
hoverDetected = { kind: 'hole', value: circle.diameterMM, position: circle.center, modelId: hitModelId };
|
||||
} else {
|
||||
const snap = resolveSnap3D(hit.object, hit.point, vertexThreshold, edgeThreshold);
|
||||
snappedPoint = snap.point;
|
||||
@@ -167,7 +180,7 @@ export function XRControllerMeasure() {
|
||||
const seg = findNearestEdgeSegment3D(hit.object, hit.point, edgeThreshold);
|
||||
if (seg) {
|
||||
const lenMM = seg.a.distanceTo(seg.b) * 1000;
|
||||
hoverDetected = { kind: 'edge', value: lenMM, position: seg.midpoint, endpoints: { a: seg.a, b: seg.b } };
|
||||
hoverDetected = { kind: 'edge', value: lenMM, position: seg.midpoint, modelId: hitModelId, endpoints: { a: seg.a, b: seg.b } };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,6 +190,25 @@ export function XRControllerMeasure() {
|
||||
}
|
||||
}
|
||||
|
||||
const strongSnap = snapKind === 'vertex' || snapKind === 'edge' || snapKind === 'hole';
|
||||
if (snappedPoint && strongSnap) {
|
||||
const locked = lockedSnap.current;
|
||||
const sameTarget = locked && locked.kind === snapKind && locked.modelId === hitModelId;
|
||||
if (sameTarget && locked.point.distanceTo(snappedPoint) < (snapKind === 'edge' ? 0.08 : 0.12)) {
|
||||
if (snapKind === 'edge') locked.point.lerp(snappedPoint, 0.25);
|
||||
snappedPoint = locked.point.clone();
|
||||
locked.lastSeen = nowT;
|
||||
} else {
|
||||
lockedSnap.current = { point: snappedPoint.clone(), kind: snapKind, modelId: hitModelId, lastSeen: nowT };
|
||||
}
|
||||
} else if (snappedPoint && lockedSnap.current && lockedSnap.current.point.distanceTo(snappedPoint) < 0.12 && nowT - lockedSnap.current.lastSeen < 600) {
|
||||
snapKind = lockedSnap.current.kind;
|
||||
snappedPoint = lockedSnap.current.point.clone();
|
||||
lockedSnap.current.lastSeen = nowT;
|
||||
} else if (!snappedPoint || (lockedSnap.current && nowT - lockedSnap.current.lastSeen > 600)) {
|
||||
lockedSnap.current = null;
|
||||
}
|
||||
|
||||
// ── Dwell detection (1 s) to auto-register hovered hole/edge ─────
|
||||
const measureModeNow = useModelStore.getState().measureMode;
|
||||
const nowT = performance.now();
|
||||
@@ -197,6 +229,7 @@ export function XRControllerMeasure() {
|
||||
a: { x: hoverDetected.endpoints.a.x, y: hoverDetected.endpoints.a.y, z: hoverDetected.endpoints.a.z },
|
||||
b: { x: hoverDetected.endpoints.b.x, y: hoverDetected.endpoints.b.y, z: hoverDetected.endpoints.b.z },
|
||||
},
|
||||
modelId: hoverDetected.modelId,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -246,6 +279,7 @@ export function XRControllerMeasure() {
|
||||
const triggerHits = raycaster.current.intersectObjects(scene.children, true);
|
||||
const triggerHit = triggerHits.find((h) => {
|
||||
const o = h.object;
|
||||
if (!(o instanceof THREE.Mesh)) return false;
|
||||
if (!isPickableModelMesh(o)) return false;
|
||||
if (o.userData.__edgeLine) return false;
|
||||
if (o.geometry instanceof THREE.SphereGeometry) return false;
|
||||
@@ -273,6 +307,7 @@ export function XRControllerMeasure() {
|
||||
sendRemoteLog('info', 'Trigger físico pressionado no AR com snapPoint ativo', snappedPoint);
|
||||
st.addMeasurePoint({
|
||||
x: snappedPoint.x, y: snappedPoint.y, z: snappedPoint.z,
|
||||
modelId: hitModelId,
|
||||
});
|
||||
}
|
||||
} else if (trigState.current && trigVal < TRIG_OFF) {
|
||||
|
||||
Reference in New Issue
Block a user