Limpiando el codigo de MainWindow y MainViewModel

This commit is contained in:
Miguel 2024-05-18 10:53:04 +02:00
parent 77ff643642
commit 664d325de8
15 changed files with 619 additions and 255 deletions

View File

@ -20,6 +20,9 @@
<None Remove="Icons\save.png" />
<None Remove="Icons\start.png" />
<None Remove="Icons\stop.png" />
<None Remove="imagenes\filler.png" />
<None Remove="imagenes\motorNegro.png" />
<None Remove="imagenes\motorVerde.png" />
<None Remove="motor2.png" />
<None Remove="tank.png" />
</ItemGroup>
@ -42,7 +45,6 @@
<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" />
<PackageReference Include="OpenCvSharp4.Windows" Version="4.9.0.20240103" />
</ItemGroup>
<ItemGroup>
@ -58,7 +60,9 @@
<Resource Include="Icons\save.png" />
<Resource Include="Icons\start.png" />
<Resource Include="Icons\stop.png" />
<Resource Include="imagenes\motor2.png" />
<Resource Include="imagenes\filler.png" />
<Resource Include="imagenes\motorNegro.png" />
<Resource Include="imagenes\motorVerde.png" />
<Resource Include="imagenes\tank.png" />
</ItemGroup>

View File

