Refactor hydraulic components: Updated osHydPipe and osHydPump to improve code clarity by changing region comments to regular comments. Enhanced osHydTank with a new OnMove method and improved initialization in ucHydTank.xaml. Updated StateSerializer to include default values during serialization.
This commit is contained in:
parent
0147e010d3
commit
8e6d457047
|
@ -193,7 +193,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ObjetosSim\HydraulicSimulator\" />
|
||||
<Folder Include="paddleocr\cls\inference\" />
|
||||
<Folder Include="paddleocr\det\inference\" />
|
||||
<Folder Include="paddleocr\keys\" />
|
||||
|
|
|
@ -0,0 +1,374 @@
|
|||
# Sistema de Componentes Hidráulicos - CtrEditor
|
||||
|
||||
## 📋 Resumen del Sistema
|
||||
|
||||
Este documento describe todos los componentes necesarios para implementar un sistema hidráulico completo en CtrEditor. El sistema está diseñado con una arquitectura modular que permite simular circuitos hidráulicos industriales complejos.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Componentes Existentes
|
||||
|
||||
### ✅ **Tanque Hidráulico** - `osHydTank`
|
||||
- **Archivo**: `osHydTank.cs` / `ucHydTank.xaml`
|
||||
- **Descripción**: Tanque hidráulico con gestión dinámica de nivel y presión configurable
|
||||
- **Tipos**: Suction, Intermediate, Storage, Process
|
||||
- **Características**:
|
||||
- Múltiples tipos de tanque via enum `HydraulicTankType`
|
||||
- Presión fija o variable (`IsFixedPressure`)
|
||||
- Gestión completa de flujos entrada/salida
|
||||
- Cálculos dinámicos de nivel y volumen
|
||||
- Propiedades visuales para UI (colores, indicadores)
|
||||
- Conexiones configurables de entrada y salida
|
||||
|
||||
### ✅ **Tubería Hidráulica** - `osHydPipe`
|
||||
- **Archivo**: `osHydPipe.cs` / `ucHydPipe.xaml`
|
||||
- **Descripción**: Tubería para transporte de fluido hidráulico
|
||||
- **Características**:
|
||||
- Cálculo de pérdidas de carga por fricción
|
||||
- Diferentes materiales y rugosidades
|
||||
- Diámetros configurables
|
||||
- Longitud variable
|
||||
- Resistencia hidráulica calculada
|
||||
|
||||
### ✅ **Bomba Hidráulica** - `osHydPump`
|
||||
- **Archivo**: `osHydPump.cs` / `ucHydPump.xaml`
|
||||
- **Descripción**: Bomba para generar presión y caudal en el sistema
|
||||
- **Tipos**: Centrifugal, Positive Displacement, Variable Displacement
|
||||
- **Características**:
|
||||
- Curvas características configurables
|
||||
- Control de velocidad variable
|
||||
- Eficiencia energética
|
||||
- Protección contra cavitación
|
||||
- Control PID integrado
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Componentes de Control (Por Implementar)
|
||||
|
||||
### **Válvulas** - `osHydValve`
|
||||
- **Archivo**: `osHydValve.cs` / `ucHydValve.xaml`
|
||||
- **Descripción**: Válvula general configurable para control de flujo
|
||||
- **Tipos**:
|
||||
- `Ball` - Válvula de bola (on/off)
|
||||
- `Gate` - Válvula de compuerta
|
||||
- `Globe` - Válvula de globo
|
||||
- `Check` - Válvula de retención
|
||||
- `Relief` - Válvula de alivio
|
||||
- `Throttle` - Válvula de estrangulación
|
||||
- **Estados**: `Open`, `Closed`, `Partial`
|
||||
- **Propiedades**:
|
||||
- Coeficiente de flujo (Cv)
|
||||
- Pérdida de presión
|
||||
- Posición del actuador
|
||||
- Tiempo de operación
|
||||
|
||||
### **Actuadores Hidráulicos** - `osHydActuator`
|
||||
- **Archivo**: `osHydActuator.cs` / `ucHydActuator.xaml`
|
||||
- **Descripción**: Cilindros y actuadores hidráulicos
|
||||
- **Tipos**:
|
||||
- `SingleAction` - Cilindro de simple efecto
|
||||
- `DoubleAction` - Cilindro de doble efecto
|
||||
- `Rotary` - Actuador rotativo
|
||||
- **Propiedades**:
|
||||
- Diámetro del pistón
|
||||
- Carrera (stroke)
|
||||
- Fuerza desarrollada
|
||||
- Velocidad de actuación
|
||||
- Posición actual
|
||||
|
||||
---
|
||||
|
||||
## 📊 Instrumentación (Por Implementar)
|
||||
|
||||
### **Sensor de Presión** - `osHydPressureSensor`
|
||||
- **Archivo**: `osHydPressureSensor.cs` / `ucHydPressureSensor.xaml`
|
||||
- **Descripción**: Medición de presión en el sistema
|
||||
- **Propiedades**:
|
||||
- Rango de medición (0-1000 bar)
|
||||
- Precisión (±0.1%)
|
||||
- Tiempo de respuesta
|
||||
- Señal de salida (4-20mA, 0-10V)
|
||||
- Calibración automática
|
||||
|
||||
### **Sensor de Caudal** - `osHydFlowSensor`
|
||||
- **Archivo**: `osHydFlowSensor.cs` / `ucHydFlowSensor.xaml`
|
||||
- **Descripción**: Medición de caudal volumétrico
|
||||
- **Tipos**: Electromagnetic, Turbine, Vortex, Ultrasonic
|
||||
- **Propiedades**:
|
||||
- Rango de caudal (L/min)
|
||||
- Pérdida de presión
|
||||
- Precisión de medición
|
||||
- Compensación de temperatura
|
||||
|
||||
### **Sensor de Nivel** - `osHydLevelSensor`
|
||||
- **Archivo**: `osHydLevelSensor.cs` / `ucHydLevelSensor.xaml`
|
||||
- **Descripción**: Medición de nivel en tanques
|
||||
- **Tipos**: Ultrasonic, Radar, Capacitive, Float
|
||||
- **Propiedades**:
|
||||
- Altura de medición
|
||||
- Zona muerta
|
||||
- Material del tanque
|
||||
- Constante dieléctrica del fluido
|
||||
|
||||
### **Sensor de Temperatura** - `osHydTemperatureSensor`
|
||||
- **Archivo**: `osHydTemperatureSensor.cs` / `ucHydTemperatureSensor.xaml`
|
||||
- **Descripción**: Medición de temperatura del fluido
|
||||
- **Tipos**: Thermocouple, RTD, Thermistor
|
||||
- **Propiedades**:
|
||||
- Rango de temperatura (-40°C a +200°C)
|
||||
- Tiempo de respuesta térmica
|
||||
- Exactitud (±0.1°C)
|
||||
- Inmersión requerida
|
||||
|
||||
---
|
||||
|
||||
## 🔀 Conexiones y Distribución (Por Implementar)
|
||||
|
||||
### **Conexión en T** - `osHydTee`
|
||||
- **Archivo**: `osHydTee.cs` / `ucHydTee.xaml`
|
||||
- **Descripción**: Conexión de tres vías para dividir flujo
|
||||
- **Propiedades**:
|
||||
- Diámetro de entrada
|
||||
- Diámetros de salida
|
||||
- Coeficiente de pérdida
|
||||
- Material de construcción
|
||||
|
||||
### **Codo 90°** - `osHydElbow`
|
||||
- **Archivo**: `osHydElbow.cs` / `ucHydElbow.xaml`
|
||||
- **Descripción**: Cambio de dirección a 90 grados
|
||||
- **Propiedades**:
|
||||
- Radio de curvatura
|
||||
- Ángulo (45°, 90°, custom)
|
||||
- Factor de pérdida K
|
||||
- Diámetro interno
|
||||
|
||||
### **Conexión Cruzada** - `osHydCross`
|
||||
- **Archivo**: `osHydCross.cs` / `ucHydCross.xaml`
|
||||
- **Descripción**: Conexión de cuatro vías
|
||||
- **Propiedades**:
|
||||
- Configuración de flujos
|
||||
- Pérdidas por turbulencia
|
||||
- Diámetros de conexión
|
||||
|
||||
### **Reductor de Diámetro** - `osHydReducer`
|
||||
- **Archivo**: `osHydReducer.cs` / `ucHydReducer.xaml`
|
||||
- **Descripción**: Cambio gradual de diámetro de tubería
|
||||
- **Tipos**: Concentric, Eccentric
|
||||
- **Propiedades**:
|
||||
- Diámetro de entrada
|
||||
- Diámetro de salida
|
||||
- Ángulo de reducción
|
||||
- Pérdida por expansión/contracción
|
||||
|
||||
### **Distribuidor Multiple** - `osHydManifold`
|
||||
- **Archivo**: `osHydManifold.cs` / `ucHydManifold.xaml`
|
||||
- **Descripción**: Distribuidor de múltiples salidas
|
||||
- **Propiedades**:
|
||||
- Número de salidas (2-12)
|
||||
- Distribución de caudal
|
||||
- Válvulas integradas opcionales
|
||||
- Presión de entrada común
|
||||
|
||||
---
|
||||
|
||||
## 🎛️ Control Avanzado (Por Implementar)
|
||||
|
||||
### **Regulador de Presión** - `osHydPressureRegulator`
|
||||
- **Archivo**: `osHydPressureRegulator.cs` / `ucHydPressureRegulator.xaml`
|
||||
- **Descripción**: Control automático de presión
|
||||
- **Propiedades**:
|
||||
- Presión de consigna (setpoint)
|
||||
- Banda proporcional
|
||||
- Control PID integrado
|
||||
- Rango de regulación
|
||||
- Precisión de control
|
||||
|
||||
### **Regulador de Caudal** - `osHydFlowRegulator`
|
||||
- **Archivo**: `osHydFlowRegulator.cs` / `ucHydFlowRegulator.xaml`
|
||||
- **Descripción**: Control automático de caudal
|
||||
- **Propiedades**:
|
||||
- Caudal de consigna
|
||||
- Compensación de presión
|
||||
- Tiempo de respuesta
|
||||
- Estabilidad de flujo
|
||||
|
||||
### **Válvula de Alivio** - `osHydPressureRelief`
|
||||
- **Archivo**: `osHydPressureRelief.cs` / `ucHydPressureRelief.xaml`
|
||||
- **Descripción**: Protección contra sobrepresión
|
||||
- **Propiedades**:
|
||||
- Presión de apertura
|
||||
- Presión de cierre
|
||||
- Capacidad de descarga
|
||||
- Tipo de pilotaje
|
||||
|
||||
---
|
||||
|
||||
## 🌡️ Gestión Térmica (Por Implementar)
|
||||
|
||||
### **Filtro Hidráulico** - `osHydFilter`
|
||||
- **Archivo**: `osHydFilter.cs` / `ucHydFilter.xaml`
|
||||
- **Descripción**: Filtración de partículas y contaminantes
|
||||
- **Tipos**:
|
||||
- `Suction` - Filtro de aspiración
|
||||
- `Return` - Filtro de retorno
|
||||
- `Pressure` - Filtro de presión
|
||||
- `Bypass` - Filtro de bypass
|
||||
- **Propiedades**:
|
||||
- Grado de filtración (micrones)
|
||||
- Capacidad de retención
|
||||
- Pérdida de presión
|
||||
- Indicador de saturación
|
||||
|
||||
### **Enfriador** - `osHydCooler`
|
||||
- **Archivo**: `osHydCooler.cs` / `ucHydCooler.xaml`
|
||||
- **Descripción**: Enfriamiento del fluido hidráulico
|
||||
- **Tipos**: Air-cooled, Water-cooled
|
||||
- **Propiedades**:
|
||||
- Capacidad de enfriamiento (kW)
|
||||
- Temperatura de entrada/salida
|
||||
- Caudal de fluido refrigerante
|
||||
- Eficiencia térmica
|
||||
|
||||
### **Calentador** - `osHydHeater`
|
||||
- **Archivo**: `osHydHeater.cs` / `ucHydHeater.xaml`
|
||||
- **Descripción**: Calentamiento del fluido hidráulico
|
||||
- **Propiedades**:
|
||||
- Potencia de calentamiento (kW)
|
||||
- Temperatura objetivo
|
||||
- Control de temperatura
|
||||
- Protección contra sobrecalentamiento
|
||||
|
||||
### **Intercambiador de Calor** - `osHydHeatExchanger`
|
||||
- **Archivo**: `osHydHeatExchanger.cs` / `ucHydHeatExchanger.xaml`
|
||||
- **Descripción**: Intercambio térmico entre fluidos
|
||||
- **Tipos**: Plate, Shell-and-tube, Coaxial
|
||||
- **Propiedades**:
|
||||
- Coeficiente de transferencia térmica
|
||||
- Área de intercambio
|
||||
- Configuración de flujos
|
||||
- Eficiencia térmica
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Componentes Especializados (Por Implementar)
|
||||
|
||||
### **Acumulador Hidráulico** - `osHydAccumulator`
|
||||
- **Archivo**: `osHydAccumulator.cs` / `ucHydAccumulator.xaml`
|
||||
- **Descripción**: Almacenamiento de energía hidráulica
|
||||
- **Tipos**:
|
||||
- `Bladder` - Membrana elastomérica
|
||||
- `Piston` - Pistón separador
|
||||
- `Diaphragm` - Diafragma metálico
|
||||
- **Propiedades**:
|
||||
- Volumen total
|
||||
- Presión de precarga
|
||||
- Volumen útil
|
||||
- Tiempo de descarga
|
||||
|
||||
### **Motor Hidráulico** - `osHydMotor`
|
||||
- **Archivo**: `osHydMotor.cs` / `ucHydMotor.xaml`
|
||||
- **Descripción**: Conversión de energía hidráulica a mecánica rotativa
|
||||
- **Tipos**:
|
||||
- `Gear` - Motor de engranajes
|
||||
- `Vane` - Motor de paletas
|
||||
- `Piston` - Motor de pistones
|
||||
- `Radial` - Motor radial
|
||||
- **Propiedades**:
|
||||
- Cilindrada (cm³/rev)
|
||||
- Velocidad nominal (rpm)
|
||||
- Par motor (Nm)
|
||||
- Eficiencia volumétrica/mecánica
|
||||
|
||||
---
|
||||
|
||||
## 📋 Plan de Implementación
|
||||
|
||||
### **Fase 1 - Componentes Básicos** ⭐⭐⭐
|
||||
1. `osHydValve` (Ball, Check, Relief)
|
||||
2. `osHydPressureSensor`
|
||||
3. `osHydFlowSensor`
|
||||
4. `osHydTee`
|
||||
|
||||
### **Fase 2 - Control Intermedio** ⭐⭐
|
||||
5. `osHydActuator`
|
||||
6. `osHydPressureRegulator`
|
||||
7. `osHydFilter`
|
||||
8. `osHydManifold`
|
||||
|
||||
### **Fase 3 - Componentes Avanzados** ⭐
|
||||
9. `osHydAccumulator`
|
||||
10. `osHydMotor`
|
||||
11. `osHydCooler`
|
||||
12. `osHydHeatExchanger`
|
||||
|
||||
### **Fase 4 - Instrumentación Completa**
|
||||
13. `osHydLevelSensor`
|
||||
14. `osHydTemperatureSensor`
|
||||
15. `osHydFlowRegulator`
|
||||
16. Componentes de conexión restantes
|
||||
|
||||
---
|
||||
|
||||
## 💡 Arquitectura de Interfaces
|
||||
|
||||
### **Interfaces Base**
|
||||
```csharp
|
||||
// Control de flujo
|
||||
public interface IHydraulicFlowController
|
||||
{
|
||||
double FlowCoefficient { get; set; }
|
||||
double PressureDrop { get; }
|
||||
ValveState CurrentState { get; set; }
|
||||
}
|
||||
|
||||
// Actuadores
|
||||
public interface IHydraulicActuator
|
||||
{
|
||||
double Force { get; }
|
||||
double Stroke { get; set; }
|
||||
double Velocity { get; }
|
||||
ActuatorType Type { get; }
|
||||
}
|
||||
|
||||
// Sensores
|
||||
public interface IHydraulicSensor
|
||||
{
|
||||
double MeasuredValue { get; }
|
||||
string Units { get; }
|
||||
bool IsCalibrated { get; set; }
|
||||
double Accuracy { get; }
|
||||
}
|
||||
|
||||
// Componentes térmicos
|
||||
public interface IHydraulicThermalComponent
|
||||
{
|
||||
double ThermalCapacity { get; }
|
||||
double HeatTransferCoefficient { get; }
|
||||
double OperatingTemperature { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Objetivos del Sistema
|
||||
|
||||
- **Modularidad**: Cada componente es independiente y reutilizable
|
||||
- **Realismo**: Cálculos basados en principios de ingeniería hidráulica
|
||||
- **Flexibilidad**: Configuración adaptable a diferentes aplicaciones
|
||||
- **Integración**: Compatible con el sistema de simulación existente
|
||||
- **Escalabilidad**: Fácil adición de nuevos componentes
|
||||
- **Documentación**: Cada componente bien documentado y ejemplificado
|
||||
|
||||
---
|
||||
|
||||
## 📚 Referencias Técnicas
|
||||
|
||||
- ISO 1219-1: Símbolos gráficos para esquemas de circuitos hidráulicos
|
||||
- ISO 4413: Transmisiones hidráulicas - Reglas generales y requisitos de seguridad
|
||||
- NFPA T3.5.17: Hidráulica industrial - Estándares de filtración
|
||||
- API 610: Bombas centrífugas para servicios de refinería petroquímica
|
||||
|
||||
---
|
||||
|
||||
*Documento generado automáticamente - CtrEditor v2024*
|
||||
*Última actualización: Septiembre 2025*
|
|
@ -1,43 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using CtrEditor.ObjetosSim.HydraulicComponents;
|
||||
|
||||
namespace CtrEditor.Test
|
||||
{
|
||||
class FilterDebugTest
|
||||
{
|
||||
static void TestHydraulicComponentDetection()
|
||||
{
|
||||
// Test hydraulic component detection logic like in osVisFilter
|
||||
var tankType = typeof(osHydTank);
|
||||
var pipeType = typeof(osHydPipe);
|
||||
|
||||
Console.WriteLine("=== Tank Type Analysis ===");
|
||||
Console.WriteLine($"Tank Type: {tankType.FullName}");
|
||||
Console.WriteLine($"Tank Namespace: {tankType.Namespace}");
|
||||
Console.WriteLine($"Has HydraulicComponents in namespace: {tankType.Namespace?.Contains("HydraulicComponents")}");
|
||||
Console.WriteLine($"Tank Interfaces: {string.Join(", ", tankType.GetInterfaces().Select(i => i.Name))}");
|
||||
Console.WriteLine($"Has Hydraulic interface: {tankType.GetInterfaces().Any(i => i.Name.Contains("Hydraulic"))}");
|
||||
|
||||
Console.WriteLine("\n=== Pipe Type Analysis ===");
|
||||
Console.WriteLine($"Pipe Type: {pipeType.FullName}");
|
||||
Console.WriteLine($"Pipe Namespace: {pipeType.Namespace}");
|
||||
Console.WriteLine($"Has HydraulicComponents in namespace: {pipeType.Namespace?.Contains("HydraulicComponents")}");
|
||||
Console.WriteLine($"Pipe Interfaces: {string.Join(", ", pipeType.GetInterfaces().Select(i => i.Name))}");
|
||||
Console.WriteLine($"Has Hydraulic interface: {pipeType.GetInterfaces().Any(i => i.Name.Contains("Hydraulic"))}");
|
||||
|
||||
// Test the exact logic from IsHydraulicComponentType
|
||||
Console.WriteLine("\n=== IsHydraulicComponentType Logic Test ===");
|
||||
bool tankIsHydraulic = tankType.Namespace != null &&
|
||||
(tankType.Namespace.Contains("HydraulicComponents") ||
|
||||
tankType.GetInterfaces().Any(i => i.Name.Contains("Hydraulic")));
|
||||
|
||||
bool pipeIsHydraulic = pipeType.Namespace != null &&
|
||||
(pipeType.Namespace.Contains("HydraulicComponents") ||
|
||||
pipeType.GetInterfaces().Any(i => i.Name.Contains("Hydraulic")));
|
||||
|
||||
Console.WriteLine($"Tank IsHydraulicComponentType: {tankIsHydraulic}");
|
||||
Console.WriteLine($"Pipe IsHydraulicComponentType: {pipeIsHydraulic}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using HydraulicSimulator.Models;
|
||||
using CtrEditor.HydraulicSimulator;
|
||||
using CtrEditor.ObjetosSim.HydraulicComponents;
|
||||
|
||||
namespace CtrEditor.HydraulicSimulator.Examples
|
||||
{
|
||||
/// <summary>
|
||||
/// Ejemplo de uso de los componentes hidráulicos según la documentación
|
||||
/// Muestra cómo crear una red simple: Bomba -> Tubería -> Tanque de Descarga
|
||||
/// </summary>
|
||||
public class SimpleHydraulicSystemExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Crea un sistema hidráulico simple con bomba, tubería y tanque
|
||||
/// </summary>
|
||||
public static void RunExample()
|
||||
{
|
||||
Console.WriteLine("🚀 Iniciando ejemplo de sistema hidráulico simple");
|
||||
Console.WriteLine("Sistema: Bomba -> Tubería -> Tanque de Descarga");
|
||||
Console.WriteLine();
|
||||
|
||||
// 1. Crear la red hidráulica
|
||||
var network = new HydraulicNetwork();
|
||||
|
||||
// 2. Agregar nodos según la documentación
|
||||
network.AddNode("SUMINISTRO", 0); // Tanque de suministro a presión atmosférica
|
||||
network.AddNode("BOMBA_OUT"); // Salida de bomba (presión calculada)
|
||||
network.AddNode("TANQUE_DESCARGA", 0); // Tanque de descarga libre
|
||||
|
||||
// 3. Crear elementos hidráulicos
|
||||
var pump = new PumpHQ(
|
||||
h0: 80, // Cabeza a caudal cero: 80 metros
|
||||
q0: 0.01, // Caudal a cabeza cero: 0.01 m³/s (36 m³/h)
|
||||
speedRel: 1.0, // Velocidad nominal
|
||||
direction: 1 // Dirección normal
|
||||
);
|
||||
|
||||
var pipe = new Pipe(
|
||||
length: 50, // 50 metros de longitud
|
||||
diameter: 0.08, // 80mm de diámetro
|
||||
roughness: 0.0015 // Rugosidad del acero comercial
|
||||
);
|
||||
|
||||
// 4. Conectar elementos en ramas según la documentación
|
||||
network.AddBranch("SUMINISTRO", "BOMBA_OUT",
|
||||
new List<Element> { pump }, "Bomba_Principal");
|
||||
|
||||
network.AddBranch("BOMBA_OUT", "TANQUE_DESCARGA",
|
||||
new List<Element> { pipe }, "Tuberia_Descarga");
|
||||
|
||||
// 5. Resolver la red
|
||||
Console.WriteLine("⚙️ Resolviendo red hidráulica...");
|
||||
var result = network.Solve(
|
||||
maxIterations: 200,
|
||||
tolerance: 1e-4,
|
||||
verbose: true
|
||||
);
|
||||
|
||||
// 6. Mostrar resultados
|
||||
if (result.Converged)
|
||||
{
|
||||
Console.WriteLine("✅ Simulación exitosa!");
|
||||
Console.WriteLine($"Convergió en {result.Iterations} iteraciones");
|
||||
Console.WriteLine();
|
||||
|
||||
ShowResults(result);
|
||||
ShowComponentAnalysis(result, pump, pipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"❌ No convergió después de {result.Iterations} iteraciones");
|
||||
Console.WriteLine($"Error final: {result.Residual:E6}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ShowResults(SolutionResult result)
|
||||
{
|
||||
Console.WriteLine("📊 RESULTADOS DE LA SIMULACIÓN:");
|
||||
Console.WriteLine("═══════════════════════════════");
|
||||
|
||||
// Flujos
|
||||
Console.WriteLine("🌊 Flujos:");
|
||||
foreach (var flow in result.Flows)
|
||||
{
|
||||
double flowM3h = flow.Value * 3600; // Convertir a m³/h
|
||||
double flowLmin = flow.Value * 60000; // Convertir a L/min
|
||||
Console.WriteLine($" {flow.Key}:");
|
||||
Console.WriteLine($" {flow.Value:F6} m³/s = {flowM3h:F2} m³/h = {flowLmin:F1} L/min");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
// Presiones
|
||||
Console.WriteLine("📈 Presiones:");
|
||||
foreach (var pressure in result.Pressures)
|
||||
{
|
||||
double pressureBar = pressure.Value / 100000.0; // Convertir a bar
|
||||
double pressureKPa = pressure.Value / 1000.0; // Convertir a kPa
|
||||
Console.WriteLine($" {pressure.Key}:");
|
||||
Console.WriteLine($" {pressure.Value:F0} Pa = {pressureKPa:F1} kPa = {pressureBar:F3} bar");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ShowComponentAnalysis(SolutionResult result, PumpHQ pump, Pipe pipe)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("🔧 ANÁLISIS DE COMPONENTES:");
|
||||
Console.WriteLine("═══════════════════════════");
|
||||
|
||||
// Análisis de la bomba
|
||||
if (result.Flows.TryGetValue("Bomba_Principal", out double pumpFlow))
|
||||
{
|
||||
double pumpFlowM3h = pumpFlow * 3600;
|
||||
double pumpHead = pump.Dp(pumpFlow, Fluid.Water20C) / (1000 * 9.81); // Convertir Pa a metros
|
||||
double pumpPower = pumpFlow * pump.Dp(pumpFlow, Fluid.Water20C) / 1000; // Potencia hidráulica en kW
|
||||
|
||||
Console.WriteLine("💨 Bomba:");
|
||||
Console.WriteLine($" Caudal: {pumpFlowM3h:F1} m³/h");
|
||||
Console.WriteLine($" Cabeza: {pumpHead:F1} m");
|
||||
Console.WriteLine($" Potencia hidráulica: {pumpPower:F2} kW");
|
||||
}
|
||||
|
||||
// Análisis de la tubería
|
||||
if (result.Flows.TryGetValue("Tuberia_Descarga", out double pipeFlow))
|
||||
{
|
||||
double pipePressureDrop = pipe.Dp(pipeFlow, Fluid.Water20C);
|
||||
double pipeHeadLoss = pipePressureDrop / (1000 * 9.81); // Convertir Pa a metros
|
||||
double velocity = Math.Abs(pipeFlow) / (Math.PI * (pipe.D * pipe.D) / 4.0);
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("🚰 Tubería:");
|
||||
Console.WriteLine($" Caudal: {pipeFlow * 3600:F1} m³/h");
|
||||
Console.WriteLine($" Velocidad: {velocity:F2} m/s");
|
||||
Console.WriteLine($" Pérdida de carga: {pipeHeadLoss:F2} m");
|
||||
Console.WriteLine($" Pérdida de presión: {pipePressureDrop / 1000:F1} kPa");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ejemplo de cómo los objetos gráficos osHyd* se integrarían en la simulación
|
||||
/// </summary>
|
||||
public static void ShowGraphicObjectsIntegration()
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("🎨 INTEGRACIÓN CON OBJETOS GRÁFICOS:");
|
||||
Console.WriteLine("═══════════════════════════════════");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Los objetos creados (osHydPump, osHydPipe, osHydDischargeTank)");
|
||||
Console.WriteLine("se integran automáticamente en el sistema de la siguiente manera:");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("1. 📋 Registro automático:");
|
||||
Console.WriteLine(" - Se registran por reflexión usando NombreCategoria() = \"Hidráulicos\"");
|
||||
Console.WriteLine(" - Aparecen en la categoría \"Hidráulicos\" del editor");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("2. 🔗 Sistema de conexiones:");
|
||||
Console.WriteLine(" - Usan ItemsSource<IHydraulicComponent> para filtrar componentes");
|
||||
Console.WriteLine(" - Similar al sistema Motor/Transporte existente");
|
||||
Console.WriteLine(" - Conexiones: Id_InletComponent, Id_OutletComponent");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("3. 🚫 No participan en Bepu:");
|
||||
Console.WriteLine(" - Override Start() sin crear geometrías Bepu");
|
||||
Console.WriteLine(" - Solo participan en el simulador hidráulico");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("4. 📊 Integración con HydraulicSimulationManager:");
|
||||
Console.WriteLine(" - Implementan IHydraulicComponent para GetHydraulicNodes()");
|
||||
Console.WriteLine(" - Implementan GetHydraulicElements() para el solver");
|
||||
Console.WriteLine(" - Reciben resultados via ApplyHydraulicResults()");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("5. 🎯 Ejemplo de configuración:");
|
||||
Console.WriteLine(" osHydPump (Nombre=\"Bomba_01\", H0=80m, Q0=36m³/h)");
|
||||
Console.WriteLine(" ↓ (Id_OutletComponent=\"Tuberia_01\")");
|
||||
Console.WriteLine(" osHydPipe (Nombre=\"Tuberia_01\", L=50m, D=80mm)");
|
||||
Console.WriteLine(" ↓ (Id_OutletComponent=\"Tanque_01\")");
|
||||
Console.WriteLine(" osHydDischargeTank (Nombre=\"Tanque_01\", Area=1m²)");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,408 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
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;
|
||||
using LibS7Adv;
|
||||
|
||||
namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Tanque de descarga hidráulico con cálculo de nivel dinámico
|
||||
/// </summary>
|
||||
public partial class osHydDischargeTank : osBase, IHydraulicTank, IosBase
|
||||
{
|
||||
#region Properties
|
||||
|
||||
private double _area = 1.0; // m²
|
||||
private double _currentVolume = 0.5; // m³
|
||||
private double _maxVolume = 2.0; // m³
|
||||
private double _minVolume = 0.0; // m³
|
||||
private double _currentHeight = 0.0;
|
||||
private double _currentPressure = 0.0;
|
||||
|
||||
// Propiedades visuales
|
||||
[ObservableProperty]
|
||||
[property: Category("🎨 Apariencia")]
|
||||
[property: Description("Ancho visual del tanque en metros")]
|
||||
[property: Name("Ancho")]
|
||||
private float ancho = 0.5f;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Category("🎨 Apariencia")]
|
||||
[property: Description("Alto visual del tanque en metros")]
|
||||
[property: Name("Alto")]
|
||||
private float alto = 0.8f;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Category("🎨 Apariencia")]
|
||||
[property: Description("Color visual del tanque")]
|
||||
[property: Name("Color")]
|
||||
private Brush colorButton_oculto = Brushes.LightBlue;
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Category("🎨 Apariencia")]
|
||||
[property: Description("Ángulo de rotación del tanque en grados")]
|
||||
[property: Name("Ángulo")]
|
||||
private float angulo = 0f;
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Área de la base del tanque en m² (alias para compatibilidad)")]
|
||||
[Name("Área Base (m²)")]
|
||||
public double Area
|
||||
{
|
||||
get => _area;
|
||||
set => SetProperty(ref _area, Math.Max(0.1, value));
|
||||
}
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Presión del tanque en Pa")]
|
||||
[Name("Presión Tanque (Pa)")]
|
||||
public double TankPressure
|
||||
{
|
||||
get => _currentPressure;
|
||||
set => SetProperty(ref _currentPressure, value);
|
||||
}
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Nivel actual del tanque en metros")]
|
||||
[Name("Nivel (m)")]
|
||||
public double Level
|
||||
{
|
||||
get => _currentHeight;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _currentHeight, value);
|
||||
CurrentVolume = value * Area;
|
||||
}
|
||||
}
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Área de la sección transversal del tanque en m²")]
|
||||
[Name("Área Sección (m²)")]
|
||||
public double CrossSectionalArea
|
||||
{
|
||||
get => _area;
|
||||
set => SetProperty(ref _area, Math.Max(0.1, value));
|
||||
}
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Indica si el tanque tiene presión fija")]
|
||||
[Name("Presión Fija")]
|
||||
[ReadOnly(true)]
|
||||
public bool IsFixedPressure => false; // Los tanques de descarga tienen presión calculada
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Volumen actual del tanque en m³")]
|
||||
[Name("Volumen Actual (m³)")]
|
||||
public double CurrentVolume
|
||||
{
|
||||
get => _currentVolume;
|
||||
set => SetProperty(ref _currentVolume, Math.Max(MinVolume, Math.Min(MaxVolume, value)));
|
||||
}
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Volumen máximo del tanque en m³")]
|
||||
[Name("Volumen Máximo (m³)")]
|
||||
public double MaxVolume
|
||||
{
|
||||
get => _maxVolume;
|
||||
set => SetProperty(ref _maxVolume, Math.Max(CurrentVolume, value));
|
||||
}
|
||||
|
||||
[Category("🔧 Tanque Hidráulico")]
|
||||
[Description("Volumen mínimo del tanque en m³")]
|
||||
[Name("Volumen Mínimo (m³)")]
|
||||
public double MinVolume
|
||||
{
|
||||
get => _minVolume;
|
||||
set => SetProperty(ref _minVolume, Math.Max(0.0, Math.Min(CurrentVolume, value)));
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Category("🔗 Conexiones")]
|
||||
[property: Description("Componente conectado en la entrada")]
|
||||
[property: Name("Componente Entrada")]
|
||||
[property: ItemsSource(typeof(osBaseItemsSource<IHydraulicComponent>))]
|
||||
private string id_InletComponent = "";
|
||||
|
||||
[Category("📊 Estado")]
|
||||
[Description("Altura actual del líquido en metros")]
|
||||
[Name("Altura Actual (m)")]
|
||||
[ReadOnly(true)]
|
||||
public double CurrentHeight
|
||||
{
|
||||
get => _currentHeight;
|
||||
set => SetProperty(ref _currentHeight, value);
|
||||
}
|
||||
|
||||
[Category("📊 Estado")]
|
||||
[Description("Presión hidrostática en el fondo del tanque en Pa")]
|
||||
[Name("Presión Fondo (Pa)")]
|
||||
[ReadOnly(true)]
|
||||
public double CurrentPressure
|
||||
{
|
||||
get => _currentPressure;
|
||||
set => SetProperty(ref _currentPressure, value);
|
||||
}
|
||||
|
||||
[Category("📊 Estado")]
|
||||
[Description("Porcentaje de llenado del tanque")]
|
||||
[Name("Nivel (%)")]
|
||||
[ReadOnly(true)]
|
||||
public double FillPercentage => MaxVolume > 0 ? (CurrentVolume / MaxVolume) * 100.0 : 0.0;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Component References
|
||||
|
||||
[JsonIgnore]
|
||||
private IHydraulicComponent InletComponent = null;
|
||||
|
||||
[JsonIgnore]
|
||||
private PropertyChangedEventHandler inletPropertyChangedHandler;
|
||||
|
||||
[JsonIgnore]
|
||||
public Action<float, float> ActualizarTamaño { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHydraulicComponent Implementation
|
||||
|
||||
public bool HasHydraulicComponents => true;
|
||||
|
||||
public List<HydraulicNodeDefinition> GetHydraulicNodes()
|
||||
{
|
||||
var nodes = new List<HydraulicNodeDefinition>();
|
||||
|
||||
// El tanque de descarga debe ser un nodo de presión fija para servir como referencia del sistema
|
||||
// Presión = presión atmosférica + presión hidrostática
|
||||
double pressureReference = 101325.0 + TankPressure; // Pa (1 atm + presión hidrostática)
|
||||
nodes.Add(new HydraulicNodeDefinition(Nombre, true, pressureReference, "Tanque de descarga (referencia)"));
|
||||
|
||||
Debug.WriteLine($"Tanque {Nombre}: Nodo de presión fija creado - {pressureReference:F0} Pa ({pressureReference/100000:F2} bar)");
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public List<HydraulicElementDefinition> GetHydraulicElements()
|
||||
{
|
||||
// Los tanques no son elementos, son nodos
|
||||
return new List<HydraulicElementDefinition>();
|
||||
}
|
||||
|
||||
public void UpdateHydraulicProperties()
|
||||
{
|
||||
// Actualizar presión basada en el nivel actual
|
||||
UpdateHeightAndPressure();
|
||||
}
|
||||
|
||||
public void ApplyHydraulicResults(Dictionary<string, double> flows, Dictionary<string, double> pressures)
|
||||
{
|
||||
// Actualizar presión del tanque
|
||||
if (pressures.TryGetValue(Nombre, out double pressure))
|
||||
{
|
||||
TankPressure = pressure;
|
||||
// Calcular nivel basado en la presión hidrostática
|
||||
Level = pressure / (1000.0 * 9.81); // Asumiendo densidad del agua
|
||||
}
|
||||
|
||||
// Calcular flujo neto hacia el tanque
|
||||
double netFlow = 0.0;
|
||||
foreach (var flow in flows)
|
||||
{
|
||||
if (flow.Key.EndsWith($"->{Nombre}"))
|
||||
netFlow += flow.Value; // Flujo entrante
|
||||
else if (flow.Key.StartsWith($"{Nombre}->"))
|
||||
netFlow -= flow.Value; // Flujo saliente
|
||||
}
|
||||
|
||||
// Aquí podrías actualizar el volumen en función del tiempo
|
||||
// Esto se haría en el update loop principal de la simulación
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHydraulicPressureReceiver Implementation
|
||||
|
||||
public void SetPressure(double pressure)
|
||||
{
|
||||
TankPressure = pressure;
|
||||
// Actualizar nivel basado en presión hidrostática
|
||||
Level = pressure / (1000.0 * 9.81);
|
||||
}
|
||||
|
||||
public double GetPressure()
|
||||
{
|
||||
return TankPressure;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Connection Management
|
||||
|
||||
partial void OnId_InletComponentChanged(string value)
|
||||
{
|
||||
if (InletComponent != null && inletPropertyChangedHandler != null)
|
||||
((INotifyPropertyChanged)InletComponent).PropertyChanged -= inletPropertyChangedHandler;
|
||||
|
||||
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
|
||||
{
|
||||
InletComponent = (IHydraulicComponent)_mainViewModel.ObjetosSimulables
|
||||
.FirstOrDefault(s => s is IHydraulicComponent comp &&
|
||||
((osBase)comp).Nombre == value);
|
||||
|
||||
if (InletComponent != null)
|
||||
{
|
||||
inletPropertyChangedHandler = (sender, e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(osBase.Nombre))
|
||||
{
|
||||
Id_InletComponent = ((osBase)sender).Nombre;
|
||||
}
|
||||
};
|
||||
((INotifyPropertyChanged)InletComponent).PropertyChanged += inletPropertyChangedHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Volume and Level Calculations
|
||||
|
||||
private void UpdateHeightAndPressure()
|
||||
{
|
||||
Level = Area > 0 ? CurrentVolume / Area : 0.0;
|
||||
// Presión hidrostática en el fondo del tanque (densidad del agua = 1000 kg/m³)
|
||||
TankPressure = 1000.0 * 9.81 * Level;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actualiza el volumen del tanque basado en flujos netos según la documentación
|
||||
/// </summary>
|
||||
/// <param name="flows">Diccionario de flujos de la simulación</param>
|
||||
/// <param name="deltaTime">Intervalo de tiempo en segundos</param>
|
||||
public void UpdateVolume(Dictionary<string, double> flows, double deltaTime)
|
||||
{
|
||||
double netFlow = 0.0;
|
||||
|
||||
// Sumar flujos entrantes, restar salientes
|
||||
foreach (var flow in flows)
|
||||
{
|
||||
if (flow.Key.EndsWith($"->{Nombre}"))
|
||||
netFlow += flow.Value; // Entrante
|
||||
else if (flow.Key.StartsWith($"{Nombre}->"))
|
||||
netFlow -= flow.Value; // Saliente
|
||||
}
|
||||
|
||||
// Actualizar volumen
|
||||
CurrentVolume += netFlow * deltaTime;
|
||||
CurrentVolume = Math.Max(MinVolume, Math.Min(MaxVolume, CurrentVolume));
|
||||
|
||||
// Actualizar altura y presión
|
||||
UpdateHeightAndPressure();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcula la presión en el fondo del tanque según la documentación
|
||||
/// </summary>
|
||||
/// <param name="density">Densidad del fluido (kg/m³)</param>
|
||||
/// <returns>Presión hidrostática en Pa</returns>
|
||||
public double BottomPressure(double density = 1000.0)
|
||||
{
|
||||
return density * 9.81 * Level; // ρgh
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region osBase Implementation
|
||||
|
||||
public static string NombreCategoria() => "Componentes Hidráulicos";
|
||||
|
||||
public static string NombreClase() => "Tanque de Descarga";
|
||||
|
||||
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 AltoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void AnchoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
// Los tanques no participan en la simulación física Bepu
|
||||
// Solo en el sistema hidráulico
|
||||
UpdateHeightAndPressure();
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
// Los tanques pueden tener sensores de nivel
|
||||
// Implementar aquí si es necesario
|
||||
}
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Actualizar geometría visual
|
||||
if (this.ActualizarTamaño != null)
|
||||
this.ActualizarTamaño(Ancho, Alto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error actualizando geometría: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Inicializar(int valorInicial)
|
||||
{
|
||||
UpdateHeightAndPressure();
|
||||
OnId_InletComponentChanged(Id_InletComponent);
|
||||
}
|
||||
|
||||
public void Disposing()
|
||||
{
|
||||
if (InletComponent != null && inletPropertyChangedHandler != null)
|
||||
((INotifyPropertyChanged)InletComponent).PropertyChanged -= inletPropertyChangedHandler;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public osHydDischargeTank()
|
||||
{
|
||||
UpdateHeightAndPressure();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
/// </summary>
|
||||
public partial class osHydPipe : osBase, IHydraulicPipe, IosBase
|
||||
{
|
||||
#region Properties
|
||||
// Properties
|
||||
|
||||
private double _length = 1.0; // metros
|
||||
private double _diameter = 0.05; // metros (50mm)
|
||||
|
@ -120,9 +120,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
set => SetProperty(ref pipeId, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Component References
|
||||
// Component References
|
||||
|
||||
[JsonIgnore]
|
||||
private IHydraulicComponent ComponenteA = null;
|
||||
|
@ -139,15 +139,15 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
[JsonIgnore]
|
||||
public Action<float, float> ActualizarTamaño { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IHydraulicPipe Implementation
|
||||
// IHydraulicPipe Implementation
|
||||
|
||||
// Ya implementadas las propiedades Length, Diameter, Roughness arriba
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IHydraulicComponent Implementation
|
||||
// IHydraulicComponent Implementation
|
||||
|
||||
public bool HasHydraulicComponents => true;
|
||||
|
||||
|
@ -277,9 +277,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IHydraulicFlowReceiver Implementation
|
||||
// IHydraulicFlowReceiver Implementation
|
||||
|
||||
public void SetFlow(double flow)
|
||||
{
|
||||
|
@ -291,9 +291,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
return CurrentFlow;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IHydraulicPressureReceiver Implementation
|
||||
// IHydraulicPressureReceiver Implementation
|
||||
|
||||
public void SetPressure(double pressure)
|
||||
{
|
||||
|
@ -305,9 +305,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
return PressureDrop;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Connection Management
|
||||
// Connection Management
|
||||
|
||||
partial void OnId_ComponenteAChanged(string value)
|
||||
{
|
||||
|
@ -359,9 +359,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region osBase Implementation
|
||||
// osBase Implementation
|
||||
|
||||
public static string NombreCategoria() => "Componentes Hidráulicos";
|
||||
|
||||
|
@ -434,9 +434,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
((INotifyPropertyChanged)ComponenteB).PropertyChanged -= componenteBPropertyChangedHandler;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructor
|
||||
// Constructor
|
||||
|
||||
public osHydPipe()
|
||||
{
|
||||
|
@ -444,6 +444,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
IsVisFilter = true; // Asegurar que el componente hidráulico sea visible en filtros
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
return "Bomba Hidráulica";
|
||||
}
|
||||
|
||||
#region Properties
|
||||
// Properties
|
||||
|
||||
[ObservableProperty]
|
||||
[property: JsonIgnore]
|
||||
|
@ -176,9 +176,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
[JsonIgnore]
|
||||
public double CurrentFlowLMin => CurrentFlow * 60000.0; // m³/s a L/min
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor y Métodos Base
|
||||
|
||||
// Constructor y Métodos Base
|
||||
|
||||
private string nombre = NombreClase();
|
||||
|
||||
|
@ -201,9 +201,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
Angulo = 0f;
|
||||
// Asegurar que el movimiento esté habilitado
|
||||
Lock_movement = false;
|
||||
// Inicializar posición por defecto
|
||||
Left = 0.0f;
|
||||
Top = 0.0f;
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/pump_stop.png");
|
||||
}
|
||||
|
||||
|
@ -240,9 +237,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
// Los objetos hidráulicos no tienen geometría que limpiar
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHydraulicComponent Implementation
|
||||
|
||||
// IHydraulicComponent Implementation
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasHydraulicComponents => true;
|
||||
|
@ -343,9 +340,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
OnPropertyChanged(nameof(CurrentPressureBar));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHydraulicFlowReceiver Implementation
|
||||
|
||||
// IHydraulicFlowReceiver Implementation
|
||||
|
||||
public void SetFlow(double flow)
|
||||
{
|
||||
|
@ -357,9 +354,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
return CurrentFlow;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHydraulicPressureReceiver Implementation
|
||||
|
||||
// IHydraulicPressureReceiver Implementation
|
||||
|
||||
public void SetPressure(double pressure)
|
||||
{
|
||||
|
@ -371,9 +368,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
return CurrentPressure;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
// Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// Invalida la red hidráulica para forzar reconstrucción
|
||||
|
@ -387,7 +384,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -41,7 +41,8 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
private string _connectedInletPipe = "";
|
||||
private string _connectedOutletPipe = "";
|
||||
private double _lastUpdateTime = 0.0;
|
||||
private readonly object _levelLock = new object();
|
||||
[JsonIgnore]
|
||||
private object _levelLock = new object();
|
||||
private PropertyChangedEventHandler? inletPropertyChangedHandler;
|
||||
private PropertyChangedEventHandler? outletPropertyChangedHandler;
|
||||
|
||||
|
@ -95,13 +96,15 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
Angulo = 0f;
|
||||
// Asegurar que el movimiento esté habilitado
|
||||
Lock_movement = false;
|
||||
// Inicializar posición por defecto
|
||||
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
|
||||
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}");
|
||||
}
|
||||
|
@ -120,6 +123,13 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
public override void OnMove(float LeftPixels, float TopPixels)
|
||||
{
|
||||
// Método básico de movimiento como otros objetos
|
||||
// Debug para verificar que se llama
|
||||
Debug.WriteLine($"osHydTank.OnMove: LeftPixels={LeftPixels}, TopPixels={TopPixels}, Left={Left}, Top={Top}");
|
||||
}
|
||||
|
||||
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||
{
|
||||
Tamano += Delta_Width + Delta_Height;
|
||||
|
@ -280,6 +290,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
get => _currentLevel;
|
||||
private set
|
||||
{
|
||||
EnsureLockInitialized();
|
||||
lock (_levelLock)
|
||||
{
|
||||
var clampedLevel = Math.Max(_minLevel, Math.Min(_maxLevel, value));
|
||||
|
@ -768,11 +779,28 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
|||
|
||||
|
||||
|
||||
// Serialization Support
|
||||
|
||||
/// <summary>
|
||||
/// Se llama antes de la serialización para asegurar que el lock esté disponible
|
||||
/// </summary>
|
||||
private void EnsureLockInitialized()
|
||||
{
|
||||
if (_levelLock == null)
|
||||
_levelLock = new object();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// osBase Overrides
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// Inicialización cuando se carga el UserControl
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
base.ucLoaded();
|
||||
|
||||
// Inicialización específica del tanque hidráulico
|
||||
UpdateVolumeCalculations();
|
||||
UpdateTankPressure();
|
||||
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.HydraulicComponents.ucHydDischargeTank"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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:vm="clr-namespace:CtrEditor.ObjetosSim.HydraulicComponents"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osHydDischargeTank Ancho="0.5" Alto="0.8"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Canvas RenderTransformOrigin="0,0">
|
||||
<Canvas.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform />
|
||||
<SkewTransform />
|
||||
<RotateTransform Angle="{Binding Angulo}" />
|
||||
<TranslateTransform />
|
||||
</TransformGroup>
|
||||
</Canvas.RenderTransform>
|
||||
|
||||
<!-- Cuerpo del tanque -->
|
||||
<Rectangle x:Name="rectTank"
|
||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Fill="{Binding ColorButton_oculto}"
|
||||
Stroke="Black"
|
||||
StrokeThickness="2"
|
||||
RadiusX="5"
|
||||
RadiusY="5"/>
|
||||
|
||||
<!-- Nivel del líquido con altura proporcional al nivel -->
|
||||
<Rectangle x:Name="rectLevel"
|
||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=6}"
|
||||
Canvas.Left="3"
|
||||
Canvas.Bottom="3">
|
||||
<Rectangle.Height>
|
||||
<MultiBinding Converter="{StaticResource LevelToHeightMultiConverter}">
|
||||
<Binding Path="FillPercentage" />
|
||||
<Binding Path="Alto" Converter="{StaticResource MeterToPixelConverter}" />
|
||||
</MultiBinding>
|
||||
</Rectangle.Height>
|
||||
<Rectangle.Fill>Blue</Rectangle.Fill>
|
||||
<Rectangle.Opacity>0.6</Rectangle.Opacity>
|
||||
</Rectangle>
|
||||
|
||||
<!-- Etiqueta con Viewbox para escalado -->
|
||||
<Viewbox Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="20"
|
||||
Stretch="Uniform"
|
||||
Canvas.Top="2">
|
||||
<Label Content="{Binding Nombre}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
FontWeight="Bold"
|
||||
FontSize="14"
|
||||
Opacity="0.9"
|
||||
Foreground="White"/>
|
||||
</Viewbox>
|
||||
|
||||
<!-- Indicador de conexión entrada -->
|
||||
<Ellipse x:Name="ConnectionIn"
|
||||
Fill="Green"
|
||||
Width="8"
|
||||
Height="8"
|
||||
Canvas.Left="-4"
|
||||
Canvas.Bottom="10"/>
|
||||
|
||||
<!-- Indicador de nivel en porcentaje -->
|
||||
<Border x:Name="LevelIndicator"
|
||||
Background="White"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1"
|
||||
CornerRadius="2"
|
||||
Canvas.Right="2"
|
||||
Canvas.Top="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.5}">
|
||||
<TextBlock x:Name="LevelText"
|
||||
Text="{Binding FillPercentage, StringFormat='{}{0:F0}%'}"
|
||||
FontSize="6"
|
||||
Foreground="Black"
|
||||
Margin="2"/>
|
||||
</Border>
|
||||
|
||||
<!-- Indicador de volumen -->
|
||||
<Border x:Name="VolumeIndicator"
|
||||
Background="Yellow"
|
||||
CornerRadius="2"
|
||||
Visibility="Collapsed"
|
||||
Canvas.Bottom="2"
|
||||
Canvas.Left="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.5}">
|
||||
<TextBlock x:Name="VolumeText"
|
||||
Text="{Binding CurrentVolume, StringFormat='{}{0:F1}m³'}"
|
||||
FontSize="5"
|
||||
Foreground="Black"
|
||||
Margin="1"/>
|
||||
</Border>
|
||||
|
||||
</Canvas>
|
||||
</UserControl>
|
|
@ -1,70 +0,0 @@
|
|||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
using CtrEditor.ObjetosSim;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucHydDischargeTank.xaml
|
||||
/// </summary>
|
||||
public partial class ucHydDischargeTank : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; } = 0;
|
||||
|
||||
private bool _isHighlighted = false;
|
||||
|
||||
public ucHydDischargeTank()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += OnLoaded;
|
||||
this.Unloaded += OnUnloaded;
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucLoaded();
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucUnLoaded();
|
||||
}
|
||||
|
||||
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (DataContext is osHydDischargeTank tank)
|
||||
{
|
||||
Datos = tank;
|
||||
}
|
||||
}
|
||||
|
||||
#region IDataContainer Implementation
|
||||
|
||||
public void Highlight(bool state)
|
||||
{
|
||||
_isHighlighted = state;
|
||||
|
||||
if (state)
|
||||
{
|
||||
rectTank.Stroke = new SolidColorBrush(Colors.Yellow);
|
||||
rectTank.StrokeThickness = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
rectTank.Stroke = new SolidColorBrush(Colors.DarkSlateGray);
|
||||
rectTank.StrokeThickness = 2;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ZIndexEnum ZIndex_Base()
|
||||
{
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,9 @@
|
|||
mc:Ignorable="d">
|
||||
|
||||
<!-- DataContext se establece desde el objeto padre, no aquí -->
|
||||
<UserControl.DataContext>
|
||||
<vm:osHydTank />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Canvas RenderTransformOrigin="0,0">
|
||||
<Canvas.RenderTransform>
|
||||
|
@ -21,8 +24,7 @@
|
|||
|
||||
<!-- Contenedor principal del tanque -->
|
||||
<Grid Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Canvas.Left="0" Canvas.Top="0">
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}">
|
||||
|
||||
<!-- Fondo del tanque (contenedor vacío) -->
|
||||
<Rectangle x:Name="rectTankContainer"
|
||||
|
@ -64,27 +66,6 @@
|
|||
Stroke="Red" StrokeThickness="1" StrokeDashArray="2,2" Opacity="0.7"/>
|
||||
</Canvas>
|
||||
|
||||
<!-- Indicadores de conexión -->
|
||||
<!-- Entrada (parte superior) -->
|
||||
<Ellipse Width="8" Height="8"
|
||||
Fill="Green"
|
||||
Stroke="DarkGreen"
|
||||
StrokeThickness="1"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Margin="2,2,0,0"
|
||||
Visibility="{Binding HasInletConnection, Converter={StaticResource BooleanToVisibilityConverter}}"/>
|
||||
|
||||
<!-- Salida (parte inferior) -->
|
||||
<Ellipse Width="8" Height="8"
|
||||
Fill="Blue"
|
||||
Stroke="DarkBlue"
|
||||
StrokeThickness="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Margin="0,0,2,2"
|
||||
Visibility="{Binding HasOutletConnection, Converter={StaticResource BooleanToVisibilityConverter}}"/>
|
||||
|
||||
<!-- Texto del porcentaje de llenado -->
|
||||
<TextBlock Text="{Binding FillPercentage, StringFormat='{}{0:F0}%'}"
|
||||
HorizontalAlignment="Center"
|
||||
|
@ -106,8 +87,7 @@
|
|||
|
||||
<!-- Panel de información -->
|
||||
<Grid Canvas.Top="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.05}"
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Canvas.Left="0">
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,2,0,0">
|
||||
|
|
|
@ -270,6 +270,7 @@ namespace CtrEditor.Serialization
|
|||
{
|
||||
Formatting = Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DefaultValueHandling = DefaultValueHandling.Include, // Incluir valores por defecto
|
||||
TypeNameHandling = TypeNameHandling.Auto,
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
||||
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
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();
|
||||
var hydTank = new osHydTank();
|
||||
|
||||
// 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())}");
|
||||
Console.WriteLine($"osHydTank implements IHydraulicComponent: {typeof(IHydraulicComponent).IsAssignableFrom(hydTank.GetType())}");
|
||||
|
||||
// Verificar NombreCategoria y NombreClase
|
||||
Console.WriteLine($"osHydTank.NombreCategoria(): {osHydTank.NombreCategoria()}");
|
||||
Console.WriteLine($"osHydTank.NombreClase(): {osHydTank.NombreClase()}");
|
||||
|
||||
// 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)}");
|
||||
Console.WriteLine($"osHydTank.GetType() == typeof(IHydraulicComponent): {hydTank.GetType() == typeof(IHydraulicComponent)}");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue