🚀 Auto-deploy: BrainWind atualizado em 13/07/2026 18:36:44
This commit is contained in:
+181
-181
@@ -115,9 +115,108 @@ const PiperackModule: React.FC = () => {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="flex-1 overflow-hidden grid lg:grid-cols-[1fr_400px]">
|
||||
{/* Painel Esquerdo: 3D */}
|
||||
<div className="relative min-h-[400px] lg:min-h-0 bg-muted/30">
|
||||
<div className="flex-1 flex flex-col lg:flex-row p-4 gap-4 overflow-hidden bg-muted/30">
|
||||
|
||||
{/* Coluna Esquerda: Entradas */}
|
||||
<div className="w-full lg:w-80 shrink-0 overflow-y-auto bg-card rounded-xl border border-border shadow-sm p-5 space-y-6">
|
||||
<div>
|
||||
<h3 className="font-medium mb-4">Geometria da Estrutura</h3>
|
||||
<div className="space-y-5">
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Largura (b)</span>
|
||||
<span className="text-sm text-muted-foreground">{width} m</span>
|
||||
</div>
|
||||
<Slider value={[width]} min={2} max={25} step={0.5} onValueChange={v => setWidth(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Altura do pórtico (h)</span>
|
||||
<span className="text-sm text-muted-foreground">{height} m</span>
|
||||
</div>
|
||||
<Slider value={[height]} min={0.5} max={5} step={0.1} onValueChange={v => setHeight(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Elevação (z)</span>
|
||||
<span className="text-sm text-muted-foreground">{elevation} m</span>
|
||||
</div>
|
||||
<Slider value={[elevation]} min={2} max={25} step={1} onValueChange={v => setElevation(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Espaçamento (e)</span>
|
||||
<span className="text-sm text-muted-foreground">{spacing} m</span>
|
||||
</div>
|
||||
<Slider value={[spacing]} min={0.5} max={5} step={0.5} onValueChange={v => setSpacing(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Número de Pórticos (n)</span>
|
||||
<span className="text-sm text-muted-foreground">{numFrames}</span>
|
||||
</div>
|
||||
<Slider value={[numFrames]} min={1} max={5} step={1} onValueChange={v => setNumFrames(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium">Índice de Solidez (φ str)</span>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Info className="w-4 h-4 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" className="max-w-xs">
|
||||
<p>O índice de solidez (φ) representa a relação entre a área efetivamente bloqueada pelos perfis do reticulado e a área total contornada pelo pórtico. Quanto mais "fechado" for o pórtico estrutural, maior o arrasto aerodinâmico (ref. Tabela 28 da NBR 6123).</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
<span className="text-sm text-muted-foreground">{phiStruct.toFixed(2)}</span>
|
||||
</div>
|
||||
<Slider value={[phiStruct]} min={0.1} max={0.6} step={0.05} onValueChange={v => setPhiStruct(v[0])} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-medium">Tubulações (Bloqueio)</h3>
|
||||
<Button variant="outline" size="sm" onClick={addPipe} className="h-7 text-xs">
|
||||
<Plus className="w-3 h-3 mr-1" /> Adicionar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{pipes.length === 0 ? (
|
||||
<div className="text-center p-4 border border-dashed rounded-lg text-sm text-muted-foreground">
|
||||
Nenhuma tubulação adicionada.
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{pipes.map((pipe, index) => (
|
||||
<div key={pipe.id} className="flex items-center gap-2 p-2 rounded-md border bg-muted/20">
|
||||
<label className="w-20 text-xs text-muted-foreground shrink-0">Tubo {index + 1}</label>
|
||||
<Input
|
||||
type="number"
|
||||
value={pipe.diameter}
|
||||
onChange={(e) => updatePipe(pipe.id, Number(e.target.value))}
|
||||
step={0.1}
|
||||
min={0.1}
|
||||
className="h-7 text-xs font-mono"
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">m</span>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 text-destructive shrink-0" onClick={() => removePipe(pipe.id)}>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Coluna Central: 3D */}
|
||||
<div className="flex-1 flex flex-col min-h-[500px] lg:min-h-0 bg-background rounded-xl border border-border shadow-sm overflow-hidden relative">
|
||||
<Piperack3D
|
||||
width={width}
|
||||
height={height}
|
||||
@@ -130,193 +229,94 @@ const PiperackModule: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Painel Direito: Controles */}
|
||||
<div className="flex flex-col border-l bg-card overflow-y-auto">
|
||||
<div className="p-6 space-y-8">
|
||||
<Card className="shadow-none border-primary/20">
|
||||
<CardHeader className="pb-4">
|
||||
<CardTitle className="text-base flex items-center justify-between">
|
||||
Forças Calculadas
|
||||
<Badge variant="secondary" className="font-mono">{result.globalForce.toFixed(1)} kN (Global)</Badge>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4 text-sm">
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground">φ efetivo</span>
|
||||
<span className="font-mono font-medium">{result.phiTotal.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground">Ca frontal (Tab. 26 adaptada)</span>
|
||||
<span className="font-mono font-medium">{result.caFrontal.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground">Fator η (Tab. 28)</span>
|
||||
<span className="font-mono font-medium">{result.eta.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground text-primary font-medium">Carga Pórtico 1</span>
|
||||
<span className="font-mono font-bold text-primary">{result.linearLoadFront.toFixed(2)} kN/m</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-4 border-b">
|
||||
<span className="text-muted-foreground text-primary font-medium">Carga Pórticos {numFrames > 1 ? `2 a ${numFrames}` : '-'}</span>
|
||||
<span className="font-mono font-bold text-primary">{result.linearLoadBack.toFixed(2)} kN/m</span>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<h4 className="font-semibold text-sm mb-3">Reações Simplificadas nas Bases</h4>
|
||||
<div className="bg-muted/30 p-3 rounded-md border text-xs space-y-4">
|
||||
{/* Coluna Direita: Resultados */}
|
||||
<div className="w-full lg:w-96 shrink-0 flex flex-col gap-4 overflow-y-auto pb-8 lg:pb-0">
|
||||
<Card className="shadow-sm border-border">
|
||||
<CardHeader className="pb-4">
|
||||
<CardTitle className="text-base flex items-center justify-between">
|
||||
Forças Calculadas
|
||||
<Badge variant="secondary" className="font-mono">{result.globalForce.toFixed(1)} kN (Global)</Badge>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4 text-sm">
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground">φ efetivo</span>
|
||||
<span className="font-mono font-medium">{result.phiTotal.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground">Ca frontal (Tab. 26 adaptada)</span>
|
||||
<span className="font-mono font-medium">{result.caFrontal.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground">Fator η (Tab. 28)</span>
|
||||
<span className="font-mono font-medium">{result.eta.toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-2 border-b">
|
||||
<span className="text-muted-foreground text-primary font-medium">Carga Pórtico 1</span>
|
||||
<span className="font-mono font-bold text-primary">{result.linearLoadFront.toFixed(2)} kN/m</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center pb-4 border-b">
|
||||
<span className="text-muted-foreground text-primary font-medium">Carga Pórticos {numFrames > 1 ? `2 a ${numFrames}` : '-'}</span>
|
||||
<span className="font-mono font-bold text-primary">{result.linearLoadBack.toFixed(2)} kN/m</span>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<h4 className="font-semibold text-sm mb-3">Reações Simplificadas nas Bases</h4>
|
||||
<div className="bg-muted/30 p-3 rounded-md border text-xs space-y-4">
|
||||
|
||||
<svg width="100%" height="120" viewBox="0 0 300 120" className="bg-white rounded border">
|
||||
<line x1="20" y1="100" x2="280" y2="100" stroke="#cbd5e1" strokeWidth="2" />
|
||||
|
||||
<svg width="100%" height="120" viewBox="0 0 300 120" className="bg-white rounded border">
|
||||
<line x1="20" y1="100" x2="280" y2="100" stroke="#cbd5e1" strokeWidth="2" />
|
||||
|
||||
<rect x="80" y="30" width="8" height="70" fill="#64748b" />
|
||||
<text x="84" y="115" textAnchor="middle" fontSize="10" fill="#475569">C1 (Barlavento)</text>
|
||||
<line x1="70" y1="100" x2="70" y2="70" stroke="#ef4444" strokeWidth="2" markerEnd="url(#arrowUp)" />
|
||||
<text x="65" y="85" textAnchor="end" fill="#ef4444" fontSize="10">Tração</text>
|
||||
<rect x="80" y="30" width="8" height="70" fill="#64748b" />
|
||||
<text x="84" y="115" textAnchor="middle" fontSize="10" fill="#475569">C1 (Barlavento)</text>
|
||||
<line x1="70" y1="100" x2="70" y2="70" stroke="#ef4444" strokeWidth="2" markerEnd="url(#arrowUp)" />
|
||||
<text x="65" y="85" textAnchor="end" fill="#ef4444" fontSize="10">Tração</text>
|
||||
|
||||
<rect x="212" y="30" width="8" height="70" fill="#64748b" />
|
||||
<text x="216" y="115" textAnchor="middle" fontSize="10" fill="#475569">C2 (Sotavento)</text>
|
||||
<line x1="225" y1="70" x2="225" y2="100" stroke="#3b82f6" strokeWidth="2" markerEnd="url(#arrowDown)" />
|
||||
<text x="230" y="85" textAnchor="start" fill="#3b82f6" fontSize="10">Comp.</text>
|
||||
<rect x="212" y="30" width="8" height="70" fill="#64748b" />
|
||||
<text x="216" y="115" textAnchor="middle" fontSize="10" fill="#475569">C2 (Sotavento)</text>
|
||||
<line x1="225" y1="70" x2="225" y2="100" stroke="#3b82f6" strokeWidth="2" markerEnd="url(#arrowDown)" />
|
||||
<text x="230" y="85" textAnchor="start" fill="#3b82f6" fontSize="10">Comp.</text>
|
||||
|
||||
<rect x="76" y="30" width="148" height="10" fill="#64748b" />
|
||||
|
||||
<line x1="20" y1="35" x2="75" y2="35" stroke="#10b981" strokeWidth="2" markerEnd="url(#arrowRight)" />
|
||||
<text x="45" y="30" textAnchor="middle" fill="#10b981" fontSize="10">Vento (F)</text>
|
||||
|
||||
<defs>
|
||||
<marker id="arrowUp" markerWidth="6" markerHeight="6" refX="3" refY="0" orient="auto">
|
||||
<path d="M0,6 L3,0 L6,6" fill="none" stroke="#ef4444" strokeWidth="1.5" />
|
||||
</marker>
|
||||
<marker id="arrowDown" markerWidth="6" markerHeight="6" refX="3" refY="6" orient="auto">
|
||||
<path d="M0,0 L3,6 L6,0" fill="none" stroke="#3b82f6" strokeWidth="1.5" />
|
||||
</marker>
|
||||
<marker id="arrowRight" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto">
|
||||
<path d="M0,0 L6,3 L0,6" fill="none" stroke="#10b981" strokeWidth="1.5" />
|
||||
</marker>
|
||||
</defs>
|
||||
</svg>
|
||||
<rect x="76" y="30" width="148" height="10" fill="#64748b" />
|
||||
|
||||
<line x1="20" y1="35" x2="75" y2="35" stroke="#10b981" strokeWidth="2" markerEnd="url(#arrowRight)" />
|
||||
<text x="45" y="30" textAnchor="middle" fill="#10b981" fontSize="10">Vento (F)</text>
|
||||
|
||||
<defs>
|
||||
<marker id="arrowUp" markerWidth="6" markerHeight="6" refX="3" refY="0" orient="auto">
|
||||
<path d="M0,6 L3,0 L6,6" fill="none" stroke="#ef4444" strokeWidth="1.5" />
|
||||
</marker>
|
||||
<marker id="arrowDown" markerWidth="6" markerHeight="6" refX="3" refY="6" orient="auto">
|
||||
<path d="M0,0 L3,6 L6,0" fill="none" stroke="#3b82f6" strokeWidth="1.5" />
|
||||
</marker>
|
||||
<marker id="arrowRight" markerWidth="6" markerHeight="6" refX="6" refY="3" orient="auto">
|
||||
<path d="M0,0 L6,3 L0,6" fill="none" stroke="#10b981" strokeWidth="1.5" />
|
||||
</marker>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-1">
|
||||
<div className="font-bold text-primary">Pórtico Frontal</div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>F (Transv.):</span> <span className="font-mono">{(result.linearLoadFront * width).toFixed(2)} kN</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Momento:</span> <span className="font-mono">{(result.linearLoadFront * width * elevation).toFixed(2)} kN·m</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Reação (C1/C2):</span> <span className="font-mono">±{((result.linearLoadFront * width * elevation) / spacing).toFixed(2)} kN</span></div>
|
||||
</div>
|
||||
{numFrames > 1 && (
|
||||
<div className="space-y-1">
|
||||
<div className="font-bold text-primary">Pórtico Frontal</div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>F (Transv.):</span> <span className="font-mono">{(result.linearLoadFront * width).toFixed(2)} kN</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Momento:</span> <span className="font-mono">{(result.linearLoadFront * width * elevation).toFixed(2)} kN·m</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Reação (C1/C2):</span> <span className="font-mono">±{((result.linearLoadFront * width * elevation) / spacing).toFixed(2)} kN</span></div>
|
||||
<div className="font-bold text-primary">Pórticos Traseiros</div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>F (Transv.):</span> <span className="font-mono">{(result.linearLoadBack * width).toFixed(2)} kN</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Momento:</span> <span className="font-mono">{(result.linearLoadBack * width * elevation).toFixed(2)} kN·m</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Reação (C1/C2):</span> <span className="font-mono">±{((result.linearLoadBack * width * elevation) / spacing).toFixed(2)} kN</span></div>
|
||||
</div>
|
||||
{numFrames > 1 && (
|
||||
<div className="space-y-1">
|
||||
<div className="font-bold text-primary">Pórticos Traseiros</div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>F (Transv.):</span> <span className="font-mono">{(result.linearLoadBack * width).toFixed(2)} kN</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Momento:</span> <span className="font-mono">{(result.linearLoadBack * width * elevation).toFixed(2)} kN·m</span></div>
|
||||
<div className="flex justify-between text-muted-foreground"><span>Reação (C1/C2):</span> <span className="font-mono">±{((result.linearLoadBack * width * elevation) / spacing).toFixed(2)} kN</span></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="font-medium mb-4">Geometria da Estrutura</h3>
|
||||
<div className="space-y-5">
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Largura (b)</span>
|
||||
<span className="text-sm text-muted-foreground">{width} m</span>
|
||||
</div>
|
||||
<Slider value={[width]} min={2} max={25} step={0.5} onValueChange={v => setWidth(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Altura do pórtico (h)</span>
|
||||
<span className="text-sm text-muted-foreground">{height} m</span>
|
||||
</div>
|
||||
<Slider value={[height]} min={0.5} max={5} step={0.1} onValueChange={v => setHeight(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Elevação (z)</span>
|
||||
<span className="text-sm text-muted-foreground">{elevation} m</span>
|
||||
</div>
|
||||
<Slider value={[elevation]} min={2} max={25} step={1} onValueChange={v => setElevation(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Espaçamento (e)</span>
|
||||
<span className="text-sm text-muted-foreground">{spacing} m</span>
|
||||
</div>
|
||||
<Slider value={[spacing]} min={0.5} max={5} step={0.5} onValueChange={v => setSpacing(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-sm font-medium">Número de Pórticos (n)</span>
|
||||
<span className="text-sm text-muted-foreground">{numFrames}</span>
|
||||
</div>
|
||||
<Slider value={[numFrames]} min={1} max={5} step={1} onValueChange={v => setNumFrames(v[0])} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium">Índice de Solidez (φ str)</span>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Info className="w-4 h-4 text-muted-foreground cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" className="max-w-xs">
|
||||
<p>O índice de solidez (φ) representa a relação entre a área efetivamente bloqueada pelos perfis do reticulado e a área total contornada pelo pórtico. Quanto mais "fechado" for o pórtico estrutural, maior o arrasto aerodinâmico (ref. Tabela 28 da NBR 6123).</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
<span className="text-sm text-muted-foreground">{phiStruct.toFixed(2)}</span>
|
||||
</div>
|
||||
<Slider value={[phiStruct]} min={0.1} max={0.6} step={0.05} onValueChange={v => setPhiStruct(v[0])} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-medium">Tubulações (Bloqueio)</h3>
|
||||
<Button variant="outline" size="sm" onClick={addPipe} className="h-7 text-xs">
|
||||
<Plus className="w-3 h-3 mr-1" /> Adicionar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{pipes.length === 0 ? (
|
||||
<div className="text-center p-4 border border-dashed rounded-lg text-sm text-muted-foreground">
|
||||
Nenhuma tubulação adicionada.
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{pipes.map((pipe, index) => (
|
||||
<div key={pipe.id} className="flex items-center gap-2 p-2 rounded-md border bg-muted/20">
|
||||
<label className="w-20 text-xs text-muted-foreground shrink-0">Tubo {index + 1}</label>
|
||||
<Input
|
||||
type="number"
|
||||
value={pipe.diameter}
|
||||
onChange={(e) => updatePipe(pipe.id, Number(e.target.value))}
|
||||
step={0.1}
|
||||
min={0.1}
|
||||
className="h-7 text-xs font-mono"
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">m</span>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 text-destructive shrink-0" onClick={() => removePipe(pipe.id)}>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SceneCapturePanel />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<SceneCapturePanel />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user