🚀 Auto-deploy: melhoria no snap e medição AR em 03/06/2026 10:19:21
This commit is contained in:
@@ -1,47 +0,0 @@
|
|||||||
## Objetivo
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## UX
|
|
||||||
|
|
||||||
### 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`).
|
|
||||||
|
|
||||||
### 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.
|
|
||||||
|
|
||||||
## Comportamento técnico
|
|
||||||
|
|
||||||
- `gl.localClippingEnabled = true` no `onCreated` do `<Canvas>`.
|
|
||||||
- Novos campos em `useModelStore` (não persistidos):
|
|
||||||
- `sectionEnabled: { x: boolean; y: boolean; z: boolean }`
|
|
||||||
- `sectionInvert: { x: boolean; y: boolean; z: boolean }`
|
|
||||||
- `sectionLevel: { x: number; y: number; z: number }` (em metros, mundo)
|
|
||||||
- `sectionPanelOpen: boolean`
|
|
||||||
- `sectionPanelOpacity: number` (0.2–1)
|
|
||||||
- Setters por eixo + `resetSection()` (zera enabled, invert e leva level ao centro do bbox).
|
|
||||||
- Helper `hasActiveSection()` derivado de `sectionEnabled`.
|
|
||||||
- Novo componente `<SectionClippingApplier>` montado dentro do `<Canvas>`:
|
|
||||||
- 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).
|
|
||||||
- Aplica `material.clippingPlanes = ativos` em cada `Mesh` dos grupos registrados em `modelTransforms`. Restaura `[]` ao desligar todos os eixos.
|
|
||||||
- Limites dos sliders: bbox mundial agregado dos `getAllModelLocalGroups()`. Calculado quando o painel abre e quando o usuário aciona "Recalcular limites".
|
|
||||||
|
|
||||||
## Arquivos afetados
|
|
||||||
|
|
||||||
- `src/stores/useModelStore.ts` — novos campos e setters de seção + painel.
|
|
||||||
- `src/components/three/ModelViewer.tsx` — `localClippingEnabled` no GL; monta `<SectionClippingApplier>`.
|
|
||||||
- `src/components/SectionCutPanel.tsx` (novo) — janela pop-up flutuante com 3 sliders, switches, opacidade.
|
|
||||||
- `src/components/ViewerControls.tsx` — botão "Cortes" + lixeira condicional.
|
|
||||||
- `src/pages/Viewer.tsx` — monta `<SectionCutPanel />` na área do viewer.
|
|
||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
"types": [
|
"types": [
|
||||||
"vitest/globals"
|
"vitest/globals"
|
||||||
],
|
],
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"strict": false,
|
"strict": true,
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": false,
|
"noUnusedParameters": false,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": [
|
||||||
"./src/*"
|
"./src/*"
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"lib": ["ES2023"],
|
"lib": ["ES2022"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user