Se ajustaron los coeficientes de fricción y configuraciones de resorte en la simulación de botellas, diferenciando entre transportes con y sin freno. Además, se modificó la visibilidad de triángulos en la visualización 3D, mejorando la iluminación y corrigiendo la creación de mallas continuas a partir de triángulos de BEPU. Se eliminaron métodos obsoletos relacionados con la geometría de curvas, optimizando la lógica de creación de mallas.

This commit is contained in:
Miguel 2025-07-05 17:53:22 +02:00
parent eb6ed62d5b
commit 71c08d8047
2 changed files with 64 additions and 104 deletions

View File

@ -127,9 +127,22 @@ namespace CtrEditor.Simulacion
// en la clase simTransporte. El motor de físicas se encarga del resto. // en la clase simTransporte. El motor de físicas se encarga del resto.
// ✅ Fricción ajustada para un arrastre firme pero no excesivo. // ✅ Fricción ajustada para un arrastre firme pero no excesivo.
pairMaterial.FrictionCoefficient = 1.2f; var transport = transportA ?? transportB;
pairMaterial.MaximumRecoveryVelocity = 1.0f; if (transport.isBrake)
pairMaterial.SpringSettings = new SpringSettings(80, 1); {
botella.isOnBrakeTransport = true;
pairMaterial.FrictionCoefficient = 14f;
pairMaterial.MaximumRecoveryVelocity = 1.0f;
pairMaterial.SpringSettings = new SpringSettings(80, 8);
}
else
{
botella.isOnBrakeTransport = false;
pairMaterial.FrictionCoefficient = 1.2f;
pairMaterial.MaximumRecoveryVelocity = 1.0f;
pairMaterial.SpringSettings = new SpringSettings(80, 1);
}
} }
// ✅ CONTACTO BOTELLA-CURVA: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA // ✅ CONTACTO BOTELLA-CURVA: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA
else if (botella != null && (curveA != null || curveB != null)) else if (botella != null && (curveA != null || curveB != null))
@ -153,9 +166,18 @@ namespace CtrEditor.Simulacion
// ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Configuración más suave para evitar el comportamiento "pegajoso". // ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Configuración más suave para evitar el comportamiento "pegajoso".
else if (botellaA != null && botellaB != null) else if (botellaA != null && botellaB != null)
{ {
pairMaterial.FrictionCoefficient = 0.01f; // Un poco menos de fricción. if (botella.isOnBrakeTransport)
pairMaterial.MaximumRecoveryVelocity = 1.5f; // Menos rebote. {
pairMaterial.SpringSettings = new SpringSettings(20, 0.5f); // Muelle MUCHO más suave y críticamente amortiguado. pairMaterial.FrictionCoefficient = 2.0f; // Un poco menos de fricción.
pairMaterial.MaximumRecoveryVelocity = 1.5f; // Menos rebote.
pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Muelle MUCHO más suave y críticamente amortiguado.
}
else
{
pairMaterial.FrictionCoefficient = 0.01f; // Un poco menos de fricción.
pairMaterial.MaximumRecoveryVelocity = 1.5f; // Menos rebote.
pairMaterial.SpringSettings = new SpringSettings(20, 0.5f); // Muelle MUCHO más suave y críticamente amortiguado.
}
} }
// Ajustes básicos para otras botellas // Ajustes básicos para otras botellas
else if (botella != null) else if (botella != null)

View File

