Se implementaron mejoras en la gestión de imágenes de fondo en el viewport 3D, permitiendo agregar, remover y sincronizar imágenes de fondo con la visualización 3D. Se corrigieron las convenciones de posicionamiento y escalado para asegurar coherencia visual entre el canvas 2D y la representación 3D. Además, se ajustaron los coeficientes de fricción en la simulación de botellas, optimizando el comportamiento en contactos y curvas.

This commit is contained in:
Miguel 2025-07-06 21:29:53 +02:00
parent f7f49d5df0
commit 62b45ebf1c
3 changed files with 194 additions and 7 deletions

View File

@ -107,6 +107,18 @@ namespace CtrEditor
// Conectar el manager 3D con el simulation manager (orden correcto de inicialización)
viewModel.simulationManager.Visualization3DManager = _visualization3DManager;
// ✅ NUEVO: Si ya hay una imagen de fondo cargada, agregarla al viewport 3D
if (imagenDeFondo?.Source is BitmapImage existingImage)
{
// Necesitamos la ruta original de la imagen, usar el UriSource si está disponible
var imageUri = existingImage.UriSource?.LocalPath ?? existingImage.UriSource?.ToString();
if (!string.IsNullOrEmpty(imageUri))
{
_visualization3DManager.SetBackgroundImage(imageUri, existingImage.PixelWidth, existingImage.PixelHeight);
System.Diagnostics.Debug.WriteLine($"[3D Background] ✅ Imagen existente agregada al viewport 3D: {imageUri}");
}
}
}
}
@ -168,6 +180,12 @@ namespace CtrEditor
Canvas.SetLeft(imagenDeFondo, 0);
Canvas.SetTop(imagenDeFondo, 0);
// ✅ NUEVO: Agregar la imagen de fondo al viewport 3D con la misma escala
if (_visualization3DManager != null)
{
_visualization3DManager.SetBackgroundImage(imagePath, bitmap.Width, bitmap.Height);
}
// Eliminar solo los ROIs, no la imagen de fondo ni el área de panning
for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--)
{
@ -367,8 +385,6 @@ namespace CtrEditor
}
}
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
// Only force canvas focus if PanelEdicion doesn't have focus
@ -539,6 +555,59 @@ namespace CtrEditor
_objectManager.ClearUndoHistory();
}
/// <summary>
/// ✅ NUEVO: Establece la imagen de fondo en el viewport 3D
/// </summary>
/// <param name="imagePath">Ruta de la imagen de fondo</param>
public void SetBackgroundImage3D(string imagePath)
{
if (_visualization3DManager != null && imagenDeFondo?.Source is BitmapImage bitmap)
{
_visualization3DManager.SetBackgroundImage(imagePath, bitmap.Width, bitmap.Height);
}
}
/// <summary>
/// ✅ NUEVO: Remueve la imagen de fondo del viewport 3D
/// </summary>
public void RemoveBackgroundImage3D()
{
_visualization3DManager?.RemoveBackgroundImage();
}
/// <summary>
/// ✅ NUEVO: Sincroniza la imagen de fondo existente con el viewport 3D
/// Útil cuando se necesita actualizar la imagen 3D basándose en la imagen 2D actual
/// </summary>
public void SyncBackgroundImage3D()
{
if (_visualization3DManager == null) return;
if (imagenDeFondo?.Source is BitmapImage existingImage)
{
// Intentar obtener la ruta de la imagen desde diferentes fuentes
var imageUri = existingImage.UriSource?.LocalPath ??
existingImage.UriSource?.ToString() ??
existingImage.BaseUri?.LocalPath;
if (!string.IsNullOrEmpty(imageUri))
{
_visualization3DManager.SetBackgroundImage(imageUri, existingImage.PixelWidth, existingImage.PixelHeight);
System.Diagnostics.Debug.WriteLine($"[3D Background] ✅ Imagen sincronizada con viewport 3D");
}
else
{
System.Diagnostics.Debug.WriteLine($"[3D Background] ⚠️ No se pudo obtener la ruta de la imagen para sincronizar");
}
}
else
{
// Si no hay imagen cargada, remover la imagen de fondo 3D
_visualization3DManager.RemoveBackgroundImage();
System.Diagnostics.Debug.WriteLine($"[3D Background] ✅ Imagen de fondo 3D removida (no hay imagen 2D)");
}
}
private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
// Aceptar el evento si viene del canvas o de la imagen de fondo

