diff --git a/Documentation/MemoriadeEvolucion.md b/Documentation/MemoriadeEvolucion.md index 29ea79b..332f9f4 100644 --- a/Documentation/MemoriadeEvolucion.md +++ b/Documentation/MemoriadeEvolucion.md @@ -28,3 +28,5 @@ simTransporte : Es un box por donde las botellas pueden desplazarse usando un tr * Se ha implementado un sistema de animaciones automáticas usando StoryBoard de WPF para los transportes en movimiento. Los transportes activos muestran una animación continua que combina: (1) rotación sutil muy lenta alrededor del eje Z (20 segundos por vuelta completa) y (2) pulsación cíclica del color del material (1.5 segundos por ciclo). Las animaciones se crean y destruyen automáticamente según el estado del transporte, sin necesidad de actualización manual en cada frame. El sistema gestiona las animaciones activas en un diccionario y las limpia correctamente cuando se eliminan objetos. Se resolvió el problema de `InvalidOperationException` al animar brushes inmutables creando una función `CreateAnimatableMaterial` que genera materiales específicamente diseñados para ser animados sin estar "frozen", proporcionando una experiencia visual fluida y eficiente. +* Se ha mejorado el sistema de guías curvas (`ucTransporteCurvaGuias`) para incluir apertura en cono en los extremos de entrada y salida. Se agregó el parámetro `AnguloAperturaGuias` (por defecto 5 grados) que permite configurar la apertura modificando los radios de las guías en los puntos extremos. En lugar de cambiar ángulos, se reduce el radio de la guía superior (externa) y se aumenta el radio de la guía inferior (interna) en los segmentos inicial y final, creando naturalmente la apertura en cono. La modificación del radio se calcula usando `Math.Sin(anguloApertura)` para obtener el desplazamiento apropiado. Esta apertura facilita la entrada y salida de botellas del transporte curvo, reduciendo atascos y mejorando el flujo de materiales manteniendo la continuidad geométrica de las guías. + diff --git a/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs b/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs index d9f384e..f0db41e 100644 --- a/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs +++ b/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs @@ -87,6 +87,7 @@ namespace CtrEditor.ObjetosSim [property: Category("Información")] [property: Name("Salida Filtro")] bool filter_Output; + [ObservableProperty] [property: Description("Cantidad de botellas generadas por hora")] [property: Category("Configuración")] @@ -113,11 +114,32 @@ namespace CtrEditor.ObjetosSim [property: Name("Velocidad Actual (%)")] private float velocidad_actual_percentual; + [ObservableProperty] + [property: Description("Distancia libre minima sin botellas sobre el transporte para colocar otra botella")] + [property: Category("Simulación")] + [property: Name("Diametro libre minimo")] + private float distancia_libre; + + [ObservableProperty] [property: Description("Diámetro de las botellas generadas")] [property: Category("Configuración")] [property: Name("Diámetro Botella")] private float diametro_botella; + + public osBottGenerator() + { + Ancho = 0.40f; + Alto = 0.40f; + Angulo = 0; + Velocidad_actual_percentual = 100; + Diametro_botella = 0.1f; + Botellas_hora = 10000; + Consenso = true; + Distancia_libre = 0.1f; + } + + public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) { if (Consenso_NC) @@ -128,7 +150,7 @@ namespace CtrEditor.ObjetosSim private bool HayEspacioParaNuevaBotella(float X, float Y) { - float radioMinimo = Diametro_botella / 4; // Distancia mínima entre centros + float radioMinimo = Distancia_libre; // Distancia mínima entre centros float radioMinimoCuadrado = radioMinimo * radioMinimo; // Buscar todas las botellas cercanas diff --git a/ObjetosSim/Estaticos/ucGuia.xaml.cs b/ObjetosSim/Estaticos/ucGuia.xaml.cs index 05be73e..4b24a02 100644 --- a/ObjetosSim/Estaticos/ucGuia.xaml.cs +++ b/ObjetosSim/Estaticos/ucGuia.xaml.cs @@ -48,7 +48,7 @@ namespace CtrEditor.ObjetosSim // ✅ SISTEMA INTELIGENTE: Solo recrear si las dimensiones han cambiado if (HasGuideDimensionsChanged(SimGeometria, Ancho, AltoGuia)) { - System.Diagnostics.Debug.WriteLine($"[osGuia] Recreando guía por cambio de dimensiones: {Ancho}x{AltoGuia}"); + //System.Diagnostics.Debug.WriteLine($"[osGuia] Recreando guía por cambio de dimensiones: {Ancho}x{AltoGuia}"); // ✅ RECREAR COMPLETAMENTE: Las dimensiones cambiaron SimGeometria.Create(Ancho, AltoGuia, topLeft, Angulo); @@ -56,7 +56,7 @@ namespace CtrEditor.ObjetosSim } else { - System.Diagnostics.Debug.WriteLine($"[osGuia] Solo actualizando posición/rotación: Left={Left}, Top={Top}, Angulo={Angulo}"); + // System.Diagnostics.Debug.WriteLine($"[osGuia] Solo actualizando posición/rotación: Left={Left}, Top={Top}, Angulo={Angulo}"); // ✅ SOLO ACTUALIZAR POSICIÓN/ROTACIÓN: Usar dimensiones reales para conversión correcta SimGeometria.UpdateFromWpfParameters(topLeft, Angulo, Ancho, AltoGuia); diff --git a/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs b/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs index c48b84e..19feab8 100644 --- a/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs +++ b/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs @@ -134,6 +134,17 @@ namespace CtrEditor.ObjetosSim ActualizarGeometrias(); } + [ObservableProperty] + [property: Category("Configuración")] + [property: Description("Ángulo de apertura en grados para los extremos de las guías")] + [property: Name("Ángulo Apertura Guías")] + private float anguloAperturaGuias = 5f; + + partial void OnAnguloAperturaGuiasChanged(float value) + { + ActualizarGeometrias(); + } + [ObservableProperty] [property: Category("Configuración")] [property: Description("Distancia de separación de las guías desde el borde")] @@ -336,6 +347,7 @@ namespace CtrEditor.ObjetosSim float anguloInicioRad = simBase.GradosARadianes(Angulo); float anguloFinalRad = simBase.GradosARadianes(AnguloFinal); float rangoAngular = anguloFinalRad - anguloInicioRad; + float anguloAperturaRad = simBase.GradosARadianes(AnguloAperturaGuias); // Calcular el paso angular entre segmentos float pasoAngular = rangoAngular / NumeroSegmentosGuias; @@ -349,14 +361,27 @@ namespace CtrEditor.ObjetosSim float angulo1 = anguloInicioRad + i * pasoAngular; float angulo2 = anguloInicioRad + (i + 1) * pasoAngular; + // Calcular radios ajustados para crear apertura en cono + // Para guía superior: reducir radio en los extremos para crear apertura + float radio1 = radioGuiaSuperior; + float radio2 = radioGuiaSuperior; + + // Calcular reducción del radio basada en el ángulo de apertura + float reduccionRadio = radioGuiaSuperior * (float)Math.Sin(anguloAperturaRad/10); + + if (InvertirDireccion && i == 0) // Primer segmento + radio1 += reduccionRadio; + if (!InvertirDireccion && i == NumeroSegmentosGuias - 1) // Último segmento + radio2 += reduccionRadio; + Vector2 punto1 = new Vector2( - radioGuiaSuperior * (float)Math.Cos(angulo1), - radioGuiaSuperior * (float)Math.Sin(angulo1) + radio1 * (float)Math.Cos(angulo1), + radio1 * (float)Math.Sin(angulo1) ); Vector2 punto2 = new Vector2( - radioGuiaSuperior * (float)Math.Cos(angulo2), - radioGuiaSuperior * (float)Math.Sin(angulo2) + radio2 * (float)Math.Cos(angulo2), + radio2 * (float)Math.Sin(angulo2) ); // Ajustar por la posición del objeto @@ -374,14 +399,27 @@ namespace CtrEditor.ObjetosSim float angulo1 = anguloInicioRad + i * pasoAngular; float angulo2 = anguloInicioRad + (i + 1) * pasoAngular; + // Calcular radios ajustados para crear apertura en cono + // Para guía inferior: aumentar radio en los extremos para crear apertura + float radio1 = radioGuiaInferior; + float radio2 = radioGuiaInferior; + + // Calcular aumento del radio basada en el ángulo de apertura + float aumentoRadio = radioGuiaInferior * (float)Math.Sin(anguloAperturaRad/10); + + if (InvertirDireccion && i == 0) // Primer segmento + radio1 -= aumentoRadio; + if (InvertirDireccion && i == NumeroSegmentosGuias - 1) // Último segmento + radio2 -= aumentoRadio; + Vector2 punto1 = new Vector2( - radioGuiaInferior * (float)Math.Cos(angulo1), - radioGuiaInferior * (float)Math.Sin(angulo1) + radio1 * (float)Math.Cos(angulo1), + radio1 * (float)Math.Sin(angulo1) ); Vector2 punto2 = new Vector2( - radioGuiaInferior * (float)Math.Cos(angulo2), - radioGuiaInferior * (float)Math.Sin(angulo2) + radio2 * (float)Math.Cos(angulo2), + radio2 * (float)Math.Sin(angulo2) ); // Ajustar por la posición del objeto diff --git a/Simulacion/BEPU.cs b/Simulacion/BEPU.cs index 75de895..bd92aa6 100644 --- a/Simulacion/BEPU.cs +++ b/Simulacion/BEPU.cs @@ -865,7 +865,7 @@ namespace CtrEditor.Simulacion if (simulation.Bodies.BodyExists(cuerpo.BodyHandle)) { // cuerpo.LimitRotationToXYPlane(); - simulation.Awakener.AwakenBody(cuerpo.BodyHandle); + // simulation.Awakener.AwakenBody(cuerpo.BodyHandle); } } catch (Exception ex) diff --git a/Simulacion/BEPUVisualization3D.cs b/Simulacion/BEPUVisualization3D.cs index 1c34c0d..a4a1979 100644 --- a/Simulacion/BEPUVisualization3D.cs +++ b/Simulacion/BEPUVisualization3D.cs @@ -457,7 +457,7 @@ namespace CtrEditor.Simulacion } // ✅ CORREGIDO: Usar altura más visible y verificar coordenadas - const float curveHeight = 0.02f; // 2cm de altura para que sea claramente visible + const float curveHeight = 0.0f; // 0.02f; // 2cm de altura para que sea claramente visible int triangleCount = 0; foreach (var triangle in localTriangles)