584 lines
21 KiB
C#
584 lines
21 KiB
C#
using CtrEditor;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
using Ookii.Dialogs.Wpf;
|
|
using System.Collections.ObjectModel;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
using System.Windows.Threading;
|
|
using CtrEditor.ObjetosSim;
|
|
using CtrEditor.Siemens;
|
|
using System.IO;
|
|
// using System.Windows.Forms;
|
|
using System.Text.Json.Serialization;
|
|
using System.Text.Json;
|
|
using Newtonsoft.Json;
|
|
using System.Windows.Data;
|
|
using System.Windows;
|
|
using static System.Resources.ResXFileRef;
|
|
using CtrEditor.Convertidores;
|
|
using CtrEditor.Simulacion;
|
|
using System.Diagnostics;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace CtrEditor
|
|
{
|
|
|
|
public class MainViewModel : INotifyPropertyChanged
|
|
{
|
|
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>();
|
|
public Stopwatch stopwatch_PLCRefresh;
|
|
public Stopwatch stopwatch_SimRefresh;
|
|
private float TiempoDesdeStartSimulacion;
|
|
private bool Debug_SimulacionCreado = false;
|
|
|
|
public SimulationManagerFP simulationManager = new SimulationManagerFP();
|
|
|
|
private readonly DispatcherTimer _timerSimulacion;
|
|
|
|
public ICommand StartSimulationCommand { get; }
|
|
public ICommand StopSimulationCommand { get; }
|
|
public ICommand ItemDoubleClickCommand { get; private set; }
|
|
|
|
public ICommand TBStartSimulationCommand { get; }
|
|
public ICommand TBStopSimulationCommand { get; }
|
|
public ICommand TBSaveCommand { get; }
|
|
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;
|
|
|
|
// Propiedades
|
|
|
|
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;
|
|
private MainWindow mainWindow;
|
|
|
|
public MainWindow MainWindow { get => mainWindow; set => mainWindow = value; }
|
|
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Constructor
|
|
//
|
|
|
|
public MainViewModel()
|
|
{
|
|
OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory);
|
|
datosDeTrabajo = new DatosDeTrabajo();
|
|
|
|
// Inicializa el PLCViewModel
|
|
plcViewModelData = new PLCViewModel();
|
|
plcViewModelData.RefreshEvent += OnRefreshEvent;
|
|
|
|
InitializeTipoSimulableList();
|
|
|
|
ItemDoubleClickCommand = new ParameterizedRelayCommand(ExecuteDoubleClick);
|
|
|
|
_timerSimulacion = new DispatcherTimer();
|
|
_timerSimulacion.Interval = TimeSpan.FromMilliseconds(16); // ajusta el intervalo según sea necesario
|
|
_timerSimulacion.Tick += OnTickSimulacion;
|
|
|
|
StartSimulationCommand = new RelayCommand(StartSimulation);
|
|
StopSimulationCommand = new RelayCommand(StopSimulation);
|
|
|
|
TBStartSimulationCommand = new RelayCommand(StartSimulation, () => !IsSimulationRunning);
|
|
TBStopSimulationCommand = new RelayCommand(StopSimulation, () => IsSimulationRunning);
|
|
TBSaveCommand = new RelayCommand(Save);
|
|
TBConnectPLCCommand = new RelayCommand(ConnectPLC, () => !IsConnected);
|
|
TBDisconnectPLCCommand = new RelayCommand(DisconnectPLC, () => IsConnected);
|
|
|
|
stopwatch_PLCRefresh = new Stopwatch();
|
|
stopwatch_SimRefresh = new Stopwatch();
|
|
}
|
|
|
|
public void LoadInitialData()
|
|
{
|
|
// Suponiendo que "SelectedImage" es una propiedad que al establecerse dispara "ImageSelected"
|
|
directorioTrabajo = EstadoPersistente.Instance.directorio;
|
|
}
|
|
|
|
// Crear un nuevo Objeto
|
|
private void ExecuteDoubleClick(object parameter)
|
|
{
|
|
if (parameter is TipoSimulable tipoSimulable)
|
|
{
|
|
CrearObjetoSimulableEnCentroCanvas(tipoSimulable.Tipo);
|
|
}
|
|
}
|
|
|
|
public void CrearObjetoSimulableEnCentroCanvas(Type tipoSimulable)
|
|
{
|
|
var CentroCanvas = MainWindow.ObtenerCentroCanvasMeters();
|
|
CrearObjetoSimulable(tipoSimulable,CentroCanvas.X,CentroCanvas.Y);
|
|
}
|
|
|
|
public osBase CrearObjetoSimulable(Type tipoSimulable,float Left,float Top)
|
|
{
|
|
// Crear una nueva instancia del osBase correspondiente
|
|
osBase? NuevoOsBase = UserControlFactory.GetInstanceForType(tipoSimulable);
|
|
|
|
NuevoOsBase.Left = Left;
|
|
NuevoOsBase.Top = Top;
|
|
|
|
if (NuevoOsBase != null)
|
|
{
|
|
if (CrearUserControlDesdeObjetoSimulable(NuevoOsBase))
|
|
// Añadir el nuevo osBase a la colección de objetos simulables
|
|
ObjetosSimulables.Add(NuevoOsBase);
|
|
}
|
|
return NuevoOsBase;
|
|
}
|
|
|
|
// Crear UserControl desde osBase : Nuevo o desde Deserealizacion
|
|
private bool CrearUserControlDesdeObjetoSimulable(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;
|
|
|
|
MainWindow.AgregarRegistrarUserControlCanvas(userControl);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void RemoverObjetoSimulable(osBase osObjeto)
|
|
{
|
|
if (osObjeto != null && ObjetosSimulables.Contains(osObjeto))
|
|
{
|
|
ObjetosSimulables.Remove(osObjeto);
|
|
if (osObjeto.VisualRepresentation != null)
|
|
MainWindow.EliminarUserControlDelCanvas(osObjeto.VisualRepresentation);
|
|
}
|
|
}
|
|
|
|
private void InitializeTipoSimulableList()
|
|
{
|
|
var baseType = typeof(osBase);
|
|
var types = AppDomain.CurrentDomain.GetAssemblies()
|
|
.SelectMany(assembly => assembly.GetTypes())
|
|
.Where(type => type.IsSubclassOf(baseType) && !type.IsAbstract);
|
|
|
|
foreach (var type in types)
|
|
{
|
|
ListaOsBase.Add(new TipoSimulable { Nombre = type.Name, Tipo = type });
|
|
}
|
|
}
|
|
|
|
private void StartSimulation()
|
|
{
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
|
objetoSimulable.UpdateGeometryStart();
|
|
|
|
simulationManager.Debug_DrawInitialBodies();
|
|
TiempoDesdeStartSimulacion = 0;
|
|
Debug_SimulacionCreado = true;
|
|
|
|
_timerSimulacion.Start();
|
|
simulationManager.stopwatch.Start();
|
|
stopwatch_SimRefresh.Start();
|
|
IsSimulationRunning = true;
|
|
}
|
|
|
|
private void StopSimulation()
|
|
{
|
|
if (Debug_SimulacionCreado)
|
|
{
|
|
simulationManager.Debug_ClearSimulationShapes();
|
|
Debug_SimulacionCreado = false;
|
|
}
|
|
_timerSimulacion.Stop();
|
|
simulationManager.stopwatch.Stop();
|
|
stopwatch_SimRefresh.Stop();
|
|
IsSimulationRunning = false;
|
|
}
|
|
|
|
private void OnTickSimulacion(object sender, EventArgs e)
|
|
{
|
|
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
|
stopwatch_SimRefresh.Stop();
|
|
float elapsedMilliseconds = (float)stopwatch_SimRefresh.Elapsed.TotalMilliseconds;
|
|
|
|
// Eliminar el diseño de Debug luego de 2 segundos
|
|
if (TiempoDesdeStartSimulacion > 2000)
|
|
simulationManager.Debug_ClearSimulationShapes();
|
|
else
|
|
TiempoDesdeStartSimulacion += elapsedMilliseconds;
|
|
|
|
// Reiniciar el cronómetro para la próxima medición
|
|
stopwatch_SimRefresh.Restart();
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
|
objetoSimulable.UpdateGeometryStep();
|
|
|
|
simulationManager.Step();
|
|
|
|
var objetosSimulablesCopy = new List<osBase>(ObjetosSimulables);
|
|
|
|
foreach (var objetoSimulable in objetosSimulablesCopy)
|
|
{
|
|
if (!objetoSimulable.RemoverDesdeSimulacion)
|
|
objetoSimulable.UpdateControl((int)elapsedMilliseconds);
|
|
else
|
|
RemoverObjetoSimulable(objetoSimulable);
|
|
}
|
|
|
|
}
|
|
|
|
private void ConnectPLC()
|
|
{
|
|
plcViewModelData.Connect();
|
|
}
|
|
|
|
private void DisconnectPLC()
|
|
{
|
|
plcViewModelData.Disconnect();
|
|
IsConnected = false;
|
|
}
|
|
|
|
private void OnRefreshEvent(object sender, EventArgs e)
|
|
{
|
|
if (plcViewModelData.IsConnected)
|
|
{
|
|
if (!isConnected)
|
|
IsConnected = true;
|
|
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
|
stopwatch_PLCRefresh.Stop();
|
|
float elapsedMilliseconds = (float)stopwatch_PLCRefresh.Elapsed.TotalMilliseconds;
|
|
|
|
// Reiniciar el cronómetro para la próxima medición
|
|
stopwatch_PLCRefresh.Restart();
|
|
|
|
foreach (var objetoSimulable in ObjetosSimulables)
|
|
objetoSimulable.UpdatePLC(plcViewModelData.PLCInterface, (int) elapsedMilliseconds);
|
|
} else
|
|
stopwatch_PLCRefresh.Stop();
|
|
|
|
|
|
}
|
|
|
|
private void OpenWorkDirectory()
|
|
{
|
|
var dialog = new VistaFolderBrowserDialog();
|
|
if (dialog.ShowDialog() == true) // Mostrar el diálogo y comprobar si el resultado es positivo
|
|
{
|
|
directorioTrabajo = dialog.SelectedPath; // Actualizar la propiedad que también actualiza el estado persistente
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lista de osBase
|
|
//
|
|
|
|
public void Save()
|
|
{
|
|
SaveStateObjetosSimulables();
|
|
}
|
|
|
|
public void SaveStateObjetosSimulables()
|
|
{
|
|
if (_selectedImage != null)
|
|
{
|
|
StopSimulation();
|
|
PLCViewModel.Disconnect();
|
|
|
|
// Crear copias temporales de las propiedades que serán anuladas
|
|
var tempVisualRepresentations = new Dictionary<osBase, UserControl>();
|
|
var tempSimulationManagers = new Dictionary<osBase, SimulationManagerFP>();
|
|
var tempMainViewModels = new Dictionary<osBase, MainViewModel>();
|
|
|
|
foreach (var obj in ObjetosSimulables)
|
|
{
|
|
// Guardar referencias temporales
|
|
tempVisualRepresentations[obj] = obj.VisualRepresentation;
|
|
tempSimulationManagers[obj] = obj.simulationManager;
|
|
tempMainViewModels[obj] = obj._mainViewModel;
|
|
|
|
// Anular propiedades para la serialización
|
|
obj.VisualRepresentation = null;
|
|
obj.simulationManager = null;
|
|
obj._mainViewModel = null;
|
|
}
|
|
|
|
var settings = new JsonSerializerSettings
|
|
{
|
|
Formatting = Formatting.Indented,
|
|
NullValueHandling = NullValueHandling.Ignore,
|
|
TypeNameHandling = TypeNameHandling.Auto
|
|
};
|
|
|
|
// Crear un objeto que incluya tanto los ObjetosSimulables como el UnitConverter y PLC_ConnectionData
|
|
var dataToSerialize = new SimulationData
|
|
{
|
|
ObjetosSimulables = ObjetosSimulables,
|
|
UnitConverter = PixelToMeter.Instance.calc,
|
|
PLC_ConnectionData = PLCViewModel
|
|
};
|
|
|
|
// Serializar
|
|
var serializedData = JsonConvert.SerializeObject(dataToSerialize, settings);
|
|
File.WriteAllText(datosDeTrabajo.ObtenerPathImagenConExtension(_selectedImage, ".json"), serializedData);
|
|
|
|
// Restaurar las propiedades originales de los objetos
|
|
foreach (var obj in ObjetosSimulables)
|
|
{
|
|
obj.VisualRepresentation = tempVisualRepresentations[obj];
|
|
obj.simulationManager = tempSimulationManagers[obj];
|
|
obj._mainViewModel = tempMainViewModels[obj];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void LoadStateObjetosSimulables()
|
|
{
|
|
try
|
|
{
|
|
StopSimulation();
|
|
PLCViewModel.Disconnect();
|
|
ObjetosSimulables.Clear();
|
|
simulationManager.Clear();
|
|
if (_selectedImage != null)
|
|
{
|
|
string jsonPath = datosDeTrabajo.ObtenerPathImagenConExtension(_selectedImage, ".json");
|
|
if (File.Exists(jsonPath))
|
|
{
|
|
string jsonString = File.ReadAllText(jsonPath);
|
|
var settings = new JsonSerializerSettings
|
|
{
|
|
TypeNameHandling = TypeNameHandling.Auto,
|
|
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
|
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
|
|
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
|
|
};
|
|
|
|
var simulationData = JsonConvert.DeserializeObject<SimulationData>(jsonString, settings);
|
|
if (simulationData != null)
|
|
{
|
|
if (simulationData.ObjetosSimulables is not null)
|
|
ObjetosSimulables = simulationData.ObjetosSimulables;
|
|
|
|
if (simulationData.PLC_ConnectionData is not null)
|
|
PLCViewModel = simulationData.PLC_ConnectionData;
|
|
else
|
|
PLCViewModel = new PLCViewModel();
|
|
|
|
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)
|
|
CrearUserControlDesdeObjetoSimulable(objetoSimulable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch { /* Consider logging the error or handling it appropriately */ }
|
|
}
|
|
|
|
|
|
// Implementación de INotifyPropertyChanged...
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
{
|
|
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
|
|
{
|
|
public ObservableCollection<osBase> ObjetosSimulables { get; set; }
|
|
public UnitConverter UnitConverter { get; set; }
|
|
public PLCViewModel PLC_ConnectionData { get; set; }
|
|
}
|
|
|
|
public class TipoSimulable
|
|
{
|
|
public string Nombre { get; set; }
|
|
public Type Tipo { get; set; }
|
|
}
|
|
|
|
public class TickSimulacionEventArgs : EventArgs
|
|
{
|
|
// Aquí puedes agregar propiedades o campos para pasar información adicional
|
|
// en el evento TickSimulacion
|
|
}
|
|
|
|
}
|