Compare commits

...

2 Commits

20 changed files with 830 additions and 85 deletions

View File

@ -6,9 +6,83 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows;
using System.Windows.Media;
namespace CtrEditor.Convertidores
{
public class WidthPercentageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double width)
{
return width * 0.25;
}
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class LevelToHeightMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is float level && values[1] is double containerHeight)
{
return containerHeight * (level / 100);
}
return 0;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class BrushToColorNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is SolidColorBrush brush)
{
if (brush == Brushes.Red) return "Rojo";
if (brush == Brushes.Blue) return "Azul";
if (brush == Brushes.Black) return "Negro";
if (brush == Brushes.Green) return "Verde";
if (brush == Brushes.Gray) return "Gris";
}
return "Unknown";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string colorName)
{
switch (colorName)
{
case "Rojo":
return Brushes.Red;
case "Azul":
return Brushes.Blue;
case "Negro":
return Brushes.Black;
case "Verde":
return Brushes.Green;
case "Gris":
return Brushes.Gray;
}
}
return Brushes.Transparent;
}
}
public class PixelToMeter
{
// Instancia privada estática, parte del patrón Singleton

View File

@ -9,19 +9,24 @@
</PropertyGroup>
<ItemGroup>
<Compile Remove="ObjetosSim\ucBasicExample.xaml.cs" />
<Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" />
<Compile Remove="Simulacion\GeometrySimulator.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="motor2.png" />
<None Remove="tank.png" />
</ItemGroup>
<ItemGroup>
<Page Remove="ObjetosSim\ucBasicExample.xaml" />
<Page Remove="ObjetosSim\ucTransporteCurva.xaml" />
</ItemGroup>
<ItemGroup>
<None Include="ObjetosSim\ucBasicExample.xaml" />
<None Include="ObjetosSim\ucBasicExample.xaml.cs" />
<None Include="ObjetosSim\ucTransporteCurva.xaml" />
<None Include="ObjetosSim\ucTransporteCurva.xaml.cs" />
<None Include="Simulacion\GeometrySimulator.cs" />
@ -44,6 +49,7 @@
<ItemGroup>
<Resource Include="motor2.png" />
<Resource Include="tank.png" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,5 @@
using System;
using CtrEditor;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
@ -25,6 +26,8 @@ using System.Windows;
using static System.Resources.ResXFileRef;
using CtrEditor.Convertidores;
using CtrEditor.Simulacion;
using System.Diagnostics;
using Newtonsoft.Json.Linq;
namespace CtrEditor
{
@ -36,6 +39,7 @@ namespace CtrEditor
public ObservableCollection<TipoSimulable> ListaOsBase { get; } = new ObservableCollection<TipoSimulable>();
private ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>();
public PLCViewModel _plcViewModelData;
public Stopwatch stopwatch;
public SimulationManagerFP simulationManager = new SimulationManagerFP();
@ -70,6 +74,8 @@ namespace CtrEditor
StartSimulationCommand = new RelayCommand(StartSimulation);
StopSimulationCommand = new RelayCommand(StopSimulation);
stopwatch = new Stopwatch();
}
public void LoadInitialData()
@ -155,11 +161,21 @@ namespace CtrEditor
private void OnRefreshEvent(object sender, EventArgs e)
{
foreach (var objetoSimulable in ObjetosSimulables)
if (_plcViewModelData.IsConnected)
{
if (_plcViewModelData.IsConnected)
objetoSimulable.UpdatePLC(_plcViewModelData.PLCInterface);
}
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
stopwatch.Stop();
float elapsedMilliseconds = (float)stopwatch.Elapsed.TotalMilliseconds;
// Reiniciar el cronómetro para la próxima medición
stopwatch.Restart();
foreach (var objetoSimulable in ObjetosSimulables)
objetoSimulable.UpdatePLC(_plcViewModelData.PLCInterface, (int) elapsedMilliseconds);
} else
stopwatch.Stop();
}
//protected virtual void OnTickSimulacion(TickSimulacionEventArgs e)
@ -260,10 +276,19 @@ namespace CtrEditor
}
}
public void Save()
{
SaveStateObjetosSimulables();
ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[_selectedImage]); // Dispara el evento con la nueva ruta de imagen
LoadStateObjetosSimulables();
}
public void SaveStateObjetosSimulables()
{
if (_selectedImage != null)
{
StopSimulation();
PLCViewModel.Disconnect();
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
@ -274,6 +299,7 @@ namespace CtrEditor
{
obj.VisualRepresentation = null;
obj.simulationManager = null;
obj._mainViewModel = null;
}
// Crear un objeto que incluya tanto los ObjetosSimulables como el UnitConverter
var dataToSerialize = new SimulationData
@ -292,6 +318,8 @@ namespace CtrEditor
{
try
{
StopSimulation();
PLCViewModel.Disconnect();
ObjetosSimulables.Clear();
simulationManager.Clear();
if (_selectedImage != null)
@ -321,6 +349,9 @@ namespace CtrEditor
PixelToMeter.Instance.calc = simulationData.UnitConverter;
// Re-register to the events
_plcViewModelData.RefreshEvent += OnRefreshEvent;
// Recorrer la colección de objetos simulables
foreach (var objetoSimulable in ObjetosSimulables)
CrearUsercontrol(objetoSimulable);
@ -343,6 +374,7 @@ namespace CtrEditor
{
// Asignar los datos al UserControl
UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager);
osObjeto._mainViewModel = this;
OnUserControlSelected?.Invoke(userControl);
@ -353,7 +385,6 @@ namespace CtrEditor
// Implementación de INotifyPropertyChanged...
public event PropertyChangedEventHandler PropertyChanged;
@ -362,7 +393,21 @@ namespace CtrEditor
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private RelayCommand saveCommand;
public ICommand SaveCommand => saveCommand ??= new RelayCommand(Save);
private void Save(object commandParameter)
{
}
private RelayCommand exitCommand;
public ICommand ExitCommand => exitCommand ??= new RelayCommand(Exit);
private void Exit()
{
Save();
Application.Current.Shutdown();
}
}
public class SimulationData
{

View File

@ -11,6 +11,7 @@
<Window.Resources>
<convert:FloatToFormattedStringConverter x:Key="floatFormatter"/>
<convert:BrushToColorNameConverter x:Key="BrushToColorNameConverter"/>
</Window.Resources>
<Window.DataContext>

View File

@ -21,6 +21,7 @@ using TextBox = System.Windows.Controls.TextBox;
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;
@ -418,6 +419,11 @@ namespace CtrEditor
foreach (var property in properties)
{
if (Attribute.IsDefined(property, typeof(HiddenAttribute)))
{
continue;
}
var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
@ -480,11 +486,61 @@ namespace CtrEditor
grid.Children.Add(label);
grid.Children.Add(checkBox);
}
else if (property.PropertyType == typeof(Brush))
{
var listBox = new ListBox
{
ItemsSource = new List<string> { "Rojo", "Azul", "Negro", "Verde", "Gris" },
Margin = new Thickness(0),
MinWidth = 200
};
listBox.SelectionChanged += (sender, e) =>
{
if (listBox.SelectedItem != null)
{
switch (listBox.SelectedItem.ToString())
{
case "Rojo":
property.SetValue(selectedObject, Brushes.Red);
break;
case "Azul":
property.SetValue(selectedObject, Brushes.Blue);
break;
case "Negro":
property.SetValue(selectedObject, Brushes.Black);
break;
case "Verde":
property.SetValue(selectedObject, Brushes.Green);
break;
case "Gris":
property.SetValue(selectedObject, Brushes.Gray);
break;
}
}
};
var binding = new Binding(property.Name)
{
Source = selectedObject,
Mode = BindingMode.TwoWay,
Converter = new BrushToColorNameConverter()
};
listBox.SetBinding(ListBox.SelectedItemProperty, binding);
Grid.SetColumn(label, 0);
Grid.SetColumn(listBox, 1);
grid.Children.Add(label);
grid.Children.Add(listBox);
}
PanelEdicion.Children.Add(grid);
}
}
private void MainWindow_Closed(object sender, EventArgs e)
{
if (DataContext is MainViewModel viewModel)

View File

@ -27,6 +27,8 @@ namespace CtrEditor.ObjetosSim
return new ucVMmotorSim();
if (tipoObjeto == typeof(osBoton))
return new ucBoton();
if (tipoObjeto == typeof(osTanque))
return new ucTanque();
// Puedes añadir más condiciones para otros tipos
@ -49,6 +51,8 @@ namespace CtrEditor.ObjetosSim
return new osVMmotorSim();
if (tipoObjeto == typeof(osBoton))
return new osBoton();
if (tipoObjeto == typeof(osTanque))
return new osTanque();
// Puedes añadir más condiciones para otros tipos

View File

@ -54,9 +54,12 @@ namespace CtrEditor.ObjetosSim
public abstract void UpdateControl();
public abstract void UpdateGeometryStart();
public abstract void UpdateGeometryStep();
public abstract void UpdatePLC(PLCModel plc);
public abstract void UpdatePLC(PLCModel plc, int elapsedMilliseconds);
public abstract void ucLoaded();
[JsonIgnore]
public MainViewModel _mainViewModel;
[JsonIgnore]
public UserControl? VisualRepresentation
{
@ -185,4 +188,8 @@ namespace CtrEditor.ObjetosSim
}
}
[AttributeUsage(AttributeTargets.Property)]
public class HiddenAttribute : Attribute
{
}
}

View File

@ -0,0 +1,20 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucBasicExample"
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="/motor2.png"
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,167 @@
using CtrEditor.Convertidores;
using CtrEditor.Siemens;
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;
namespace CtrEditor.ObjetosSim
{
/// <summary>
/// Interaction logic for ucBasicExample.xaml
/// </summary>
public class osBasicExample : osBase
{
// Otros datos y métodos relevantes para la simulación
private string _nombre = "Ejemplo";
private float _ancho;
private float _alto;
private float _left;
private float _top;
private float _angulo;
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 osBasicExample()
{
Ancho = 0.30f;
Alto = 0.30f;
}
public override void UpdateGeometryStart()
{
// Se llama antes de la simulacion
}
public override void UpdateGeometryStep()
{
}
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
{
}
public override void UpdateControl()
{
}
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
// crear el objeto de simulacion
}
}
public partial class ucBasicExample : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public ucBasicExample()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
}
public void Resize(float width, float height) {
if (Datos is osBasicExample 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 osBasicExample datos)
datos.Angulo = Angle;
}
public void Highlight(bool State) { }
public int ZIndex()
{
return 10;
}
}
}