@ -37,14 +37,9 @@ namespace CtrEditor
public DatosDeTrabajo datosDeTrabajo { get; }
public ObservableCollection<string> listaImagenes { get; private set; } // Publicación de las claves del diccionario
public ObservableCollection<TipoSimulable> ListaOsBase { get; } = new ObservableCollection<TipoSimulable>();
private ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>();
public PLCViewModel plcViewModelData;
public Stopwatch stopwatch_PLCRefresh;
public Stopwatch stopwatch_SimRefresh;
private bool isSimulationRunning;
private bool isConnected;
public SimulationManagerFP simulationManager = new SimulationManagerFP();
private readonly DispatcherTimer _timerSimulacion;
@ -59,11 +54,153 @@ namespace CtrEditor
public ICommand TBConnectPLCCommand { get; }
public ICommand TBDisconnectPLCCommand { get; }
public ICommand OpenWorkDirectoryCommand { get; }
// Evento que se dispara cuando se selecciona una nueva imagen
public event EventHandler<string> ImageSelected;
public event EventHandler<TickSimulacionEventArgs> TickSimulacion;
public event Action<UserControl> OnUserControlSelected;
private bool isSimulationRunning;
private bool isConnected;
public PLCViewModel plcViewModelData;
private osBase _selectedItemOsList;
private string _selectedImage = null;
private ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>();
private float _left;
private float _top;
public float CanvasLeft
{
get => _left;
set
{
_left = value;
OnPropertyChanged(nameof(CanvasLeft));
}
}
public float CanvasTop
{
get => _top;
set
{
_top = value;
OnPropertyChanged(nameof(CanvasTop));
}
}
public bool IsSimulationRunning
{
get => isSimulationRunning;
set
{
isSimulationRunning = value;
OnPropertyChanged(nameof(IsSimulationRunning));
CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado
}
}
public bool IsConnected
{
get => isConnected;
set
{
isConnected = value;
OnPropertyChanged(nameof(IsConnected));
CommandManager.InvalidateRequerySuggested();
}
}
public string directorioTrabajo
{
get => EstadoPersistente.Instance.directorio;
set
{
if (value != null)
{
EstadoPersistente.Instance.directorio = value; // Actualizar el estado persistente
EstadoPersistente.Instance.GuardarEstado(); // Guardar el estado actualizado
datosDeTrabajo.CargarImagenes();
listaImagenes = new ObservableCollection<string>(datosDeTrabajo.Imagenes.Keys); // Actualizar claves
SelectedImage = null;
if (listaImagenes.FirstOrDefault() != null)
SelectedImage = listaImagenes.FirstOrDefault();
OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad
OnPropertyChanged(nameof(listaImagenes)); // Notificar que la lista de imágenes ha cambiado
}
}
}
public PLCViewModel PLCViewModel
{
get { return plcViewModelData; }
set
{
plcViewModelData = value;
OnPropertyChanged(nameof(PLCViewModel));
}
}
public string SelectedImage
{
get => _selectedImage;
set
{
if (_selectedImage != value && value != null)
{
StopSimulation();
SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen
_selectedImage = value;
ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen
LoadStateObjetosSimulables();
}
_selectedImage = value;
OnPropertyChanged(nameof(SelectedImage));
}
}
public osBase SelectedItemOsList
{
get => _selectedItemOsList;
set
{
if (_selectedItemOsList != value)
{
_selectedItemOsList = value;
OnPropertyChanged(nameof(SelectedItemOsList));
}
}
}
private TipoSimulable _selectedItem = null;
public TipoSimulable SelectedItem
{
get => _selectedItem;
set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged(nameof(SelectedItem)); // Notificar que la propiedad ha cambiado
}
}
}
public ObservableCollection<osBase> ObjetosSimulables
{
get => _objetosSimulables;
set
{
if (_objetosSimulables != value)
{
_objetosSimulables = value;
OnPropertyChanged(nameof(ObjetosSimulables));
}
}
}
public MainViewModel()
{
OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory);
@ -101,33 +238,44 @@ namespace CtrEditor
}
private TipoSimulable _selectedItem = null;
public TipoSimulable SelectedItem
public void CrearUserControl(Type tipoSimulable)
{
get => _selectedItem;
set
// Crear una nueva instancia del osBase correspondiente
osBase? newosBase = UserControlFactory.GetInstanceForType(tipoSimulable);
if (newosBase != null)
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged(nameof(SelectedItem)); // Notificar que la propiedad ha cambiado
}
if (CrearUsercontrol(newosBase))
// Añadir el nuevo osBase a la colección de objetos simulables
ObjetosSimulables.Add(newosBase);
}
}
private bool CrearUsercontrol(osBase osObjeto)
{
Type tipoObjeto = osObjeto.GetType();
// Obtén el UserControl correspondiente para el tipo de objeto
UserControl? userControl = UserControlFactory.GetControlForType(tipoObjeto);
if (userControl != null)
{
// Asignar los datos al UserControl
UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager);
osObjeto._mainViewModel = this;
OnUserControlSelected?.Invoke(userControl);
return true;
}
return false;
}
private void ExecuteDoubleClick(object parameter)
{
if (parameter is TipoSimulable tipoSimulable)
{
// Crear una nueva instancia del osBase correspondiente
osBase? newosBase = UserControlFactory.GetInstanceForType(tipoSimulable.Tipo);
if (newosBase != null)
{
if (CrearUsercontrol(newosBase))
// Añadir el nuevo osBase a la colección de objetos simulables
ObjetosSimulables.Add(newosBase);
}
CrearUserControl(tipoSimulable.Tipo);
}
}
@ -144,28 +292,6 @@ namespace CtrEditor
}
}
public bool IsSimulationRunning
{
get => isSimulationRunning;
set
{
isSimulationRunning = value;
OnPropertyChanged(nameof(IsSimulationRunning));
CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado
}
}
public bool IsConnected
{
get => isConnected;
set
{
isConnected = value;
OnPropertyChanged(nameof(IsConnected));
CommandManager.InvalidateRequerySuggested();
}
}
private void StartSimulation()
{
foreach (var objetoSimulable in ObjetosSimulables)
@ -238,77 +364,6 @@ namespace CtrEditor
}
//protected virtual void OnTickSimulacion(TickSimulacionEventArgs e)
//{
// TickSimulacion?.Invoke(this, e);
//}
public string directorioTrabajo
{
get => EstadoPersistente.Instance.directorio;
set
{
if (value != null)
{
EstadoPersistente.Instance.directorio = value; // Actualizar el estado persistente
EstadoPersistente.Instance.GuardarEstado(); // Guardar el estado actualizado
datosDeTrabajo.CargarImagenes();
listaImagenes = new ObservableCollection<string>(datosDeTrabajo.Imagenes.Keys); // Actualizar claves
SelectedImage = null;
if (listaImagenes.FirstOrDefault() != null)
SelectedImage = listaImagenes.FirstOrDefault();
OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad
OnPropertyChanged(nameof(listaImagenes)); // Notificar que la lista de imágenes ha cambiado
}
}
}
public PLCViewModel PLCViewModel
{
get { return plcViewModelData; }
set
{
plcViewModelData = value;
OnPropertyChanged(nameof(PLCViewModel));
}
}
private string _selectedImage = null;
public string SelectedImage
{
get => _selectedImage;
set
{
if (_selectedImage != value && value != null)
{
StopSimulation();
SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen
_selectedImage = value;
ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen
LoadStateObjetosSimulables();
}
_selectedImage = value;
OnPropertyChanged(nameof(SelectedImage));
}
}
private osBase _selectedItemOsList;
public osBase SelectedItemOsList
{
get => _selectedItemOsList;
set
{
if (_selectedItemOsList != value)
{
_selectedItemOsList = value;
OnPropertyChanged(nameof(SelectedItemOsList));
}
}
}
public ICommand OpenWorkDirectoryCommand { get; }
private void OpenWorkDirectory()
{
var dialog = new VistaFolderBrowserDialog();
@ -322,20 +377,6 @@ namespace CtrEditor
// Lista de osBase
//
public ObservableCollection<osBase> ObjetosSimulables
{
get => _objetosSimulables;
set
{
if (_objetosSimulables != value)
{
_objetosSimulables = value;
OnPropertyChanged(nameof(ObjetosSimulables));
}
}
}
public void Save()
{
SaveStateObjetosSimulables();
@ -423,28 +464,6 @@ namespace CtrEditor
}
private bool CrearUsercontrol(osBase osObjeto)
{
Type tipoObjeto = osObjeto.GetType();
// Obtén el UserControl correspondiente para el tipo de objeto
UserControl? userControl = UserControlFactory.GetControlForType(tipoObjeto);
if (userControl != null)
{
// Asignar los datos al UserControl
UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager);
osObjeto._mainViewModel = this;
OnUserControlSelected?.Invoke(userControl);
return true;
}
return false;
}
// Implementación de INotifyPropertyChanged...
public event PropertyChangedEventHandler PropertyChanged;

