From 62b45ebf1cb7a82e48e7929d63f6337a777c1131 Mon Sep 17 00:00:00 2001 From: Miguel Date: Sun, 6 Jul 2025 21:29:53 +0200 Subject: [PATCH] =?UTF-8?q?Se=20implementaron=20mejoras=20en=20la=20gesti?= =?UTF-8?q?=C3=B3n=20de=20im=C3=A1genes=20de=20fondo=20en=20el=20viewport?= =?UTF-8?q?=203D,=20permitiendo=20agregar,=20remover=20y=20sincronizar=20i?= =?UTF-8?q?m=C3=A1genes=20de=20fondo=20con=20la=20visualizaci=C3=B3n=203D.?= =?UTF-8?q?=20Se=20corrigieron=20las=20convenciones=20de=20posicionamiento?= =?UTF-8?q?=20y=20escalado=20para=20asegurar=20coherencia=20visual=20entre?= =?UTF-8?q?=20el=20canvas=202D=20y=20la=20representaci=C3=B3n=203D.=20Adem?= =?UTF-8?q?=C3=A1s,=20se=20ajustaron=20los=20coeficientes=20de=20fricci?= =?UTF-8?q?=C3=B3n=20en=20la=20simulaci=C3=B3n=20de=20botellas,=20optimiza?= =?UTF-8?q?ndo=20el=20comportamiento=20en=20contactos=20y=20curvas.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MainWindow.xaml.cs | 73 +++++++++++++++++- Simulacion/BEPU.cs | 10 +-- Simulacion/BEPUVisualization3D.cs | 118 ++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 7 deletions(-) diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index fd8c16c..8bb6f04 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -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(); } + /// + /// ✅ NUEVO: Establece la imagen de fondo en el viewport 3D + /// + /// Ruta de la imagen de fondo + public void SetBackgroundImage3D(string imagePath) + { + if (_visualization3DManager != null && imagenDeFondo?.Source is BitmapImage bitmap) + { + _visualization3DManager.SetBackgroundImage(imagePath, bitmap.Width, bitmap.Height); + } + } + + /// + /// ✅ NUEVO: Remueve la imagen de fondo del viewport 3D + /// + public void RemoveBackgroundImage3D() + { + _visualization3DManager?.RemoveBackgroundImage(); + } + + /// + /// ✅ 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 + /// + 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 diff --git a/Simulacion/BEPU.cs b/Simulacion/BEPU.cs index ce07f6e..f211389 100644 --- a/Simulacion/BEPU.cs +++ b/Simulacion/BEPU.cs @@ -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 } diff --git a/Simulacion/BEPUVisualization3D.cs b/Simulacion/BEPUVisualization3D.cs index a4a1979..2c8bba9 100644 --- a/Simulacion/BEPUVisualization3D.cs +++ b/Simulacion/BEPUVisualization3D.cs @@ -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 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(); } /// @@ -1578,6 +1585,117 @@ namespace CtrEditor.Simulacion System.Diagnostics.Debug.WriteLine($"[3D Barrera] ❌ ERROR recreando geometría: {ex.Message}"); } } + + /// + /// ✅ 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); + /// + /// Ruta absoluta de la imagen de fondo + /// Ancho del canvas WPF en píxeles + /// Alto del canvas WPF en píxeles + 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}"); + } + } + + /// + /// ✅ NUEVO: Remueve la imagen de fondo del viewport 3D + /// + 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