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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="ObjetosSim\HydraulicSimulator\" />
|
|
||||||
<Folder Include="paddleocr\cls\inference\" />
|
<Folder Include="paddleocr\cls\inference\" />
|
||||||
<Folder Include="paddleocr\det\inference\" />
|
<Folder Include="paddleocr\det\inference\" />
|
||||||
<Folder Include="paddleocr\keys\" />
|
<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>
|
/// </summary>
|
||||||
public partial class osHydPipe : osBase, IHydraulicPipe, IosBase
|
public partial class osHydPipe : osBase, IHydraulicPipe, IosBase
|
||||||
{
|
{
|
||||||
#region Properties
|
// Properties
|
||||||
|
|
||||||
private double _length = 1.0; // metros
|
private double _length = 1.0; // metros
|
||||||
private double _diameter = 0.05; // metros (50mm)
|
private double _diameter = 0.05; // metros (50mm)
|
||||||
|
@ -120,9 +120,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
set => SetProperty(ref pipeId, value);
|
set => SetProperty(ref pipeId, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Component References
|
|
||||||
|
// Component References
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private IHydraulicComponent ComponenteA = null;
|
private IHydraulicComponent ComponenteA = null;
|
||||||
|
@ -139,15 +139,15 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Action<float, float> ActualizarTamaño { get; set; }
|
public Action<float, float> ActualizarTamaño { get; set; }
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IHydraulicPipe Implementation
|
|
||||||
|
// IHydraulicPipe Implementation
|
||||||
|
|
||||||
// Ya implementadas las propiedades Length, Diameter, Roughness arriba
|
// Ya implementadas las propiedades Length, Diameter, Roughness arriba
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IHydraulicComponent Implementation
|
|
||||||
|
// IHydraulicComponent Implementation
|
||||||
|
|
||||||
public bool HasHydraulicComponents => true;
|
public bool HasHydraulicComponents => true;
|
||||||
|
|
||||||
|
@ -277,9 +277,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IHydraulicFlowReceiver Implementation
|
|
||||||
|
// IHydraulicFlowReceiver Implementation
|
||||||
|
|
||||||
public void SetFlow(double flow)
|
public void SetFlow(double flow)
|
||||||
{
|
{
|
||||||
|
@ -291,9 +291,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
return CurrentFlow;
|
return CurrentFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IHydraulicPressureReceiver Implementation
|
|
||||||
|
// IHydraulicPressureReceiver Implementation
|
||||||
|
|
||||||
public void SetPressure(double pressure)
|
public void SetPressure(double pressure)
|
||||||
{
|
{
|
||||||
|
@ -305,9 +305,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
return PressureDrop;
|
return PressureDrop;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Connection Management
|
|
||||||
|
// Connection Management
|
||||||
|
|
||||||
partial void OnId_ComponenteAChanged(string value)
|
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";
|
public static string NombreCategoria() => "Componentes Hidráulicos";
|
||||||
|
|
||||||
|
@ -434,9 +434,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
((INotifyPropertyChanged)ComponenteB).PropertyChanged -= componenteBPropertyChangedHandler;
|
((INotifyPropertyChanged)ComponenteB).PropertyChanged -= componenteBPropertyChangedHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
|
// Constructor
|
||||||
|
|
||||||
public osHydPipe()
|
public osHydPipe()
|
||||||
{
|
{
|
||||||
|
@ -444,6 +444,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
IsVisFilter = true; // Asegurar que el componente hidráulico sea visible en filtros
|
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";
|
return "Bomba Hidráulica";
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Properties
|
// Properties
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[property: JsonIgnore]
|
[property: JsonIgnore]
|
||||||
|
@ -176,9 +176,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public double CurrentFlowLMin => CurrentFlow * 60000.0; // m³/s a L/min
|
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();
|
private string nombre = NombreClase();
|
||||||
|
|
||||||
|
@ -201,9 +201,6 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
Angulo = 0f;
|
Angulo = 0f;
|
||||||
// Asegurar que el movimiento esté habilitado
|
// Asegurar que el movimiento esté habilitado
|
||||||
Lock_movement = false;
|
Lock_movement = false;
|
||||||
// Inicializar posición por defecto
|
|
||||||
Left = 0.0f;
|
|
||||||
Top = 0.0f;
|
|
||||||
ImageSource_oculta = ImageFromPath("/imagenes/pump_stop.png");
|
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
|
// Los objetos hidráulicos no tienen geometría que limpiar
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IHydraulicComponent Implementation
|
|
||||||
|
// IHydraulicComponent Implementation
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool HasHydraulicComponents => true;
|
public bool HasHydraulicComponents => true;
|
||||||
|
@ -343,9 +340,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
OnPropertyChanged(nameof(CurrentPressureBar));
|
OnPropertyChanged(nameof(CurrentPressureBar));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IHydraulicFlowReceiver Implementation
|
|
||||||
|
// IHydraulicFlowReceiver Implementation
|
||||||
|
|
||||||
public void SetFlow(double flow)
|
public void SetFlow(double flow)
|
||||||
{
|
{
|
||||||
|
@ -357,9 +354,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
return CurrentFlow;
|
return CurrentFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IHydraulicPressureReceiver Implementation
|
|
||||||
|
// IHydraulicPressureReceiver Implementation
|
||||||
|
|
||||||
public void SetPressure(double pressure)
|
public void SetPressure(double pressure)
|
||||||
{
|
{
|
||||||
|
@ -371,9 +368,9 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
return CurrentPressure;
|
return CurrentPressure;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Helper Methods
|
|
||||||
|
// Helper Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalida la red hidráulica para forzar reconstrucción
|
/// Invalida la red hidráulica para forzar reconstrucción
|
||||||
|
@ -387,7 +384,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -41,7 +41,8 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
private string _connectedInletPipe = "";
|
private string _connectedInletPipe = "";
|
||||||
private string _connectedOutletPipe = "";
|
private string _connectedOutletPipe = "";
|
||||||
private double _lastUpdateTime = 0.0;
|
private double _lastUpdateTime = 0.0;
|
||||||
private readonly object _levelLock = new object();
|
[JsonIgnore]
|
||||||
|
private object _levelLock = new object();
|
||||||
private PropertyChangedEventHandler? inletPropertyChangedHandler;
|
private PropertyChangedEventHandler? inletPropertyChangedHandler;
|
||||||
private PropertyChangedEventHandler? outletPropertyChangedHandler;
|
private PropertyChangedEventHandler? outletPropertyChangedHandler;
|
||||||
|
|
||||||
|
@ -95,13 +96,15 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
Angulo = 0f;
|
Angulo = 0f;
|
||||||
// Asegurar que el movimiento esté habilitado
|
// Asegurar que el movimiento esté habilitado
|
||||||
Lock_movement = false;
|
Lock_movement = false;
|
||||||
// Inicializar posición por defecto
|
|
||||||
ImageSource_oculta = ImageFromPath("/imagenes/tank.png");
|
ImageSource_oculta = ImageFromPath("/imagenes/tank.png");
|
||||||
_currentVolume = _currentLevel * _crossSectionalArea;
|
_currentVolume = _currentLevel * _crossSectionalArea;
|
||||||
_maxVolume = _maxLevel * _crossSectionalArea;
|
_maxVolume = _maxLevel * _crossSectionalArea;
|
||||||
IsVisFilter = true; // Asegurar que el componente hidráulico sea visible en filtros
|
IsVisFilter = true; // Asegurar que el componente hidráulico sea visible en filtros
|
||||||
UpdateTankPressure();
|
UpdateTankPressure();
|
||||||
|
|
||||||
|
// Inicializar el lock para thread safety
|
||||||
|
EnsureLockInitialized();
|
||||||
|
|
||||||
// Debug: Confirmar que el constructor se ejecuta
|
// 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}");
|
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);
|
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)
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
{
|
{
|
||||||
Tamano += Delta_Width + Delta_Height;
|
Tamano += Delta_Width + Delta_Height;
|
||||||
|
@ -280,6 +290,7 @@ namespace CtrEditor.ObjetosSim.HydraulicComponents
|
||||||
get => _currentLevel;
|
get => _currentLevel;
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
|
EnsureLockInitialized();
|
||||||
lock (_levelLock)
|
lock (_levelLock)
|
||||||
{
|
{
|
||||||
var clampedLevel = Math.Max(_minLevel, Math.Min(_maxLevel, value));
|
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
|
// osBase Overrides
|
||||||
|
|
||||||
public override void ucLoaded()
|
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();
|
UpdateVolumeCalculations();
|
||||||
UpdateTankPressure();
|
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">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<!-- DataContext se establece desde el objeto padre, no aquí -->
|
<!-- DataContext se establece desde el objeto padre, no aquí -->
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osHydTank />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
<Canvas RenderTransformOrigin="0,0">
|
<Canvas RenderTransformOrigin="0,0">
|
||||||
<Canvas.RenderTransform>
|
<Canvas.RenderTransform>
|
||||||
|
@ -21,8 +24,7 @@
|
||||||
|
|
||||||
<!-- Contenedor principal del tanque -->
|
<!-- Contenedor principal del tanque -->
|
||||||
<Grid Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
<Grid Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}">
|
||||||
Canvas.Left="0" Canvas.Top="0">
|
|
||||||
|
|
||||||
<!-- Fondo del tanque (contenedor vacío) -->
|
<!-- Fondo del tanque (contenedor vacío) -->
|
||||||
<Rectangle x:Name="rectTankContainer"
|
<Rectangle x:Name="rectTankContainer"
|
||||||
|
@ -64,27 +66,6 @@
|
||||||
Stroke="Red" StrokeThickness="1" StrokeDashArray="2,2" Opacity="0.7"/>
|
Stroke="Red" StrokeThickness="1" StrokeDashArray="2,2" Opacity="0.7"/>
|
||||||
</Canvas>
|
</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 -->
|
<!-- Texto del porcentaje de llenado -->
|
||||||
<TextBlock Text="{Binding FillPercentage, StringFormat='{}{0:F0}%'}"
|
<TextBlock Text="{Binding FillPercentage, StringFormat='{}{0:F0}%'}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
@ -106,8 +87,7 @@
|
||||||
|
|
||||||
<!-- Panel de información -->
|
<!-- Panel de información -->
|
||||||
<Grid Canvas.Top="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.05}"
|
<Grid Canvas.Top="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.05}"
|
||||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}">
|
||||||
Canvas.Left="0">
|
|
||||||
<StackPanel Orientation="Horizontal"
|
<StackPanel Orientation="Horizontal"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Margin="0,2,0,0">
|
Margin="0,2,0,0">
|
||||||
|
|
|
@ -270,6 +270,7 @@ namespace CtrEditor.Serialization
|
||||||
{
|
{
|
||||||
Formatting = Formatting.Indented,
|
Formatting = Formatting.Indented,
|
||||||
NullValueHandling = NullValueHandling.Ignore,
|
NullValueHandling = NullValueHandling.Ignore,
|
||||||
|
DefaultValueHandling = DefaultValueHandling.Include, // Incluir valores por defecto
|
||||||
TypeNameHandling = TypeNameHandling.Auto,
|
TypeNameHandling = TypeNameHandling.Auto,
|
||||||
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
||||||
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
|
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