import React, { useMemo, useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Slider } from '@/components/ui/slider'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { useWindStore } from '@/store/appStore'; import { useHydrationStore } from '@/store/hydrationStore'; import { calculateShelterWind, calculateShelterWindAllAngles, type ShelterCondition, type OpeningPosition, type ShelterWindAngle, } from '@/lib/nbr-tables/table-shelters'; import Shelter3D from '@/components/three/Shelter3D'; import { WindFlowGrid2D } from '@/components/WindFlowGrid2D'; import SceneCapturePanel from '../components/SceneCapturePanel'; import ExportMenu from '../components/ExportMenu'; import { EducationalManual } from '@/components/EducationalManual'; import { WindParametersSummary } from '@/components/WindParametersSummary'; import { SaveModuleDialog } from '@/components/SaveModuleDialog'; import { exportGenericToPDF, type GenericPDFSection } from '../lib/export-generic-pdf'; import { Eye, Box, Layers, ArrowUpRight, CheckCircle2, Wind, AlertTriangle } from 'lucide-react'; import { cn } from '@/lib/utils'; import { usePersistentState } from '@/hooks/usePersistentState'; const conditionLabels: Record = { cond1: '1. Estanque 3 lados (Fundo + Lados)', cond2: '2. Fundo Fechado + Lados Abertos', cond3: '3. Fundo Aberto + Lados Fechados (Túnel)', cond4: '4. Totalmente Livre (4 lados abertos)', }; const ShelterModule: React.FC = () => { const { q } = useWindStore(); const [condition, setCondition] = usePersistentState('ShelterModule_condition', 'cond1'); const [windAngle, setWindAngle] = usePersistentState('ShelterModule_windAngle', 0); const [depth, setDepth] = usePersistentState('ShelterModule_depth', 6); const [width, setWidth] = usePersistentState('ShelterModule_width', 10); const [height, setHeight] = usePersistentState('ShelterModule_height', 4.8); const [theta, setTheta] = usePersistentState('ShelterModule_theta', 5); const [numColumns, setNumColumns] = usePersistentState('ShelterModule_numColumns', 2); const [backClosure, setBackClosure] = usePersistentState('ShelterModule_backClosure', 75); const [backRange, setBackRange] = usePersistentState<[number, number]>('ShelterModule_backRange', [0, 75]); const [leftClosure, setLeftClosure] = usePersistentState('ShelterModule_leftClosure', 100); const [rightClosure, setRightClosure] = usePersistentState('ShelterModule_rightClosure', 100); const [surfaceMass, setSurfaceMass] = usePersistentState('ShelterModule_surfaceMass', 15); // kg/m² para lona/telha leve const [viewMode, setViewMode] = usePersistentState<'3d' | 'elevation' | 'airflow'>('ShelterModule_viewMode', '3d'); const pendingLoad = useHydrationStore((s) => s.pendingLoad); const clearPendingLoad = useHydrationStore((s) => s.clearPendingLoad); React.useEffect(() => { if (pendingLoad && pendingLoad.module === 'shelter') { const p = pendingLoad.inputs as any; if (p.condition !== undefined) setCondition(p.condition); if (p.windAngle !== undefined) setWindAngle(p.windAngle); if (p.depth !== undefined) setDepth(p.depth); if (p.width !== undefined) setWidth(p.width); if (p.height !== undefined) setHeight(p.height); if (p.theta !== undefined) setTheta(p.theta); if (p.numColumns !== undefined) setNumColumns(p.numColumns); if (p.backClosure !== undefined) setBackClosure(p.backClosure); if (p.leftClosure !== undefined) setLeftClosure(p.leftClosure); if (p.rightClosure !== undefined) setRightClosure(p.rightClosure); if (p.surfaceMass !== undefined) setSurfaceMass(p.surfaceMass); clearPendingLoad(); } }, [pendingLoad, clearPendingLoad, setCondition, setWindAngle, setDepth, setWidth, setHeight, setTheta, setNumColumns, setBackClosure, setLeftClosure, setRightClosure, setSurfaceMass]); // Determinação automática da posição da fresta/vão a partir dos cursores (base e topo) const bottomGap = backRange[0]; const topGap = 100 - backRange[1]; const openingPos: OpeningPosition = topGap > 2 && topGap >= bottomGap ? 'top' : bottomGap > 2 && bottomGap > topGap ? 'bottom' : 'distributed'; const handleConditionChange = (cond: ShelterCondition) => { setCondition(cond); if (cond === 'cond1') { setBackRange([0, 100]); setBackClosure(100); setLeftClosure(100); setRightClosure(100); } else if (cond === 'cond2') { setBackRange([0, 100]); setBackClosure(100); setLeftClosure(0); setRightClosure(0); } else if (cond === 'cond3') { setBackRange([0, 0]); setBackClosure(0); setLeftClosure(100); setRightClosure(100); } else if (cond === 'cond4') { setBackRange([0, 0]); setBackClosure(0); setLeftClosure(0); setRightClosure(0); } }; const { result, envelope } = useMemo(() => { const input = { condition, depth, width, height, theta, backClosure, backRange, leftClosure, rightClosure, openingPos, numColumns, }; return { result: calculateShelterWind({ ...input, windAngle }, q), envelope: calculateShelterWindAllAngles(input, q), }; }, [condition, q, depth, width, height, theta, backClosure, backRange, leftClosure, rightClosure, openingPos, windAngle, numColumns]); const effAreaRoof = depth * width; const effAreaBack = (width * height) * (backClosure / 100); const effAreaSideTotal = (depth * height) * ((leftClosure + rightClosure) / 100); const gravityForce = (surfaceMass * effAreaRoof * 9.81) / 1000; // in kN const isUpliftCritical = envelope.criticalUp.value > gravityForce; const handleExportPDF = () => { const angleLabel = windAngle === 0 ? '0° (Frontal)' : windAngle === 45 ? '45° (Oblíquo)' : '90° (Lateral)'; const sections: GenericPDFSection[] = [ { title: 'Geometria, Inclinação e Fechamentos do Abrigo', type: 'grid', gridItems: [ { label: 'Comprimento (d / balanço)', value: `${depth.toFixed(1)} m` }, { label: 'Largura (b)', value: `${width.toFixed(1)} m` }, { label: 'Altura do Pilar (h)', value: `${height.toFixed(1)} m` }, { label: 'Inclinação da Cobertura (θ)', value: `${theta}°` }, { label: 'Condição NBR 6123 (Sec. 6.3)', value: condition }, { label: 'Fechamento Parede de Fundo', value: `${backClosure}%` }, { label: 'Fresta Parede de Fundo', value: backRange ? `${backRange[0]}% a ${backRange[1]}%` : 'Sem fresta' }, { label: 'Fechamento Lateral Esq / Dir', value: `${leftClosure}% / ${rightClosure}%` }, ], }, { title: `Coeficientes Aerodinâmicos e Pressões Líquidas - Direção ${angleLabel}`, type: 'grid', gridItems: [ { label: 'Ce Médio (Cobertura)', value: result.cpeTop }, { label: 'Ce Borda (Pico Aerodinâmico)', value: result.cpeEdgeTop }, { label: 'Cpi Inferior (Sobrepressão sob Telhado)', value: result.cpiBottom }, { label: 'Cnf Médio Resultante', value: result.cnfVertical }, { label: 'Cnf Borda Resultante', value: result.cnfEdgeVertical }, { label: 'Cf Parede de Fundo (Tab. 23 / 6)', value: result.cfBack }, { label: 'Cf Paredes Laterais', value: result.cfSide }, ], }, { title: `Pressões Distribuídas por Área de Incidência - Direção ${angleLabel} (kN/m² e kgf/m²)`, type: 'grid', gridItems: [ { label: 'Pressão na Cobertura (Fz / A_telhado)', value: `${(result.forces.fzUp / effAreaRoof).toFixed(2)} kN/m²`, }, { label: 'Pressão na Parede Traseira (Fx / A_fundo)', value: effAreaBack > 0 ? `${(result.forces.fxBack / effAreaBack).toFixed(2)} kN/m²` : '0.00 kN/m² (0% fechado)', }, { label: 'Pressão nas Paredes Laterais (Fy / A_lat)', value: effAreaSideTotal > 0 ? `${(result.forces.fySide / effAreaSideTotal).toFixed(2)} kN/m²` : '0.00 kN/m² (0% fechado)', }, { label: 'Pressão Dinâmica Base do Vento (q)', value: `${q.toFixed(2)} kN/m²`, }, { label: 'Área da Cobertura (Telhado)', value: `${effAreaRoof.toFixed(1)} m² (100%)`, }, { label: 'Áreas Efetivas Parede Fundo / Laterais', value: `${effAreaBack.toFixed(1)} m² (${backClosure}%) / ${effAreaSideTotal.toFixed(1)} m² (Esq ${leftClosure}% + Dir ${rightClosure}%)`, }, ], }, { title: `Demonstração dos Passos Matemáticos — Pressões Distribuídas por m² (Direção ${angleLabel})`, type: 'math-card', mathSteps: [ { title: '1. Pressão na Cobertura (Fz / A_telhado)', formula: 'p_telhado = q · |Cnf_vertical| ou p_telhado = Fz / (d · b)', calculation: `${q.toFixed(2)} kN/m² · |${result.cnfVertical}| = ${(result.forces.fzUp / effAreaRoof).toFixed(2)} kN/m² (onde A_telhado = ${depth.toFixed(1)}m × ${width.toFixed(1)}m = ${effAreaRoof.toFixed(1)}m²)`, result: `${(result.forces.fzUp / effAreaRoof).toFixed(2)} kN/m²`, note: 'A solicitação de arrancamento atua uniformemente distribuída na projeção horizontal da cobertura.', }, { title: '2. Pressão na Parede Traseira (Fx / A_efetiva,fundo)', formula: 'p_fundo = q · Cf_parede ou p_fundo = Fx / [ (b · h) · (φ_fundo) ]', calculation: effAreaBack > 0 ? `${q.toFixed(2)} kN/m² · ${result.cfBack} = ${(result.forces.fxBack / effAreaBack).toFixed(2)} kN/m² (área de incidência sólida = ${effAreaBack.toFixed(1)}m² para ${backClosure}% fechado)` : `Parede 0% fechada (Sem fechamento traseiro) -> A_efetiva = 0.0 m² e Fx = 0.00 kN`, result: effAreaBack > 0 ? `${(result.forces.fxBack / effAreaBack).toFixed(2)} kN/m²` : '0.00 kN/m² (0% fechado)', note: 'O coeficiente de força e a área são proporcionais à taxa de fechamento da parede de fundo.', }, { title: '3. Pressão nas Paredes Laterais (Fy / A_efetiva,laterais)', formula: 'p_lateral = q · Cf_lateral ou p_lateral = Fy / [ 2 · (d · h) · (φ_médio) ]', calculation: effAreaSideTotal > 0 ? `${q.toFixed(2)} kN/m² · ${result.cfSide} = ${(result.forces.fySide / effAreaSideTotal).toFixed(2)} kN/m² (área efetiva = ${effAreaSideTotal.toFixed(1)}m²)` : `Sem paredes laterais selecionadas (0% esq + 0% dir) -> A_efetiva = 0.0 m² e Fy = 0.00 kN`, result: effAreaSideTotal > 0 ? `${(result.forces.fySide / effAreaSideTotal).toFixed(2)} kN/m²` : '0.00 kN/m² (0% fechado)', note: effAreaSideTotal > 0 ? 'A solicitação lateral é distribuída sobre a área efetiva sólida existente nas paredes esq/dir.' : 'Como nenhuma parede lateral foi adicionada (0%), a área de incidência é nula (0,0 m²) e a pressão atuante é zero.', }, { title: '4. Pressão Dinâmica Base do Vento (q)', formula: 'q = 0,613 · Vk² [N/m²] = 0,000613 · Vk² [kN/m²] (NBR 6123 Sec. 4.2)', calculation: `0,613 · (${Math.sqrt((q * 1000) / 0.613).toFixed(1)} m/s)² / 1000 = ${q.toFixed(2)} kN/m²`, result: `${q.toFixed(2)} kN/m²`, note: 'Pressão dinâmica de referência calculada com base na velocidade característica Vk no nível superior do pilar.', }, ], }, { title: 'Envoltória e Comparativo Normativo — As 3 Incidências de Vento (0° • 45° • 90°)', type: 'table', tableHeaders: ['Parâmetro / Força', '0° (Frontal)', '45° (Oblíquo)', '90° (Lateral)', 'Envoltória / Crítico'], tableRows: [ [ 'Ce Superior (Cobertura)', String(envelope.res0.cpeTop), String(envelope.res45.cpeTop), String(envelope.res90.cpeTop), `Máx: ${Math.min(envelope.res0.cpeTop, envelope.res45.cpeTop, envelope.res90.cpeTop)} (Sucção)` ], [ 'Cpi Inferior (Sob Telhado)', String(envelope.res0.cpiBottom), String(envelope.res45.cpiBottom), String(envelope.res90.cpiBottom), `Máx: +${Math.max(envelope.res0.cpiBottom, envelope.res45.cpiBottom, envelope.res90.cpiBottom).toFixed(2)}` ], [ 'Cnf Vertical Médio | Borda', `${envelope.res0.cnfVertical} | ${envelope.res0.cnfEdgeVertical}`, `${envelope.res45.cnfVertical} | ${envelope.res45.cnfEdgeVertical}`, `${envelope.res90.cnfVertical} | ${envelope.res90.cnfEdgeVertical}`, `Crítico Borda: ${Math.min(envelope.res0.cnfEdgeVertical, envelope.res45.cnfEdgeVertical, envelope.res90.cnfEdgeVertical)}` ], [ 'Força Vertical Telhado [Fz ↑]', `${envelope.res0.forces.fzUp} kN`, `${envelope.res45.forces.fzUp} kN`, `${envelope.res90.forces.fzUp} kN`, `${envelope.criticalUp.value} kN (${envelope.criticalUp.angle}°)` ], [ 'Empuxo Parede Traseira [Fx →]', `${envelope.res0.forces.fxBack} kN`, `${envelope.res45.forces.fxBack} kN`, `${envelope.res90.forces.fxBack} kN`, `${envelope.criticalFx.value} kN (${envelope.criticalFx.angle}°)` ], [ 'Empuxo Paredes Laterais [Fy ↗]', `${envelope.res0.forces.fySide} kN`, `${envelope.res45.forces.fySide} kN`, `${envelope.res90.forces.fySide} kN`, `${envelope.criticalFy.value} kN (${envelope.criticalFy.angle}°)` ], [ ' ↳ Pressão Cobertura (kN/m²)', `${(envelope.res0.forces.fzUp / effAreaRoof).toFixed(2)} kN/m²`, `${(envelope.res45.forces.fzUp / effAreaRoof).toFixed(2)} kN/m²`, `${(envelope.res90.forces.fzUp / effAreaRoof).toFixed(2)} kN/m²`, `${(envelope.criticalUp.value / effAreaRoof).toFixed(2)} kN/m² (${envelope.criticalUp.angle}°)` ], [ ' ↳ Pressão Parede Fundo (kN/m²)', effAreaBack > 0 ? `${(envelope.res0.forces.fxBack / effAreaBack).toFixed(2)} kN/m²` : '0.00 kN/m²', effAreaBack > 0 ? `${(envelope.res45.forces.fxBack / effAreaBack).toFixed(2)} kN/m²` : '0.00 kN/m²', effAreaBack > 0 ? `${(envelope.res90.forces.fxBack / effAreaBack).toFixed(2)} kN/m²` : '0.00 kN/m²', effAreaBack > 0 ? `${(envelope.criticalFx.value / effAreaBack).toFixed(2)} kN/m² (${envelope.criticalFx.angle}°)` : '0.00 kN/m²' ], [ ' ↳ Pressão Paredes Lat. (kN/m²)', effAreaSideTotal > 0 ? `${(envelope.res0.forces.fySide / effAreaSideTotal).toFixed(2)} kN/m²` : '0.00 kN/m²', effAreaSideTotal > 0 ? `${(envelope.res45.forces.fySide / effAreaSideTotal).toFixed(2)} kN/m²` : '0.00 kN/m²', effAreaSideTotal > 0 ? `${(envelope.res90.forces.fySide / effAreaSideTotal).toFixed(2)} kN/m²` : '0.00 kN/m²', effAreaSideTotal > 0 ? `${(envelope.criticalFy.value / effAreaSideTotal).toFixed(2)} kN/m² (${envelope.criticalFy.angle}°)` : '0.00 kN/m²' ], [ 'Carga Horiz. no Pilar', `${envelope.res0.lineLoads.columnLoad} kN/m`, `${envelope.res45.lineLoads.columnLoad} kN/m`, `${envelope.res90.lineLoads.columnLoad} kN/m`, `${envelope.criticalColumnLoad.value} kN/m (${envelope.criticalColumnLoad.angle}°)` ], [ 'Carga Vert. na Viga', `${envelope.res0.lineLoads.beamLoad} kN/m`, `${envelope.res45.lineLoads.beamLoad} kN/m`, `${envelope.res90.lineLoads.beamLoad} kN/m`, `${Math.max(envelope.res0.lineLoads.beamLoad, envelope.res45.lineLoads.beamLoad, envelope.res90.lineLoads.beamLoad).toFixed(2)} kN/m` ], [ 'Momento na Raiz da Viga', `${envelope.res0.lineLoads.beamMoment} kN.m`, `${envelope.res45.lineLoads.beamMoment} kN.m`, `${envelope.res90.lineLoads.beamMoment} kN.m`, `${Math.max(envelope.res0.lineLoads.beamMoment, envelope.res45.lineLoads.beamMoment, envelope.res90.lineLoads.beamMoment).toFixed(2)} kN.m` ], ], }, { title: `Forças Resultantes no Pórtico (${angleLabel}) (kN)`, type: 'grid', gridItems: [ { label: 'Força Vertical no Telhado [Fz ↑]', value: `${result.forces.fzUp} kN` }, { label: 'Empuxo na Parede Traseira [Fx →]', value: `${result.forces.fxBack} kN` }, { label: 'Empuxo nas Paredes Laterais [Fy ↗]', value: `${result.forces.fySide} kN` }, { label: 'Força de Atrito no Telhado [F_atrito]', value: `${result.forces.fFriction} kN` }, ], }, { title: `Cargas Lineares para Dimensionamento (${angleLabel}) (kN/m)`, type: 'grid', gridItems: [ { label: 'Carga Horiz. Pórtico Central', value: `${result.lineLoads.columnLoad} kN/m` }, { label: 'Carga Horiz. Extremidade', value: `${result.lineLoads.columnLoadEdge} kN/m` }, { label: 'Carga Vert. Média Viga Central', value: `${result.lineLoads.beamLoad} kN/m` }, { label: 'Carga Vert. Média Extremidade', value: `${result.lineLoads.beamLoadEdge} kN/m` }, { label: 'Momento Engaste Viga Central', value: `${result.lineLoads.beamMoment} kN.m` }, { label: 'Momento Engaste Extremidade', value: `${result.lineLoads.beamMomentEdge} kN.m` }, ], }, { title: 'Parecer Técnico e Alertas Aerodinâmicos (Zonas de Borda)', type: 'text', content: `${result.statusText} Permeabilidade líquida da parede de fundo: ${100 - backClosure}%. Alívio de arrancamento obtido pela fresta superior: ${result.reliefPercentage}%. ⚠️ ATENÇÃO ESTRUTURAL (Efeito Asa de Avião): O coeficiente global médio subestima a força de arrancamento na ponta do balanço. Os cálculos acima consideram as zonas de borda com coeficientes extremos (Cnf Borda = ${result.cnfEdgeVertical}). O Momento Fletor na raiz da viga foi calculado considerando que o centro de pressão está deslocado para próximo à extremidade livre (L/3), o que resulta num momento de engaste substancialmente maior que o de uma carga uniformemente distribuída simples.`, }, { title: 'Guia de Aplicação dos Eixos e Resultantes no Croqui', type: 'table', tableHeaders: ['Eixo / Componente', 'Símbolo', 'Sentido e Aplicação no Croqui', 'Carga Distribuída'], tableRows: [ [ 'Eixo Z (Vertical)', 'Fz (↑)', 'Perpendicular ao telhado. Valor (+) indica sucção para cima (arrancamento); (-) indica carga descendente.', `${result.lineLoads.beamLoad} kN/m na viga` ], [ 'Eixo X (Longitudinal)', 'Fx (→)', 'Na direção do vento (frente -> fundo). Atua como empuxo horizontal contra a parede traseira.', `${result.lineLoads.columnLoad} kN/m no pilar` ], [ 'Eixo Y (Transversal)', 'Fy (↗)', 'Perpendicular ao vento. Atua horizontalmente contra o fechamento das paredes laterais.', '—' ], ], }, ]; exportGenericToPDF('Abrigo / Pórtico Fechado', sections); }; return (
{/* Coluna Esquerda: Controles do Abrigo */}
Abrigos e Pórticos Pórticos em balanço (Tab. 23-25 e sec. 6.3).
{(['cond1', 'cond2', 'cond3', 'cond4'] as ShelterCondition[]).map((c) => ( ))}
{([0, 45, 90] as ShelterWindAngle[]).map((ang) => ( ))}
Parede de Fundo: {backClosure}% {backRange[0] > 0 || backRange[1] < 100 ? `(Base ${backRange[0]}% | Topo ${100 - backRange[1]}%)` : ''}
{ if (Array.isArray(val) && val.length === 2) { const [start, end] = val; if (end >= start) { setBackRange([start, end]); setBackClosure(end - start); } } }} />
Lateral Esq: {leftClosure}%
setLeftClosure(v[0])} />
Lateral Dir: {rightClosure}%
setRightClosure(v[0])} />
Vão do Balanço (d): {depth.toFixed(1)} m
setDepth(v[0])} />
Altura do Pilar (h): {height.toFixed(1)} m
setHeight(v[0])} />
Largura do Abrigo (b): {width.toFixed(1)} m
setWidth(v[0])} />
Inclinação Cobertura (θ): {theta}°
setTheta(v[0])} />
Número de Pórticos (Pilares): {numColumns} pórticos
setNumColumns(v[0])} />
Massa Superficial (kg/m²): {surfaceMass} kg/m²
setSurfaceMass(v[0])} />

