Agregado Trace3

This commit is contained in:
Miguel 2024-05-27 10:34:20 +02:00
parent c66be28764
commit 56f8630a65
16 changed files with 700 additions and 71 deletions

View File

@ -53,6 +53,7 @@
<PackageReference Include="Aether.Physics2D" Version="2.1.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="FarseerPhysics" Version="3.5.0" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc2" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />

View File

@ -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);
@ -291,7 +291,8 @@ namespace CtrEditor
{
// Log error or handle it accordingly
}
finally {
finally
{
objDuplicar.RestaurarDatosNoSerializables();
}
}
@ -409,7 +410,7 @@ 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);
}
}
@ -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<osBase>? ObjetosSimulables { get; set; }
public UnitConverter? UnitConverter { get; set; }
public PLCViewModel? PLC_ConnectionData { get; set; }
public PLCViewModel? PLC_ConnectionData { get; set; }
}
public class TipoSimulable

View File

@ -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()

View File

@ -21,8 +21,8 @@
<Grid>
<Image x:Name="TankImage"
Source="/imagenes/tank.png"
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform">
</Image>
<Slider

View File

@ -38,7 +38,11 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty]
public float tamano;
[ObservableProperty]
public float maxRatedHz;
public float proporcionalSpeed;
[ObservableProperty]
public float max_Speed_for_Ramp;
[ObservableProperty]
public float tiempoRampa;
@ -72,7 +76,8 @@ namespace CtrEditor.ObjetosSim
{
Tamano = 0.30f;
PLC_NumeroMotor = 31;
MaxRatedHz = 100;
ProporcionalSpeed = 100;
Max_Speed_for_Ramp = 100;
TiempoRampa = 3;
ImageSource_oculta = ImageFromPath("/imagenes/motor2.png");
}
@ -85,14 +90,13 @@ namespace CtrEditor.ObjetosSim
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {
motState.UpdatePLC(plc,PLC_NumeroMotor,Encendido, elapsedMilliseconds);
Velocidad = motState.STATUS_VFD_ACT_Speed_Hz / 10;
Velocidad = (ProporcionalSpeed / 100) * (motState.STATUS_VFD_ACT_Speed_Hz / 10);
}
public override void UpdateControl(int elapsedMilliseconds)
{
// Calculamos la velocidad
motState.UpdateSpeed(MaxRatedHz,TiempoRampa, elapsedMilliseconds);
motState.UpdateSpeed(Max_Speed_for_Ramp, TiempoRampa, elapsedMilliseconds);
}
@ -196,9 +200,9 @@ namespace CtrEditor.ObjetosSim
}
private float CalcSpeedRamp(float MaxRatedHz, float TiempoRampa, float actual, float expected, int elapsedMilliseconds)
private float CalcSpeedRamp(float max_Speed_for_Ramp, float TiempoRampa, float actual, float expected, int elapsedMilliseconds)
{
float hzIncrementsRamp = (MaxRatedHz * 10) / (TiempoRampa * (1000.0f / elapsedMilliseconds));
float hzIncrementsRamp = (max_Speed_for_Ramp * 10) / (TiempoRampa * (1000.0f / elapsedMilliseconds));
float delta = expected - actual;
// Conrtolar si la diferencia no es mayor de lo que falta
if (Math.Abs(hzIncrementsRamp) > 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);
}
}

View File

@ -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);
@ -77,7 +77,13 @@ 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)

View File

@ -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) {
}

View File

