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
{
///
/// Tubería hidráulica simplificada para integración con TSNet
///
public partial class osHydPipe : osBase, IHydraulicComponent, IHydraulicFlowReceiver, IHydraulicPressureReceiver, IosBase
{
public static string NombreCategoria() => "Componentes Hidráulicos";
public static string NombreClase() => "Tubería Hidráulica";
// Private fields para TSNet
private double _length = 1.0; // m - longitud de la tubería
private double _diameter = 0.05; // m - diámetro interno
private double _roughness = 4.5e-5; // m - rugosidad del material
// Estado actual (desde TSNet)
private double _currentFlow = 0.0; // m³/s - flujo actual
private double _pressureDrop = 0.0; // Pa - caída de presión
private double _velocity = 0.0; // m/s - velocidad del fluido
// TSNet Integration
[JsonIgnore]
public TSNetPipeAdapter? TSNetAdapter { get; private set; }
// Propiedades visuales
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Ancho visual de la tubería en metros")]
[property: Name("Ancho")]
private float ancho = 1.0f;
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Alto visual de la tubería en metros")]
[property: Name("Alto")]
private float alto = 0.05f;
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Color visual de la tubería")]
[property: Name("Color")]
private Brush colorButton_oculto = Brushes.Gray;
[ObservableProperty]
[property: Category("🎨 Apariencia")]
[property: Description("Ángulo de rotación de la tubería en grados")]
[property: Name("Ángulo")]
private float angulo = 0f;
// Propiedades de conexión
[ObservableProperty]
[property: Category("🔗 Conexiones")]
[property: Description("Primer componente hidráulico conectado")]
[property: Name("Componente A")]
[property: ItemsSource(typeof(osBaseItemsSource))]
private string id_ComponenteA = "";
[ObservableProperty]
[property: Category("🔗 Conexiones")]
[property: Description("Segundo componente hidráulico conectado")]
[property: Name("Componente B")]
[property: ItemsSource(typeof(osBaseItemsSource))]
private string id_ComponenteB = "";
// Constructor
public osHydPipe()
{
try
{
Nombre = "Tubería Hidráulica";
Ancho = 1.0f;
Alto = 0.05f;
Angulo = 0f;
Lock_movement = false;
Debug.WriteLine($"osHydPipe Constructor completado correctamente");
}
catch (Exception ex)
{
Debug.WriteLine($"Error en constructor osHydPipe: {ex.Message}");
Nombre = "Tubería Hidráulica";
Ancho = 1.0f;
Alto = 0.05f;
}
}
// Propiedades de configuración de la tubería
[Category("🔧 Tubería Hidráulica")]
[DisplayName("Longitud")]
[Description("Longitud de la tubería en metros")]
public double Length
{
get => _length;
set
{
if (SetProperty(ref _length, Math.Max(0.1, value)))
{
InvalidateHydraulicNetwork();
}
}
}
[Category("🔧 Tubería Hidráulica")]
[DisplayName("Diámetro")]
[Description("Diámetro interno de la tubería en metros")]
public double Diameter
{
get => _diameter;
set
{
if (SetProperty(ref _diameter, Math.Max(0.001, value)))
{
InvalidateHydraulicNetwork();
}
}
}
[Category("🔧 Tubería Hidráulica")]
[DisplayName("Rugosidad")]
[Description("Rugosidad del material en metros")]
public double Roughness
{
get => _roughness;
set
{
if (SetProperty(ref _roughness, Math.Max(1e-6, value)))
{
InvalidateHydraulicNetwork();
}
}
}
// Estado actual (desde TSNet)
[Category("📊 Estado Actual")]
[DisplayName("Flujo actual")]
[Description("Flujo actual a través de la tubería (m³/s)")]
[ReadOnly(true)]
public double CurrentFlow
{
get => _currentFlow;
private set => SetProperty(ref _currentFlow, value);
}
[Category("📊 Estado Actual")]
[DisplayName("Caída de presión")]
[Description("Caída de presión en la tubería (Pa)")]
[ReadOnly(true)]
public double PressureDrop
{
get => _pressureDrop;
private set => SetProperty(ref _pressureDrop, value);
}
[Category("📊 Estado Actual")]
[DisplayName("Velocidad")]
[Description("Velocidad del fluido en la tubería (m/s)")]
[ReadOnly(true)]
public double FluidVelocity
{
get => _velocity;
private set => SetProperty(ref _velocity, value);
}
[Category("📊 Estado Actual")]
[DisplayName("Flujo (L/min)")]
[Description("Flujo actual en L/min")]
[ReadOnly(true)]
public double CurrentFlowLMin => Math.Abs(CurrentFlow) * 60000.0; // m³/s a L/min
[Category("📊 Estado Actual")]
[DisplayName("Caída presión (bar)")]
[Description("Caída de presión en bar")]
[ReadOnly(true)]
public double PressureDropBar => PressureDrop / 100000.0; // Pa a bar
[Category("📊 Estado Actual")]
[DisplayName("Tiene flujo")]
[Description("Indica si hay flujo en la tubería")]
[ReadOnly(true)]
public bool HasFlow => Math.Abs(CurrentFlow) > 1e-6;
// 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)
{
Ancho += Delta_Width;
Alto += 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(CurrentFlowLMin));
OnPropertyChanged(nameof(PressureDropBar));
OnPropertyChanged(nameof(HasFlow));
UpdatePipeColor();
}
private void UpdatePipeColor()
{
// Cambiar color según el flujo
if (HasFlow)
{
var flowPercent = Math.Min(1.0, CurrentFlowLMin / 100.0); // normalizar a 100 L/min
var intensity = (byte)(255 * flowPercent);
ColorButton_oculto = new SolidColorBrush(Color.FromRgb(intensity, (byte)(255 - intensity), 0));
}
else
{
ColorButton_oculto = Brushes.Gray;
}
}
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)
{
// La caída de presión se calcula en TSNet
}
public void ApplyHydraulicFlow(double flowM3s)
{
CurrentFlow = flowM3s;
// Calcular velocidad
if (Diameter > 0)
{
var area = Math.PI * Math.Pow(Diameter / 2, 2); // m²
FluidVelocity = Math.Abs(CurrentFlow) / area; // m/s
}
}
public void UpdateHydraulicState(double timeSeconds)
{
// TSNet maneja el estado
}
// Métodos para TSNet
public void UpdateFromTSNetResults(double flow, double pressureDrop)
{
CurrentFlow = flow;
PressureDrop = pressureDrop;
// Calcular velocidad
if (Diameter > 0)
{
var area = Math.PI * Math.Pow(Diameter / 2, 2); // m²
FluidVelocity = Math.Abs(CurrentFlow) / area; // m/s
}
}
// Crear adapter para TSNet
public TSNetPipeAdapter CreateTSNetAdapter()
{
TSNetAdapter = new TSNetPipeAdapter(this);
return TSNetAdapter;
}
// Implementación de IHydraulicComponent
[JsonIgnore]
public bool HasHydraulicComponents => true;
public List GetHydraulicNodes()
{
// Las tuberías no crean nodos propios, se conectan entre nodos existentes
return new List();
}
public void ApplyHydraulicResults(Dictionary flows, Dictionary pressures)
{
try
{
// Buscar resultados de esta tubería en TSNet
var pipeElementName = $"PIPE_{Nombre}";
if (flows.ContainsKey(pipeElementName))
{
var pipeFlow = flows[pipeElementName];
ApplyHydraulicFlow(pipeFlow);
}
// Calcular caída de presión si tenemos datos de los nodos conectados
if (!string.IsNullOrEmpty(Id_ComponenteA) && !string.IsNullOrEmpty(Id_ComponenteB))
{
if (pressures.ContainsKey(Id_ComponenteA) && pressures.ContainsKey(Id_ComponenteB))
{
var pressureA = pressures[Id_ComponenteA];
var pressureB = pressures[Id_ComponenteB];
PressureDrop = Math.Abs(pressureA - pressureB);
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error en Pipe {Nombre} ApplyHydraulicResults: {ex.Message}");
}
}
public List GetHydraulicElements()
{
var elements = new List();
// Verificar que la tubería esté conectada a dos componentes
if (!string.IsNullOrEmpty(Id_ComponenteA) && !string.IsNullOrEmpty(Id_ComponenteB))
{
// Crear elemento pipe con propiedades correctas
var pipeElement = new Pipe(Length, Diameter, Roughness);
elements.Add(new HydraulicElementDefinition(
$"PIPE_{Nombre}",
Id_ComponenteA,
Id_ComponenteB,
pipeElement,
$"Tubería - L:{Length:F1}m, D:{Diameter*1000:F0}mm, Rough:{Roughness*1000:F2}mm"
));
}
return elements;
}
public void UpdateHydraulicProperties()
{
// Actualizar propiedades antes de la simulación
// Validar conexiones
if (string.IsNullOrEmpty(Id_ComponenteA) || string.IsNullOrEmpty(Id_ComponenteB))
{
Debug.WriteLine($"Warning: Tubería {Nombre} no está completamente conectada");
}
}
// Implementación de IHydraulicFlowReceiver
public void SetFlow(double flow)
{
ApplyHydraulicFlow(flow);
}
public double GetFlow()
{
return CurrentFlow;
}
// Implementación de IHydraulicPressureReceiver
public void SetPressure(double pressure)
{
// Las tuberías no tienen presión propia, solo caída de presión
}
public double GetPressure()
{
return PressureDrop;
}
// Implementación de IosBase
public void Start()
{
// Inicialización de la tubería 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; } = 1;
public ZIndexEnum ZIndex_Base()
{
return ZIndexEnum.Estaticos;
}
public override void CopyFrom(osBase source)
{
if (source is osHydPipe sourcePipe)
{
Length = sourcePipe.Length;
Diameter = sourcePipe.Diameter;
Roughness = sourcePipe.Roughness;
Id_ComponenteA = sourcePipe.Id_ComponenteA;
Id_ComponenteB = sourcePipe.Id_ComponenteB;
}
base.CopyFrom(source);
}
}
}