From f787e8c002a59a7705d55603f567a67c8a7935ca Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 26 Aug 2026 11:43:19 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Auto-deploy:=20BrainWind=20atual?= =?UTF-8?q?izado=20em=2026/08/2026=2011:43:19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/App.tsx | 2 - app/src/components/DragCoefficientChart.tsx | 2 +- app/src/components/Heatmap2D.tsx | 54 ++--- app/src/lib/audit/scenarios.ts | 210 ++++++++++++++++++++ app/src/pages/Compare.tsx | 28 --- app/src/pages/GalpaoModule.tsx | 31 +-- 6 files changed, 258 insertions(+), 69 deletions(-) delete mode 100644 app/src/pages/Compare.tsx diff --git a/app/src/App.tsx b/app/src/App.tsx index cefcab1..18b0b50 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -15,7 +15,6 @@ const TowerModule = lazy(() => import('./pages/TowerModule')); const PiperackModule = lazy(() => import('./pages/PiperackModule')); const ShelterModule = lazy(() => import('./pages/ShelterModule')); const CertificatePage = lazy(() => import('./pages/CertificatePage')); -const CompareModule = lazy(() => import('./pages/Compare')); import { Home, Settings, Menu, Cylinder, Church, CircleDot, Square, Layers, BarChart3, Activity, Warehouse, @@ -377,7 +376,6 @@ function App() { } /> } /> } /> - } /> diff --git a/app/src/components/DragCoefficientChart.tsx b/app/src/components/DragCoefficientChart.tsx index 7df0a8a..434aafc 100644 --- a/app/src/components/DragCoefficientChart.tsx +++ b/app/src/components/DragCoefficientChart.tsx @@ -85,7 +85,7 @@ export function DragCoefficientChart({ l1, l2, h, caLow, caHigh }: DragCoefficie {/* Fake Curves */} {curves.map((d, idx) => ( - + ))} {/* Axes */} diff --git a/app/src/components/Heatmap2D.tsx b/app/src/components/Heatmap2D.tsx index 555d480..20f9b42 100644 --- a/app/src/components/Heatmap2D.tsx +++ b/app/src/components/Heatmap2D.tsx @@ -67,33 +67,34 @@ const Heatmap2D: React.FC = ({ overrideAngle, overrideWallCpe, o return (
-
-

Planta Baixa - Telhado e Paredes

-

Vento incidindo a {windAngle}°

+
+

Planta Baixa - Telhado e Paredes

+

Vento incidindo a {windAngle}°

- - - - - - +
+ + + + + + {/* Vento (Setas Dinâmicas) */} {windAngle === 90 && ( - - - - Vento (90°) + + + + Vento (90°) )} {windAngle === 0 && ( - - - - Vento (0°) + + + + Vento (0°) )} @@ -162,23 +163,24 @@ const Heatmap2D: React.FC = ({ overrideAngle, overrideWallCpe, o {/* Indicadores de Paredes */} {windAngle === 0 ? ( <> - A - B - D - C + A + B + D + C ) : ( <> - A - B - C - D + A + B + C + D )} +
-
+
Sucção Máxima diff --git a/app/src/lib/audit/scenarios.ts b/app/src/lib/audit/scenarios.ts index da9e13e..bca0560 100644 --- a/app/src/lib/audit/scenarios.ts +++ b/app/src/lib/audit/scenarios.ts @@ -17,6 +17,13 @@ import { evaluateComfort } from '../comfort'; import { classifyBridge, type BridgeClassificationInput } from '../modules/bridge'; import { calculateTower } from '../modules/tower'; import { calculatePiperack, type PiperackInput } from '../modules/piperack'; +import { calculateVault, type VaultInput } from '../modules/vault'; +import { calculateDome, type DomeInput } from '../modules/dome'; +import { calculateIsolatedGableRoof, calculateIsolatedShedRoof } from '../nbr-tables/table-24-25'; +import { calculateFlatBarForce, type FlatBarForceInput } from '../nbr-tables/table-26'; +import { applyRoughnessChange } from '../wind-direction'; +import { TABLE_1 } from '../nbr-tables/table-1'; +import { getStrouhalNumber, criticalVelocity, scrutonNumber } from '../nbr-tables/table-33'; function calcWind( v0: number, s1: number, s3: number, @@ -267,6 +274,209 @@ export function generateAllScenarios(): AuditScenario[] { )); } + // --- NOVOS CENÁRIOS BIBLIOGRÁFICOS EXPANDIDOS (LITERATURA & NBR 6123) --- + + // 1.1 Abóbada Cilíndrica (Blessmann / Tabela 15 NBR 6123) + { + const vaultIn: VaultInput = { f: 4, l: 20, b: 40, vk: 35, regime: 'laminar-rough', cpi: 0 }; + const vaultRes = calculateVault(vaultIn); + scenarios.push(makeScenario( + 'blessmann-abobada-f4-l20', 'vault', 'Blessmann: Abóbada Cilíndrica f=4m l=20m b=40m', + { ...vaultIn }, + { q: vaultRes.q, fOverL: 4 / 20 }, + { ...vaultRes.windPerpendicular, q: vaultRes.q }, + { q: { min: 0.5, max: 1.5 } }, + 'vault', + { f: 4, l: 20, b: 40, cpeValues: vaultRes.windPerpendicular }, + 'Sec. 6.2.3 / Tabela 15', + true, + 'Blessmann, J. Ação do Vento em Coberturas Curvas e Abóbadas, Exemplo 3.2 / NBR 6123:2023 Tabela 15', + 'Abóbada cilíndrica com vão de 20m, flecha de 4m (f/l = 0,20) e comprimento de 40m sob vento perpendicular de 35 m/s. Avaliação da sucção no topo e pressões no bordo de ataque.' + )); + } + + // 1.2 Cúpula Semiesférica apoiada no solo (Rebello / Tabela 21 NBR 6123) + { + const domeIn: DomeInput = { d: 30, f: 6, vk: 40, type: 'on-ground', cpi: 0 }; + const domeRes = calculateDome(domeIn); + scenarios.push(makeScenario( + 'rebello-cupula-d30-f6', 'dome', 'Rebello: Cúpula no Solo d=30m f=6m', + { ...domeIn }, + { q: domeRes.q, fOverD: domeRes.fOverD }, + { cpeBarlavento: domeRes.cpeBarlavento, cpeTopo: domeRes.cpeTopo, liftCoefficient: domeRes.liftCoefficient, liftForceKN: domeRes.liftForceKN }, + { q: { min: 0.5, max: 1.8 }, liftForceKN: { min: 50, max: 1000 } }, + 'dome', + { d: 30, f: 6, cpeTopo: domeRes.cpeTopo, cpeBarlavento: domeRes.cpeBarlavento }, + 'Sec. 6.2.4 / Tabela 21', + true, + 'Rebello, Y. A Concepção Estrutural e a Arquitetura / NBR 6123 Tabela 21 (Cúpulas sobre o solo)', + 'Cúpula esférica implantada diretamente no terreno com diâmetro d=30m e flecha f=6m (f/d = 0,20). Determinação da força global de sustentação aerodinâmica (empuxo ascendente) para velocidade característica de 40 m/s.' + )); + } + + // 1.3 Cobertura Isolada a Duas Águas - Hangar Aberto (Pfeil / Tabela 25 NBR 6123) + { + const isoIn = { theta: 10, height: 5, depth: 15 }; + const isoRes = calculateIsolatedGableRoof(isoIn); + scenarios.push(makeScenario( + 'pfeil-cobertura-isolada-2aguas', 'isolated-roof', 'Pfeil: Cobertura Isolada 2 Águas θ=10°', + { ...isoIn, q: 0.85 }, + { cpb1: isoRes.cpb.cpb1, cpa1: isoRes.cpa.cpa1 }, + { cpb1: isoRes.cpb.cpb1, cpb2: isoRes.cpb.cpb2, cpa1: isoRes.cpa.cpa1, cpa2: isoRes.cpa.cpa2, applies: isoRes.applies ? 1 : 0 }, + { cpb1: { min: 0.5, max: 2.0 }, cpa1: { min: -2.0, max: -0.5 } }, + 'isolatedRoof', + { theta: 10, height: 5, depth: 15, cpa: isoRes.cpa, cpb: isoRes.cpb }, + 'Sec. 7.2 / Tabela 25', + true, + 'Pfeil & Pfeil, Estruturas de Aço, 8ª ed., Cap. 5 (Galpões Abertos e Hangares Isolados) / NBR 6123 Tabela 25', + 'Cobertura isolada simétrica de duas águas com inclinação de 10° e pé-direito livre h=5m (b=15m). Análise dos coeficientes de pressão líquida nos carregamentos extremos de sobrepressão e sucção.' + )); + } + + // 1.4 Cobertura Isolada a Uma Água - Marquise / Abrigo (NBR 6123 Tabela 24) + { + const shedIn = { theta: 5, height: 3.5, depth: 10 }; + const shedRes = calculateIsolatedShedRoof(shedIn); + scenarios.push(makeScenario( + 'nbr-marquise-isolada-1agua', 'isolated-roof', 'NBR 6123: Marquise Isolada a Uma Água θ=5°', + { ...shedIn, q: 0.95 }, + { cph1High: shedRes.cph1.high, cph1Low: shedRes.cph1.low }, + { cph1High: shedRes.cph1.high, cph1Low: shedRes.cph1.low, applies: shedRes.applies ? 1 : 0 }, + { cph1High: { min: -1.5, max: 0.0 }, cph1Low: { min: -2.5, max: -0.5 } }, + 'isolatedRoof', + { theta: 5, height: 3.5, depth: 10 }, + 'Sec. 7.2.1 / Tabela 24', + true, + 'NBR 6123:2023, Tabela 24 — Coberturas isoladas a uma água plana / Exemplo Didático CBCA', + 'Marquise/alpendre isolado a 1 água com inclinação suave de 5° e altura de 3.5m. Verificação dos coeficientes médios e limites de sucção no bordo de ataque.' + )); + } + + // 1.5 Torre Treliçada Triangular de Telecomunicações (NBR 6123 Tabela 29/30 & Blessmann) + { + const towerIn = { section: 'triangular' as const, barType: 'flat' as const, phi: 0.25, aFace: 90, alphaWind: 0 as const, q: 1.15 }; + const towerRes = calculateTower(towerIn); + scenarios.push(makeScenario( + 'blessmann-torre-triangular-phi025', 'tower', 'Blessmann: Torre Triangular φ=0.25', + { ...towerIn }, + { caEff: towerRes.caEff }, + { caEff: towerRes.caEff, forceKN: towerRes.forceKN }, + { caEff: { min: 1.5, max: 3.5 }, forceKN: { min: 100, max: 500 } }, + 'tower', + { section: 'triangular', baseWidth: 3, height: 30, panels: 6, phi: 0.25, alphaWind: 0, forceKN: towerRes.forceKN }, + 'Sec. 8.5 / Tabelas 29-30', + true, + 'Blessmann, J. Ação do Vento em Torres e Estruturas Treliçadas, Cap. 7 / NBR 6123:2023 Sec. 8.5', + 'Torre treliçada de seção triangular equilátera com índice de plenitude φ=0,25 e área projetada da face de 90 m² submetida a vento frontal (0°). Cálculo do coeficiente de arrasto efetivo e da força global na torre.' + )); + } + + // 1.6 Barra Isolada Perfil L / Cantoneira de Torre (Pfeil & NBR 6123 Tabela 26) + { + const barIn: FlatBarForceInput = { section: 'l', alpha: 45, width: 0.15, length: 3.0, q: 1.05 }; + const barRes = calculateFlatBarForce(barIn); + scenarios.push(makeScenario( + 'pfeil-cantoneira-l-alpha45', 'bar', 'Pfeil: Cantoneira L150x150 sob Vento a 45°', + { ...barIn }, + { cx: barRes.cx, cy: barRes.cy, kFactor: barRes.kFactor }, + { fxKN: barRes.fxKN, fyKN: barRes.fyKN, cx: barRes.cx, cy: barRes.cy }, + { cx: { min: 1.0, max: 2.2 }, cy: { min: 1.0, max: 2.2 }, fxKN: { min: 0.5, max: 2.0 } }, + 'bar', + { section: 'l', width: 0.15, length: 3.0, alpha: 45, fxKN: barRes.fxKN, fyKN: barRes.fyKN }, + 'Sec. 8.1 / Tabelas 26 e 28', + true, + 'Pfeil, M. & Pfeil, W. Estruturas de Aço, Cap. Ações em Barras Isoladas / NBR 6123 Tabela 26', + 'Barra prismática isolada de seção cantoneira de abas iguais (L 150x150 mm) com 3 metros de comprimento livre, sob incidência oblíqua do vento a 45°. Determinação das componentes de força Cx, Cy e redução por comprimento finito (Fator K).' + )); + } + + // 1.7 Galpão Extenso — Força de Atrito Superficial (Blessmann Cap. 5 / NBR 6123 Sec. 6.1.5) + { + const fricIn = { roughness: 'rounded-ribs' as const, length: 80, width: 15, height: 6, roofPitch: 8, q: 1.0, windAngle: 0 as const }; + const fricRes = calculateFriction(fricIn); + scenarios.push(makeScenario( + 'blessmann-galpao-extenso-atrito', 'galpao', 'Blessmann: Galpão Extenso 80x15m — Atrito Superficial', + { ...fricIn }, + { applies: fricRes.applies ? 1 : 0, ratioLh: 80 / 6 }, + { applies: fricRes.applies ? 1 : 0, forceKN: fricRes.forceKN, roofArea: fricRes.roofArea, cf: fricRes.cf }, + { forceKN: { min: 10, max: 50 }, roofArea: { min: 1000, max: 1500 } }, + 'warehouse', + { width: 15, length: 80, height: 6, roofPitch: 8, windAngle: 0, cpi: 0 }, + 'Sec. 6.1.5', + true, + 'Blessmann, J. O Vento na Engenharia Estrutural, Cap. 5 (Forças de Atrito em Edificações Longas) / NBR 6123 Sec. 6.1.5', + 'Galpão industrial longo de 80 metros de comprimento por 15m de largura e 6m de altura (l/h = 13,3 > 4). Telhas com nervuras onduladas/arredondadas (Cf = 0,02). Cálculo da força de arrasto por atrito superficial na cobertura.' + )); + } + + // 1.8 Transição de Rugosidade de Terreno — Litoral para Centro Urbano (NBR 6123 Sec. 5.5) + { + const transIn = { near: 'IV' as TerrainCategory, far: 'I' as TerrainCategory, distance: 500, height: 30 }; + const params = new Map(); + (['I', 'II', 'III', 'IV', 'V'] as TerrainCategory[]).forEach(cat => { + params.set(cat, TABLE_1[cat].B); + }); + const transRes = applyRoughnessChange(transIn, params); + scenarios.push(makeScenario( + 'nbr-transicao-rugosidade-catI-IV', 'galpao', 'NBR 6123: Transição de Rugosidade Cat I -> Cat IV (x=500m, z=30m)', + { ...transIn }, + { z1: transRes.z1, z2: transRes.z2, s2: transRes.s2 }, + { s2: transRes.s2, z1: transRes.z1 }, + { s2: { min: 0.8, max: 1.3 } }, + 'warehouse', + { width: 20, length: 40, height: 30, roofPitch: 0, windAngle: 0, cpi: 0 }, + 'Sec. 5.5', + true, + 'NBR 6123:2023, Seção 5.5 (Mudança de Rugosidade do Terreno) / Notas de Aula Prof. Blessmann', + 'Edificação de 30m de altura situada a 500 metros da linha de transição costeira (saída de Terreno Aberto Cat. I para Zona Urbana Densa Cat. IV). Determinação da altura da camada limite interna (z1) e do fator S2 interpolado.' + )); + } + + // 1.9 Desprendimento de Vórtices em Chaminé Esbelta (Strouhal & Scruton — NBR 6123 Sec. 10) + { + const st = getStrouhalNumber('circle', 0); // 0.20 + const fn = 1.2; // Hz + const d = 1.5; // m + const vcr = criticalVelocity(fn, d, st); // 1.2 * 1.5 / 0.20 = 9.0 m/s + const sc = scrutonNumber(0.02, 600, 1.225, 1.5); // 0.02 * 600 / (1.225 * 1.5) = 6.53 + scenarios.push(makeScenario( + 'nbr-vortices-chamine-strouhal', 'dynamics', 'NBR 6123: Vórtices de Von Kármán em Chaminé Cilíndrica', + { shape: 'circle', diameter: d, naturalFreq: fn, massPerLength: 600, dampingRatio: 0.02 }, + { st, vcr, sc }, + { st, vcr, sc, isSusceptible: sc < 20 ? 1 : 0 }, + { vcr: { min: 5, max: 20 }, sc: { min: 2, max: 20 } }, + 'dynamics', + { height: 45, freq: fn, windSpeed: vcr, scruton: sc, sectionShape: 'circle', sectionSize: d }, + 'Sec. 10 / Tabela 33', + true, + 'NBR 6123:2023, Seção 10 (Efeitos Dinâmicos de Desprendimento de Vórtices) & Simiu & Scanlan', + 'Chaminé metálica esbelta circular com d=1.5m, frequência natural fundamental fn=1.2 Hz, massa linear de 600 kg/m e amortecimento estrutural ξ=0,02. Cálculo do Número de Strouhal (St=0,20), velocidade crítica de ressonância (Vcr) e Número de Scruton (Sc).' + )); + } + + // 1.10 Pipe-Rack Industrial com Múltiplos Planos (NBR 6123 Sec. 8.4 / Blessmann) + { + const pipeIn: PiperackInput = { + width: 12, height: 5, elevation: 8, spacing: 6, numFrames: 4, phiStruct: 0.20, + pipes: [{ id: 'p1', diameter: 0.6, elevationOffset: 5 }, { id: 'p2', diameter: 0.6, elevationOffset: 5 }], + q: 1.10 + }; + const pipeRes = calculatePiperack(pipeIn); + scenarios.push(makeScenario( + 'blessmann-piperack-4quadros', 'piperack', 'Blessmann: Pipe-Rack Industrial 4 Quadros com Tubulações', + { ...pipeIn }, + { phiTotal: pipeRes.phiTotal, effectiveElevation: pipeRes.effectiveElevation }, + { caFrontal: pipeRes.caFrontal, eta: pipeRes.eta, globalForce: pipeRes.globalForce }, + { caFrontal: { min: 1.5, max: 3.0 }, eta: { min: 0.4, max: 1.0 }, globalForce: { min: 10, max: 300 } }, + 'warehouse', + { width: 12, height: 5, length: 24 }, + 'Sec. 8.4', + true, + 'Blessmann, J. Ação do Vento em Estruturas Industriais e Reticulados / NBR 6123:2023 Sec. 8.4', + 'Pipe-rack industrial contendo 4 pórticos transversais espaçados de 6m com bandejas de cabos e 2 linhas de tubulação de 600mm de diâmetro. Cálculo do índice de plenitude total (φ), fator de sombreamento (η) e carga de arrasto global.' + )); + } + // 2. GALPÃO VARREDURA const galpaoGeos = [ { w: 10, l: 20, h: 4 }, { w: 15, l: 30, h: 6 }, { w: 20, l: 50, h: 8 }, diff --git a/app/src/pages/Compare.tsx b/app/src/pages/Compare.tsx deleted file mode 100644 index c6f6f2e..0000000 --- a/app/src/pages/Compare.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { useGalpaoStore } from '../store/galpaoStore'; -import { getWallCpeOfficial as getWallCpe, getRoofCpeOfficial as getRoofCpe } from '../lib/coefficients'; -import Heatmap2D from '../components/Heatmap2D'; - -const Compare: React.FC = () => { - const { length, width, height, roofPitch } = useGalpaoStore(); - - const wallCpe0 = getWallCpe(length, width, height, 0); - const roofCpe0 = getRoofCpe(length, width, height, roofPitch, 0); - - const wallCpe90 = getWallCpe(length, width, height, 90); - const roofCpe90 = getRoofCpe(length, width, height, roofPitch, 90); - - return ( -
-

Comparação A/B (0° vs 90°)

-

Compare visualmente a distribuição de pressões (Cpe - Cpi) nas duas direções normativas simultaneamente.

- -
- - -
-
- ); -}; - -export default Compare; diff --git a/app/src/pages/GalpaoModule.tsx b/app/src/pages/GalpaoModule.tsx index 5bc1e19..92cf955 100644 --- a/app/src/pages/GalpaoModule.tsx +++ b/app/src/pages/GalpaoModule.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Link } from 'react-router-dom'; import Warehouse3DViewer from '../components/Warehouse3D'; import Heatmap2D from '../components/Heatmap2D'; import LinearLoadsTable from '../components/LinearLoadsTable'; @@ -8,6 +7,7 @@ import FtoolExportCard from '../components/FtoolExportCard'; import { CpiSettingsCard } from '../components/CpiSettingsCard'; import { useGalpaoStore } from '../store/galpaoStore'; import { useWindStore } from '../store/appStore'; +import { getWallCpeOfficial as getWallCpe, getRoofCpeOfficial as getRoofCpe } from '../lib/coefficients'; 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'; @@ -16,7 +16,7 @@ import { Separator } from '@/components/ui/separator'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; import { Button } from '@/components/ui/button'; -import { AlertCircle, Lightbulb, Box, Wind, Columns } from 'lucide-react'; +import { AlertCircle, Lightbulb, Box, Wind } from 'lucide-react'; import ExportMenu from '../components/ExportMenu'; import { EducationalManual } from '@/components/EducationalManual'; import { PressureLegend } from '@/components/PressureLegend'; @@ -280,25 +280,17 @@ const GalpaoModule: React.FC = () => { Modelo 3D Heatmap 2D + Modo A/B
-
- -
-
-
+