View File

@ -164,15 +164,15 @@ namespace CtrEditor.Simulacion
}
botella.isOnBrakeTransport = true;
pairMaterial.FrictionCoefficient = 4f;
pairMaterial.MaximumRecoveryVelocity = 0f;
pairMaterial.SpringSettings = new SpringSettings(120, 8f);
pairMaterial.FrictionCoefficient = 2f;
pairMaterial.MaximumRecoveryVelocity = 0.1f;
pairMaterial.SpringSettings = new SpringSettings(80, 1f);
}
else
{
botella.isOnBrakeTransport = false;
// ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
pairMaterial.FrictionCoefficient = CalculateTransportFriction(botella, transport, botellaCollidable);
pairMaterial.FrictionCoefficient = 0.3f; // CalculateTransportFriction(botella, transport, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.1f;
pairMaterial.SpringSettings = new SpringSettings(80, 1f);
}
@ -193,7 +193,7 @@ namespace CtrEditor.Simulacion
// ✅ NUEVO: Usar fricción dinámica basada en deslizamiento
var curve = curveA ?? curveB;
pairMaterial.FrictionCoefficient = CalculateCurveFriction(botella, curve, botellaCollidable);
pairMaterial.FrictionCoefficient = 0.3f; // CalculateCurveFriction(botella, curve, botellaCollidable);
pairMaterial.MaximumRecoveryVelocity = 0.1f;
pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Colision con la cinta por gravedad
}

View File

