feat: adicionar super manual didatico com fluxos 2d e sheet panel
This commit is contained in:
@@ -25,11 +25,6 @@ export interface Bar3DInput {
|
||||
cx: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converte kN para um comprimento visual proporcional no eixo 3D.
|
||||
*/
|
||||
const forceToLength = (kN: number): number => Math.min(Math.max(Math.abs(kN) * 0.3, 0.3), 4);
|
||||
|
||||
function BarModel({
|
||||
barType,
|
||||
section,
|
||||
@@ -37,94 +32,60 @@ function BarModel({
|
||||
width,
|
||||
length,
|
||||
alpha,
|
||||
fxKN,
|
||||
fyKN,
|
||||
cx,
|
||||
}: Bar3DInput) {
|
||||
const barRadius = barType === 'circular' ? (diameter ?? 0.05) / 2 : Math.min(width ?? 0.1, 0.08) / 2;
|
||||
const barThickness = barType === 'circular' ? barRadius : barRadius * 0.5;
|
||||
|
||||
// Cor baseada em Cx
|
||||
const barColor = useMemo(() => {
|
||||
const intensity = Math.min(1, Math.abs(cx) / 2.5);
|
||||
const hue = 215 - intensity * 215;
|
||||
return new THREE.Color(`hsl(${hue}, ${65 + intensity * 25}%, ${45 - intensity * 10}%)`);
|
||||
}, [cx]);
|
||||
|
||||
// Rotação da barra em torno do eixo Y (alinhada com eixo X inicialmente)
|
||||
// Direção do vento é +X; α é o ângulo da face da barra em relação ao vento
|
||||
// Ação do vento deve rotacionar a barra em seu próprio eixo longitudinal (roll).
|
||||
// O eixo longitudinal na nossa geometria é o X.
|
||||
const alphaRad = (alpha * Math.PI) / 180;
|
||||
const barRotation = -alphaRad; // rotação em torno do eixo Y para alinhar a face
|
||||
|
||||
// Direção do vetor de força resultante (na direção da força calculada)
|
||||
const forceMag = Math.sqrt(fxKN * fxKN + fyKN * fyKN);
|
||||
const forceAngle = Math.atan2(fyKN, fxKN);
|
||||
const arrowLen = forceToLength(forceMag);
|
||||
|
||||
// Centro da barra (origem)
|
||||
const center = new THREE.Vector3(0, 0, 0);
|
||||
|
||||
// Posição da ponta da seta
|
||||
const arrowEnd = useMemo(
|
||||
() => new THREE.Vector3(
|
||||
Math.cos(forceAngle) * arrowLen,
|
||||
Math.sin(forceAngle) * arrowLen,
|
||||
0,
|
||||
),
|
||||
[forceAngle, arrowLen],
|
||||
);
|
||||
const arrowMid = useMemo(
|
||||
() => new THREE.Vector3(arrowEnd.x / 2, arrowEnd.y / 2, 0),
|
||||
[arrowEnd],
|
||||
);
|
||||
const quat = useMemo(() => {
|
||||
const dir = arrowEnd.clone().normalize();
|
||||
const q = new THREE.Quaternion();
|
||||
q.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir);
|
||||
return new THREE.Euler().setFromQuaternion(q);
|
||||
}, [arrowEnd]);
|
||||
|
||||
const headLen = 0.25;
|
||||
// A rotação deve ser negativa para que o vento (vindo de -Z) atinja as faces corretas conforme a NBR.
|
||||
const barRotationX = -alphaRad;
|
||||
|
||||
return (
|
||||
<group rotation={[0, barRotation, 0]}>
|
||||
{/* Eixo principal da barra ao longo do eixo X */}
|
||||
{barType === 'circular' ? (
|
||||
<mesh position={[0, 0, 0]} rotation={[0, 0, Math.PI / 2]} castShadow>
|
||||
<cylinderGeometry args={[barRadius, barRadius, length, 16]} />
|
||||
<meshStandardMaterial color={barColor} roughness={0.4} metalness={0.3} />
|
||||
<group>
|
||||
{/* Seta do Vento (Fixa Globalmente, soprando em +Z) */}
|
||||
<group position={[0, 0, barRadius + 0.5]}>
|
||||
<mesh position={[0, 0, 0.4]} rotation={[Math.PI / 2, 0, 0]}>
|
||||
<cylinderGeometry args={[0.02, 0.02, 0.8, 8]} />
|
||||
<meshStandardMaterial color="#22c55e" />
|
||||
</mesh>
|
||||
) : (
|
||||
<SectionShape section={section ?? 'placa'} width={width ?? 0.1} length={length} color={barColor} thickness={barThickness} />
|
||||
)}
|
||||
|
||||
{/* Eixos de referência */}
|
||||
<axesHelper args={[length * 0.5]} />
|
||||
|
||||
{/* Vetor de força (resultante) */}
|
||||
{forceMag > 0.01 && (
|
||||
<group>
|
||||
{arrowLen - headLen > 0.01 && (
|
||||
<mesh position={arrowMid.toArray()} rotation={[quat.x, quat.y, quat.z]} castShadow>
|
||||
<cylinderGeometry args={[0.04, 0.04, arrowLen - headLen, 10]} />
|
||||
<meshStandardMaterial color="#ef4444" />
|
||||
</mesh>
|
||||
)}
|
||||
<mesh position={arrowEnd.toArray()} rotation={[quat.x, quat.y, quat.z]} castShadow>
|
||||
<coneGeometry args={[0.1, headLen, 10]} />
|
||||
<meshStandardMaterial color="#ef4444" />
|
||||
<mesh position={[0, 0, 0]} rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<coneGeometry args={[0.08, 0.2, 8]} />
|
||||
<meshStandardMaterial color="#22c55e" />
|
||||
</mesh>
|
||||
</group>
|
||||
|
||||
{/* Barra Rotacionada (Roll) */}
|
||||
<group rotation={[barRotationX, 0, 0]}>
|
||||
{/* Eixo principal da barra ao longo do eixo X */}
|
||||
{barType === 'circular' ? (
|
||||
<mesh position={[0, 0, 0]} rotation={[0, 0, Math.PI / 2]} castShadow>
|
||||
<cylinderGeometry args={[barRadius, barRadius, length, 16]} />
|
||||
<meshStandardMaterial color={barColor} roughness={0.4} metalness={0.3} />
|
||||
</mesh>
|
||||
</group>
|
||||
)}
|
||||
) : (
|
||||
<SectionShape section={section ?? 'placa'} width={width ?? 0.1} length={length} color={barColor} thickness={barThickness} />
|
||||
)}
|
||||
|
||||
{/* Eixos de referência locais da barra */}
|
||||
<axesHelper args={[length * 0.5]} />
|
||||
</group>
|
||||
|
||||
{/* Marca de origem */}
|
||||
<mesh position={[0, 0, 0]} castShadow>
|
||||
<sphereGeometry args={[0.06, 12, 12]} />
|
||||
<meshStandardMaterial color="#fbbf24" emissive="#fbbf24" emissiveIntensity={0.4} />
|
||||
</mesh>
|
||||
<axesHelper args={[length * 0.3]} />
|
||||
<Text
|
||||
position={[0, -barRadius * 2 - 0.3, 0]}
|
||||
position={[0, -barRadius * 2 - 0.4, 0]}
|
||||
fontSize={0.3}
|
||||
color="#1e40af"
|
||||
anchorX="center"
|
||||
@@ -132,7 +93,6 @@ function BarModel({
|
||||
>
|
||||
α={alpha}° | Cx={cx.toFixed(2)}
|
||||
</Text>
|
||||
{center && null}
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user