View File

@ -22,7 +22,6 @@ using UserControl = System.Windows.Controls.UserControl;
using CheckBox = System.Windows.Controls.CheckBox;
using Orientation = System.Windows.Controls.Orientation;
using ListBox = System.Windows.Controls.ListBox;
//using OpenCvSharp;
namespace CtrEditor
@ -70,6 +69,33 @@ namespace CtrEditor
}
}
private (float X, float Y) ObtenerCentroCanvasPixels()
{
var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform;
float scaleX = (float)(scaleTransform?.ScaleX ?? 1.0);
float scaleY = (float)(scaleTransform?.ScaleY ?? 1.0);
// Obtiene el área visible del ScrollViewer
float visibleWidth = (float)ImagenEnTrabajoScrollViewer.ViewportWidth;
float visibleHeight = (float)ImagenEnTrabajoScrollViewer.ViewportHeight;
// Obtiene la posición actual del desplazamiento ajustada por el zoom
float offsetX = (float)ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX;
float offsetY = (float)ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY;
// Calcula el centro visible ajustado
float centerX = offsetX + (visibleWidth / scaleX) / 2;
float centerY = offsetY + (visibleHeight / scaleY) / 2;
return (centerX, centerY);
}
private (float X, float Y) ObtenerCentroCanvasMeters()
{
var c = ObtenerCentroCanvasPixels();
return (PixelToMeter.Instance.calc.PixelsToMeters(c.X), PixelToMeter.Instance.calc.PixelsToMeters(c.Y));
}
private void AgregarUserControl(UserControl userControl)
{
if (userControl is IDataContainer dataContainer)
@ -78,26 +104,12 @@ namespace CtrEditor
if (!NuevoOS.Inicializado) // Aun no fue inicializado
{
Random rnd = new Random();
// Obtiene el factor de escala
var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform;
double scaleX = scaleTransform?.ScaleX ?? 1.0;
double scaleY = scaleTransform?.ScaleY ?? 1.0;
// Obtiene el área visible del ScrollViewer
double visibleWidth = ImagenEnTrabajoScrollViewer.ViewportWidth;
double visibleHeight = ImagenEnTrabajoScrollViewer.ViewportHeight;
// Obtiene la posición actual del desplazamiento ajustada por el zoom
double offsetX = ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX;
double offsetY = ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY;
// Calcula el centro visible ajustado
double centerX = offsetX + (visibleWidth / scaleX) / 2;
double centerY = offsetY + (visibleHeight / scaleY) / 2;
var centro = ObtenerCentroCanvasPixels();
// Ajusta la posición del UserControl para que esté centrado en el área visible
double leftPixels = centerX - (userControl.ActualWidth / 2);
double topPixels = centerY - (userControl.ActualHeight / 2);
double leftPixels = centro.X - (userControl.ActualWidth / 2);
double topPixels = centro.Y - (userControl.ActualHeight / 2);
// Establece la posición del UserControl
NuevoOS.Left = PixelToMeter.Instance.calc.PixelsToMeters((float)leftPixels + (float)(rnd.NextDouble() - 0.5) );

View File

@ -31,6 +31,8 @@ namespace CtrEditor.ObjetosSim
return new ucTanque();
if (tipoObjeto == typeof(osSensTemperatura))
return new ucSensTemperatura();
if (tipoObjeto == typeof(osFiller))
return new ucFiller();
// Puedes añadir más condiciones para otros tipos
@ -58,6 +60,8 @@ namespace CtrEditor.ObjetosSim
return new osTanque();
if (tipoObjeto == typeof(osSensTemperatura))
return new osSensTemperatura();
if (tipoObjeto == typeof(osFiller))
return new osFiller();
// Puedes añadir más condiciones para otros tipos

View File

@ -18,6 +18,7 @@ using System.Windows.Media;
using Microsoft.Xna.Framework;
using FarseerPhysics.Dynamics;
using Siemens.Simatic.Simulation.Runtime;
using System.Windows.Media.Imaging;
namespace CtrEditor.ObjetosSim
{
@ -33,6 +34,7 @@ namespace CtrEditor.ObjetosSim
public interface IDataContainer
{
[JsonIgnore]
osBase? Datos { get; set; }
void Resize(float width, float height);
void Move(float Left, float Top);
@ -47,7 +49,8 @@ namespace CtrEditor.ObjetosSim
public abstract float Top { get; set; }
public bool Inicializado = false;
[JsonIgnore]
protected UserControl? _visualRepresentation = null;
public abstract string Nombre { get; set; }
@ -241,6 +244,28 @@ namespace CtrEditor.ObjetosSim
return simulationManager.AddLine(coords.Start, coords.End);
}
public ImageSource ImageFromPath(string value)
{
if (value is string stringValue)
{
return new BitmapImage(new Uri(stringValue, UriKind.RelativeOrAbsolute));
}
return null;
}
static protected T GetLastElement<T>(List<T> list) where T : class
{
if (list.Count > 0)
{
return list[list.Count - 1];
}
else
{
return null;
}
}
public event PropertyChangedEventHandler PropertyChanged;

View File

@ -13,8 +13,12 @@
<Grid>
<Image Source="/motor2.png"
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform"/>
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform">
<Image.RenderTransform>
<RotateTransform Angle="{Binding Angulo}" />
</Image.RenderTransform>
</Image>
</Grid>
</UserControl>

View File

@ -27,9 +27,9 @@ namespace CtrEditor.ObjetosSim
private string _nombre = "Ejemplo";
private float _ancho;
private float _alto;
private float _angulo;
private float _left;
private float _top;
private float _angulo;
public override float Left
{
@ -112,7 +112,7 @@ namespace CtrEditor.ObjetosSim
{
}
public override void UpdateControl()
public override void UpdateControl(int elapsedMilliseconds)
{
}

24
ObjetosSim/ucFiller.xaml Normal file
View File

@ -0,0 +1,24 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucFiller"
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"
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
mc:Ignorable="d"
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
<UserControl.Resources>
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
</UserControl.Resources>
<Grid>
<Image Source="/imagenes/filler.png"
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform">
<Image.RenderTransform>
<RotateTransform Angle="{Binding Angulo}" />
</Image.RenderTransform>
</Image>
</Grid>
</UserControl>

242
ObjetosSim/ucFiller.xaml.cs Normal file
View File

@ -0,0 +1,242 @@
using CtrEditor.Convertidores;
using CtrEditor.Siemens;
using CtrEditor.Simulacion;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Xna.Framework;
namespace CtrEditor.ObjetosSim
{
/// <summary>
/// Interaction logic for ucFiller.xaml
/// </summary>
public class osFiller : osBase
{
// Otros datos y métodos relevantes para la simulación
private string _nombre = "Filler";
private float _ancho;
private float _alto;
private float _left;
private float _top;
private float _angulo;
private float _botellas_hora;
private float _velocidad_actual;
private float _diametro_botella;
private string _tag_consenso;
private bool _consenso;
private float TiempoRestante;
private List<simCircle> Botellas = new List<simCircle>();
public bool Consenso
{
get => _consenso;
set
{
_consenso = value;
OnPropertyChanged(nameof(Consenso));
}
}
public float Botellas_hora
{
get => _botellas_hora;
set
{
_botellas_hora = value;
OnPropertyChanged(nameof(Botellas_hora));
}
}
public float Velocidad_actual_percentual
{
get => _velocidad_actual;
set
{
_velocidad_actual = value;
OnPropertyChanged(nameof(Velocidad_actual_percentual));
}
}
public float Diametro_botella
{
get => _diametro_botella;
set
{
_diametro_botella = value;
OnPropertyChanged(nameof(Diametro_botella));
}
}
public string Tag_consenso
{
get => _tag_consenso;
set
{
_tag_consenso = value;
OnPropertyChanged(nameof(Tag_consenso));
}
}
public override float Left
{
get => _left;
set
{
_left = value;
CanvasSetLeftinMeter(value);
OnPropertyChanged(nameof(Left));
}
}
public override float Top
{
get => _top;
set
{
_top = value;
CanvasSetTopinMeter(value);
OnPropertyChanged(nameof(Top));
}
}
public float Ancho
{
get => _ancho;
set
{
_ancho = value;
OnPropertyChanged(nameof(Ancho));
}
}
public float Alto
{
get => _alto;
set
{
_alto = value;
OnPropertyChanged(nameof(Alto));
}
}
public float Angulo
{
get => _angulo;
set
{
_angulo = value;
OnPropertyChanged(nameof(Angulo));
}
}
public override string Nombre
{
get => _nombre;
set
{
if (_nombre != value)
{
_nombre = value;
OnPropertyChanged(nameof(Nombre));
}
}
}
public osFiller()
{
Ancho = 0.30f;
Alto = 0.30f;
Angulo = 0;
Velocidad_actual_percentual = 0;
Diametro_botella = 0.1f;
Botellas_hora = 10000;
}
public override void UpdateGeometryStart()
{
// Se llama antes de la simulacion
}
public override void UpdateGeometryStep()
{
}
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
{
Consenso = LeerBitTag(plc, Tag_consenso);
}
public override void UpdateControl(int elapsedMilliseconds)
{
if (Consenso && Velocidad_actual_percentual>0)
{
TiempoRestante -= elapsedMilliseconds / 1000.0f;
if (TiempoRestante <= 0)
{
TiempoRestante = Botellas_hora * (Velocidad_actual_percentual / 100.0f) / 3600.0f;
var PosSalida = new Vector2(Left, Top);
var UltimaBotellla = GetLastElement<simCircle>(Botellas);
if (UltimaBotellla != null && UltimaBotellla.Center != PosSalida)
Botellas.Add(simulationManager.AddCircle(Diametro_botella, PosSalida, 1));
}
}
}
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
// crear el objeto de simulacion
}
}
public partial class ucFiller : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public ucFiller()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
}
public void Resize(float width, float height)
{
if (Datos is osFiller datos)
{
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(width);
}
}
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)
{
if (Datos != null)
if (Datos is osFiller datos)
datos.Angulo = Angle;
}
public void Highlight(bool State) { }
public int ZIndex()
{
return 10;
}
}
}

