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