2024-05-23 14:56:14 -03:00
|
|
|
|
using System.ComponentModel;
|
2024-05-02 11:06:45 -03:00
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
using Ookii.Dialogs.Wpf;
|
2024-05-03 03:58:21 -03:00
|
|
|
|
using System.Collections.ObjectModel;
|
2024-05-03 05:13:25 -03:00
|
|
|
|
using System.Windows.Threading;
|
2024-05-04 06:00:52 -03:00
|
|
|
|
using CtrEditor.ObjetosSim;
|
2024-06-28 14:47:08 -03:00
|
|
|
|
using LibS7Adv;
|
2024-05-04 06:00:52 -03:00
|
|
|
|
using System.IO;
|
|
|
|
|
using Newtonsoft.Json;
|
2024-05-04 15:35:06 -03:00
|
|
|
|
using System.Windows;
|
2024-05-14 03:15:54 -03:00
|
|
|
|
using CtrEditor.Simulacion;
|
2024-05-14 12:10:32 -03:00
|
|
|
|
using System.Diagnostics;
|
2024-05-19 16:38:57 -03:00
|
|
|
|
using System.Reflection;
|
2024-05-25 07:53:34 -03:00
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
2024-06-02 04:13:01 -03:00
|
|
|
|
using Xceed.Wpf.Toolkit.PropertyGrid;
|
2024-06-10 19:22:33 -03:00
|
|
|
|
using CtrEditor.ObjetosSim.Extraccion_Datos;
|
|
|
|
|
using ClosedXML.Excel;
|
|
|
|
|
using CtrEditor.PopUps;
|
2024-06-12 19:26:02 -03:00
|
|
|
|
using System.Windows.Data;
|
2024-06-28 14:47:08 -03:00
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
2025-02-13 10:00:47 -03:00
|
|
|
|
using System.Text.RegularExpressions;
|
2025-02-13 12:52:33 -03:00
|
|
|
|
using System.Collections.Specialized;
|
2024-06-12 19:26:02 -03:00
|
|
|
|
|
2024-05-02 11:06:45 -03:00
|
|
|
|
|
|
|
|
|
namespace CtrEditor
|
|
|
|
|
{
|
2024-05-03 05:13:25 -03:00
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
public partial class MainViewModel : ObservableObject
|
2024-05-02 11:06:45 -03:00
|
|
|
|
{
|
2024-05-25 07:53:34 -03:00
|
|
|
|
public Stopwatch stopwatch_Sim;
|
|
|
|
|
|
|
|
|
|
private double stopwatch_SimPLC_last;
|
|
|
|
|
private double stopwatch_SimModel_last;
|
|
|
|
|
|
2024-05-18 10:35:46 -03:00
|
|
|
|
private float TiempoDesdeStartSimulacion;
|
|
|
|
|
private bool Debug_SimulacionCreado = false;
|
2024-05-16 13:45:14 -03:00
|
|
|
|
|
2024-05-14 03:15:54 -03:00
|
|
|
|
public SimulationManagerFP simulationManager = new SimulationManagerFP();
|
2024-05-06 12:31:45 -03:00
|
|
|
|
|
2024-05-03 05:13:25 -03:00
|
|
|
|
private readonly DispatcherTimer _timerSimulacion;
|
2024-06-28 14:47:08 -03:00
|
|
|
|
private readonly DispatcherTimer _timerPLCUpdate;
|
2024-05-04 06:00:52 -03:00
|
|
|
|
|
2024-05-31 14:25:24 -03:00
|
|
|
|
public Canvas MainCanvas;
|
|
|
|
|
|
2025-02-17 09:04:21 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private bool isConnected;
|
|
|
|
|
|
|
|
|
|
partial void OnPLCViewModelChanged(PLCViewModel value)
|
2024-06-28 14:47:08 -03:00
|
|
|
|
{
|
2025-02-17 09:04:21 -03:00
|
|
|
|
if (value != null)
|
|
|
|
|
{
|
|
|
|
|
value.PropertyChanged += PLCViewModel_PropertyChanged;
|
|
|
|
|
IsConnected = value.IsConnected;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PLCViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.PropertyName == nameof(PLCViewModel.IsConnected))
|
|
|
|
|
{
|
|
|
|
|
IsConnected = PLCViewModel.IsConnected;
|
|
|
|
|
}
|
2024-06-28 14:47:08 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private DatosDeTrabajo datosDeTrabajo;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private ObservableCollection<string> listaImagenes; // Publicación de las claves del diccionario
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
public ObservableCollection<TipoSimulable> listaOsBase;
|
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
public ICommand StartSimulationCommand { get; }
|
|
|
|
|
public ICommand StopSimulationCommand { get; }
|
|
|
|
|
public ICommand ItemDoubleClickCommand { get; private set; }
|
|
|
|
|
|
2024-05-15 06:20:09 -03:00
|
|
|
|
public ICommand TBStartSimulationCommand { get; }
|
|
|
|
|
public ICommand TBStopSimulationCommand { get; }
|
|
|
|
|
public ICommand TBSaveCommand { get; }
|
2024-06-10 19:22:33 -03:00
|
|
|
|
public ICommand TBExtractTagsCommand { get; }
|
2024-05-02 11:06:45 -03:00
|
|
|
|
|
2024-05-19 14:56:08 -03:00
|
|
|
|
public ICommand TBEliminarUserControlCommand { get; }
|
2024-05-20 09:05:34 -03:00
|
|
|
|
public ICommand TBDuplicarUserControlCommand { get; }
|
|
|
|
|
|
2024-05-18 05:53:04 -03:00
|
|
|
|
public ICommand OpenWorkDirectoryCommand { get; }
|
|
|
|
|
|
2024-06-10 19:22:33 -03:00
|
|
|
|
public ICommand TBEliminarTodosCommand { get; }
|
|
|
|
|
public ICommand TBEliminarAutoCreatedCommand { get; }
|
|
|
|
|
public ICommand TBEliminarClonedCommand { get; }
|
|
|
|
|
public ICommand TBAssingPagesCommand { get; }
|
|
|
|
|
public ICommand TBMultiPageExtractTagsCommand { get; }
|
|
|
|
|
public ICommand TBMultiPageAnalizeCommand { get; }
|
2025-02-15 18:38:12 -03:00
|
|
|
|
public ICommand TBMultiPageMatrixCommand { get; }
|
2024-06-10 19:22:33 -03:00
|
|
|
|
|
2025-02-17 09:04:21 -03:00
|
|
|
|
|
|
|
|
|
public ICommand TBTogglePLCConnectionCommand => new RelayCommand(() =>
|
|
|
|
|
{
|
|
|
|
|
if (IsConnected)
|
|
|
|
|
DisconnectPLC();
|
|
|
|
|
else
|
|
|
|
|
ConnectPLC();
|
|
|
|
|
});
|
|
|
|
|
|
2024-05-03 03:58:21 -03:00
|
|
|
|
// Evento que se dispara cuando se selecciona una nueva imagen
|
|
|
|
|
public event EventHandler<string> ImageSelected;
|
2024-05-03 05:13:25 -03:00
|
|
|
|
public event EventHandler<TickSimulacionEventArgs> TickSimulacion;
|
2024-05-02 11:06:45 -03:00
|
|
|
|
|
2024-05-18 06:49:02 -03:00
|
|
|
|
// Propiedades
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2024-05-19 14:56:08 -03:00
|
|
|
|
private bool habilitarEliminarUserControl;
|
2024-05-25 07:53:34 -03:00
|
|
|
|
|
2024-05-18 06:49:02 -03:00
|
|
|
|
private MainWindow mainWindow;
|
|
|
|
|
|
|
|
|
|
public MainWindow MainWindow { get => mainWindow; set => mainWindow = value; }
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2024-06-12 19:26:02 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
public ICollectionView vistaFiltrada;
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private float canvasLeft;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private float canvasTop;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private bool isSimulationRunning;
|
|
|
|
|
|
2025-02-13 12:52:33 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private bool hasUnsavedChanges;
|
|
|
|
|
|
2025-02-14 10:04:29 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private ObservableCollection<string> recentDirectories;
|
|
|
|
|
|
2025-02-15 18:38:12 -03:00
|
|
|
|
private bool inhibitSaveChangesControl;
|
|
|
|
|
|
2025-02-14 10:04:29 -03:00
|
|
|
|
public ICommand OpenRecentDirectoryCommand { get; private set; }
|
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
partial void OnIsSimulationRunningChanged(bool value)
|
2024-05-18 05:53:04 -03:00
|
|
|
|
{
|
2024-05-25 07:53:34 -03:00
|
|
|
|
CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado
|
2024-05-18 05:53:04 -03:00
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 12:52:33 -03:00
|
|
|
|
partial void OnHasUnsavedChangesChanged(bool value)
|
|
|
|
|
{
|
|
|
|
|
// Notificar el cambio del título indirectamente a través de directorioTrabajo
|
|
|
|
|
OnPropertyChanged(nameof(directorioTrabajo));
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-18 05:53:04 -03:00
|
|
|
|
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
|
2024-05-25 07:53:34 -03:00
|
|
|
|
DatosDeTrabajo.CargarImagenes();
|
|
|
|
|
ListaImagenes = new ObservableCollection<string>(DatosDeTrabajo.Imagenes.Keys); // Actualizar claves
|
2024-09-12 11:43:39 -03:00
|
|
|
|
// Si no hay imágenes en el directorio, copiar base.png desde los recursos
|
|
|
|
|
if (!ListaImagenes.Any())
|
|
|
|
|
{
|
|
|
|
|
CopiarImagenBase(value);
|
|
|
|
|
// Recargar las imágenes después de copiar la imagen base
|
|
|
|
|
DatosDeTrabajo.CargarImagenes();
|
|
|
|
|
ListaImagenes = new ObservableCollection<string>(DatosDeTrabajo.Imagenes.Keys); // Actualizar claves nuevamente
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-18 05:53:04 -03:00
|
|
|
|
SelectedImage = null;
|
2024-06-12 19:26:02 -03:00
|
|
|
|
var x = ListaImagenes.FirstOrDefault(o => o == EstadoPersistente.Instance.imagen, null);
|
|
|
|
|
if (EstadoPersistente.Instance.imagen != null && EstadoPersistente.Instance.imagen.Length > 0 && x != null)
|
2024-06-09 05:39:31 -03:00
|
|
|
|
SelectedImage = EstadoPersistente.Instance.imagen;
|
|
|
|
|
else if (ListaImagenes.FirstOrDefault() != null)
|
2024-05-25 07:53:34 -03:00
|
|
|
|
SelectedImage = ListaImagenes.FirstOrDefault();
|
2024-06-09 05:39:31 -03:00
|
|
|
|
|
2024-05-18 05:53:04 -03:00
|
|
|
|
OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad
|
2024-05-25 07:53:34 -03:00
|
|
|
|
OnPropertyChanged(nameof(ListaImagenes)); // Notificar que la lista de imágenes ha cambiado
|
2025-02-14 10:04:29 -03:00
|
|
|
|
|
|
|
|
|
AddToRecentDirectories(value);
|
2024-05-18 05:53:04 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 11:43:39 -03:00
|
|
|
|
// Función para copiar la imagen base desde los recursos
|
|
|
|
|
private void CopiarImagenBase(string directorio)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Obtener el path del archivo base.png desde los recursos (dentro del ensamblado)
|
|
|
|
|
var assembly = Assembly.GetExecutingAssembly();
|
|
|
|
|
var resourcePath = "CtrEditor.Images.base.png"; // Ajusta el namespace y el path según tu proyecto
|
|
|
|
|
|
|
|
|
|
using (Stream resourceStream = assembly.GetManifestResourceStream(resourcePath))
|
|
|
|
|
{
|
|
|
|
|
if (resourceStream != null)
|
|
|
|
|
{
|
|
|
|
|
string destino = Path.Combine(directorio, "base.png");
|
|
|
|
|
|
|
|
|
|
using (FileStream fileStream = new FileStream(destino, FileMode.Create, FileAccess.Write))
|
|
|
|
|
{
|
|
|
|
|
resourceStream.CopyTo(fileStream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show($"Error al copiar la imagen base: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-28 14:47:08 -03:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
public void DebugWindow()
|
|
|
|
|
{
|
|
|
|
|
MainWindow.DebugWindow();
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private PLCViewModel pLCViewModel;
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private string selectedImage;
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2025-02-17 09:04:21 -03:00
|
|
|
|
partial void OnSelectedImageChanging(string? oldValue, string newValue)
|
2024-05-18 05:53:04 -03:00
|
|
|
|
{
|
2025-02-17 09:04:21 -03:00
|
|
|
|
if (HasUnsavedChanges && !inhibitSaveChangesControl)
|
2024-05-18 05:53:04 -03:00
|
|
|
|
{
|
2025-02-17 09:04:21 -03:00
|
|
|
|
var result = MessageBox.Show("There are unsaved changes. Do you want to save them?",
|
|
|
|
|
"Save Changes",
|
|
|
|
|
MessageBoxButton.YesNo);
|
|
|
|
|
|
|
|
|
|
if (result == MessageBoxResult.Yes)
|
2025-02-13 12:52:33 -03:00
|
|
|
|
{
|
2025-02-17 09:04:21 -03:00
|
|
|
|
SaveStateObjetosSimulables();
|
2025-02-13 12:52:33 -03:00
|
|
|
|
}
|
2025-02-17 09:04:21 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
partial void OnSelectedImageChanged(string value)
|
|
|
|
|
{
|
|
|
|
|
if (value != null)
|
|
|
|
|
{
|
2024-05-25 07:53:34 -03:00
|
|
|
|
StopSimulation();
|
2025-02-13 12:52:33 -03:00
|
|
|
|
ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]);
|
2024-05-25 07:53:34 -03:00
|
|
|
|
LoadStateObjetosSimulables();
|
2024-06-09 05:39:31 -03:00
|
|
|
|
EstadoPersistente.Instance.imagen = value;
|
|
|
|
|
EstadoPersistente.Instance.GuardarEstado();
|
2025-02-13 12:52:33 -03:00
|
|
|
|
HasUnsavedChanges = false;
|
2024-05-18 05:53:04 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
[ObservableProperty]
|
2024-06-12 19:26:02 -03:00
|
|
|
|
private osBase selectedItemOsList;
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2024-06-12 19:26:02 -03:00
|
|
|
|
partial void OnSelectedItemOsListChanged(osBase value)
|
2024-05-18 05:53:04 -03:00
|
|
|
|
{
|
2024-06-12 19:26:02 -03:00
|
|
|
|
if (value != null)
|
2024-05-25 07:53:34 -03:00
|
|
|
|
habilitarEliminarUserControl = true;
|
|
|
|
|
else
|
|
|
|
|
habilitarEliminarUserControl = false;
|
2024-05-18 05:53:04 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-12 19:26:02 -03:00
|
|
|
|
[ObservableProperty]
|
2024-06-20 09:50:23 -03:00
|
|
|
|
public ObjetosSimulablesFilterTypes osListFilter;
|
2024-06-12 19:26:02 -03:00
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private TipoSimulable selectedItem;
|
|
|
|
|
|
2024-06-05 17:27:53 -03:00
|
|
|
|
public ICollectionView ObjetosSimulablesFiltered { get; }
|
|
|
|
|
public ICollectionView ObjetosSimulablesAllPages { get; }
|
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
public ObservableCollection<osBase> objetosSimulables;
|
2024-05-27 05:34:20 -03:00
|
|
|
|
|
2024-06-12 19:26:02 -03:00
|
|
|
|
partial void OnObjetosSimulablesChanged(ObservableCollection<osBase> value)
|
|
|
|
|
{
|
|
|
|
|
VistaFiltrada = CollectionViewSource.GetDefaultView(ObjetosSimulables);
|
|
|
|
|
VistaFiltrada.Filter = FiltrarObjetos;
|
2025-02-15 18:38:12 -03:00
|
|
|
|
ObjetosSimulables.CollectionChanged += (s, e) =>
|
|
|
|
|
{
|
|
|
|
|
VistaFiltrada.Refresh();
|
|
|
|
|
if (!inhibitSaveChangesControl && e.Action != NotifyCollectionChangedAction.Move)
|
|
|
|
|
HasUnsavedChanges = true;
|
|
|
|
|
};
|
2024-06-12 19:26:02 -03:00
|
|
|
|
}
|
2024-06-05 17:27:53 -03:00
|
|
|
|
|
2024-05-18 06:49:02 -03:00
|
|
|
|
//
|
|
|
|
|
// Constructor
|
|
|
|
|
//
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2025-02-17 09:04:21 -03:00
|
|
|
|
private StateManager _stateManager;
|
|
|
|
|
|
2024-05-02 11:06:45 -03:00
|
|
|
|
public MainViewModel()
|
|
|
|
|
{
|
|
|
|
|
OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory);
|
2024-05-03 03:58:21 -03:00
|
|
|
|
datosDeTrabajo = new DatosDeTrabajo();
|
2024-05-04 06:00:52 -03:00
|
|
|
|
|
2024-06-20 09:50:23 -03:00
|
|
|
|
OsListFilter = new ObjetosSimulablesFilterTypes();
|
|
|
|
|
OsListFilter.All = true;
|
2024-06-11 14:43:12 -03:00
|
|
|
|
|
2024-06-12 19:26:02 -03:00
|
|
|
|
osListFilter.PropertyChanged += OsListFilter_PropertyChanged;
|
|
|
|
|
|
|
|
|
|
ObjetosSimulables = new ObservableCollection<osBase>();
|
2024-06-05 17:27:53 -03:00
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
ListaOsBase = new ObservableCollection<TipoSimulable>();
|
|
|
|
|
|
2024-05-10 17:17:57 -03:00
|
|
|
|
// Inicializa el PLCViewModel
|
2024-05-25 07:53:34 -03:00
|
|
|
|
PLCViewModel = new PLCViewModel();
|
2024-06-28 14:47:08 -03:00
|
|
|
|
|
|
|
|
|
_timerPLCUpdate = new DispatcherTimer();
|
2025-02-17 09:04:21 -03:00
|
|
|
|
_timerPLCUpdate.Interval = TimeSpan.FromMilliseconds(10); // ajusta el intervalo según sea necesario
|
2024-06-28 14:47:08 -03:00
|
|
|
|
_timerPLCUpdate.Tick += OnRefreshEvent;
|
2024-05-10 17:17:57 -03:00
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
InitializeTipoSimulableList();
|
|
|
|
|
|
|
|
|
|
ItemDoubleClickCommand = new ParameterizedRelayCommand(ExecuteDoubleClick);
|
2024-05-03 05:13:25 -03:00
|
|
|
|
|
|
|
|
|
_timerSimulacion = new DispatcherTimer();
|
2025-02-13 10:00:47 -03:00
|
|
|
|
_timerSimulacion.Interval = TimeSpan.FromMilliseconds(10); // ajusta el intervalo según sea necesario
|
2024-05-03 05:13:25 -03:00
|
|
|
|
_timerSimulacion.Tick += OnTickSimulacion;
|
|
|
|
|
|
|
|
|
|
StartSimulationCommand = new RelayCommand(StartSimulation);
|
2024-05-14 12:10:32 -03:00
|
|
|
|
StopSimulationCommand = new RelayCommand(StopSimulation);
|
|
|
|
|
|
2024-05-15 06:20:09 -03:00
|
|
|
|
TBStartSimulationCommand = new RelayCommand(StartSimulation, () => !IsSimulationRunning);
|
|
|
|
|
TBStopSimulationCommand = new RelayCommand(StopSimulation, () => IsSimulationRunning);
|
|
|
|
|
TBSaveCommand = new RelayCommand(Save);
|
|
|
|
|
|
2024-05-19 14:56:08 -03:00
|
|
|
|
TBEliminarUserControlCommand = new RelayCommand(EliminarUserControl, () => habilitarEliminarUserControl);
|
2024-05-20 09:05:34 -03:00
|
|
|
|
TBDuplicarUserControlCommand = new RelayCommand(DuplicarUserControl, () => habilitarEliminarUserControl);
|
2024-05-19 14:56:08 -03:00
|
|
|
|
|
2024-06-10 19:22:33 -03:00
|
|
|
|
TBEliminarTodosCommand = new RelayCommand(EliminarTodosCommand);
|
|
|
|
|
TBEliminarAutoCreatedCommand = new RelayCommand(EliminarAutoCreatedCommand);
|
|
|
|
|
TBEliminarClonedCommand = new RelayCommand(EliminarClonedCommand);
|
|
|
|
|
TBAssingPagesCommand = new RelayCommand(AssingPagesCommand);
|
|
|
|
|
TBMultiPageAnalizeCommand = new RelayCommand(MultiPageAnalizeCommand);
|
2025-02-15 18:38:12 -03:00
|
|
|
|
TBMultiPageMatrixCommand = new RelayCommand(MultiPageMatrixCommand);
|
2024-06-10 19:22:33 -03:00
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
stopwatch_Sim = new Stopwatch();
|
|
|
|
|
stopwatch_Sim.Start();
|
2025-02-13 12:52:33 -03:00
|
|
|
|
|
|
|
|
|
ObjetosSimulables.CollectionChanged += (s, e) =>
|
|
|
|
|
{
|
|
|
|
|
if (e.Action != NotifyCollectionChangedAction.Move)
|
|
|
|
|
HasUnsavedChanges = true;
|
|
|
|
|
};
|
2025-02-14 10:04:29 -03:00
|
|
|
|
|
|
|
|
|
recentDirectories = new ObservableCollection<string>(EstadoPersistente.Instance.RecentDirectories);
|
|
|
|
|
OpenRecentDirectoryCommand = new RelayCommand<string>(OpenRecentDirectory);
|
2025-02-17 09:04:21 -03:00
|
|
|
|
|
|
|
|
|
_stateManager = new StateManager(EstadoPersistente.Instance.directorio, this);
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-12 19:26:02 -03:00
|
|
|
|
private void OsListFilter_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
VistaFiltrada.Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool FiltrarObjetos(object item)
|
|
|
|
|
{
|
|
|
|
|
var objeto = item as osBase;
|
|
|
|
|
|
2024-06-20 09:50:23 -03:00
|
|
|
|
return osListFilter.All || (objeto.Cloned == osListFilter.Cloned) &&
|
2024-06-12 19:26:02 -03:00
|
|
|
|
(objeto.Enable_On_All_Pages == osListFilter.Enable_On_All_Pages) &&
|
|
|
|
|
(objeto.Show_On_This_Page == osListFilter.Show_On_This_Page);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
public void LoadInitialData()
|
|
|
|
|
{
|
|
|
|
|
// Suponiendo que "SelectedImage" es una propiedad que al establecerse dispara "ImageSelected"
|
|
|
|
|
directorioTrabajo = EstadoPersistente.Instance.directorio;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-18 06:49:02 -03:00
|
|
|
|
// Crear un nuevo Objeto
|
|
|
|
|
private void ExecuteDoubleClick(object parameter)
|
|
|
|
|
{
|
|
|
|
|
if (parameter is TipoSimulable tipoSimulable)
|
|
|
|
|
{
|
2024-05-18 09:58:41 -03:00
|
|
|
|
CrearObjetoSimulableEnCentroCanvas(tipoSimulable.Tipo);
|
2024-05-18 06:49:02 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-04 06:00:52 -03:00
|
|
|
|
|
2024-05-18 09:58:41 -03:00
|
|
|
|
public void CrearObjetoSimulableEnCentroCanvas(Type tipoSimulable)
|
|
|
|
|
{
|
|
|
|
|
var CentroCanvas = MainWindow.ObtenerCentroCanvasMeters();
|
2024-05-27 05:34:20 -03:00
|
|
|
|
CrearObjetoSimulable(tipoSimulable, CentroCanvas.X, CentroCanvas.Y);
|
2024-05-18 09:58:41 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-27 05:34:20 -03:00
|
|
|
|
public osBase CrearObjetoSimulable(Type tipoSimulable, float Left, float Top)
|
2024-05-04 06:00:52 -03:00
|
|
|
|
{
|
2024-05-18 05:53:04 -03:00
|
|
|
|
// Crear una nueva instancia del osBase correspondiente
|
2024-05-18 06:49:02 -03:00
|
|
|
|
osBase? NuevoOsBase = UserControlFactory.GetInstanceForType(tipoSimulable);
|
|
|
|
|
|
2024-05-18 09:58:41 -03:00
|
|
|
|
NuevoOsBase.Left = Left;
|
|
|
|
|
NuevoOsBase.Top = Top;
|
2024-05-18 06:49:02 -03:00
|
|
|
|
|
|
|
|
|
if (NuevoOsBase != null)
|
2024-05-04 06:00:52 -03:00
|
|
|
|
{
|
2024-05-18 06:49:02 -03:00
|
|
|
|
if (CrearUserControlDesdeObjetoSimulable(NuevoOsBase))
|
2025-02-13 12:52:33 -03:00
|
|
|
|
{
|
2024-05-18 05:53:04 -03:00
|
|
|
|
// Añadir el nuevo osBase a la colección de objetos simulables
|
2024-05-18 06:49:02 -03:00
|
|
|
|
ObjetosSimulables.Add(NuevoOsBase);
|
2025-02-13 12:52:33 -03:00
|
|
|
|
HasUnsavedChanges = true;
|
|
|
|
|
}
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
2024-05-18 09:58:41 -03:00
|
|
|
|
return NuevoOsBase;
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-18 06:49:02 -03:00
|
|
|
|
// Crear UserControl desde osBase : Nuevo o desde Deserealizacion
|
|
|
|
|
private bool CrearUserControlDesdeObjetoSimulable(osBase osObjeto)
|
2024-05-18 05:53:04 -03:00
|
|
|
|
{
|
|
|
|
|
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;
|
2024-06-10 19:22:33 -03:00
|
|
|
|
if (osObjeto.Id == null) // Para los objetos salvados antes de usar UniqueID
|
|
|
|
|
osObjeto.Id = new UniqueId().ObtenerNuevaID();
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
2024-05-18 06:49:02 -03:00
|
|
|
|
MainWindow.AgregarRegistrarUserControlCanvas(userControl);
|
2024-05-18 05:53:04 -03:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-05-04 06:00:52 -03:00
|
|
|
|
|
2024-05-18 09:58:41 -03:00
|
|
|
|
public void RemoverObjetoSimulable(osBase osObjeto)
|
|
|
|
|
{
|
|
|
|
|
if (osObjeto != null && ObjetosSimulables.Contains(osObjeto))
|
|
|
|
|
{
|
|
|
|
|
ObjetosSimulables.Remove(osObjeto);
|
|
|
|
|
if (osObjeto.VisualRepresentation != null)
|
|
|
|
|
MainWindow.EliminarUserControlDelCanvas(osObjeto.VisualRepresentation);
|
2025-02-13 12:52:33 -03:00
|
|
|
|
HasUnsavedChanges = true;
|
2024-05-18 09:58:41 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-19 14:56:08 -03:00
|
|
|
|
|
2024-05-20 09:05:34 -03:00
|
|
|
|
private void DuplicarUserControl()
|
|
|
|
|
{
|
2024-06-12 19:26:02 -03:00
|
|
|
|
if (SelectedItemOsList is osBase objDuplicar)
|
2024-06-10 06:07:25 -03:00
|
|
|
|
DuplicarObjeto(objDuplicar, 0.5f, 0.5f);
|
|
|
|
|
}
|
2024-05-20 09:05:34 -03:00
|
|
|
|
|
2024-06-10 06:07:25 -03:00
|
|
|
|
public osBase DuplicarObjeto(osBase objDuplicar, float OffsetX, float OffsetY)
|
|
|
|
|
{
|
|
|
|
|
StopSimulation();
|
|
|
|
|
DisconnectPLC();
|
2024-05-20 09:05:34 -03:00
|
|
|
|
|
2024-06-10 06:07:25 -03:00
|
|
|
|
osBase? NuevoObjetoDuplicado = null;
|
2024-05-20 09:05:34 -03:00
|
|
|
|
|
2024-06-10 06:07:25 -03:00
|
|
|
|
objDuplicar.SalvarDatosNoSerializables();
|
|
|
|
|
|
|
|
|
|
var settings = new JsonSerializerSettings
|
|
|
|
|
{
|
|
|
|
|
Formatting = Formatting.Indented,
|
|
|
|
|
NullValueHandling = NullValueHandling.Ignore,
|
|
|
|
|
TypeNameHandling = TypeNameHandling.All
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Serializar
|
|
|
|
|
var serializedData = JsonConvert.SerializeObject(objDuplicar, settings);
|
|
|
|
|
// Duplicar
|
|
|
|
|
NuevoObjetoDuplicado = JsonConvert.DeserializeObject<osBase>(serializedData, settings);
|
|
|
|
|
if (NuevoObjetoDuplicado != null)
|
2024-05-27 05:34:20 -03:00
|
|
|
|
{
|
2024-06-10 06:07:25 -03:00
|
|
|
|
NuevoObjetoDuplicado.Id.ObtenerNuevaID();
|
2025-02-13 10:00:47 -03:00
|
|
|
|
string nombre = Regex.IsMatch(NuevoObjetoDuplicado.Nombre, @"_\d+$")
|
|
|
|
|
? Regex.Replace(NuevoObjetoDuplicado.Nombre, @"_\d+$", $"_{NuevoObjetoDuplicado.Id.Value}")
|
|
|
|
|
: NuevoObjetoDuplicado.Nombre + "_" + NuevoObjetoDuplicado.Id.Value;
|
2024-06-10 06:07:25 -03:00
|
|
|
|
|
|
|
|
|
NuevoObjetoDuplicado.Nombre = nombre;
|
|
|
|
|
NuevoObjetoDuplicado.Left += OffsetX;
|
|
|
|
|
NuevoObjetoDuplicado.Top += OffsetY;
|
|
|
|
|
ObjetosSimulables.Add(NuevoObjetoDuplicado);
|
|
|
|
|
CrearUserControlDesdeObjetoSimulable(NuevoObjetoDuplicado);
|
2025-02-13 12:52:33 -03:00
|
|
|
|
HasUnsavedChanges = true;
|
2024-05-20 09:05:34 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-10 06:07:25 -03:00
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// Log error or handle it accordingly
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
2024-06-10 19:22:33 -03:00
|
|
|
|
objDuplicar.RestaurarDatosNoSerializables();
|
2024-06-10 06:07:25 -03:00
|
|
|
|
}
|
|
|
|
|
return NuevoObjetoDuplicado;
|
2024-05-20 09:05:34 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-10 06:07:25 -03:00
|
|
|
|
|
2025-02-13 12:52:33 -03:00
|
|
|
|
public void EliminarObjetoSeleccionado()
|
2024-05-19 14:56:08 -03:00
|
|
|
|
{
|
2024-06-12 19:26:02 -03:00
|
|
|
|
if (SelectedItemOsList is osBase objEliminar)
|
2024-06-09 05:39:31 -03:00
|
|
|
|
{
|
2025-02-13 12:52:33 -03:00
|
|
|
|
var result = MessageBox.Show($"¿Está seguro que desea eliminar el objeto '{objEliminar.Nombre}'?",
|
|
|
|
|
"Confirmar eliminación",
|
|
|
|
|
MessageBoxButton.YesNo,
|
|
|
|
|
MessageBoxImage.Question);
|
|
|
|
|
|
|
|
|
|
if (result == MessageBoxResult.Yes)
|
|
|
|
|
{
|
|
|
|
|
RemoverObjetoSimulable(objEliminar);
|
|
|
|
|
}
|
2024-06-09 05:39:31 -03:00
|
|
|
|
}
|
2024-05-19 14:56:08 -03:00
|
|
|
|
}
|
2024-05-18 09:58:41 -03:00
|
|
|
|
|
2025-02-13 12:52:33 -03:00
|
|
|
|
private void EliminarUserControl()
|
|
|
|
|
{
|
|
|
|
|
EliminarObjetoSeleccionado();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-10 19:22:33 -03:00
|
|
|
|
|
|
|
|
|
private void EliminarTodosCommand()
|
|
|
|
|
{
|
|
|
|
|
var objetosSimulablesCopy = new List<osBase>(ObjetosSimulables);
|
|
|
|
|
foreach (var obj in objetosSimulablesCopy)
|
|
|
|
|
RemoverObjetoSimulable(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EliminarAutoCreatedCommand()
|
|
|
|
|
{
|
2024-06-12 19:26:02 -03:00
|
|
|
|
var osAutoCreated_List = ObjetosSimulables
|
|
|
|
|
.Where(o => o.Show_On_This_Page && o.AutoCreated)
|
|
|
|
|
.ToList();
|
|
|
|
|
foreach (var obj in osAutoCreated_List)
|
2024-06-10 19:22:33 -03:00
|
|
|
|
RemoverObjetoSimulable(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EliminarClonedCommand()
|
|
|
|
|
{
|
2024-06-12 19:26:02 -03:00
|
|
|
|
var osCloned_List = ObjetosSimulables
|
|
|
|
|
.Where(o => o.Show_On_This_Page && o.Cloned)
|
|
|
|
|
.ToList();
|
|
|
|
|
foreach (var obj in osCloned_List)
|
2024-06-10 19:22:33 -03:00
|
|
|
|
RemoverObjetoSimulable(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AssingPagesCommand()
|
|
|
|
|
{
|
|
|
|
|
var assignImagesWindow = new AssignImagesWindow();
|
|
|
|
|
var assignImagesViewModel = new AssignImagesViewModel();
|
|
|
|
|
assignImagesViewModel.Initialize(this, assignImagesWindow);
|
|
|
|
|
assignImagesWindow.DataContext = assignImagesViewModel;
|
|
|
|
|
assignImagesWindow.ShowDialog();
|
2024-06-11 07:30:27 -03:00
|
|
|
|
if (assignImagesWindow.DataContext is AssignImagesViewModel dialog && dialog.CloseOK)
|
|
|
|
|
SaveStateObjetosSimulables();
|
2024-06-10 19:22:33 -03:00
|
|
|
|
}
|
|
|
|
|
|
2025-02-15 18:38:12 -03:00
|
|
|
|
public async Task WaitForUIUpdateAsync()
|
2024-06-10 19:22:33 -03:00
|
|
|
|
{
|
|
|
|
|
await Task.Yield();
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() => { }, DispatcherPriority.ApplicationIdle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void MultiPageAnalizeCommand()
|
|
|
|
|
{
|
2024-06-11 07:30:27 -03:00
|
|
|
|
var ImagenesSeleccionadas = new ObservableCollection<string>
|
|
|
|
|
{
|
|
|
|
|
SelectedImage
|
|
|
|
|
};
|
2024-06-10 19:22:33 -03:00
|
|
|
|
|
|
|
|
|
StopSimulation();
|
|
|
|
|
|
|
|
|
|
var selectPagesWindow = new SelectPages();
|
|
|
|
|
var selectPagesViewModel = new SelectPagesViewModel();
|
|
|
|
|
selectPagesViewModel.Initialize(this, selectPagesWindow, ref ImagenesSeleccionadas);
|
|
|
|
|
selectPagesWindow.DataContext = selectPagesViewModel;
|
|
|
|
|
selectPagesWindow.ShowDialog();
|
|
|
|
|
|
2025-02-15 18:38:12 -03:00
|
|
|
|
bool originalHasUnsavedChanges = HasUnsavedChanges;
|
|
|
|
|
HasUnsavedChanges = false;
|
2024-06-10 19:22:33 -03:00
|
|
|
|
|
2025-02-15 18:38:12 -03:00
|
|
|
|
try
|
2024-06-10 19:22:33 -03:00
|
|
|
|
{
|
2025-02-15 18:38:12 -03:00
|
|
|
|
if (selectPagesWindow.DataContext is SelectPagesViewModel dialog && dialog.CloseOK)
|
|
|
|
|
{
|
|
|
|
|
SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen
|
|
|
|
|
|
|
|
|
|
foreach (var page in ImagenesSeleccionadas)
|
|
|
|
|
{
|
|
|
|
|
SelectedImage = page;
|
|
|
|
|
await WaitForUIUpdateAsync(); // Espera a que la UI se actualice
|
|
|
|
|
AnalizePageCommand();
|
|
|
|
|
await WaitForUIUpdateAsync(); // Espera a que la UI se actualice
|
2024-06-10 19:22:33 -03:00
|
|
|
|
|
2025-02-15 18:38:12 -03:00
|
|
|
|
SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
HasUnsavedChanges = originalHasUnsavedChanges;
|
2024-06-10 19:22:33 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AnalizePageCommand()
|
|
|
|
|
{
|
|
|
|
|
foreach (var obj in ObjetosSimulables)
|
|
|
|
|
if (obj is osBuscarCoincidencias objBC)
|
2024-06-11 07:30:27 -03:00
|
|
|
|
if (objBC.Show_On_This_Page)
|
|
|
|
|
objBC.BuscarCoincidencias();
|
2024-06-10 19:22:33 -03:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
private void InitializeTipoSimulableList()
|
|
|
|
|
{
|
|
|
|
|
var baseType = typeof(osBase);
|
|
|
|
|
var types = AppDomain.CurrentDomain.GetAssemblies()
|
|
|
|
|
.SelectMany(assembly => assembly.GetTypes())
|
2024-05-19 16:38:57 -03:00
|
|
|
|
.Where(type => type.IsSubclassOf(baseType) && !type.IsAbstract && typeof(IosBase).IsAssignableFrom(type));
|
2024-05-04 06:00:52 -03:00
|
|
|
|
|
|
|
|
|
foreach (var type in types)
|
|
|
|
|
{
|
2024-05-19 16:38:57 -03:00
|
|
|
|
var methodInfo = type.GetMethod("NombreClase", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
|
|
|
|
|
string nombre = methodInfo != null ? methodInfo.Invoke(null, null)?.ToString() : "Nombre no encontrado";
|
|
|
|
|
|
|
|
|
|
ListaOsBase.Add(new TipoSimulable { Nombre = nombre, Tipo = type });
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
2024-05-03 05:13:25 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-19 16:38:57 -03:00
|
|
|
|
|
2024-05-03 05:13:25 -03:00
|
|
|
|
private void StartSimulation()
|
|
|
|
|
{
|
2024-05-22 14:21:39 -03:00
|
|
|
|
IsSimulationRunning = true;
|
|
|
|
|
|
2024-05-14 03:15:54 -03:00
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
|
|
|
|
objetoSimulable.UpdateGeometryStart();
|
|
|
|
|
|
|
|
|
|
simulationManager.Debug_DrawInitialBodies();
|
2024-05-18 10:35:46 -03:00
|
|
|
|
TiempoDesdeStartSimulacion = 0;
|
|
|
|
|
Debug_SimulacionCreado = true;
|
2024-05-14 03:15:54 -03:00
|
|
|
|
|
2024-05-03 05:13:25 -03:00
|
|
|
|
_timerSimulacion.Start();
|
2025-01-04 06:34:19 -03:00
|
|
|
|
simulationManager.Start();
|
2024-05-03 05:13:25 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void StopSimulation()
|
|
|
|
|
{
|
2024-05-22 14:21:39 -03:00
|
|
|
|
IsSimulationRunning = false;
|
|
|
|
|
|
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
|
|
|
|
objetoSimulable.SimulationStop();
|
|
|
|
|
|
2024-05-18 10:35:46 -03:00
|
|
|
|
if (Debug_SimulacionCreado)
|
|
|
|
|
{
|
|
|
|
|
simulationManager.Debug_ClearSimulationShapes();
|
|
|
|
|
Debug_SimulacionCreado = false;
|
|
|
|
|
}
|
2024-05-03 05:13:25 -03:00
|
|
|
|
_timerSimulacion.Stop();
|
2024-05-02 11:06:45 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-03 05:13:25 -03:00
|
|
|
|
private void OnTickSimulacion(object sender, EventArgs e)
|
|
|
|
|
{
|
2025-02-13 10:00:47 -03:00
|
|
|
|
var stopwatch = Stopwatch.StartNew(); // Start measuring time
|
|
|
|
|
|
2024-05-16 13:45:14 -03:00
|
|
|
|
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
2024-05-25 07:53:34 -03:00
|
|
|
|
var elapsedMilliseconds = stopwatch_Sim.Elapsed.TotalMilliseconds - stopwatch_SimModel_last;
|
|
|
|
|
stopwatch_SimModel_last = stopwatch_Sim.Elapsed.TotalMilliseconds;
|
2024-05-16 13:45:14 -03:00
|
|
|
|
|
2024-05-18 10:35:46 -03:00
|
|
|
|
// Eliminar el diseño de Debug luego de 2 segundos
|
2024-05-31 14:25:24 -03:00
|
|
|
|
if (TiempoDesdeStartSimulacion > 12000)
|
2024-05-18 10:35:46 -03:00
|
|
|
|
simulationManager.Debug_ClearSimulationShapes();
|
|
|
|
|
else
|
2024-05-25 07:53:34 -03:00
|
|
|
|
TiempoDesdeStartSimulacion += (float)elapsedMilliseconds;
|
2024-05-03 05:13:25 -03:00
|
|
|
|
|
2024-05-10 20:40:51 -03:00
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
2024-05-14 03:15:54 -03:00
|
|
|
|
objetoSimulable.UpdateGeometryStep();
|
2024-05-10 20:40:51 -03:00
|
|
|
|
|
2024-05-14 07:04:22 -03:00
|
|
|
|
simulationManager.Step();
|
2024-05-06 12:31:45 -03:00
|
|
|
|
|
2024-05-18 09:58:41 -03:00
|
|
|
|
var objetosSimulablesCopy = new List<osBase>(ObjetosSimulables);
|
|
|
|
|
|
|
|
|
|
foreach (var objetoSimulable in objetosSimulablesCopy)
|
|
|
|
|
{
|
|
|
|
|
if (!objetoSimulable.RemoverDesdeSimulacion)
|
|
|
|
|
objetoSimulable.UpdateControl((int)elapsedMilliseconds);
|
|
|
|
|
else
|
|
|
|
|
RemoverObjetoSimulable(objetoSimulable);
|
|
|
|
|
}
|
2024-05-06 12:31:45 -03:00
|
|
|
|
|
2025-02-13 10:00:47 -03:00
|
|
|
|
stopwatch.Stop(); // Stop measuring time
|
|
|
|
|
//Debug.WriteLine($"OnTickSimulacion execution time: {stopwatch.TotalMilliseconds} ms");
|
2024-05-03 05:13:25 -03:00
|
|
|
|
}
|
2024-05-02 11:06:45 -03:00
|
|
|
|
|
2024-05-15 06:20:09 -03:00
|
|
|
|
private void ConnectPLC()
|
|
|
|
|
{
|
2024-06-28 14:47:08 -03:00
|
|
|
|
_timerPLCUpdate.Start();
|
2024-05-25 07:53:34 -03:00
|
|
|
|
PLCViewModel.Connect();
|
2024-06-28 14:47:08 -03:00
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
|
|
|
|
objetoSimulable.SetPLC(PLCViewModel);
|
2024-05-15 06:20:09 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DisconnectPLC()
|
|
|
|
|
{
|
2024-05-25 07:53:34 -03:00
|
|
|
|
PLCViewModel.Disconnect();
|
2024-06-28 14:47:08 -03:00
|
|
|
|
_timerPLCUpdate.Stop();
|
2024-05-23 14:56:14 -03:00
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
|
|
|
|
objetoSimulable.SetPLC(null);
|
|
|
|
|
|
2024-05-15 06:20:09 -03:00
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 10:00:47 -03:00
|
|
|
|
private List<osBase> objetosSimulablesLlamados = new List<osBase>();
|
|
|
|
|
|
2024-05-14 09:15:10 -03:00
|
|
|
|
private void OnRefreshEvent(object sender, EventArgs e)
|
|
|
|
|
{
|
2025-02-13 10:00:47 -03:00
|
|
|
|
var stopwatch = Stopwatch.StartNew(); // Start measuring time
|
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
if (PLCViewModel.IsConnected)
|
2024-05-14 09:15:10 -03:00
|
|
|
|
{
|
2024-05-14 12:10:32 -03:00
|
|
|
|
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
2024-05-25 07:53:34 -03:00
|
|
|
|
var elapsedMilliseconds = stopwatch_Sim.Elapsed.TotalMilliseconds - stopwatch_SimPLC_last;
|
|
|
|
|
stopwatch_SimPLC_last = stopwatch_Sim.Elapsed.TotalMilliseconds;
|
2024-05-14 12:10:32 -03:00
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
// Reiniciar el cronómetro para la próxima medición
|
2025-02-13 10:00:47 -03:00
|
|
|
|
var remainingObjetosSimulables = ObjetosSimulables.Except(objetosSimulablesLlamados).ToList();
|
|
|
|
|
|
|
|
|
|
foreach (var objetoSimulable in remainingObjetosSimulables)
|
|
|
|
|
{
|
|
|
|
|
var objStopwatch = Stopwatch.StartNew();
|
2024-06-28 14:47:08 -03:00
|
|
|
|
objetoSimulable.UpdatePLC(PLCViewModel, (int)elapsedMilliseconds);
|
2025-02-13 10:00:47 -03:00
|
|
|
|
objStopwatch.Stop();
|
|
|
|
|
|
|
|
|
|
objetosSimulablesLlamados.Add(objetoSimulable);
|
|
|
|
|
|
|
|
|
|
if (stopwatch.Elapsed.TotalMilliseconds >= 10)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (remainingObjetosSimulables.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
objetosSimulablesLlamados.Clear();
|
|
|
|
|
}
|
2024-05-27 05:34:20 -03:00
|
|
|
|
}
|
2025-02-13 10:00:47 -03:00
|
|
|
|
|
|
|
|
|
stopwatch.Stop(); // Stop measuring time
|
|
|
|
|
Debug.WriteLine($"OnRefreshEvent: {stopwatch.Elapsed.TotalMilliseconds} ms");
|
2024-05-14 09:15:10 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-02 11:06:45 -03:00
|
|
|
|
private void OpenWorkDirectory()
|
|
|
|
|
{
|
|
|
|
|
var dialog = new VistaFolderBrowserDialog();
|
|
|
|
|
if (dialog.ShowDialog() == true) // Mostrar el diálogo y comprobar si el resultado es positivo
|
|
|
|
|
{
|
2024-05-03 03:58:21 -03:00
|
|
|
|
directorioTrabajo = dialog.SelectedPath; // Actualizar la propiedad que también actualiza el estado persistente
|
2024-05-02 11:06:45 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:04:29 -03:00
|
|
|
|
private void OpenRecentDirectory(string path)
|
|
|
|
|
{
|
|
|
|
|
if (Directory.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
directorioTrabajo = path;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show($"Directory not found: {path}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
RecentDirectories.Remove(path);
|
|
|
|
|
UpdateRecentDirectories();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateRecentDirectories()
|
|
|
|
|
{
|
|
|
|
|
EstadoPersistente.Instance.RecentDirectories = RecentDirectories.ToList();
|
|
|
|
|
EstadoPersistente.Instance.GuardarEstado();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddToRecentDirectories(string path)
|
|
|
|
|
{
|
|
|
|
|
// Remove the path if it already exists
|
|
|
|
|
RecentDirectories.Remove(path);
|
|
|
|
|
|
|
|
|
|
// Add the new path at the beginning
|
|
|
|
|
RecentDirectories.Insert(0, path);
|
|
|
|
|
|
|
|
|
|
// Keep only the last 10 entries
|
|
|
|
|
while (RecentDirectories.Count > 10)
|
|
|
|
|
{
|
|
|
|
|
RecentDirectories.RemoveAt(RecentDirectories.Count - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateRecentDirectories();
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
//
|
|
|
|
|
// Lista de osBase
|
|
|
|
|
//
|
2024-05-27 05:34:20 -03:00
|
|
|
|
|
2024-05-14 12:10:32 -03:00
|
|
|
|
public void Save()
|
|
|
|
|
{
|
|
|
|
|
SaveStateObjetosSimulables();
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
public void SaveStateObjetosSimulables()
|
|
|
|
|
{
|
2024-05-25 07:53:34 -03:00
|
|
|
|
if (SelectedImage != null)
|
2024-05-04 06:00:52 -03:00
|
|
|
|
{
|
2024-05-14 12:10:32 -03:00
|
|
|
|
StopSimulation();
|
2024-05-20 09:05:34 -03:00
|
|
|
|
DisconnectPLC();
|
2024-05-18 09:58:41 -03:00
|
|
|
|
|
2024-06-05 17:27:53 -03:00
|
|
|
|
ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>();
|
|
|
|
|
ObservableCollection<osBase> _objetosSimulablesAllPages = new ObservableCollection<osBase>();
|
2024-05-18 09:58:41 -03:00
|
|
|
|
|
2024-05-20 09:05:34 -03:00
|
|
|
|
foreach (var obj in ObjetosSimulables)
|
2024-06-05 17:27:53 -03:00
|
|
|
|
{
|
2024-05-20 09:05:34 -03:00
|
|
|
|
// Guardar referencias temporales
|
|
|
|
|
obj.SalvarDatosNoSerializables();
|
2024-06-10 19:22:33 -03:00
|
|
|
|
if (!obj.Enable_On_All_Pages)
|
2024-06-05 17:27:53 -03:00
|
|
|
|
_objetosSimulables.Add(obj);
|
|
|
|
|
else
|
|
|
|
|
_objetosSimulablesAllPages.Add(obj);
|
|
|
|
|
}
|
2024-05-20 09:05:34 -03:00
|
|
|
|
|
2024-06-05 17:27:53 -03:00
|
|
|
|
// Salvar los objetos de la pagina actual
|
2024-05-18 09:58:41 -03:00
|
|
|
|
|
|
|
|
|
// Crear un objeto que incluya tanto los ObjetosSimulables como el UnitConverter y PLC_ConnectionData
|
2024-05-08 03:00:31 -03:00
|
|
|
|
var dataToSerialize = new SimulationData
|
|
|
|
|
{
|
2024-06-05 17:27:53 -03:00
|
|
|
|
ObjetosSimulables = _objetosSimulables,
|
2024-05-10 17:17:57 -03:00
|
|
|
|
UnitConverter = PixelToMeter.Instance.calc,
|
|
|
|
|
PLC_ConnectionData = PLCViewModel
|
2024-05-08 03:00:31 -03:00
|
|
|
|
};
|
|
|
|
|
|
2024-06-05 17:27:53 -03:00
|
|
|
|
// Ruta del archivo a ser guardado
|
|
|
|
|
var path = DatosDeTrabajo.ObtenerPathImagenConExtension(SelectedImage, ".json");
|
|
|
|
|
if (path != null)
|
|
|
|
|
SerializarYSalvar(dataToSerialize, path);
|
|
|
|
|
|
|
|
|
|
// Salvar los objetos de todas las paginas
|
|
|
|
|
|
|
|
|
|
// Ruta del archivo a ser guardado
|
|
|
|
|
path = DatosDeTrabajo.ObtenerPathAllPages(".json");
|
2024-06-09 05:39:31 -03:00
|
|
|
|
if (path != null)
|
2024-06-05 17:27:53 -03:00
|
|
|
|
SerializarYSalvar(_objetosSimulablesAllPages, path);
|
2024-05-18 09:58:41 -03:00
|
|
|
|
|
|
|
|
|
// Restaurar las propiedades originales de los objetos
|
|
|
|
|
foreach (var obj in ObjetosSimulables)
|
2024-05-20 09:05:34 -03:00
|
|
|
|
obj.RestaurarDatosNoSerializables();
|
2025-02-13 12:52:33 -03:00
|
|
|
|
|
|
|
|
|
HasUnsavedChanges = false;
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 17:27:53 -03:00
|
|
|
|
private void SerializarYSalvar(object listaObjetos, string path)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Verificar si el archivo ya existe y crear un respaldo
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
var backupPath = Path.ChangeExtension(path, ".bak");
|
|
|
|
|
File.Copy(path, backupPath, true); // Copia el archivo existente a un nuevo archivo .bak, sobrescribiendo si es necesario
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var settings = new JsonSerializerSettings
|
|
|
|
|
{
|
|
|
|
|
Formatting = Formatting.Indented,
|
2024-06-10 06:07:25 -03:00
|
|
|
|
// PreserveReferencesHandling = PreserveReferencesHandling.Objects,
|
2024-06-05 17:27:53 -03:00
|
|
|
|
NullValueHandling = NullValueHandling.Ignore,
|
|
|
|
|
TypeNameHandling = TypeNameHandling.Auto
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Serializar
|
|
|
|
|
var serializedData = JsonConvert.SerializeObject(listaObjetos, settings);
|
|
|
|
|
File.WriteAllText(path, serializedData); // Escribir el nuevo archivo JSON
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
public void LoadStateObjetosSimulables()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2024-05-14 12:10:32 -03:00
|
|
|
|
StopSimulation();
|
2024-05-20 09:05:34 -03:00
|
|
|
|
DisconnectPLC();
|
2024-05-04 06:00:52 -03:00
|
|
|
|
ObjetosSimulables.Clear();
|
2024-05-14 07:04:22 -03:00
|
|
|
|
simulationManager.Clear();
|
2024-05-25 07:53:34 -03:00
|
|
|
|
if (SelectedImage != null)
|
2024-06-09 05:39:31 -03:00
|
|
|
|
{
|
|
|
|
|
var settings = new JsonSerializerSettings
|
2024-06-05 17:27:53 -03:00
|
|
|
|
{
|
|
|
|
|
TypeNameHandling = TypeNameHandling.Auto,
|
|
|
|
|
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
2024-06-09 05:39:31 -03:00
|
|
|
|
// PreserveReferencesHandling = PreserveReferencesHandling.Objects,
|
2024-06-05 17:27:53 -03:00
|
|
|
|
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-25 07:53:34 -03:00
|
|
|
|
string jsonPath = datosDeTrabajo.ObtenerPathImagenConExtension(SelectedImage, ".json");
|
2024-05-04 06:00:52 -03:00
|
|
|
|
if (File.Exists(jsonPath))
|
|
|
|
|
{
|
|
|
|
|
string jsonString = File.ReadAllText(jsonPath);
|
2024-06-09 05:39:31 -03:00
|
|
|
|
|
2024-05-08 03:00:31 -03:00
|
|
|
|
|
|
|
|
|
var simulationData = JsonConvert.DeserializeObject<SimulationData>(jsonString, settings);
|
|
|
|
|
if (simulationData != null)
|
2024-05-04 06:00:52 -03:00
|
|
|
|
{
|
2024-05-10 17:17:57 -03:00
|
|
|
|
if (simulationData.ObjetosSimulables is not null)
|
|
|
|
|
ObjetosSimulables = simulationData.ObjetosSimulables;
|
|
|
|
|
|
|
|
|
|
if (simulationData.PLC_ConnectionData is not null)
|
|
|
|
|
PLCViewModel = simulationData.PLC_ConnectionData;
|
|
|
|
|
else
|
|
|
|
|
PLCViewModel = new PLCViewModel();
|
2024-05-04 15:35:06 -03:00
|
|
|
|
|
2024-05-08 03:00:31 -03:00
|
|
|
|
PixelToMeter.Instance.calc = simulationData.UnitConverter;
|
|
|
|
|
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-05 17:27:53 -03:00
|
|
|
|
|
2024-06-09 05:39:31 -03:00
|
|
|
|
jsonPath = DatosDeTrabajo.ObtenerPathAllPages(".json");
|
2024-06-05 17:27:53 -03:00
|
|
|
|
if (File.Exists(jsonPath))
|
|
|
|
|
{
|
|
|
|
|
string jsonString = File.ReadAllText(jsonPath);
|
|
|
|
|
|
|
|
|
|
ObservableCollection<osBase> _objetosSimulablesAllPages = new ObservableCollection<osBase>();
|
|
|
|
|
|
|
|
|
|
_objetosSimulablesAllPages = JsonConvert.DeserializeObject<ObservableCollection<osBase>>(jsonString, settings);
|
|
|
|
|
if (_objetosSimulablesAllPages != null)
|
2024-06-09 05:39:31 -03:00
|
|
|
|
foreach (var obj in _objetosSimulablesAllPages)
|
2024-06-05 17:27:53 -03:00
|
|
|
|
ObjetosSimulables.Add(obj);
|
|
|
|
|
}
|
|
|
|
|
// Recorrer la colección de objetos simulables
|
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
2024-06-28 14:47:08 -03:00
|
|
|
|
if (objetoSimulable != null)
|
|
|
|
|
{
|
|
|
|
|
objetoSimulable.CheckData();
|
|
|
|
|
CrearUserControlDesdeObjetoSimulable(objetoSimulable);
|
|
|
|
|
}
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch { /* Consider logging the error or handling it appropriately */ }
|
|
|
|
|
}
|
2024-05-02 11:06:45 -03:00
|
|
|
|
|
2024-05-22 06:19:31 -03:00
|
|
|
|
// Se cargan los datos de cada UserControl en el StackPanel
|
2024-06-02 04:13:01 -03:00
|
|
|
|
public void CargarPropiedadesosDatos(osBase selectedObject, PropertyGrid PanelEdicion, ResourceDictionary Resources)
|
2024-05-22 06:19:31 -03:00
|
|
|
|
{
|
2024-06-02 04:13:01 -03:00
|
|
|
|
UserControlFactory.CargarPropiedadesosDatos(selectedObject, PanelEdicion);
|
2024-05-22 06:19:31 -03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-14 12:10:32 -03:00
|
|
|
|
private RelayCommand saveCommand;
|
|
|
|
|
public ICommand SaveCommand => saveCommand ??= new RelayCommand(Save);
|
2024-05-04 06:00:52 -03:00
|
|
|
|
|
2024-05-14 12:10:32 -03:00
|
|
|
|
private void Save(object commandParameter)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private RelayCommand exitCommand;
|
|
|
|
|
public ICommand ExitCommand => exitCommand ??= new RelayCommand(Exit);
|
|
|
|
|
|
|
|
|
|
private void Exit()
|
|
|
|
|
{
|
2025-02-13 12:52:33 -03:00
|
|
|
|
if (HasUnsavedChanges)
|
|
|
|
|
{
|
|
|
|
|
var result = MessageBox.Show("There are unsaved changes. Do you want to save them?",
|
|
|
|
|
"Save Changes",
|
|
|
|
|
MessageBoxButton.YesNoCancel);
|
|
|
|
|
|
|
|
|
|
if (result == MessageBoxResult.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
else if (result == MessageBoxResult.Yes)
|
|
|
|
|
SaveStateObjetosSimulables();
|
|
|
|
|
}
|
2024-05-14 12:10:32 -03:00
|
|
|
|
Application.Current.Shutdown();
|
|
|
|
|
}
|
2025-02-14 10:04:29 -03:00
|
|
|
|
|
2025-02-15 18:38:12 -03:00
|
|
|
|
private async void MultiPageMatrixCommand()
|
|
|
|
|
{
|
|
|
|
|
if (HasUnsavedChanges)
|
|
|
|
|
{
|
|
|
|
|
var result = MessageBox.Show("There are unsaved changes. Do you want to save them?",
|
|
|
|
|
"Save Changes",
|
|
|
|
|
MessageBoxButton.YesNoCancel);
|
|
|
|
|
|
|
|
|
|
if (result == MessageBoxResult.Cancel)
|
|
|
|
|
return;
|
|
|
|
|
else if (result == MessageBoxResult.Yes)
|
|
|
|
|
SaveStateObjetosSimulables();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ImagenesSeleccionadas = new ObservableCollection<string>
|
|
|
|
|
{
|
|
|
|
|
SelectedImage
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
StopSimulation();
|
|
|
|
|
|
|
|
|
|
var selectPagesWindow = new SelectPages();
|
|
|
|
|
var selectPagesViewModel = new SelectPagesViewModel();
|
|
|
|
|
selectPagesViewModel.Initialize(this, selectPagesWindow, ref ImagenesSeleccionadas);
|
|
|
|
|
selectPagesWindow.DataContext = selectPagesViewModel;
|
|
|
|
|
selectPagesWindow.ShowDialog();
|
|
|
|
|
|
|
|
|
|
inhibitSaveChangesControl = true;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (selectPagesWindow.DataContext is SelectPagesViewModel dialog && dialog.CloseOK)
|
|
|
|
|
{
|
|
|
|
|
var matrixPreviewWindow = new MatrixPreviewWindow();
|
|
|
|
|
var matrixPreviewViewModel = new MatrixPreviewViewModel();
|
|
|
|
|
matrixPreviewViewModel.Initialize(this, matrixPreviewWindow, ImagenesSeleccionadas);
|
|
|
|
|
matrixPreviewWindow.DataContext = matrixPreviewViewModel;
|
|
|
|
|
matrixPreviewWindow.ShowDialog();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
inhibitSaveChangesControl = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
2024-05-08 03:00:31 -03:00
|
|
|
|
public class SimulationData
|
|
|
|
|
{
|
2024-05-25 07:53:34 -03:00
|
|
|
|
public ObservableCollection<osBase>? ObjetosSimulables { get; set; }
|
|
|
|
|
public UnitConverter? UnitConverter { get; set; }
|
2024-05-27 05:34:20 -03:00
|
|
|
|
public PLCViewModel? PLC_ConnectionData { get; set; }
|
2024-05-08 03:00:31 -03:00
|
|
|
|
}
|
2024-05-04 06:00:52 -03:00
|
|
|
|
|
|
|
|
|
public class TipoSimulable
|
|
|
|
|
{
|
2024-05-25 07:53:34 -03:00
|
|
|
|
public string? Nombre { get; set; }
|
|
|
|
|
public Type? Tipo { get; set; }
|
2024-05-04 06:00:52 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class TickSimulacionEventArgs : EventArgs
|
|
|
|
|
{
|
|
|
|
|
// Aquí puedes agregar propiedades o campos para pasar información adicional
|
|
|
|
|
// en el evento TickSimulacion
|
2024-05-02 11:06:45 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|