🚀 Auto-deploy: melhoria no snap e medição AR em 22/05/2026 14:53:05

This commit is contained in:
2026-05-22 14:53:05 +00:00
parent bd9d0028f1
commit 69b001f316
5 changed files with 925 additions and 27 deletions
+20 -24
View File
@@ -2,7 +2,14 @@ import { useRef, useState } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { useModelStore } from '@/stores/useModelStore';
import { resolveSnap, detectCircularEdgeAtPoint, findNearestEdgeSegment } from './SmartMeasure';
import {
resolveSnap,
detectCircularEdgeAtPoint,
findNearestEdgeSegment,
resolveSnap3D,
detectCircularEdgeAtPoint3D,
findNearestEdgeSegment3D
} from './SmartMeasure';
const TRIG_ON = 0.7;
const TRIG_OFF = 0.3;
@@ -121,48 +128,37 @@ export function XRControllerMeasure() {
});
if (hit && hit.object instanceof THREE.Mesh) {
const size = gl.getSize(new THREE.Vector2());
const canvasSize = { width: size.x || 1024, height: size.y || 1024 };
const fakeCam = new THREE.PerspectiveCamera(60, 1, 0.01, 100);
fakeCam.position.copy(tmpOrigin.current);
fakeCam.quaternion.copy(tmpQuat.current);
fakeCam.updateMatrixWorld(true);
// Snap to existing registered hole centers first (within ~30px screen)
// Snap to existing registered hole centers first (within ~4cm)
const existing = useModelStore.getState().measurements;
let bestHoleCenter: THREE.Vector3 | null = null;
let bestHolePx = Infinity;
const hitProj = hit.point.clone().project(fakeCam);
const hx = (hitProj.x * 0.5 + 0.5) * canvasSize.width;
const hy = (-hitProj.y * 0.5 + 0.5) * canvasSize.height;
let bestHoleDist = Infinity;
for (const m of existing) {
if (m.kind !== 'hole') continue;
const c = new THREE.Vector3(m.pointA.x, m.pointA.y, m.pointA.z);
const p = c.clone().project(fakeCam);
const sx = (p.x * 0.5 + 0.5) * canvasSize.width;
const sy = (-p.y * 0.5 + 0.5) * canvasSize.height;
const d = Math.hypot(sx - hx, sy - hy);
if (d < 30 && d < bestHolePx) { bestHolePx = d; bestHoleCenter = c; }
const d = hit.point.distanceTo(c);
if (d < 0.04 && d < bestHoleDist) {
bestHoleDist = d;
bestHoleCenter = c;
}
}
if (snapEnabled && bestHoleCenter) {
snappedPoint = bestHoleCenter;
snapKind = 'hole';
} else if (snapEnabled) {
// Try detecting a circular edge (hole) at hit radius mais generoso
const circle = detectCircularEdgeAtPoint(hit.object, hit.point, fakeCam, canvasSize, 90);
// Try detecting a circular edge (hole) at hit (8cm radius)
const circle = detectCircularEdgeAtPoint3D(hit.object, hit.point, 0.08);
if (circle) {
snappedPoint = circle.center;
snapKind = 'hole';
hoverDetected = { kind: 'hole', value: circle.diameterMM, position: circle.center };
} else {
// Snap mais "magnético": raios maiores de busca em pixels
// vértice: 32px (antes 14), aresta: 48px (antes 18)
const snap = resolveSnap(hit.object, hit.point, fakeCam, canvasSize, 32, 48);
// Snap 3D físico puro (3.5cm para vértices, 5cm para arestas)
const snap = resolveSnap3D(hit.object, hit.point, 0.035, 0.05);
snappedPoint = snap.point;
snapKind = snap.type;
if (snap.type === 'edge') {
const seg = findNearestEdgeSegment(hit.object, hit.point, fakeCam, canvasSize, 48);
const seg = findNearestEdgeSegment3D(hit.object, hit.point, 0.05);
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 } };