Files
SteelBase/ORIGINAL/calculations.js

909 lines
38 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ========================================
// CONTINUATION OF CALCULATION FUNCTIONS
// ========================================
// Bolts Calculation
function calcularParafusos() {
const fy = parseFloat(document.getElementById('bolt-type').value) || 400;
const d = parseFloat(document.getElementById('bolt-d').value) || 20;
const qty = parseInt(document.getElementById('bolt-qty').value) || 1;
const planes = parseInt(document.getElementById('bolt-planes').value) || 1;
const force = parseFloat(document.getElementById('bolt-force').value) || 0;
const area = Math.PI * Math.pow(d / 2, 2);
const Fv = 0.6 * fy * area * planes / 1000;
const capacity = Fv * qty;
const utilization = (force / capacity) * 100;
let alertClass = 'alert-success';
let status = '✅ OK - Capacidade adequada';
if (utilization > 100) {
alertClass = 'alert-error';
status = '❌ FALHA - Capacidade insuficiente';
} else if (utilization > 80) {
alertClass = 'alert-warning';
status = '⚠️ ATENÇÃO - Utilização elevada';
}
document.getElementById('bolt-result').innerHTML = `
<div class="result-box">
<div class="result-title">Verificação ao Cisalhamento</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Área Parafuso</div>
<div class="result-value">${area.toFixed(0)} mm²</div>
</div>
<div class="result-item">
<div class="result-label">Fv por Parafuso</div>
<div class="result-value">${Fv.toFixed(1)} kN</div>
</div>
<div class="result-item">
<div class="result-label">Capacidade Total</div>
<div class="result-value">${capacity.toFixed(1)} kN</div>
</div>
<div class="result-item">
<div class="result-label">Utilização</div>
<div class="result-value">${utilization.toFixed(1)}%</div>
</div>
</div>
<div class="alert ${alertClass}" style="margin-top: 16px;">
<strong>${status}</strong>
</div>
</div>
`;
addToHistory('Ligações Parafusadas', `${qty} parafusos Ø${d}mm, Utilização = ${utilization.toFixed(1)}%`);
}
// Layout Verification
function verificarLayout() {
const d = parseFloat(document.getElementById('layout-d').value) || 20;
const edge = parseFloat(document.getElementById('layout-edge').value) || 0;
const spacing = parseFloat(document.getElementById('layout-spacing').value) || 0;
const minEdge = 1.5 * d;
const maxEdge = 12 * 10;
const minSpacing = 2.67 * d;
const maxSpacing = 300;
let edgeStatus = '✅ Conforme';
let edgeClass = 'alert-success';
if (edge < minEdge) {
edgeStatus = `❌ Abaixo do mínimo (${minEdge.toFixed(1)}mm)`;
edgeClass = 'alert-error';
} else if (edge > maxEdge) {
edgeStatus = `⚠️ Acima do máximo (${maxEdge}mm)`;
edgeClass = 'alert-warning';
}
let spacingStatus = '✅ Conforme';
let spacingClass = 'alert-success';
if (spacing < minSpacing) {
spacingStatus = `❌ Abaixo do mínimo (${minSpacing.toFixed(1)}mm)`;
spacingClass = 'alert-error';
} else if (spacing > maxSpacing) {
spacingStatus = `⚠️ Acima do máximo (${maxSpacing}mm)`;
spacingClass = 'alert-warning';
}
document.getElementById('layout-result').innerHTML = `
<div class="card">
<div class="card-title">Verificação NBR 8800</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Dist. Borda Mín</div>
<div class="result-value" style="font-size: 18px;">${minEdge.toFixed(1)} mm</div>
</div>
<div class="result-item">
<div class="result-label">Dist. Borda Máx</div>
<div class="result-value" style="font-size: 18px;">${maxEdge} mm</div>
</div>
<div class="result-item">
<div class="result-label">Espaç. Mínimo</div>
<div class="result-value" style="font-size: 18px;">${minSpacing.toFixed(1)} mm</div>
</div>
<div class="result-item">
<div class="result-label">Espaç. Máximo</div>
<div class="result-value" style="font-size: 18px;">${maxSpacing} mm</div>
</div>
</div>
<div class="alert ${edgeClass}" style="margin-top: 16px;">
<strong>Distância de Borda: ${edgeStatus}</strong>
</div>
<div class="alert ${spacingClass}">
<strong>Espaçamento: ${spacingStatus}</strong>
</div>
</div>
`;
addToHistory('Layout de Furação', `Ø${d}mm, Borda: ${edge}mm, Espaç: ${spacing}mm`);
}
// Bolt vs Weld Comparison
function compararParafusoSolda() {
const force = parseFloat(document.getElementById('comp-force').value) || 0;
const length = parseFloat(document.getElementById('comp-length').value) || 0;
const fy = parseFloat(document.getElementById('comp-fy').value) || 345;
// Parafusos A325 Ø20mm
const boltCapacity = 60;
const boltQty = Math.ceil(force / boltCapacity);
const boltCost = boltQty * 15;
// Solda
const weldLeg = (force * 1000) / (0.707 * length * 0.65 * fy);
const weldLegRounded = Math.ceil(weldLeg);
const weldCost = (weldLegRounded * length / 1000) * 25;
document.getElementById('comparison-result').innerHTML = `
<div class="card">
<div class="card-title">Comparação de Soluções</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div style="background: var(--color-bg-1); padding: 20px; border-radius: 12px;">
<h3 style="color: var(--color-primary); margin-bottom: 16px;">🔩 Solução Parafusada</h3>
<p><strong>Tipo:</strong> A325 Ø20mm</p>
<p><strong>Quantidade:</strong> ${boltQty} parafusos</p>
<p><strong>Capacidade:</strong> ${(boltQty * boltCapacity).toFixed(1)} kN</p>
<p><strong>Custo estimado:</strong> R$ ${boltCost.toFixed(2)}</p>
<p><strong>Vantagens:</strong> Desmontável, inspeção visual</p>
<p><strong>Desvantagens:</strong> Maior tempo de instalação</p>
</div>
<div style="background: var(--color-bg-2); padding: 20px; border-radius: 12px;">
<h3 style="color: var(--color-warning); margin-bottom: 16px;">🔥 Solução Soldada</h3>
<p><strong>Tipo:</strong> Solda de filete</p>
<p><strong>Perna:</strong> ${weldLegRounded} mm</p>
<p><strong>Comprimento:</strong> ${length} mm</p>
<p><strong>Custo estimado:</strong> R$ ${weldCost.toFixed(2)}</p>
<p><strong>Vantagens:</strong> Melhor rigidez, econômica</p>
<p><strong>Desvantagens:</strong> Permanente, requer qualificação</p>
</div>
</div>
<div class="alert alert-success" style="margin-top: 20px;">
<strong>Recomendação:</strong> ${weldCost < boltCost ? 'Solda de filete é mais econômica' : 'Parafusos mais econômicos'}
</div>
</div>
`;
addToHistory('Parafuso vs Solda', `${boltQty} parafusos vs solda ${weldLegRounded}mm`);
}
// Preheat Calculation
function calcularPreaquecimento() {
const cev = parseFloat(document.getElementById('preheat-cev').value) || 0;
const thickness = parseFloat(document.getElementById('preheat-thickness').value) || 0;
const ambient = parseFloat(document.getElementById('preheat-ambient').value) || 20;
const preheatTemp = 50 + (cev * 100) + (thickness / 10 * 20) + ((20 - ambient) / 2);
const maxInterpass = preheatTemp + 100;
let pwhtRecommendation = '';
if (thickness > 50 || cev > 0.60) {
pwhtRecommendation = '⚠️ PWHT (Tratamento Térmico Pós-Soldagem) recomendado';
} else {
pwhtRecommendation = '✅ PWHT não obrigatório';
}
document.getElementById('preheat-result').innerHTML = `
<div class="result-box">
<div class="result-title">Temperatura de Pré-Aquecimento (AWS D1.1)</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Temp. Mínima</div>
<div class="result-value">${Math.round(preheatTemp)}°C</div>
</div>
<div class="result-item">
<div class="result-label">Temp. Interpasse Máx</div>
<div class="result-value">${Math.round(maxInterpass)}°C</div>
</div>
</div>
<div class="alert alert-warning" style="margin-top: 16px;">
<strong>${pwhtRecommendation}</strong>
</div>
<div class="expert-only" style="margin-top: 16px; padding: 16px; background: var(--color-bg-3); border-radius: 8px;">
<strong>Procedimento:</strong><br>
1. Aquecer uniformemente até ${Math.round(preheatTemp)}°C<br>
2. Medir temperatura a 75mm da junta<br>
3. Manter durante toda a soldagem<br>
4. Temperatura interpasse máxima: ${Math.round(maxInterpass)}°C
</div>
</div>
`;
addToHistory('Pré-Aquecimento', `CEV=${cev}, esp=${thickness}mm → ${Math.round(preheatTemp)}°C`);
}
// Weld Fillet Calculation
function calcularSoldaFilete() {
const force = parseFloat(document.getElementById('weld-force').value) || 0;
const length = parseFloat(document.getElementById('weld-length').value) || 0;
const fy = parseFloat(document.getElementById('weld-fy').value) || 345;
const fyWeld = fy * 0.6;
const leg = (force * 1000) / (0.707 * length * 0.65 * fyWeld);
const throat = leg * 0.707;
const legCommercial = Math.ceil(leg);
const passes = legCommercial <= 5 ? 1 : legCommercial <= 8 ? 2 : 3;
document.getElementById('weld-result').innerHTML = `
<div class="result-box">
<div class="result-title">Dimensionamento da Solda de Filete</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Perna Calculada</div>
<div class="result-value">${leg.toFixed(2)} mm</div>
</div>
<div class="result-item">
<div class="result-label">Perna Adotada</div>
<div class="result-value">${legCommercial} mm</div>
</div>
<div class="result-item">
<div class="result-label">Garganta Efetiva</div>
<div class="result-value">${throat.toFixed(2)} mm</div>
</div>
<div class="result-item">
<div class="result-label">Número de Passes</div>
<div class="result-value">${passes}</div>
</div>
</div>
<div class="alert alert-success" style="margin-top: 16px;">
<strong>Eletrodo recomendado:</strong> E${Math.round(fy * 1.15)} (resistência compatível com o aço base)
</div>
</div>
`;
addToHistory('Solda de Filete', `Perna ${legCommercial}mm, ${passes} passe(s)`);
}
// Heat Input Calculation
function calcularEnergiaSoldagem() {
const voltage = parseFloat(document.getElementById('hi-voltage').value) || 0;
const current = parseFloat(document.getElementById('hi-current').value) || 0;
const speed = parseFloat(document.getElementById('hi-speed').value) || 0;
const heatInput = (voltage * current * 60) / (speed * 1000);
let interpretation = '';
let alertClass = '';
if (heatInput < 1.0) {
interpretation = 'Energia baixa - Risco de falta de fusão ou trincas a frio';
alertClass = 'alert-warning';
} else if (heatInput <= 2.0) {
interpretation = 'Energia adequada - Dentro da faixa recomendada';
alertClass = 'alert-success';
} else {
interpretation = 'Energia alta - Risco de fragilização da ZTA e distorção';
alertClass = 'alert-error';
}
document.getElementById('hi-result').innerHTML = `
<div class="result-box">
<div class="result-title">Energia de Soldagem (Heat Input)</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Energia</div>
<div class="result-value">${heatInput.toFixed(2)} kJ/mm</div>
</div>
</div>
<div class="alert ${alertClass}" style="margin-top: 16px;">
<strong>${interpretation}</strong>
</div>
<div class="expert-only" style="margin-top: 16px; padding: 16px; background: var(--color-bg-4); border-radius: 8px;">
<strong>Fórmula:</strong> HI = (V × I × 60) / (v × 1000)<br>
<strong>Recomendações:</strong><br>
• Aços carbono: 0.8 - 2.0 kJ/mm<br>
• Alta resistência: 0.8 - 1.5 kJ/mm<br>
• Baixa liga: 1.0 - 2.5 kJ/mm
</div>
</div>
`;
addToHistory('Energia de Soldagem', `HI = ${heatInput.toFixed(2)} kJ/mm`);
}
// Electrode Consumption
function calcularConsumoEletrodos() {
const leg = parseFloat(document.getElementById('elec-leg').value) || 0;
const length = parseFloat(document.getElementById('elec-length').value) || 0;
const factor = parseFloat(document.getElementById('elec-type').value) || 1.10;
const loss = parseFloat(document.getElementById('elec-loss').value) || 15;
const throat = leg * 0.707;
const volume = throat * leg * length * 1000;
const mass = (volume / 1000000) * 7850 / 1000;
const consumption = mass * factor * (1 + loss / 100);
document.getElementById('elec-result').innerHTML = `
<div class="result-box">
<div class="result-title">Consumo de Eletrodos</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Volume de Solda</div>
<div class="result-value">${(volume / 1000).toFixed(1)} cm³</div>
</div>
<div class="result-item">
<div class="result-label">Massa de Solda</div>
<div class="result-value">${mass.toFixed(2)} kg</div>
</div>
<div class="result-item">
<div class="result-label">Consumo Total</div>
<div class="result-value">${consumption.toFixed(2)} kg</div>
</div>
</div>
<div style="margin-top: 16px; padding: 16px; background: var(--color-bg-5); border-radius: 8px;">
<strong>Estimativa de embalagens:</strong><br>
Eletrodos Ø3,25mm (1 kg cada): ${Math.ceil(consumption)} embalagens
</div>
</div>
`;
addToHistory('Consumo de Eletrodos', `${consumption.toFixed(2)} kg para ${length}m de solda`);
}
// Hardness Converter
function converterDureza(source) {
let HB = 0;
if (source === 'hb') {
HB = parseFloat(document.getElementById('hard-hb').value) || 0;
} else if (source === 'hrc') {
const HRC = parseFloat(document.getElementById('hard-hrc').value) || 0;
HB = (HRC + 9.8) / 0.0338;
document.getElementById('hard-hb').value = Math.round(HB);
} else if (source === 'hv') {
const HV = parseFloat(document.getElementById('hard-hv').value) || 0;
HB = HV / 0.95;
document.getElementById('hard-hb').value = Math.round(HB);
}
if (HB === 0) return;
const HRC = HB * 0.0338 - 9.8;
const HV = HB * 0.95;
const fu = HB * 10;
const fy = fu * 0.7;
if (source !== 'hrc') document.getElementById('hard-hrc').value = HRC.toFixed(1);
if (source !== 'hv') document.getElementById('hard-hv').value = Math.round(HV);
document.getElementById('hardness-result').innerHTML = `
<div class="result-box">
<div class="result-title">Conversão de Dureza</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">HB (Brinell)</div>
<div class="result-value">${Math.round(HB)}</div>
</div>
<div class="result-item">
<div class="result-label">HRC (Rockwell C)</div>
<div class="result-value">${HRC.toFixed(1)}</div>
</div>
<div class="result-item">
<div class="result-label">HV (Vickers)</div>
<div class="result-value">${Math.round(HV)}</div>
</div>
</div>
<div style="margin-top: 16px; padding: 16px; background: var(--color-bg-6); border-radius: 8px;">
<strong>Estimativa de Resistência:</strong><br>
fu ≈ ${fu.toFixed(0)} MPa<br>
fy ≈ ${fy.toFixed(0)} MPa (aproximado)
</div>
</div>
`;
}
// Charpy Analysis
function analisarCharpy() {
const temps = [
parseFloat(document.getElementById('charpy-t1').value),
parseFloat(document.getElementById('charpy-t2').value),
parseFloat(document.getElementById('charpy-t3').value),
parseFloat(document.getElementById('charpy-t4').value)
];
const energies = [
parseFloat(document.getElementById('charpy-e1').value),
parseFloat(document.getElementById('charpy-e2').value),
parseFloat(document.getElementById('charpy-e3').value),
parseFloat(document.getElementById('charpy-e4').value)
];
const validPoints = temps.map((t, i) => ({ temp: t, energy: energies[i] }))
.filter(p => !isNaN(p.temp) && !isNaN(p.energy))
.sort((a, b) => a.temp - b.temp);
if (validPoints.length < 2) {
alert('Insira pelo menos 2 pontos válidos');
return;
}
let ttdf = null;
for (let i = 0; i < validPoints.length - 1; i++) {
if ((validPoints[i].energy >= 27 && validPoints[i+1].energy < 27) ||
(validPoints[i].energy < 27 && validPoints[i+1].energy >= 27)) {
const t1 = validPoints[i].temp;
const e1 = validPoints[i].energy;
const t2 = validPoints[i+1].temp;
const e2 = validPoints[i+1].energy;
ttdf = t1 + (27 - e1) * (t2 - t1) / (e2 - e1);
break;
}
}
document.getElementById('charpy-result').innerHTML = `
<div class="card">
<div class="card-title">Curva de Transição Dúctil-Frágil</div>
<div class="chart-container">
<canvas id="charpy-chart"></canvas>
</div>
${ttdf !== null ? `
<div class="alert alert-success" style="margin-top: 16px;">
<strong>TTDF (Temperatura de Transição):</strong> ${ttdf.toFixed(1)}°C<br>
Temperatura onde a energia de impacto = 27J
</div>
` : `
<div class="alert alert-warning" style="margin-top: 16px;">
<strong>Não foi possível calcular TTDF</strong><br>
A curva não intercepta 27J no intervalo medido
</div>
`}
</div>
`;
if (currentChart) {
currentChart.destroy();
}
const ctx = document.getElementById('charpy-chart').getContext('2d');
currentChart = new Chart(ctx, {
type: 'line',
data: {
labels: validPoints.map(p => p.temp + '°C'),
datasets: [{
label: 'Energia (J)',
data: validPoints.map(p => p.energy),
borderColor: '#1FB8CD',
backgroundColor: '#1FB8CD40',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: 'Curva de Transição Charpy'
}
},
scales: {
y: {
title: {
display: true,
text: 'Energia (J)'
}
},
x: {
title: {
display: true,
text: 'Temperatura (°C)'
}
}
}
}
});
addToHistory('Análise Charpy', `${validPoints.length} pontos, TTDF = ${ttdf ? ttdf.toFixed(1) : 'N/A'}°C`);
}
// Certificate Checklist
function gerarChecklistCertificado() {
const norm = document.getElementById('cert-norm').value;
const requirements = certRequirements[norm] || [];
document.getElementById('cert-result').innerHTML = `
<div class="card">
<div class="card-title">Checklist de Requisitos - ${norm.toUpperCase().replace('_', ' ')}</div>
${requirements.map((req, index) => `
<div style="padding: 12px; background: var(--color-background); border-radius: 8px; margin-bottom: 8px; display: flex; align-items: center; gap: 12px;">
<input type="checkbox" id="req-${index}" style="width: 20px; height: 20px; cursor: pointer;">
<label for="req-${index}" style="cursor: pointer; flex: 1;">${req}</label>
</div>
`).join('')}
</div>
`;
}
// Paint Area Calculation
function updatePaintFields() {
const type = document.getElementById('paint-type').value;
const field3 = document.getElementById('paint-field3');
if (type === 'chapa') {
document.getElementById('paint-label1').textContent = 'Comprimento (mm)';
document.getElementById('paint-label2').textContent = 'Largura (mm)';
field3.style.display = 'none';
} else if (type === 'perfilW') {
document.getElementById('paint-label1').textContent = 'Comprimento (mm)';
document.getElementById('paint-label2').textContent = 'Altura (mm)';
field3.style.display = 'none';
} else if (type === 'tubo') {
document.getElementById('paint-label1').textContent = 'Comprimento (mm)';
document.getElementById('paint-label2').textContent = 'Diâmetro (mm)';
field3.style.display = 'none';
} else if (type === 'rhs') {
document.getElementById('paint-label1').textContent = 'Comprimento (mm)';
document.getElementById('paint-label2').textContent = 'Largura (mm)';
document.getElementById('paint-label3').textContent = 'Altura (mm)';
field3.style.display = 'block';
}
}
function calcularAreaPintura() {
const type = document.getElementById('paint-type').value;
const dim1 = parseFloat(document.getElementById('paint-dim1').value) || 0;
const dim2 = parseFloat(document.getElementById('paint-dim2').value) || 0;
const dim3 = parseFloat(document.getElementById('paint-dim3').value) || 0;
const qty = parseInt(document.getElementById('paint-qty').value) || 1;
let area = 0;
if (type === 'chapa') {
area = (dim1 * dim2 * 2) / 1000000;
} else if (type === 'perfilW') {
const perimeter = dim2 * 3.5;
area = (perimeter * dim1) / 1000000;
} else if (type === 'tubo') {
area = (Math.PI * dim2 * dim1) / 1000000;
} else if (type === 'rhs') {
const perimeter = 2 * (dim2 + dim3);
area = (perimeter * dim1) / 1000000;
}
const totalArea = area * qty;
document.getElementById('paint-area-result').innerHTML = `
<div class="result-box">
<div class="result-title">Área de Pintura</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Área Unitária</div>
<div class="result-value">${area.toFixed(2)} m²</div>
</div>
<div class="result-item">
<div class="result-label">Área Total</div>
<div class="result-value">${totalArea.toFixed(2)} m²</div>
</div>
</div>
</div>
`;
document.getElementById('tinta-area').value = totalArea.toFixed(2);
addToHistory('Área de Pintura', `${totalArea.toFixed(2)}m² (${qty} unidades)`);
}
// Paint Consumption
function calcularConsumoTinta() {
const area = parseFloat(document.getElementById('tinta-area').value) || 0;
const dft = parseFloat(document.getElementById('tinta-dft').value) || 0;
const solids = parseFloat(document.getElementById('tinta-solids').value) || 0;
const loss = parseFloat(document.getElementById('tinta-loss').value) || 0;
const coats = parseInt(document.getElementById('tinta-coats').value) || 1;
const cost = parseFloat(document.getElementById('tinta-cost').value) || 0;
const volumeTheoretical = (dft * area) / (1000 * (solids / 100));
const volumeWithLoss = volumeTheoretical / (1 - loss / 100);
const volumePerCoat = volumeWithLoss;
const volumeTotal = volumePerCoat * coats;
const totalCost = volumeTotal * cost;
document.getElementById('tinta-result').innerHTML = `
<div class="result-box">
<div class="result-title">Consumo de Tinta</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Volume Teórico</div>
<div class="result-value">${volumeTheoretical.toFixed(2)} L</div>
</div>
<div class="result-item">
<div class="result-label">Volume por Demão</div>
<div class="result-value">${volumePerCoat.toFixed(2)} L</div>
</div>
<div class="result-item">
<div class="result-label">Volume Total</div>
<div class="result-value">${volumeTotal.toFixed(2)} L</div>
</div>
<div class="result-item">
<div class="result-label">Custo Total</div>
<div class="result-value">R$ ${totalCost.toFixed(2)}</div>
</div>
</div>
<div style="margin-top: 16px; padding: 16px; background: var(--color-bg-7); border-radius: 8px;">
<strong>Recomendação de embalagens:</strong><br>
${volumeTotal > 20 ? `Galões 20L: ${Math.ceil(volumeTotal / 20)} unidades` :
volumeTotal > 5 ? `Galões 5L: ${Math.ceil(volumeTotal / 5)} unidades` :
`Latas 1L: ${Math.ceil(volumeTotal)} unidades`}
</div>
</div>
`;
addToHistory('Consumo de Tinta', `${volumeTotal.toFixed(2)}L para ${area}`);
}
// Galvanization
function calcularGalvanizacao() {
const env = document.getElementById('galv-env').value;
const area = parseFloat(document.getElementById('galv-area').value) || 0;
const thickness = parseFloat(document.getElementById('galv-thickness').value) || 85;
const corrosionRate = {
'interno': 0.5,
'urbano': 1.5,
'marinho': 3.0,
'industrial': 2.5
};
const rate = corrosionRate[env] || 1.5;
const lifeYears = thickness / rate;
const zincDensity = 7140;
const zincMass = (area * thickness / 1000) * (zincDensity / 1000000);
const zincCost = zincMass * 12;
document.getElementById('galv-result').innerHTML = `
<div class="result-box">
<div class="result-title">Galvanização a Quente</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Taxa de Corrosão</div>
<div class="result-value">${rate.toFixed(1)} μm/ano</div>
</div>
<div class="result-item">
<div class="result-label">Vida Útil Estimada</div>
<div class="result-value">${lifeYears.toFixed(0)} anos</div>
</div>
<div class="result-item">
<div class="result-label">Consumo de Zinco</div>
<div class="result-value">${zincMass.toFixed(2)} kg</div>
</div>
<div class="result-item">
<div class="result-label">Custo Estimado</div>
<div class="result-value">R$ ${(zincCost + area * 180).toFixed(2)}</div>
</div>
</div>
<div class="alert alert-success" style="margin-top: 16px;">
<strong>Normas aplicáveis:</strong> ASTM A123, ISO 1461, NBR 6323
</div>
</div>
`;
addToHistory('Galvanização', `${area}m², ${thickness}μm → ${lifeYears.toFixed(0)} anos`);
}
// Budget
function adicionarItemOrcamento() {
const type = document.getElementById('budget-type').value;
const spec = document.getElementById('budget-spec').value;
const qty = parseFloat(document.getElementById('budget-qty').value) || 0;
const unit = document.getElementById('budget-unit').value;
const price = parseFloat(document.getElementById('budget-price').value) || 0;
if (!spec || qty <= 0 || price <= 0) {
alert('Preencha todos os campos corretamente');
return;
}
const item = {
id: Date.now(),
type: type,
spec: spec,
qty: qty,
unit: unit,
price: price,
total: qty * price
};
appState.budgetItems.push(item);
atualizarTabelaOrcamento();
document.getElementById('budget-spec').value = '';
document.getElementById('budget-qty').value = '1';
document.getElementById('budget-price').value = '0';
}
function removerItemOrcamento(id) {
appState.budgetItems = appState.budgetItems.filter(item => item.id !== id);
atualizarTabelaOrcamento();
}
function atualizarTabelaOrcamento() {
const tbody = document.getElementById('budget-tbody');
if (appState.budgetItems.length === 0) {
tbody.innerHTML = '<tr><td colspan="7" style="text-align: center; color: var(--color-text-secondary);">Nenhum item adicionado</td></tr>';
} else {
tbody.innerHTML = appState.budgetItems.map(item => `
<tr>
<td>${item.type}</td>
<td>${item.spec}</td>
<td>${item.qty.toFixed(2)}</td>
<td>${item.unit}</td>
<td>R$ ${item.price.toFixed(2)}</td>
<td><strong>R$ ${item.total.toFixed(2)}</strong></td>
<td><button class="btn btn-secondary" style="padding: 6px 12px; font-size: 12px;" onclick="removerItemOrcamento(${item.id})">Remover</button></td>
</tr>
`).join('');
}
atualizarTotalOrcamento();
}
function atualizarTotalOrcamento() {
const subtotal = appState.budgetItems.reduce((sum, item) => sum + item.total, 0);
const bdi = parseFloat(document.getElementById('budget-bdi').value) || 0;
const total = subtotal * (1 + bdi / 100);
const resultDiv = document.getElementById('budget-total');
resultDiv.innerHTML = `
<div class="result-box">
<div class="result-grid">
<div class="result-item">
<div class="result-label">Subtotal</div>
<div class="result-value">R$ ${subtotal.toFixed(2)}</div>
</div>
<div class="result-item">
<div class="result-label">BDI (${bdi}%)</div>
<div class="result-value">R$ ${(total - subtotal).toFixed(2)}</div>
</div>
<div class="result-item">
<div class="result-label">TOTAL GERAL</div>
<div class="result-value" style="color: var(--color-success);">R$ ${total.toFixed(2)}</div>
</div>
</div>
</div>
`;
}
// Weight & Rigging
function updateWeightFields() {
const type = document.getElementById('weight-type').value;
const field3 = document.getElementById('weight-field3');
const field4 = document.getElementById('weight-field4');
if (type === 'perfilW') {
document.getElementById('weight-label1').textContent = 'Altura (mm)';
document.getElementById('weight-label2').textContent = 'Comprimento (m)';
field3.style.display = 'none';
field4.style.display = 'none';
} else if (type === 'chapa') {
document.getElementById('weight-label1').textContent = 'Largura (mm)';
document.getElementById('weight-label2').textContent = 'Altura (mm)';
document.getElementById('weight-label3').textContent = 'Espessura (mm)';
field3.style.display = 'block';
field4.style.display = 'none';
} else if (type === 'tubo') {
document.getElementById('weight-label1').textContent = 'Diâmetro Externo (mm)';
document.getElementById('weight-label2').textContent = 'Comprimento (m)';
document.getElementById('weight-label3').textContent = 'Espessura Parede (mm)';
field3.style.display = 'block';
field4.style.display = 'none';
} else if (type === 'barra') {
document.getElementById('weight-label1').textContent = 'Diâmetro (mm)';
document.getElementById('weight-label2').textContent = 'Comprimento (m)';
field3.style.display = 'none';
field4.style.display = 'none';
}
}
function calcularPeso() {
const type = document.getElementById('weight-type').value;
const dim1 = parseFloat(document.getElementById('weight-dim1').value) || 0;
const dim2 = parseFloat(document.getElementById('weight-dim2').value) || 0;
const dim3 = parseFloat(document.getElementById('weight-dim3').value) || 0;
let weight = 0;
if (type === 'perfilW') {
weight = (dim1 / 100) * 31.8 * dim2;
} else if (type === 'chapa') {
weight = (dim1 / 1000) * (dim2 / 1000) * (dim3 / 1000) * 7850;
} else if (type === 'tubo') {
const dExt = dim1;
const dInt = dExt - 2 * dim3;
const area = Math.PI * (Math.pow(dExt/2, 2) - Math.pow(dInt/2, 2));
weight = area / 1000000 * dim2 * 7850;
} else if (type === 'barra') {
const area = Math.PI * Math.pow(dim1/2, 2);
weight = area / 1000000 * dim2 * 7850;
}
document.getElementById('weight-result').innerHTML = `
<div class="result-box">
<div class="result-title">Cálculo de Peso</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Peso Total</div>
<div class="result-value">${weight.toFixed(2)} kg</div>
</div>
</div>
</div>
`;
document.getElementById('rigging-weight').value = weight.toFixed(0);
addToHistory('Cálculo de Peso', `${weight.toFixed(2)}kg`);
}
function calcularRigging() {
const weight = parseFloat(document.getElementById('rigging-weight').value) || 0;
const points = parseInt(document.getElementById('rigging-points').value) || 2;
const angle = parseInt(document.getElementById('rigging-angle').value) || 60;
const fs = parseFloat(document.getElementById('rigging-fs').value) || 4;
const angleRad = angle * Math.PI / 180;
const forcePerCable = (weight * 9.81 / 1000) / (points * Math.cos(angleRad)) * fs;
const cableSteelCapacity = 21;
const chainCapacity = 15;
const syntheticCapacity = 12;
let recommendation = '';
let alertClass = 'alert-success';
if (forcePerCable <= syntheticCapacity) {
recommendation = '✅ Cabo sintético (12 kN)';
} else if (forcePerCable <= chainCapacity) {
recommendation = '✅ Corrente grau 80 (15 kN)';
} else if (forcePerCable <= cableSteelCapacity) {
recommendation = '⚠️ Cabo de aço (21 kN)';
alertClass = 'alert-warning';
} else {
recommendation = '❌ Requer cabo especial ou mais pontos de içamento';
alertClass = 'alert-error';
}
document.getElementById('rigging-result').innerHTML = `
<div class="result-box">
<div class="result-title">Plano de Rigging</div>
<div class="result-grid">
<div class="result-item">
<div class="result-label">Força por Cabo</div>
<div class="result-value">${forcePerCable.toFixed(1)} kN</div>
</div>
<div class="result-item">
<div class="result-label">Ângulo</div>
<div class="result-value">${angle}°</div>
</div>
<div class="result-item">
<div class="result-label">Fator Segurança</div>
<div class="result-value">${fs}</div>
</div>
</div>
<div class="alert ${alertClass}" style="margin-top: 16px;">
<strong>Recomendação: ${recommendation}</strong>
</div>
<div style="margin-top: 16px; padding: 16px; background: var(--color-bg-8); border-radius: 8px;">
<strong>Capacidades de Referência:</strong><br>
• Cabo sintético: 12 kN<br>
• Corrente grau 80: 15 kN<br>
• Cabo de aço: 21 kN
</div>
</div>
`;
addToHistory('Rigging', `${weight}kg, ${points} pontos, ${angle}° → ${forcePerCable.toFixed(1)}kN/cabo`);
}
// ========================================
// INITIALIZATION
// ========================================
document.addEventListener('DOMContentLoaded', function() {
showSection('cev');
mostrarEquivalencias();
gerarChecklistCertificado();
updatePaintFields();
updateWeightFields();
});