View File

@ -139,7 +139,7 @@ namespace CtrEditor.ObjetosSim
ActualizarGeometrias();
}
public override void UpdatePLC(PLCModel plc) { }
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { }
public override void UpdateControl()
{

View File

@ -13,37 +13,24 @@
</UserControl.Resources>
<Grid>
<Rectangle x:Name="BackgroundRectangle"
Fill="LightGray"
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.5}"
VerticalAlignment="Top"
HorizontalAlignment="Left"
/>
<Button Content="Button"
<Border x:Name="BackgroundRectangle"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="0,0,10,10"
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Background="{Binding Color}"
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.5}"
VerticalAlignment="Top"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
MouseLeftButtonDown="Button_MouseLeftButtonDown"
MouseLeftButtonUp="Button_MouseLeftButtonUp">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<ei:InvokeCommandAction Command="{Binding ButtonDownCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeftButtonUp">
<ei:InvokeCommandAction Command="{Binding ButtonUpCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="2"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
Background="Gray"/>
<Ellipse Fill="{Binding ColorButton}"
Stroke="Black"
StrokeThickness="2"
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp">
</Ellipse>
</Grid>
</UserControl>

View File

@ -32,6 +32,8 @@ namespace CtrEditor.ObjetosSim
private string _tag;
private Brush _color;
private Brush _colorButton;
public Brush Color
{
get => _color;
@ -42,9 +44,16 @@ namespace CtrEditor.ObjetosSim
}
}
public ICommand ButtonClickCommand { get; }
public ICommand ButtonDownCommand { get; }
public ICommand ButtonUpCommand { get; }
[Hidden]
public Brush ColorButton
{
get => _colorButton;
set
{
_colorButton = value;
OnPropertyChanged(nameof(ColorButton));
}
}
public override float Left
{
@ -81,6 +90,10 @@ namespace CtrEditor.ObjetosSim
set
{
_estado = value;
if (value)
ColorButton = Brushes.LightGreen;
else
ColorButton = Color;
OnPropertyChanged(nameof(Estado));
}
}
@ -110,20 +123,11 @@ namespace CtrEditor.ObjetosSim
}
}
private void OnButtonClick()
{
// Handle the click event here
// Example: Change color on click
Color = Brushes.LightGreen;
}
private void OnButtonDown()
public void ButtonDownCommand()
{
Estado = true;
}
private void OnButtonUp()
public void ButtonUpCommand()
{
Estado = false;
}
@ -135,11 +139,6 @@ namespace CtrEditor.ObjetosSim
Tag = "M50.0";
// Set initial color
Color = Brushes.LightBlue;
// Initialize the command
ButtonClickCommand = new RelayCommand(OnButtonClick);
ButtonDownCommand = new RelayCommand(OnButtonDown);
ButtonUpCommand = new RelayCommand(OnButtonUp);
}
public override void UpdateGeometryStart()
@ -150,9 +149,9 @@ namespace CtrEditor.ObjetosSim
public override void UpdateGeometryStep()
{
}
public override void UpdatePLC(PLCModel plc)
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
{
plc.EscribirTagBool(Tag, Estado);
plc.EscribirTagBool(_tag, Estado);
}
public override void UpdateControl()
@ -175,28 +174,37 @@ namespace CtrEditor.ObjetosSim
{
InitializeComponent();
this.Loaded += OnLoaded;
this.DataContextChanged += OnDataContextChanged;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
}
private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Datos = e.NewValue as osBase;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (Datos is osBoton osBotonData)
{
osBotonData.ButtonDownCommand.Execute(null);
Mouse.Capture((UIElement)sender);
osBotonData.ButtonDownCommand();
e.Handled = true; // Evita que el evento se propague
}
}
private void Button_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
private void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (Datos is osBoton osBotonData)
{
osBotonData.ButtonUpCommand.Execute(null);
Mouse.Capture(null); // Release mouse capture
osBotonData.ButtonUpCommand();
e.Handled = true; // Evita que el evento se propague
}
}
public void Resize(float width, float height) { }
public void Move(float LeftPixels, float TopPixels)
{

View File

@ -121,7 +121,7 @@ namespace CtrEditor.ObjetosSim
public override void UpdateGeometryStep()
{
}
public override void UpdatePLC(PLCModel plc) { }
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { }
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para

39
ObjetosSim/ucTanque.xaml Normal file
View File

@ -0,0 +1,39 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucTanque"
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"/>
<convert:LevelToHeightMultiConverter x:Key="LevelToHeightMultiConverter"/>
<convert:WidthPercentageConverter x:Key="WidthPercentageConverter"/>
</UserControl.Resources>
<Grid>
<Image x:Name="TankImage"
Source="/tank.png"
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform"/>
<Rectangle x:Name="WaterLevel"
Fill="Blue"
VerticalAlignment="Bottom"
HorizontalAlignment="Center">
<Rectangle.Width>
<Binding ElementName="TankImage" Path="ActualWidth" Converter="{StaticResource WidthPercentageConverter}" />
</Rectangle.Width>
<Rectangle.Height>
<MultiBinding Converter="{StaticResource LevelToHeightMultiConverter}">
<Binding Path="Level" />
<Binding ElementName="TankImage" Path="ActualHeight" />
</MultiBinding>
</Rectangle.Height>
</Rectangle>
<Label Content="{Binding Level}" HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Top"/>
</Grid>
</UserControl>

201
ObjetosSim/ucTanque.xaml.cs Normal file
View File

@ -0,0 +1,201 @@
using CtrEditor.Convertidores;
using CtrEditor.Siemens;
using OpenCvSharp.Flann;
using Siemens.Simatic.Simulation.Runtime;
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;
namespace CtrEditor.ObjetosSim
{
/// <summary>
/// Interaction logic for ucTanque.xaml
/// </summary>
public class osTanque : osBase
{
// Otros datos y métodos relevantes para la simulación
private string _nombre = "Tanque";
private float _ancho;
private float _alto;
private float _left;
private float _top;
private float _angulo;
private float _level;
private string _tag;
public string Tag
{
get => _tag;
set
{
if (_tag != value)
{
_tag = value;
OnPropertyChanged(nameof(Tag));
}
}
}
public float Level
{
get => _level;
set
{
_level = value;
OnPropertyChanged(nameof(Level));
}
}
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 osTanque()
{
Ancho = 0.30f;
Alto = 0.30f;
}
public override void UpdateGeometryStart()
{
// Se llama antes de la simulacion
}
public override void UpdateGeometryStep()
{
}
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
{
if (Tag.Length > 0)
{
SDataValue s = new SDataValue();
s.UInt16 = (ushort)(Level / 100.0 * 26600);
plc.EscribirTag(Tag, s);
}
}
public override void UpdateControl()
{
}
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
// crear el objeto de simulacion
}
}
public partial class ucTanque : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public ucTanque()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
}
public void Resize(float width, float height)
{
if (Datos is osTanque 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 osTanque datos)
datos.Angulo = Angle;
}
public void Highlight(bool State) { }
public int ZIndex()
{
return 10;
}
}
}

