diff --git a/src/components/FineTuningControls.tsx b/src/components/FineTuningControls.tsx new file mode 100644 index 0000000..bfaa134 --- /dev/null +++ b/src/components/FineTuningControls.tsx @@ -0,0 +1,116 @@ +import { Move, RotateCw, RefreshCw } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { useModelStore } from '@/stores/useModelStore'; + +const POSITION_STEP = 0.001; // 1mm +const ROTATION_STEP = 0.1; // 0.1° + +function StepButton({ label, onClick }: { label: string; onClick: () => void }) { + return ( + + ); +} + +function AxisControl({ + axis, + value, + unit, + onIncrement, + onDecrement, + displayValue, +}: { + axis: string; + value: number; + unit: string; + onIncrement: () => void; + onDecrement: () => void; + displayValue: string; +}) { + return ( +
+ {axis} + + {displayValue}{unit} + +
+ ); +} + +export function FineTuningControls() { + const { fineTuning, setFineTuning, resetFineTuning } = useModelStore(); + + return ( +
+
+

+ Ajuste Fino +

+ +
+ + {/* Position */} +
+
+ + Posição (±1mm) +
+ setFineTuning({ posX: fineTuning.posX + POSITION_STEP })} + onDecrement={() => setFineTuning({ posX: fineTuning.posX - POSITION_STEP })} + /> + setFineTuning({ posY: fineTuning.posY + POSITION_STEP })} + onDecrement={() => setFineTuning({ posY: fineTuning.posY - POSITION_STEP })} + /> + setFineTuning({ posZ: fineTuning.posZ + POSITION_STEP })} + onDecrement={() => setFineTuning({ posZ: fineTuning.posZ - POSITION_STEP })} + /> +
+ + {/* Rotation */} +
+
+ + Rotação Y (±0.1°) +
+ setFineTuning({ rotY: fineTuning.rotY + ROTATION_STEP })} + onDecrement={() => setFineTuning({ rotY: fineTuning.rotY - ROTATION_STEP })} + /> +
+ +
+

+ No Quest 3: Grip + Joystick esq. = X/Y, Joystick dir. = Z/Rotação +

+
+
+ ); +} diff --git a/src/components/three/ModelViewer.tsx b/src/components/three/ModelViewer.tsx index ea013f4..b9e73ab 100644 --- a/src/components/three/ModelViewer.tsx +++ b/src/components/three/ModelViewer.tsx @@ -26,6 +26,7 @@ function GLBModel({ url }: { url: string }) { const opacity = useModelStore((s) => s.opacity); const renderMode = useModelStore((s) => s.renderMode); const checklist = useModelStore((s) => s.checklist); + const fineTuning = useModelStore((s) => s.fineTuning); const modelInfo = useMemo(() => { const box = new THREE.Box3().setFromObject(scene); @@ -71,8 +72,18 @@ function GLBModel({ url }: { url: string }) { }); }, [scene, opacity, renderMode, checklist]); + const rotYRad = (fineTuning.rotY * Math.PI) / 180; + return ( - + ); diff --git a/src/pages/Viewer.tsx b/src/pages/Viewer.tsx index 0cbd362..0ecd83c 100644 --- a/src/pages/Viewer.tsx +++ b/src/pages/Viewer.tsx @@ -5,6 +5,7 @@ import { useModelStore } from '@/stores/useModelStore'; import { ModelViewerCanvas } from '@/components/three/ModelViewer'; import { ViewerControls } from '@/components/ViewerControls'; import { InspectionChecklist } from '@/components/InspectionChecklist'; +import { FineTuningControls } from '@/components/FineTuningControls'; import { useEffect } from 'react'; import { toast } from 'sonner'; import { ScrollArea } from '@/components/ui/scroll-area'; @@ -84,6 +85,10 @@ const Viewer = () => { + + + +