Lonas ~3kg/m², Telhas Metálicas ~10-15kg/m²

{isUpliftCritical && (

Alerta de Arrancamento: Força (↑) {envelope.criticalUp.value.toFixed(1)} kN > Peso ({gravityForce.toFixed(1)} kN). Exige ancoragem/estaiamento.

)}
Vento: {windAngle}° ({windAngle === 0 ? 'Frontal' : windAngle === 45 ? 'Oblíquo' : 'Lateral'}) θ = {theta}° Fundo: {backClosure}% ({openingPos === 'top' ? 'Fresta Topo' : openingPos === 'bottom' ? 'Vão Base' : 'Distrib.'}) {result.reliefPercentage > 0 && ( Alívio Arrancamento: -{result.reliefPercentage}% )}
{viewMode === '3d' || viewMode === 'airflow' ? ( ) : (
)}
Forças ({windAngle}°) {result.forces.fzUp.toFixed(1)} kN (Arrancamento)
F. Vertical [Fz ↑ - Cobertura] {result.forces.fzUp.toFixed(2)} kN
Cnf Médio | Cnf Borda {result.cnfVertical} | {result.cnfEdgeVertical}
Pressão (/m²) {(result.forces.fzUp / effAreaRoof).toFixed(2)} kN/m² ({(result.forces.fzUp / effAreaRoof * 101.97).toFixed(1)} kgf/m²)
Empuxo Traseiro [Fx → - Parede] {result.forces.fxBack.toFixed(2)} kN
Cf / Estanqueidade Cf = {result.cfBack} ({backClosure}%)
Pressão (/m²) {effAreaBack > 0 ? `${(result.forces.fxBack / effAreaBack).toFixed(2)} kN/m² (${(result.forces.fxBack / effAreaBack * 101.97).toFixed(1)} kgf/m²)` : '0.00 kN/m² (0% fechado)'}
Empuxo Lateral [Fy ↗ - Paredes] {result.forces.fySide.toFixed(2)} kN
Pressão (/m²) {effAreaSideTotal > 0 ? `${(result.forces.fySide / effAreaSideTotal).toFixed(2)} kN/m² (${(result.forces.fySide / effAreaSideTotal * 101.97).toFixed(1)} kgf/m²)` : '0.00 kN/m² (0% fechado)'}
Carga no Pilar (Central) {result.lineLoads.columnLoad.toFixed(2)} kN/m
Carga Vertical Viga (Central) {result.lineLoads.beamLoad.toFixed(2)} kN/m
Momento Engaste (Asa) {result.lineLoads.beamMoment.toFixed(2)} kN.m
Envoltória — 3 Incidências (0° • 45° • 90°) Crítico: {envelope.criticalUp.angle}°
Direção
Fz (↑)
Fx (→)
Fy (↗)
0° Frontal
{envelope.res0.forces.fzUp.toFixed(1)}
{envelope.res0.forces.fxBack.toFixed(1)}
{envelope.res0.forces.fySide.toFixed(1)}
45° Oblíquo
{envelope.res45.forces.fzUp.toFixed(1)}
{envelope.res45.forces.fxBack.toFixed(1)}
{envelope.res45.forces.fySide.toFixed(1)}
90° Lateral
{envelope.res90.forces.fzUp.toFixed(1)}
{envelope.res90.forces.fxBack.toFixed(1)}
{envelope.res90.forces.fySide.toFixed(1)}
Parâmetros Adicionais (NBR 6123)
Permeabilidade (μ): {100 - backClosure}%
Alívio por Fresta Superior: {result.reliefPercentage}%
Força de Atrito (Ff): {result.forces.fFriction.toFixed(2)} kN

* Para a visualização didática dos esquemas aerodinâmicos e linhas de corrente, utilize a aba Corte A-A no painel central.

); }; export default ShelterModule;