@ -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()
{

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,41 @@
<UserControl x:Class="CtrEditor.ObjetosSim.Traces.ucTrace3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim.Traces"
mc:Ignorable="d" Background="#FFECECEC">
<UserControl.Resources>
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
</UserControl.Resources>
<UserControl.DataContext>
<vm:osTrace3 Descripcion_Serie_1="Serie 1" Max_Cantidad_Elementos="100"/>
</UserControl.DataContext>
<Grid Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<!-- Title -->
<RowDefinition Height="*"/>
<!-- Chart Area -->
<RowDefinition Height="Auto"/>
<!-- Descriptions -->
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Titulo}" FontSize="16" HorizontalAlignment="Center" Margin="10"/>
<Canvas Grid.Row="1" x:Name="ChartCanvas" Background="White" Margin="10"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="10">
<TextBlock Text="{Binding Descripcion_Serie_1}" Margin="10" Foreground="{Binding Color_Serie_1}"/>
<TextBlock Text="{Binding Descripcion_Serie_2}" Margin="10" Foreground="{Binding Color_Serie_2}"/>
<TextBlock Text="{Binding Descripcion_Serie_3}" Margin="10" Foreground="{Binding Color_Serie_3}"/>
</StackPanel>
</Grid>
</UserControl>

View File

@ -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
{
/// <summary>
/// Interaction logic for ucTrace3.xaml
/// </summary>
public partial class osTrace3 : osBase, IosBase
{
private List<float> _series1 = new List<float>();
private List<float> _series2 = new List<float>();
private List<float> _series3 = new List<float>();
// 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<float> 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;
}
}
}

View File

@ -0,0 +1,25 @@
<UserControl x:Class="CtrEditor.ObjetosSim.Traces.ucTraceSimple"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim.Traces"
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
<UserControl.Resources>
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
</UserControl.Resources>
<UserControl.DataContext>
<vm:osTraceSimple Alto="3" Ancho="6"/>
</UserControl.DataContext>
<Grid>
<lvc:CartesianChart Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Name="SignalChart" Series="{Binding Series}">
</lvc:CartesianChart>
</Grid>
</UserControl>

View File

@ -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
{
/// <summary>
/// Interaction logic for ucTraceSimple.xaml
/// </summary>
public partial class osTraceSimple : osBase, IosBase
{
private List<float> 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<ObservableValue> _observableValues;
public ObservableCollection<ISeries> Series { get; set; }
public osTraceSimple()
{
// Use ObservableCollections to let the chart listen for changes (or any INotifyCollectionChanged).
_observableValues = new ObservableCollection<ObservableValue>();
Series = new ObservableCollection<ISeries>
{
new LineSeries<ObservableValue>
{
Values = _observableValues,
Fill = null
}
};
data = new List<float>();
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;
}
}
}

View File

