CtrEditor/ObjetosSim/HydraulicComponents/osPumpExample.cs

365 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Media;
using CtrEditor.HydraulicSimulator;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
using HydraulicSimulator.Models;
using Newtonsoft.Json;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CommunityToolkit.Mvvm.ComponentModel;
namespace CtrEditor.ObjetosSim.HydraulicComponents
{
/// <summary>
/// Bomba hidráulica que implementa las interfaces del simulador hidráulico
/// </summary>
public partial class osHydPump : osBase, IHydraulicPump, IosBase
{
#region Properties
private double _pumpHead = 50.0; // metros
private double _maxFlow = 0.01; // m³/s (36 m³/h)
private double _speedRatio = 1.0;
private bool _isRunning = true;
private int _pumpDirection = 1;
private double _currentFlow = 0.0;
private double _currentPressure = 0.0;
// Propiedades visuales
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Ancho de la bomba en metros")]
[property: Name("Ancho")]
private float ancho = 0.15f;
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Alto de la bomba en metros")]
[property: Name("Alto")]
private float alto = 0.10f;
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Color visual de la bomba")]
[property: Name("Color")]
private Brush colorButton_oculto = Brushes.Blue;
[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("Caudal máximo")]
[Description("Caudal máximo de la bomba (m³/s)")]
public double MaxFlow
{
get => _maxFlow;
set
{
if (SetProperty(ref _maxFlow, Math.Max(0.001, value)))
{
InvalidateHydraulicNetwork();
}
}
}
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Velocidad relativa")]
[Description("Velocidad relativa de la bomba (0.0 a 1.0)")]
public double SpeedRatio
{
get => _speedRatio;
set
{
SetProperty(ref _speedRatio, Math.Max(0.0, Math.Min(1.0, value)));
}
}
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Funcionando")]
[Description("Indica si la bomba está encendida")]
public bool IsRunning
{
get => _isRunning;
set
{
SetProperty(ref _isRunning, value);
}
}
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Dirección")]
[Description("Dirección de la bomba (+1 o -1)")]
[ItemsSource(typeof(PumpDirectionItemsSource))]
public int PumpDirection
{
get => _pumpDirection;
set
{
if (SetProperty(ref _pumpDirection, value == -1 ? -1 : 1))
{
InvalidateHydraulicNetwork();
}
}
}
[Category("📊 Estado Actual")]
[DisplayName("Caudal actual")]
[Description("Caudal actual de la bomba (m³/s)")]
[JsonIgnore]
public double CurrentFlow
{
get => _currentFlow;
private set => SetProperty(ref _currentFlow, value);
}
[Category("📊 Estado Actual")]
[DisplayName("Presión actual")]
[Description("Presión actual en la bomba (Pa)")]
[JsonIgnore]
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)")]
[JsonIgnore]
public double CurrentPressureBar => CurrentPressure / 100000.0;
[Category("📊 Estado Actual")]
[DisplayName("Caudal (L/min)")]
[Description("Caudal actual en L/min")]
[JsonIgnore]
public double CurrentFlowLMin => CurrentFlow * 60000.0; // m³/s a L/min
#endregion
#region Constructor y Métodos Base
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)
{
// Los objetos hidráulicos no necesitan actualizar geometría física
}
public override void OnResize(float Delta_Width, float Delta_Height)
{
Ancho += Delta_Width;
Alto += Delta_Height;
}
public osHydPump()
{
Nombre = "Bomba Hidráulica";
}
public override void UpdateGeometryStart()
{
// Los objetos hidráulicos se registran automáticamente
// cuando inicia la simulación a través de las interfaces
}
public override void UpdateGeometryStep()
{
// Los objetos hidráulicos actualizan sus resultados
// a través de ApplyHydraulicResults()
}
public override void UpdateControl(int elapsedMilliseconds)
{
// Actualizar el color según el estado
if (IsRunning)
ColorButton_oculto = Brushes.Green;
else
ColorButton_oculto = Brushes.Gray;
}
public override void ucLoaded()
{
// Los objetos hidráulicos no necesitan geometría física
base.ucLoaded();
}
public override void ucUnLoaded()
{
// Los objetos hidráulicos no tienen geometría que limpiar
}
#endregion
#region IHydraulicComponent Implementation
[JsonIgnore]
public bool HasHydraulicComponents => true;
public List<HydraulicNodeDefinition> GetHydraulicNodes()
{
var nodes = new List<HydraulicNodeDefinition>
{
new HydraulicNodeDefinition($"{Nombre}_In", false, null, "Entrada de la bomba"),
new HydraulicNodeDefinition($"{Nombre}_Out", false, null, "Salida de la bomba")
};
return nodes;
}
public List<HydraulicElementDefinition> GetHydraulicElements()
{
var elements = new List<HydraulicElementDefinition>();
if (HasHydraulicComponents)
{
// Crear bomba con parámetros actuales
var pump = new PumpHQ(
h0: PumpHead,
q0: MaxFlow,
speedRel: IsRunning ? SpeedRatio : 0.0, // Si no está funcionando, velocidad = 0
direction: PumpDirection
);
var pumpElement = new HydraulicElementDefinition(
$"{Nombre}_Pump",
$"{Nombre}_In",
$"{Nombre}_Out",
pump,
$"Bomba {Nombre}"
);
elements.Add(pumpElement);
}
return elements;
}
public void UpdateHydraulicProperties()
{
// Aquí se pueden hacer validaciones o ajustes antes de la simulación
if (!IsRunning)
{
SpeedRatio = 0.0;
}
if (SpeedRatio < 0.0) SpeedRatio = 0.0;
if (SpeedRatio > 1.0) SpeedRatio = 1.0;
Debug.WriteLine($"Bomba {Nombre}: Velocidad={SpeedRatio:F2}, Funcionando={IsRunning}");
}
public void ApplyHydraulicResults(Dictionary<string, double> flows, Dictionary<string, double> pressures)
{
// Buscar resultados para esta bomba
string pumpBranchName = $"{Nombre}_Pump";
string inletNodeName = $"{Nombre}_In";
string outletNodeName = $"{Nombre}_Out";
if (flows.ContainsKey(pumpBranchName))
{
CurrentFlow = flows[pumpBranchName];
}
if (pressures.ContainsKey(inletNodeName))
{
CurrentPressure = pressures[inletNodeName];
}
else if (pressures.ContainsKey(outletNodeName))
{
CurrentPressure = pressures[outletNodeName];
}
}
#endregion
#region IHydraulicFlowReceiver Implementation
public void SetFlow(double flow)
{
CurrentFlow = flow;
}
public double GetFlow()
{
return CurrentFlow;
}
#endregion
#region IHydraulicPressureReceiver Implementation
public void SetPressure(double pressure)
{
CurrentPressure = pressure;
}
public double GetPressure()
{
return CurrentPressure;
}
#endregion
#region Helper Methods
/// <summary>
/// Invalida la red hidráulica para forzar reconstrucción
/// </summary>
private void InvalidateHydraulicNetwork()
{
// Si tenemos acceso al MainViewModel, invalidar la red
if (_mainViewModel?.hydraulicSimulationManager != null)
{
_mainViewModel.hydraulicSimulationManager.InvalidateNetwork();
}
}
#endregion
#region Static Interface Implementation
public static string NombreClase() => "Bomba Hidráulica";
public static string NombreCategoria() => "Componentes Hidráulicos";
#endregion
}
/// <summary>
/// Proveedor de items para la dirección de la bomba
/// </summary>
public class PumpDirectionItemsSource : IItemsSource
{
public Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection GetValues()
{
var items = new Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection();
items.Add(1, "Adelante (+1)");
items.Add(-1, "Atrás (-1)");
return items;
}
}
}