import { useMemo } from 'react'; import { useXRPlanes, XRPlaneModel } from '@react-three/xr'; import { XRSpace } from '@react-three/xr'; import * as THREE from 'three'; interface XRPlaneOverlayProps { showPlanes: boolean; highlightNearest?: THREE.Vector3 | null; } /** * Renders semi-transparent overlays on all detected WebXR planes. * Walls are tinted blue, floors/ceilings green, others grey. */ export function XRPlaneOverlay({ showPlanes, highlightNearest }: XRPlaneOverlayProps) { const allPlanes = useXRPlanes(); if (!showPlanes || allPlanes.length === 0) return null; return ( <> {allPlanes.map((plane, i) => { const label = plane.semanticLabel ?? ''; const isHorizontal = plane.orientation === 'horizontal'; const isVertical = plane.orientation === 'vertical'; // Color by type let color = '#64748b'; // default grey if (label === 'floor' || label === 'table' || (isHorizontal && label !== 'ceiling')) { color = '#22c55e'; // green for floor/table/horizontal } else if (label === 'wall' || isVertical) { color = '#3b82f6'; // blue for walls } else if (label === 'ceiling') { color = '#a855f7'; // purple for ceiling } return ( ); })} ); } /** * Hook to find the nearest detected plane to a given point. * Returns the plane's center position and orientation quaternion. */ export function useNearestPlane( targetPoint: THREE.Vector3 | null, maxDistance = 0.5 ): { position: THREE.Vector3; quaternion: THREE.Quaternion; plane: XRPlane } | null { const allPlanes = useXRPlanes(); return useMemo(() => { if (!targetPoint || allPlanes.length === 0) return null; let nearest: { position: THREE.Vector3; quaternion: THREE.Quaternion; plane: XRPlane } | null = null; let minDist = maxDistance; for (const plane of allPlanes) { // Use the plane's polygon center as approximation const polygon = plane.polygon; if (!polygon || polygon.length === 0) continue; const center = new THREE.Vector3(); for (const pt of polygon) { center.add(new THREE.Vector3(pt.x, pt.y, pt.z)); } center.divideScalar(polygon.length); const dist = center.distanceTo(targetPoint); if (dist < minDist) { minDist = dist; nearest = { position: center.clone(), quaternion: new THREE.Quaternion(), plane, }; } } return nearest; }, [targetPoint, allPlanes, maxDistance]); }