Changes
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
+37
-32
@@ -1,42 +1,47 @@
|
|||||||
|
|
||||||
## Objetivo
|
## Objetivo
|
||||||
|
|
||||||
Adicionar alternância entre câmera **Perspectiva** e **Ortográfica** no viewer principal, com **Ortográfica como padrão**, e tornar a calibração mais confiável usando a vista ortogonal (sem distorção de perspectiva, normais alinhadas com os eixos da tela).
|
Adicionar uma ferramenta de **corte de seção** (clipping planes) nos eixos X, Y e Z — padrão em viewers IFC/BIM. O usuário move sliders por eixo e a peça vai sendo cortada/revelada em tempo real. Implementada como **janela pop-up flutuante** sobre o viewer, com controle de opacidade da própria janela. Sem presets persistidos.
|
||||||
|
|
||||||
## Por que isso resolve a calibração
|
## UX
|
||||||
|
|
||||||
Em perspectiva, ao clicar numa face "de frente", a normal capturada pelo raycaster é a normal real do triângulo, mas o usuário tende a clicar em faces inclinadas achando que estão alinhadas — o que gera pares de vetores ruins. Em **ortográfica + vista alinhada ao cubo (FRENTE/TOPO/DIR)**, a face que aparece "de frente" é geometricamente perpendicular à câmera, então a chance de capturar a normal certa é muito maior. Também damos uma dica visual (snap angular) para validar o clique.
|
### Botões na barra `ViewerControls`
|
||||||
|
- **"Cortes"** (ícone `Scissors`) — abre/fecha a janela pop-up. O estado dos cortes é independente da janela: fechar não reseta nada.
|
||||||
|
- **Lixeira** ao lado, só fica habilitada quando há pelo menos um eixo de corte ativo. Clicar = `resetSection()` (desliga e zera os 3 eixos). Único caminho para zerar.
|
||||||
|
- Indicador visual no botão "Cortes" quando há corte ativo (badge ou variante `default`).
|
||||||
|
|
||||||
## Mudanças
|
### Pop-up (componente `SectionCutPanel`)
|
||||||
|
- Janela flutuante sobre o viewer (canto superior-direito da área 3D), arrastável pelo header. Não-modal.
|
||||||
|
- Estilo: `bg-card/X` + `backdrop-blur`, borda industrial, font-mono.
|
||||||
|
- **Header**: título "Cortes de Seção", slider de **opacidade da janela** (20%–100%, default 90%), botão fechar (X).
|
||||||
|
- **3 blocos idênticos** para X / Y / Z, cada um com controle individual:
|
||||||
|
- Switch on/off do eixo.
|
||||||
|
- Switch "Inverter" (flip do lado mantido).
|
||||||
|
- Slider do nível de corte mapeado ao bbox mundial da peça ativa naquele eixo, valor em mm.
|
||||||
|
- Mini-botões: **Min** · **Centro** · **Max** para saltar a posição.
|
||||||
|
- Botão **"Recalcular limites"** (re-amostra o bbox depois de calibração/fine-tuning).
|
||||||
|
- Sem botões de salvar/memória.
|
||||||
|
- Fechar a janela apenas oculta os controles. Reabrir mostra exatamente o estado dos cortes que o usuário deixou.
|
||||||
|
|
||||||
### 1. Toggle de câmera no viewer (`ModelViewer.tsx` + `ViewerControls.tsx`)
|
## Comportamento técnico
|
||||||
- Estado `cameraMode: 'ortho' | 'persp'` no `useModelStore` (default `'ortho'`, persistido em localStorage junto com as demais prefs visuais).
|
|
||||||
- Em `ModelViewer.tsx`, condicionar `<PerspectiveCamera>` / `<OrthographicCamera>` (drei) como `makeDefault`, compartilhando posição/target com o `OrbitControls`. Ao trocar de modo, copiar `position`, `target` e calcular `zoom` ortográfico a partir da distância atual para evitar "pulo" visual.
|
|
||||||
- `OrbitControls` permanece, apenas com `enableRotate` igual; em ortho mantemos rotação livre (estilo CAD). Pan/zoom continuam funcionando.
|
|
||||||
- Botão de alternância adicionado em `ViewerControls.tsx` ao lado dos controles de render (Sólido / Bordas), com ícones (ex.: `Box` para perspectiva, `Square` para ortho) e tooltip. Atalho de teclado opcional `O`/`P`.
|
|
||||||
|
|
||||||
### 2. ViewCube já existente
|
- `gl.localClippingEnabled = true` no `onCreated` do `<Canvas>`.
|
||||||
- Continua funcionando igual, mas agora ao clicar numa face em modo ortográfico o resultado é uma vista verdadeiramente axial (sem foreshortening), o que é o comportamento esperado de CAD.
|
- Novos campos em `useModelStore` (não persistidos):
|
||||||
|
- `sectionEnabled: { x: boolean; y: boolean; z: boolean }`
|
||||||
### 3. Calibração refinada (`ViewCube.tsx` + `viewCubeBus.ts`)
|
- `sectionInvert: { x: boolean; y: boolean; z: boolean }`
|
||||||
- Ao iniciar a calibração, **forçar modo ortográfico** automaticamente (salvando o modo anterior para restaurar ao concluir/cancelar).
|
- `sectionLevel: { x: number; y: number; z: number }` (em metros, mundo)
|
||||||
- Em cada passo "await-cube-N", após o usuário clicar a face do cubo, **animar a câmera principal** para essa vista (já temos `requestView`) — assim a próxima clique na peça é feito olhando a face de frente.
|
- `sectionPanelOpen: boolean`
|
||||||
- Adicionar **snap de normal**: ao capturar a normal da face da peça, se ela estiver a <10° de um eixo principal (X/Y/Z), arredondar para esse eixo. Isso elimina ruído de faces ligeiramente chanfradas.
|
- `sectionPanelOpacity: number` (0.2–1)
|
||||||
- Mostrar no hint: "olhando para FRENTE — clique na face frontal da peça" (texto dinâmico do passo).
|
- Setters por eixo + `resetSection()` (zera enabled, invert e leva level ao centro do bbox).
|
||||||
- Manter o fluxo de 4 cliques + verificação opcional já aprovado.
|
- Helper `hasActiveSection()` derivado de `sectionEnabled`.
|
||||||
|
- Novo componente `<SectionClippingApplier>` montado dentro do `<Canvas>`:
|
||||||
### 4. Persistência
|
- Mantém 3 `THREE.Plane` reutilizáveis. A cada mudança nos campos do store, atualiza `plane.normal` (com sinal flipado se `invert`) e `plane.constant = -level` (axis-aligned, mundo).
|
||||||
- `cameraMode` salvo globalmente (preferência do app, não por peça).
|
- Aplica `material.clippingPlanes = ativos` em cada `Mesh` dos grupos registrados em `modelTransforms`. Restaura `[]` ao desligar todos os eixos.
|
||||||
- `calibrationQuat` por peça continua como já está.
|
- Limites dos sliders: bbox mundial agregado dos `getAllModelLocalGroups()`. Calculado quando o painel abre e quando o usuário aciona "Recalcular limites".
|
||||||
|
|
||||||
## Arquivos afetados
|
## Arquivos afetados
|
||||||
|
|
||||||
- `src/stores/useModelStore.ts` — campo `cameraMode` + setter.
|
- `src/stores/useModelStore.ts` — novos campos e setters de seção + painel.
|
||||||
- `src/components/three/ModelViewer.tsx` — alternância de câmera, sincronização de posição/zoom.
|
- `src/components/three/ModelViewer.tsx` — `localClippingEnabled` no GL; monta `<SectionClippingApplier>`.
|
||||||
- `src/components/ViewerControls.tsx` — botão de alternância Persp/Ortho.
|
- `src/components/SectionCutPanel.tsx` (novo) — janela pop-up flutuante com 3 sliders, switches, opacidade.
|
||||||
- `src/components/ViewCube.tsx` — força ortho durante calibração, anima vista após cada cube-click.
|
- `src/components/ViewerControls.tsx` — botão "Cortes" + lixeira condicional.
|
||||||
- `src/components/three/viewCubeBus.ts` — snap angular da normal capturada.
|
- `src/pages/Viewer.tsx` — monta `<SectionCutPanel />` na área do viewer.
|
||||||
|
|
||||||
## Pergunta
|
|
||||||
|
|
||||||
Te parece bom seguir com **ortográfica como default** e **forçar ortho durante calibração** com snap automático nas normais? Ou prefere deixar o usuário trocar manualmente e a calibração apenas "sugerir" o modo ortho via toast?
|
|
||||||
|
|||||||
Reference in New Issue
Block a user