View File

@ -15,6 +15,7 @@ using System.Windows.Shapes;
using CtrEditor.Convertidores;
using CtrEditor.Siemens;
using CtrEditor.Simulacion;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace CtrEditor.ObjetosSim
{
@ -39,12 +40,28 @@ namespace CtrEditor.ObjetosSim
private float _top;
private float _angulo;
private float _velocidadActual;
private osBase _osMotor = null;
private string _motor;
private simRectangle? TransporteCentral;
private simLine? Guia_Superior;
private simLine? Guia_Inferior;
public string Motor
{
get => _motor;
set
{
if (_motor != value)
{
_motor = value;
OnPropertyChanged(nameof(Motor));
}
}
}
public override float Left
{
get => _left;
@ -179,7 +196,24 @@ namespace CtrEditor.ObjetosSim
public override void UpdateControl()
{
}
public override void UpdatePLC(PLCModel plc) { }
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
{
if (_osMotor != null)
{
if (_osMotor is osVMmotorSim motor)
VelocidadActual = motor.Velocidad;
} else
{
if (Motor.Length > 0)
if (_mainViewModel != null)
foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables)
if (objetoSimulable.Nombre == _motor)
{
_osMotor = objetoSimulable;
break;
}
}
}
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
@ -196,6 +230,7 @@ namespace CtrEditor.ObjetosSim
Guia_Superior = AddLine(simulationManager, uc.GuiaSuperior);
Guia_Inferior = AddLine(simulationManager, uc.GuiaInferior);
}
Motor = Motor; // Forzar la busqueda
}

