CtrEditor/ObjetosSim/HydraulicComponents/osHydPump.cs

451 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using CtrEditor.HydraulicSimulator;
using CtrEditor.HydraulicSimulator.TSNet.Components;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
using Newtonsoft.Json;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CommunityToolkit.Mvvm.ComponentModel;
using HydraulicSimulator.Models;
namespace CtrEditor.ObjetosSim
{
/// <summary>
/// Dirección de funcionamiento de la bomba
/// </summary>
public enum PumpDirection
{
Forward = 1,
Reverse = -1
}
/// <summary>
/// Bomba hidráulica simplificada para integración con TSNet
/// </summary>
public partial class osHydPump : osBase, IHydraulicComponent, IHydraulicFlowReceiver, IHydraulicPressureReceiver, IosBase
{
public static string NombreCategoria() => "Componentes Hidráulicos";
public static string NombreClase() => "Bomba Hidráulica";
// Private fields para TSNet
private double _pumpHead = 50.0; // m - cabeza de la bomba
private double _maxFlow = 0.01; // m³/s - flujo máximo
private double _efficiency = 0.85; // eficiencia de la bomba
private bool _isRunning = true; // bomba funcionando
// Estado actual (desde TSNet)
private double _currentFlow = 0.0; // m³/s - flujo actual
private double _currentHead = 0.0; // m - cabeza actual
private double _currentPressure = 0.0; // Pa - presión actual
// TSNet Integration
[JsonIgnore]
public TSNetPumpAdapter? TSNetAdapter { get; private set; }
// Propiedades visuales
[ObservableProperty]
[property: JsonIgnore]
[property: Category("🎨 Apariencia")]
[property: Description("Imagen visual")]
[property: Name("Imagen")]
public ImageSource imageSource_oculta;
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Tamaño visual de la bomba")]
[property: Name("Tamaño")]
public float tamano;
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Color visual de la bomba")]
[property: Name("Color")]
private Brush colorButton_oculto = Brushes.Blue;
// Constructor
public osHydPump()
{
try
{
Nombre = "Bomba Hidráulica";
Tamano = 1.0f;
Ancho = 0.25f;
Alto = 0.25f;
Angulo = 0f;
Lock_movement = false;
UpdatePumpImage();
Debug.WriteLine($"osHydPump Constructor completado correctamente");
}
catch (Exception ex)
{
Debug.WriteLine($"Error en constructor osHydPump: {ex.Message}");
Nombre = "Bomba Hidráulica";
Tamano = 1.0f;
}
}
// Propiedades de configuración de la bomba
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Cabeza de bomba")]
[Description("Cabeza de la bomba a caudal cero (m)")]
public double PumpHead
{
get => _pumpHead;
set
{
if (SetProperty(ref _pumpHead, Math.Max(0, value)))
{
InvalidateHydraulicNetwork();
}
}
}
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Flujo máximo")]
[Description("Flujo máximo de la bomba (m³/s)")]
public double MaxFlow
{
get => _maxFlow;
set
{
// Si el valor es mayor a 1, asumir que está en m³/h y convertir a m³/s
double valueInM3s = value > 1.0 ? value / 3600.0 : value;
if (SetProperty(ref _maxFlow, Math.Max(0.0001, valueInM3s)))
{
InvalidateHydraulicNetwork();
Debug.WriteLine($"Bomba {Nombre}: MaxFlow establecido a {_maxFlow:F6} m³/s ({_maxFlow * 3600:F2} m³/h)");
}
}
}
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Eficiencia")]
[Description("Eficiencia de la bomba (0.0 a 1.0)")]
public double Efficiency
{
get => _efficiency;
set
{
if (SetProperty(ref _efficiency, Math.Max(0.1, Math.Min(1.0, value))))
{
InvalidateHydraulicNetwork();
}
}
}
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Funcionando")]
[Description("Indica si la bomba está encendida")]
public bool IsRunning
{
get => _isRunning;
set
{
if (SetProperty(ref _isRunning, value))
{
UpdatePumpImage();
InvalidateHydraulicNetwork();
}
}
}
// Estado actual (desde TSNet)
[Category("📊 Estado Actual")]
[DisplayName("Flujo actual")]
[Description("Flujo actual de la bomba (m³/s)")]
[ReadOnly(true)]
public double CurrentFlow
{
get => _currentFlow;
private set => SetProperty(ref _currentFlow, value);
}
[Category("📊 Estado Actual")]
[DisplayName("Cabeza actual")]
[Description("Cabeza actual de la bomba (m)")]
[ReadOnly(true)]
public double CurrentHead
{
get => _currentHead;
private set => SetProperty(ref _currentHead, value);
}
[Category("📊 Estado Actual")]
[DisplayName("Presión actual")]
[Description("Presión actual en la bomba (Pa)")]
[ReadOnly(true)]
public double CurrentPressure
{
get => _currentPressure;
private set => SetProperty(ref _currentPressure, value);
}
[Category("📊 Estado Actual")]
[DisplayName("Presión (bar)")]
[Description("Presión actual en la bomba (bar)")]
[ReadOnly(true)]
public double CurrentPressureBar => CurrentPressure / 100000.0;
[Category("📊 Estado Actual")]
[DisplayName("Flujo (L/min)")]
[Description("Flujo actual en L/min")]
[ReadOnly(true)]
public double CurrentFlowLMin => CurrentFlow * 60000.0; // m³/s a L/min
[Category("📊 Estado Actual")]
[DisplayName("Tiene Flujo")]
[Description("Indica si hay flujo en la bomba")]
[ReadOnly(true)]
public bool HasFlow => Math.Abs(CurrentFlow) > 1e-6;
/// <summary>
/// Relación de velocidad de la bomba
/// </summary>
[Category("⚙️ Configuración")]
[DisplayName("Relación de velocidad")]
[Description("Relación de velocidad de la bomba (0.0 - 1.0)")]
public double SpeedRatio
{
get => _speedRatio;
set => SetProperty(ref _speedRatio, Math.Max(0.0, Math.Min(1.0, value)));
}
private double _speedRatio = 1.0;
/// <summary>
/// Dirección de la bomba
/// </summary>
[Category("⚙️ Configuración")]
[DisplayName("Dirección bomba")]
[Description("Dirección de funcionamiento de la bomba")]
public PumpDirection PumpDirection
{
get => _pumpDirection;
set => SetProperty(ref _pumpDirection, value);
}
private PumpDirection _pumpDirection = PumpDirection.Forward;
// Métodos básicos
private string nombre = NombreClase();
[Category("🏷️ Identificación")]
[Description("Nombre identificativo del objeto")]
[Name("Nombre")]
public override string Nombre
{
get => nombre;
set => SetProperty(ref nombre, value);
}
public override void OnMove(float LeftPixels, float TopPixels)
{
// Movimiento básico
}
public override void OnResize(float Delta_Width, float Delta_Height)
{
Tamano += Delta_Width + Delta_Height;
}
public override void UpdateGeometryStart()
{
// El componente se registra automáticamente como IHydraulicComponent
}
public override void UpdateControl(int elapsedMilliseconds)
{
// Los valores provienen de TSNet
OnPropertyChanged(nameof(CurrentPressureBar));
OnPropertyChanged(nameof(CurrentFlowLMin));
OnPropertyChanged(nameof(HasFlow));
UpdatePumpImage();
}
private void UpdatePumpImage()
{
if (IsRunning && HasFlow)
ImageSource_oculta = ImageFromPath("/imagenes/pump_run.png");
else if (IsRunning)
ImageSource_oculta = ImageFromPath("/imagenes/pump_idle.png");
else
ImageSource_oculta = ImageFromPath("/imagenes/pump_stop.png");
}
private void InvalidateHydraulicNetwork()
{
// Invalidar la red hidráulica para que se recalcule
var mainViewModel = Application.Current?.MainWindow?.DataContext as MainViewModel;
mainViewModel?.InvalidateHydraulicNetwork();
}
// Implementación de interfaces hidráulicas
public void ApplyHydraulicPressure(double pressurePa)
{
CurrentPressure = pressurePa;
}
public void ApplyHydraulicFlow(double flowM3s)
{
CurrentFlow = flowM3s;
}
public void UpdateHydraulicState(double timeSeconds)
{
// TSNet maneja el estado
}
// Métodos para TSNet
public void UpdateFromTSNetResults(double flow, double head, double pressure)
{
CurrentFlow = flow;
CurrentHead = head;
CurrentPressure = pressure;
}
// Crear adapter para TSNet
public TSNetPumpAdapter CreateTSNetAdapter()
{
TSNetAdapter = new TSNetPumpAdapter(this);
return TSNetAdapter;
}
// Implementación de IHydraulicComponent
[JsonIgnore]
public bool HasHydraulicComponents => true;
public List<HydraulicNodeDefinition> GetHydraulicNodes()
{
// Las bombas no crean nodos propios, se conectan entre nodos existentes
return new List<HydraulicNodeDefinition>();
}
public void ApplyHydraulicResults(Dictionary<string, double> flows, Dictionary<string, double> pressures)
{
try
{
// Buscar resultados de esta bomba en TSNet
var pumpElementName = $"PUMP_{Nombre}";
if (flows.ContainsKey(pumpElementName))
{
var pumpFlow = flows[pumpElementName];
CurrentFlow = pumpFlow;
}
// Calcular cabeza basada en la diferencia de presión
// Esto se podría calcular desde TSNet directamente si está disponible
if (Math.Abs(CurrentFlow) > 1e-6)
{
// Estimación simplificada de la cabeza actual
CurrentHead = PumpHead * (1.0 - (CurrentFlow / MaxFlow));
CurrentHead = Math.Max(0, CurrentHead);
}
else
{
CurrentHead = IsRunning ? PumpHead : 0;
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error en Pump {Nombre} ApplyHydraulicResults: {ex.Message}");
}
}
public List<HydraulicElementDefinition> GetHydraulicElements()
{
var elements = new List<HydraulicElementDefinition>();
if (IsRunning)
{
// Crear elemento de bomba para TSNet
var pumpElement = new PumpHQ(PumpHead, MaxFlow);
elements.Add(new HydraulicElementDefinition(
$"PUMP_{Nombre}",
$"NODE_A_{Nombre}",
$"NODE_B_{Nombre}",
pumpElement,
$"Bomba hidráulica - Head: {PumpHead:F1}m, Flow: {MaxFlow * 3600:F1} m³/h"
));
}
return elements;
}
public void UpdateHydraulicProperties()
{
// Actualizar propiedades antes de la simulación
if (!IsRunning)
{
CurrentFlow = 0;
CurrentHead = 0;
}
}
// Implementación de IHydraulicFlowReceiver
public void SetFlow(double flow)
{
CurrentFlow = flow;
}
public double GetFlow()
{
return CurrentFlow;
}
// Implementación de IHydraulicPressureReceiver
public void SetPressure(double pressure)
{
CurrentPressure = pressure;
}
public double GetPressure()
{
return CurrentPressure;
}
// Implementación de IosBase
public void Start()
{
// Inicialización de la bomba para la simulación
}
public void Inicializar(int valorInicial)
{
// Inicialización con valor inicial
}
public void Disposing()
{
// Limpieza si es necesaria
}
public int zIndex_fromFrames { get; set; } = 2;
public ZIndexEnum ZIndex_Base()
{
return ZIndexEnum.Estaticos;
}
public override void CopyFrom(osBase source)
{
if (source is osHydPump sourcePump)
{
PumpHead = sourcePump.PumpHead;
MaxFlow = sourcePump.MaxFlow;
Efficiency = sourcePump.Efficiency;
IsRunning = sourcePump.IsRunning;
}
base.CopyFrom(source);
}
}
}