CtrEditor/ObjetosSim/osSistemaFluidos.cs

313 lines
10 KiB
C#

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
{
/// <summary>
/// ViewModel para el sistema de fluidos
/// </summary>
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: Description("Ancho del área de simulación en metros")]
[property: Category("Simulación:")]
private float anchoSimulacion = 10.0f;
[ObservableProperty]
[property: Description("Alto del área de simulación en metros")]
[property: Category("Simulación:")]
private float altoSimulacion = 10.0f;
// Propiedades del fluido
[ObservableProperty]
[property: Description("Tamaño visual de las partículas")]
[property: Category("Visual:")]
private float tamañoParticula = 0.01f;
[ObservableProperty]
[property: Description("Color del fluido")]
[property: Category("Visual:")]
private Color colorFluido = Colors.CornflowerBlue;
[ObservableProperty]
[property: Description("Opacidad de las partículas")]
[property: Category("Visual:")]
private double opacidadParticulas = 0.7;
// Propiedades de gravedad
[ObservableProperty]
[property: Description("Gravedad en X (m/s²)")]
[property: Category("Física:")]
private float gravedadX = 0.0f;
[ObservableProperty]
[property: Description("Gravedad en Y (m/s²)")]
[property: Category("Física:")]
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: Description("Número de partículas")]
[property: Category("Estadísticas:")]
private int numeroParticulas;
[ObservableProperty]
[property: Description("Rendimiento en FPS")]
[property: Category("Estadísticas:")]
private double fps;
// Referencia a componentes (solo para la función Add)
private List<IContenedorFluido> _contenedores = new List<IContenedorFluido>();
// Nombre de la clase para identificación
public static string NombreClase()
{
return "SistemaFluidos";
}
private string nombre = NombreClase();
public override string Nombre
{
get => nombre;
set => SetProperty(ref nombre, value);
}
// Métodos para interactuar con la simulación
/// <summary>
/// Agrega partículas en un punto específico
/// </summary>
public void AgregarParticula(Vector2 posicion)
{
_simFluidos?.AgregarParticula(posicion);
}
/// <summary>
/// Agrega múltiples partículas en un área
/// </summary>
public void AgregarParticulasEnArea(Vector2 centro, float ancho, float alto, int cantidad)
{
_simFluidos?.AgregarParticulasEnArea(centro, ancho, alto, cantidad);
}
/// <summary>
/// Crea un nuevo tanque y lo agrega a la simulación
/// </summary>
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;
}
/// <summary>
/// Crea una nueva tubería
/// </summary>
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;
}
/// <summary>
/// Crea una nueva válvula
/// </summary>
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;
}
/// <summary>
/// Elimina un componente de la simulación
/// </summary>
public void EliminarComponente(IContenedorFluido componente)
{
if (_simFluidos == null || componente == null) return;
_simFluidos.RemoverContenedor(componente);
_contenedores.Remove(componente);
}
/// <summary>
/// Limpia todas las partículas de la simulación
/// </summary>
public void LimpiarParticulas()
{
_simFluidos?.LimpiarParticulas();
}
/// <summary>
/// Actualiza el vector de gravedad según las propiedades
/// </summary>
private void ActualizarGravedad()
{
if (_simFluidos != null)
{
_simFluidos.AjustarGravedad(new Vector2(GravedadX, GravedadY));
}
}
/// <summary>
/// Constructor de la clase
/// </summary>
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;
}
}
/// <summary>
/// Llamado cuando se inicia la simulación de fluidos
/// </summary>
public void OnFluidSimulationStart()
{
// Crear la simulación de fluidos si es necesario
UpdateGeometryStart();
}
/// <summary>
/// Llamado cuando se detiene la simulación de fluidos
/// </summary>
public void OnFluidSimulationStop()
{
// Detener recursos si es necesario
SimulationStop();
}
/// <summary>
/// Actualiza la simulación de fluidos
/// </summary>
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);
}
}
}
}