Files
SteelXR/.lovable/plan.md
T
gpt-engineer-app[bot] cffa66c6df Changes
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
2026-05-20 18:48:16 +00:00

3.5 KiB

Modo Posicionar (desktop)

Permite que, antes de entrar no AR, o usuário mova e gire a peça ativa com o mouse — exatamente como faria com o controle no AR. As outras peças permanecem travadas. Ao desativar o botão, todas ficam fixas nas posições atuais e o estado persiste (já temos savePlacement por fileName).

Comportamento

  • Botão Posicionar (ícone Move3D) na barra ViewerControls, ao lado de Medir.
  • Quando ativo:
    • OrbitControls é desabilitado (não conflitar com o arrasto da peça).
    • Cursor vira move.
    • Apenas a peça com activeModelId responde ao mouse. Clicar em outra peça troca a ativa e passa a manipulá-la (as outras voltam a ficar travadas).
    • Arrastar com botão esquerdo → translada no plano da câmera (X/Y da tela projetados para o mundo).
    • Shift + arrastar esquerdo ou arrastar com botão do meio → translada no eixo Z (profundidade) usando o movimento vertical do mouse.
    • Arrastar com botão direito → rotaciona: movimento horizontal = rotY (yaw), movimento vertical = rotX (pitch). Shift + direito = rotZ (roll).
    • Cada movimento atualiza fineTuning via setFineTuning da peça ativa, o que já dispara savePlacement (persistência entre sessões/entrar-sair do AR — mesma chave usada hoje).
  • Quando desativado: tudo volta ao normal (Orbit ativo, peças travadas onde foram deixadas). Modo Medir e Posicionar são mutuamente exclusivos.

Arquivos a alterar

  1. src/stores/useModelStore.ts

    • Adicionar positionMode: boolean + setPositionMode(on).
    • Em setPositionMode(true) desligar measureMode; e vice-versa em setMeasureMode.
  2. src/components/three/ModelViewer.tsx

    • Novo componente PositionDragHandler (dentro do Canvas) que:
      • Escuta pointerdown/move/up no gl.domElement quando positionMode está on e existe activeModelId.
      • Converte delta de pixels em delta de mundo usando a distância câmera↔peça e o FOV (2 * dist * tan(fov/2) / canvasHeight), depois divide pelo scaleRatio.factor para gravar em coordenadas locais coerentes com fineTuning.
      • Aplica via setFineTuning({ posX: ..., posY: ..., posZ: ..., rotX: ..., rotY: ..., rotZ: ... }).
    • Em OrbitControls, definir enabled={!positionMode && !measureMode} (medir já não rotaciona hoje só por cursor, mas reforça).
    • Cursor: quando positionMode, setar gl.domElement.style.cursor = 'move'.
  3. src/components/ViewerControls.tsx

    • Importar ícone Move3D do lucide.
    • Novo botão Posicionar com variant={positionMode ? 'default' : 'outline'} chamando setPositionMode(!positionMode). Label dinâmica: Posicionar / Posicionando — [nome da peça ativa].

Detalhes técnicos

  • A translação é gravada em fineTuning.pos{X,Y,Z} (espaço local da peça, antes do renderFactor da escala). Para que 1 pixel ↔ 1 mm visual fique coerente, o cálculo divide o delta-mundo por scaleRatio.factor (ex: em 1:50, mover 100 px arrasta o objeto 100 px de tela tanto na visualização quanto na coordenada interna).
  • Rotação em graus (já é o formato de fineTuning.rotX/Y/Z), sensibilidade ~0.4°/px.
  • O bloqueio de outras peças é automático: o handler só atualiza a activeModelId. Clicar em outra peça (handler onClick já existente em GLBModel) muda a ativa.
  • Persistência: setFineTuning já chama savePlacement(fileName, fineTuning), então sair/voltar do AR mantém posições.
  • Sem mudanças no AR; apenas no viewer desktop.