From 5f680b3a7a34bc2a2581a32f7c657dca2a2e399a Mon Sep 17 00:00:00 2001
From: Miguel <miguel.vera.csa@gmail.com>
Date: Sun, 23 Feb 2025 21:22:42 +0100
Subject: [PATCH] Mejorado de las curvas. Se creo un overlapPercentage para las
 curvas.

---
 CtrEditor.code-workspace                      |  11 ++
 MainViewModel.cs                              |   2 +-
 ObjetosSim/Emuladores/ucBottGenerator.xaml.cs | 115 ++++++++----------
 ObjetosSim/Estaticos/ucVMmotorSim.xaml.cs     |  10 +-
 Simulacion/Aether.cs                          |  89 ++++++++++++--
 5 files changed, 148 insertions(+), 79 deletions(-)
 create mode 100644 CtrEditor.code-workspace

diff --git a/CtrEditor.code-workspace b/CtrEditor.code-workspace
new file mode 100644
index 0000000..c0cd4b5
--- /dev/null
+++ b/CtrEditor.code-workspace
@@ -0,0 +1,11 @@
+{
+	"folders": [
+		{
+			"path": "."
+		},
+		{
+			"path": "../Libraries/LibS7Adv"
+		}
+	],
+	"settings": {}
+}
\ No newline at end of file
diff --git a/MainViewModel.cs b/MainViewModel.cs
index f9b6018..4f38103 100644
--- a/MainViewModel.cs
+++ b/MainViewModel.cs
@@ -746,7 +746,7 @@ namespace CtrEditor
             }
 
             stopwatch.Stop(); // Stop measuring time
-            Debug.WriteLine($"OnRefreshEvent: {stopwatch.Elapsed.TotalMilliseconds} ms");
+           // Debug.WriteLine($"OnRefreshEvent: {stopwatch.Elapsed.TotalMilliseconds} ms");
         }
 
         private void OpenWorkDirectory()