@ -72,7 +72,7 @@ namespace CtrEditor.Simulacion
private Dictionary<simBase, ShapeDimensions> lastKnownDimensions; private Dictionary<simBase, ShapeDimensions> lastKnownDimensions;
// ✅ CORREGIDO: Flag de debug para mostrar triángulos individuales de curvas (true temporalmente para verificar) // ✅ CORREGIDO: Flag de debug para mostrar triángulos individuales de curvas (true temporalmente para verificar)
public static bool DebugShowIndividualTriangles { get; set; } = true; public static bool DebugShowIndividualTriangles { get; set; } = false;
public HelixViewport3D Viewport3D public HelixViewport3D Viewport3D
{ {
@ -112,14 +112,14 @@ namespace CtrEditor.Simulacion
// Agregar luces // Agregar luces
var directionalLight = new DirectionalLight var directionalLight = new DirectionalLight
{ {
Color = Colors.White, Color = Color.FromRgb(150, 150, 150), // Luz direccional menos intensa
Direction = new Vector3D(0, 0, -1) Direction = new Vector3D(-0.2, -0.3, -1) // Ligeramente angulada para evitar reflejos directos
}; };
viewport3D.Children.Add(new ModelVisual3D { Content = directionalLight }); viewport3D.Children.Add(new ModelVisual3D { Content = directionalLight });
var ambientLight = new AmbientLight var ambientLight = new AmbientLight
{ {
Color = Color.FromRgb(64, 64, 64) Color = Color.FromRgb(120, 120, 120) // Más luz ambiente para suavizar sombras
}; };
viewport3D.Children.Add(new ModelVisual3D { Content = ambientLight }); viewport3D.Children.Add(new ModelVisual3D { Content = ambientLight });
@ -397,7 +397,7 @@ namespace CtrEditor.Simulacion
} }
else else
{ {
// ✅ Usar directamente los triángulos originales de BEPU (superficie continua) // ✅ CORREGIDO: Crea un arco de mesh continuo y simple desde los triángulos de BEPU
CreateCurveMeshFromBEPUTriangles(meshBuilder, curve); CreateCurveMeshFromBEPUTriangles(meshBuilder, curve);
} }
@ -422,44 +422,57 @@ namespace CtrEditor.Simulacion
} }
/// <summary> /// <summary>
/// ✅ CORREGIDO: Crea mesh desde los triángulos locales de BEPU /// ✅ CORREGIDO: Crea un arco de mesh continuo y simple desde los triángulos de BEPU
/// Extrae la geometría exacta en coordenadas locales para evitar transformación duplicada /// Genera una superficie plana que forma un arco suave y eficiente
/// </summary> /// </summary>
private void CreateCurveMeshFromBEPUTriangles(MeshBuilder meshBuilder, simCurve curve) private void CreateCurveMeshFromBEPUTriangles(MeshBuilder meshBuilder, simCurve curve)
{ {
try try
{ {
// ✅ EXTRAER TRIÁNGULOS LOCALES DE BEPU (sin transformación duplicada) // Obtener los triángulos de BEPU
var localTriangles = curve.GetRealBEPUTriangles(); var localTriangles = curve.GetRealBEPUTriangles();
System.Diagnostics.Debug.WriteLine($"[3D Curve] Creating continuous arc mesh from {localTriangles.Length} BEPU triangles");
if (localTriangles.Length == 0) if (localTriangles.Length == 0)
{ {
System.Diagnostics.Debug.WriteLine($"[3D BEPU] WARNING: No se pudieron extraer triángulos locales, usando fallback"); System.Diagnostics.Debug.WriteLine($"[3D Curve] WARNING: No triangles found in BEPU curve");
CreateCurveMeshFallback(meshBuilder, curve);
return; return;
} }
System.Diagnostics.Debug.WriteLine($"[3D BEPU] Creando mesh desde {localTriangles.Length} triángulos locales de BEPU"); // ✅ CORREGIDO: Usar altura más visible y verificar coordenadas
const float curveHeight = 0.02f; // 2cm de altura para que sea claramente visible
int triangleCount = 0;
// ✅ USAR TRIÁNGULOS LOCALES DE BEPU (la transformación se aplicará automáticamente en UpdateVisualization)
foreach (var triangle in localTriangles) foreach (var triangle in localTriangles)
{ {
// Convertir triángulos de BEPU a puntos 3D de Helix // ✅ LOGGING: Verificar las coordenadas del primer triángulo
var pointA = new Point3D(triangle.A.X, triangle.A.Y, triangle.A.Z); if (triangleCount == 0)
var pointB = new Point3D(triangle.B.X, triangle.B.Y, triangle.B.Z); {
var pointC = new Point3D(triangle.C.X, triangle.C.Y, triangle.C.Z); System.Diagnostics.Debug.WriteLine($"[3D Curve] First triangle: A({triangle.A.X:F3}, {triangle.A.Y:F3}, {triangle.A.Z:F3})");
System.Diagnostics.Debug.WriteLine($"[3D Curve] First triangle: B({triangle.B.X:F3}, {triangle.B.Y:F3}, {triangle.B.Z:F3})");
System.Diagnostics.Debug.WriteLine($"[3D Curve] First triangle: C({triangle.C.X:F3}, {triangle.C.Y:F3}, {triangle.C.Z:F3})");
}
// Crear triángulo en la superficie superior con altura visible
var pointA = new Point3D(triangle.A.X, triangle.A.Y, triangle.A.Z + curveHeight);
var pointB = new Point3D(triangle.B.X, triangle.B.Y, triangle.B.Z + curveHeight);
var pointC = new Point3D(triangle.C.X, triangle.C.Y, triangle.C.Z + curveHeight);
// Agregar triángulo en coordenadas locales al mesh // ✅ CORREGIDO: Probar ambos órdenes de vértices para asegurar normales correctas
meshBuilder.AddTriangle(pointA, pointB, pointC); meshBuilder.AddTriangle(pointA, pointB, pointC);
// También agregar el triángulo con orden inverso para que sea visible desde ambos lados
meshBuilder.AddTriangle(pointA, pointC, pointB);
triangleCount++;
} }
System.Diagnostics.Debug.WriteLine($"[3D BEPU] ✅ Mesh creado usando triángulos locales de BEPU (transformación aplicada automáticamente)"); System.Diagnostics.Debug.WriteLine($"[3D Curve] ✅ Continuous arc mesh created with {triangleCount} triangles (height: {curveHeight})");
} }
catch (Exception ex) catch (Exception ex)
{ {
System.Diagnostics.Debug.WriteLine($"[3D BEPU] ERROR extrayendo triángulos locales: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"[3D Curve] ERROR creating continuous arc mesh: {ex.Message}");
System.Diagnostics.Debug.WriteLine($"[3D BEPU] Fallback a geometría recreada"); System.Diagnostics.Debug.WriteLine($"[3D Curve] Stack trace: {ex.StackTrace}");
CreateCurveMeshFallback(meshBuilder, curve);
} }
} }
@ -477,7 +490,7 @@ namespace CtrEditor.Simulacion
if (localTriangles.Length == 0) if (localTriangles.Length == 0)
{ {
System.Diagnostics.Debug.WriteLine($"[3D Debug] WARNING: No hay triángulos locales para debug, usando fallback"); System.Diagnostics.Debug.WriteLine($"[3D Debug] WARNING: No hay triángulos locales para debug, usando fallback");
CreateCurveMeshFallback(meshBuilder, curve); CreateBasicDebugGeometry(meshBuilder, curve);
return; return;
} }
@ -574,81 +587,6 @@ namespace CtrEditor.Simulacion
} }
} }
/// <summary>
/// Método fallback que recrea la geometría (mantener por compatibilidad)
/// </summary>
private void CreateCurveMeshFallback(MeshBuilder meshBuilder, simCurve curve)
{
// Obtener parámetros de la curva
float innerRadius = curve.InnerRadius;
float outerRadius = curve.OuterRadius;
float startAngle = curve.StartAngle;
float endAngle = curve.EndAngle;
System.Diagnostics.Debug.WriteLine($"[3D Fallback] Parameters - Inner: {innerRadius}, Outer: {outerRadius}, Start: {startAngle}, End: {endAngle}");
// Configuración de segmentos
const float SegmentationFactor = 32f / 3f;
const int MinSegments = 8;
const int MaxSegments = 64;
// Calcular número de segmentos basado en el tamaño del arco
float arcLength = (endAngle - startAngle) * ((innerRadius + outerRadius) / 2f);
int segments = (int)(arcLength * SegmentationFactor);
segments = Math.Max(MinSegments, Math.Min(segments, MaxSegments));
float angleStep = (endAngle - startAngle) / segments;
// Altura muy pequeña para simular triángulos planos
const float curveHeight = 0.05f;
// Generar vértices para el arco interior y exterior
var innerBottomPoints = new Point3D[segments + 1];
var innerTopPoints = new Point3D[segments + 1];
var outerBottomPoints = new Point3D[segments + 1];
var outerTopPoints = new Point3D[segments + 1];
for (int i = 0; i <= segments; i++)
{
float angle = startAngle + i * angleStep;
float cosAngle = (float)Math.Cos(angle);
float sinAngle = (float)Math.Sin(angle);
// Puntos en la parte inferior (Z = 0)
innerBottomPoints[i] = new Point3D(innerRadius * cosAngle, innerRadius * sinAngle, 0);
outerBottomPoints[i] = new Point3D(outerRadius * cosAngle, outerRadius * sinAngle, 0);
// Puntos en la parte superior (Z = curveHeight)
innerTopPoints[i] = new Point3D(innerRadius * cosAngle, innerRadius * sinAngle, curveHeight);
outerTopPoints[i] = new Point3D(outerRadius * cosAngle, outerRadius * sinAngle, curveHeight);
}
// Crear la superficie superior de la curva
for (int i = 0; i < segments; i++)
{
meshBuilder.AddTriangle(innerTopPoints[i], outerTopPoints[i], outerTopPoints[i + 1]);
meshBuilder.AddTriangle(innerTopPoints[i], outerTopPoints[i + 1], innerTopPoints[i + 1]);
}
// Crear la superficie inferior de la curva
for (int i = 0; i < segments; i++)
{
meshBuilder.AddTriangle(innerBottomPoints[i], outerBottomPoints[i + 1], outerBottomPoints[i]);
meshBuilder.AddTriangle(innerBottomPoints[i], innerBottomPoints[i + 1], outerBottomPoints[i + 1]);
}
// Crear las paredes laterales
for (int i = 0; i < segments; i++)
{
meshBuilder.AddQuad(innerBottomPoints[i], innerBottomPoints[i + 1], innerTopPoints[i + 1], innerTopPoints[i]);
meshBuilder.AddQuad(outerBottomPoints[i], outerTopPoints[i], outerTopPoints[i + 1], outerBottomPoints[i + 1]);
}
// Crear las paredes de los extremos
meshBuilder.AddQuad(innerBottomPoints[0], innerTopPoints[0], outerTopPoints[0], outerBottomPoints[0]);
meshBuilder.AddQuad(outerBottomPoints[segments], outerTopPoints[segments], innerTopPoints[segments], innerBottomPoints[segments]);
}
private void UpdateVisualizationFromSimBase(simBase simObj) private void UpdateVisualizationFromSimBase(simBase simObj)
{ {
if (!simBaseToModelMap.TryGetValue(simObj, out var visual)) if (!simBaseToModelMap.TryGetValue(simObj, out var visual))