451 lines
14 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|