diff --git a/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs b/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs
index 4c25a79..e73cb3a 100644
--- a/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs
+++ b/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs
@@ -14,46 +14,36 @@ namespace CtrEditor.ObjetosSim
     public partial class osBottGenerator : osBase, IosBase
     {
         TimerTON_TOFF _TON_TOFF = new TimerTON_TOFF();
-        // Otros datos y métodos relevantes para la simulación
-
         private float TiempoRestante;
-        private osBotella UltimaBotella;
-
         public static string NombreClase()
         {
             return "BottGenerator";
         }
+
         private string nombre = NombreClase();
-        public override string Nombre
-        {
-            get => nombre;
-            set => SetProperty(ref nombre, value);
-        }
+        public override string Nombre { get => nombre; set => SetProperty(ref nombre, value); }
 
         [ObservableProperty]
         private float offsetLeftSalida;
         [ObservableProperty]
         private float offsetTopSalida;
-
         [ObservableProperty]
         [property: Description("The bottle will be destroyed if fall outside transport.")]
         [property: Category("Enable to Run:")]
         private bool preserve_Outside_Transport;
-
         [ObservableProperty]
         [property: Description("PLC tag for consense to run. 1 => always")]
         [property: Category("Enable to Run:")]
         private string tag_consenso;
-
         [ObservableProperty]
         [property: Description("Consense to run.")]
         [property: Category("Enable to Run:")]
         private bool consenso;
-
         partial void OnConsensoChanged(bool value)
         {
             _TON_TOFF.Senal = value;
         }
+
         [ObservableProperty]
         [property: Description("Consense is Normally close.")]
         [property: Category("Enable to Run:")]
@@ -74,10 +64,8 @@ namespace CtrEditor.ObjetosSim
         [property: Description("Filter OUT signal.")]
         [property: Category("Enable to Run:")]
         bool filter_Output;
-
         [ObservableProperty]
         private float botellas_hora;
-
         partial void OnBotellas_horaChanged(float value)
         {
             Botellas_segundo = value / 3600;
@@ -85,7 +73,6 @@ namespace CtrEditor.ObjetosSim
 
         [ObservableProperty]
         private float botellas_segundo;
-
         partial void OnBotellas_segundoChanged(float value)
         {
             Botellas_hora = value * 3600;
@@ -95,21 +82,6 @@ namespace CtrEditor.ObjetosSim
         private float velocidad_actual_percentual;
         [ObservableProperty]
         private float diametro_botella;
-
-
-        public osBottGenerator()
-        {
-            Ancho = 0.30f;
-            Alto = 0.30f;
-            Angulo = 0;
-            Velocidad_actual_percentual = 100;
-            Diametro_botella = 0.1f;
-            Botellas_hora = 10000;
-            Filtro_consenso_ON_s = 1;
-            Filtro_consenso_OFF_s = 0.1f;
-            Preserve_Outside_Transport = false;
-        }
-
         public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
         {
             if (Consenso_NC)
@@ -118,67 +90,68 @@ namespace CtrEditor.ObjetosSim
                 Consenso = LeerBitTag(Tag_consenso);
         }
 
+        private bool HayEspacioParaNuevaBotella(float X, float Y)
+        {
+            float radioMinimo = Diametro_botella / 4;  // Distancia mínima entre centros
+            float radioMinimoCuadrado = radioMinimo * radioMinimo;
+
+            // Buscar todas las botellas cercanas
+            foreach (var obj in _mainViewModel.ObjetosSimulables)
+            {
+                if (obj is osBotella)
+                {
+                    float distanciaCuadrada = (float)(Math.Pow(obj.Left - X, 2) + Math.Pow(obj.Top - Y, 2));
+                    if (distanciaCuadrada < radioMinimoCuadrado)
+                    {
+                        return false;  // Hay una botella demasiado cerca
+                    }
+                }
+            }
+            return true;  // No hay botellas cercanas
+        }
+
         public override void UpdateControl(int elapsedMilliseconds)
         {
             bool habilitado;
-
             _TON_TOFF.Tiempo_ON_s = Filtro_consenso_ON_s;
             _TON_TOFF.Tiempo_OFF_s = Filtro_consenso_OFF_s;
-
             if (Consenso_Filtrado)
                 habilitado = _TON_TOFF.SenalFiltrada();
             else
                 habilitado = Consenso;
-
             Filter_Output = habilitado;
 
             if (habilitado && Velocidad_actual_percentual > 0)
             {
+                if (PrimeraActualizacion)
+                {
+                    TiempoEntreBotellas = 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
+                    TiempoRestante = TiempoEntreBotellas;
+                    PrimeraActualizacion = false;
+                }
+
                 TiempoRestante -= elapsedMilliseconds / 1000.0f;
                 if (TiempoRestante <= 0)
                 {
-                    bool BotellaCreada = false;
                     var X = Left + OffsetLeftSalida;
                     var Y = Top + OffsetTopSalida;
 
-                    if (UltimaBotella != null && UltimaBotella.RemoverDesdeSimulacion)
-                        UltimaBotella = null;
-
-                    if (UltimaBotella == null)
+                    if (HayEspacioParaNuevaBotella(X, Y))
                     {
-                        // No hay botellas, se puede crear una nueva directamente
                         var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
                         ((osBotella)nuevaBotella).Diametro = Diametro_botella;
                         ((osBotella)nuevaBotella).Preserve_Outside_Transport = Preserve_Outside_Transport;
-                        ((osBotella)nuevaBotella).AutoCreated = true;
                         nuevaBotella.AutoCreated = true;
-                        UltimaBotella = (osBotella)nuevaBotella;
-                        BotellaCreada = true;
-                    }
-                    else
-                    {
-                        // Calcular la distancia entre el centro de la última botella y la nueva posición
-                        float distancia = (float)Math.Sqrt(Math.Pow(UltimaBotella.Left - X, 2) + Math.Pow(UltimaBotella.Top - Y, 2));
-                        float distanciaMinima = Diametro_botella / 4; // Asumiendo que el diámetro de la nueva botella es similar
 
-                        if (distancia > distanciaMinima)
-                        {
-                            osBotella nuevaBotella = (osBotella)_mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
-                            nuevaBotella.Diametro = Diametro_botella;
-                            ((osBotella)nuevaBotella).Preserve_Outside_Transport = Preserve_Outside_Transport;
-                            nuevaBotella.AutoCreated = true;
-                            UltimaBotella = nuevaBotella;
-                            BotellaCreada = true;
-                        }
+                        // Recalcular el tiempo entre botellas por si cambió la velocidad
+                        TiempoEntreBotellas = 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
+                        TiempoRestante = TiempoEntreBotellas;
                     }
-                    if (BotellaCreada)
-                        TiempoRestante += 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
-
                 }
             }
             else
             {
-                TiempoRestante = 0;
+                PrimeraActualizacion = true;
             }
         }
 
@@ -189,6 +162,13 @@ namespace CtrEditor.ObjetosSim
             base.ucLoaded();
         }
 
+        private float TiempoEntreBotellas; // Nuevo: almacena el intervalo calculado
+        private bool PrimeraActualizacion = true; // Nuevo: flag para la primera actualización
+        public override void SimulationStop()
+        {
+            PrimeraActualizacion = true; // Reset del flag al detener
+            base.SimulationStop();
+        }
     }
 
     public partial class ucBottGenerator : UserControl, IDataContainer
@@ -202,19 +182,24 @@ namespace CtrEditor.ObjetosSim
             this.Loaded += OnLoaded;
             this.Unloaded += OnUnloaded;
         }
+
         private void OnLoaded(object sender, RoutedEventArgs e)
         {
             Datos?.ucLoaded();
         }
+
         private void OnUnloaded(object sender, RoutedEventArgs e)
         {
             Datos?.ucUnLoaded();
         }
-        public void Highlight(bool State) { }
+
+        public void Highlight(bool State)
+        {
+        }
+
         public ZIndexEnum ZIndex_Base()
         {
             return ZIndexEnum.Generadores;
         }
     }
-
-}
+}
\ No newline at end of file
diff --git a/ObjetosSim/Estaticos/ucVMmotorSim.xaml.cs b/ObjetosSim/Estaticos/ucVMmotorSim.xaml.cs
index 6616a41..f8074e5 100644
--- a/ObjetosSim/Estaticos/ucVMmotorSim.xaml.cs
+++ b/ObjetosSim/Estaticos/ucVMmotorSim.xaml.cs
@@ -202,10 +202,15 @@ namespace CtrEditor.ObjetosSim
             if (DB_Motor == 0)
                 return;
 
-            // Read ControlWord in one operation
-            int controlWord = plc.LeerTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].ControlWord") ?? 0;
+            // Add timestamp to trace when the read occurs
+            var timestamp = DateTime.Now;
+            
+            // Read ControlWord and track the raw response
+            var rawResponse = plc.LeerTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].ControlWord");
+            int controlWord = rawResponse ?? 0;    
             var control = VMMotorBitPacker.UnpackControlWord(controlWord);
 
+
             // Update local state from ControlWord
             OUT_Run = control.run;
             OUT_Stop = control.stop;
@@ -233,6 +238,7 @@ namespace CtrEditor.ObjetosSim
             if (Data.VFD_Trip_NC)
                 STATUS_VFD_Trip = !STATUS_VFD_Trip;
 
+
             // Pack all status bits and speed into StatusWord
             int statusWord = VMMotorBitPacker.PackStatusWord(
                 _STATUS_VFD_Ready,
diff --git a/Simulacion/Aether.cs b/Simulacion/Aether.cs
index 9617d37..fa439a3 100644
--- a/Simulacion/Aether.cs
+++ b/Simulacion/Aether.cs
@@ -128,6 +128,43 @@ namespace CtrEditor.Simulacion
             return verticesList;
         }
 
+        private float CalculateAngleOverlap(Fixture bottle)
+        {
+            // Get bottle position relative to curve center
+            Vector2 centerToBottle = bottle.Body.Position - Body.Position;
+            
+            // Calculate angle of bottle relative to curve center (in radians)
+            float bottleAngle = (float)Math.Atan2(centerToBottle.Y, centerToBottle.X);
+            
+            // Normalize angle to be positive
+            if (bottleAngle < 0)
+                bottleAngle += 2 * (float)Math.PI;
+
+            // If bottle is outside the angle range, return 0
+            if (bottleAngle < _startAngle || bottleAngle > _endAngle)
+                return 0;
+
+            // Calculate distance from center
+            float distanceToCenter = centerToBottle.Length();
+            
+            // If bottle is outside radius range, return 0
+            if (distanceToCenter < _innerRadius || distanceToCenter > _outerRadius)
+                return 0;
+
+            // Calculate how far the bottle is from the edges
+            float angleFromStart = bottleAngle - _startAngle;
+            float angleToEnd = _endAngle - bottleAngle;
+            
+            // Use the minimum distance to either edge to calculate overlap
+            float minAngleDistance = Math.Min(angleFromStart, angleToEnd);
+            float totalAngle = _endAngle - _startAngle;
+            
+            // Calculate overlap percentage based on angle proximity to edges
+            float overlapPercentage = Math.Min(minAngleDistance / (totalAngle * 0.1f), 1.0f);
+            
+            return overlapPercentage;
+        }
+
         public void ApplyCurveEffect(Fixture bottle)
         {
             Vector2 centerToBottle = bottle.Body.Position - Body.Position;
@@ -135,17 +172,46 @@ namespace CtrEditor.Simulacion
 
             if (distanceToCenter >= _innerRadius && distanceToCenter <= _outerRadius)
             {
-                // Calcular la velocidad tangencial
-                float speedMetersPerSecond = Speed / 60.0f;
-                float angularVelocity = speedMetersPerSecond / distanceToCenter;
+                // Calculate overlap percentage
+                float overlapPercentage = CalculateAngleOverlap(bottle);
 
-                // Vector tangente (perpendicular al radio)
-                Vector2 tangent = new Vector2(-centerToBottle.Y, centerToBottle.X);
-                tangent.Normalize();
+                // Only apply effect if there's overlap
+                if (overlapPercentage > 0)
+                {
+                    // Calculate the tangential velocity
+                    float speedMetersPerSecond = Speed / 60.0f;
 
-                // Velocidad deseada
-                Vector2 desiredVelocity = tangent * angularVelocity * distanceToCenter;
-                bottle.Body.LinearVelocity = desiredVelocity;
+                    // Vector tangent (perpendicular to radius)
+                    Vector2 tangent = new Vector2(-centerToBottle.Y, centerToBottle.X);
+                    tangent.Normalize();
+
+                    // Adjust tangent direction based on speed sign
+                    if (speedMetersPerSecond < 0)
+                        tangent = -tangent;
+
+                    // Current velocity magnitude
+                    float currentSpeed = bottle.Body.LinearVelocity.Length();
+
+                    // Desired conveyor speed
+                    float conveyorSpeed = Math.Abs(speedMetersPerSecond);
+
+                    // Use the larger of the two speeds as base speed
+                    float targetSpeed = Math.Max(currentSpeed, conveyorSpeed);
+
+                    // Lerp between current direction and curve direction
+                    Vector2 currentDir = bottle.Body.LinearVelocity;
+                    if (currentDir.LengthSquared() > 0)
+                        currentDir.Normalize();
+                    else
+                        currentDir = tangent;
+
+                    // Interpolate between current direction and curve direction
+                    Vector2 newDirection = currentDir * (1 - overlapPercentage) + tangent * overlapPercentage;
+                    newDirection.Normalize();
+
+                    // Apply new velocity with combined speed
+                    bottle.Body.LinearVelocity = newDirection * targetSpeed;
+                }
             }
         }
     }
@@ -574,8 +640,9 @@ namespace CtrEditor.Simulacion
             foreach (var transporte in ListOnTransports)
             {
                 if (transporte is simTransporte conveyorRect)
-                    if (ApplyConveyorEffect(deltaTime_s, conveyorRect))
-                        break;
+                    ApplyConveyorEffect(deltaTime_s, conveyorRect);
+                  //  if (ApplyConveyorEffect(deltaTime_s, conveyorRect))
+                    //    break;
                 if (transporte is simCurve conveyorCurve)
                     conveyorCurve.ApplyCurveEffect(Body.FixtureList[0]);
             }