import { Document, Page, Text, View, StyleSheet, Image as PdfImage, pdf } from '@react-pdf/renderer'; import { useGalpaoStore } from '../store/galpaoStore'; import { useWindStore } from '../store/appStore'; import { useCaptureStore } from '../store/captureStore'; import { getColumnLinearLoads, getRoofLinearLoads, getAllPillarBaseReactions, getDragForce, } from './line-loads'; import { getWallCpeOfficial, getRoofCpeOfficial } from './coefficients'; import { appendKgf } from './export-generic-pdf'; const styles = StyleSheet.create({ page: { flexDirection: 'column', padding: 40, fontSize: 10, fontFamily: 'Helvetica', color: '#333', }, header: { marginBottom: 15, borderBottom: '2pt solid #4f46e5', paddingBottom: 10, }, title: { fontSize: 22, fontWeight: 'extrabold', color: '#1e1b4b' }, subtitle: { fontSize: 11, color: '#4338ca', marginTop: 4, fontWeight: 'bold' }, section: { marginTop: 15, marginBottom: 10 }, sectionTitle: { fontSize: 14, fontWeight: 'bold', marginBottom: 8, color: '#111' }, row: { flexDirection: 'row', marginBottom: 4 }, label: { width: 200, fontWeight: 'bold' }, value: { flex: 1 }, table: { display: 'flex', flexDirection: 'column', marginTop: 10, borderTop: '1pt solid #ccc', borderLeft: '1pt solid #ccc', }, tableRow: { flexDirection: 'row' }, tableHeader: { backgroundColor: '#f3f4f6', fontWeight: 'bold' }, tableCell: { flex: 1, padding: 5, borderRight: '1pt solid #ccc', borderBottom: '1pt solid #ccc', textAlign: 'center', }, tableCellFirst: { flex: 1, padding: 5, borderRight: '1pt solid #ccc', borderBottom: '1pt solid #ccc', textAlign: 'left', }, footer: { position: 'absolute', bottom: 30, left: 40, right: 40, textAlign: 'center', color: '#999', fontSize: 8, borderTop: '1pt solid #eaeaea', paddingTop: 10, }, sceneImage: { width: 480, height: 270, objectFit: 'contain', marginVertical: 8, border: '1pt solid #ddd', }, sceneCaption: { fontSize: 8, color: '#666', fontStyle: 'italic', textAlign: 'center', marginBottom: 8, }, }); interface ReportProps { galpao: ReturnType; wind: ReturnType; sceneImage?: string | null; } const ReportDocument = ({ galpao, wind, sceneImage }: ReportProps) => { const pressure = (cpe: number) => (wind.q * (cpe - wind.cpi)).toFixed(3); const cpi = wind.cpi.toFixed(2); const fmtSigned = (v: number, p = 3) => (v >= 0 ? `+${v.toFixed(p)}` : v.toFixed(p)); const FRAME_SPACING = 6.0; const PURLIN_SPACING = 1.5; return ( BrainWind v1.0 — Memória de Cálculo Relatório de Ação do Vento em Galpão (Conforme NBR 6123:2023) Este documento apresenta o memorial de cálculo detalhado passo a passo, comprovando a exatidão dos parâmetros adotados e a aderência integral às diretrizes da norma brasileira. 1. Parâmetros Globais do Vento e Pressão Dinâmica Velocidade Básica (V₀): {wind.v0} m/s (conforme Figura 1 e Anexo C da NBR 6123) Fator Topográfico (S₁): {wind.s1} (conforme Seção 5.2) Fator de Rugosidade (S₂): {wind.s2.toFixed(3)} (Categoria {wind.terrainCategory}, Classe {wind.structureClass}, conforme Tabela 2) Fator Estatístico (S₃): {wind.s3.toFixed(2)} (Grupo {wind.s3Group}, conforme Tabela 4) Memória de Cálculo (Sec 4.2 e 4.3): Vₖ = V₀ × S₁ × S₂ × S₃ Vₖ = {wind.v0} × {wind.s1} × {wind.s2.toFixed(3)} × {wind.s3.toFixed(2)} = {wind.vk.toFixed(2)} m/s q = 0,613 × (Vₖ)² {appendKgf(`q = 0,613 × (${wind.vk.toFixed(2)})² = ${(0.613 * Math.pow(wind.vk, 2) / 1000).toFixed(4)} kN/m²`)} 2. Geometria do Galpão (Tabelas 4 e 5) Largura (b): {galpao.width} m Comprimento (a): {galpao.length} m Altura do Pé-direito (h): {galpao.height} m Inclinação do Telhado (θ): {galpao.roofPitch}° Direção do Vento Analisada: {wind.windAngle}° 3. Pressão Interna (Sec. 6.3, Figura 2) Caso de Permeabilidade: {wind.permeabilityCase} Coeficiente Cpi: {cpi} {[0, 90].map((angle, index) => { const wCpe = getWallCpeOfficial(galpao.length, galpao.width, galpao.height, angle as 0 | 90); const rCpe = getRoofCpeOfficial(galpao.length, galpao.width, galpao.height, galpao.roofPitch, angle as 0 | 90); const colLoads = getColumnLinearLoads(wind.cpi, wind.q, wCpe, FRAME_SPACING, angle as 0 | 90); const rLoads = getRoofLinearLoads(wind.cpi, wind.q, rCpe, PURLIN_SPACING, galpao.roofPitch); const rxns = getAllPillarBaseReactions(colLoads, galpao.height); const dForce = getDragForce(wCpe, rCpe, wind.q, galpao.length, galpao.width, galpao.height, galpao.roofPitch, angle as 0 | 90); const secBase = index === 0 ? 4 : 6; return ( Cenário: Vento a {angle}° {secBase}. Coeficientes e Pressões (q × (Cpe − Cpi)) Elemento / Região Cpe Cpi p [kN/m² (kgf/m²)] {Object.entries(wCpe).map(([face, cpeVal]) => ( Parede — {face} {(cpeVal as number).toFixed(2)} {cpi} {pressure(cpeVal as number)} ({(parseFloat(pressure(cpeVal as number)) * 101.9716).toFixed(1)}) ))} {Object.entries(rCpe).map(([face, cpeVal]) => ( Telhado — {face} {(cpeVal as number).toFixed(2)} {cpi} {pressure(cpeVal as number)} ({(parseFloat(pressure(cpeVal as number)) * 101.9716).toFixed(1)}) ))} {secBase + 1}. Cargas Lineares (kN/m (kgf/m)) Pórticos: {FRAME_SPACING} m | Terças: {PURLIN_SPACING} m Pilar Cpe w [kN/m (kgf/m)] {([ ['Barlavento', angle === 0 ? wCpe.C : wCpe.A, colLoads.windward], ['Sotavento', angle === 0 ? wCpe.D : wCpe.B, colLoads.leeward], ['Lateral 1', angle === 0 ? wCpe.A : wCpe.C, colLoads.sideA], ['Lateral 2', angle === 0 ? wCpe.B : wCpe.D, colLoads.sideB], ] as const).map(([label, cpeVal, w]) => ( {label} {cpeVal.toFixed(2)} {fmtSigned(w)} ({fmtSigned(w * 101.9716, 1)}) ))} Terça (Zona) Cpe w [kN/m (kgf/m)] {(['E', 'F', 'G', 'H', 'I', 'J'] as const).map((z) => ( {z} {rCpe[z].toFixed(2)} {fmtSigned(rLoads[z])} ({fmtSigned(rLoads[z] * 101.9716, 1)}) ))} Reação global na base: {fmtSigned(rxns.total, 3)} kN ({fmtSigned(rxns.total * 101.9716, 1)} kgf) Força de arrasto global (Cₐ): {dForce.forceKN.toFixed(3)} kN ({(dForce.forceKN * 101.9716).toFixed(1)} kgf) ); })} {sceneImage && ( 8. Modelo 3D (Captura de Cena) Vista isométrica capturada em tempo real pelo projetista na interface web. Cores indicam intensidade de pressão (azul: empuxo, vermelho: sucção). )} Declaração de Conformidade: Todos os coeficientes de forma (Cpe), coeficientes de pressão interna (Cpi) e pressões dinâmicas calculados neste relatório estão em conformidade estrita com os procedimentos, tabelas e ábacos definidos pela norma ABNT NBR 6123:2023. Este memorial serve como prova matemática e pode ser anexado aos documentos do projeto estrutural. Gerado por BrainWind v1.0 — Tecnologia Auditada em Engenharia Estrutural (NBR 6123:2023) ); }; export async function exportGalpaoToPDF() { const galpao = useGalpaoStore.getState(); const wind = useWindStore.getState(); const sceneImage = useCaptureStore.getState().capturedImage; const blob = await pdf( , ).toBlob(); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', 'memoria_calculo_vento.pdf'); document.body.appendChild(link); link.click(); document.body.removeChild(link); }