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;
|
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.
|
* 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 laserMat = useRef(new THREE.LineBasicMaterial({ color: '#22c55e', transparent: true, opacity: 0.7, depthTest: false }));
|
||||||
const tipColor = useRef(new THREE.Color('#22c55e'));
|
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)
|
// Dwell detection for hover-based smart measurement (1 s)
|
||||||
const dwellPos = useRef(new THREE.Vector3(Infinity, Infinity, Infinity));
|
const dwellPos = useRef(new THREE.Vector3(Infinity, Infinity, Infinity));
|
||||||
@@ -118,11 +128,13 @@ export function XRControllerMeasure() {
|
|||||||
|
|
||||||
let snappedPoint: THREE.Vector3 | null = null;
|
let snappedPoint: THREE.Vector3 | null = null;
|
||||||
let snapKind: 'vertex' | 'edge' | 'surface' | 'hole' = 'surface';
|
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 hits = raycaster.current.intersectObjects(scene.children, true);
|
||||||
const hit = hits.find((h) => {
|
const hit = hits.find((h) => {
|
||||||
const o = h.object;
|
const o = h.object;
|
||||||
|
if (!(o instanceof THREE.Mesh)) return false;
|
||||||
if (!isPickableModelMesh(o)) return false;
|
if (!isPickableModelMesh(o)) return false;
|
||||||
if (o.userData.__edgeLine) return false;
|
if (o.userData.__edgeLine) return false;
|
||||||
if (o.geometry instanceof THREE.SphereGeometry) return false;
|
if (o.geometry instanceof THREE.SphereGeometry) return false;
|
||||||
@@ -132,9 +144,10 @@ export function XRControllerMeasure() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (hit && hit.object instanceof THREE.Mesh) {
|
if (hit && hit.object instanceof THREE.Mesh) {
|
||||||
|
hitModelId = getModelIdFromObject(hit.object);
|
||||||
const dist = tmpOrigin.current.distanceTo(hit.point);
|
const dist = tmpOrigin.current.distanceTo(hit.point);
|
||||||
const vertexThreshold = Math.max(0.06, dist * 0.08);
|
const vertexThreshold = Math.max(0.08, dist * 0.12);
|
||||||
const edgeThreshold = Math.max(0.08, dist * 0.10);
|
const edgeThreshold = Math.max(0.10, dist * 0.14);
|
||||||
|
|
||||||
// Snap to existing registered hole centers first
|
// Snap to existing registered hole centers first
|
||||||
const existing = useModelStore.getState().measurements;
|
const existing = useModelStore.getState().measurements;
|
||||||
@@ -158,7 +171,7 @@ export function XRControllerMeasure() {
|
|||||||
if (circle) {
|
if (circle) {
|
||||||
snappedPoint = circle.center;
|
snappedPoint = circle.center;
|
||||||
snapKind = 'hole';
|
snapKind = 'hole';
|
||||||
hoverDetected = { kind: 'hole', value: circle.diameterMM, position: circle.center };
|
hoverDetected = { kind: 'hole', value: circle.diameterMM, position: circle.center, modelId: hitModelId };
|
||||||
} else {
|
} else {
|
||||||
const snap = resolveSnap3D(hit.object, hit.point, vertexThreshold, edgeThreshold);
|
const snap = resolveSnap3D(hit.object, hit.point, vertexThreshold, edgeThreshold);
|
||||||
snappedPoint = snap.point;
|
snappedPoint = snap.point;
|
||||||
@@ -167,7 +180,7 @@ export function XRControllerMeasure() {
|
|||||||
const seg = findNearestEdgeSegment3D(hit.object, hit.point, edgeThreshold);
|
const seg = findNearestEdgeSegment3D(hit.object, hit.point, edgeThreshold);
|
||||||
if (seg) {
|
if (seg) {
|
||||||
const lenMM = seg.a.distanceTo(seg.b) * 1000;
|
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 ─────
|
// ── Dwell detection (1 s) to auto-register hovered hole/edge ─────
|
||||||
const measureModeNow = useModelStore.getState().measureMode;
|
const measureModeNow = useModelStore.getState().measureMode;
|
||||||
const nowT = performance.now();
|
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 },
|
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 },
|
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 triggerHits = raycaster.current.intersectObjects(scene.children, true);
|
||||||
const triggerHit = triggerHits.find((h) => {
|
const triggerHit = triggerHits.find((h) => {
|
||||||
const o = h.object;
|
const o = h.object;
|
||||||
|
if (!(o instanceof THREE.Mesh)) return false;
|
||||||
if (!isPickableModelMesh(o)) return false;
|
if (!isPickableModelMesh(o)) return false;
|
||||||
if (o.userData.__edgeLine) return false;
|
if (o.userData.__edgeLine) return false;
|
||||||
if (o.geometry instanceof THREE.SphereGeometry) 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);
|
sendRemoteLog('info', 'Trigger físico pressionado no AR com snapPoint ativo', snappedPoint);
|
||||||
st.addMeasurePoint({
|
st.addMeasurePoint({
|
||||||
x: snappedPoint.x, y: snappedPoint.y, z: snappedPoint.z,
|
x: snappedPoint.x, y: snappedPoint.y, z: snappedPoint.z,
|
||||||
|
modelId: hitModelId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (trigState.current && trigVal < TRIG_OFF) {
|
} else if (trigState.current && trigVal < TRIG_OFF) {
|
||||||
|
|||||||
Reference in New Issue
Block a user