Codigo adaptado base aun errores

This commit is contained in:
Miguel 2025-07-01 19:47:10 +02:00
parent 121e586d53
commit fbac81ec45
24 changed files with 579 additions and 445 deletions

View File

@ -6,7 +6,7 @@ using Ookii.Dialogs.Wpf;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Windows.Threading; using System.Windows.Threading;
using CtrEditor.ObjetosSim; using CtrEditor.ObjetosSim;
using LibS7Adv; using LibS7Adv; // Using stub implementation
using System.IO; using System.IO;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Windows; using System.Windows;
@ -26,6 +26,7 @@ using CtrEditor.Serialization; // Add this line
using CtrEditor.Controls; // Add this using directive using CtrEditor.Controls; // Add this using directive
using CtrEditor.PopUps; // Add this using directive using CtrEditor.PopUps; // Add this using directive
namespace CtrEditor namespace CtrEditor
{ {
@ -49,6 +50,7 @@ namespace CtrEditor
private readonly DispatcherTimer _timerSimulacion; private readonly DispatcherTimer _timerSimulacion;
private readonly DispatcherTimer _timerPLCUpdate; private readonly DispatcherTimer _timerPLCUpdate;
private readonly DispatcherTimer _timerDisplayUpdate; private readonly DispatcherTimer _timerDisplayUpdate;
private readonly DispatcherTimer _timer3DUpdate; // Nuevo timer para actualización 3D cuando simulación está detenida
public Canvas MainCanvas; public Canvas MainCanvas;
@ -94,7 +96,6 @@ namespace CtrEditor
public ICommand StopSimulationCommand { get; } public ICommand StopSimulationCommand { get; }
public ICommand ItemDoubleClickCommand { get; private set; } public ICommand ItemDoubleClickCommand { get; private set; }
public SimulationFluidsViewModel FluidSimulation { get; private set; }
public ICommand TBStartSimulationCommand { get; } public ICommand TBStartSimulationCommand { get; }
public ICommand TBStopSimulationCommand { get; } public ICommand TBStopSimulationCommand { get; }
@ -117,6 +118,12 @@ namespace CtrEditor
public ICommand TBMultiPageMatrixCommand { get; } public ICommand TBMultiPageMatrixCommand { get; }
public ICommand TBLibraryManagerCommand { 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(() => public ICommand TBTogglePLCConnectionCommand => new RelayCommand(() =>
{ {
@ -174,6 +181,18 @@ namespace CtrEditor
partial void OnIsSimulationRunningChanged(bool value) partial void OnIsSimulationRunningChanged(bool value)
{ {
CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado 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) partial void OnHasUnsavedChangesChanged(bool value)
@ -370,16 +389,18 @@ namespace CtrEditor
_timerDisplayUpdate.Tick += OnDisplayUpdate; _timerDisplayUpdate.Tick += OnDisplayUpdate;
_timerDisplayUpdate.Start(); _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); StartSimulationCommand = new RelayCommand(StartSimulation);
StopSimulationCommand = new RelayCommand(StopSimulation); StopSimulationCommand = new RelayCommand(StopSimulation);
TBStartSimulationCommand = new RelayCommand(StartSimulation, () => !IsSimulationRunning); TBStartSimulationCommand = new RelayCommand(StartSimulation, () => !IsSimulationRunning);
TBStopSimulationCommand = new RelayCommand(StopSimulation, () => 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); TBSaveCommand = new RelayCommand(Save);
TBEliminarUserControlCommand = new RelayCommand(EliminarUserControl, () => habilitarEliminarUserControl); TBEliminarUserControlCommand = new RelayCommand(EliminarUserControl, () => habilitarEliminarUserControl);
@ -392,6 +413,12 @@ namespace CtrEditor
TBMultiPageAnalizeCommand = new RelayCommand(MultiPageAnalizeCommand); TBMultiPageAnalizeCommand = new RelayCommand(MultiPageAnalizeCommand);
TBMultiPageMatrixCommand = new RelayCommand(MultiPageMatrixCommand); TBMultiPageMatrixCommand = new RelayCommand(MultiPageMatrixCommand);
TBLibraryManagerCommand = new RelayCommand(ShowLibraryManager); 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<string>(RenameImage); RenameImageCommand = new RelayCommand<string>(RenameImage);
stopwatch_Sim = new Stopwatch(); stopwatch_Sim = new Stopwatch();
@ -411,6 +438,9 @@ namespace CtrEditor
// Conectar DatosDeTrabajo con este ViewModel para el escaneo de imágenes // Conectar DatosDeTrabajo con este ViewModel para el escaneo de imágenes
datosDeTrabajo.SetMainViewModel(this); 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 // Métodos para manejo de datos de imágenes
@ -876,8 +906,6 @@ namespace CtrEditor
private void StartSimulation() private void StartSimulation()
{ {
// Detener simulación de fluidos si está ejecutándose
StopFluidSimulation();
IsSimulationRunning = true; IsSimulationRunning = true;
@ -887,7 +915,7 @@ namespace CtrEditor
foreach (var objetoSimulable in ObjetosSimulables) foreach (var objetoSimulable in ObjetosSimulables)
objetoSimulable.UpdateGeometryStart(); objetoSimulable.UpdateGeometryStart();
simulationManager.Debug_DrawInitialBodies();
TiempoDesdeStartSimulacion = 0; TiempoDesdeStartSimulacion = 0;
Debug_SimulacionCreado = true; Debug_SimulacionCreado = true;
@ -904,7 +932,6 @@ namespace CtrEditor
if (Debug_SimulacionCreado) if (Debug_SimulacionCreado)
{ {
simulationManager.Debug_ClearSimulationShapes();
Debug_SimulacionCreado = false; Debug_SimulacionCreado = false;
} }
_timerSimulacion.Stop(); _timerSimulacion.Stop();
@ -916,26 +943,7 @@ namespace CtrEditor
MainWindow?.ClearUndoHistory(); MainWindow?.ClearUndoHistory();
} }
/// <summary>
/// Inicia la simulación de fluidos independiente
/// </summary>
public void StartFluidSimulation()
{
// Detener simulación física si está ejecutándose
StopSimulation();
FluidSimulation.StartFluidSimulation();
CommandManager.InvalidateRequerySuggested();
}
/// <summary>
/// Detiene la simulación de fluidos independiente
/// </summary>
public void StopFluidSimulation()
{
FluidSimulation.StopFluidSimulation();
CommandManager.InvalidateRequerySuggested();
}
private void OnTickSimulacion(object sender, EventArgs e) private void OnTickSimulacion(object sender, EventArgs e)
{ {
@ -949,10 +957,8 @@ namespace CtrEditor
accumulatedSimTime += elapsedMilliseconds; accumulatedSimTime += elapsedMilliseconds;
simSampleCount++; simSampleCount++;
// Eliminar el diseño de Debug luego de 2 segundos // Contador de tiempo desde el inicio de la simulación
if (TiempoDesdeStartSimulacion > 1200) if (TiempoDesdeStartSimulacion <= 1200)
simulationManager.Debug_ClearSimulationShapes();
else
TiempoDesdeStartSimulacion += (float)elapsedMilliseconds; TiempoDesdeStartSimulacion += (float)elapsedMilliseconds;
foreach (var objetoSimulable in ObjetosSimulables) foreach (var objetoSimulable in ObjetosSimulables)
@ -1268,7 +1274,6 @@ namespace CtrEditor
{ {
// Detener simulaciones antes de cambiar la escala // Detener simulaciones antes de cambiar la escala
StopSimulation(); StopSimulation();
StopFluidSimulation();
DisconnectPLC(); DisconnectPLC();
// Actualizar la escala en el UnitConverter // Actualizar la escala en el UnitConverter
@ -1341,6 +1346,15 @@ namespace CtrEditor
libraryWindow.Show(); 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();
}
}
} }

View File

@ -10,6 +10,7 @@
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim"
xmlns:helix="http://helix-toolkit.org/wpf"
xmlns:ObjetosExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos" xmlns:ObjetosExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos"
x:Class="CtrEditor.MainWindow" x:Class="CtrEditor.MainWindow"
Height="900" Width="1600" WindowState="Maximized" ResizeMode="CanResize" Title="{Binding directorioTrabajo, Converter={StaticResource UnsavedChangesConverter}}" Height="900" Width="1600" WindowState="Maximized" ResizeMode="CanResize" Title="{Binding directorioTrabajo, Converter={StaticResource UnsavedChangesConverter}}"

View File

@ -91,7 +91,6 @@ namespace CtrEditor
viewModel.MainWindow = this; viewModel.MainWindow = this;
viewModel.ImageSelected += ViewModel_ImageSelected; viewModel.ImageSelected += ViewModel_ImageSelected;
viewModel?.LoadInitialData(); viewModel?.LoadInitialData();
viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas;
viewModel.MainCanvas = ImagenEnTrabajoCanvas; viewModel.MainCanvas = ImagenEnTrabajoCanvas;
// Inicializar ObjectHierarchyView // Inicializar ObjectHierarchyView

View File

@ -1,15 +1,12 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucBotella" <UserControl x:Class="CtrEditor.ObjetosSim.ucBotella" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
>
<UserControl.DataContext> <UserControl.DataContext>
<vm:osBotella/> <vm:osBotella />
</UserControl.DataContext> </UserControl.DataContext>
<Ellipse Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" <Ellipse Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
Stroke="{Binding ColorButton_oculto}" Fill="Gray" Stroke="{Binding ColorButton_oculto}" Fill="Gray"
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" StrokeThickness="0.5"/> Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" StrokeThickness="0.5" />
</UserControl> </UserControl>

View File

@ -93,6 +93,12 @@ namespace CtrEditor.ObjetosSim
[property: Name("Porcentaje de Tracción")] [property: Name("Porcentaje de Tracción")]
private float porcentaje_Traccion; 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] [ObservableProperty]
[property: Category("Simulación")] [property: Category("Simulación")]
[property: Description("Masa del objeto en kg")] [property: Description("Masa del objeto en kg")]
@ -109,7 +115,7 @@ namespace CtrEditor.ObjetosSim
} }
public void SetCentro(float x, float y) public void SetCentro(float x, float y)
{ Left = x; Top = y; } { Left = x - Diametro / 2; Top = y - Diametro / 2; }
public void SetCentro(Vector2 centro) public void SetCentro(Vector2 centro)
{ {
@ -144,27 +150,41 @@ namespace CtrEditor.ObjetosSim
public override void UpdateGeometryStart() public override void UpdateGeometryStart()
{ {
// Se llama antes de la simulacion // Se llama cuando inicia la simulación - crear geometría si no existe
ActualizarGeometrias(); if (SimGeometria == null)
SimGeometria?.SetDiameter(Diametro); {
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
}
else
{
ActualizarGeometrias();
SimGeometria?.SetDiameter(Diametro);
SimGeometria?.SetMass(Mass);
}
} }
public override void UpdateGeometryStep() public override void UpdateGeometryStep()
{ {
// Se llama antes de la simulacion // Se llama durante cada paso de la simulación
ActualizarGeometrias(); if (SimGeometria != null)
{
// Actualizar posición desde la simulación hacia WPF
SetCentro(SimGeometria.Center);
}
} }
public override void UpdateControl(int elapsedMilliseconds) public override void UpdateControl(int elapsedMilliseconds)
{ {
SetCentro(SimGeometria.Center); SetCentro(SimGeometria.Center);
// Sistema de colores jerarquizado para diferentes estados
if (SimGeometria.isRestricted) 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 else
{ ColorButton_oculto = Brushes.Gray; // Estado libre
if (SimGeometria.IsOnAnyTransport())
ColorButton_oculto = Brushes.Red;
else
ColorButton_oculto = Brushes.Gray;
}
// Ha sido marcada para remover // Ha sido marcada para remover
if (SimGeometria.Descartar) if (SimGeometria.Descartar)
@ -174,9 +194,10 @@ namespace CtrEditor.ObjetosSim
if (!Preserve_Outside_Transport && !SimGeometria.IsOnAnyTransport()) if (!Preserve_Outside_Transport && !SimGeometria.IsOnAnyTransport())
RemoverDesdeSimulacion = true; RemoverDesdeSimulacion = true;
Velocidad_desde_simulacion = SimGeometria.Body.LinearVelocity.ToString(); Velocidad_desde_simulacion = SimGeometria.GetLinearVelocity().ToString();
Inercia_desde_simulacion = SimGeometria.Body.Inertia; Inercia_desde_simulacion = SimGeometria.Mass; // En BEPU usamos masa en lugar de inercia directa
Porcentaje_Traccion = SimGeometria.OverlapPercentage; Porcentaje_Traccion = SimGeometria.OverlapPercentage;
EnTransporteConFreno = SimGeometria.isOnBrakeTransport; // Actualizar estado de freno
} }
public override void ucLoaded() public override void ucLoaded()

View File

@ -80,6 +80,24 @@ namespace CtrEditor.ObjetosSim
[property: Name("Inercia Simulación")] [property: Name("Inercia Simulación")]
private float inercia_desde_simulacion; 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] [ObservableProperty]
[property: Category("Simulación")] [property: Category("Simulación")]
[property: Description("Masa de la botella")] [property: Description("Masa de la botella")]
@ -140,19 +158,29 @@ namespace CtrEditor.ObjetosSim
public override void UpdateControl(int elapsedMilliseconds) public override void UpdateControl(int elapsedMilliseconds)
{ {
SetCentro(SimGeometria.Center); SetCentro(SimGeometria.Center);
// Sistema de colores jerarquizado para diferentes estados
if (SimGeometria.isRestricted) 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 else
{ ColorButton_oculto = Brushes.Gray; // Estado libre
if (SimGeometria.isOnTransports > 0)
ColorButton_oculto = Brushes.Red; // Ha sido marcada para remover
else if (SimGeometria.Descartar)
ColorButton_oculto = Brushes.Gray;
}
if (SimGeometria.Descartar) // Ha sido marcada para remover
RemoverDesdeSimulacion = true; 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() public override void ucLoaded()

View File

@ -1,21 +1,17 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucBottGenerator" <UserControl x:Class="CtrEditor.ObjetosSim.ucBottGenerator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"
mc:Ignorable="d" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
<UserControl.DataContext> <UserControl.DataContext>
<vm:osFiller/> <vm:osBottGenerator />
</UserControl.DataContext> </UserControl.DataContext>
<Grid> <Grid>
<Image Source="/imagenes/gear.png" <Image Source="/imagenes/gear.png" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Stretch="Uniform">
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Stretch="Uniform">
<Image.RenderTransform> <Image.RenderTransform>
<RotateTransform Angle="{Binding Angulo}" /> <RotateTransform Angle="{Binding Angulo}" />
</Image.RenderTransform> </Image.RenderTransform>

View File

@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using CtrEditor.FuncionesBase; using CtrEditor.FuncionesBase;
using System.ComponentModel; using System.ComponentModel;
using DocumentFormat.OpenXml.Spreadsheet;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {

View File

@ -1,42 +1,31 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucDescarte" <UserControl x:Class="CtrEditor.ObjetosSim.ucDescarte" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim" mc:Ignorable="d">
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<Storyboard x:Key="PulsingStoryboard" RepeatBehavior="Forever"> <Storyboard x:Key="PulsingStoryboard" RepeatBehavior="Forever">
<DoubleAnimation <DoubleAnimation Storyboard.TargetName="AnimatedEllipse"
Storyboard.TargetName="AnimatedEllipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" From="1" To="0.5" Duration="0:0:1" AutoReverse="True" />
From="1" To="0.5" Duration="0:0:1" AutoReverse="True" /> <DoubleAnimation Storyboard.TargetName="AnimatedEllipse"
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
Storyboard.TargetName="AnimatedEllipse" From="1" To="0.5" Duration="0:0:1" AutoReverse="True" />
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
From="1" To="0.5" Duration="0:0:1" AutoReverse="True" />
</Storyboard> </Storyboard>
</UserControl.Resources> </UserControl.Resources>
<UserControl.DataContext> <UserControl.DataContext>
<vm:osDescarte/> <vm:osDescarte />
</UserControl.DataContext> </UserControl.DataContext>
<Grid> <Grid>
<Ellipse <Ellipse Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" Stroke="Yellow"
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" Fill="Black" Opacity="0.5" />
Stroke="Yellow" <Ellipse x:Name="AnimatedEllipse" Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
Fill="Black" Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" Stroke="Blue"
Opacity="0.5"/> Fill="Transparent" RenderTransformOrigin="0.5,0.5">
<Ellipse x:Name="AnimatedEllipse"
Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
Stroke="Blue"
Fill="Transparent"
RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform> <Ellipse.RenderTransform>
<TransformGroup> <TransformGroup>
<ScaleTransform /> <ScaleTransform />

View File

@ -3,11 +3,11 @@ using LibS7Adv;
using CtrEditor.Simulacion; using CtrEditor.Simulacion;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Numerics;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.FuncionesBase; using CtrEditor.FuncionesBase;
using System.ComponentModel; using System.ComponentModel;
using System.Numerics;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
/// <summary> /// <summary>

View File

@ -5,6 +5,7 @@ using LibS7Adv;
using CtrEditor.Simulacion; using CtrEditor.Simulacion;
using CtrEditor.FuncionesBase; using CtrEditor.FuncionesBase;
using System.ComponentModel; using System.ComponentModel;
using System.Numerics;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
@ -32,14 +33,21 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty] [ObservableProperty]
[property: Category("Configuración")] [property: Category("Configuración")]
[property: Description("Alto de la guía en metros")] [property: Description("Grosor de la guía en metros")]
[property: Name("Alto de la Guía")] [property: Name("Grosor de la Guía")]
public float altoGuia; public float altoGuia;
private void ActualizarGeometrias() private void ActualizarGeometrias()
{ {
if (_visualRepresentation is ucGuia uc) 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); UpdateOrCreateLine(SimGeometria, uc.Guia);
}
} }
public override void OnMoveResizeRotate() public override void OnMoveResizeRotate()
@ -81,7 +89,21 @@ namespace CtrEditor.ObjetosSim
simulationManager?.Remove(SimGeometria); 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 public partial class ucGuia : UserControl, IDataContainer

View File

@ -1,11 +1,10 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteCurva" <UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteCurva"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:localuc="clr-namespace:CtrEditor.ObjetosSim.UserControls" xmlns:localuc="clr-namespace:CtrEditor.ObjetosSim.UserControls" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim" mc:Ignorable="d">
mc:Ignorable="d">
<UserControl.DataContext> <UserControl.DataContext>
<vm:osTransporteCurva /> <vm:osTransporteCurva />
@ -13,7 +12,9 @@
<Canvas x:Name="MainCanvas"> <Canvas x:Name="MainCanvas">
<localuc:CircularSegment x:Name="Transporte" Angle="0" OuterRadius="{Binding RadioExterno, Converter={StaticResource MeterToPixelConverter}}" InnerRadius="{Binding RadioInterno, Converter={StaticResource MeterToPixelConverter}}" <localuc:CircularSegment x:Name="Transporte" Angle="0"
StartAngle="{Binding Angulo}" EndAngle="{Binding AnguloFinal}" /> OuterRadius="{Binding RadioExterno, Converter={StaticResource MeterToPixelConverter}}"
InnerRadius="{Binding RadioInterno, Converter={StaticResource MeterToPixelConverter}}"
StartAngle="{Binding Angulo}" EndAngle="{Binding AnguloFinal}" />
</Canvas> </Canvas>
</UserControl> </UserControl>

View File

@ -7,6 +7,7 @@ using CtrEditor.Simulacion;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CtrEditor.FuncionesBase; using CtrEditor.FuncionesBase;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Numerics;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
@ -93,6 +94,50 @@ namespace CtrEditor.ObjetosSim
ActualizarGeometrias(); 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] [ObservableProperty]
[property: Category("Configuración")] [property: Category("Configuración")]
[property: Description("Radio interior de la curva en metros")] [property: Description("Radio interior de la curva en metros")]
@ -140,6 +185,7 @@ namespace CtrEditor.ObjetosSim
public override void AnguloChanged(float value) public override void AnguloChanged(float value)
{ {
OnPropertyChanged(nameof(AnguloFinal)); OnPropertyChanged(nameof(AnguloFinal));
ActualizarGeometrias();
} }
[ObservableProperty] [ObservableProperty]
@ -156,7 +202,15 @@ namespace CtrEditor.ObjetosSim
{ {
if (_visualRepresentation is ucTransporteCurva uc) 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(); SetSpeed();
} }
} }
@ -209,6 +263,9 @@ namespace CtrEditor.ObjetosSim
// Ensure radioInterno is always less than radioExterno // Ensure radioInterno is always less than radioExterno
if (RadioInterno >= RadioExterno) if (RadioInterno >= RadioExterno)
RadioInterno = RadioExterno * 0.75f; 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) 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); CrearAnimacionStoryBoardTrasnporteCircular(uc.Transporte.TransportePath, InvertirDireccion, Angulo);
} }
} }

View File

@ -8,6 +8,7 @@ using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CtrEditor.FuncionesBase; using CtrEditor.FuncionesBase;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Windows.Media; using System.Windows.Media;
using System.Numerics;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
@ -302,7 +303,7 @@ namespace CtrEditor.ObjetosSim
float pasoAngular = rangoAngular / NumeroSegmentosGuias; float pasoAngular = rangoAngular / NumeroSegmentosGuias;
// Obtener el centro una vez para todo el método // 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) // Crear segmentos para guía superior (externa)
for (int i = 0; i < NumeroSegmentosGuias; i++) for (int i = 0; i < NumeroSegmentosGuias; i++)
@ -310,12 +311,12 @@ namespace CtrEditor.ObjetosSim
float angulo1 = anguloInicioRad + i * pasoAngular; float angulo1 = anguloInicioRad + i * pasoAngular;
float angulo2 = anguloInicioRad + (i + 1) * 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.Cos(angulo1),
radioGuiaSuperior * (float)Math.Sin(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.Cos(angulo2),
radioGuiaSuperior * (float)Math.Sin(angulo2) radioGuiaSuperior * (float)Math.Sin(angulo2)
); );
@ -334,12 +335,12 @@ namespace CtrEditor.ObjetosSim
float angulo1 = anguloInicioRad + i * pasoAngular; float angulo1 = anguloInicioRad + i * pasoAngular;
float angulo2 = anguloInicioRad + (i + 1) * 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.Cos(angulo1),
radioGuiaInferior * (float)Math.Sin(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.Cos(angulo2),
radioGuiaInferior * (float)Math.Sin(angulo2) radioGuiaInferior * (float)Math.Sin(angulo2)
); );

