using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Media; using CommunityToolkit.Mvvm.ComponentModel; using CtrEditor.FuncionesBase; using CtrEditor.Simulacion.Fluids; using CtrEditor.Simulacion.Fluids.Components; using nkast.Aether.Physics2D.Common; using Color = System.Windows.Media.Color; using Siemens.Simatic.Simulation.Runtime; using LibS7Adv; namespace CtrEditor.ObjetosSim { /// /// ViewModel para el sistema de fluidos /// public partial class osSistemaFluidos : osBase, IosBase { // Referencia a la simulación de fluidos public SimulacionFluidos _simFluidos; // Tamaño del área de simulación [ObservableProperty] [property: Category("Configuración")] [property: Description("Ancho del área de simulación en metros")] [property: Name("Ancho Simulación")] private float anchoSimulacion = 10.0f; [ObservableProperty] [property: Category("Configuración")] [property: Description("Alto del área de simulación en metros")] [property: Name("Alto Simulación")] private float altoSimulacion = 10.0f; // Propiedades del fluido [ObservableProperty] [property: Category("Apariencia")] [property: Description("Tamaño visual de las partículas")] [property: Name("Tamaño Partícula")] private float tamañoParticula = 0.01f; [ObservableProperty] [property: Category("Apariencia")] [property: Description("Color del fluido")] [property: Name("Color Fluido")] private Color colorFluido = Colors.CornflowerBlue; [ObservableProperty] [property: Category("Apariencia")] [property: Description("Opacidad de las partículas")] [property: Name("Opacidad Partículas")] private double opacidadParticulas = 0.7; // Propiedades de gravedad [ObservableProperty] [property: Category("Simulación")] [property: Description("Gravedad en X (m/s²)")] [property: Name("Gravedad X")] private float gravedadX = 0.0f; [ObservableProperty] [property: Category("Simulación")] [property: Description("Gravedad en Y (m/s²)")] [property: Name("Gravedad Y")] private float gravedadY = 9.8f; partial void OnGravedadXChanged(float value) { ActualizarGravedad(); } partial void OnGravedadYChanged(float value) { ActualizarGravedad(); } // Estadísticas de la simulación [ObservableProperty] [property: Category("Información")] [property: Description("Número de partículas")] [property: Name("Número Partículas")] private int numeroParticulas; [ObservableProperty] [property: Category("Información")] [property: Description("Rendimiento en FPS")] [property: Name("FPS")] private double fps; // Referencia a componentes (solo para la función Add) private List _contenedores = new List(); // Nombre de la clase para identificación public static string NombreClase() { return "Sistema de Fluidos"; } private string nombre = NombreClase(); [property: Category("Identificación")] [property: Description("Nombre identificativo del objeto")] [property: Name("Nombre")] public override string Nombre { get => nombre; set => SetProperty(ref nombre, value); } // Métodos para interactuar con la simulación /// /// Agrega partículas en un punto específico /// public void AgregarParticula(Vector2 posicion) { _simFluidos?.AgregarParticula(posicion); } /// /// Agrega múltiples partículas en un área /// public void AgregarParticulasEnArea(Vector2 centro, float ancho, float alto, int cantidad) { _simFluidos?.AgregarParticulasEnArea(centro, ancho, alto, cantidad); } /// /// Crea un nuevo tanque y lo agrega a la simulación /// public Tanque CrearTanque(Vector2 posicion, float ancho, float alto) { if (_simFluidos == null) return null; Tanque tanque = new Tanque(posicion, ancho, alto, (int)(AnchoSimulacion * 100)); _simFluidos.AgregarContenedor(tanque); _contenedores.Add(tanque); return tanque; } /// /// Crea una nueva tubería /// public Tuberia CrearTuberia(float diametro) { if (_simFluidos == null) return null; Tuberia tuberia = new Tuberia(diametro, (int)(AnchoSimulacion * 100)); _simFluidos.AgregarContenedor(tuberia); _contenedores.Add(tuberia); return tuberia; } /// /// Crea una nueva válvula /// public Valvula CrearValvula(Vector2 posicion, float diametro, float apertura = 1.0f) { if (_simFluidos == null) return null; Valvula valvula = new Valvula(posicion, diametro, apertura, (int)(AnchoSimulacion * 100)); _simFluidos.AgregarContenedor(valvula); _contenedores.Add(valvula); return valvula; } /// /// Elimina un componente de la simulación /// public void EliminarComponente(IContenedorFluido componente) { if (_simFluidos == null || componente == null) return; _simFluidos.RemoverContenedor(componente); _contenedores.Remove(componente); } /// /// Limpia todas las partículas de la simulación /// public void LimpiarParticulas() { _simFluidos?.LimpiarParticulas(); } /// /// Actualiza el vector de gravedad según las propiedades /// private void ActualizarGravedad() { if (_simFluidos != null) { _simFluidos.AjustarGravedad(new Vector2(GravedadX, GravedadY)); } } /// /// Constructor de la clase /// public osSistemaFluidos() { // Inicializar propiedades básicas Ancho = 1.0f; Alto = 1.0f; } // Métodos sobrescritos de osBase public override void UpdateGeometryStart() { // Crear la simulación de fluidos si es necesario if (_simFluidos == null) { _simFluidos = new SimulacionFluidos( AnchoSimulacion, AltoSimulacion, 10000, // Máximo de partículas new Vector2(GravedadX, GravedadY) ); } } public override void UpdateGeometryStep() { // No es necesario actualizar en cada paso } public override void UpdateControl(int elapsedMilliseconds) { // Actualizar estadísticas if (_simFluidos != null) { NumeroParticulas = _simFluidos.ParticlesCount; } } /// /// Llamado cuando se inicia la simulación de fluidos /// public void OnFluidSimulationStart() { // Crear la simulación de fluidos si es necesario UpdateGeometryStart(); } /// /// Llamado cuando se detiene la simulación de fluidos /// public void OnFluidSimulationStop() { // Detener recursos si es necesario SimulationStop(); } /// /// Actualiza la simulación de fluidos /// public void UpdateFluidSimulation(float deltaTime) { // Actualizar la simulación con el delta time if (_simFluidos != null) { _simFluidos.Actualizar(deltaTime); // Actualizar el control visual UpdateControl((int)(deltaTime * 1000)); } } public override void SimulationStop() { // Limpiar recursos si es necesario cuando se detiene la simulación } public override void ucLoaded() { base.ucLoaded(); // Inicializar la simulación de fluidos si es necesario UpdateGeometryStart(); } public override void ucUnLoaded() { // Limpiar recursos _simFluidos = null; _contenedores.Clear(); } // Implementación para las conexiones con PLC [ObservableProperty] [property: Description("Tag de lectura/escritura del nivel del Tanque 1")] [property: Category("PLC:")] private string tagNivelTanque1; [ObservableProperty] [property: Description("Tag de lectura/escritura de la apertura de la Válvula 1")] [property: Category("PLC:")] private string tagAperturaValvula1; // Referencia a componentes típicos para integración con PLC private Tanque _tanque1; private Valvula _valvula1; public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) { // Ejemplo de integración con PLC para la válvula if (_valvula1 != null && !string.IsNullOrEmpty(TagAperturaValvula1)) { float aperturaValvula = LeerWordTagScaled(TagAperturaValvula1) / 100.0f; _valvula1.Apertura = Math.Clamp(aperturaValvula, 0, 1); } // Ejemplo de escritura del nivel del tanque al PLC if (_tanque1 != null && !string.IsNullOrEmpty(TagNivelTanque1)) { float nivelTanque = 0; // Implementar cálculo real del nivel EscribirWordTagScaled(TagNivelTanque1, nivelTanque * 100, 0, 100, 0, 27648); } } } }