import React, { useMemo } from 'react'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Slider } from '@/components/ui/slider'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Badge } from '@/components/ui/badge'; import { Separator } from '@/components/ui/separator'; import { useWindStore } from '@/store/appStore'; import { calculateIsolatedShedRoof, calculateIsolatedGableRoof, frictionForceIsolatedRoof } from '@/lib/nbr-tables/table-24-25'; import IsolatedRoof3DViewer from '@/components/three/IsolatedRoof3D'; import SceneCapturePanel from '../components/SceneCapturePanel'; import ExportMenu from '../components/ExportMenu'; import { EducationalManual } from '@/components/EducationalManual'; import { PressureLegend } from '@/components/PressureLegend'; import { exportGenericToPDF, type GenericPDFSection } from '../lib/export-generic-pdf'; const IsolatedRoofModule: React.FC = () => { const { q } = useWindStore(); const [type, setType] = React.useState<'shed' | 'gable'>('shed'); const [theta, setTheta] = React.useState(15); const [height, setHeight] = React.useState(2); const [width, setWidth] = React.useState(10); const [depth, setDepth] = React.useState(10); const result = useMemo(() => { if (type === 'shed') { const r = calculateIsolatedShedRoof({ theta, height, depth }); return { ...r, cpb: { cpb1: 0, cpb2: 0 }, cpa: { cpa1: 0, cpa2: 0 } }; } const g = calculateIsolatedGableRoof({ theta, height, depth }); return { ...g, cph1: { high: 0, low: 0 }, cph2: { high: 0, low: 0 } }; }, [type, theta, height, depth]); const frictionForce = useMemo(() => frictionForceIsolatedRoof(q, depth, width), [q, depth, width]); // Cálculo dos Cpe para o viewer 3D const cpeWindward = useMemo(() => { if (type === 'shed') return (result.cph1 as { high: number; low: number }).low; return (result.cpb as { cpb1: number; cpb2: number }).cpb1; }, [type, result]); const cpeLeeward = useMemo(() => { if (type === 'shed') return (result.cph2 as { high: number; low: number }).low; return (result.cpa as { cpa1: number; cpa2: number }).cpa1; }, [type, result]); const cpeTop = useMemo(() => { if (type === 'shed') return (result.cph1 as { high: number; low: number }).high; return (result.cpb as { cpb1: number; cpb2: number }).cpb1; }, [type, result]); // Decomposição de forças globais (Carregamento 1 principal) const forces = useMemo(() => { const Ap = width * depth; // Plan area const tan = Math.tan((theta * Math.PI) / 180); let fx = 0; let fy = 0; // +Y = sustentação/arrancamento para cima if (type === 'shed') { const cp = (result.cph1 as { high: number; low: number }).high; fy = Ap * q * (-cp); fx = Ap * q * (cp * tan); } else { const cpb = (result.cpb as { cpb1: number; cpb2: number }).cpb1; const cpa = (result.cpa as { cpa1: number; cpa2: number }).cpa1; fy = -q * (Ap / 2) * (cpb + cpa); fx = q * (Ap / 2) * tan * (cpb - cpa); } return { fx, fy, magnitude: Math.sqrt(fx*fx + fy*fy) }; }, [type, width, depth, theta, q, result]); const handleExportPDF = () => { const sections: GenericPDFSection[] = [ { title: 'Geometria da Cobertura Isolada', type: 'grid', gridItems: [ { label: 'Tipo', value: type === 'shed' ? 'Uma água' : 'Duas águas' }, { label: 'Inclinação (θ)', value: `${theta}°` }, { label: 'Largura (b)', value: `${width} m` }, { label: 'Profundidade (ℓ)', value: `${depth} m` }, { label: 'Altura livre (h)', value: `${height} m` }, { label: 'Aplicável à norma', value: result.applies ? 'Sim' : 'Não' }, ], }, { title: 'Coeficientes de Pressão (Cpe)', type: 'grid', gridItems: type === 'shed' ? [ { label: 'Carregamento 1 (alta/baixa)', value: `${(result.cph1 as any).high.toFixed(2)} / ${(result.cph1 as any).low.toFixed(2)}` }, { label: 'Carregamento 2 (alta/baixa)', value: `${(result.cph2 as any).high.toFixed(2)} / ${(result.cph2 as any).low.toFixed(2)}` }, ] : [ { label: 'Barlavento (Cp_b1 / Cp_b2)', value: `${(result.cpb as any).cpb1.toFixed(2)} / ${(result.cpb as any).cpb2.toFixed(2)}` }, { label: 'Sotavento (Cp_a1 / Cp_a2)', value: `${(result.cpa as any).cpa1.toFixed(2)} / ${(result.cpa as any).cpa2.toFixed(2)}` }, ], }, { title: 'Forças Globais (Carr. 1)', type: 'grid', gridItems: [ { label: 'Vertical (Fy - Arrancamento)', value: `${forces.fy.toFixed(2)} kN` }, { label: 'Horizontal (Fx - Arrasto)', value: `${forces.fx.toFixed(2)} kN` }, { label: 'Atrito (Ff)', value: `${frictionForce.toFixed(3)} kN` }, ], }, ]; exportGenericToPDF('Cobertura Isolada', sections); }; return (
{/* Coluna Esquerda: Controles */}
Cobertura Isolada Sec. 7.2 — sobre suportes de reduzidas dimensões.
{theta}°
setTheta(v[0])} />
{width} m
setWidth(v[0])} />
{depth} m
setDepth(v[0])} />
{height} m
setHeight(v[0])} />
q:{q.toFixed(4)} kN/m²
Aplicável:{result.applies ? 'sim' : 'não'}
{!result.applies && (
Limites da Tabela {type === 'shed' ? '24' : '25'} não atendidos (h ≤ tg(θ)·b/2). Tratar como edificação fechada.
)}
{/* Coluna Central: 3D */}
θ = {theta}° {type === 'shed' ? 'Uma água' : 'Duas águas'}
{/* Coluna Direita: Resultados */}
Coeficientes (Cpe) Dois carregamentos a verificar {type === 'shed' ? ( <>

Carregamento 1 (barlavento)

Alta (h)
{(result.cph1 as { high: number; low: number }).high.toFixed(2)}
Baixa (l)
{(result.cph1 as { high: number; low: number }).low.toFixed(2)}

Carregamento 2 (invertido)

Alta (h)
{(result.cph2 as { high: number; low: number }).high.toFixed(2)}
Baixa (l)
{(result.cph2 as { high: number; low: number }).low.toFixed(2)}
) : ( <>

Zona barlavento (Cp_b)

Cp_b1
{(result.cpb as { cpb1: number; cpb2: number }).cpb1.toFixed(2)}
Cp_b2
{(result.cpb as { cpb1: number; cpb2: number }).cpb2.toFixed(2)}

Zona sotavento (Cp_a)

Cp_a1
{(result.cpa as { cpa1: number; cpa2: number }).cpa1.toFixed(2)}
Cp_a2
{(result.cpa as { cpa1: number; cpa2: number }).cpa2.toFixed(2)}
)}

Forças Globais (Carr. 1)

Fx (Arrasto)
{forces.fx.toFixed(2)} kN
Fy (Arrancamento)
{forces.fy.toFixed(2)} kN
Força de atrito (vento ∥ geratriz): {frictionForce.toFixed(3)} kN
); }; export default IsolatedRoofModule;