@ -10,6 +10,7 @@ using System.Linq;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media.Imaging;
namespace CtrEditor.Simulacion
{
@ -80,6 +81,9 @@ namespace CtrEditor.Simulacion
// ✅ NUEVO: Diccionario para gestionar animaciones activas
private Dictionary<simBase, Storyboard> activeAnimations;
// ✅ NUEVO: Referencia al modelo visual de la imagen de fondo
private ModelVisual3D? _backgroundImageVisual;
// ✅ CORREGIDO: Flag de debug para mostrar triángulos individuales de curvas (true temporalmente para verificar)
public static bool DebugShowIndividualTriangles { get; set; } = false;
@ -847,6 +851,9 @@ namespace CtrEditor.Simulacion
}
simBaseToModelMap.Clear();
lastKnownDimensions.Clear();
// ✅ NUEVO: También limpiar la imagen de fondo
RemoveBackgroundImage();
}
/// <summary>
@ -1578,6 +1585,117 @@ namespace CtrEditor.Simulacion
System.Diagnostics.Debug.WriteLine($"[3D Barrera] ❌ ERROR recreando geometría: {ex.Message}");
}
}
/// <summary>
/// ✅ NUEVO: Agrega la imagen de fondo como un plano 2D estático en el viewport 3D
/// con la misma escala que el canvas WPF usando las convenciones WPF-BEPU correctas
///
/// Esta funcionalidad permite tener coherencia visual entre el canvas 2D WPF y la visualización 3D:
/// - La imagen se posiciona en el plano XY con Z=0
/// - Usa el sistema de conversión PixelToMeter para mantener la escala correcta
/// - Aplica las conversiones WPF-BEPU: WPF (x,y) -> BEPU (x,-y)
/// - Se aplica como textura difusa en un rectángulo plano
/// - Respeta las convenciones: WPF Y hacia abajo, BEPU Y hacia arriba
///
/// Ejemplo de uso:
/// SetBackgroundImage(@"C:\imagen.png", 1920, 1080);
/// </summary>
/// <param name="imagePath">Ruta absoluta de la imagen de fondo</param>
/// <param name="canvasWidth">Ancho del canvas WPF en píxeles</param>
/// <param name="canvasHeight">Alto del canvas WPF en píxeles</param>
public void SetBackgroundImage(string imagePath, double canvasWidth, double canvasHeight)
{
try
{
// Remover imagen de fondo anterior si existe
RemoveBackgroundImage();
// Convertir dimensiones de píxeles a metros usando el sistema de conversión
float widthInMeters = PixelToMeter.Instance.calc.PixelsToMeters((float)canvasWidth);
float heightInMeters = PixelToMeter.Instance.calc.PixelsToMeters((float)canvasHeight);
// Crear la geometría del plano
var meshBuilder = new MeshBuilder();
// ✅ CORREGIDO: Usar convenciones WPF-BEPU correctas
// En WPF: (0,0) = esquina superior izquierda, Y hacia abajo
// En BEPU: Y hacia arriba, entonces convertimos WPF (x,y) -> BEPU (x,-y)
// Definir las esquinas en coordenadas WPF
var wpfTopLeft = new System.Numerics.Vector2(0, 0);
var wpfTopRight = new System.Numerics.Vector2(widthInMeters, 0);
var wpfBottomRight = new System.Numerics.Vector2(widthInMeters, heightInMeters);
var wpfBottomLeft = new System.Numerics.Vector2(0, heightInMeters);
// Convertir a coordenadas BEPU usando CoordinateConverter
var bepuTopLeft = CoordinateConverter.WpfToBepuVector2(wpfTopLeft);
var bepuTopRight = CoordinateConverter.WpfToBepuVector2(wpfTopRight);
var bepuBottomRight = CoordinateConverter.WpfToBepuVector2(wpfBottomRight);
var bepuBottomLeft = CoordinateConverter.WpfToBepuVector2(wpfBottomLeft);
// Crear los puntos 3D con Z=0
var p1 = new Point3D(bepuTopLeft.X, bepuTopLeft.Y, 0); // Esquina superior izquierda WPF
var p2 = new Point3D(bepuTopRight.X, bepuTopRight.Y, 0); // Esquina superior derecha WPF
var p3 = new Point3D(bepuBottomRight.X, bepuBottomRight.Y, 0); // Esquina inferior derecha WPF
var p4 = new Point3D(bepuBottomLeft.X, bepuBottomLeft.Y, 0); // Esquina inferior izquierda WPF
// ✅ CORREGIDO: Crear quad con orientación correcta
// Orden antihorario para normal hacia arriba (visible desde arriba)
meshBuilder.AddQuad(p1, p2, p3, p4);
// Crear el material con la imagen como textura
var imageSource = new BitmapImage(new Uri(imagePath, UriKind.Absolute));
var imageBrush = new ImageBrush(imageSource)
{
Stretch = Stretch.Fill,
TileMode = TileMode.None
};
var frontMaterial = new DiffuseMaterial(imageBrush);
var backMaterial = new DiffuseMaterial(imageBrush); // ✅ NUEVO: Material para la cara trasera
// Crear el modelo 3D con material en ambas caras
var geometry = meshBuilder.ToMesh();
var model = new GeometryModel3D(geometry, frontMaterial)
{
BackMaterial = backMaterial // ✅ NUEVO: Hace visible desde ambos lados
};
// Crear el visual 3D
_backgroundImageVisual = new ModelVisual3D { Content = model };
// Agregar al viewport
viewport3D.Children.Add(_backgroundImageVisual);
System.Diagnostics.Debug.WriteLine($"[3D Background] ✅ Imagen de fondo agregada con convenciones WPF-BEPU: {widthInMeters:F2}m x {heightInMeters:F2}m");
System.Diagnostics.Debug.WriteLine($"[3D Background] WPF (0,0) -> BEPU ({bepuTopLeft.X:F2},{bepuTopLeft.Y:F2})");
System.Diagnostics.Debug.WriteLine($"[3D Background] WPF ({widthInMeters:F2},{heightInMeters:F2}) -> BEPU ({bepuBottomRight.X:F2},{bepuBottomRight.Y:F2})");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[3D Background] ❌ ERROR agregando imagen de fondo: {ex.Message}");
}
}
/// <summary>
/// ✅ NUEVO: Remueve la imagen de fondo del viewport 3D
/// </summary>
public void RemoveBackgroundImage()
{
try
{
if (_backgroundImageVisual != null && viewport3D.Children.Contains(_backgroundImageVisual))
{
viewport3D.Children.Remove(_backgroundImageVisual);
System.Diagnostics.Debug.WriteLine($"[3D Background] ✅ Imagen de fondo removida");
}
_backgroundImageVisual = null;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[3D Background] ❌ ERROR removiendo imagen de fondo: {ex.Message}");
}
}
}
public enum CameraView