View File

@ -1,17 +1,17 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteGuias" <UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteGuias"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim" mc:Ignorable="d">
mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<!-- Define the VisualBrush for the conveyor belt pattern --> <!-- Define the VisualBrush for the conveyor belt pattern -->
<VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10" ViewboxUnits="Absolute"> <VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10"
ViewboxUnits="Absolute">
<VisualBrush.Transform> <VisualBrush.Transform>
<TransformGroup> <TransformGroup>
<TranslateTransform/> <TranslateTransform />
</TransformGroup> </TransformGroup>
</VisualBrush.Transform> </VisualBrush.Transform>
<VisualBrush.Visual> <VisualBrush.Visual>
@ -24,41 +24,42 @@
</UserControl.Resources> </UserControl.Resources>
<UserControl.DataContext> <UserControl.DataContext>
<vm:osTransporteGuias/> <vm:osTransporteGuias />
</UserControl.DataContext> </UserControl.DataContext>
<Grid> <Grid>
<Canvas RenderTransformOrigin="0,0"> <Canvas RenderTransformOrigin="0,0">
<Canvas.RenderTransform> <Canvas.RenderTransform>
<TransformGroup> <TransformGroup>
<ScaleTransform/> <ScaleTransform />
<SkewTransform/> <SkewTransform />
<RotateTransform Angle="{Binding Angulo}"/> <RotateTransform Angle="{Binding Angulo}" />
<TranslateTransform/> <TranslateTransform />
</TransformGroup> </TransformGroup>
</Canvas.RenderTransform> </Canvas.RenderTransform>
<StackPanel x:Name="RectanglesContainer"> <StackPanel x:Name="RectanglesContainer">
<Rectangle x:Name="GuiaSuperior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" <Rectangle x:Name="GuiaSuperior"
Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"/> Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}"
<Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}" />
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" <Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Fill="{StaticResource BeltBrush}"/> Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"
<Rectangle x:Name="GuiaInferior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Fill="{StaticResource BeltBrush}" />
Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" <Rectangle x:Name="GuiaInferior"
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}"/> Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}" />
</StackPanel> </StackPanel>
<Viewbox Canvas.Top="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" <Viewbox Canvas.Top="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Stretch="Uniform">
Stretch="Uniform"> <Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center"
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" FontSize="18" Opacity="0.9"/> FontWeight="Bold" FontSize="18" Opacity="0.9" />
</Viewbox> </Viewbox>
</Canvas> </Canvas>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -1,4 +1,5 @@
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
@ -8,6 +9,7 @@ using CtrEditor.Simulacion;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CtrEditor.FuncionesBase; using CtrEditor.FuncionesBase;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Siemens.Simatic.Simulation.Runtime;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
@ -91,7 +93,7 @@ namespace CtrEditor.ObjetosSim
[property: Category("Enlace PLC")] [property: Category("Enlace PLC")]
[property: Description("Motor enlazado al transporte")] [property: Description("Motor enlazado al transporte")]
[property: Name("Motor Enlazado")] [property: Name("Motor Enlazado")]
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))] //[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
string id_Motor; string id_Motor;
[JsonIgnore] [JsonIgnore]
@ -99,24 +101,24 @@ namespace CtrEditor.ObjetosSim
partial void OnId_MotorChanged(string value) partial void OnId_MotorChanged(string value)
{ {
if (Motor != null && motorPropertyChangedHandler != null) //if (Motor != null && motorPropertyChangedHandler != null)
Motor.PropertyChanged -= motorPropertyChangedHandler; // Motor.PropertyChanged -= motorPropertyChangedHandler;
if (_mainViewModel != null && !string.IsNullOrEmpty(value)) //if (_mainViewModel != null && !string.IsNullOrEmpty(value))
{ //{
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value); // Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
if (Motor != null) // if (Motor != null)
{ // {
motorPropertyChangedHandler = (sender, e) => // motorPropertyChangedHandler = (sender, e) =>
{ // {
if (e.PropertyName == nameof(osVMmotorSim.Nombre)) // if (e.PropertyName == nameof(osVMmotorSim.Nombre))
{ // {
Id_Motor = ((osVMmotorSim)sender).Nombre; // Id_Motor = ((osVMmotorSim)sender).Nombre;
} // }
}; // };
Motor.PropertyChanged += motorPropertyChangedHandler; // Motor.PropertyChanged += motorPropertyChangedHandler;
} // }
} //}
} }
public override void AltoChanged(float value) public override void AltoChanged(float value)
@ -124,6 +126,16 @@ namespace CtrEditor.ObjetosSim
ActualizarGeometrias(); ActualizarGeometrias();
} }
public override void AnchoChanged(float value)
{
ActualizarGeometrias();
}
public override void AnguloChanged(float value)
{
ActualizarGeometrias();
}
[ObservableProperty] [ObservableProperty]
[property: Category("Configuración")] [property: Category("Configuración")]
[property: Description("Actuar como freno")] [property: Description("Actuar como freno")]
@ -132,8 +144,14 @@ namespace CtrEditor.ObjetosSim
partial void OnEsFrenoChanged(bool value) 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) if (SimGeometria != null)
SimGeometria.isBrake = value; {
System.Diagnostics.Debug.WriteLine($"[✅ FRENO SYNC] SimGeometria.isBrake = {SimGeometria.isBrake}");
}
} }
[ObservableProperty] [ObservableProperty]
@ -142,6 +160,11 @@ namespace CtrEditor.ObjetosSim
[property: Name("Coeficiente Fricción")] [property: Name("Coeficiente Fricción")]
public float frictionCoefficient; public float frictionCoefficient;
partial void OnFrictionCoefficientChanged(float value)
{
ActualizarGeometrias();
}
[ObservableProperty] [ObservableProperty]
[property: Category("Configuración")] [property: Category("Configuración")]
[property: Description("Velocidad máxima a 50Hz")] [property: Description("Velocidad máxima a 50Hz")]
@ -160,32 +183,132 @@ namespace CtrEditor.ObjetosSim
[property: Name("En Marcha")] [property: Name("En Marcha")]
public bool esMarcha; 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";
/// <summary>
/// Actualiza la información de botellas en el transporte con freno
/// </summary>
public void ActualizarInfoBotellasFreno()
{
if (SimGeometria?.isBrake == true && simulationManager != null)
{
// Contar botellas marcadas como en transporte con freno
var botellasEnFreno = simulationManager.Cuerpos
.OfType<simBotella>()
.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] [ObservableProperty]
[property: Category("Configuración")] [property: Category("Configuración")]
[property: Description("Distancia entre guías")] [property: Description("Distancia entre guías")]
[property: Name("Distancia")] [property: Name("Distancia")]
private float distance; private float distance;
partial void OnDistanceChanged(float value)
{
ActualizarGeometrias();
}
[ObservableProperty] [ObservableProperty]
[property: Category("Configuración")] [property: Category("Configuración")]
[property: Description("Alto de las guías")] [property: Description("Alto de las guías")]
[property: Name("Alto Guía")] [property: Name("Alto Guía")]
private float altoGuia; private float altoGuia;
partial void OnAltoGuiaChanged(float value)
{
ActualizarGeometrias();
}
private void ActualizarGeometrias() private void ActualizarGeometrias()
{ {
if (_visualRepresentation is ucTransporteGuias uc) if (_visualRepresentation is ucTransporteGuias uc)
{ {
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo); UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
UpdateOrCreateLine(Guia_Superior, uc.GuiaSuperior);
UpdateOrCreateLine(Guia_Inferior, uc.GuiaInferior);
SimGeometria.DistanceGuide2Guide = Alto; // Actualizar guías con método específico para transporte
SimGeometria.isBrake = esFreno; 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(); SetSpeed();
} }
} }
/// <summary>
/// Actualiza una guía específica del transporte (superior o inferior)
/// </summary>
/// <param name="simGuia">Objeto de simulación de la guía</param>
/// <param name="wpfRect">Rectángulo WPF de la guía</param>
/// <param name="isTopGuide">true para guía superior, false para inferior</param>
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}°");
}
}
/// <summary>
/// Crea una guía específica del transporte (superior o inferior)
/// </summary>
/// <param name="wpfRect">Rectángulo WPF de la guía</param>
/// <param name="isTopGuide">true para guía superior, false para inferior</param>
/// <returns>Objeto simGuia creado</returns>
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() public override void OnMoveResizeRotate()
{ {
ActualizarGeometrias(); ActualizarGeometrias();
@ -196,7 +319,7 @@ namespace CtrEditor.ObjetosSim
Ancho = 1; Ancho = 1;
Alto = 0.10f; Alto = 0.10f;
AltoGuia = 0.03f; AltoGuia = 0.03f;
Distance = 0.01f; Distance = 0.5f;
Tag_ReleActivatedMotor = "1"; Tag_ReleActivatedMotor = "1";
} }
@ -214,12 +337,18 @@ namespace CtrEditor.ObjetosSim
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
{ {
if (Motor != null) //if (Motor != null)
if (Motor is osVMmotorSim id_motor) // if (Motor is osVMmotorSim id_motor)
if (LeerBitTag(Tag_ReleActivatedMotor)) // if (LeerBitTag(Tag_ReleActivatedMotor))
VelocidadActual = id_motor.Velocidad; // VelocidadActual = id_motor.Velocidad;
else // else
VelocidadActual = 0; // VelocidadActual = 0;
// Actualizar información de botellas en tiempo real si es un transporte con freno
if (EsFreno)
{
ActualizarInfoBotellasFreno();
}
} }
public override void ucLoaded() public override void ucLoaded()
@ -233,12 +362,22 @@ namespace CtrEditor.ObjetosSim
if (_visualRepresentation is ucTransporteGuias uc) if (_visualRepresentation is ucTransporteGuias uc)
{ {
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo); SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
SimGeometria.TransportWithGuides = true;
SimGeometria.DistanceGuide2Guide = Alto; // CORREGIR: Asegurar que todas las propiedades se inicialicen correctamente
Guia_Superior = AddLine(simulationManager, uc.GuiaSuperior); if (SimGeometria != null)
Guia_Inferior = AddLine(simulationManager, uc.GuiaInferior); {
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); CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
SetSpeed(); // Aplicar velocidad inicial
} }
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
} }

View File

@ -7,6 +7,7 @@ using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using System.ComponentModel; using System.ComponentModel;
using CtrEditor.FuncionesBase; using CtrEditor.FuncionesBase;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Numerics;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {

View File

@ -1,5 +1,5 @@
using CtrEditor.Simulacion; using CtrEditor.Simulacion;
using LibS7Adv; using LibS7Adv; // Using stub implementation
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
@ -9,6 +9,7 @@ using CtrEditor.FuncionesBase;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute; using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute;
using System.ComponentModel; using System.ComponentModel;
using System.Numerics;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
@ -34,7 +35,14 @@ namespace CtrEditor.ObjetosSim
public override string Nombre public override string Nombre
{ {
get => 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] [ObservableProperty]
@ -200,6 +208,10 @@ namespace CtrEditor.ObjetosSim
Frecuency = 0; Frecuency = 0;
timer = new Stopwatch(); timer = new Stopwatch();
timer.Start(); timer.Start();
Color = Brushes.Black;
// Forzar notificación de la propiedad Nombre para asegurar binding inicial
OnPropertyChanged(nameof(Nombre));
} }
public override void UpdateGeometryStart() public override void UpdateGeometryStart()
@ -213,7 +225,7 @@ namespace CtrEditor.ObjetosSim
if (DetectarCuello) if (DetectarCuello)
LuzCortada = Simulation_Photocell.LuzCortadaNeck; LuzCortada = Simulation_Photocell.LuzCortadaNeck;
else else
LuzCortada = Simulation_Photocell.LuzCortada > 0; LuzCortada = Simulation_Photocell.LuzCortada; // Ahora es bool directamente
} }
public override void UpdatePLCPrimerCiclo() public override void UpdatePLCPrimerCiclo()
{ {
@ -232,7 +244,7 @@ namespace CtrEditor.ObjetosSim
base.ucLoaded(); base.ucLoaded();
if (_visualRepresentation is ucPhotocell uc) 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() public override void ucUnLoaded()
{ {

View File

@ -76,7 +76,7 @@ namespace CtrEditor.ObjetosSim
return instance; 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) if (userControl is IDataContainer dataContainer)
{ {

View File

@ -1,30 +1,29 @@
<UserControl x:Class="CtrEditor.ObjetosSim.UserControls.CircularSegment" <UserControl x:Class="CtrEditor.ObjetosSim.UserControls.CircularSegment"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls" xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls" mc:Ignorable="d" Name="circularSegmentControl">
mc:Ignorable="d" Name="circularSegmentControl">
<Canvas Name="mainCanvas"> <Canvas Name="mainCanvas">
<Path Name="path" Stroke="Black" StrokeThickness="1"> <Path Name="path" Stroke="Black" StrokeThickness="1">
<Path.Fill> <Path.Fill>
<VisualBrush TileMode="Tile" Viewport="0,0,20,20" ViewportUnits="Absolute"> <VisualBrush TileMode="Tile" Viewport="0,0,20,20" ViewportUnits="Absolute">
<VisualBrush.Transform> <VisualBrush.Transform>
<TransformGroup> <TransformGroup>
<TranslateTransform X="0" Y="0"/> <TranslateTransform X="0" Y="0" />
</TransformGroup> </TransformGroup>
</VisualBrush.Transform> </VisualBrush.Transform>
<VisualBrush.Visual> <VisualBrush.Visual>
<Canvas Width="20" Height="20"> <Canvas Width="20" Height="20">
<!-- Patrón de rayas radiales que simulan el movimiento tangencial --> <!-- Patrón de rayas radiales que simulan el movimiento tangencial -->
<Rectangle Fill="LightGray" Width="10" Height="10" Canvas.Left="0" Canvas.Top="0"/> <Rectangle Fill="LightGray" Width="10" Height="10" Canvas.Left="0" Canvas.Top="0" />
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="0" Canvas.Top="10"/> <Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="0" Canvas.Top="10" />
</Canvas> </Canvas>
</VisualBrush.Visual> </VisualBrush.Visual>
</VisualBrush> </VisualBrush>
</Path.Fill> </Path.Fill>
<Path.RenderTransform> <Path.RenderTransform>
<RotateTransform Angle="{Binding Angle, ElementName=circularSegmentControl}"/> <RotateTransform Angle="{Binding Angle, ElementName=circularSegmentControl}" />
</Path.RenderTransform> </Path.RenderTransform>
</Path> </Path>
</Canvas> </Canvas>

View File

@ -16,7 +16,6 @@ using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
using Tesseract;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using Application = System.Windows.Application; using Application = System.Windows.Application;
using ItemCollection = Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection; using ItemCollection = Xceed.Wpf.Toolkit.PropertyGrid.Attributes.ItemCollection;
@ -44,16 +43,16 @@ namespace CtrEditor.ObjetosSim
{ {
private MainViewModel? _mainViewModel; private MainViewModel? _mainViewModel;
private UserControl? VisualRepresentation; 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; _mainViewModel = a;
VisualRepresentation = b; VisualRepresentation = b;
simulationManager = c; 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; a = _mainViewModel;
b = VisualRepresentation; b = VisualRepresentation;
@ -71,6 +70,7 @@ namespace CtrEditor.ObjetosSim
[JsonIgnore] [JsonIgnore]
private System.Threading.Timer timer = null; private System.Threading.Timer timer = null;
[ObservableProperty] [ObservableProperty]
[property: JsonIgnore] [property: JsonIgnore]
[property: Hidden] [property: Hidden]
@ -113,6 +113,7 @@ namespace CtrEditor.ObjetosSim
// Actualizar posición relativa si el movimiento no viene del FramePlate // Actualizar posición relativa si el movimiento no viene del FramePlate
UpdateFramePlateRelativePosition(); UpdateFramePlateRelativePosition();
} }
public virtual void LeftChanging(float oldValue, float newValue) { } public virtual void LeftChanging(float oldValue, float newValue) { }
[ObservableProperty] [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 // 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) 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")] [property: Name("Habilitado en Todas Páginas")]
private bool enable_On_All_Pages; private bool enable_On_All_Pages;
partial void OnEnable_On_All_PagesChanged(bool value) partial void OnEnable_On_All_PagesChanged(bool value)
{ {
// Si se está desactivando el modo global // Si se está desactivando el modo global
@ -785,7 +702,6 @@ namespace CtrEditor.ObjetosSim
} }
} }
// Local Data for Global Objects // Local Data for Global Objects
[NotifyPropertyChangedFor(nameof(Show_On_This_Page))] [NotifyPropertyChangedFor(nameof(Show_On_This_Page))]
[ObservableProperty] [ObservableProperty]
@ -1050,6 +966,7 @@ namespace CtrEditor.ObjetosSim
/// <param name="elapsedMilliseconds"></param> /// <param name="elapsedMilliseconds"></param>
public virtual void UpdateControl(int elapsedMilliseconds) { } public virtual void UpdateControl(int elapsedMilliseconds) { }
/// <summary> /// <summary>
/// Se llama antes de comenzar la simulacion con el boton de Iniciar simulacion. /// 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. /// 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. /// Link al Simualdor fisico.
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public SimulationManagerFP simulationManager; public SimulationManagerBEPU simulationManager;
/// <summary> /// <summary>
/// Prepara la clase para ser serializable poniendo a null los objetos que tienen referencias circulares /// 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); 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) public void UpdateRectangle(simTransporte simRect, Rectangle wpfRect, float Alto, float Ancho, float Angulo)
{ {
if (simRect != null) 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) public void UpdateRectangle(simBarrera simRect, Rectangle wpfRect, float Alto, float Ancho, float Angulo)
{ {
if (simRect != null) 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) 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) 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); var topLeft2D = GetRectangleTopLeft(wpfRect);
} return simulationManager.AddBarrera(Ancho, Alto, topLeft2D, Angulo, detectarCuello);
public simBarrera AddBarrera(SimulationManagerFP simulationManager, Rectangle wpfRect, float Alto, float Ancho, float Angulo, bool detectarCuello)
{
return simulationManager.AddBarrera(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo, detectarCuello);
} }
public void UpdateOrCreateLine(simGuia simGuia, Rectangle wpfRect) public void UpdateOrCreateLine(simGuia simGuia, Rectangle wpfRect)
{ {
if (simGuia != null) if (simGuia != null)
{ {
// Usar el mismo sistema que transportes: Top-Left + Ángulo
var topLeft2D = GetRectangleTopLeft(wpfRect);
var coords = GetCenterLineVectors(wpfRect); // Actualizar las propiedades desde el objeto osGuia
if (this is osGuia guiaObj)
// Crear o actualizar simRectangle {
simGuia.Create(coords.Start, coords.End); // asumiendo que el ángulo inicial es 0 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); // Usar el mismo sistema que transportes: Top-Left + Ángulo
return simulationManager.AddLine(coords.Start, coords.End); 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) public ImageSource ImageFromPath(string value)
@ -1717,7 +1677,6 @@ namespace CtrEditor.ObjetosSim
} }
} }
public class UniqueId public class UniqueId
{ {
public int Value { get; set; } public int Value { get; set; }

View File

@ -14,9 +14,9 @@ namespace CtrEditor.Serialization
{ {
private readonly DatosDeTrabajo _datosDeTrabajo; private readonly DatosDeTrabajo _datosDeTrabajo;
private readonly MainViewModel _mainViewModel; 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; _mainViewModel = mainViewModel;
_datosDeTrabajo = datosDeTrabajo; _datosDeTrabajo = datosDeTrabajo;

View File

@ -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
{
/// <summary>
/// ViewModel para controlar la simulación de fluidos de forma independiente
/// </summary>
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;
/// <summary>
/// Constructor
/// </summary>
/// <param name="mainViewModel">Referencia al ViewModel principal</param>
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();
}
/// <summary>
/// Inicia la simulación de fluidos
/// </summary>
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();
}
/// <summary>
/// Detiene la simulación de fluidos
/// </summary>
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();
}
}
}
/// <summary>
/// Evento que se dispara cada tick de la simulación de fluidos
/// </summary>
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;
}
}
}

