CtrEditor/Documentation/MemoriadeEvolucion.md

472 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### Aqui se mantiene la memoria de evolucion de las distintas decisiones que fueron tomadas y porque
BEPU.cs : SimulationManagerBEPU gestor de la simulacion con el motor BEPUphysics y punto de creacion y modificacion de los objetos dentro del mundo que se derivan des simBase
simBase : Clase base que da un marco a el resto de los objetos
simBarrera : Simula una fotocelula con un espejo usando RayCast
simBotella : Simula una botella que puede transitar por los transportes simTransporte o simCurve
simCurve : Simula una curva o arco de curva de transporte
simDescarte : Permite la eliminacion localizada de botellas en un punto del mundo
simGuia : Es un box con el que las botellas pueden colisionar y cambiar de direccion.
simTransporte : Es un box por donde las botellas pueden desplazarse usando un truco de aplicar la Velocity.Linear pero sin integrar esta velocidad para que no se mueva el objeto transporte.
* Se usaron esferas en vez de cilindros para mejorar la eficiencia. En el Debug3D si se usan cilindros. **Revertido**: Se ha vuelto a usar `Cylinder` para las `simBotella` ya que el nuevo sistema de fricción debería prevenir la rotación indeseada que ocurría con los `LinearAxisMotor`.
* Se reemplazó el sistema de `LinearAxisMotor` que actuaba sobre las `simBotella` por un sistema basado en fricción. Los transportes (`simTransporte` y `simCurve`) ahora son cuerpos cinemáticos que no se mueven de su sitio. Para lograr que arrastren a las botellas, se les asigna una velocidad (`Velocity.Linear` o `Velocity.Angular`) justo antes de que el solver se ejecute (en `OnSubstepStarted`) y se les quita justo después (en `OnSubstepEnded`). Esto permite que los cuerpos cinemáticos transmitan su velocidad a través de la fricción durante la simulación, pero evita que el `PoseIntegrator` los desplace de su posición original, ya que su velocidad es cero cuando se integra la pose.
* Para aumentar la estabilidad de las `simBotella` y evitar que roten descontroladamente sobre su eje Z al ser arrastradas, se implementó un callback `IntegrateVelocity` personalizado. Este callback identifica las botellas durante la integración y les aplica un amortiguamiento angular (`AngularDamping`) adicional solo en el eje Z. Se descartó la idea inicial de modificar dinámicamente la masa de las botellas dentro de este callback, ya que la arquitectura de BEPUphysics no permite cambiar la masa o la inercia de un cuerpo durante la fase de integración de velocidad.
* Originalmente se habia puesto todos los objetos en awaken para poder usar las colisiones constantemente incluso con objetos en modo sleep para que los simBarrera puedan detectar las colisiones. Ahora que se usar RayCast podemos dejar que las simBotellas se duerman
* La unica clase que se ha terminado de refactorizar respecto a el cambio de coordenadas es simBarrera y ucPhotocell. El concepto es poder separar usando metodos de SimulationManagerBEPU y estructuras como BarreraData la conversion de coordenadas de WPF a coordenadas BEPU. Para esto se usa CoordinateConverter que permite bidireccionalmente convertir las coordenadas pero esto solo se debe usar en SimulationManagerBEPU las clases derivadas de osBase solo deben manejar coordenadas WPF, mientras que las clases dervadas de simBase solo deben almacenar y usar coordenadas BEPU. La z tambien es algo que se debe transferir a SimulationManagerBEPU ya que los objetos simBase deberian recibir tambien sus coordenadas de Z desde SimulationManagerBEPU y ser SimulationManagerBEPU el que gestione las Z.
* Se ha implementado un sistema para evitar que las botellas (`simBotella`) "floten" o se eleven de manera irreal por la acumulación de presión en la simulación. Cada botella ahora registra si está en contacto con un transporte y almacena la última coordenada Z válida durante dicho contacto. Si la botella deja de tener contacto con transportes por varios frames consecutivos, se incrementa un contador de "presión". Al superar un umbral, el sistema reestablece la posición Z de la botella a su última altura conocida, previniendo la flotación. Este contador de presión se decrementa rápidamente al volver a hacer contacto con un transporte.
* Cuando una botella (`simBotella`) entra en contacto con un transporte de frenado (`simTransporte` con `isBrake = true`), su posición se ajusta automáticamente para centrarla en el eje longitudinal del transporte. Esto se realiza una única vez, en el primer contacto, para asegurar un acoplamiento suave y predecible. La posición de la botella se proyecta sobre la línea central del transporte y su velocidad lateral se anula, evitando que la botella se desvíe mientras frena y se alinea con el flujo de salida.
* Se ha implementado un indicador visual simple para mostrar cuando los transportes (`simTransporte`) están en movimiento. El sistema detecta automáticamente si un transporte tiene velocidad (`Speed > 0.001`) y cambia su color a verde brillante. Los transportes detenidos se muestran en verde normal. Esta funcionalidad se integra en el sistema de materiales del `BEPUVisualization3DManager` y se actualiza automáticamente cuando cambia el estado del transporte, proporcionando una retroalimentación visual inmediata del estado de operación.
* Se ha implementado un sistema de animaciones automáticas usando StoryBoard de WPF para los transportes en movimiento. Los transportes activos muestran una animación continua que combina: (1) rotación sutil muy lenta alrededor del eje Z (20 segundos por vuelta completa) y (2) pulsación cíclica del color del material (1.5 segundos por ciclo). Las animaciones se crean y destruyen automáticamente según el estado del transporte, sin necesidad de actualización manual en cada frame. El sistema gestiona las animaciones activas en un diccionario y las limpia correctamente cuando se eliminan objetos. Se resolvió el problema de `InvalidOperationException` al animar brushes inmutables creando una función `CreateAnimatableMaterial` que genera materiales específicamente diseñados para ser animados sin estar "frozen", proporcionando una experiencia visual fluida y eficiente.
* Se ha mejorado el sistema de guías curvas (`ucTransporteCurvaGuias`) para incluir apertura en cono en los extremos de entrada y salida. Se agregó el parámetro `AnguloAperturaGuias` (por defecto 5 grados) que permite configurar la apertura modificando los radios de las guías en los puntos extremos. En lugar de cambiar ángulos, se reduce el radio de la guía superior (externa) y se aumenta el radio de la guía inferior (interna) en los segmentos inicial y final, creando naturalmente la apertura en cono. La modificación del radio se calcula usando `Math.Sin(anguloApertura)` para obtener el desplazamiento apropiado. Esta apertura facilita la entrada y salida de botellas del transporte curvo, reduciendo atascos y mejorando el flujo de materiales manteniendo la continuidad geométrica de las guías.
* Se ha implementado un sistema de fricción dinámica que simula el comportamiento de fricción estática vs dinámica para contactos botella-transporte y botella-curva. El sistema calcula el deslizamiento relativo entre la botella y la superficie del transporte: cuando el deslizamiento es bajo (< 0.05 m/s), se aplica fricción estática alta para un arrastre efectivo; cuando el deslizamiento es alto, se aplica fricción dinámica menor para permitir un deslizamiento suave. Para curvas, se calcula la velocidad de superficie usando el producto vectorial (v = ω × r). Para contactos botella-botella, se usa detección de profundidad de penetración para aplicar materiales ultra-suaves cuando hay alta presión, previniendo acumulaciones explosivas. Este enfoque proactivo reemplaza el sistema reactivo de `PressureBuildup` y proporciona un comportamiento más físicamente realista y estable en acumulaciones de botellas.
* Se ha reemplazado el sistema `ProcessPressureSystem` por un nuevo sistema de calibración visual `HighSlippery` que permite ajustar las fricciones de cada componente. Cada botella tiene una propiedad `HighSlippery` (rango 0-9) con sistema de heatup/cooldown que se incrementa durante deslizamiento y se decrementa durante adherencia. El valor se muestra como número en el centro de cada botella para calibración visual. Los `SpringSettings` se mantienen >= 30 para evitar compresiones irreales. El sistema permite calibrar las tasas de heatup/cooldown específicas para transportes (0.2/0.1) y curvas (0.15/0.08), y el umbral de cambio estático/dinámico (HighSlippery > 3). Este sistema elimina el problema del cooldown que reactivaba prematuramente la fricción estática.
# Sistema de Limitación de Fuerzas para Contactos Múltiples Simultáneos (ELIMINADO)
## Problema Identificado
Durante la simulación de "trenes largos" de botellas que impactan simultáneamente, se generaban fuerzas armónicas irreales que no ocurren en la vida real. Aunque tengas 50 botellas empujando, la fuerza máxima está limitada por la resistencia de los materiales.
## Solución Inicial Implementada (OBSOLETA)
### 1. Sistema de Tracking de Densidad de Contactos
- **Discretización espacial**: El espacio se dividía en regiones de 0.5m x 0.5m x 0.5m
- **Contador por región**: Se contaba el número de contactos simultáneos en cada región
- **Límite de contactos**: Máximo 10 contactos antes de aplicar limitación de fuerzas
### 2. Factor de Escala Dinámico
```csharp
// Sin limitación hasta 10 contactos
if (contactCount <= 10) return 1.0f;
// Reducción progresiva: 5% por cada contacto extra
var scaleFactor = 1.0f - (excessContacts * 0.05f);
return Math.Max(scaleFactor, 0.3f); // Mínimo 30% de fuerza original
```
### 3. Aplicación Integral
- **SpringSettings**: Se escalaban proporcionalmente (frecuencia reducida)
- **MaximumRecoveryVelocity**: Se reducía proporcionalmente
- **Todos los tipos de contacto**: Botella-botella, botella-transporte, botella-curva, etc.
## Razón para la Eliminación
Este sistema se **eliminó completamente** porque:
- Era un enfoque indirecto modificando parámetros de material
- El nuevo sistema de **intervención post-solver** es más efectivo
- La cancelación directa de velocidades Z es más elegante y simple
- Reducía la complejidad del código sin comprometer la funcionalidad
# Sistema de Intervención Post-Solver para Control de Velocidades Z
## Problema Identificado
El sistema anterior de limitación de fuerzas pre-solver no controlaba directamente las velocidades Z excesivas generadas por el solver de BEPU. Las botellas seguían elevándose debido a fuerzas de separación acumuladas que se aplicaban después de las restricciones iniciales. Además, el sistema de `forceScale` para contactos múltiples era un enfoque indirecto que no atacaba la causa raíz del problema.
## Solución Implementada
### 1. Enfoque Post-Solver como "Fusible de Energía"
- **Timing crítico**: Intervención en `OnSubstepEnded` - después del solver, antes de la integración de posición
- **Fusible de energía**: Elimina velocidades Z excesivas sin interferir con el comportamiento normal del solver
- **Preservación de física**: Permite al solver trabajar con fuerzas realistas, interviniendo solo cuando es necesario
### 2. Control de Velocidades Z Granular
```csharp
// Límites configurables
const float maxUpwardVelocity = 0.15f; // Anti-elevación
const float maxDownwardVelocity = 2.0f; // Anti-hundimiento
const float zDampingFactor = 0.7f; // Amortiguamiento suave
// Intervención directa en velocidades
if (velocity.Linear.Z > maxUpwardVelocity) {
velocity.Linear.Z = maxUpwardVelocity;
}
```
### 3. Corrección de Posición Extrema
- **Detección de altura excesiva**: Si la botella está muy por encima del nivel normal
- **Corrección suave**: Aplicar velocidad correctiva hacia abajo (máximo 0.5 m/s)
- **Cálculo proporcional**: Velocidad correctiva basada en la altura excesiva
## Simplificación del Sistema
### 1. Eliminación de `ApplyZForceLimitation`
- **Antes**: Limitación pre-solver que interfería con el comportamiento normal
- **Ahora**: Intervención post-solver más directa y efectiva
### 2. Simplificación de `IntegrateVelocity`
- **Antes**: Control complejo de velocidades Z durante la integración
- **Ahora**: Solo control angular básico (anti-vuelco) y damping en Z
- **Beneficio**: Menor interferencia con la física normal de BEPU
## Beneficios del Enfoque Post-Solver
- **Más efectivo**: Intervención después de que el solver haya calculado todas las fuerzas
- **Menos interferencia**: Permite comportamiento físico normal hasta el punto de intervención
- **Más directo**: Control directo de velocidades en lugar de modificar parámetros de material
- **Más predecible**: Comportamiento determinista independiente de las configuraciones del solver
- **Mantenimiento de rigidez**: Las fuerzas normales en XY permanecen intactas
- **Solución integral**: Resuelve tanto el problema de elevación como el de contactos múltiples simultáneos
- **Código más simple**: Elimina la complejidad del sistema de tracking de densidad de contactos
# Sistema Hidráulico Integrado con HydraulicSimulationManager
## Arquitectura del Sistema Hidráulico
Se ha implementado un sistema de simulación hidráulica completo que funciona en paralelo con la simulación física BEPU. El sistema está basado en el `HydraulicSimulationManager` que actúa como puente entre los objetos gráficos derivados de `osBase` y el motor de simulación hidráulica.
### Componentes Principales
#### HydraulicSimulationManager
- **Función**: Gestiona el ciclo de vida y la comunicación entre objetos hidráulicos y el solver
- **Integración**: Se ejecuta en paralelo con BEPU en el timer loop principal de MainViewModel
- **Responsabilidades**:
- Registro automático de objetos que implementan `IHydraulicComponent`
- Construcción dinámica de la red hidráulica
- Aplicación de resultados a los objetos tras cada iteración del solver
#### Interfaces Hidráulicas
- **IHydraulicComponent**: Interfaz base para todos los objetos hidráulicos
- **IHydraulicPump**: Para bombas con curvas H-Q
- **IHydraulicPipe**: Para tuberías con pérdidas por fricción
- **IHydraulicTank**: Para tanques con cálculo de nivel dinámico
- **IHydraulicValve**: Para válvulas con coeficiente Kv
## Mejoras Implementadas en Objetos Hidráulicos
### 1. Sistema de Conexiones Mejorado en osHydPipe
**Problema Original**: El sistema de conexiones era limitado y no seguía el patrón establecido en otros objetos del sistema.
**Solución Implementada**:
```csharp
// Antes - Sistema limitado
[ObservableProperty] string id_InletComponent = "";
[ObservableProperty] string id_OutletComponent = "";
// Después - Patrón consistente
[ItemsSource(typeof(osBaseItemsSource<IHydraulicComponent>))]
[ObservableProperty] string id_ComponenteA = "";
[ItemsSource(typeof(osBaseItemsSource<IHydraulicComponent>))]
[ObservableProperty] string id_ComponenteB = "";
```
**Beneficios**:
- **Filtrado automático**: Solo muestra objetos que implementan `IHydraulicComponent` en el PropertyGrid
- **Consistencia**: Sigue el mismo patrón usado en `ucTransporteGuias` con `Motor`
- **Mantenimiento automático**: PropertyChangedHandlers mantienen sincronizados los nombres
- **Validación**: Solo crea elementos hidráulicos cuando ambos componentes están conectados
### 2. Lógica de Nodos Corregida
**Problema Original**: Las tuberías intentaban crear sus propios nodos, generando duplicación y conflictos.
**Solución Implementada**:
```csharp
// Las tuberías no crean nodos propios
public List<HydraulicNodeDefinition> GetHydraulicNodes()
{
// Los nodos son creados por los componentes conectados (tanques, bombas, etc.)
return new List<HydraulicNodeDefinition>();
}
// Solo conectan nodos existentes
public List<HydraulicElementDefinition> GetHydraulicElements()
{
if (!string.IsNullOrEmpty(Id_ComponenteA) && !string.IsNullOrEmpty(Id_ComponenteB))
{
var pipeElement = new Pipe(Length, Diameter, Roughness);
// Conecta directamente usando nombres de componentes como nodos
return new List<HydraulicElementDefinition> {
new HydraulicElementDefinition($"{Nombre}_Pipe", Id_ComponenteA, Id_ComponenteB, pipeElement)
};
}
return new List<HydraulicElementDefinition>();
}
```
### 3. Integración Completa con ItemsSource
**En osHydDischargeTank**:
```csharp
[Category("🔗 Conexiones")]
[Name("Componente Entrada")]
[ItemsSource(typeof(osBaseItemsSource<IHydraulicComponent>))]
[ObservableProperty] string id_InletComponent = "";
```
## Flujo de Simulación Hidráulica
### 1. Registro Automático
- Los objetos que implementan `IHydraulicComponent` se registran automáticamente en `HydraulicSimulationManager`
- El sistema detecta cuando hay cambios y marca la red para reconstrucción (`_networkNeedsRebuild = true`)
### 2. Construcción de Red
- **BuildNodesFromObjects()**: Crea nodos basándose en las definiciones de cada objeto
- **BuildBranchesFromObjects()**: Crea elementos (tuberías, bombas, válvulas) que conectan los nodos
- La red resultante es compatible con el solver `HydraulicNetwork.Solve()`
### 3. Resolución y Aplicación
- **UpdateObjectProperties()**: Actualiza propiedades antes del solver (apertura de válvulas, velocidad de bombas, etc.)
- **Network.Solve()**: Resuelve el sistema de ecuaciones usando el algoritmo iterativo
- **ApplyResultsToObjects()**: Aplica caudales y presiones calculados a cada objeto
## Patrón de Conexión Establecido
El sistema establecido para conexiones sigue este patrón consistente:
```csharp
// 1. Propiedad string con ItemsSource filtrado
[ItemsSource(typeof(osBaseItemsSource<IInterfaceEspecifica>))]
[ObservableProperty] string id_ComponenteConectado = "";
// 2. Referencia privada al objeto real
[JsonIgnore] private IInterfaceEspecifica ComponenteConectado = null;
// 3. PropertyChangedHandler para mantener sincronización
[JsonIgnore] private PropertyChangedEventHandler componentePropertyChangedHandler;
// 4. Método OnChanged que maneja la conexión
partial void OnId_ComponenteConectadoChanged(string value)
{
// Desconectar anterior si existe
if (ComponenteConectado != null && componentePropertyChangedHandler != null)
((INotifyPropertyChanged)ComponenteConectado).PropertyChanged -= componentePropertyChangedHandler;
// Buscar y conectar nuevo componente
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
{
ComponenteConectado = (IInterfaceEspecifica)_mainViewModel.ObjetosSimulables
.FirstOrDefault(s => s is IInterfaceEspecifica comp &&
((osBase)comp).Nombre == value);
// Establecer handler para sincronización de nombres
if (ComponenteConectado != null)
{
componentePropertyChangedHandler = (sender, e) =>
{
if (e.PropertyName == nameof(osBase.Nombre))
Id_ComponenteConectado = ((osBase)sender).Nombre;
};
((INotifyPropertyChanged)ComponenteConectado).PropertyChanged += componentePropertyChangedHandler;
}
}
}
```
## Beneficios del Sistema Integrado
- **Doble simulación**: Simulación física (BEPU) y hidráulica funcionan en paralelo sin interferencia
- **Interfaces unificadas**: Todos los objetos hidráulicos implementan interfaces consistentes
- **Red dinámica**: La red hidráulica se reconstruye automáticamente cuando cambian las conexiones
- **Resultados bidireccionales**: Los resultados hidráulicos pueden influir en la simulación física y viceversa
- **Patrón consistente**: Todas las conexiones siguen el mismo patrón establecido
- **Mantenimiento automático**: Los nombres y referencias se mantienen sincronizados automáticamente
## Resolución de Problemas de Simulación Hidráulica - Bomba con Caudal Cero
### Problema Identificado
La bomba hidráulica mostraba velocidad=1.0 y funcionando=true pero registraba 0 caudal y 0 presión constantemente.
### Causas Encontradas
1. **Doble registro de objetos**: Los objetos hidráulicos se registraban dos veces - una al cargar cada objeto individualmente y otra al ejecutar `RegisterLoadedHydraulicObjects()` después de cargar el proyecto completo.
2. **Unidades incorrectas en MaxFlow**: La configuración JSON tenía `MaxFlow: 10.0` pero el código manejaba valores en m³/s. El valor 10.0 se interpretaba como 10 m³/s (36,000 m³/h) en lugar de 10 m³/h.
3. **Falta de información de debugging**: El `VerboseOutput` estaba desactivado, ocultando información crítica sobre la construcción de la red y convergencia del solver.
### Soluciones Implementadas
#### 1. Prevención de Doble Registro
Modificado `RegisterHydraulicObjectIfNeeded()` en `MainViewModel.cs` para verificar si el objeto ya está registrado antes de agregarlo:
```csharp
if (!hydraulicSimulationManager.HydraulicObjects.Contains(obj))
{
hydraulicSimulationManager.RegisterHydraulicObject(obj);
}
```
#### 2. Corrección de Unidades MaxFlow
Implementado en `osHydPump.cs` conversión automática de unidades para `MaxFlow`:
- Si el valor > 1.0, se asume que está en m³/h y se convierte a m³/s (dividiendo por 3600)
- Se agregó logging detallado mostrando ambas unidades para verificación
#### 3. Activación de Verbose Output
- Habilitado `VerboseOutput = true` por defecto en `HydraulicSimulationManager`
- Agregado logging detallado de construcción de red mostrando todos los nodos y ramas
- Implementado logging periódico de resultados (cada 5 segundos aprox.) mostrando flujos y presiones
- Mejorado logging de errores de convergencia con detalles de iteraciones y residual
#### 4. Debugging Mejorado
Los logs ahora muestran:
- Detalles completos de nodos (presión fija/libre, valores de presión)
- Ramas con elementos y tipos de componentes
- Resultados de flujos en m³/s y m³/h
- Presiones en Pa y bar
- Estado de convergencia del solver con detalles de error
### Corrección Final: Convergencia del Solver Hidráulico
#### Problema de Convergencia
El solver no convergía porque el sistema carecía de suficientes nodos de presión fija:
- La bomba tenía nodos de entrada y salida libres
- Solo el tanque de descarga tenía presión fija
- El solver necesita al menos dos puntos de referencia para sistemas complejos
#### Solución Implementada
**1. Nodo de Succión en la Bomba**
```csharp
// En GetHydraulicNodes() de osHydPump
double suctionPressure = 101325.0; // Pa (1 atm)
nodes.Add(new HydraulicNodeDefinition($"{Nombre}_In", true, suctionPressure, "Entrada de la bomba (succión)"));
```
**2. Parámetros Optimizados del Solver**
- MaxIterations: 200 → 300
- Tolerance: 1e-4 → 1e-3 (más relajada para convergencia inicial)
- RelaxationFactor: 0.8 (mantiene estabilidad)
**3. Sistema de Referencias Hidráulicas**
- Nodo de succión: 101325 Pa (presión atmosférica)
- Nodo de descarga: 101325 + TankPressure Pa (atmosférica + hidrostática)
- Esto simula un sistema real con tanque de succión y descarga
### Corrección Final: Problema del DataContext en UI
#### Problema Identificado
Aunque la simulación funcionaba correctamente y los valores se calculaban bien, estos no se mostraban en el UserControl de la bomba porque:
- El UserControl tenía su propio `DataContext` definido en el XAML
- Esto creaba una instancia separada de `osHydPump` solo para el UI
- Los valores se actualizaban en el objeto real, pero el UI mostraba el objeto falso
#### Solución Implementada
```xml
<!-- Eliminado el DataContext problemático -->
<!-- <UserControl.DataContext>
<vm:osHydPump ImageSource_oculta="/imagenes/pump_run.png" />
</UserControl.DataContext> -->
<!-- DataContext se establece desde el objeto padre, no aquí -->
```
### Resultado Final del Sistema Hidráulico
Sistema hidráulico completamente funcional:
- ✅ Convergencia estable del solver con residuales < 1e-3
- Registro único de objetos (sin duplicados)
- Conversión automática de unidades (m³/h m³/s)
- Logging detallado para monitoreo y debugging
- Bomba genera flujo y presión reales según configuración
- **UserControl muestra valores actualizados en tiempo real**
## Nuevo Tanque Hidráulico Avanzado (osHydTank)
### Arquitectura Modular Implementada
Se siguió el enfoque arquitectónico de **"Tanques como Terminales + Pipes como Conectores"** para crear un sistema más realista y mantenible:
```
[Tanque Succión] → [Pipe] → [Bomba] → [Pipe] → [Válvula] → [Pipe] → [Tanque Descarga]
```
### Características del osHydTank
**Gestión Dinámica de Nivel:**
- Nivel calculado en base a flujos de entrada y salida
- Seguimiento de volumen actual vs. máximo/mínimo
- Indicadores visuales de estado del tanque
- Detección automática de desbordamiento y vaciado
**Presión Configurable:**
- Presión independiente del nivel (simulando PID externo)
- Opción de presión fija o variable
- Diferentes tipos de tanque: Succión, Intermedio, Almacenamiento, Proceso
**Interfaces Hidráulicas:**
- `IHydraulicComponent`: Integración con red hidráulica
- `IHydraulicFlowReceiver`: Recepción de flujos calculados
- `IHydraulicPressureReceiver`: Actualización de presiones
**UserControl Avanzado:**
- Visualización en tiempo real del nivel de líquido
- Indicadores de tipo de tanque y conexiones
- Balance de flujo con códigos de color
- Conversión automática de TankLevelToHeightConverter
## Solución de Problemas de Visualización osHydTank
### Problema
El componente `osHydTank` no se mostraba correctamente en el canvas a pesar de registrarse exitosamente en el sistema hidráulico. Los logs mostraban errores de binding en el MultiBinding del rectángulo de nivel del líquido.
### Análisis
1. **Error de Converter**: El XAML usaba `TankLevelToHeightConverter` que tenía incompatibilidades de tipos
2. **Falta de inicialización**: El UserControl `ucHydTank` no llamaba a `ucLoaded()`/`ucUnLoaded()` como otros componentes
3. **Binding incorrecto**: No se convertía `Tamano` a píxeles antes del MultiBinding
### Solución Implementada
1. **Cambio de Converter**: Reemplazamos `TankLevelToHeightConverter` por `LevelToHeightMultiConverter` (que funciona en otros componentes)
2. **Conversión a Píxeles**: Agregamos `MeterToPixelConverter` a `Tamano` antes del MultiBinding
3. **Ciclo de Vida**: Implementamos las llamadas correctas a `ucLoaded()`/`ucUnLoaded()` en `ucHydTank.xaml.cs`
### Cambios Técnicos
- **XAML**: `<Binding Path="Tamano" Converter="{StaticResource MeterToPixelConverter}"/>`
- **UserControl**: Agregado `Unloaded += OnUserControlUnloaded` y llamadas a `ucLoaded()`/`ucUnLoaded()`
- **Converter Corregido**: `LevelToHeightMultiConverter` ahora usa `System.Convert.ToDouble()` para flexibilidad de tipos
- **Patrón consistente** con `ucHydPump`, `ucHydDischargeTank` y `ucHydPipe`
### Detalle del Error del Converter
El `LevelToHeightMultiConverter` esperaba tipos específicos (`float` y `double`) pero recibía tipos invertidos:
- `FillPercentage`: `double` (esperaba `float`)
- `MeterToPixelConverter` output: `float` (esperaba `double`)
**Solución**: Implementar función `TryConvertToDouble()` robusta que maneja:
- Valores especiales de WPF (`DependencyProperty.UnsetValue`, `MS.Internal.NamedObject`)
- Múltiples tipos numéricos (`double`, `float`, `int`, `decimal`)
- Conversión segura de strings
- Verificación `IConvertible` antes de usar `System.Convert.ToDouble()`
### Validación de Arquitectura
El sistema ahora requiere que:
- Todo circuito hidráulico **inicie con un tanque**
- Todo circuito hidráulico **termine con un tanque**
- Los `pipes` sean los únicos conectores entre componentes
- Cada componente tenga **responsabilidad única**
### Beneficios del Nuevo Diseño
**Realismo Físico:**
- Refleja sistemas hidráulicos reales donde tanques son puntos de referencia
- Presión independiente del nivel (como en sistemas industriales)
- Gestión de volumen dinámica
**Escalabilidad:**
- Patrón consistente para nuevos componentes hidráulicos
- Fácil conexión de válvulas, filtros, intercambiadores de calor
- Sistema preparado para redes complejas
**Mantenibilidad:**
- Principio de responsabilidad única por componente
- Interfaces claras y bien definidas
- Debugging simplificado con logging detallado
**Flexibilidad:**
- Diferentes tipos de tanques para diferentes funciones
- Configuración de presión independiente
- Conectividad modular via pipes
La bomba ahora debe mostrar correctamente:
- **Presión actual** en bar (ej: "1.0 bar")
- **Caudal actual** en L/min (ej: "165.8 L/min")