diff --git a/CtrEditor.csproj b/CtrEditor.csproj
index 98043c8..e5600a5 100644
--- a/CtrEditor.csproj
+++ b/CtrEditor.csproj
@@ -53,6 +53,7 @@
+
diff --git a/MainViewModel.cs b/MainViewModel.cs
index 83a3fac..68abed8 100644
--- a/MainViewModel.cs
+++ b/MainViewModel.cs
@@ -146,7 +146,7 @@ namespace CtrEditor
[ObservableProperty]
public ObservableCollection objetosSimulables;
-
+
//
// Constructor
//
@@ -205,10 +205,10 @@ namespace CtrEditor
public void CrearObjetoSimulableEnCentroCanvas(Type tipoSimulable)
{
var CentroCanvas = MainWindow.ObtenerCentroCanvasMeters();
- CrearObjetoSimulable(tipoSimulable,CentroCanvas.X,CentroCanvas.Y);
+ CrearObjetoSimulable(tipoSimulable, CentroCanvas.X, CentroCanvas.Y);
}
- public osBase CrearObjetoSimulable(Type tipoSimulable,float Left,float Top)
+ public osBase CrearObjetoSimulable(Type tipoSimulable, float Left, float Top)
{
// Crear una nueva instancia del osBase correspondiente
osBase? NuevoOsBase = UserControlFactory.GetInstanceForType(tipoSimulable);
@@ -261,7 +261,7 @@ namespace CtrEditor
if (SelectedItemOsList is osBase objDuplicar)
{
StopSimulation();
- DisconnectPLC();
+ DisconnectPLC();
objDuplicar.SalvarDatosNoSerializables();
@@ -287,11 +287,12 @@ namespace CtrEditor
CrearUserControlDesdeObjetoSimulable(NuevoObjetoDuplicado);
}
}
- catch
+ catch
{
// Log error or handle it accordingly
}
- finally {
+ finally
+ {
objDuplicar.RestaurarDatosNoSerializables();
}
}
@@ -409,8 +410,8 @@ namespace CtrEditor
// Reiniciar el cronómetro para la próxima medición
foreach (var objetoSimulable in ObjetosSimulables)
- objetoSimulable.UpdatePLC(PLCViewModel.PLCInterface, (int) elapsedMilliseconds);
- }
+ objetoSimulable.UpdatePLC(PLCViewModel.PLCInterface, (int)elapsedMilliseconds);
+ }
}
private void OpenWorkDirectory()
@@ -425,7 +426,7 @@ namespace CtrEditor
//
// Lista de osBase
//
-
+
public void Save()
{
SaveStateObjetosSimulables();
@@ -528,7 +529,7 @@ namespace CtrEditor
// Se cargan los datos de cada UserControl en el StackPanel
public void CargarPropiedadesosDatos(osBase selectedObject, StackPanel PanelEdicion, ResourceDictionary Resources)
{
- UserControlFactory.CargarPropiedadesosDatos(selectedObject,PanelEdicion, Resources);
+ UserControlFactory.CargarPropiedadesosDatos(selectedObject, PanelEdicion, Resources);
}
private RelayCommand saveCommand;
@@ -551,7 +552,7 @@ namespace CtrEditor
{
public ObservableCollection? ObjetosSimulables { get; set; }
public UnitConverter? UnitConverter { get; set; }
- public PLCViewModel? PLC_ConnectionData { get; set; }
+ public PLCViewModel? PLC_ConnectionData { get; set; }
}
public class TipoSimulable
diff --git a/ObjetosSim/Dinamicos/ucBotella.xaml.cs b/ObjetosSim/Dinamicos/ucBotella.xaml.cs
index 2720ca4..73388e7 100644
--- a/ObjetosSim/Dinamicos/ucBotella.xaml.cs
+++ b/ObjetosSim/Dinamicos/ucBotella.xaml.cs
@@ -43,6 +43,12 @@ namespace CtrEditor.ObjetosSim
SimGeometria?.SetDiameter(Diametro);
}
+ [ObservableProperty]
+ private string velocidad_desde_simulacion;
+ [ObservableProperty]
+ private float inercia_desde_simulacion;
+
+
[ObservableProperty]
private float mass;
partial void OnMassChanged(float value)
@@ -111,6 +117,8 @@ namespace CtrEditor.ObjetosSim
}
if (SimGeometria.Descartar) // Ha sido marcada para remover
RemoverDesdeSimulacion = true;
+ Velocidad_desde_simulacion = SimGeometria.Body.LinearVelocity.ToString();
+ Inercia_desde_simulacion = SimGeometria.Body.Inertia;
}
public override void ucLoaded()
diff --git a/ObjetosSim/Emuladores/ucTanque.xaml b/ObjetosSim/Emuladores/ucTanque.xaml
index 48a449e..becaf14 100644
--- a/ObjetosSim/Emuladores/ucTanque.xaml
+++ b/ObjetosSim/Emuladores/ucTanque.xaml
@@ -21,8 +21,8 @@
Math.Abs(delta))
@@ -209,10 +213,10 @@ namespace CtrEditor.ObjetosSim
return hzIncrementsRamp;
}
- public void UpdateSpeed(float MaxRatedHz, float TiempoRampa, int elapsedMilliseconds)
+ public void UpdateSpeed(float max_Speed_for_Ramp, float TiempoRampa, int elapsedMilliseconds)
{
// Calculamos la velocidad
- STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(MaxRatedHz, TiempoRampa, STATUS_VFD_ACT_Speed_Hz, OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds);
+ STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(max_Speed_for_Ramp, TiempoRampa, STATUS_VFD_ACT_Speed_Hz, OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds);
}
}
diff --git a/ObjetosSim/SensoresComandos/ucBoton.xaml.cs b/ObjetosSim/SensoresComandos/ucBoton.xaml.cs
index 0462d80..421980f 100644
--- a/ObjetosSim/SensoresComandos/ucBoton.xaml.cs
+++ b/ObjetosSim/SensoresComandos/ucBoton.xaml.cs
@@ -43,7 +43,7 @@ namespace CtrEditor.ObjetosSim
ColorButton_oculto = Brushes.LightGreen;
else
ColorButton_oculto = Color;
- if (!tipo_NC)
+ if (!Tipo_NC)
EscribirBitTag(Tag, value);
else
EscribirBitTag(Tag, !value);
@@ -76,8 +76,14 @@ namespace CtrEditor.ObjetosSim
}
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
- {
-
+ {
+ }
+
+ public override void UpdatePLCPrimerCiclo() {
+ // Escribimos el valor actual al iniciar la conexion
+ // Esto es util para NC principalmente
+
+ OnEstadoChanged(Estado);
}
public override void UpdateControl(int elapsedMilliseconds)
diff --git a/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs b/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs
index 8d7c9ff..a06515c 100644
--- a/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs
+++ b/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs
@@ -5,6 +5,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using CommunityToolkit.Mvvm.ComponentModel;
+using System.Diagnostics;
namespace CtrEditor.ObjetosSim
@@ -15,6 +16,9 @@ namespace CtrEditor.ObjetosSim
public partial class osPhotocell : osBase, IosBase
{
private simBarrera Simulation_Photocell;
+ Stopwatch timer;
+ double timer_lastPositive;
+ double timer_lastNegative;
public static string NombreClase()
{
@@ -42,9 +46,46 @@ namespace CtrEditor.ObjetosSim
EscribirBitTag(TagPhotocell_OUT, !LuzCortada);
else
EscribirBitTag(TagPhotocell_OUT, LuzCortada);
+ if (filter_Frecuency < 1)
+ {
+ Filter_Frecuency = 1;
+ Frecuency = 0;
+ }
+
+ if (!value) {
+ Lenght_positive_pulse = (float) (timer.ElapsedMilliseconds- timer_lastPositive);
+ timer_lastNegative = timer.ElapsedMilliseconds;
+ } else
+ {
+ Lenght_negative_pulse = (float)(timer.ElapsedMilliseconds - timer_lastNegative);
+ timer_lastPositive = timer.ElapsedMilliseconds;
+ Lenght_FP_to_FP = Lenght_positive_pulse + Lenght_negative_pulse;
+ Frecuency = (Frecuency * (filter_Frecuency - 1) + (1000 / Lenght_FP_to_FP)) / filter_Frecuency;
+ }
}
+ [ObservableProperty]
+ float filter_Frecuency;
+
+ partial void OnFilter_FrecuencyChanged(float value)
+ {
+ if (value<=0)
+ Filter_Frecuency = 10;
+ }
+
+ [ObservableProperty]
+ float frecuency;
+
+ [ObservableProperty]
+ float lenght_positive_pulse;
+
+ [ObservableProperty]
+ float lenght_negative_pulse;
+
+ [ObservableProperty]
+ float lenght_FP_to_FP;
+
[ObservableProperty]
public bool tipo_NC;
@@ -96,6 +137,9 @@ namespace CtrEditor.ObjetosSim
{
Ancho = 1;
Alto = 0.03f;
+ Frecuency = 0;
+ timer = new Stopwatch();
+ timer.Start();
}
public override void UpdateGeometryStart()
@@ -105,11 +149,14 @@ namespace CtrEditor.ObjetosSim
}
public override void UpdateControl(int elapsedMilliseconds)
{
- LuzCortada = Simulation_Photocell.LuzCortada;
+ LuzCortada = Simulation_Photocell.LuzCortada > 0;
}
- public override void UpdateGeometryStep()
+ public override void UpdatePLCPrimerCiclo()
{
- Simulation_Photocell.LuzCortada = false;
+ // Escribimos el valor actual al iniciar la conexion
+ // Esto es util para NC principalmente
+
+ OnLuzCortadaChanged(LuzCortada);
}
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {
}
diff --git a/ObjetosSim/SensoresComandos/ucSensTemperatura.xaml.cs b/ObjetosSim/SensoresComandos/ucSensTemperatura.xaml.cs
index b41c58f..8e7f6f4 100644
--- a/ObjetosSim/SensoresComandos/ucSensTemperatura.xaml.cs
+++ b/ObjetosSim/SensoresComandos/ucSensTemperatura.xaml.cs
@@ -57,6 +57,11 @@ namespace CtrEditor.ObjetosSim
{
}
+ public override void UpdatePLCPrimerCiclo()
+ {
+ // Escribimos el valor actual al iniciar la conexion
+ OnValueChanged(Value);
+ }
public override void ucLoaded()
{
diff --git a/ObjetosSim/TagsSignals/ucAnalogTag.xaml.cs b/ObjetosSim/TagsSignals/ucAnalogTag.xaml.cs
index cd14584..2152702 100644
--- a/ObjetosSim/TagsSignals/ucAnalogTag.xaml.cs
+++ b/ObjetosSim/TagsSignals/ucAnalogTag.xaml.cs
@@ -78,6 +78,12 @@ namespace CtrEditor.ObjetosSim
{
}
+ public override void UpdatePLCPrimerCiclo()
+ {
+ // Escribimos el valor actual al iniciar la conexion
+ OnValueChanged(Value);
+ }
+
public override void UpdateControl(int elapsedMilliseconds)
{
// Calculamos la velocidad
diff --git a/ObjetosSim/TagsSignals/ucBoolTag.xaml.cs b/ObjetosSim/TagsSignals/ucBoolTag.xaml.cs
index 419700f..7355f4a 100644
--- a/ObjetosSim/TagsSignals/ucBoolTag.xaml.cs
+++ b/ObjetosSim/TagsSignals/ucBoolTag.xaml.cs
@@ -60,6 +60,12 @@ namespace CtrEditor.ObjetosSim
Descripcion = "Nombre del Tag";
}
+ public override void UpdatePLCPrimerCiclo()
+ {
+ // Escribimos el valor actual al iniciar la conexion
+ OnEstadoChanged(Estado);
+ }
+
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
diff --git a/ObjetosSim/Traces/ucTrace3.xaml b/ObjetosSim/Traces/ucTrace3.xaml
new file mode 100644
index 0000000..1d450a7
--- /dev/null
+++ b/ObjetosSim/Traces/ucTrace3.xaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ObjetosSim/Traces/ucTrace3.xaml.cs b/ObjetosSim/Traces/ucTrace3.xaml.cs
new file mode 100644
index 0000000..9366711
--- /dev/null
+++ b/ObjetosSim/Traces/ucTrace3.xaml.cs
@@ -0,0 +1,231 @@
+using CtrEditor.Convertidores;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using CommunityToolkit.Mvvm.ComponentModel;
+using System.Windows.Shapes;
+using CtrEditor.Siemens;
+using System.Runtime.Intrinsics;
+
+namespace CtrEditor.ObjetosSim.Traces
+{
+ ///
+ /// Interaction logic for ucTrace3.xaml
+ ///
+ public partial class osTrace3 : osBase, IosBase
+ {
+ private List _series1 = new List();
+ private List _series2 = new List();
+ private List _series3 = new List();
+
+ // Otros datos y métodos relevantes para la simulación
+
+ public static string NombreClase()
+ {
+ return "Trace3";
+ }
+ private string nombre = NombreClase();
+ public override string Nombre
+ {
+ get => nombre;
+ set => SetProperty(ref nombre, value);
+ }
+
+ [ObservableProperty]
+ private Brush color_Serie_1;
+ [ObservableProperty]
+ private Brush color_Serie_2;
+ [ObservableProperty]
+ private Brush color_Serie_3;
+
+ [ObservableProperty]
+ float alto;
+ [ObservableProperty]
+ float ancho;
+
+ [ObservableProperty]
+ string tag_Serie1;
+ [ObservableProperty]
+ string tag_Serie2;
+ [ObservableProperty]
+ string tag_Serie3;
+
+ [ObservableProperty]
+ string titulo;
+
+ [ObservableProperty]
+ string descripcion_Serie_1;
+ [ObservableProperty]
+ string descripcion_Serie_2;
+ [ObservableProperty]
+ string descripcion_Serie_3;
+
+ [ObservableProperty]
+ float min_Serie_1;
+ [ObservableProperty]
+ float max_Serie_1;
+ [ObservableProperty]
+ float min_Serie_2;
+ [ObservableProperty]
+ float max_Serie_2;
+ [ObservableProperty]
+ float min_Serie_3;
+ [ObservableProperty]
+ float max_Serie_3;
+
+ [ObservableProperty]
+ float y_offset_1;
+ [ObservableProperty]
+ float y_offset_2;
+ [ObservableProperty]
+ float y_offset_3;
+
+
+ [ObservableProperty]
+ float max_Cantidad_Elementos;
+
+ public osTrace3()
+ {
+ Alto = 3;
+ Ancho = 5;
+ Titulo = "Datos";
+ Max_Cantidad_Elementos = 10;
+ Color_Serie_1 = Brushes.Black;
+ Color_Serie_2 = Brushes.Red;
+ Color_Serie_3 = Brushes.Blue;
+ Max_Serie_1 = 2;
+ Max_Serie_2 = 2;
+ Max_Serie_3 = 2;
+ }
+
+ public void AddData(float series1Value, float series2Value, float series3Value)
+ {
+ if (_series1.Count >= Max_Cantidad_Elementos)
+ {
+ _series1.RemoveAt(0);
+ _series2.RemoveAt(0);
+ _series3.RemoveAt(0);
+ }
+
+ _series1.Add(series1Value);
+ _series2.Add(series2Value);
+ _series3.Add(series3Value);
+
+ DrawChart();
+ }
+
+ private void DrawChart()
+ {
+ if (VisualRepresentation != null)
+ if (VisualRepresentation is ucTrace3 uc)
+ {
+ uc.ChartCanvas.Children.Clear();
+
+ DrawSeries(uc.ChartCanvas,_series1, Brushes.Red,Min_Serie_1, Max_Serie_1, Y_offset_1);
+ DrawSeries(uc.ChartCanvas,_series2, Brushes.Green, Min_Serie_2, Max_Serie_2, Y_offset_2);
+ DrawSeries(uc.ChartCanvas,_series3, Brushes.Blue, Min_Serie_3, Max_Serie_3, Y_offset_3);
+ }
+
+ }
+
+ private void DrawSeries(Canvas ChartCanvas, List series, Brush color, float minY, float maxY, float yoffset)
+ {
+ if (series.Count < 2) return;
+
+ foreach (var value in series)
+ {
+ if (value < minY) minY = value;
+ if (value > maxY) maxY = value;
+ }
+ if (minY == maxY) return;
+
+ float canvasHeight = (float) ChartCanvas.ActualHeight;
+ float canvasWidth = (float) ChartCanvas.ActualWidth;
+ float scaleX = canvasWidth / Max_Cantidad_Elementos;
+ float scaleY = canvasHeight / (maxY - minY + yoffset);
+
+ for (int i = 1; i < series.Count; i++)
+ {
+ float x1 = (i - 1) * scaleX;
+ float y1 = canvasHeight - (series[i - 1] - minY + yoffset) * scaleY;
+ float x2 = i * scaleX;
+ float y2 = canvasHeight - (series[i] - minY + yoffset) * scaleY;
+
+ var line = new Line
+ {
+ Stroke = color,
+ StrokeThickness = 2,
+ X1 = x1,
+ Y1 = y1,
+ X2 = x2,
+ Y2 = y2
+ };
+
+ ChartCanvas.Children.Add(line);
+ }
+ }
+
+ public override void UpdatePLCPrimerCiclo()
+ {
+ // Escribimos el valor actual al iniciar la conexion
+ }
+ public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
+ {
+ base.UpdatePLC(plc, elapsedMilliseconds);
+
+ float v1 = LeerBitTag(Tag_Serie1) ? 0 : 1;
+ float v2 = LeerBitTag(Tag_Serie2) ? 0 : 1;
+ float v3 = LeerBitTag(Tag_Serie3) ? 0 : 1;
+
+ AddData(v1, v2, v3);
+ }
+ public override void ucLoaded()
+ {
+ // El UserControl ya se ha cargado y podemos obtener las coordenadas para
+ // crear el objeto de simulacion
+ base.ucLoaded();
+
+ }
+ }
+
+ public partial class ucTrace3 : UserControl, IDataContainer
+ {
+ public osBase? Datos { get; set; }
+
+ public ucTrace3()
+ {
+ InitializeComponent();
+ 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 Resize(float width, float height) {
+ if (Datos is osTrace3 datos)
+ {
+ datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
+ datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(height);
+ }
+ }
+ public void Move(float LeftPixels, float TopPixels)
+ {
+ if (Datos != null)
+ {
+ Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
+ Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
+ }
+ }
+ public void Rotate(float Angle) { }
+ public void Highlight(bool State) { }
+ public int ZIndex()
+ {
+ return 10;
+ }
+ }
+}
diff --git a/ObjetosSim/Traces/ucTraceSimple.xaml b/ObjetosSim/Traces/ucTraceSimple.xaml
new file mode 100644
index 0000000..5d9c50c
--- /dev/null
+++ b/ObjetosSim/Traces/ucTraceSimple.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ObjetosSim/Traces/ucTraceSimple.xaml.cs b/ObjetosSim/Traces/ucTraceSimple.xaml.cs
new file mode 100644
index 0000000..876a561
--- /dev/null
+++ b/ObjetosSim/Traces/ucTraceSimple.xaml.cs
@@ -0,0 +1,168 @@
+using CtrEditor.Convertidores;
+using CtrEditor.Siemens;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using Newtonsoft.Json;
+using CommunityToolkit.Mvvm.ComponentModel;
+using System.Collections.ObjectModel;
+using LiveChartsCore;
+using LiveChartsCore.SkiaSharpView;
+using LiveChartsCore.Defaults;
+using System.Diagnostics;
+
+namespace CtrEditor.ObjetosSim.Traces
+{
+ ///
+ /// Interaction logic for ucTraceSimple.xaml
+ ///
+ public partial class osTraceSimple : osBase, IosBase
+ {
+
+ private List data;
+ Stopwatch stopwatch;
+ private double YScale { get; set; }
+
+ // Otros datos y métodos relevantes para la simulación
+
+ public static string NombreClase()
+ {
+ return "Trace";
+ }
+ private string nombre = NombreClase();
+ public override string Nombre
+ {
+ get => nombre;
+ set => SetProperty(ref nombre, value);
+ }
+
+ [ObservableProperty]
+ float alto;
+
+ [ObservableProperty]
+ float ancho;
+
+ [ObservableProperty]
+ string tag_serie;
+
+ [ObservableProperty]
+ string x_Series_Name;
+
+ [ObservableProperty]
+ string y_Series_Name;
+
+ private readonly ObservableCollection _observableValues;
+
+
+ public ObservableCollection Series { get; set; }
+
+ public osTraceSimple()
+ {
+ // Use ObservableCollections to let the chart listen for changes (or any INotifyCollectionChanged).
+ _observableValues = new ObservableCollection();
+ Series = new ObservableCollection
+ {
+ new LineSeries
+ {
+ Values = _observableValues,
+ Fill = null
+ }
+ };
+ data = new List();
+ stopwatch = new Stopwatch();
+
+ YScale = 2.0;
+ Alto = 1;
+ Ancho = 1;
+ }
+
+ public override void UpdateGeometryStart()
+ {
+ // Se llama antes de la simulacion
+
+ }
+
+ public override void UpdatePLCPrimerCiclo()
+ {
+ stopwatch.Start();
+ }
+
+ public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
+ {
+ if (Tag_serie != null && Tag_serie.Length > 0) {
+ var value = LeerBitTag(Tag_serie) == false ? 0 : 1;
+ data.Add(value);
+ }
+ if (data.Count > 50)
+ data.RemoveAt(0);
+ if (stopwatch.ElapsedMilliseconds > 1000)
+ {
+ stopwatch.Reset();
+ stopwatch.Start();
+ foreach (var v in data)
+ {
+ _observableValues.Add(new(v));
+ if (_observableValues.Count > 50)
+ _observableValues.RemoveAt(0);
+ }
+
+ }
+ }
+
+ public override void UpdateControl(int elapsedMilliseconds)
+ {
+ // Calculamos la velocidad
+
+ }
+
+ public override void ucLoaded()
+ {
+ // El UserControl ya se ha cargado y podemos obtener las coordenadas para
+ // crear el objeto de simulacion
+ ActualizarLeftTop();
+
+ }
+ }
+
+ public partial class ucTraceSimple : UserControl, IDataContainer
+ {
+ public osBase? Datos { get; set; }
+
+ public ucTraceSimple()
+ {
+ InitializeComponent();
+ 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 Resize(float width, float height) {
+ if (Datos is osTraceSimple datos)
+ {
+ datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
+ datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(height);
+ }
+ }
+ public void Move(float LeftPixels, float TopPixels)
+ {
+ if (Datos != null)
+ {
+ Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
+ Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
+ }
+ }
+ public void Rotate(float Angle) { }
+ public void Highlight(bool State) { }
+ public int ZIndex()
+ {
+ return 10;
+ }
+ }
+
+}
diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs
index 698e9f5..f0a6e0f 100644
--- a/ObjetosSim/osBase.cs
+++ b/ObjetosSim/osBase.cs
@@ -26,8 +26,6 @@ using System.Windows.Media.Animation;
namespace CtrEditor.ObjetosSim
{
-
-
public interface IosBase
{
static abstract string NombreClase();
@@ -50,7 +48,7 @@ namespace CtrEditor.ObjetosSim
private UserControl? VisualRepresentation;
private SimulationManagerFP? simulationManager;
- public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerFP c )
+ public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerFP c)
{
_mainViewModel = a;
VisualRepresentation = b;
@@ -93,35 +91,62 @@ namespace CtrEditor.ObjetosSim
public virtual void TopChanged(float value) { }
-
- public bool Inicializado = false;
+ ///
+ /// Usado para saber cuando un objeto fue creado manualmente o por algun generador
+ /// Mas adelante la idea es poder eliminar o tratar de manera diferente a estos objetos
+ ///
public bool AutoCreated = false;
+
+ ///
+ /// Son los objetos marcados para ser eliminados luego de se detectados por un sensor del mundo fisico
+ /// Se deben eliminar fuera de la simulacion
+ ///
public bool RemoverDesdeSimulacion = false; // La simulacion indica que se debe remover
[JsonIgnore]
private DataSaveToSerialize DataSave;
+ ///
+ /// Link al UserControl. Inicializado en el evento OnLoaded
+ ///
[JsonIgnore]
protected UserControl? _visualRepresentation = null;
+ ///
+ /// Link al control PLC.
+ /// Inicializado en el metodo SetPLC
+ ///
[JsonIgnore]
protected PLCModel? _plc = null;
///
- ///
+ /// Se llama luego de cada Step. Esto permite actualziar las posiciones graficas de cada objeto que se esta dibujando
+ /// con las nuevas posiciones calculadas luego de la simulacion fisica.
///
///
public virtual void UpdateControl(int elapsedMilliseconds) { }
+
///
- /// Se llama antes de la simulacion
+ /// Se llama antes de comenzar la simulacion con el boton de Iniciar simulacion.
+ /// La idea es actualizar los objetos en el motor fisico antes de comenzar la simulacion fisica.
+ ///
+ public virtual void UpdateGeometryStart() { }
+
+ ///
+ /// Se llama al terminar la simulacion con el boton de Detener simulacion.
+ /// Se puede utilizar para detener los storyboard o alguna otra simulacion independiente
+ ///
+ public virtual void SimulationStop() { }
+
+ ///
+ /// Se llama antes de cada Step al World de la simulacion fisica.
+ /// Permite actualizar el estado de los objetos de la simulacion fisica
///
- public virtual void UpdateGeometryStart() { }
- public virtual void SimulationStop() { }
public virtual void UpdateGeometryStep() { }
///
/// Es llamada en cada Tick del reloj establecido del PLC
- /// cuando la conexion con el PLC esta establecida
+ /// cuando la conexion con el PLC esta establecida.
///
///
///
@@ -140,38 +165,70 @@ namespace CtrEditor.ObjetosSim
/// El UserControl se esta eliminando
/// eliminar el objeto de simulacion
///
- public virtual void ucUnLoaded() { }
+ public virtual void ucUnLoaded() { }
[JsonIgnore]
public MainViewModel _mainViewModel;
+ ///
+ /// Link al UserControl. Inicializado en el evento OnLoaded
+ ///
[JsonIgnore]
public UserControl? VisualRepresentation
{
get => _visualRepresentation;
set => _visualRepresentation = value;
}
+
+ ///
+ /// Link al Simualdor fisico.
+ ///
[JsonIgnore]
public SimulationManagerFP simulationManager;
+
+ ///
+ /// Prepara la clase para ser serializable poniendo a null los objetos que tienen referencias circulares
+ /// Luego se debe llamar a RestaurarDatosNoSerializables para restaurar el estado original
+ ///
public void SalvarDatosNoSerializables()
{
- DataSave = new DataSaveToSerialize(_mainViewModel,_visualRepresentation,simulationManager);
+ DataSave = new DataSaveToSerialize(_mainViewModel, _visualRepresentation, simulationManager);
_mainViewModel = null;
_visualRepresentation = null;
simulationManager = null;
}
+
+ ///
+ /// Restaura los links de los objetos que se eliminaron temporalmente para serializar.
+ ///
public void RestaurarDatosNoSerializables()
{
if (DataSave == null) return;
- DataSave.DataRestoreAfterSerialize(out _mainViewModel,out _visualRepresentation,out simulationManager);
+ DataSave.DataRestoreAfterSerialize(out _mainViewModel, out _visualRepresentation, out simulationManager);
}
-
+ ///
+ /// Se llama una unica vez al conectar con el PLC.
+ ///
+ ///
public void SetPLC(PLCModel plc)
{
_plc = plc;
+ UpdatePLCPrimerCiclo();
}
+ ///
+ /// Se llama una unica vez al conectar con el PLC
+ ///
+ public virtual void UpdatePLCPrimerCiclo() { }
+
+ ///
+ /// Crea una conexion entre los osBase segun el NameLink sea igual al nombre de algun osBase siempre que se cumpla
+ /// con el requisito que el osBase encontrado sea de tipo tipoOsBase
+ ///
+ ///
+ ///
+ ///
protected osBase ObtenerLink(string NameLink, Type tipoOsBase)
{
if (!string.IsNullOrEmpty(NameLink) && _mainViewModel != null)
@@ -218,6 +275,9 @@ namespace CtrEditor.ObjetosSim
_storyboard.SetSpeedRatio(velocidadActual);
}
+ ///
+ /// Actualiza Left Top del objeto respecto al Canvas padre.
+ ///
public void ActualizarLeftTop()
{
CanvasSetLeftinMeter(Left);
@@ -237,6 +297,11 @@ namespace CtrEditor.ObjetosSim
return false;
}
+ ///
+ /// Si la conexion con el plc esta activa y el Tag no es nulo escribe el bit en el PLC
+ ///
+ ///
+ ///
public void EscribirBitTag(string Tag, bool Value)
{
if (_plc == null) return;
@@ -380,9 +445,9 @@ namespace CtrEditor.ObjetosSim
simRect.Create(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo);
}
- public void UpdateCurve(simCurve curva,float RadioInterno, float RadioExterno, float startAngle, float endAngle)
+ public void UpdateCurve(simCurve curva, float RadioInterno, float RadioExterno, float startAngle, float endAngle)
{
- curva.Create(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno));
+ curva.Create(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno));
}
public simCurve AddCurve(float RadioInterno, float RadioExterno, float startAngle, float endAngle)
diff --git a/Simulacion/Aether.cs b/Simulacion/Aether.cs
index 8ad34e0..e278b78 100644
--- a/Simulacion/Aether.cs
+++ b/Simulacion/Aether.cs
@@ -223,7 +223,7 @@ namespace CtrEditor.Simulacion
public class simBarrera : simBase
{
- public bool LuzCortada = false;
+ public int LuzCortada;
private List _deferredActions;
public simBarrera(World world, List deferredActions, float width, float height, Vector2 position, float angle = 0)
@@ -260,7 +260,7 @@ namespace CtrEditor.Simulacion
Body.BodyType = BodyType.Static;
Body.Rotation = Microsoft.Xna.Framework.MathHelper.ToRadians(angle);
Body.Tag = this; // Importante para la identificación durante la colisión
- LuzCortada = false;
+ LuzCortada = 0;
}
}
@@ -295,20 +295,20 @@ namespace CtrEditor.Simulacion
public bool Descartar = false;
public int isOnTransports;
+ public List ListOnTransports;
public bool isRestricted;
public bool isNoMoreRestricted;
public float OriginalMass;
public simTransporte ConveyorRestrictedTo;
public Fixture axisRestrictedBy;
- public Vector2 Speed;
-
PrismaticJoint _activeJoint;
private List _deferredActions;
public simBotella(World world, List deferredActions, float diameter, Vector2 position, float mass)
{
_world = world;
+ ListOnTransports = new List();
_deferredActions = deferredActions;
_radius = diameter / 2;
_mass = mass;
@@ -362,9 +362,9 @@ namespace CtrEditor.Simulacion
Body.SetFriction(0.5f);
// Configurar amortiguamiento
- Body.LinearDamping = 4f; // Ajustar para controlar la reducción de la velocidad lineal
+ Body.LinearDamping = 1f; // Ajustar para controlar la reducción de la velocidad lineal
Body.AngularDamping = 1f; // Ajustar para controlar la reducción de la velocidad angular
- Body.SetRestitution(0.3f); // Baja restitución para menos rebote
+ Body.SetRestitution(0.1f); // Baja restitución para menos rebote
Body.SleepingAllowed = false;
Body.IsBullet = true;
@@ -385,7 +385,7 @@ namespace CtrEditor.Simulacion
{
if (fixtureB.Body.Tag is simBarrera Sensor)
{
- Sensor.LuzCortada = true;
+ Sensor.LuzCortada += 1;
return true;
}
else if (fixtureB.Body.Tag is simCurve curve)
@@ -403,20 +403,16 @@ namespace CtrEditor.Simulacion
simTransporte conveyor = fixtureB.Body.Tag as simTransporte;
isOnTransports += 1;
+ ListOnTransports.Add(conveyor);
- if (conveyor.Speed != 0)
+ // Aplicar el efecto del transportador usando el porcentaje calculado
+ if (conveyor.TransportWithGuides && conveyor.isBrake)
{
- // Aplicar el efecto del transportador usando el porcentaje calculado
- if (conveyor.TransportWithGuides && conveyor.isBrake)
- {
- ConveyorRestrictedTo = conveyor;
- axisRestrictedBy = fixtureB;
- OriginalMass = Body.Mass;
- isRestricted = true;
- isNoMoreRestricted = false;
- }
-
- ApplyConveyorEffect(conveyor, fixtureA, 1);
+ ConveyorRestrictedTo = conveyor;
+ axisRestrictedBy = fixtureB;
+ OriginalMass = Body.Mass;
+ isRestricted = true;
+ isNoMoreRestricted = false;
}
return true; // No aplicar respuestas físicas
}
@@ -443,21 +439,35 @@ namespace CtrEditor.Simulacion
private void HandleOnSeparation(Fixture sender, Fixture fixtureB, Contact contact)
{
- if (isOnTransports>0 && fixtureB.Body.Tag is simTransporte)
+ if (isOnTransports > 0 && fixtureB.Body.Tag is simTransporte)
+ {
+ if (fixtureB.Body.Tag is simTransporte transport)
+ ListOnTransports.Remove(transport);
isOnTransports -= 1;
+ }
if (isRestricted && fixtureB == axisRestrictedBy)
{
isRestricted = false;
isNoMoreRestricted = true;
}
+ if (fixtureB.Body.Tag is simBarrera Sensor)
+ Sensor.LuzCortada -= 1;
}
- private void ApplyConveyorEffect(simTransporte conveyor, Fixture circleFixture, float porcentajeCompartido)
+ public void ApplyConveyorSpeed()
+ {
+ Body.LinearVelocity = new Vector2(0.0f, 0.0f);
+ foreach (var conveyor in ListOnTransports)
+ {
+ ApplyConveyorEffect(conveyor);
+ }
+ }
+
+ private void ApplyConveyorEffect(simTransporte conveyor)
{
float speedMetersPerSecond = conveyor.Speed / 60.0f;
Vector2 desiredVelocity = new Vector2((float)Math.Cos(conveyor.Body.Rotation), (float)Math.Sin(conveyor.Body.Rotation)) * speedMetersPerSecond;
- // circleFixture.Body.ApplyForce(desiredVelocity * porcentajeCompartido);
- Speed = desiredVelocity;
+ Body.LinearVelocity += desiredVelocity;
}
public void CenterFixtureOnConveyor()
@@ -505,6 +515,7 @@ namespace CtrEditor.Simulacion
private Canvas simulationCanvas;
public List Cuerpos;
public List _deferredActions;
+ SolverIterations Iterations;
private Stopwatch stopwatch;
private double stopwatch_last;
@@ -514,6 +525,11 @@ namespace CtrEditor.Simulacion
public SimulationManagerFP()
{
world = new World(new Vector2(0, 0)); // Vector2.Zero
+
+ SolverIterations Iterations = new SolverIterations();
+ Iterations.PositionIterations = 1;
+ Iterations.VelocityIterations = 1;
+
Cuerpos = new List();
_deferredActions = new List();
stopwatch = new Stopwatch();
@@ -538,14 +554,13 @@ namespace CtrEditor.Simulacion
// Pasar el tiempo transcurrido al método Step
world.Step(elapsedMilliseconds / 1000.0f);
-
-
+
foreach (var cuerpo in Cuerpos)
{
if (cuerpo is simBotella botella)
{
- if (botella.isOnTransports > 0)
- botella.Body.LinearVelocity = botella.Speed;
+ botella.ApplyConveyorSpeed();
+
if (botella.isRestricted)
{
botella.CenterFixtureOnConveyor();