Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-05-24 20:51:01 +00:00
parent d02afa1797
commit c3d0f6c01d
+37
View File
@@ -1078,6 +1078,43 @@ function GridAutoFollower() {
return null; return null;
} }
/** When gridCalibMode is on, the next click on the model sets the grid Y to
* the world Y of the clicked surface point and disables auto-follow. */
function GridCalibrationHandler() {
const { camera, scene, gl } = useThree();
const gridCalibMode = useModelStore((s) => s.gridCalibMode);
const raycaster = useMemo(() => new THREE.Raycaster(), []);
const mouse = useMemo(() => new THREE.Vector2(), []);
useEffect(() => {
if (!gridCalibMode) return;
const canvas = gl.domElement;
const prevCursor = canvas.style.cursor;
canvas.style.cursor = 'crosshair';
const onPointerUp = (ev: PointerEvent) => {
if (ev.button !== 0) return;
const rect = canvas.getBoundingClientRect();
mouse.x = ((ev.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((ev.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const hits = raycaster.intersectObjects(scene.children, true);
const hit = hits.find((h) => isPickableModelMesh(h.object));
if (!hit) return;
useModelStore.setState({
gridY: hit.point.y - 0.001,
gridAutoFollow: false,
gridCalibMode: false,
showGrid: true,
});
};
canvas.addEventListener('pointerup', onPointerUp);
return () => {
canvas.removeEventListener('pointerup', onPointerUp);
canvas.style.cursor = prevCursor;
};
}, [gridCalibMode, camera, scene, gl, raycaster, mouse]);
return null;
}
/** Mouse drag handler for desktop "Posicionar" mode: translates/rotates the active model. */ /** Mouse drag handler for desktop "Posicionar" mode: translates/rotates the active model. */
function PositionDragHandler() { function PositionDragHandler() {
const { camera, gl, scene } = useThree(); const { camera, gl, scene } = useThree();