using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using CtrEditor.FuncionesBase;
using CtrEditor.Simulacion.Fluids;
using tainicom.Aether.Physics2D.Fluids;
namespace CtrEditor.ObjetosSim
{
///
/// Lógica para ucSistemaFluidos.xaml
///
public partial class ucSistemaFluidos : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public int zIndex_fromFrames { get; set; }
// Host para el sistema visual de partículas
private ParticulasFluidoHost _hostVisual;
// Timer para medir FPS
private DateTime _ultimaActualizacion = DateTime.Now;
private int _contadorFrames = 0;
private double _fps = 0;
public ucSistemaFluidos()
{
InitializeComponent();
this.Loaded += OnLoaded;
this.Unloaded += OnUnloaded;
// Inicializar el host visual y agregarlo al contenedor
_hostVisual = new ParticulasFluidoHost();
ContenedorVisual.Children.Add(_hostVisual);
// Configurar actualizaciones periódicas para FPS
CompositionTarget.Rendering += OnRendering;
}
private void OnRendering(object sender, EventArgs e)
{
_contadorFrames++;
// Calcular FPS cada segundo
TimeSpan elapsed = DateTime.Now - _ultimaActualizacion;
if (elapsed.TotalSeconds >= 1)
{
_fps = _contadorFrames / elapsed.TotalSeconds;
_contadorFrames = 0;
_ultimaActualizacion = DateTime.Now;
if (Datos is osSistemaFluidos vm)
{
vm.Fps = _fps;
}
}
// Actualizar la visualización de partículas
ActualizarVisualizacion();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
Datos?.ucUnLoaded();
CompositionTarget.Rendering -= OnRendering;
}
public void Highlight(bool State) { }
public ZIndexEnum ZIndex_Base()
{
return ZIndexEnum.Dinamicos;
}
///
/// Actualiza la visualización de partículas
///
private void ActualizarVisualizacion()
{
if (Datos is osSistemaFluidos viewModel)
{
// Obtener la simulación activa desde el ViewModel
var simulacion = viewModel._simFluidos?.SistemaFluido;
if (simulacion != null)
{
// Configurar propiedades visuales
float tamañoParticula = viewModel.TamañoParticula;
Color colorFluido = viewModel.ColorFluido;
// Actualizar la visualización
_hostVisual.ActualizarParticulasFluido(simulacion.Particles, tamañoParticula, colorFluido, viewModel.OpacidadParticulas);
}
}
}
}
///
/// Clase que maneja el rendering optimizado de partículas usando DrawingVisual
///
public class ParticulasFluidoHost : FrameworkElement
{
private readonly DrawingVisual _visual = new DrawingVisual();
private readonly MeterToPixelConverter _converter = new MeterToPixelConverter();
public ParticulasFluidoHost()
{
AddVisualChild(_visual);
}
protected override int VisualChildrenCount => 1;
protected override Visual GetVisualChild(int index)
{
if (index != 0)
throw new ArgumentOutOfRangeException();
return _visual;
}
///
/// Actualiza la visualización de las partículas de fluido
///
/// Lista de partículas a visualizar
/// Tamaño de las partículas en metros
/// Color base del fluido
/// Opacidad base de las partículas
public void ActualizarParticulasFluido(IEnumerable particulas,
float tamañoParticula,
Color colorFluido,
double opacidadBase)
{
using (DrawingContext dc = _visual.RenderOpen())
{
foreach (var particula in particulas)
{
// Ignorar partículas inactivas u ocultas
if (particula == null)
continue;
// Convertir posición a píxeles
float x = (float)_converter.Convert((particula.Position.X / 100) + 5, null, null, null);
float y = (float)_converter.Convert(particula.Position.Y / 100, null, null, null);
float radio = (float)_converter.Convert(tamañoParticula / 2, null, null, null);
// Calcular opacidad basada en densidad
double opacidad = Math.Clamp(particula.Density / 15.0, 0.4, 0.9) * opacidadBase;
// Calcular color basado en velocidad (opcional)
Color colorFinal = colorFluido;
double velocidad = Math.Sqrt(particula.Velocity.X * particula.Velocity.X +
particula.Velocity.Y * particula.Velocity.Y);
if (velocidad > 50)
{
// Partículas más rápidas tienden a ser más claras
float factor = Math.Min(1.0f, (float)velocidad / 400);
colorFinal = MezclarColores(colorFluido, Colors.White, factor);
}
SolidColorBrush brush = new SolidColorBrush(colorFinal) { Opacity = opacidad };
// Dibujar partícula
dc.DrawEllipse(brush, null, new Point(x, y), radio, radio);
}
}
InvalidateVisual();
}
///
/// Mezcla dos colores según un factor (0-1)
///
private Color MezclarColores(Color color1, Color color2, float factor)
{
byte r = (byte)(color1.R + (color2.R - color1.R) * factor);
byte g = (byte)(color1.G + (color2.G - color1.G) * factor);
byte b = (byte)(color1.B + (color2.B - color1.B) * factor);
return Color.FromRgb(r, g, b);
}
}
}