diff --git a/DataStates/StateManager.cs b/DataStates/StateManager.cs
index 372686d..884af89 100644
--- a/DataStates/StateManager.cs
+++ b/DataStates/StateManager.cs
@@ -275,7 +275,7 @@ namespace CtrEditor
if (userControl != null)
{
- UserControlFactory.AssignDatos(userControl, osObjeto, _mainViewModel.simulationManager);
+ UserControlFactory.AssignDatos(userControl, osObjeto, _mainViewModel.simulationManager, _mainViewModel.hydraulicSimulationManager);
osObjeto._mainViewModel = _mainViewModel;
if (osObjeto.Id == null)
diff --git a/HydraulicSimulator/HydraulicSimulationManager.cs b/HydraulicSimulator/HydraulicSimulationManager.cs
index 3138473..fb4bd1b 100644
--- a/HydraulicSimulator/HydraulicSimulationManager.cs
+++ b/HydraulicSimulator/HydraulicSimulationManager.cs
@@ -451,6 +451,13 @@ namespace CtrEditor.HydraulicSimulator
///
private void UpdateObjectProperties()
{
+ // Actualizar objetos hidráulicos específicos
+ foreach (var simObj in HydraulicSimObjects)
+ {
+ simObj.UpdateProperties();
+ }
+
+ // Actualizar objetos hidráulicos generales (legacy)
foreach (var obj in HydraulicObjects)
{
// Aquí se implementará la actualización de propiedades específicas
@@ -548,6 +555,14 @@ namespace CtrEditor.HydraulicSimulator
///
private void ApplyResultsToObjects()
{
+ // Aplicar resultados a objetos hidráulicos específicos
+ foreach (var simObj in HydraulicSimObjects)
+ {
+ ApplyResultsToSimObject(simObj);
+ simObj.ApplySimulationResults();
+ }
+
+ // Aplicar resultados a objetos hidráulicos generales (legacy)
foreach (var obj in HydraulicObjects)
{
// Aplicar caudales y presiones calculados al objeto
@@ -555,6 +570,58 @@ namespace CtrEditor.HydraulicSimulator
}
}
+ ///
+ /// Aplica los resultados de la simulación a un objeto específico
+ ///
+ private void ApplyResultsToSimObject(simHydraulicBase simObj)
+ {
+ // Aplicar resultados específicos según el tipo de objeto
+ if (simObj is simHydraulicPump pump)
+ {
+ // Buscar flujo y presión de la bomba en los resultados
+ string pumpBranchName = $"{pump.Nombre}_Pump";
+ if (LastSolutionResult.Flows.TryGetValue(pumpBranchName, out double flow))
+ {
+ pump.CurrentFlow = flow;
+ }
+
+ string inletNodeName = $"{pump.Nombre}_In";
+ if (LastSolutionResult.Pressures.TryGetValue(inletNodeName, out double pressure))
+ {
+ pump.CurrentPressure = pressure;
+ }
+ }
+ else if (simObj is simHydraulicTank tank)
+ {
+ // Buscar flujos de entrada y salida del tanque
+ // Esto requeriría mapeo de tuberías conectadas
+ // Por ahora, aplicar presión del tanque
+ string tankNodeName = $"{tank.Nombre}_Tank";
+ if (LastSolutionResult.Pressures.TryGetValue(tankNodeName, out double pressure))
+ {
+ tank.CurrentPressure = pressure;
+ }
+ }
+ else if (simObj is simHydraulicPipe pipe)
+ {
+ // Buscar flujo a través de la tubería
+ string pipeBranchName = $"{pipe.Nombre}_Pipe";
+ if (LastSolutionResult.Flows.TryGetValue(pipeBranchName, out double flow))
+ {
+ pipe.CurrentFlow = flow;
+ }
+
+ // Calcular pérdida de presión
+ string fromNode = pipe.ComponenteAId;
+ string toNode = pipe.ComponenteBId;
+ if (LastSolutionResult.Pressures.TryGetValue(fromNode, out double pressureA) &&
+ LastSolutionResult.Pressures.TryGetValue(toNode, out double pressureB))
+ {
+ pipe.PressureDrop = pressureA - pressureB;
+ }
+ }
+ }
+
///
/// Aplica los resultados a un objeto específico
///
@@ -729,5 +796,103 @@ namespace CtrEditor.HydraulicSimulator
}
#endregion
+
+ #region Hydraulic Object Creation
+
+ ///
+ /// Lista de objetos hidráulicos específicos del simulador
+ ///
+ public List HydraulicSimObjects { get; private set; } = new List();
+
+ ///
+ /// Crea una bomba hidráulica en la simulación
+ ///
+ public simHydraulicPump AddPump(double pumpHead, double maxFlow, double speedRatio, bool isRunning, int direction)
+ {
+ var pump = new simHydraulicPump(this)
+ {
+ PumpHead = pumpHead,
+ MaxFlow = maxFlow,
+ SpeedRatio = speedRatio,
+ IsRunning = isRunning,
+ PumpDirection = direction
+ };
+
+ HydraulicSimObjects.Add(pump);
+ _networkNeedsRebuild = true;
+
+ Debug.WriteLine($"Bomba hidráulica creada: H={pumpHead}m, Q={maxFlow}m³/s");
+ return pump;
+ }
+
+ ///
+ /// Crea un tanque hidráulico en la simulación
+ ///
+ public simHydraulicTank AddTank(double pressure, double currentLevel, double maxLevel, double minLevel, double crossSectionalArea, bool isFixedPressure)
+ {
+ var tank = new simHydraulicTank(this)
+ {
+ TankPressure = pressure,
+ CurrentLevel = currentLevel,
+ MaxLevel = maxLevel,
+ MinLevel = minLevel,
+ CrossSectionalArea = crossSectionalArea,
+ IsFixedPressure = isFixedPressure
+ };
+
+ HydraulicSimObjects.Add(tank);
+ _networkNeedsRebuild = true;
+
+ Debug.WriteLine($"Tanque hidráulico creado: P={pressure}Pa, Nivel={currentLevel}m");
+ return tank;
+ }
+
+ ///
+ /// Crea una tubería hidráulica en la simulación
+ ///
+ public simHydraulicPipe AddPipe(double length, double diameter, double roughness, string componenteAId, string componenteBId)
+ {
+ var pipe = new simHydraulicPipe(this)
+ {
+ Length = length,
+ Diameter = diameter,
+ Roughness = roughness,
+ ComponenteAId = componenteAId,
+ ComponenteBId = componenteBId
+ };
+
+ HydraulicSimObjects.Add(pipe);
+ _networkNeedsRebuild = true;
+
+ Debug.WriteLine($"Tubería hidráulica creada: L={length}m, D={diameter}m");
+ return pipe;
+ }
+
+ ///
+ /// Remueve un objeto hidráulico de la simulación
+ ///
+ public void Remove(simHydraulicBase hydraulicObject)
+ {
+ if (hydraulicObject != null && HydraulicSimObjects.Contains(hydraulicObject))
+ {
+ HydraulicSimObjects.Remove(hydraulicObject);
+ _networkNeedsRebuild = true;
+
+ Debug.WriteLine($"Objeto hidráulico removido: {hydraulicObject.SimObjectType}");
+ }
+ }
+
+ ///
+ /// Limpia todos los objetos hidráulicos específicos
+ ///
+ public void ClearHydraulicSimObjects()
+ {
+ HydraulicSimObjects.Clear();
+ _networkNeedsRebuild = true;
+
+ Debug.WriteLine("Todos los objetos hidráulicos específicos han sido limpiados");
+ }
+
+ #endregion
}
}
diff --git a/HydraulicSimulator/simHydraulicBase.cs b/HydraulicSimulator/simHydraulicBase.cs
new file mode 100644
index 0000000..c4ee0c1
--- /dev/null
+++ b/HydraulicSimulator/simHydraulicBase.cs
@@ -0,0 +1,179 @@
+using System.Numerics;
+using System.ComponentModel;
+using CtrEditor.ObjetosSim;
+
+namespace CtrEditor.HydraulicSimulator
+{
+ ///
+ /// Clase base para objetos hidráulicos en la simulación
+ /// Similar a simBase pero para el sistema hidráulico
+ ///
+ public class simHydraulicBase
+ {
+ public string SimObjectType { get; set; } = "";
+ public osBase WpfObject { get; set; }
+ public string Nombre { get; set; }
+ public bool Descartar { get; set; } = false;
+
+ protected HydraulicSimulationManager _hydraulicManager;
+
+ public simHydraulicBase(HydraulicSimulationManager hydraulicManager)
+ {
+ _hydraulicManager = hydraulicManager;
+ }
+
+ ///
+ /// Método virtual para actualizar propiedades específicas del objeto
+ ///
+ public virtual void UpdateProperties()
+ {
+ // Implementación base - puede ser sobrescrita
+ }
+
+ ///
+ /// Método virtual para aplicar resultados de la simulación al objeto WPF
+ ///
+ public virtual void ApplySimulationResults()
+ {
+ // Implementación base - puede ser sobrescrita
+ }
+ }
+
+ ///
+ /// Representa una bomba hidráulica en la simulación
+ ///
+ public class simHydraulicPump : simHydraulicBase
+ {
+ public double PumpHead { get; set; }
+ public double MaxFlow { get; set; }
+ public double SpeedRatio { get; set; }
+ public bool IsRunning { get; set; }
+ public int PumpDirection { get; set; }
+
+ // Resultados de la simulación
+ public double CurrentFlow { get; set; }
+ public double CurrentPressure { get; set; }
+
+ public simHydraulicPump(HydraulicSimulationManager hydraulicManager) : base(hydraulicManager)
+ {
+ SimObjectType = "HydraulicPump";
+ }
+
+ public override void UpdateProperties()
+ {
+ // Actualizar propiedades específicas de la bomba
+ if (WpfObject is IHydraulicPump pump)
+ {
+ PumpHead = pump.PumpHead;
+ MaxFlow = pump.MaxFlow;
+ SpeedRatio = pump.SpeedRatio;
+ IsRunning = pump.IsRunning;
+ PumpDirection = pump.PumpDirection;
+ }
+ }
+
+ public override void ApplySimulationResults()
+ {
+ // Aplicar resultados al objeto WPF
+ if (WpfObject is IHydraulicPump pump)
+ {
+ pump.SetFlow(CurrentFlow);
+ pump.SetPressure(CurrentPressure);
+ }
+ }
+ }
+
+ ///
+ /// Representa un tanque hidráulico en la simulación
+ ///
+ public class simHydraulicTank : simHydraulicBase
+ {
+ public double TankPressure { get; set; }
+ public double CurrentLevel { get; set; }
+ public double MaxLevel { get; set; }
+ public double MinLevel { get; set; }
+ public double CrossSectionalArea { get; set; }
+ public bool IsFixedPressure { get; set; }
+
+ // Resultados de la simulación
+ public double InletFlow { get; set; }
+ public double OutletFlow { get; set; }
+ public double CurrentPressure { get; set; }
+
+ public simHydraulicTank(HydraulicSimulationManager hydraulicManager) : base(hydraulicManager)
+ {
+ SimObjectType = "HydraulicTank";
+ }
+
+ public override void UpdateProperties()
+ {
+ // Actualizar propiedades específicas del tanque
+ if (WpfObject is osHydTank tank)
+ {
+ TankPressure = tank.TankPressure;
+ CurrentLevel = tank.CurrentLevel;
+ MaxLevel = tank.MaxLevel;
+ MinLevel = tank.MinLevel;
+ CrossSectionalArea = tank.CrossSectionalArea;
+ IsFixedPressure = tank.IsFixedPressure;
+ }
+ }
+
+ public override void ApplySimulationResults()
+ {
+ // Aplicar resultados al objeto WPF
+ if (WpfObject is IHydraulicFlowReceiver flowReceiver)
+ {
+ flowReceiver.SetFlow(InletFlow - OutletFlow); // Flujo neto
+ }
+
+ if (WpfObject is IHydraulicPressureReceiver pressureReceiver)
+ {
+ pressureReceiver.SetPressure(CurrentPressure);
+ }
+ }
+ }
+
+ ///
+ /// Representa una tubería hidráulica en la simulación
+ ///
+ public class simHydraulicPipe : simHydraulicBase
+ {
+ public double Length { get; set; }
+ public double Diameter { get; set; }
+ public double Roughness { get; set; }
+ public string ComponenteAId { get; set; }
+ public string ComponenteBId { get; set; }
+
+ // Resultados de la simulación
+ public double CurrentFlow { get; set; }
+ public double PressureDrop { get; set; }
+
+ public simHydraulicPipe(HydraulicSimulationManager hydraulicManager) : base(hydraulicManager)
+ {
+ SimObjectType = "HydraulicPipe";
+ }
+
+ public override void UpdateProperties()
+ {
+ // Actualizar propiedades específicas de la tubería
+ if (WpfObject is IHydraulicPipe pipe)
+ {
+ Length = pipe.Length;
+ Diameter = pipe.Diameter;
+ Roughness = pipe.Roughness;
+ // Obtener IDs de componentes conectados (esto se manejará en el manager)
+ }
+ }
+
+ public override void ApplySimulationResults()
+ {
+ // Aplicar resultados al objeto WPF
+ if (WpfObject is IHydraulicPipe pipe)
+ {
+ pipe.SetFlow(CurrentFlow);
+ pipe.SetPressure(PressureDrop); // En tuberías, "presión" es la pérdida de presión
+ }
+ }
+ }
+}
diff --git a/MainViewModel.cs b/MainViewModel.cs
index 7db8adc..900e8d2 100644
--- a/MainViewModel.cs
+++ b/MainViewModel.cs
@@ -813,7 +813,7 @@ namespace CtrEditor
if (userControl != null)
{
// Asignar los datos al UserControl
- UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager);
+ UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager, hydraulicSimulationManager);
osObjeto._mainViewModel = this;
if (osObjeto.Id == null) // Para los objetos salvados antes de usar UniqueID
osObjeto.Id = new UniqueId().ObtenerNuevaID();
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 439d529..c47f914 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -971,7 +971,37 @@ namespace CtrEditor
try
{
var serializedData = JsonConvert.SerializeObject(original, settings);
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Serialized data: {serializedData}");
+
copy = JsonConvert.DeserializeObject(serializedData, settings);
+
+ if (copy == null)
+ {
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Deserialización devolvió null para tipo: {original.GetType().Name}");
+ }
+ else
+ {
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Copia exitosa de tipo: {copy.GetType().Name}");
+ }
+ }
+ catch (JsonSerializationException jsonEx)
+ {
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Error de serialización JSON: {jsonEx.Message}");
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - StackTrace: {jsonEx.StackTrace}");
+ if (jsonEx.InnerException != null)
+ {
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Inner Exception: {jsonEx.InnerException.Message}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Error general: {ex.Message}");
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Tipo de excepción: {ex.GetType().Name}");
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - StackTrace: {ex.StackTrace}");
+ if (ex.InnerException != null)
+ {
+ Debug.WriteLine($"CreateCopyUsingExistingLogic - Inner Exception: {ex.InnerException.Message}");
+ }
}
finally
{
diff --git a/ObjetosSim/HydraulicComponents/osHydPipe.cs b/ObjetosSim/HydraulicComponents/osHydPipe.cs
index 3479c5a..12eda05 100644
--- a/ObjetosSim/HydraulicComponents/osHydPipe.cs
+++ b/ObjetosSim/HydraulicComponents/osHydPipe.cs
@@ -12,13 +12,15 @@ using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CommunityToolkit.Mvvm.ComponentModel;
using LibS7Adv;
-namespace CtrEditor.ObjetosSim.HydraulicComponents
+namespace CtrEditor.ObjetosSim
{
///
/// Tubería hidráulica que conecta componentes del sistema hidráulico
///
- public partial class osHydPipe : osBase, IHydraulicPipe, IosBase
+ public partial class osHydPipe : osBase, IHydraulicFlowReceiver, IHydraulicPressureReceiver, IosBase
{
+ // Referencia al objeto de simulación hidráulica específico
+ private simHydraulicPipe SimHydraulicPipe;
// Properties
private double _length = 1.0; // metros
@@ -396,9 +398,59 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
public override void UpdateGeometryStart()
{
+ // Se llama cuando inicia la simulación - crear objeto hidráulico si no existe
+ if (SimHydraulicPipe == null && !string.IsNullOrEmpty(Id_ComponenteA) && !string.IsNullOrEmpty(Id_ComponenteB))
+ {
+ SimHydraulicPipe = hydraulicSimulationManager.AddPipe(Length, Diameter, Roughness, Id_ComponenteA, Id_ComponenteB);
+ SimHydraulicPipe.SimObjectType = "HydraulicPipe";
+ SimHydraulicPipe.WpfObject = this;
+ SimHydraulicPipe.Nombre = Nombre;
+ }
+ else if (SimHydraulicPipe != null)
+ {
+ // Actualizar propiedades si el objeto ya existe
+ SimHydraulicPipe.Length = Length;
+ SimHydraulicPipe.Diameter = Diameter;
+ SimHydraulicPipe.Roughness = Roughness;
+ SimHydraulicPipe.ComponenteAId = Id_ComponenteA;
+ SimHydraulicPipe.ComponenteBId = Id_ComponenteB;
+ }
+
ActualizarGeometrias();
}
+ public override void UpdateGeometryStep()
+ {
+ // Los objetos hidráulicos actualizan sus resultados
+ // a través de ApplySimulationResults() desde HydraulicSimulationManager
+ }
+
+ public override void UpdateControl(int elapsedMilliseconds)
+ {
+ // Actualizar propiedades desde la simulación hidráulica
+ if (SimHydraulicPipe != null)
+ {
+ CurrentFlow = SimHydraulicPipe.CurrentFlow;
+ PressureDrop = SimHydraulicPipe.PressureDrop;
+ }
+ }
+
+ public override void ucLoaded()
+ {
+ // Objeto hidráulico se crea en UpdateGeometryStart cuando inicia la simulación
+ base.ucLoaded();
+ }
+
+ public override void ucUnLoaded()
+ {
+ // Remover objeto hidráulico de la simulación
+ if (SimHydraulicPipe != null)
+ {
+ hydraulicSimulationManager.Remove(SimHydraulicPipe);
+ SimHydraulicPipe = null;
+ }
+ }
+
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
{
// Las tuberías no tienen control PLC directo
diff --git a/ObjetosSim/HydraulicComponents/osHydPump.cs b/ObjetosSim/HydraulicComponents/osHydPump.cs
index 183a7ad..b64e392 100644
--- a/ObjetosSim/HydraulicComponents/osHydPump.cs
+++ b/ObjetosSim/HydraulicComponents/osHydPump.cs
@@ -11,13 +11,16 @@ using Newtonsoft.Json;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CommunityToolkit.Mvvm.ComponentModel;
-namespace CtrEditor.ObjetosSim.HydraulicComponents
+namespace CtrEditor.ObjetosSim
{
///
/// Bomba hidráulica que implementa las interfaces del simulador hidráulico
///
- public partial class osHydPump : osBase, IHydraulicPump, IosBase
+ public partial class osHydPump : osBase, IHydraulicFlowReceiver, IHydraulicPressureReceiver, IosBase
{
+ // Referencia al objeto de simulación hidráulica específico
+ private simHydraulicPump SimHydraulicPump;
+
public static string NombreCategoria() => "Componentes Hidráulicos";
public static string NombreClase()
@@ -206,35 +209,62 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
public override void UpdateGeometryStart()
{
- // Los objetos hidráulicos se registran automáticamente
- // cuando inicia la simulación a través de las interfaces
+ // Se llama cuando inicia la simulación - crear objeto hidráulico si no existe
+ if (SimHydraulicPump == null)
+ {
+ SimHydraulicPump = hydraulicSimulationManager.AddPump(PumpHead, MaxFlow, SpeedRatio, IsRunning, PumpDirection);
+ SimHydraulicPump.SimObjectType = "HydraulicPump";
+ SimHydraulicPump.WpfObject = this;
+ SimHydraulicPump.Nombre = Nombre;
+ }
+ else
+ {
+ // Actualizar propiedades si el objeto ya existe
+ SimHydraulicPump.PumpHead = PumpHead;
+ SimHydraulicPump.MaxFlow = MaxFlow;
+ SimHydraulicPump.SpeedRatio = SpeedRatio;
+ SimHydraulicPump.IsRunning = IsRunning;
+ SimHydraulicPump.PumpDirection = PumpDirection;
+ }
}
public override void UpdateGeometryStep()
{
// Los objetos hidráulicos actualizan sus resultados
- // a través de ApplyHydraulicResults()
+ // a través de ApplySimulationResults() desde HydraulicSimulationManager
}
public override void UpdateControl(int elapsedMilliseconds)
{
- // Actualizar el color según el estado
- if (IsRunning)
- ColorButton_oculto = Brushes.Green;
- else
- ColorButton_oculto = Brushes.Gray;
+ // Actualizar propiedades desde la simulación hidráulica
+ if (SimHydraulicPump != null)
+ {
+ CurrentFlow = SimHydraulicPump.CurrentFlow;
+ CurrentPressure = SimHydraulicPump.CurrentPressure;
+
+ // 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
+ // Objeto hidráulico se crea en UpdateGeometryStart cuando inicia la simulación
base.ucLoaded();
UpdatePumpImage();
}
public override void ucUnLoaded()
{
- // Los objetos hidráulicos no tienen geometría que limpiar
+ // Remover objeto hidráulico de la simulación
+ if (SimHydraulicPump != null)
+ {
+ hydraulicSimulationManager.Remove(SimHydraulicPump);
+ SimHydraulicPump = null;
+ }
}
@@ -368,23 +398,13 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
return CurrentPressure;
}
-
-
// Helper Methods
- ///
- /// Invalida la red hidráulica para forzar reconstrucción
- ///
private void InvalidateHydraulicNetwork()
{
- // Si tenemos acceso al MainViewModel, invalidar la red
- if (_mainViewModel?.hydraulicSimulationManager != null)
- {
- _mainViewModel.hydraulicSimulationManager.InvalidateNetwork();
- }
+ hydraulicSimulationManager?.InvalidateNetwork();
}
-
}
///
diff --git a/ObjetosSim/HydraulicComponents/osHydTank.cs b/ObjetosSim/HydraulicComponents/osHydTank.cs
index ad1782c..6b4e25c 100644
--- a/ObjetosSim/HydraulicComponents/osHydTank.cs
+++ b/ObjetosSim/HydraulicComponents/osHydTank.cs
@@ -13,13 +13,15 @@ using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CommunityToolkit.Mvvm.ComponentModel;
using LibS7Adv;
-namespace CtrEditor.ObjetosSim.HydraulicComponents
+namespace CtrEditor.ObjetosSim
{
///
/// Tanque hidráulico con gestión dinámica de nivel y presión configurable
///
- public partial class osHydTank : osBase, IHydraulicComponent, IHydraulicFlowReceiver, IHydraulicPressureReceiver, IosBase
+ public partial class osHydTank : osBase, IHydraulicFlowReceiver, IHydraulicPressureReceiver, IosBase
{
+ // Referencia al objeto de simulación hidráulica específico
+ private simHydraulicTank SimHydraulicTank;
public static string NombreCategoria() => "Componentes Hidráulicos";
public static string NombreClase() => "Tanque Hidráulico";
@@ -63,13 +65,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
// 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 del tanque")]
@@ -88,25 +83,37 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
// Constructor
public osHydTank()
{
- Nombre = "Tanque Hidráulico";
- Tamano = 1.0f; // Usar un tamaño mayor para mayor visibilidad
- // Inicializar dimensiones usando las propiedades de osBase
- Ancho = 0.30f;
- Alto = 0.40f;
- Angulo = 0f;
- // Asegurar que el movimiento esté habilitado
- Lock_movement = false;
- ImageSource_oculta = ImageFromPath("/imagenes/tank.png");
- _currentVolume = _currentLevel * _crossSectionalArea;
- _maxVolume = _maxLevel * _crossSectionalArea;
- IsVisFilter = true; // Asegurar que el componente hidráulico sea visible en filtros
- UpdateTankPressure();
-
- // Inicializar el lock para thread safety
+ // Inicializar el lock primero para thread safety
EnsureLockInitialized();
- // Debug: Confirmar que el constructor se ejecuta
- Debug.WriteLine($"osHydTank Constructor: Nombre='{Nombre}', Tamaño={Tamano}, ZIndex={zIndex_fromFrames}, IsVisFilter={IsVisFilter}, Lock_movement={Lock_movement}");
+ try
+ {
+ Nombre = "Tanque Hidráulico";
+ Tamano = 1.0f; // Usar un tamaño mayor para mayor visibilidad
+ // Inicializar dimensiones usando las propiedades de osBase
+ Ancho = 0.30f;
+ Alto = 0.40f;
+ Angulo = 0f;
+ // Asegurar que el movimiento esté habilitado
+ Lock_movement = false;
+
+ // No cargar imagen aquí - se carga en ucLoaded()
+ // para evitar problemas de serialización
+
+ // Cálculos seguros
+ SafeUpdateVolumeCalculations();
+ IsVisFilter = true; // Asegurar que el componente hidráulico sea visible en filtros
+ SafeUpdateTankPressure();
+
+ // Debug: Confirmar que el constructor se ejecuta
+ Debug.WriteLine($"osHydTank Constructor: Nombre='{Nombre}', Tamaño={Tamano}, ZIndex={zIndex_fromFrames}, IsVisFilter={IsVisFilter}, Lock_movement={Lock_movement}");
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error in osHydTank constructor: {ex.Message}");
+ // Inicializar valores por defecto mínimos
+ InitializeDefaults();
+ }
}
@@ -137,18 +144,49 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
public override void UpdateGeometryStart()
{
- // Los objetos hidráulicos se registran automáticamente
- // cuando inicia la simulación a través de las interfaces
+ // Se llama cuando inicia la simulación - crear objeto hidráulico si no existe
+ if (SimHydraulicTank == null)
+ {
+ SimHydraulicTank = hydraulicSimulationManager.AddTank(TankPressure, CurrentLevel, MaxLevel, MinLevel, CrossSectionalArea, IsFixedPressure);
+ SimHydraulicTank.SimObjectType = "HydraulicTank";
+ SimHydraulicTank.WpfObject = this;
+ SimHydraulicTank.Nombre = Nombre;
+ }
+ else
+ {
+ // Actualizar propiedades si el objeto ya existe
+ SimHydraulicTank.TankPressure = TankPressure;
+ SimHydraulicTank.CurrentLevel = CurrentLevel;
+ SimHydraulicTank.MaxLevel = MaxLevel;
+ SimHydraulicTank.MinLevel = MinLevel;
+ SimHydraulicTank.CrossSectionalArea = CrossSectionalArea;
+ SimHydraulicTank.IsFixedPressure = IsFixedPressure;
+ }
}
public override void UpdateGeometryStep()
{
// Los objetos hidráulicos actualizan sus resultados
- // a través de ApplyHydraulicResults()
+ // a través de ApplySimulationResults() desde HydraulicSimulationManager
}
public override void UpdateControl(int elapsedMilliseconds)
{
+ // Actualizar propiedades desde la simulación hidráulica
+ if (SimHydraulicTank != null)
+ {
+ InletFlow = SimHydraulicTank.InletFlow;
+ OutletFlow = SimHydraulicTank.OutletFlow;
+ CurrentPressure = SimHydraulicTank.CurrentPressure;
+
+ // Actualizar nivel del tanque basado en el balance de flujo
+ double deltaTime = elapsedMilliseconds / 1000.0; // Convertir a segundos
+ if (deltaTime > 0)
+ {
+ UpdateLevelFromFlowBalance(deltaTime);
+ }
+ }
+
// Actualizar el color según el estado del tanque
var percentage = FillPercentage;
if (percentage < 20)
@@ -191,7 +229,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
{
if (SetProperty(ref _crossSectionalArea, Math.Max(0.1, value)))
{
- UpdateVolumeCalculations();
+ SafeUpdateVolumeCalculations();
InvalidateHydraulicNetwork();
}
}
@@ -209,7 +247,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
{
if (_currentLevel > _maxLevel)
CurrentLevel = _maxLevel;
- UpdateVolumeCalculations();
+ SafeUpdateVolumeCalculations();
}
}
}
@@ -226,7 +264,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
{
if (_currentLevel < _minLevel)
CurrentLevel = _minLevel;
- UpdateVolumeCalculations();
+ SafeUpdateVolumeCalculations();
}
}
}
@@ -245,7 +283,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
{
if (SetProperty(ref _isFixedPressure, value))
{
- UpdateTankPressure();
+ SafeUpdateTankPressure();
InvalidateHydraulicNetwork();
}
}
@@ -261,7 +299,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
{
if (SetProperty(ref _tankPressure, Math.Max(0, value)))
{
- UpdateTankPressure();
+ SafeUpdateTankPressure();
InvalidateHydraulicNetwork();
}
}
@@ -296,7 +334,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
var clampedLevel = Math.Max(_minLevel, Math.Min(_maxLevel, value));
if (SetProperty(ref _currentLevel, clampedLevel))
{
- UpdateVolumeCalculations();
+ SafeUpdateVolumeCalculations();
OnPropertyChanged(nameof(FillPercentage));
}
}
@@ -442,8 +480,8 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
public void UpdateHydraulicProperties()
{
// Actualizar propiedades antes de la simulación
- UpdateTankPressure();
- UpdateVolumeCalculations();
+ SafeUpdateTankPressure();
+ SafeUpdateVolumeCalculations();
}
public void ApplyHydraulicResults(Dictionary flows, Dictionary pressures)
@@ -588,6 +626,67 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
// Private Methods
+ private void InitializeDefaults()
+ {
+ // Valores mínimos para que el objeto sea funcional
+ try
+ {
+ if (string.IsNullOrEmpty(nombre))
+ nombre = "Tanque Hidráulico";
+
+ if (Tamano <= 0)
+ Tamano = 1.0f;
+
+ if (Ancho <= 0)
+ Ancho = 0.30f;
+
+ if (Alto <= 0)
+ Alto = 0.40f;
+
+ SafeUpdateVolumeCalculations();
+ SafeUpdateTankPressure();
+
+ Debug.WriteLine("osHydTank: Initialized with default values");
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error in InitializeDefaults: {ex.Message}");
+ }
+ }
+
+ private void SafeUpdateVolumeCalculations()
+ {
+ try
+ {
+ _currentVolume = _currentLevel * _crossSectionalArea;
+ _maxVolume = _maxLevel * _crossSectionalArea;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error in SafeUpdateVolumeCalculations: {ex.Message}");
+ // Usar valores por defecto seguros
+ _currentVolume = 1.0;
+ _maxVolume = 2.0;
+ }
+ }
+
+ private void SafeUpdateTankPressure()
+ {
+ try
+ {
+ if (IsFixedPressure)
+ {
+ CurrentPressure = TankPressure;
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Error in SafeUpdateTankPressure: {ex.Message}");
+ // Usar presión atmosférica por defecto
+ _currentPressure = 101325.0;
+ }
+ }
+
private string GetTankDescription()
{
return TankType switch
@@ -751,15 +850,15 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
public void Start()
{
// Inicialización del tanque para la simulación
- UpdateVolumeCalculations();
- UpdateTankPressure();
+ SafeUpdateVolumeCalculations();
+ SafeUpdateTankPressure();
}
public void Inicializar(int valorInicial)
{
// Inicialización con valor inicial
- UpdateVolumeCalculations();
- UpdateTankPressure();
+ SafeUpdateVolumeCalculations();
+ SafeUpdateTankPressure();
}
public void Disposing()
@@ -800,9 +899,11 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
// crear el objeto de simulacion
base.ucLoaded();
+ Debug.WriteLine($"osHydTank.ucLoaded(): Componente hidráulico cargado correctamente");
+
// Inicialización específica del tanque hidráulico
- UpdateVolumeCalculations();
- UpdateTankPressure();
+ SafeUpdateVolumeCalculations();
+ SafeUpdateTankPressure();
// Debug: Confirmar que el UserControl se está cargando
Debug.WriteLine($"osHydTank.ucLoaded(): Tanque '{Nombre}' cargado - Tamaño: {Tamano}, ZIndex: {zIndex_fromFrames}");
@@ -810,7 +911,12 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
public override void ucUnLoaded()
{
- // Los tanques hidráulicos no tienen geometría que limpiar
+ // Remover objeto hidráulico de la simulación
+ if (SimHydraulicTank != null)
+ {
+ hydraulicSimulationManager.Remove(SimHydraulicTank);
+ SimHydraulicTank = null;
+ }
}
diff --git a/ObjetosSim/HydraulicComponents/ucHydPipe.xaml b/ObjetosSim/HydraulicComponents/ucHydPipe.xaml
index 728d2d8..7973eb9 100644
--- a/ObjetosSim/HydraulicComponents/ucHydPipe.xaml
+++ b/ObjetosSim/HydraulicComponents/ucHydPipe.xaml
@@ -1,10 +1,10 @@
-
diff --git a/ObjetosSim/HydraulicComponents/ucHydPipe.xaml.cs b/ObjetosSim/HydraulicComponents/ucHydPipe.xaml.cs
index 8e60b80..7f1b75b 100644
--- a/ObjetosSim/HydraulicComponents/ucHydPipe.xaml.cs
+++ b/ObjetosSim/HydraulicComponents/ucHydPipe.xaml.cs
@@ -4,7 +4,7 @@ using System.Windows;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
-namespace CtrEditor.ObjetosSim.HydraulicComponents
+namespace CtrEditor.ObjetosSim
{
///
/// Interaction logic for ucHydPipe.xaml
diff --git a/ObjetosSim/HydraulicComponents/ucHydPump.xaml b/ObjetosSim/HydraulicComponents/ucHydPump.xaml
index 74a7ed6..9d73d66 100644
--- a/ObjetosSim/HydraulicComponents/ucHydPump.xaml
+++ b/ObjetosSim/HydraulicComponents/ucHydPump.xaml
@@ -1,10 +1,10 @@
-
diff --git a/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs b/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs
index 39ef95f..fb8e761 100644
--- a/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs
+++ b/ObjetosSim/HydraulicComponents/ucHydPump.xaml.cs
@@ -6,7 +6,7 @@ using System.Windows.Media;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
-namespace CtrEditor.ObjetosSim.HydraulicComponents
+namespace CtrEditor.ObjetosSim
{
///
/// UserControl para la bomba hidráulica
diff --git a/ObjetosSim/HydraulicComponents/ucHydTank.xaml b/ObjetosSim/HydraulicComponents/ucHydTank.xaml
index 49cb02a..cbb6eec 100644
--- a/ObjetosSim/HydraulicComponents/ucHydTank.xaml
+++ b/ObjetosSim/HydraulicComponents/ucHydTank.xaml
@@ -1,10 +1,10 @@
-
diff --git a/ObjetosSim/HydraulicComponents/ucHydTank.xaml.cs b/ObjetosSim/HydraulicComponents/ucHydTank.xaml.cs
index 7e9aebf..eada20c 100644
--- a/ObjetosSim/HydraulicComponents/ucHydTank.xaml.cs
+++ b/ObjetosSim/HydraulicComponents/ucHydTank.xaml.cs
@@ -8,7 +8,7 @@ using System.Diagnostics;
using CtrEditor.ObjetosSim;
using CtrEditor.FuncionesBase;
-namespace CtrEditor.ObjetosSim.HydraulicComponents
+namespace CtrEditor.ObjetosSim
{
///
/// UserControl para el tanque hidráulico osHydTank
diff --git a/ObjetosSim/UserControlFactory.cs b/ObjetosSim/UserControlFactory.cs
index 271b6e5..4aab89e 100644
--- a/ObjetosSim/UserControlFactory.cs
+++ b/ObjetosSim/UserControlFactory.cs
@@ -1,5 +1,6 @@
using Newtonsoft.Json;
using System.Windows.Controls;
+using CtrEditor.HydraulicSimulator;
using CtrEditor.Simulacion;
using System.Reflection;
using System;
@@ -77,7 +78,7 @@ namespace CtrEditor.ObjetosSim
return instance;
}
- public static void AssignDatos(UserControl userControl, osBase datos, SimulationManagerBEPU simulationManager)
+ public static void AssignDatos(UserControl userControl, osBase datos, SimulationManagerBEPU simulationManager, HydraulicSimulationManager hydraulicSimulationManager = null)
{
if (userControl is IDataContainer dataContainer)
{
@@ -85,6 +86,7 @@ namespace CtrEditor.ObjetosSim
userControl.DataContext = datos;
datos.VisualRepresentation = userControl;
datos.simulationManager = simulationManager;
+ datos.hydraulicSimulationManager = hydraulicSimulationManager;
}
}
diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs
index ba4b314..230fee4 100644
--- a/ObjetosSim/osBase.cs
+++ b/ObjetosSim/osBase.cs
@@ -1,5 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.FuncionesBase;
+using CtrEditor.HydraulicSimulator;
using CtrEditor.Serialization;
using CtrEditor.Services;
using CtrEditor.Simulacion;
@@ -45,19 +46,22 @@ namespace CtrEditor.ObjetosSim
private MainViewModel? _mainViewModel;
private UserControl? VisualRepresentation;
private SimulationManagerBEPU? simulationManager;
+ private HydraulicSimulationManager? hydraulicSimulationManager;
- public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerBEPU c)
+ public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerBEPU c, HydraulicSimulationManager d = null)
{
_mainViewModel = a;
VisualRepresentation = b;
simulationManager = c;
+ hydraulicSimulationManager = d;
}
- public void DataRestoreAfterSerialize(out MainViewModel a, out UserControl b, out SimulationManagerBEPU c)
+ public void DataRestoreAfterSerialize(out MainViewModel a, out UserControl b, out SimulationManagerBEPU c, out HydraulicSimulationManager d)
{
a = _mainViewModel;
b = VisualRepresentation;
c = simulationManager;
+ d = hydraulicSimulationManager;
}
}
@@ -1054,16 +1058,23 @@ namespace CtrEditor.ObjetosSim
[JsonIgnore]
public SimulationManagerBEPU simulationManager;
+ ///
+ /// Link al Simulador hidráulico.
+ ///
+ [JsonIgnore]
+ public HydraulicSimulationManager hydraulicSimulationManager;
+
///
/// Prepara la clase para ser serializable poniendo a null los objetos que tienen referencias circulares
/// Luego se debe llamar a RestaurarDatosNoSerializables para restaurar el estado original
///
public void SalvarDatosNoSerializables()
{
- DataSave = new DataSaveToSerialize(_mainViewModel, _visualRepresentation, simulationManager);
+ DataSave = new DataSaveToSerialize(_mainViewModel, _visualRepresentation, simulationManager, hydraulicSimulationManager);
_mainViewModel = null;
_visualRepresentation = null;
simulationManager = null;
+ hydraulicSimulationManager = null;
}
///
@@ -1072,7 +1083,7 @@ namespace CtrEditor.ObjetosSim
public void RestaurarDatosNoSerializables()
{
if (DataSave == null) return;
- DataSave.DataRestoreAfterSerialize(out _mainViewModel, out _visualRepresentation, out simulationManager);
+ DataSave.DataRestoreAfterSerialize(out _mainViewModel, out _visualRepresentation, out simulationManager, out hydraulicSimulationManager);
}
///
/// Se llama una unica vez al conectar con el PLC.