View File

@ -27,10 +27,23 @@ namespace CtrEditor.ObjetosSim
private float _top;
private float _angulo;
private float _velocidadActual;
private osBase _osMotor = null;
private string _motor;
private simRectangle Simulation_Transporte;
public string Motor
{
get => _motor;
set
{
if (_motor != value)
{
_motor = value;
OnPropertyChanged(nameof(Motor));
}
}
}
public override float Left
{
get => _left;
@ -132,8 +145,25 @@ namespace CtrEditor.ObjetosSim
public override void UpdateGeometryStep()
{
}
public override void UpdatePLC(PLCModel plc) { }
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
{
if (_osMotor != null)
{
if (_osMotor is osVMmotorSim motor)
VelocidadActual = motor.Velocidad;
}
else
{
if (Motor.Length > 0)
if (_mainViewModel != null)
foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables)
if (objetoSimulable.Nombre == _motor)
{
_osMotor = objetoSimulable;
break;
}
}
}
public override void UpdateControl()
{

View File

@ -51,6 +51,9 @@ namespace CtrEditor.ObjetosSim
private float _ratio;
private float _velocidad;
private bool _encendido;
private float _rampaSegundos;
private float _maxHz;
public VMSimMotor motState = new VMSimMotor();
@ -64,6 +67,29 @@ namespace CtrEditor.ObjetosSim
}
}
public float MaxRatedHz
{
get => _maxHz;
set
{
_maxHz = value;
OnPropertyChanged(nameof(Tamano));
}
}
public float TiempoRampa
{
get => _rampaSegundos;
set
{
if (value < 0.1f)
value = 0.1f;
_rampaSegundos = value;
OnPropertyChanged(nameof(Tamano));
}
}
public bool Encendido
{
get => _encendido;
@ -139,6 +165,8 @@ namespace CtrEditor.ObjetosSim
{
Tamano = 0.30f;
PLC_NumeroMotor = 31;
MaxRatedHz = 100;
TiempoRampa = 3;
}
public override void UpdateGeometryStart()
@ -149,7 +177,7 @@ namespace CtrEditor.ObjetosSim
public override void UpdateGeometryStep()
{
}
public override void UpdatePLC(PLCModel plc) {
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {
var index = 0;
switch (PLC_NumeroMotor)
{
@ -162,6 +190,8 @@ namespace CtrEditor.ObjetosSim
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");
if (Encendido)
{
motState._STATUS_VFD_Ready = true;
@ -169,19 +199,19 @@ namespace CtrEditor.ObjetosSim
motState.STATUS_VFD_Trip = false;
motState.STATUS_VFD_Warning = false;
motState.STATUS_VFD_Coasting = false;
if (motState.STATUS_VFD_ACT_Speed_Hz < motState.OUT_OUT_VFD_REQ_Speed_Hz)
motState.STATUS_VFD_ACT_Speed_Hz += motState.OUT_OUT_VFD_REQ_Speed_Hz / 375 ; // Simulate Ramp
} else
}
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;
if (motState.STATUS_VFD_ACT_Speed_Hz > 0)
motState.STATUS_VFD_ACT_Speed_Hz -= 1; // Simulate Ramp
}
// 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);
@ -193,6 +223,19 @@ namespace CtrEditor.ObjetosSim
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()
{

View File

@ -42,7 +42,7 @@ namespace CtrEditor.Siemens
{
IsConnected = false;
PLCInterface = new PLCModel();
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1000) };
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(10) };
_timer.Tick += (s, e) => Refresh();
ConnectCommand = new RelayCommand(Connect, () => true);
@ -102,7 +102,7 @@ namespace CtrEditor.Siemens
}
}
private void Connect()
public void Connect()
{
// Implementa la conexión utilizando PLCModel
PLCInterface.Instance = SimulationRuntimeManager.CreateInterface(Name);
@ -123,7 +123,7 @@ namespace CtrEditor.Siemens
PLCInterface.UpdateTagList();
}
private void Disconnect()
public void Disconnect()
{
IsConnected = false;
_timer.Stop();
@ -137,10 +137,10 @@ namespace CtrEditor.Siemens
{
CpuTime = PLCInterface.LeerTagInt16("\"DB HMI\".CPU_Scan_Time")?.ToString() ?? "N/A";
LastError = PLCInterface.LastError;
}
// Disparar el evento RefreshEvent
RefreshEvent?.Invoke(this, EventArgs.Empty);
// Disparar el evento RefreshEvent
RefreshEvent?.Invoke(this, EventArgs.Empty);
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
@ -193,7 +193,29 @@ namespace CtrEditor.Siemens
LastError = ex.Message;
}
}
public void EscribirTag(string pTag, SDataValue Value)
{
try
{
Instance?.Write(pTag, Value);
}
catch (Exception ex)
{
LastError = pTag + ":" + ex.Message;
}
}
public SDataValue LeerTag(string pTag)
{
try
{
return Instance.Read(pTag);
}
catch (Exception ex)
{
LastError = pTag + ":" + ex.Message;
return new SDataValue();
}
}
public void EscribirTagBool(string pTag, bool pValue)
{
try

BIN
tank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB