diff --git a/MainViewModel.cs b/MainViewModel.cs index e2ee2e2..c01f95d 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -6,7 +6,7 @@ using Ookii.Dialogs.Wpf; using System.Collections.ObjectModel; using System.Windows.Threading; using CtrEditor.ObjetosSim; -using LibS7Adv; +using LibS7Adv; // Using stub implementation using System.IO; using Newtonsoft.Json; using System.Windows; @@ -26,6 +26,7 @@ using CtrEditor.Serialization; // Add this line using CtrEditor.Controls; // Add this using directive using CtrEditor.PopUps; // Add this using directive + namespace CtrEditor { @@ -49,6 +50,7 @@ namespace CtrEditor private readonly DispatcherTimer _timerSimulacion; private readonly DispatcherTimer _timerPLCUpdate; private readonly DispatcherTimer _timerDisplayUpdate; + private readonly DispatcherTimer _timer3DUpdate; // Nuevo timer para actualización 3D cuando simulación está detenida public Canvas MainCanvas; @@ -94,7 +96,6 @@ namespace CtrEditor public ICommand StopSimulationCommand { get; } public ICommand ItemDoubleClickCommand { get; private set; } - public SimulationFluidsViewModel FluidSimulation { get; private set; } public ICommand TBStartSimulationCommand { get; } public ICommand TBStopSimulationCommand { get; } @@ -117,6 +118,12 @@ namespace CtrEditor public ICommand TBMultiPageMatrixCommand { get; } public ICommand TBLibraryManagerCommand { get; } + // Comandos para vista 3D + public ICommand TB3DViewTopCommand { get; } + public ICommand TB3DViewSideCommand { get; } + public ICommand TB3DViewFrontCommand { get; } + public ICommand TB3DViewIsometricCommand { get; } + public ICommand TBTogglePLCConnectionCommand => new RelayCommand(() => { @@ -174,6 +181,18 @@ namespace CtrEditor partial void OnIsSimulationRunningChanged(bool value) { CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado + + // Controlar el timer de actualización 3D + if (value) + { + // Simulación iniciada - detener timer 3D (la sincronización se hace en Step()) + _timer3DUpdate.Stop(); + } + else + { + // Simulación detenida - iniciar timer 3D para mantener sincronización + _timer3DUpdate.Start(); + } } partial void OnHasUnsavedChangesChanged(bool value) @@ -370,16 +389,18 @@ namespace CtrEditor _timerDisplayUpdate.Tick += OnDisplayUpdate; _timerDisplayUpdate.Start(); + _timer3DUpdate = new DispatcherTimer(); + _timer3DUpdate.Interval = TimeSpan.FromMilliseconds(20); + _timer3DUpdate.Tick += OnTick3DUpdate; + _timer3DUpdate.Start(); // Iniciar porque la simulación empieza detenida + StartSimulationCommand = new RelayCommand(StartSimulation); StopSimulationCommand = new RelayCommand(StopSimulation); TBStartSimulationCommand = new RelayCommand(StartSimulation, () => !IsSimulationRunning); TBStopSimulationCommand = new RelayCommand(StopSimulation, () => IsSimulationRunning); - // Inicializar simulación de fluidos - FluidSimulation = new SimulationFluidsViewModel(this); - TBStartFluidSimulationCommand = new RelayCommand(StartFluidSimulation, () => !FluidSimulation.IsFluidSimulationRunning); - TBStopFluidSimulationCommand = new RelayCommand(StopFluidSimulation, () => FluidSimulation.IsFluidSimulationRunning); + TBSaveCommand = new RelayCommand(Save); TBEliminarUserControlCommand = new RelayCommand(EliminarUserControl, () => habilitarEliminarUserControl); @@ -392,6 +413,12 @@ namespace CtrEditor TBMultiPageAnalizeCommand = new RelayCommand(MultiPageAnalizeCommand); TBMultiPageMatrixCommand = new RelayCommand(MultiPageMatrixCommand); TBLibraryManagerCommand = new RelayCommand(ShowLibraryManager); + + // Comandos para vista 3D + TB3DViewTopCommand = new RelayCommand(() => Visualization3DManager?.SetCameraView(CameraView.Top)); + TB3DViewSideCommand = new RelayCommand(() => Visualization3DManager?.SetCameraView(CameraView.Side)); + TB3DViewFrontCommand = new RelayCommand(() => Visualization3DManager?.SetCameraView(CameraView.Front)); + TB3DViewIsometricCommand = new RelayCommand(() => Visualization3DManager?.SetCameraView(CameraView.Isometric)); RenameImageCommand = new RelayCommand(RenameImage); stopwatch_Sim = new Stopwatch(); @@ -411,6 +438,9 @@ namespace CtrEditor // Conectar DatosDeTrabajo con este ViewModel para el escaneo de imágenes datosDeTrabajo.SetMainViewModel(this); + + // NOTA: La conexión del manager 3D se hace en MainWindow_Loaded + // después de que se cree la instancia de BEPUVisualization3DManager } // Métodos para manejo de datos de imágenes @@ -876,8 +906,6 @@ namespace CtrEditor private void StartSimulation() { - // Detener simulación de fluidos si está ejecutándose - StopFluidSimulation(); IsSimulationRunning = true; @@ -887,7 +915,7 @@ namespace CtrEditor foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.UpdateGeometryStart(); - simulationManager.Debug_DrawInitialBodies(); + TiempoDesdeStartSimulacion = 0; Debug_SimulacionCreado = true; @@ -904,7 +932,6 @@ namespace CtrEditor if (Debug_SimulacionCreado) { - simulationManager.Debug_ClearSimulationShapes(); Debug_SimulacionCreado = false; } _timerSimulacion.Stop(); @@ -916,26 +943,7 @@ namespace CtrEditor MainWindow?.ClearUndoHistory(); } - /// - /// Inicia la simulación de fluidos independiente - /// - public void StartFluidSimulation() - { - // Detener simulación física si está ejecutándose - StopSimulation(); - FluidSimulation.StartFluidSimulation(); - CommandManager.InvalidateRequerySuggested(); - } - - /// - /// Detiene la simulación de fluidos independiente - /// - public void StopFluidSimulation() - { - FluidSimulation.StopFluidSimulation(); - CommandManager.InvalidateRequerySuggested(); - } private void OnTickSimulacion(object sender, EventArgs e) { @@ -949,10 +957,8 @@ namespace CtrEditor accumulatedSimTime += elapsedMilliseconds; simSampleCount++; - // Eliminar el diseño de Debug luego de 2 segundos - if (TiempoDesdeStartSimulacion > 1200) - simulationManager.Debug_ClearSimulationShapes(); - else + // Contador de tiempo desde el inicio de la simulación + if (TiempoDesdeStartSimulacion <= 1200) TiempoDesdeStartSimulacion += (float)elapsedMilliseconds; foreach (var objetoSimulable in ObjetosSimulables) @@ -1268,7 +1274,6 @@ namespace CtrEditor { // Detener simulaciones antes de cambiar la escala StopSimulation(); - StopFluidSimulation(); DisconnectPLC(); // Actualizar la escala en el UnitConverter @@ -1341,6 +1346,15 @@ namespace CtrEditor libraryWindow.Show(); } + private void OnTick3DUpdate(object? sender, EventArgs e) + { + // Solo actualizar Helix3D si la simulación está detenida + // Cuando la simulación está corriendo, la sincronización se hace en simulationManager.Step() + if (!IsSimulationRunning && Visualization3DManager != null) + { + Visualization3DManager.SynchronizeWorld(); + } + } } diff --git a/MainWindow.xaml b/MainWindow.xaml index 530febf..ccef2ee 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -10,6 +10,7 @@ xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" + xmlns:helix="http://helix-toolkit.org/wpf" xmlns:ObjetosExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos" x:Class="CtrEditor.MainWindow" Height="900" Width="1600" WindowState="Maximized" ResizeMode="CanResize" Title="{Binding directorioTrabajo, Converter={StaticResource UnsavedChangesConverter}}" diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 7a8e574..05f31be 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -91,7 +91,6 @@ namespace CtrEditor viewModel.MainWindow = this; viewModel.ImageSelected += ViewModel_ImageSelected; viewModel?.LoadInitialData(); - viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas; viewModel.MainCanvas = ImagenEnTrabajoCanvas; // Inicializar ObjectHierarchyView diff --git a/ObjetosSim/Dinamicos/ucBotella.xaml b/ObjetosSim/Dinamicos/ucBotella.xaml index 8bc27a0..cd4b32c 100644 --- a/ObjetosSim/Dinamicos/ucBotella.xaml +++ b/ObjetosSim/Dinamicos/ucBotella.xaml @@ -1,15 +1,12 @@ - - + + - + + Stroke="{Binding ColorButton_oculto}" Fill="Gray" + Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" StrokeThickness="0.5" /> \ No newline at end of file diff --git a/ObjetosSim/Dinamicos/ucBotella.xaml.cs b/ObjetosSim/Dinamicos/ucBotella.xaml.cs index ca9433b..472da7c 100644 --- a/ObjetosSim/Dinamicos/ucBotella.xaml.cs +++ b/ObjetosSim/Dinamicos/ucBotella.xaml.cs @@ -93,6 +93,12 @@ namespace CtrEditor.ObjetosSim [property: Name("Porcentaje de Tracción")] private float porcentaje_Traccion; + [ObservableProperty] + [property: Category("Información")] + [property: Description("Indica si la botella está en un transporte con freno")] + [property: Name("En Transporte con Freno")] + private bool enTransporteConFreno; + [ObservableProperty] [property: Category("Simulación")] [property: Description("Masa del objeto en kg")] @@ -109,7 +115,7 @@ namespace CtrEditor.ObjetosSim } public void SetCentro(float x, float y) - { Left = x; Top = y; } + { Left = x - Diametro / 2; Top = y - Diametro / 2; } public void SetCentro(Vector2 centro) { @@ -144,27 +150,41 @@ namespace CtrEditor.ObjetosSim public override void UpdateGeometryStart() { - // Se llama antes de la simulacion - ActualizarGeometrias(); - SimGeometria?.SetDiameter(Diametro); + // Se llama cuando inicia la simulación - crear geometría si no existe + if (SimGeometria == null) + { + SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass); + } + else + { + ActualizarGeometrias(); + SimGeometria?.SetDiameter(Diametro); + SimGeometria?.SetMass(Mass); + } } + public override void UpdateGeometryStep() { - // Se llama antes de la simulacion - ActualizarGeometrias(); + // Se llama durante cada paso de la simulación + if (SimGeometria != null) + { + // Actualizar posición desde la simulación hacia WPF + SetCentro(SimGeometria.Center); + } } public override void UpdateControl(int elapsedMilliseconds) { SetCentro(SimGeometria.Center); + + // Sistema de colores jerarquizado para diferentes estados if (SimGeometria.isRestricted) - ColorButton_oculto = Brushes.Yellow; + ColorButton_oculto = Brushes.Yellow; // Estado restringido (prioridad alta) + else if (SimGeometria.isOnBrakeTransport) + ColorButton_oculto = Brushes.Blue; // En transporte con freno - NUEVO ESTADO + else if (SimGeometria.IsOnAnyTransport()) + ColorButton_oculto = Brushes.Red; // En transporte normal else - { - if (SimGeometria.IsOnAnyTransport()) - ColorButton_oculto = Brushes.Red; - else - ColorButton_oculto = Brushes.Gray; - } + ColorButton_oculto = Brushes.Gray; // Estado libre // Ha sido marcada para remover if (SimGeometria.Descartar) @@ -174,9 +194,10 @@ namespace CtrEditor.ObjetosSim if (!Preserve_Outside_Transport && !SimGeometria.IsOnAnyTransport()) RemoverDesdeSimulacion = true; - Velocidad_desde_simulacion = SimGeometria.Body.LinearVelocity.ToString(); - Inercia_desde_simulacion = SimGeometria.Body.Inertia; + Velocidad_desde_simulacion = SimGeometria.GetLinearVelocity().ToString(); + Inercia_desde_simulacion = SimGeometria.Mass; // En BEPU usamos masa en lugar de inercia directa Porcentaje_Traccion = SimGeometria.OverlapPercentage; + EnTransporteConFreno = SimGeometria.isOnBrakeTransport; // Actualizar estado de freno } public override void ucLoaded() diff --git a/ObjetosSim/Dinamicos/ucBotellaCuello.xaml.cs b/ObjetosSim/Dinamicos/ucBotellaCuello.xaml.cs index 751a152..a8fc856 100644 --- a/ObjetosSim/Dinamicos/ucBotellaCuello.xaml.cs +++ b/ObjetosSim/Dinamicos/ucBotellaCuello.xaml.cs @@ -80,6 +80,24 @@ namespace CtrEditor.ObjetosSim [property: Name("Inercia Simulación")] private float inercia_desde_simulacion; + [ObservableProperty] + [property: Category("Configuración")] + [property: Description("Conservar objeto cuando sale de transporte")] + [property: Name("Conservar Fuera de Transporte")] + private bool preserve_Outside_Transport; + + [ObservableProperty] + [property: Category("Información")] + [property: Description("Porcentaje de tracción con transporte")] + [property: Name("Porcentaje de Tracción")] + private float porcentaje_Traccion; + + [ObservableProperty] + [property: Category("Información")] + [property: Description("Indica si la botella está en un transporte con freno")] + [property: Name("En Transporte con Freno")] + private bool enTransporteConFreno; + [ObservableProperty] [property: Category("Simulación")] [property: Description("Masa de la botella")] @@ -140,19 +158,29 @@ namespace CtrEditor.ObjetosSim public override void UpdateControl(int elapsedMilliseconds) { SetCentro(SimGeometria.Center); + + // Sistema de colores jerarquizado para diferentes estados if (SimGeometria.isRestricted) - ColorButton_oculto = Brushes.Yellow; + ColorButton_oculto = Brushes.Yellow; // Estado restringido (prioridad alta) + else if (SimGeometria.isOnBrakeTransport) + ColorButton_oculto = Brushes.Blue; // En transporte con freno - NUEVO ESTADO + else if (SimGeometria.IsOnAnyTransport()) + ColorButton_oculto = Brushes.Red; // En transporte normal else - { - if (SimGeometria.isOnTransports > 0) - ColorButton_oculto = Brushes.Red; - else - ColorButton_oculto = Brushes.Gray; - } - if (SimGeometria.Descartar) // Ha sido marcada para remover + ColorButton_oculto = Brushes.Gray; // Estado libre + + // Ha sido marcada para remover + if (SimGeometria.Descartar) RemoverDesdeSimulacion = true; - Velocidad_desde_simulacion = SimGeometria.Body.LinearVelocity.ToString(); - Inercia_desde_simulacion = SimGeometria.Body.Inertia; + + // Eliminar la botella si esta fuera de un transporte + if (!Preserve_Outside_Transport && !SimGeometria.IsOnAnyTransport()) + RemoverDesdeSimulacion = true; + + Velocidad_desde_simulacion = SimGeometria.GetLinearVelocity().ToString(); + Inercia_desde_simulacion = SimGeometria.Mass; // En BEPU usamos masa en lugar de inercia directa + Porcentaje_Traccion = SimGeometria.OverlapPercentage; + EnTransporteConFreno = SimGeometria.isOnBrakeTransport; // Actualizar estado de freno } public override void ucLoaded() diff --git a/ObjetosSim/Emuladores/ucBottGenerator.xaml b/ObjetosSim/Emuladores/ucBottGenerator.xaml index 24fc082..2ef664e 100644 --- a/ObjetosSim/Emuladores/ucBottGenerator.xaml +++ b/ObjetosSim/Emuladores/ucBottGenerator.xaml @@ -1,21 +1,17 @@  - + 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" mc:Ignorable="d" + xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"> - + - + diff --git a/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs b/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs index 7119127..8843f03 100644 --- a/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs +++ b/ObjetosSim/Emuladores/ucBottGenerator.xaml.cs @@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using System.Diagnostics; using CtrEditor.FuncionesBase; using System.ComponentModel; +using DocumentFormat.OpenXml.Spreadsheet; namespace CtrEditor.ObjetosSim { diff --git a/ObjetosSim/Estaticos/ucDescarte.xaml b/ObjetosSim/Estaticos/ucDescarte.xaml index d54f141..206b27c 100644 --- a/ObjetosSim/Estaticos/ucDescarte.xaml +++ b/ObjetosSim/Estaticos/ucDescarte.xaml @@ -1,42 +1,31 @@ - - + + - - + + - + - - + + diff --git a/ObjetosSim/Estaticos/ucDescarte.xaml.cs b/ObjetosSim/Estaticos/ucDescarte.xaml.cs index d9f2fb0..b4c7509 100644 --- a/ObjetosSim/Estaticos/ucDescarte.xaml.cs +++ b/ObjetosSim/Estaticos/ucDescarte.xaml.cs @@ -3,11 +3,11 @@ using LibS7Adv; using CtrEditor.Simulacion; using System.Windows; using System.Windows.Controls; -using System.Numerics; using System.Windows.Media.Animation; using CommunityToolkit.Mvvm.ComponentModel; using CtrEditor.FuncionesBase; using System.ComponentModel; +using System.Numerics; namespace CtrEditor.ObjetosSim { /// diff --git a/ObjetosSim/Estaticos/ucGuia.xaml.cs b/ObjetosSim/Estaticos/ucGuia.xaml.cs index cc1d71e..fdc9bed 100644 --- a/ObjetosSim/Estaticos/ucGuia.xaml.cs +++ b/ObjetosSim/Estaticos/ucGuia.xaml.cs @@ -5,6 +5,7 @@ using LibS7Adv; using CtrEditor.Simulacion; using CtrEditor.FuncionesBase; using System.ComponentModel; +using System.Numerics; namespace CtrEditor.ObjetosSim { @@ -32,14 +33,21 @@ namespace CtrEditor.ObjetosSim [ObservableProperty] [property: Category("Configuración")] - [property: Description("Alto de la guía en metros")] - [property: Name("Alto de la Guía")] + [property: Description("Grosor de la guía en metros")] + [property: Name("Grosor de la Guía")] public float altoGuia; private void ActualizarGeometrias() { if (_visualRepresentation is ucGuia uc) + { + // Actualizar las propiedades del objeto de simulación + if (SimGeometria != null) + { + SimGeometria.UpdateProperties(Ancho, AltoGuia, Angulo); + } UpdateOrCreateLine(SimGeometria, uc.Guia); + } } public override void OnMoveResizeRotate() @@ -81,7 +89,21 @@ namespace CtrEditor.ObjetosSim simulationManager?.Remove(SimGeometria); } + public override void AnchoChanged(float value) + { + ActualizarGeometrias(); + } + public override void AnguloChanged(float value) + { + ActualizarGeometrias(); + } + + // Método llamado cuando cambia AltoGuia + partial void OnAltoGuiaChanged(float value) + { + ActualizarGeometrias(); + } } public partial class ucGuia : UserControl, IDataContainer diff --git a/ObjetosSim/Estaticos/ucTransporteCurva.xaml b/ObjetosSim/Estaticos/ucTransporteCurva.xaml index 7697457..f662804 100644 --- a/ObjetosSim/Estaticos/ucTransporteCurva.xaml +++ b/ObjetosSim/Estaticos/ucTransporteCurva.xaml @@ -1,11 +1,10 @@  + 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:localuc="clr-namespace:CtrEditor.ObjetosSim.UserControls" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim" + mc:Ignorable="d"> @@ -13,7 +12,9 @@ - + diff --git a/ObjetosSim/Estaticos/ucTransporteCurva.xaml.cs b/ObjetosSim/Estaticos/ucTransporteCurva.xaml.cs index bc5141c..21bf2d3 100644 --- a/ObjetosSim/Estaticos/ucTransporteCurva.xaml.cs +++ b/ObjetosSim/Estaticos/ucTransporteCurva.xaml.cs @@ -7,6 +7,7 @@ using CtrEditor.Simulacion; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using CtrEditor.FuncionesBase; using System.Text.Json.Serialization; +using System.Numerics; namespace CtrEditor.ObjetosSim { @@ -93,6 +94,50 @@ namespace CtrEditor.ObjetosSim ActualizarGeometrias(); } + partial void OnRadioInternoChanged(float value) + { + // Ensure radioInterno is always less than radioExterno + if (value >= RadioExterno) + { + RadioInterno = RadioExterno * 0.75f; // Maintain proportion + return; + } + + ActualizarGeometrias(); + } + + partial void OnArco_en_gradosChanged(float value) + { + OnPropertyChanged(nameof(AnguloFinal)); + ActualizarGeometrias(); + } + + // Manejar cambios de posición usando métodos virtuales de osBase + public override void LeftChanging(float oldValue, float newValue) + { + base.LeftChanging(oldValue, newValue); + ActualizarPosicionBEPU(); + } + + public override void TopChanging(float oldValue, float newValue) + { + base.TopChanging(oldValue, newValue); + ActualizarPosicionBEPU(); + } + + private void ActualizarPosicionBEPU() + { + if (Simulation_TransporteCurva != null) + { + // ✅ CORRIGIDO: startAngle = Angulo, endAngle = Angulo + Arco_en_grados (como Aether) + var topLeft = new Vector2(Left, Top); + Simulation_TransporteCurva.Create(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados, topLeft, 0); + + // Sincronizar con la visualización 3D tras la actualización + simulationManager?.Visualization3DManager?.SynchronizeWorld(); + } + } + [ObservableProperty] [property: Category("Configuración")] [property: Description("Radio interior de la curva en metros")] @@ -140,6 +185,7 @@ namespace CtrEditor.ObjetosSim public override void AnguloChanged(float value) { OnPropertyChanged(nameof(AnguloFinal)); + ActualizarGeometrias(); } [ObservableProperty] @@ -156,7 +202,15 @@ namespace CtrEditor.ObjetosSim { if (_visualRepresentation is ucTransporteCurva uc) { - UpdateCurve(Simulation_TransporteCurva, RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados); + if (Simulation_TransporteCurva != null) + { + // ✅ CORRIGIDO: startAngle = Angulo, endAngle = Angulo + Arco_en_grados (como Aether) + var topLeft = new Vector2(Left, Top); + Simulation_TransporteCurva.Create(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados, topLeft, 0); + + // Sincronizar con la visualización 3D tras la actualización + simulationManager?.Visualization3DManager?.SynchronizeWorld(); + } SetSpeed(); } } @@ -209,6 +263,9 @@ namespace CtrEditor.ObjetosSim // Ensure radioInterno is always less than radioExterno if (RadioInterno >= RadioExterno) RadioInterno = RadioExterno * 0.75f; + + // Actualizar geometrías en BEPU después del redimensionamiento + ActualizarGeometrias(); } @@ -256,7 +313,9 @@ namespace CtrEditor.ObjetosSim if (_visualRepresentation is ucTransporteCurva uc) { - Simulation_TransporteCurva = AddCurve(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados); + // ✅ CORRIGIDO: startAngle = Angulo, endAngle = Angulo + Arco_en_grados (como Aether) + var topLeft = new Vector2(Left, Top); + Simulation_TransporteCurva = simulationManager?.AddCurve(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados, topLeft, 0); CrearAnimacionStoryBoardTrasnporteCircular(uc.Transporte.TransportePath, InvertirDireccion, Angulo); } } diff --git a/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs b/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs index 8add54b..2ad76ef 100644 --- a/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs +++ b/ObjetosSim/Estaticos/ucTransporteCurvaGuias.xaml.cs @@ -8,6 +8,7 @@ using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using CtrEditor.FuncionesBase; using System.Text.Json.Serialization; using System.Windows.Media; +using System.Numerics; namespace CtrEditor.ObjetosSim { @@ -302,7 +303,7 @@ namespace CtrEditor.ObjetosSim float pasoAngular = rangoAngular / NumeroSegmentosGuias; // Obtener el centro una vez para todo el método - nkast.Aether.Physics2D.Common.Vector2 centro = GetCurveCenterInMeter(RadioExterno); + Vector2 centro = GetCurveCenterInMeter(RadioExterno); // Crear segmentos para guía superior (externa) for (int i = 0; i < NumeroSegmentosGuias; i++) @@ -310,12 +311,12 @@ namespace CtrEditor.ObjetosSim float angulo1 = anguloInicioRad + i * pasoAngular; float angulo2 = anguloInicioRad + (i + 1) * pasoAngular; - nkast.Aether.Physics2D.Common.Vector2 punto1 = new nkast.Aether.Physics2D.Common.Vector2( + Vector2 punto1 = new Vector2( radioGuiaSuperior * (float)Math.Cos(angulo1), radioGuiaSuperior * (float)Math.Sin(angulo1) ); - nkast.Aether.Physics2D.Common.Vector2 punto2 = new nkast.Aether.Physics2D.Common.Vector2( + Vector2 punto2 = new Vector2( radioGuiaSuperior * (float)Math.Cos(angulo2), radioGuiaSuperior * (float)Math.Sin(angulo2) ); @@ -334,12 +335,12 @@ namespace CtrEditor.ObjetosSim float angulo1 = anguloInicioRad + i * pasoAngular; float angulo2 = anguloInicioRad + (i + 1) * pasoAngular; - nkast.Aether.Physics2D.Common.Vector2 punto1 = new nkast.Aether.Physics2D.Common.Vector2( + Vector2 punto1 = new Vector2( radioGuiaInferior * (float)Math.Cos(angulo1), radioGuiaInferior * (float)Math.Sin(angulo1) ); - nkast.Aether.Physics2D.Common.Vector2 punto2 = new nkast.Aether.Physics2D.Common.Vector2( + Vector2 punto2 = new Vector2( radioGuiaInferior * (float)Math.Cos(angulo2), radioGuiaInferior * (float)Math.Sin(angulo2) ); diff --git a/ObjetosSim/Estaticos/ucTransporteGuias.xaml b/ObjetosSim/Estaticos/ucTransporteGuias.xaml index 83334eb..7922b33 100644 --- a/ObjetosSim/Estaticos/ucTransporteGuias.xaml +++ b/ObjetosSim/Estaticos/ucTransporteGuias.xaml @@ -1,17 +1,17 @@  + 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:vm="clr-namespace:CtrEditor.ObjetosSim" + mc:Ignorable="d"> - + - + @@ -24,41 +24,42 @@ - + - - - - + + + + - - - + + + - - diff --git a/ObjetosSim/Estaticos/ucTransporteGuias.xaml.cs b/ObjetosSim/Estaticos/ucTransporteGuias.xaml.cs index 48dffdd..0d708a7 100644 --- a/ObjetosSim/Estaticos/ucTransporteGuias.xaml.cs +++ b/ObjetosSim/Estaticos/ucTransporteGuias.xaml.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -8,6 +9,7 @@ using CtrEditor.Simulacion; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using CtrEditor.FuncionesBase; using System.Text.Json.Serialization; +using Siemens.Simatic.Simulation.Runtime; namespace CtrEditor.ObjetosSim { @@ -91,7 +93,7 @@ namespace CtrEditor.ObjetosSim [property: Category("Enlace PLC")] [property: Description("Motor enlazado al transporte")] [property: Name("Motor Enlazado")] - [property: ItemsSource(typeof(osBaseItemsSource))] + //[property: ItemsSource(typeof(osBaseItemsSource))] string id_Motor; [JsonIgnore] @@ -99,24 +101,24 @@ namespace CtrEditor.ObjetosSim partial void OnId_MotorChanged(string value) { - if (Motor != null && motorPropertyChangedHandler != null) - Motor.PropertyChanged -= motorPropertyChangedHandler; + //if (Motor != null && motorPropertyChangedHandler != null) + // Motor.PropertyChanged -= motorPropertyChangedHandler; - if (_mainViewModel != null && !string.IsNullOrEmpty(value)) - { - Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value); - if (Motor != null) - { - motorPropertyChangedHandler = (sender, e) => - { - if (e.PropertyName == nameof(osVMmotorSim.Nombre)) - { - Id_Motor = ((osVMmotorSim)sender).Nombre; - } - }; - Motor.PropertyChanged += motorPropertyChangedHandler; - } - } + //if (_mainViewModel != null && !string.IsNullOrEmpty(value)) + //{ + // Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value); + // if (Motor != null) + // { + // motorPropertyChangedHandler = (sender, e) => + // { + // if (e.PropertyName == nameof(osVMmotorSim.Nombre)) + // { + // Id_Motor = ((osVMmotorSim)sender).Nombre; + // } + // }; + // Motor.PropertyChanged += motorPropertyChangedHandler; + // } + //} } public override void AltoChanged(float value) @@ -124,6 +126,16 @@ namespace CtrEditor.ObjetosSim ActualizarGeometrias(); } + public override void AnchoChanged(float value) + { + ActualizarGeometrias(); + } + + public override void AnguloChanged(float value) + { + ActualizarGeometrias(); + } + [ObservableProperty] [property: Category("Configuración")] [property: Description("Actuar como freno")] @@ -132,8 +144,14 @@ namespace CtrEditor.ObjetosSim partial void OnEsFrenoChanged(bool value) { + System.Diagnostics.Debug.WriteLine($"[🔧 FRENO CAMBIO] Transporte '{Nombre}' - EsFreno cambiado a: {value}"); + ActualizarGeometrias(); + + // Verificar que la asignación se realizó correctamente if (SimGeometria != null) - SimGeometria.isBrake = value; + { + System.Diagnostics.Debug.WriteLine($"[✅ FRENO SYNC] SimGeometria.isBrake = {SimGeometria.isBrake}"); + } } [ObservableProperty] @@ -142,6 +160,11 @@ namespace CtrEditor.ObjetosSim [property: Name("Coeficiente Fricción")] public float frictionCoefficient; + partial void OnFrictionCoefficientChanged(float value) + { + ActualizarGeometrias(); + } + [ObservableProperty] [property: Category("Configuración")] [property: Description("Velocidad máxima a 50Hz")] @@ -160,32 +183,132 @@ namespace CtrEditor.ObjetosSim [property: Name("En Marcha")] public bool esMarcha; + [ObservableProperty] + [property: Category("Información")] + [property: Description("Información sobre botellas en el transporte con freno")] + [property: Name("Info Botellas Freno")] + public string infoBotellasFreno = "Sin información"; + + /// + /// Actualiza la información de botellas en el transporte con freno + /// + public void ActualizarInfoBotellasFreno() + { + if (SimGeometria?.isBrake == true && simulationManager != null) + { + // Contar botellas marcadas como en transporte con freno + var botellasEnFreno = simulationManager.Cuerpos + .OfType() + .Where(b => b.isOnBrakeTransport) + .Count(); + + InfoBotellasFreno = $"Botellas con freno: {botellasEnFreno}"; + } + else if (SimGeometria?.isBrake == false) + { + InfoBotellasFreno = "Transporte SIN freno"; + } + else + { + InfoBotellasFreno = "Sin información"; + } + } + [ObservableProperty] [property: Category("Configuración")] [property: Description("Distancia entre guías")] [property: Name("Distancia")] private float distance; + partial void OnDistanceChanged(float value) + { + ActualizarGeometrias(); + } + [ObservableProperty] [property: Category("Configuración")] [property: Description("Alto de las guías")] [property: Name("Alto Guía")] private float altoGuia; + partial void OnAltoGuiaChanged(float value) + { + ActualizarGeometrias(); + } + private void ActualizarGeometrias() { if (_visualRepresentation is ucTransporteGuias uc) { UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo); - UpdateOrCreateLine(Guia_Superior, uc.GuiaSuperior); - UpdateOrCreateLine(Guia_Inferior, uc.GuiaInferior); - SimGeometria.DistanceGuide2Guide = Alto; - SimGeometria.isBrake = esFreno; + // Actualizar guías con método específico para transporte + UpdateTransportGuide(Guia_Superior, uc.GuiaSuperior, isTopGuide: true); + UpdateTransportGuide(Guia_Inferior, uc.GuiaInferior, isTopGuide: false); + + if (SimGeometria != null) + { + SimGeometria.TransportWithGuides = true; + SimGeometria.DistanceGuide2Guide = Distance; + SimGeometria.isBrake = EsFreno; // Usar propiedad generada + SimGeometria.Friction = FrictionCoefficient; // Usar propiedad generada + + System.Diagnostics.Debug.WriteLine($"[🔄 ACTUALIZAR GEOMETRIAS] Transporte '{Nombre}' - TransportWithGuides={SimGeometria.TransportWithGuides}, DistanceGuide2Guide={SimGeometria.DistanceGuide2Guide:F3}, isBrake={SimGeometria.isBrake}, Friction={SimGeometria.Friction:F3}, Speed={SimGeometria.Speed:F1}"); + + // Actualizar información de botellas si es un transporte con freno + ActualizarInfoBotellasFreno(); + } + SetSpeed(); } } + /// + /// Actualiza una guía específica del transporte (superior o inferior) + /// + /// Objeto de simulación de la guía + /// Rectángulo WPF de la guía + /// true para guía superior, false para inferior + private void UpdateTransportGuide(simGuia simGuia, System.Windows.Shapes.Rectangle wpfRect, bool isTopGuide) + { + if (simGuia != null && wpfRect != null) + { + // Actualizar propiedades específicas de la guía + simGuia.UpdateProperties(Ancho, AltoGuia, Angulo); + + // Calcular posición usando el rectángulo WPF actual + var topLeft2D = GetRectangleTopLeft(wpfRect); + + // Crear/actualizar la guía con las dimensiones correctas + simGuia.Create(Ancho, AltoGuia, topLeft2D, Angulo); + + System.Diagnostics.Debug.WriteLine($"[UpdateTransportGuide] {(isTopGuide ? "Superior" : "Inferior")} - Pos: ({topLeft2D.X:F3}, {topLeft2D.Y:F3}), Ancho: {Ancho:F3}, Alto: {AltoGuia:F3}, Ángulo: {Angulo:F1}°"); + } + } + + /// + /// Crea una guía específica del transporte (superior o inferior) + /// + /// Rectángulo WPF de la guía + /// true para guía superior, false para inferior + /// Objeto simGuia creado + private simGuia CreateTransportGuide(System.Windows.Shapes.Rectangle wpfRect, bool isTopGuide) + { + if (wpfRect != null) + { + // Calcular posición usando el rectángulo WPF actual + var topLeft2D = GetRectangleTopLeft(wpfRect); + + // Crear la guía con las dimensiones del transporte + var simGuia = simulationManager.AddLine(Ancho, AltoGuia, topLeft2D, Angulo); + + System.Diagnostics.Debug.WriteLine($"[CreateTransportGuide] {(isTopGuide ? "Superior" : "Inferior")} creada - Pos: ({topLeft2D.X:F3}, {topLeft2D.Y:F3}), Ancho: {Ancho:F3}, Alto: {AltoGuia:F3}, Ángulo: {Angulo:F1}°"); + + return simGuia; + } + return null; + } + public override void OnMoveResizeRotate() { ActualizarGeometrias(); @@ -196,7 +319,7 @@ namespace CtrEditor.ObjetosSim Ancho = 1; Alto = 0.10f; AltoGuia = 0.03f; - Distance = 0.01f; + Distance = 0.5f; Tag_ReleActivatedMotor = "1"; } @@ -214,12 +337,18 @@ namespace CtrEditor.ObjetosSim public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) { - if (Motor != null) - if (Motor is osVMmotorSim id_motor) - if (LeerBitTag(Tag_ReleActivatedMotor)) - VelocidadActual = id_motor.Velocidad; - else - VelocidadActual = 0; + //if (Motor != null) + // if (Motor is osVMmotorSim id_motor) + // if (LeerBitTag(Tag_ReleActivatedMotor)) + // VelocidadActual = id_motor.Velocidad; + // else + // VelocidadActual = 0; + + // Actualizar información de botellas en tiempo real si es un transporte con freno + if (EsFreno) + { + ActualizarInfoBotellasFreno(); + } } public override void ucLoaded() @@ -233,12 +362,22 @@ namespace CtrEditor.ObjetosSim if (_visualRepresentation is ucTransporteGuias uc) { SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo); - SimGeometria.TransportWithGuides = true; - SimGeometria.DistanceGuide2Guide = Alto; - Guia_Superior = AddLine(simulationManager, uc.GuiaSuperior); - Guia_Inferior = AddLine(simulationManager, uc.GuiaInferior); + + // CORREGIR: Asegurar que todas las propiedades se inicialicen correctamente + if (SimGeometria != null) + { + SimGeometria.TransportWithGuides = true; // Siempre true para TransporteGuias + SimGeometria.DistanceGuide2Guide = Distance; // Usar Distance en lugar de Alto + SimGeometria.isBrake = EsFreno; // Usar propiedad generada + SimGeometria.Friction = FrictionCoefficient; // Usar propiedad generada + } + + // Crear guías usando método específico para transporte + Guia_Superior = CreateTransportGuide(uc.GuiaSuperior, isTopGuide: true); + Guia_Inferior = CreateTransportGuide(uc.GuiaInferior, isTopGuide: false); CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion); + SetSpeed(); // Aplicar velocidad inicial } OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor } diff --git a/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs b/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs index fe4aac1..8bb31fe 100644 --- a/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs +++ b/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs @@ -7,6 +7,7 @@ using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using System.ComponentModel; using CtrEditor.FuncionesBase; using System.Text.Json.Serialization; +using System.Numerics; namespace CtrEditor.ObjetosSim { diff --git a/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs b/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs index ed08bfc..e876e09 100644 --- a/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs +++ b/ObjetosSim/SensoresComandos/ucPhotocell.xaml.cs @@ -1,5 +1,5 @@ using CtrEditor.Simulacion; -using LibS7Adv; +using LibS7Adv; // Using stub implementation using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -9,6 +9,7 @@ using CtrEditor.FuncionesBase; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute; using System.ComponentModel; +using System.Numerics; namespace CtrEditor.ObjetosSim { @@ -34,7 +35,14 @@ namespace CtrEditor.ObjetosSim public override string Nombre { get => nombre; - set => SetProperty(ref nombre, value); + set + { + if (SetProperty(ref nombre, value)) + { + // Asegurar que siempre se notifique el cambio, incluso en inicialización + OnPropertyChanged(); + } + } } [ObservableProperty] @@ -200,6 +208,10 @@ namespace CtrEditor.ObjetosSim Frecuency = 0; timer = new Stopwatch(); timer.Start(); + Color = Brushes.Black; + + // Forzar notificación de la propiedad Nombre para asegurar binding inicial + OnPropertyChanged(nameof(Nombre)); } public override void UpdateGeometryStart() @@ -213,7 +225,7 @@ namespace CtrEditor.ObjetosSim if (DetectarCuello) LuzCortada = Simulation_Photocell.LuzCortadaNeck; else - LuzCortada = Simulation_Photocell.LuzCortada > 0; + LuzCortada = Simulation_Photocell.LuzCortada; // Ahora es bool directamente } public override void UpdatePLCPrimerCiclo() { @@ -232,7 +244,7 @@ namespace CtrEditor.ObjetosSim base.ucLoaded(); if (_visualRepresentation is ucPhotocell uc) - Simulation_Photocell = AddBarrera(simulationManager, uc.Photocell, Alto, Ancho, Angulo, DetectarCuello); + Simulation_Photocell = AddBarrera(simulationManager, uc.Photocell, Ancho_Haz_De_Luz, Ancho, Angulo, DetectarCuello); } public override void ucUnLoaded() { diff --git a/ObjetosSim/UserControlFactory.cs b/ObjetosSim/UserControlFactory.cs index 362e2d9..88d9d6c 100644 --- a/ObjetosSim/UserControlFactory.cs +++ b/ObjetosSim/UserControlFactory.cs @@ -76,7 +76,7 @@ namespace CtrEditor.ObjetosSim return instance; } - public static void AssignDatos(UserControl userControl, osBase datos, SimulationManagerFP simulationManager) + public static void AssignDatos(UserControl userControl, osBase datos, SimulationManagerBEPU simulationManager) { if (userControl is IDataContainer dataContainer) { diff --git a/ObjetosSim/UserControls/CircularSegment.xaml b/ObjetosSim/UserControls/CircularSegment.xaml index dbe6441..81caf47 100644 --- a/ObjetosSim/UserControls/CircularSegment.xaml +++ b/ObjetosSim/UserControls/CircularSegment.xaml @@ -1,30 +1,29 @@  + 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:local="clr-namespace:CtrEditor.ObjetosSim.UserControls" mc:Ignorable="d" Name="circularSegmentControl"> - + - - + + - + diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs index 3089a9b..644b457 100644 --- a/ObjetosSim/osBase.cs +++ b/ObjetosSim/osBase.cs @@ -16,7 +16,6 @@ using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Shapes; -using Tesseract; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using Application = System.Windows.Application; using ItemCollection = Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection; @@ -44,16 +43,16 @@ namespace CtrEditor.ObjetosSim { private MainViewModel? _mainViewModel; private UserControl? VisualRepresentation; - private SimulationManagerFP? simulationManager; + private SimulationManagerBEPU? simulationManager; - public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerFP c) + public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerBEPU c) { _mainViewModel = a; VisualRepresentation = b; simulationManager = c; } - public void DataRestoreAfterSerialize(out MainViewModel a, out UserControl b, out SimulationManagerFP c) + public void DataRestoreAfterSerialize(out MainViewModel a, out UserControl b, out SimulationManagerBEPU c) { a = _mainViewModel; b = VisualRepresentation; @@ -71,6 +70,7 @@ namespace CtrEditor.ObjetosSim [JsonIgnore] private System.Threading.Timer timer = null; + [ObservableProperty] [property: JsonIgnore] [property: Hidden] @@ -113,6 +113,7 @@ namespace CtrEditor.ObjetosSim // Actualizar posición relativa si el movimiento no viene del FramePlate UpdateFramePlateRelativePosition(); } + public virtual void LeftChanging(float oldValue, float newValue) { } [ObservableProperty] @@ -566,89 +567,6 @@ namespace CtrEditor.ObjetosSim } - public string CaptureImageAreaAndDoOCR(float Left, float Top, float Ancho, float Alto, float Angulo = 0, bool ShowPreview = false) - { - if (_mainViewModel?.MainCanvas.Children[0] is Image imagenDeFondo) - { - if (imagenDeFondo.Source is BitmapSource bitmapSource) - { - float originalDpiX = (float)bitmapSource.DpiX; - float originalDpiY = (float)bitmapSource.DpiY; - - float canvasDpiX = 96; - float canvasDpiY = 96; - - float scaleFactorX = originalDpiX / canvasDpiX; - float scaleFactorY = originalDpiY / canvasDpiY; - - int x = (int)MeterToPixels(Left * scaleFactorX); - int y = (int)MeterToPixels(Top * scaleFactorY); - int width = (int)MeterToPixels(Ancho * scaleFactorX); - int height = (int)MeterToPixels(Alto * scaleFactorY); - - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x + width > bitmapSource.PixelWidth) width = bitmapSource.PixelWidth - x; - if (y + height > bitmapSource.PixelHeight) height = bitmapSource.PixelHeight - y; - - CroppedBitmap croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect(x, y, width, height)); - - TransformedBitmap transformedBitmap = new TransformedBitmap(); - transformedBitmap.BeginInit(); - transformedBitmap.Source = croppedBitmap; - - if (Angulo != 0) - { - // TransformedBitmap only accepts rotations in 90-degree increments - // Round to nearest 90 degrees: 0, 90, 180, or 270 - double normalizedAngle = Math.Round(Angulo / 90.0) * 90.0; - RotateTransform rotateTransform = new RotateTransform(-normalizedAngle); - transformedBitmap.Transform = rotateTransform; - } - - transformedBitmap.EndInit(); - - PngBitmapEncoder encoder = new PngBitmapEncoder(); - encoder.Frames.Add(BitmapFrame.Create(transformedBitmap)); - - using (MemoryStream memoryStream = new MemoryStream()) - { - encoder.Save(memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - - if (ShowPreview) ShowPreviewWindow(memoryStream); - - using (var bmp = new System.Drawing.Bitmap(memoryStream)) - { - int targetDpi = 400; - var resizedBmp = new System.Drawing.Bitmap(bmp, new System.Drawing.Size(bmp.Width * targetDpi / (int)originalDpiX, bmp.Height * targetDpi / (int)originalDpiY)); - - using (var msResized = new MemoryStream()) - { - resizedBmp.Save(msResized, System.Drawing.Imaging.ImageFormat.Png); - msResized.Seek(0, SeekOrigin.Begin); - - using (var img = Pix.LoadFromMemory(msResized.ToArray())) - { - // Use AppDomain.CurrentDomain.BaseDirectory to ensure we find Tesseract in the application directory - string tesseractPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tesseract"); - using (var engine = new TesseractEngine(tesseractPath, "eng", EngineMode.Default)) - { - // Configuraciones para mejorar el OCR de una sola letra - engine.SetVariable("tessedit_char_whitelist", " ABCDEFGHIJKLMNÑOPQRSTUVWXYZabcdefghijklmnñopqrstuvwxyz0123456789-./"); // Lista blanca de caracteres - var result = engine.Process(img); - return result.GetText(); - } - } - } - } - } - } - } - return ""; - } - - // Reemplaza el método existente CaptureImageAreaAndDoOCR con esta implementación public string CaptureImageAreaAndDoOCRPPaddle(float Left, float Top, float Ancho, float Alto, float Angulo = 0, bool ShowPreview = false) { @@ -768,7 +686,6 @@ namespace CtrEditor.ObjetosSim [property: Name("Habilitado en Todas Páginas")] private bool enable_On_All_Pages; - partial void OnEnable_On_All_PagesChanged(bool value) { // Si se está desactivando el modo global @@ -785,7 +702,6 @@ namespace CtrEditor.ObjetosSim } } - // Local Data for Global Objects [NotifyPropertyChangedFor(nameof(Show_On_This_Page))] [ObservableProperty] @@ -1050,6 +966,7 @@ namespace CtrEditor.ObjetosSim /// public virtual void UpdateControl(int elapsedMilliseconds) { } + /// /// Se llama antes de comenzar la simulacion con el boton de Iniciar simulacion. /// La idea es actualizar los objetos en el motor fisico antes de comenzar la simulacion fisica. @@ -1111,7 +1028,7 @@ namespace CtrEditor.ObjetosSim /// Link al Simualdor fisico. /// [JsonIgnore] - public SimulationManagerFP simulationManager; + public SimulationManagerBEPU simulationManager; /// /// Prepara la clase para ser serializable poniendo a null los objetos que tienen referencias circulares @@ -1602,56 +1519,99 @@ namespace CtrEditor.ObjetosSim return new Vector2((topLeft.X + bottomRight.X) / 2, (topLeft.Y + bottomRight.Y) / 2); } + public Vector2 GetRectangleTopLeft(Rectangle wpfRect) + { + var coords = GetRectangleCoordinatesInMeter(wpfRect); + return coords.TopLeft; + } public void UpdateRectangle(simTransporte simRect, Rectangle wpfRect, float Alto, float Ancho, float Angulo) { if (simRect != null) - simRect.Create(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo); + { + var topLeft2D = GetRectangleTopLeft(wpfRect); + // simRect.Create maneja internamente la conversión a 3D con pivot correcto + simRect.Create(Ancho, Alto, topLeft2D, Angulo); + } } public void UpdateRectangle(simBarrera simRect, Rectangle wpfRect, float Alto, float Ancho, float Angulo) { if (simRect != null) - simRect.Create(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo); + { + var topLeft2D = GetRectangleTopLeft(wpfRect); + // simRect.Create maneja internamente la conversión a 3D con pivot correcto + simRect.Create(Ancho, Alto, topLeft2D, Angulo); + } } + // Nota: simCurve no está implementado en BEPU, estos métodos están comentados por compatibilidad + /* public void UpdateCurve(simCurve curva, float RadioInterno, float RadioExterno, float startAngle, float endAngle) { - curva.Create(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno)); + var center2D = GetCurveCenterInMeter(RadioExterno); + var center3D = new Vector3(center2D.X, center2D.Y, 0); + curva.Create(RadioInterno, RadioExterno, startAngle, endAngle, center3D); } public simCurve AddCurve(float RadioInterno, float RadioExterno, float startAngle, float endAngle) { - return simulationManager.AddCurve(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno)); + var center2D = GetCurveCenterInMeter(RadioExterno); + var center3D = new Vector3(center2D.X, center2D.Y, 0); + return simulationManager.AddCurve(RadioInterno, RadioExterno, startAngle, endAngle, center3D); + } + */ + + public simTransporte AddRectangle(SimulationManagerBEPU simulationManager, Rectangle wpfRect, float Alto, float Ancho, float Angulo) + { + var topLeft2D = GetRectangleTopLeft(wpfRect); + return simulationManager.AddRectangle(Ancho, Alto, topLeft2D, Angulo); } - public simTransporte AddRectangle(SimulationManagerFP simulationManager, Rectangle wpfRect, float Alto, float Ancho, float Angulo) + public simBarrera AddBarrera(SimulationManagerBEPU simulationManager, Rectangle wpfRect, float Alto, float Ancho, float Angulo, bool detectarCuello) { - return simulationManager.AddRectangle(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo); - } - - public simBarrera AddBarrera(SimulationManagerFP simulationManager, Rectangle wpfRect, float Alto, float Ancho, float Angulo, bool detectarCuello) - { - return simulationManager.AddBarrera(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo, detectarCuello); + var topLeft2D = GetRectangleTopLeft(wpfRect); + return simulationManager.AddBarrera(Ancho, Alto, topLeft2D, Angulo, detectarCuello); } public void UpdateOrCreateLine(simGuia simGuia, Rectangle wpfRect) { if (simGuia != null) { + // Usar el mismo sistema que transportes: Top-Left + Ángulo + var topLeft2D = GetRectangleTopLeft(wpfRect); - var coords = GetCenterLineVectors(wpfRect); - - // Crear o actualizar simRectangle - simGuia.Create(coords.Start, coords.End); // asumiendo que el ángulo inicial es 0 + // Actualizar las propiedades desde el objeto osGuia + if (this is osGuia guiaObj) + { + simGuia.UpdateProperties(guiaObj.Ancho, guiaObj.AltoGuia, guiaObj.Angulo); + // Crear usando Top-Left + dimensiones + ángulo + simGuia.Create(guiaObj.Ancho, guiaObj.AltoGuia, topLeft2D, guiaObj.Angulo); + } } } - public simGuia AddLine(SimulationManagerFP simulationManager, Rectangle wpfRect) + public simGuia AddLine(SimulationManagerBEPU simulationManager, Rectangle wpfRect) { - var coords = GetCenterLineVectors(wpfRect); - return simulationManager.AddLine(coords.Start, coords.End); + // Usar el mismo sistema que transportes: Top-Left + Ángulo + var topLeft2D = GetRectangleTopLeft(wpfRect); + + // Obtener propiedades desde el objeto osGuia + float ancho = 1.0f; + float altoGuia = 0.05f; + float angulo = 0f; + + if (this is osGuia guiaObj) + { + ancho = guiaObj.Ancho; + altoGuia = guiaObj.AltoGuia; + angulo = guiaObj.Angulo; + } + + var simGuia = simulationManager.AddLine(ancho, altoGuia, topLeft2D, angulo); + + return simGuia; } public ImageSource ImageFromPath(string value) @@ -1717,7 +1677,6 @@ namespace CtrEditor.ObjetosSim } } - public class UniqueId { public int Value { get; set; } diff --git a/Serialization/StateSerializer.cs b/Serialization/StateSerializer.cs index afe4ebc..b6b0462 100644 --- a/Serialization/StateSerializer.cs +++ b/Serialization/StateSerializer.cs @@ -14,9 +14,9 @@ namespace CtrEditor.Serialization { private readonly DatosDeTrabajo _datosDeTrabajo; private readonly MainViewModel _mainViewModel; - private readonly SimulationManagerFP _simulationManager; + private readonly SimulationManagerBEPU _simulationManager; - public StateSerializer(MainViewModel mainViewModel, DatosDeTrabajo datosDeTrabajo, SimulationManagerFP simulationManager) + public StateSerializer(MainViewModel mainViewModel, DatosDeTrabajo datosDeTrabajo, SimulationManagerBEPU simulationManager) { _mainViewModel = mainViewModel; _datosDeTrabajo = datosDeTrabajo; diff --git a/SimulationFluidsViewModel.cs b/SimulationFluidsViewModel.cs deleted file mode 100644 index ef40980..0000000 --- a/SimulationFluidsViewModel.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Diagnostics; -using System.Windows.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using CtrEditor.Simulacion.Fluids; -using System.Numerics; -using CtrEditor.ObjetosSim; - -namespace CtrEditor -{ - /// - /// ViewModel para controlar la simulación de fluidos de forma independiente - /// - public partial class SimulationFluidsViewModel : ObservableObject - { - private MainViewModel _mainViewModel; - private readonly DispatcherTimer _timerSimulacionFluidos; - private Stopwatch _stopwatch; - private double _lastUpdateTime; - - // Propiedades observables - [ObservableProperty] - private bool isFluidSimulationRunning; - - [ObservableProperty] - private float fps; - - [ObservableProperty] - private int particulasCount; - - /// - /// Constructor - /// - /// Referencia al ViewModel principal - public SimulationFluidsViewModel(MainViewModel mainViewModel) - { - _mainViewModel = mainViewModel; - - // Inicializar timer para simulación de fluidos - _timerSimulacionFluidos = new DispatcherTimer(); - _timerSimulacionFluidos.Interval = TimeSpan.FromMilliseconds(16); // ~60fps - _timerSimulacionFluidos.Tick += OnTickSimulacionFluidos; - - _stopwatch = new Stopwatch(); - _stopwatch.Start(); - } - - /// - /// Inicia la simulación de fluidos - /// - public void StartFluidSimulation() - { - if (IsFluidSimulationRunning) - return; - - IsFluidSimulationRunning = true; - - // Notificar a todos los objetos que usan fluidos que inicie su simulación - foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) - { - if (objetoSimulable is osSistemaFluidos sistemaFluidos) - { - sistemaFluidos.UpdateGeometryStart(); - } - } - - _lastUpdateTime = _stopwatch.Elapsed.TotalMilliseconds; - _timerSimulacionFluidos.Start(); - } - - /// - /// Detiene la simulación de fluidos - /// - public void StopFluidSimulation() - { - if (!IsFluidSimulationRunning) - return; - - IsFluidSimulationRunning = false; - _timerSimulacionFluidos.Stop(); - - // Notificar a todos los objetos que usan fluidos que detenga su simulación - foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) - { - if (objetoSimulable is osSistemaFluidos sistemaFluidos) - { - sistemaFluidos.SimulationStop(); - } - } - } - - /// - /// Evento que se dispara cada tick de la simulación de fluidos - /// - private void OnTickSimulacionFluidos(object sender, EventArgs e) - { - // Calcular delta time - double currentTime = _stopwatch.Elapsed.TotalMilliseconds; - float deltaTime = (float)(currentTime - _lastUpdateTime) / 1000.0f; // convertir a segundos - _lastUpdateTime = currentTime; - - int totalParticleCount = 0; - - // Actualizar todos los sistemas de fluidos - foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) - { - if (objetoSimulable is osSistemaFluidos sistemaFluidos && sistemaFluidos.Show_On_This_Page) - { - // Actualizar la simulación con el deltaTime calculado - if (sistemaFluidos._simFluidos != null) - { - sistemaFluidos._simFluidos.Actualizar(deltaTime); - totalParticleCount += sistemaFluidos._simFluidos.ParticlesCount; - } - - // Actualizar controles visuales - sistemaFluidos.UpdateControl((int)(deltaTime * 1000)); - } - } - - // Actualizar estadísticas - Fps = 1.0f / Math.Max(deltaTime, 0.001f); - ParticulasCount = totalParticleCount; - } - } -} diff --git a/estadoPersistente.cs b/estadoPersistente.cs index 9974632..368b9d8 100644 --- a/estadoPersistente.cs +++ b/estadoPersistente.cs @@ -34,6 +34,20 @@ namespace CtrEditor public bool IsMaximized { get; set; } = false; } + public class CameraSettings + { + public double PositionX { get; set; } = 3.86; + public double PositionY { get; set; } = -18.13; + public double PositionZ { get; set; } = 10; + public double LookDirectionX { get; set; } = -3.86; + public double LookDirectionY { get; set; } = 18.1; + public double LookDirectionZ { get; set; } = -10; + public double UpDirectionX { get; set; } = -0.1; + public double UpDirectionY { get; set; } = 0.48; + public double UpDirectionZ { get; set; } = 0.87; + public double FieldOfView { get; set; } = 60; + } + internal class EstadoPersistente { // Ruta donde se guardará el estado @@ -58,6 +72,8 @@ namespace CtrEditor public LibraryWindowSettings LibraryWindow { get; set; } = new LibraryWindowSettings(); + public CameraSettings Camera { get; set; } = new CameraSettings(); + // Propiedad pública con get y set para controlar el acceso a _strDirectorioTrabajo public string directorio { @@ -91,6 +107,7 @@ namespace CtrEditor _strDirectorioTrabajo = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); RecentDirectories = new List(); LibraryWindow = new LibraryWindowSettings(); + Camera = new CameraSettings(); return this; } @@ -133,6 +150,9 @@ namespace CtrEditor // Asegurar que LibraryWindow esté inicializado if (estado.LibraryWindow == null) estado.LibraryWindow = new LibraryWindowSettings(); + // Asegurar que Camera esté inicializado + if (estado.Camera == null) + estado.Camera = new CameraSettings(); return estado; } return new EstadoPersistente().Inizializar(); // Devuelve una nueva instancia si no existe el archivo