diff --git a/CtrEditor.csproj b/CtrEditor.csproj
index b8c6be5..3608e46 100644
--- a/CtrEditor.csproj
+++ b/CtrEditor.csproj
@@ -74,6 +74,9 @@
+
+
+
@@ -150,6 +153,8 @@
+
+
diff --git a/ObjetosSim/HydraulicComponents/osHydPipe.cs b/ObjetosSim/HydraulicComponents/osHydPipe.cs
index 053339a..92a3917 100644
--- a/ObjetosSim/HydraulicComponents/osHydPipe.cs
+++ b/ObjetosSim/HydraulicComponents/osHydPipe.cs
@@ -169,21 +169,80 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
// Solo crear elemento si ambos componentes están conectados
if (!string.IsNullOrEmpty(Id_ComponenteA) && !string.IsNullOrEmpty(Id_ComponenteB))
{
- // Crear el elemento Pipe según la documentación
- var pipeElement = new Pipe(Length, Diameter, Roughness);
+ // Obtener los nombres de nodos correctos para cada componente
+ string fromNodeName = GetNodeNameForComponent(Id_ComponenteA, true); // true = es el nodo origen
+ string toNodeName = GetNodeNameForComponent(Id_ComponenteB, false); // false = es el nodo destino
- elements.Add(new HydraulicElementDefinition(
- name: $"{Nombre}_Pipe",
- fromNode: Id_ComponenteA, // Usar el nombre del componente A como nodo origen
- toNode: Id_ComponenteB, // Usar el nombre del componente B como nodo destino
- element: pipeElement,
- description: $"Tubería {Nombre} - L:{Length:F2}m, D:{Diameter*1000:F0}mm ({Id_ComponenteA} → {Id_ComponenteB})"
- ));
+ if (!string.IsNullOrEmpty(fromNodeName) && !string.IsNullOrEmpty(toNodeName))
+ {
+ // Crear el elemento Pipe según la documentación
+ var pipeElement = new Pipe(Length, Diameter, Roughness);
+
+ elements.Add(new HydraulicElementDefinition(
+ name: $"{Nombre}_Pipe",
+ fromNode: fromNodeName,
+ toNode: toNodeName,
+ element: pipeElement,
+ description: $"Tubería {Nombre} - L:{Length:F2}m, D:{Diameter*1000:F0}mm ({fromNodeName} → {toNodeName})"
+ ));
+ }
}
return elements;
}
+ ///
+ /// Obtiene el nombre del nodo correcto para un componente dado
+ ///
+ /// Nombre del componente
+ /// True si es el nodo origen de la tubería, False si es destino
+ /// Nombre del nodo o string vacío si no se encuentra
+ private string GetNodeNameForComponent(string componentName, bool isSource)
+ {
+ if (string.IsNullOrEmpty(componentName) || _mainViewModel == null)
+ return "";
+
+ // Buscar el componente hidráulico
+ var component = _mainViewModel.ObjetosSimulables
+ .FirstOrDefault(s => s is IHydraulicComponent comp &&
+ ((osBase)comp).Nombre == componentName) as IHydraulicComponent;
+
+ if (component == null)
+ return "";
+
+ // Obtener los nodos que crea este componente
+ var nodes = component.GetHydraulicNodes();
+ if (nodes == null || !nodes.Any())
+ return "";
+
+ // Determinar qué nodo usar según el tipo de componente
+ var componentType = component.GetType();
+
+ // Para tanques: siempre usar su único nodo
+ if (componentType.Name.Contains("Tank"))
+ {
+ return nodes.FirstOrDefault()?.Name ?? "";
+ }
+
+ // Para bombas: usar nodo de entrada o salida según corresponda
+ if (componentType.Name.Contains("Pump"))
+ {
+ if (isSource)
+ {
+ // Si la tubería sale desde este componente, usar el nodo de salida de la bomba
+ return nodes.FirstOrDefault(n => n.Name.EndsWith("_Out"))?.Name ?? "";
+ }
+ else
+ {
+ // Si la tubería llega a este componente, usar el nodo de entrada de la bomba
+ return nodes.FirstOrDefault(n => n.Name.EndsWith("_In"))?.Name ?? "";
+ }
+ }
+
+ // Para otros tipos de componentes, usar el primer nodo disponible
+ return nodes.FirstOrDefault()?.Name ?? "";
+ }
+
public void UpdateHydraulicProperties()
{
// Actualizar propiedades antes de la simulación si es necesario
@@ -195,18 +254,25 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
// Solo procesar si ambos componentes están conectados
if (!string.IsNullOrEmpty(Id_ComponenteA) && !string.IsNullOrEmpty(Id_ComponenteB))
{
- string branchKey = $"{Id_ComponenteA}->{Id_ComponenteB}";
+ // Obtener los nombres de nodos correctos
+ string fromNodeName = GetNodeNameForComponent(Id_ComponenteA, true);
+ string toNodeName = GetNodeNameForComponent(Id_ComponenteB, false);
- if (flows.TryGetValue(branchKey, out double flow))
+ if (!string.IsNullOrEmpty(fromNodeName) && !string.IsNullOrEmpty(toNodeName))
{
- CurrentFlow = flow;
- }
-
- // Calcular pérdida de presión entre nodos
- if (pressures.TryGetValue(Id_ComponenteA, out double pressureA) &&
- pressures.TryGetValue(Id_ComponenteB, out double pressureB))
- {
- PressureDrop = pressureA - pressureB;
+ string branchKey = $"{fromNodeName}->{toNodeName}";
+
+ if (flows.TryGetValue(branchKey, out double flow))
+ {
+ CurrentFlow = flow;
+ }
+
+ // Calcular pérdida de presión entre nodos
+ if (pressures.TryGetValue(fromNodeName, out double pressureA) &&
+ pressures.TryGetValue(toNodeName, out double pressureB))
+ {
+ PressureDrop = pressureA - pressureB;
+ }
}
}
}
diff --git a/ObjetosSim/HydraulicComponents/osHydPump.cs b/ObjetosSim/HydraulicComponents/osHydPump.cs
index ca836c0..1397547 100644
--- a/ObjetosSim/HydraulicComponents/osHydPump.cs
+++ b/ObjetosSim/HydraulicComponents/osHydPump.cs
@@ -18,8 +18,33 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
///
public partial class osHydPump : osBase, IHydraulicPump, IosBase
{
- #region Properties
+ public static string NombreCategoria() => "Hidraulico";
+ public static string NombreClase()
+ {
+ return "Bomba Hidráulica";
+ }
+
+ #region Properties
+
+ [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;
+
+ public override void OnResize(float Delta_Width, float Delta_Height)
+ {
+ Tamano += Delta_Width + Delta_Height;
+ }
+
private double _pumpHead = 50.0; // metros
private double _maxFlow = 0.01; // m³/s (36 m³/h)
private double _speedRatio = 1.0;
@@ -103,9 +128,20 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
get => _isRunning;
set
{
- SetProperty(ref _isRunning, value);
+ if (SetProperty(ref _isRunning, value))
+ {
+ UpdatePumpImage();
+ }
}
}
+
+ private void UpdatePumpImage()
+ {
+ if (IsRunning)
+ ImageSource_oculta = ImageFromPath("/imagenes/pump_run.png");
+ else
+ ImageSource_oculta = ImageFromPath("/imagenes/pump_stop.png");
+ }
[Category("🔧 Bomba Hidráulica")]
[DisplayName("Dirección")]
@@ -175,15 +211,11 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
// 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";
+ Tamano = 0.30f;
+ ImageSource_oculta = ImageFromPath("/imagenes/pump_stop.png");
}
public override void UpdateGeometryStart()
@@ -211,6 +243,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
{
// Los objetos hidráulicos no necesitan geometría física
base.ucLoaded();
+ UpdatePumpImage();
}
public override void ucUnLoaded()
@@ -242,11 +275,17 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
if (HasHydraulicComponents)
{
+ // Calcular velocidad efectiva basada en el estado de la bomba
+ double effectiveSpeed = IsRunning ? SpeedRatio : 0.0;
+
+ // Asegurar que la velocidad esté en rango válido
+ effectiveSpeed = Math.Max(0.0, Math.Min(1.0, effectiveSpeed));
+
// 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
+ speedRel: effectiveSpeed,
direction: PumpDirection
);
@@ -259,6 +298,8 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
);
elements.Add(pumpElement);
+
+ Debug.WriteLine($"Bomba {Nombre}: Creando elemento hidráulico - H0={PumpHead}m, Q0={MaxFlow}m³/s, Velocidad={effectiveSpeed:F2}, Dirección={PumpDirection}");
}
return elements;
@@ -288,16 +329,25 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
if (flows.ContainsKey(pumpBranchName))
{
CurrentFlow = flows[pumpBranchName];
+ Debug.WriteLine($"Bomba {Nombre}: Aplicando caudal={CurrentFlow:F6} m³/s ({CurrentFlowLMin:F2} L/min)");
}
if (pressures.ContainsKey(inletNodeName))
{
CurrentPressure = pressures[inletNodeName];
+ Debug.WriteLine($"Bomba {Nombre}: Presión entrada={CurrentPressure:F2} Pa ({CurrentPressureBar:F2} bar)");
}
else if (pressures.ContainsKey(outletNodeName))
{
CurrentPressure = pressures[outletNodeName];
+ Debug.WriteLine($"Bomba {Nombre}: Presión salida={CurrentPressure:F2} Pa ({CurrentPressureBar:F2} bar)");
}
+
+ // Disparar PropertyChanged para actualizar el UI
+ OnPropertyChanged(nameof(CurrentFlow));
+ OnPropertyChanged(nameof(CurrentFlowLMin));
+ OnPropertyChanged(nameof(CurrentPressure));
+ OnPropertyChanged(nameof(CurrentPressureBar));
}
#endregion
@@ -345,13 +395,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
}
#endregion
-
- #region Static Interface Implementation
-
- public static string NombreClase() => "Bomba Hidráulica";
- public static string NombreCategoria() => "Componentes Hidráulicos";
-
- #endregion
}
///
diff --git a/ObjetosSim/HydraulicComponents/ucHydPump.xaml b/ObjetosSim/HydraulicComponents/ucHydPump.xaml
index 2ae0cbd..50d1115 100644
--- a/ObjetosSim/HydraulicComponents/ucHydPump.xaml
+++ b/ObjetosSim/HydraulicComponents/ucHydPump.xaml
@@ -3,77 +3,39 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+ xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim.HydraulicComponents"
mc:Ignorable="d">
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs b/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs
index 6ba1a86..39ef95f 100644
--- a/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs
+++ b/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs
@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
-using System.Windows.Media.Animation;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
@@ -17,7 +16,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
public osBase? Datos { get; set; }
public int zIndex_fromFrames { get; set; } = 0;
- private Storyboard? _rotationAnimation;
private bool _isHighlighted = false;
public ucHydPump()
@@ -25,13 +23,11 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
InitializeComponent();
this.Loaded += OnLoaded;
this.Unloaded += OnUnloaded;
- DataContextChanged += OnDataContextChanged;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
- UpdateVisualState();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
@@ -39,155 +35,12 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
Datos?.ucUnLoaded();
}
- private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
- {
- if (DataContext is osHydPump pump)
- {
- Datos = pump;
- pump.PropertyChanged += OnPumpPropertyChanged;
- UpdateVisualState();
- }
- }
-
- private void OnPumpPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
- {
- if (e.PropertyName == nameof(osHydPump.IsRunning) ||
- e.PropertyName == nameof(osHydPump.SpeedRatio) ||
- e.PropertyName == nameof(osHydPump.PumpDirection) ||
- e.PropertyName == nameof(osHydPump.CurrentFlow) ||
- e.PropertyName == nameof(osHydPump.CurrentPressure))
- {
- UpdateVisualState();
- }
- }
-
- ///
- /// Actualiza el estado visual de la bomba
- ///
- private void UpdateVisualState()
- {
- if (Datos is not osHydPump pump) return;
-
- try
- {
- Dispatcher.BeginInvoke(() =>
- {
- UpdateStatusLED(pump);
- UpdateRotationAnimation(pump);
- UpdateDirectionArrow(pump);
- UpdateStatusInfo(pump);
- });
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"Error updating pump visual state: {ex.Message}");
- }
- }
-
- ///
- /// Actualiza el LED de estado
- ///
- private void UpdateStatusLED(osHydPump pump)
- {
- if (pump.IsRunning && pump.SpeedRatio > 0)
- {
- StatusLED.Fill = new SolidColorBrush(Colors.LimeGreen);
- }
- else
- {
- StatusLED.Fill = new SolidColorBrush(Colors.Red);
- }
- }
-
- ///
- /// Actualiza la animación de rotación
- ///
- private void UpdateRotationAnimation(osHydPump pump)
- {
- _rotationAnimation?.Stop();
-
- if (pump.IsRunning && pump.SpeedRatio > 0)
- {
- // Crear animación de rotación
- var rotateTransform = new RotateTransform();
- PumpBackground.RenderTransform = rotateTransform;
- PumpBackground.RenderTransformOrigin = new Point(0.5, 0.5);
-
- var animation = new DoubleAnimation
- {
- From = 0,
- To = 360,
- Duration = TimeSpan.FromSeconds(2.0 / pump.SpeedRatio), // Más rápido con mayor velocidad
- RepeatBehavior = RepeatBehavior.Forever
- };
-
- _rotationAnimation = new Storyboard();
- Storyboard.SetTarget(animation, rotateTransform);
- Storyboard.SetTargetProperty(animation, new PropertyPath(RotateTransform.AngleProperty));
- _rotationAnimation.Children.Add(animation);
- _rotationAnimation.Begin();
- }
- else
- {
- PumpBackground.RenderTransform = null;
- }
- }
-
- ///
- /// Actualiza la flecha de dirección
- ///
- private void UpdateDirectionArrow(osHydPump pump)
- {
- if (pump.PumpDirection == -1)
- {
- // Cambiar el color de la flecha para indicar dirección inversa
- DirectionArrow.Fill = new SolidColorBrush(Colors.Orange);
- }
- else
- {
- DirectionArrow.Fill = new SolidColorBrush(Colors.DarkBlue);
- }
- }
-
- ///
- /// Actualiza la información de estado
- ///
- private void UpdateStatusInfo(osHydPump pump)
- {
- // La información de estado se mostrará a través de la etiqueta principal
- // El StatusLED ya está configurado para mostrar el estado IsRunning
- }
-
#region IDataContainer Implementation
public void Highlight(bool state)
{
_isHighlighted = state;
-
- if (state)
- {
- PumpBackground.Stroke = new SolidColorBrush(Colors.Yellow);
- PumpBackground.StrokeThickness = 3;
- }
- else
- {
- PumpBackground.Stroke = new SolidColorBrush(Colors.DarkSlateGray);
- PumpBackground.StrokeThickness = 2;
- }
- }
-
- #endregion
-
- protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
- {
- base.OnMouseEnter(e);
- // No hay elementos adicionales para mostrar en la implementación actual
- }
-
- protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
- {
- base.OnMouseLeave(e);
- // No hay elementos adicionales para ocultar en la implementación actual
+ // Aquí se podría agregar lógica de resaltado si fuera necesario
}
public ZIndexEnum ZIndex_Base()
@@ -195,9 +48,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
return ZIndexEnum.Estaticos;
}
- ~ucHydPump()
- {
- _rotationAnimation?.Stop();
- }
+ #endregion
}
}
diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs
index 44d88c0..ba4b314 100644
--- a/ObjetosSim/osBase.cs
+++ b/ObjetosSim/osBase.cs
@@ -1919,9 +1919,30 @@ namespace CtrEditor.ObjetosSim
items.Add("");
foreach (var obj in objetosSimulables)
{
- if (obj.GetType() == typeof(T))
+ try
{
- items.Add(obj.Nombre);
+ // Verificar si el tipo T es una interfaz
+ if (typeof(T).IsInterface)
+ {
+ // Para interfaces, verificar si el objeto implementa la interfaz
+ if (typeof(T).IsAssignableFrom(obj.GetType()))
+ {
+ items.Add(obj.Nombre);
+ }
+ }
+ else
+ {
+ // Para clases concretas, usar comparación directa de tipos
+ if (obj.GetType() == typeof(T))
+ {
+ items.Add(obj.Nombre);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // Log the exception but continue processing other objects
+ System.Diagnostics.Debug.WriteLine($"Error checking type compatibility for {obj?.GetType()?.Name}: {ex.Message}");
}
}
diff --git a/imagenes/pump_run.png b/imagenes/pump_run.png
new file mode 100644
index 0000000..46bb083
Binary files /dev/null and b/imagenes/pump_run.png differ
diff --git a/imagenes/pump_stop.png b/imagenes/pump_stop.png
new file mode 100644
index 0000000..46bb083
Binary files /dev/null and b/imagenes/pump_stop.png differ
diff --git a/test_osBaseItemsSource.cs b/test_osBaseItemsSource.cs
new file mode 100644
index 0000000..5fe4ee3
--- /dev/null
+++ b/test_osBaseItemsSource.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using CtrEditor.ObjetosSim;
+using CtrEditor.ObjetosSim.HydraulicComponents;
+using CtrEditor.HydraulicSimulator;
+
+// Este archivo es solo para verificar que la corrección funciona
+// Se puede eliminar después de confirmar que todo funciona bien
+
+namespace CtrEditor.Test
+{
+ class TestItemsSource
+ {
+ static void TestTypeAssignability()
+ {
+ // Crear instancias de objetos hidráulicos
+ var pipe = new osHydPipe();
+ var tank = new osHydDischargeTank();
+ var pump = new osHydPump();
+
+ // Probar la corrección - debería ser true para todos
+ Console.WriteLine($"osHydPipe implements IHydraulicComponent: {typeof(IHydraulicComponent).IsAssignableFrom(pipe.GetType())}");
+ Console.WriteLine($"osHydDischargeTank implements IHydraulicComponent: {typeof(IHydraulicComponent).IsAssignableFrom(tank.GetType())}");
+ Console.WriteLine($"osHydPump implements IHydraulicComponent: {typeof(IHydraulicComponent).IsAssignableFrom(pump.GetType())}");
+
+ // La comparación anterior que fallaba
+ Console.WriteLine($"osHydPipe.GetType() == typeof(IHydraulicComponent): {pipe.GetType() == typeof(IHydraulicComponent)}");
+ Console.WriteLine($"osHydDischargeTank.GetType() == typeof(IHydraulicComponent): {tank.GetType() == typeof(IHydraulicComponent)}");
+ Console.WriteLine($"osHydPump.GetType() == typeof(IHydraulicComponent): {pump.GetType() == typeof(IHydraulicComponent)}");
+ }
+ }
+}