diff --git a/src/components/three/SmartMeasure.ts b/src/components/three/SmartMeasure.ts index 7d74090..fda52d5 100644 --- a/src/components/three/SmartMeasure.ts +++ b/src/components/three/SmartMeasure.ts @@ -252,8 +252,16 @@ export function findNearestEdgeSegment( } }); - // If no edge lines, generate from EdgesGeometry - const geo = edgeLines?.geometry ?? new THREE.EdgesGeometry(mesh.geometry, 15); + // If no edge lines, fetch from cache or generate and store in cache + let geo: THREE.BufferGeometry; + if (edgeLines) { + geo = edgeLines.geometry; + } else { + if (!mesh.userData.__cachedEdgesGeometry) { + mesh.userData.__cachedEdgesGeometry = new THREE.EdgesGeometry(mesh.geometry, 15); + } + geo = mesh.userData.__cachedEdgesGeometry; + } const posAttr = geo.attributes.position; if (!posAttr) return null; @@ -298,8 +306,6 @@ export function findNearestEdgeSegment( } } - if (!edgeLines) geo.dispose(); - if (bestDist <= thresholdPx && bestMid && bestA && bestB && bestLen > 0.5) { return { midpoint: bestMid, lengthMM: bestLen, a: bestA, b: bestB }; } @@ -321,7 +327,16 @@ export function detectCircularEdgeAtPoint( mesh.children.forEach(c => { if (c.userData.__edgeLine && c instanceof THREE.LineSegments) edgeLines = c; }); - const geo = edgeLines?.geometry ?? new THREE.EdgesGeometry(mesh.geometry, 15); + + let geo: THREE.BufferGeometry; + if (edgeLines) { + geo = edgeLines.geometry; + } else { + if (!mesh.userData.__cachedEdgesGeometry) { + mesh.userData.__cachedEdgesGeometry = new THREE.EdgesGeometry(mesh.geometry, 15); + } + geo = mesh.userData.__cachedEdgesGeometry; + } const posAttr = geo.attributes.position; if (!posAttr) return null; @@ -347,7 +362,6 @@ export function detectCircularEdgeAtPoint( seen.add(key); verts.push(tmp.clone()); } - if (!edgeLines) geo.dispose(); if (verts.length < 6) return null; @@ -497,7 +511,15 @@ export function findNearestEdgeSegment3D( } }); - const geo = edgeLines?.geometry ?? new THREE.EdgesGeometry(mesh.geometry, 15); + let geo: THREE.BufferGeometry; + if (edgeLines) { + geo = edgeLines.geometry; + } else { + if (!mesh.userData.__cachedEdgesGeometry) { + mesh.userData.__cachedEdgesGeometry = new THREE.EdgesGeometry(mesh.geometry, 15); + } + geo = mesh.userData.__cachedEdgesGeometry; + } const posAttr = geo.attributes.position; if (!posAttr) return null; @@ -525,8 +547,6 @@ export function findNearestEdgeSegment3D( } } - if (!edgeLines) geo.dispose(); - if (bestIndex !== -1 && bestDistSq <= thresholdSq) { const a = new THREE.Vector3().fromBufferAttribute(posAttr, bestIndex * 2).applyMatrix4(matrix); const b = new THREE.Vector3().fromBufferAttribute(posAttr, bestIndex * 2 + 1).applyMatrix4(matrix); @@ -546,7 +566,16 @@ export function detectCircularEdgeAtPoint3D( mesh.children.forEach(c => { if (c.userData.__edgeLine && c instanceof THREE.LineSegments) edgeLines = c; }); - const geo = edgeLines?.geometry ?? new THREE.EdgesGeometry(mesh.geometry, 15); + + let geo: THREE.BufferGeometry; + if (edgeLines) { + geo = edgeLines.geometry; + } else { + if (!mesh.userData.__cachedEdgesGeometry) { + mesh.userData.__cachedEdgesGeometry = new THREE.EdgesGeometry(mesh.geometry, 15); + } + geo = mesh.userData.__cachedEdgesGeometry; + } const posAttr = geo.attributes.position; if (!posAttr) return null; @@ -573,7 +602,6 @@ export function detectCircularEdgeAtPoint3D( seen.add(key); verts.push(tmp.clone().applyMatrix4(matrix)); } - if (!edgeLines) geo.dispose(); if (verts.length < 6) return null; @@ -618,8 +646,8 @@ export function detectCircularEdgeAtPoint3D( export function resolveSnap3D( mesh: THREE.Mesh, hitPoint: THREE.Vector3, - vertexThresholdMeters: number = 0.035, - edgeThresholdMeters: number = 0.05 + vertexThresholdMeters: number = 0.07, + edgeThresholdMeters: number = 0.09 ): { point: THREE.Vector3; type: 'vertex' | 'edge' | 'surface' } { const v = findNearestVertex3D(mesh, hitPoint, vertexThresholdMeters); if (v) return { point: v, type: 'vertex' }; diff --git a/src/components/three/XRControllerMeasure.tsx b/src/components/three/XRControllerMeasure.tsx index 8aada1e..fdb4801 100644 --- a/src/components/three/XRControllerMeasure.tsx +++ b/src/components/three/XRControllerMeasure.tsx @@ -162,12 +162,12 @@ export function XRControllerMeasure() { snapKind = 'hole'; hoverDetected = { kind: 'hole', value: circle.diameterMM, position: circle.center }; } else { - // Snap 3D físico puro (3.5cm para vértices, 5cm para arestas) - const snap = resolveSnap3D(hit.object, hit.point, 0.035, 0.05); + // Snap 3D físico puro (7cm para vértices, 9cm para arestas) + const snap = resolveSnap3D(hit.object, hit.point, 0.07, 0.09); snappedPoint = snap.point; snapKind = snap.type; if (snap.type === 'edge') { - const seg = findNearestEdgeSegment3D(hit.object, hit.point, 0.05); + const seg = findNearestEdgeSegment3D(hit.object, hit.point, 0.09); 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 } }; @@ -259,7 +259,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; if (o.geometry instanceof THREE.RingGeometry) return false;