View File

@ -1,7 +1,6 @@
using CtrEditor.Convertidores;
using CtrEditor.Siemens;
using Newtonsoft.Json.Linq;
using OpenCvSharp.Flann;
using Siemens.Simatic.Simulation.Runtime;
using System;
using System.Collections.Generic;
@ -46,7 +45,6 @@ namespace CtrEditor.ObjetosSim
private bool _SalidaAbierta_Bool;
private float _capacidadLitros;
public float Capacidad_Litros
{
get => _capacidadLitros;

View File

@ -12,7 +12,7 @@
</UserControl.Resources>
<Grid>
<Image Source="/imagenes/motor2.png"
<Image Source="{Binding ImageSource}"
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform"/>

View File

@ -15,6 +15,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CtrEditor.Simulacion;
using Newtonsoft.Json;
namespace CtrEditor.ObjetosSim
{
@ -22,25 +23,10 @@ namespace CtrEditor.ObjetosSim
/// Interaction logic for ucVMmotorSim.xaml
/// </summary>
///
public class VMSimMotor
{
public bool _STATUS_VFD_Ready;
public float STATUS_VFD_ACT_Speed_Hz;
public bool Motor_Running;
public bool STATUS_VFD_Trip;
public bool STATUS_VFD_Warning;
public bool STATUS_VFD_Coasting;
public bool OUT_Run;
public bool OUT_Stop;
public bool OUT_Reversal;
public float OUT_OUT_VFD_REQ_Speed_Hz;
}
public class osVMmotorSim : osBase
{
// Otros datos y métodos relevantes para la simulación
private string _nombre = "VetroMeccanica Motor";
@ -53,9 +39,21 @@ namespace CtrEditor.ObjetosSim
private bool _encendido;
private float _rampaSegundos;
private float _maxHz;
private ImageSource _imageSource;
private VMSimMotor motState = new VMSimMotor();
public VMSimMotor motState = new VMSimMotor();
[Hidden]
[JsonIgnore]
public ImageSource ImageSource
{
get { return _imageSource; }
set
{
_imageSource = value;
OnPropertyChanged(nameof(ImageSource));
}
}
public float Tamano
{
@ -89,13 +87,12 @@ namespace CtrEditor.ObjetosSim
}
}
public bool Encendido
{
get => _encendido;
set
{
_encendido = value;
_encendido = value;
OnPropertyChanged(nameof(Encendido));
}
}
@ -156,7 +153,12 @@ namespace CtrEditor.ObjetosSim
public float Velocidad {
get => _velocidad;
set {
_velocidad = value;
_velocidad = value;
if (value > 0)
ImageSource = ImageFromPath("/imagenes/motorVerde.png");
else
ImageSource = ImageFromPath("/imagenes/motorNegro.png");
OnPropertyChanged(nameof(Velocidad));
}
}
@ -167,7 +169,8 @@ namespace CtrEditor.ObjetosSim
PLC_NumeroMotor = 31;
MaxRatedHz = 100;
TiempoRampa = 3;
}
ImageSource = ImageFromPath("/imagenes/motor2.png");
}
public override void UpdateGeometryStart()
{
@ -178,68 +181,19 @@ namespace CtrEditor.ObjetosSim
{
}
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {
var index = 0;
switch (PLC_NumeroMotor)
{
case < 100:
index = (int)PLC_NumeroMotor-30+300;
break;
}
motState.OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run");
motState.OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\"");
motState.OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz");
motState.UpdatePLC(plc,PLC_NumeroMotor,Encendido, elapsedMilliseconds);
Velocidad = motState.STATUS_VFD_ACT_Speed_Hz / 10;
if (Encendido)
{
motState._STATUS_VFD_Ready = true;
motState.Motor_Running = true;
motState.STATUS_VFD_Trip = false;
motState.STATUS_VFD_Warning = false;
motState.STATUS_VFD_Coasting = false;
}
else
{
motState._STATUS_VFD_Ready = false;
motState.Motor_Running = false;
motState.STATUS_VFD_Trip = true;
motState.STATUS_VFD_Warning = false;
motState.STATUS_VFD_Coasting = false;
}
// Calculamos la velocidad
motState.STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(motState.STATUS_VFD_ACT_Speed_Hz, motState.OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", motState._STATUS_VFD_Ready);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", motState.Motor_Running);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Trip", motState.STATUS_VFD_Trip);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Warning", motState.STATUS_VFD_Warning);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Coasting", motState.STATUS_VFD_Coasting);
plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz",(int)motState.STATUS_VFD_ACT_Speed_Hz);
Velocidad = motState.STATUS_VFD_ACT_Speed_Hz/10;
}
private float CalcSpeedRamp(float actual, float expected, int elapsedMilliseconds)
{
float hzIncrementsRamp = (MaxRatedHz * 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))
hzIncrementsRamp = Math.Abs(delta);
if (delta < 0)
return -hzIncrementsRamp;
else
return hzIncrementsRamp;
}
public override void UpdateControl(int elapsedMilliseconds)
{
// Calculamos la velocidad
motState.UpdateSpeed(MaxRatedHz,TiempoRampa, elapsedMilliseconds);
}
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
@ -277,4 +231,82 @@ namespace CtrEditor.ObjetosSim
return 10;
}
}
public class VMSimMotor
{
public bool _STATUS_VFD_Ready;
public float STATUS_VFD_ACT_Speed_Hz;
public bool Motor_Running;
public bool STATUS_VFD_Trip;
public bool STATUS_VFD_Warning;
public bool STATUS_VFD_Coasting;
public bool OUT_Run;
public bool OUT_Stop;
public bool OUT_Reversal;
public float OUT_OUT_VFD_REQ_Speed_Hz;
public void UpdatePLC(PLCModel plc, int NumeroMotor, bool Encendido, int elapsedMilliseconds)
{
var index = 0;
switch (NumeroMotor)
{
case < 100:
index = (int)NumeroMotor - 30 + 300;
break;
}
OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run");
OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\"");
OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz");
if (Encendido)
{
_STATUS_VFD_Ready = true;
Motor_Running = true;
STATUS_VFD_Trip = false;
STATUS_VFD_Warning = false;
STATUS_VFD_Coasting = false;
}
else
{
_STATUS_VFD_Ready = false;
Motor_Running = false;
STATUS_VFD_Trip = true;
STATUS_VFD_Warning = false;
STATUS_VFD_Coasting = false;
}
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", _STATUS_VFD_Ready);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", Motor_Running);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Trip", STATUS_VFD_Trip);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Warning", STATUS_VFD_Warning);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Coasting", STATUS_VFD_Coasting);
plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz", (int)STATUS_VFD_ACT_Speed_Hz);
}
private float CalcSpeedRamp(float MaxRatedHz, float TiempoRampa, float actual, float expected, int elapsedMilliseconds)
{
float hzIncrementsRamp = (MaxRatedHz * 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))
hzIncrementsRamp = Math.Abs(delta);
if (delta < 0)
return -hzIncrementsRamp;
else
return hzIncrementsRamp;
}
public void UpdateSpeed(float MaxRatedHz, 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);
}
}
}

BIN
imagenes/filler.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

BIN
imagenes/motorVerde.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB