Antes de cambios en simCurve

This commit is contained in:
Miguel 2025-07-02 23:39:22 +02:00
parent e38adc9f56
commit 4ff93a5802
2 changed files with 829 additions and 216 deletions

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,24 @@ namespace CtrEditor.Simulacion
/// <summary> /// <summary>
/// Manager que sincroniza el mundo 3D de BEPU con la visualización HelixToolkit /// Manager que sincroniza el mundo 3D de BEPU con la visualización HelixToolkit
/// Usa simBase como clave única para evitar problemas de reutilización de BodyHandle /// Usa simBase como clave única para evitar problemas de reutilización de BodyHandle
///
/// ✅ NUEVO: Funcionalidad de Debug para Triángulos
/// Para activar la visualización de triángulos individuales de curvas:
///
/// // Activar modo debug
/// visualizationManager.SetDebugTrianglesMode(true);
///
/// // Desactivar modo debug (volver a superficie continua)
/// visualizationManager.SetDebugTrianglesMode(false);
///
/// // Verificar si está activo
/// bool isDebugActive = visualizationManager.IsDebugTrianglesModeEnabled();
///
/// En modo debug:
/// - Cada triángulo de BEPU se muestra separado con un pequeño offset
/// - Los triángulos tienen bordes wireframe para mejor visualización
/// - Se usa un material naranja semi-transparente para distinguir del modo normal
/// - Se muestran mensajes de debug en la consola con información detallada
/// </summary> /// </summary>
public class BEPUVisualization3DManager public class BEPUVisualization3DManager
{ {
@ -53,6 +71,9 @@ namespace CtrEditor.Simulacion
private Dictionary<simBase, ModelVisual3D> simBaseToModelMap; private Dictionary<simBase, ModelVisual3D> simBaseToModelMap;
private Dictionary<simBase, ShapeDimensions> lastKnownDimensions; private Dictionary<simBase, ShapeDimensions> lastKnownDimensions;
// ✅ NUEVO: Flag de debug para mostrar triángulos individuales de curvas
public static bool DebugShowIndividualTriangles { get; set; } = true;
public HelixViewport3D Viewport3D public HelixViewport3D Viewport3D
{ {
get => viewport3D; get => viewport3D;
@ -221,20 +242,17 @@ namespace CtrEditor.Simulacion
// Caso especial: simBotella usa esfera en BEPU pero se visualiza como cilindro // Caso especial: simBotella usa esfera en BEPU pero se visualiza como cilindro
if (simObj is simBotella botella) if (simObj is simBotella botella)
{ {
System.Diagnostics.Debug.WriteLine($"[3D Create] Creating CYLINDER visualization for simBotella (BEPU uses sphere)");
visual3D = CreateCylinderVisualization(botella.Radius, botella.Height, simObj); visual3D = CreateCylinderVisualization(botella.Radius, botella.Height, simObj);
} }
// Caso especial: simCurve usa múltiples triángulos pero se visualiza como superficie curva // Caso especial: simCurve usa múltiples triángulos pero se visualiza como superficie curva
else if (simObj is simCurve curve) else if (simObj is simCurve curve)
{ {
System.Diagnostics.Debug.WriteLine($"[3D Create] Creating CURVE visualization for simCurve");
visual3D = CreateCurveVisualization(curve); visual3D = CreateCurveVisualization(curve);
} }
else else
{ {
// Para otros objetos, usar la forma real de BEPU // Para otros objetos, usar la forma real de BEPU
var dimensions = GetShapeDimensions(shapeIndex, simObj); var dimensions = GetShapeDimensions(shapeIndex, simObj);
System.Diagnostics.Debug.WriteLine($"[3D Create] Shape type: {dimensions.ShapeType}, Radius: {dimensions.Radius}");
if (dimensions.ShapeType == BepuPhysics.Collidables.Sphere.Id) if (dimensions.ShapeType == BepuPhysics.Collidables.Sphere.Id)
{ {
@ -269,8 +287,6 @@ namespace CtrEditor.Simulacion
// Agregar a la vista 3D y asociar con simBase // Agregar a la vista 3D y asociar con simBase
viewport3D.Children.Add(visual3D); viewport3D.Children.Add(visual3D);
simBaseToModelMap[simObj] = visual3D; simBaseToModelMap[simObj] = visual3D;
System.Diagnostics.Debug.WriteLine($"[3D Create] Successfully created 3D visualization for {simObj.GetType().Name}");
} }
} }
catch (Exception ex) catch (Exception ex)
@ -338,11 +354,25 @@ namespace CtrEditor.Simulacion
{ {
var meshBuilder = new MeshBuilder(); var meshBuilder = new MeshBuilder();
// ✅ NUEVO: Usar directamente los triángulos originales de BEPU (debug real) // ✅ NUEVO: Elegir entre visualización normal o debug según el flag
CreateCurveMeshFromBEPUTriangles(meshBuilder, curve); if (DebugShowIndividualTriangles)
{
CreateCurveDebugMeshWithIndividualTriangles(meshBuilder, curve);
}
else
{
// ✅ Usar directamente los triángulos originales de BEPU (superficie continua)
CreateCurveMeshFromBEPUTriangles(meshBuilder, curve);
}
var geometry = meshBuilder.ToMesh(); var geometry = meshBuilder.ToMesh();
var model = new GeometryModel3D(geometry, GetMaterialForSimBase(curve));
// ✅ NUEVO: Usar material específico para debug si está activo
Material material = DebugShowIndividualTriangles ?
GetDebugMaterialForCurve(curve) :
GetMaterialForSimBase(curve);
var model = new GeometryModel3D(geometry, material);
var visual = new ModelVisual3D(); var visual = new ModelVisual3D();
visual.Content = model; visual.Content = model;
@ -365,8 +395,6 @@ namespace CtrEditor.Simulacion
// Obtener los triángulos originales directamente de BEPU // Obtener los triángulos originales directamente de BEPU
var originalTriangles = curve.GetOriginalTriangles(); var originalTriangles = curve.GetOriginalTriangles();
System.Diagnostics.Debug.WriteLine($"[3D Debug] Creating curve mesh from {originalTriangles.Count} BEPU triangles");
if (originalTriangles.Count == 0) if (originalTriangles.Count == 0)
{ {
System.Diagnostics.Debug.WriteLine($"[3D Debug] WARNING: No triangles found in BEPU curve"); System.Diagnostics.Debug.WriteLine($"[3D Debug] WARNING: No triangles found in BEPU curve");
@ -410,7 +438,6 @@ namespace CtrEditor.Simulacion
meshBuilder.AddQuad(p3Bottom, p1Bottom, p1Top, p3Top); // Lado 3-1 meshBuilder.AddQuad(p3Bottom, p1Bottom, p1Top, p3Top); // Lado 3-1
} }
System.Diagnostics.Debug.WriteLine($"[3D Debug] Successfully created mesh from BEPU triangles");
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -422,6 +449,136 @@ namespace CtrEditor.Simulacion
} }
} }
/// <summary>
/// ✅ NUEVO: Función de debug que muestra triángulos individuales de BEPU
/// Cada triángulo se renderiza de manera separada para poder hacer debug visual
/// </summary>
private void CreateCurveDebugMeshWithIndividualTriangles(MeshBuilder meshBuilder, simCurve curve)
{
try
{
// Obtener los triángulos originales directamente de BEPU
var originalTriangles = curve.GetOriginalTriangles();
if (originalTriangles.Count == 0)
{
System.Diagnostics.Debug.WriteLine($"[3D Debug] WARNING: No triangles found in BEPU curve");
return;
}
System.Diagnostics.Debug.WriteLine($"[3D Debug] Creating debug visualization for {originalTriangles.Count} triangles");
// Altura muy pequeña para mostrar triángulos planos (como en BEPU)
const float debugHeight = 0.02f; // Más bajo que la superficie normal para diferenciarlo
const float triangleSeparation = 0.01f; // Separación pequeña entre triángulos para distinguirlos
// Convertir cada triángulo de BEPU a un triángulo 3D individual
for (int i = 0; i < originalTriangles.Count; i++)
{
var triangle = originalTriangles[i];
if (triangle.Count != 3)
{
System.Diagnostics.Debug.WriteLine($"[3D Debug] WARNING: Invalid triangle {i} with {triangle.Count} vertices");
continue;
}
// Calcular el centro del triángulo para aplicar separación
var center = new System.Numerics.Vector3(
(triangle[0].X + triangle[1].X + triangle[2].X) / 3f,
(triangle[0].Y + triangle[1].Y + triangle[2].Y) / 3f,
0
);
// Aplicar una pequeña separación desde el centro para distinguir triángulos
var offset = center * triangleSeparation;
// Crear triángulo superior (visible desde arriba)
var p1Top = new Point3D(triangle[0].X + offset.X, triangle[0].Y + offset.Y, debugHeight);
var p2Top = new Point3D(triangle[1].X + offset.X, triangle[1].Y + offset.Y, debugHeight);
var p3Top = new Point3D(triangle[2].X + offset.X, triangle[2].Y + offset.Y, debugHeight);
// Crear triángulo inferior (visible desde abajo)
var p1Bottom = new Point3D(triangle[0].X + offset.X, triangle[0].Y + offset.Y, 0);
var p2Bottom = new Point3D(triangle[1].X + offset.X, triangle[1].Y + offset.Y, 0);
var p3Bottom = new Point3D(triangle[2].X + offset.X, triangle[2].Y + offset.Y, 0);
// Agregar triángulo superior (normal hacia arriba)
meshBuilder.AddTriangle(p1Top, p2Top, p3Top);
// Agregar triángulo inferior (normal hacia abajo)
meshBuilder.AddTriangle(p1Bottom, p3Bottom, p2Bottom);
// ✅ OPCIONAL: Agregar bordes/wireframe para mejor visualización del debug
// Crear líneas delgadas en los bordes del triángulo para verlo mejor
const float edgeThickness = 0.005f;
// Borde 1-2
AddDebugEdge(meshBuilder, p1Top, p2Top, p1Bottom, p2Bottom, edgeThickness);
// Borde 2-3
AddDebugEdge(meshBuilder, p2Top, p3Top, p2Bottom, p3Bottom, edgeThickness);
// Borde 3-1
AddDebugEdge(meshBuilder, p3Top, p1Top, p3Bottom, p1Bottom, edgeThickness);
}
System.Diagnostics.Debug.WriteLine($"[3D Debug] Successfully created debug mesh with {originalTriangles.Count} individual triangles");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[3D Debug] ERROR creating debug mesh: {ex.Message}");
// Fallback: mostrar mensaje de error en consola y usar geometría básica
System.Diagnostics.Debug.WriteLine($"[3D Debug] Falling back to basic debug geometry");
CreateBasicDebugGeometry(meshBuilder, curve);
}
}
/// <summary>
/// ✅ NUEVO: Agrega un borde delgado entre dos puntos para debug visual
/// </summary>
private void AddDebugEdge(MeshBuilder meshBuilder, Point3D p1Top, Point3D p2Top, Point3D p1Bottom, Point3D p2Bottom, float thickness)
{
try
{
// Crear un cilindro muy delgado como borde
meshBuilder.AddCylinder(p1Top, p2Top, thickness, 4, false, false);
meshBuilder.AddCylinder(p1Bottom, p2Bottom, thickness, 4, false, false);
meshBuilder.AddCylinder(p1Top, p1Bottom, thickness, 4, false, false);
meshBuilder.AddCylinder(p2Top, p2Bottom, thickness, 4, false, false);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[3D Debug] ERROR adding debug edge: {ex.Message}");
}
}
/// <summary>
/// ✅ NUEVO: Geometría básica de debug cuando fallan otras opciones
/// </summary>
private void CreateBasicDebugGeometry(MeshBuilder meshBuilder, simCurve curve)
{
try
{
// Crear una geometría muy simple que indique que hay un problema
float innerRadius = curve.InnerRadius;
float outerRadius = curve.OuterRadius;
float centerRadius = (innerRadius + outerRadius) / 2f;
// Crear un triángulo básico como indicador de debug
var p1 = new Point3D(centerRadius, 0, 0);
var p2 = new Point3D(centerRadius * Math.Cos(Math.PI/3), centerRadius * Math.Sin(Math.PI/3), 0);
var p3 = new Point3D(centerRadius * Math.Cos(-Math.PI/3), centerRadius * Math.Sin(-Math.PI/3), 0);
meshBuilder.AddTriangle(p1, p2, p3);
System.Diagnostics.Debug.WriteLine($"[3D Debug] Created basic debug geometry as fallback");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[3D Debug] ERROR creating basic debug geometry: {ex.Message}");
}
}
/// <summary> /// <summary>
/// Método fallback que recrea la geometría (mantener por compatibilidad) /// Método fallback que recrea la geometría (mantener por compatibilidad)
/// </summary> /// </summary>
@ -519,23 +676,15 @@ namespace CtrEditor.Simulacion
{ {
dimensionsChanged = !currentDimensions.Equals(lastDimensions); dimensionsChanged = !currentDimensions.Equals(lastDimensions);
// ✅ LOGGING: Debug para curvas
if (simObj is simCurve && dimensionsChanged)
{
System.Diagnostics.Debug.WriteLine($"[3D Update] CURVE dimensions changed! Old: Inner={lastDimensions.InnerRadius}, Outer={lastDimensions.OuterRadius}, Start={lastDimensions.StartAngle}, End={lastDimensions.EndAngle}");
System.Diagnostics.Debug.WriteLine($"[3D Update] CURVE dimensions changed! New: Inner={currentDimensions.InnerRadius}, Outer={currentDimensions.OuterRadius}, Start={currentDimensions.StartAngle}, End={currentDimensions.EndAngle}");
}
} }
else else
{ {
dimensionsChanged = true; // Primera vez dimensionsChanged = true; // Primera vez
System.Diagnostics.Debug.WriteLine($"[3D Update] First time creating geometry for {simObj.GetType().Name}");
} }
// Si las dimensiones cambiaron, recrear la geometría // Si las dimensiones cambiaron, recrear la geometría
if (dimensionsChanged) if (dimensionsChanged)
{ {
System.Diagnostics.Debug.WriteLine($"[3D Update] Recreating geometry for {simObj.GetType().Name}");
RecreateVisualizationGeometry(simObj, visual, currentDimensions); RecreateVisualizationGeometry(simObj, visual, currentDimensions);
lastKnownDimensions[simObj] = currentDimensions; lastKnownDimensions[simObj] = currentDimensions;
} }
@ -595,7 +744,6 @@ namespace CtrEditor.Simulacion
dimensions.StartAngle = curve.StartAngle; dimensions.StartAngle = curve.StartAngle;
dimensions.EndAngle = curve.EndAngle; dimensions.EndAngle = curve.EndAngle;
dimensions.ShapeType = -1; // Tipo especial para curvas dimensions.ShapeType = -1; // Tipo especial para curvas
System.Diagnostics.Debug.WriteLine($"[3D GetDimensions] Curve - Inner: {curve.InnerRadius}, Outer: {curve.OuterRadius}, Start: {curve.StartAngle}, End: {curve.EndAngle}");
return dimensions; return dimensions;
} }
@ -668,17 +816,21 @@ namespace CtrEditor.Simulacion
// Caso especial: simCurve necesita recreación completa de geometría // Caso especial: simCurve necesita recreación completa de geometría
else if (simObj is simCurve curve) else if (simObj is simCurve curve)
{ {
System.Diagnostics.Debug.WriteLine($"[3D Recreate] Creating CURVE mesh from BEPU triangles - Inner: {curve.InnerRadius}, Outer: {curve.OuterRadius}, Start: {curve.StartAngle}, End: {curve.EndAngle}");
var meshBuilder = new MeshBuilder(); var meshBuilder = new MeshBuilder();
// ✅ NUEVO: Usar directamente los triángulos de BEPU (debug real) // ✅ CORREGIDO: Respetar el flag de debug también en recreación
CreateCurveMeshFromBEPUTriangles(meshBuilder, curve); if (DebugShowIndividualTriangles)
{
CreateCurveDebugMeshWithIndividualTriangles(meshBuilder, curve);
newMaterial = GetDebugMaterialForCurve(curve);
}
else
{
CreateCurveMeshFromBEPUTriangles(meshBuilder, curve);
newMaterial = GetMaterialForSimBase(simObj);
}
newGeometry = meshBuilder.ToMesh(); newGeometry = meshBuilder.ToMesh();
newMaterial = GetMaterialForSimBase(simObj);
System.Diagnostics.Debug.WriteLine($"[3D Recreate] CURVE mesh created successfully with {newGeometry?.Positions?.Count ?? 0} vertices");
} }
else if (dimensions.ShapeType == BepuPhysics.Collidables.Sphere.Id) else if (dimensions.ShapeType == BepuPhysics.Collidables.Sphere.Id)
{ {
@ -711,7 +863,6 @@ namespace CtrEditor.Simulacion
{ {
geometryModel.Geometry = newGeometry; geometryModel.Geometry = newGeometry;
geometryModel.Material = newMaterial; geometryModel.Material = newMaterial;
System.Diagnostics.Debug.WriteLine($"[3D Recreate] Successfully recreated geometry for {simObj.GetType().Name}");
} }
} }
catch (Exception ex) catch (Exception ex)
@ -730,6 +881,25 @@ namespace CtrEditor.Simulacion
lastKnownDimensions.Clear(); lastKnownDimensions.Clear();
} }
/// <summary>
/// ✅ NUEVO: Material específico para debug de curvas
/// </summary>
/// <param name="curve">Curva en modo debug</param>
/// <returns>Material especial para visualización de debug</returns>
private Material GetDebugMaterialForCurve(simCurve curve)
{
// Material wireframe semi-transparente para debug
// Color naranja brillante para que sea muy visible
var debugBrush = new SolidColorBrush(Color.FromRgb(255, 165, 0)); // Naranja
debugBrush.Opacity = 0.7; // 70% opacidad para ver superposiciones
return MaterialHelper.CreateMaterial(
debugBrush,
specularPower: 20, // Menos reflectante para mejor visibilidad
ambient: 250 // Más ambiente para que se vea bien en todas las condiciones
);
}
/// <summary> /// <summary>
/// Función centralizada para obtener el material apropiado según el tipo de simBase /// Función centralizada para obtener el material apropiado según el tipo de simBase
/// </summary> /// </summary>
@ -837,6 +1007,119 @@ namespace CtrEditor.Simulacion
} }
} }
/// <summary>
/// ✅ NUEVO: Activa o desactiva el modo debug para mostrar triángulos individuales de curvas
/// </summary>
/// <param name="enableDebug">True para activar debug, false para modo normal</param>
/// <param name="forceRefresh">True para forzar actualización inmediata de todas las curvas</param>
public void SetDebugTrianglesMode(bool enableDebug, bool forceRefresh = true)
{
bool wasChanged = DebugShowIndividualTriangles != enableDebug;
DebugShowIndividualTriangles = enableDebug;
System.Diagnostics.Debug.WriteLine($"[3D Debug] Debug triangles mode: {(enableDebug ? "ENABLED" : "DISABLED")}");
if (wasChanged && forceRefresh)
{
RefreshCurveVisualizations();
}
}
/// <summary>
/// ✅ NUEVO: Fuerza la regeneración de todas las visualizaciones de curvas
/// Útil cuando se cambia el modo debug
/// </summary>
public void RefreshCurveVisualizations()
{
if (simulationManager?.Cuerpos == null)
return;
try
{
System.Diagnostics.Debug.WriteLine($"[3D Debug] Refreshing curve visualizations...");
// Encontrar todas las curvas y forzar su regeneración
var curvesToRefresh = simulationManager.Cuerpos.OfType<simCurve>().ToList();
foreach (var curve in curvesToRefresh)
{
// Remover las dimensiones conocidas para forzar recreación
lastKnownDimensions.Remove(curve);
// Forzar actualización de la visualización
if (simBaseToModelMap.ContainsKey(curve))
{
UpdateVisualizationFromSimBase(curve);
}
}
System.Diagnostics.Debug.WriteLine($"[3D Debug] Refreshed {curvesToRefresh.Count} curve visualizations");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[3D Debug] ERROR refreshing curve visualizations: {ex.Message}");
}
}
/// <summary>
/// ✅ NUEVO: Obtiene el estado actual del modo debug
/// </summary>
/// <returns>True si el modo debug está activo</returns>
public bool IsDebugTrianglesModeEnabled()
{
return DebugShowIndividualTriangles;
}
/// <summary>
/// ✅ NUEVO: Obtiene información detallada de debug sobre los triángulos de una curva
/// Útil para debug sin cambiar la visualización
/// </summary>
/// <param name="curve">Curva para analizar</param>
/// <returns>Información de debug como string</returns>
public string GetCurveDebugInfo(simCurve curve)
{
if (curve == null)
return "ERROR: Curva es null";
try
{
var triangles = curve.GetOriginalTriangles();
var debugInfo = new System.Text.StringBuilder();
debugInfo.AppendLine($"=== DEBUG INFO PARA CURVA ===");
debugInfo.AppendLine($"Parámetros de curva:");
debugInfo.AppendLine($" - Radio Interior: {curve.InnerRadius}");
debugInfo.AppendLine($" - Radio Exterior: {curve.OuterRadius}");
debugInfo.AppendLine($" - Ángulo Inicio: {curve.StartAngle} rad ({curve.StartAngle * 180 / Math.PI:F1}°)");
debugInfo.AppendLine($" - Ángulo Fin: {curve.EndAngle} rad ({curve.EndAngle * 180 / Math.PI:F1}°)");
debugInfo.AppendLine($"");
debugInfo.AppendLine($"Triángulos en BEPU: {triangles.Count}");
for (int i = 0; i < Math.Min(triangles.Count, 10); i++) // Mostrar máximo 10 triángulos
{
var triangle = triangles[i];
debugInfo.AppendLine($" Triángulo {i + 1}:");
debugInfo.AppendLine($" P1: ({triangle[0].X:F3}, {triangle[0].Y:F3}, {triangle[0].Z:F3})");
debugInfo.AppendLine($" P2: ({triangle[1].X:F3}, {triangle[1].Y:F3}, {triangle[1].Z:F3})");
debugInfo.AppendLine($" P3: ({triangle[2].X:F3}, {triangle[2].Y:F3}, {triangle[2].Z:F3})");
}
if (triangles.Count > 10)
{
debugInfo.AppendLine($" ... y {triangles.Count - 10} triángulos más");
}
debugInfo.AppendLine($"");
debugInfo.AppendLine($"Modo debug actual: {(DebugShowIndividualTriangles ? "ACTIVADO" : "DESACTIVADO")}");
return debugInfo.ToString();
}
catch (Exception ex)
{
return $"ERROR obteniendo info de debug: {ex.Message}";
}
}
/// <summary> /// <summary>
/// Carga el estado guardado de la cámara desde EstadoPersistente /// Carga el estado guardado de la cámara desde EstadoPersistente
/// </summary> /// </summary>
@ -854,7 +1137,6 @@ namespace CtrEditor.Simulacion
FieldOfView = cameraSettings.FieldOfView FieldOfView = cameraSettings.FieldOfView
}; };
System.Diagnostics.Debug.WriteLine($"[3D Camera] Loaded camera state from persistent storage");
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -893,7 +1175,6 @@ namespace CtrEditor.Simulacion
cameraSettings.FieldOfView = camera.FieldOfView; cameraSettings.FieldOfView = camera.FieldOfView;
EstadoPersistente.Instance.GuardarEstado(); EstadoPersistente.Instance.GuardarEstado();
System.Diagnostics.Debug.WriteLine($"[3D Camera] Saved camera state to persistent storage");
} }
} }
catch (Exception ex) catch (Exception ex)
@ -916,7 +1197,6 @@ namespace CtrEditor.Simulacion
viewport3D.MouseUp += (sender, e) => SaveCameraState(); viewport3D.MouseUp += (sender, e) => SaveCameraState();
viewport3D.MouseWheel += (sender, e) => SaveCameraState(); viewport3D.MouseWheel += (sender, e) => SaveCameraState();
System.Diagnostics.Debug.WriteLine($"[3D Camera] Subscribed to camera change events");
} }
catch (Exception ex) catch (Exception ex)
{ {