View File

@ -34,6 +34,20 @@ namespace CtrEditor
public bool IsMaximized { get; set; } = false; 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 internal class EstadoPersistente
{ {
// Ruta donde se guardará el estado // Ruta donde se guardará el estado
@ -58,6 +72,8 @@ namespace CtrEditor
public LibraryWindowSettings LibraryWindow { get; set; } = new LibraryWindowSettings(); 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 // Propiedad pública con get y set para controlar el acceso a _strDirectorioTrabajo
public string directorio public string directorio
{ {
@ -91,6 +107,7 @@ namespace CtrEditor
_strDirectorioTrabajo = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); _strDirectorioTrabajo = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
RecentDirectories = new List<string>(); RecentDirectories = new List<string>();
LibraryWindow = new LibraryWindowSettings(); LibraryWindow = new LibraryWindowSettings();
Camera = new CameraSettings();
return this; return this;
} }
@ -133,6 +150,9 @@ namespace CtrEditor
// Asegurar que LibraryWindow esté inicializado // Asegurar que LibraryWindow esté inicializado
if (estado.LibraryWindow == null) if (estado.LibraryWindow == null)
estado.LibraryWindow = new LibraryWindowSettings(); estado.LibraryWindow = new LibraryWindowSettings();
// Asegurar que Camera esté inicializado
if (estado.Camera == null)
estado.Camera = new CameraSettings();
return estado; return estado;
} }
return new EstadoPersistente().Inizializar(); // Devuelve una nueva instancia si no existe el archivo return new EstadoPersistente().Inizializar(); // Devuelve una nueva instancia si no existe el archivo