@ -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;
/// <summary>
/// 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
/// </summary>
public bool AutoCreated = false;
/// <summary>
/// Son los objetos marcados para ser eliminados luego de se detectados por un sensor del mundo fisico
/// Se deben eliminar fuera de la simulacion
/// </summary>
public bool RemoverDesdeSimulacion = false; // La simulacion indica que se debe remover
[JsonIgnore]
private DataSaveToSerialize DataSave;
/// <summary>
/// Link al UserControl. Inicializado en el evento OnLoaded
/// </summary>
[JsonIgnore]
protected UserControl? _visualRepresentation = null;
/// <summary>
/// Link al control PLC.
/// Inicializado en el metodo SetPLC
/// </summary>
[JsonIgnore]
protected PLCModel? _plc = null;
/// <summary>
///
/// 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.
/// </summary>
/// <param name="elapsedMilliseconds"></param>
public virtual void UpdateControl(int elapsedMilliseconds) { }
/// <summary>
/// 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.
/// </summary>
public virtual void UpdateGeometryStart() { }
/// <summary>
/// Se llama al terminar la simulacion con el boton de Detener simulacion.
/// Se puede utilizar para detener los storyboard o alguna otra simulacion independiente
/// </summary>
public virtual void SimulationStop() { }
/// <summary>
/// Se llama antes de cada Step al World de la simulacion fisica.
/// Permite actualizar el estado de los objetos de la simulacion fisica
/// </summary>
public virtual void UpdateGeometryStart() { }
public virtual void SimulationStop() { }
public virtual void UpdateGeometryStep() { }
/// <summary>
/// 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.
/// </summary>
/// <param name="plc"></param>
/// <param name="elapsedMilliseconds"></param>
@ -140,38 +165,70 @@ namespace CtrEditor.ObjetosSim
/// El UserControl se esta eliminando
/// eliminar el objeto de simulacion
/// </summary>
public virtual void ucUnLoaded() { }
public virtual void ucUnLoaded() { }
[JsonIgnore]
public MainViewModel _mainViewModel;
/// <summary>
/// Link al UserControl. Inicializado en el evento OnLoaded
/// </summary>
[JsonIgnore]
public UserControl? VisualRepresentation
{
get => _visualRepresentation;
set => _visualRepresentation = value;
}
/// <summary>
/// Link al Simualdor fisico.
/// </summary>
[JsonIgnore]
public SimulationManagerFP simulationManager;
/// <summary>
/// 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
/// </summary>
public void SalvarDatosNoSerializables()
{
DataSave = new DataSaveToSerialize(_mainViewModel,_visualRepresentation,simulationManager);
DataSave = new DataSaveToSerialize(_mainViewModel, _visualRepresentation, simulationManager);
_mainViewModel = null;
_visualRepresentation = null;
simulationManager = null;
}
/// <summary>
/// Restaura los links de los objetos que se eliminaron temporalmente para serializar.
/// </summary>
public void RestaurarDatosNoSerializables()
{
if (DataSave == null) return;
DataSave.DataRestoreAfterSerialize(out _mainViewModel,out _visualRepresentation,out simulationManager);
DataSave.DataRestoreAfterSerialize(out _mainViewModel, out _visualRepresentation, out simulationManager);
}
/// <summary>
/// Se llama una unica vez al conectar con el PLC.
/// </summary>
/// <param name="plc"></param>
public void SetPLC(PLCModel plc)
{
_plc = plc;
UpdatePLCPrimerCiclo();
}
/// <summary>
/// Se llama una unica vez al conectar con el PLC
/// </summary>
public virtual void UpdatePLCPrimerCiclo() { }
/// <summary>
/// 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
/// </summary>
/// <param name="NameLink"></param>
/// <param name="tipoOsBase"></param>
/// <returns></returns>
protected osBase ObtenerLink(string NameLink, Type tipoOsBase)
{
if (!string.IsNullOrEmpty(NameLink) && _mainViewModel != null)
@ -218,6 +275,9 @@ namespace CtrEditor.ObjetosSim
_storyboard.SetSpeedRatio(velocidadActual);
}
/// <summary>
/// Actualiza Left Top del objeto respecto al Canvas padre.
/// </summary>
public void ActualizarLeftTop()
{
CanvasSetLeftinMeter(Left);
@ -237,6 +297,11 @@ namespace CtrEditor.ObjetosSim
return false;
}
/// <summary>
/// Si la conexion con el plc esta activa y el Tag no es nulo escribe el bit en el PLC
/// </summary>
/// <param name="Tag"></param>
/// <param name="Value"></param>
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)

View File

@ -223,7 +223,7 @@ namespace CtrEditor.Simulacion
public class simBarrera : simBase
{
public bool LuzCortada = false;
public int LuzCortada;
private List<Action> _deferredActions;
public simBarrera(World world, List<Action> 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<simTransporte> ListOnTransports;
public bool isRestricted;
public bool isNoMoreRestricted;
public float OriginalMass;
public simTransporte ConveyorRestrictedTo;
public Fixture axisRestrictedBy;
public Vector2 Speed;
PrismaticJoint _activeJoint;
private List<Action> _deferredActions;
public simBotella(World world, List<Action> deferredActions, float diameter, Vector2 position, float mass)
{
_world = world;
ListOnTransports = new List<simTransporte>();
_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<simBase> Cuerpos;
public List<Action> _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<simBase>();
_deferredActions = new List<Action>();
stopwatch = new Stopwatch();
@ -539,13 +555,12 @@ 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();