From fefc0a700d3bac1137dcea8fc4c1b86fc608846d Mon Sep 17 00:00:00 2001 From: Miguel Date: Sun, 22 Jun 2025 16:44:19 +0200 Subject: [PATCH] =?UTF-8?q?Se=20a=C3=B1adi=C3=B3=20un=20nuevo=20m=C3=A9tod?= =?UTF-8?q?o=20para=20verificar=20si=20un=20objeto=20visual=20es=20un=20hi?= =?UTF-8?q?jo=20visual=20de=20otro,=20mejorando=20la=20gesti=C3=B3n=20de?= =?UTF-8?q?=20transformaciones=20en=20la=20clase=20osBase.=20Adem=C3=A1s,?= =?UTF-8?q?=20se=20implementaron=20mejoras=20en=20la=20obtenci=C3=B3n=20de?= =?UTF-8?q?=20coordenadas=20de=20rect=C3=A1ngulos,=20incluyendo=20validaci?= =?UTF-8?q?ones=20para=20asegurar=20que=20los=20rect=C3=A1ngulos=20est?= =?UTF-8?q?=C3=A9n=20cargados=20y=20disponibles=20antes=20de=20realizar=20?= =?UTF-8?q?transformaciones.=20Se=20mejor=C3=B3=20la=20l=C3=B3gica=20de=20?= =?UTF-8?q?creaci=C3=B3n=20de=20geometr=C3=ADa=20en=20ucTransporteTTop,=20?= =?UTF-8?q?asegurando=20que=20el=20layout=20est=C3=A9=20actualizado=20y=20?= =?UTF-8?q?manejando=20excepciones=20para=20evitar=20fallos=20en=20la=20cr?= =?UTF-8?q?eaci=C3=B3n=20de=20simulaciones.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 26 ++++ .vscode/tasks.json | 41 ++++++ ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs | 54 ++++++- ObjetosSim/osBase.cs | 139 +++++++++++++++--- 4 files changed, 235 insertions(+), 25 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..16523d6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net8.0-windows8.0/CtrEditor.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..1063d1d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/CtrEditor.sln", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/CtrEditor.sln", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/CtrEditor.sln" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs b/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs index 64b659d..092132f 100644 --- a/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs +++ b/ObjetosSim/Estaticos/ucTransporteTTop.xaml.cs @@ -26,7 +26,7 @@ namespace CtrEditor.ObjetosSim return "Transporte"; } private string nombre = "Transporte TTOP"; - + [property: Category("Id:")] public override string Nombre { @@ -77,7 +77,7 @@ namespace CtrEditor.ObjetosSim [property: ItemsSource(typeof(osBaseItemsSource))] string id_Motor; - [JsonIgnore] + [JsonIgnore] private PropertyChangedEventHandler motorPropertyChangedHandler; partial void OnId_MotorChanged(string value) @@ -169,8 +169,54 @@ namespace CtrEditor.ObjetosSim if (_visualRepresentation is ucTransporteTTop uc) { - SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo); - CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion); + try + { + // Asegurar que el layout esté actualizado antes de crear la geometría + uc.UpdateLayout(); + + // Validar que el rectángulo esté disponible y tenga dimensiones válidas + if (uc.Transporte != null && + (!double.IsNaN(uc.Transporte.ActualWidth) && uc.Transporte.ActualWidth > 0) || + (!double.IsNaN(uc.Transporte.Width) && uc.Transporte.Width > 0)) + { + SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo); + CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion); + } + else + { + // Si el rectángulo no está listo, intentar después del próximo layout + uc.Dispatcher.BeginInvoke(new Action(() => + { + if (uc.Transporte != null && simulationManager != null) + { + SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo); + CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion); + } + }), System.Windows.Threading.DispatcherPriority.Loaded); + } + } + catch (Exception ex) + { + // Log del error para diagnóstico pero continuar sin fallar + System.Diagnostics.Debug.WriteLine($"Error al crear geometría de simulación: {ex.Message}"); + + // Intentar crear la geometría más tarde + uc.Dispatcher.BeginInvoke(new Action(() => + { + try + { + if (uc.Transporte != null && simulationManager != null) + { + SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo); + CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion); + } + } + catch (Exception ex2) + { + System.Diagnostics.Debug.WriteLine($"Segundo intento falló: {ex2.Message}"); + } + }), System.Windows.Threading.DispatcherPriority.ApplicationIdle); + } } } public override void ucUnLoaded() diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs index 9970345..ba8e1a4 100644 --- a/ObjetosSim/osBase.cs +++ b/ObjetosSim/osBase.cs @@ -1364,13 +1364,65 @@ namespace CtrEditor.ObjetosSim return transformGroup; } + private static bool IsVisualChild(Visual child, Visual parent) + { + if (child == null || parent == null) + return false; + + try + { + // Intentar obtener el ancestro común + var transform = child.TransformToAncestor(parent); + return transform != null; + } + catch (InvalidOperationException) + { + return false; + } + } + public (Vector2 TopLeft, Vector2 BottomRight) GetRectangleCoordinatesInMeter(Rectangle rect) { - if (rect != null) + if (rect == null) + return (new Vector2(0, 0), new Vector2(0, 0)); + + var _canvasLeft = CanvasGetLeftinMeter(); + var _canvasTop = CanvasGetTopinMeter(); + + try { - var _canvasLeft = CanvasGetLeftinMeter(); - var _canvasTop = CanvasGetTopinMeter(); + // Verificar que tanto el rectángulo como la representación visual estén cargados + if (!rect.IsLoaded || _visualRepresentation == null || !_visualRepresentation.IsLoaded) + { + // Fallback: usar las propiedades básicas de posición si la transformación no está disponible + float rectWidth = (float)rect.Width; + float rectHeight = (float)rect.Height; + + if (double.IsNaN(rectWidth) || rectWidth == 0) + rectWidth = Ancho * PixelToMeter.Instance.calc.MetersToPixels(1); + if (double.IsNaN(rectHeight) || rectHeight == 0) + rectHeight = Alto * PixelToMeter.Instance.calc.MetersToPixels(1); + + return (new Vector2(_canvasLeft, _canvasTop), + new Vector2(_canvasLeft + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth), + _canvasTop + PixelToMeter.Instance.calc.PixelsToMeters(rectHeight))); + } + + // Forzar actualización del layout + _visualRepresentation.UpdateLayout(); + + // Verificar que el rectángulo sea un descendiente visual de _visualRepresentation + if (!IsVisualChild(rect, _visualRepresentation)) + { + // Fallback: usar las dimensiones básicas + float rectWidth = (float)rect.ActualWidth; + float rectHeight = (float)rect.ActualHeight; + + return (new Vector2(_canvasLeft, _canvasTop), + new Vector2(_canvasLeft + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth), + _canvasTop + PixelToMeter.Instance.calc.PixelsToMeters(rectHeight))); + } // Obtiene la transformada del objeto visual GeneralTransform transform = rect.TransformToAncestor(_visualRepresentation); @@ -1379,10 +1431,26 @@ namespace CtrEditor.ObjetosSim Point topLeft = transform.Transform(new Point(0, 0)); Point bottomRight = transform.Transform(new Point(rect.ActualWidth, rect.ActualHeight)); - return (new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.Y) + _canvasTop), - new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)bottomRight.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)bottomRight.Y) + _canvasTop)); + return (new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.X) + _canvasLeft, + PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.Y) + _canvasTop), + new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)bottomRight.X) + _canvasLeft, + PixelToMeter.Instance.calc.PixelsToMeters((float)bottomRight.Y) + _canvasTop)); + } + catch (InvalidOperationException) + { + // Fallback en caso de error de transformación + float rectWidth = (float)rect.ActualWidth; + float rectHeight = (float)rect.ActualHeight; + + if (double.IsNaN(rectWidth) || rectWidth == 0) + rectWidth = Ancho * PixelToMeter.Instance.calc.MetersToPixels(1); + if (double.IsNaN(rectHeight) || rectHeight == 0) + rectHeight = Alto * PixelToMeter.Instance.calc.MetersToPixels(1); + + return (new Vector2(_canvasLeft, _canvasTop), + new Vector2(_canvasLeft + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth), + _canvasTop + PixelToMeter.Instance.calc.PixelsToMeters(rectHeight))); } - else return (new Vector2(0, 0), new Vector2(0, 0)); } public (Vector2 Start, Vector2 End) GetCenterLineVectors(Rectangle rect) @@ -1396,27 +1464,56 @@ namespace CtrEditor.ObjetosSim // Usar Dispatcher para asegurar la ejecución en el hilo correcto _visualRepresentation?.Dispatcher.Invoke(() => { - // Asegúrate de que el control está en el árbol visual y actualizado - if (_visualRepresentation.IsLoaded && rect.IsLoaded) + try { - _visualRepresentation.UpdateLayout(); + // Asegúrate de que el control está en el árbol visual y actualizado + if (_visualRepresentation.IsLoaded && rect.IsLoaded && IsVisualChild(rect, _visualRepresentation)) + { + _visualRepresentation.UpdateLayout(); + var _canvasLeft = CanvasGetLeftinMeter(); + var _canvasTop = CanvasGetTopinMeter(); + + var transform = rect.TransformToAncestor(_visualRepresentation); + + // Puntos en coordenadas locales del rectángulo no rotado + Point startLocal = new Point(0, rect.ActualHeight / 2); + Point endLocal = new Point(rect.ActualWidth, rect.ActualHeight / 2); + + // Transformar estos puntos al sistema de coordenadas del ancestro + Point transformedStart = transform.Transform(startLocal); + Point transformedEnd = transform.Transform(endLocal); + + // Convierte a unidades de Farseer (metros en este caso) + start = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.Y) + _canvasTop); + end = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.Y) + _canvasTop); + } + else + { + // Fallback: usar coordenadas básicas + var _canvasLeft = CanvasGetLeftinMeter(); + var _canvasTop = CanvasGetTopinMeter(); + + float rectWidth = (float)rect.ActualWidth; + if (double.IsNaN(rectWidth) || rectWidth == 0) + rectWidth = Ancho * PixelToMeter.Instance.calc.MetersToPixels(1); + + start = new Vector2(_canvasLeft, _canvasTop + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth / 2)); + end = new Vector2(_canvasLeft + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth), _canvasTop + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth / 2)); + } + } + catch (InvalidOperationException) + { + // Fallback en caso de error de transformación var _canvasLeft = CanvasGetLeftinMeter(); var _canvasTop = CanvasGetTopinMeter(); - var transform = rect.TransformToAncestor(_visualRepresentation); + float rectWidth = (float)rect.ActualWidth; + if (double.IsNaN(rectWidth) || rectWidth == 0) + rectWidth = Ancho * PixelToMeter.Instance.calc.MetersToPixels(1); - // Puntos en coordenadas locales del rectángulo no rotado - Point startLocal = new Point(0, rect.ActualHeight / 2); - Point endLocal = new Point(rect.ActualWidth, rect.ActualHeight / 2); - - // Transformar estos puntos al sistema de coordenadas del ancestro - Point transformedStart = transform.Transform(startLocal); - Point transformedEnd = transform.Transform(endLocal); - - // Convierte a unidades de Farseer (metros en este caso) - start = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.Y) + _canvasTop); - end = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.Y) + _canvasTop); + start = new Vector2(_canvasLeft, _canvasTop + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth / 2)); + end = new Vector2(_canvasLeft + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth), _canvasTop + PixelToMeter.Instance.calc.PixelsToMeters(rectWidth / 2)); } });