using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Text; using System.Text.Json.Serialization; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using static System.Runtime.InteropServices.JavaScript.JSType; using CtrEditor.Convertidores; using CtrEditor.Siemens; using CtrEditor.Simulacion; using System.Windows.Media; using nkast.Aether.Physics2D.Common; using FarseerPhysics.Dynamics; using Siemens.Simatic.Simulation.Runtime; using System.Windows.Media.Imaging; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using System.Windows.Media.Animation; namespace CtrEditor.ObjetosSim { public interface IosBase { static abstract string NombreClase(); } public interface IDataContainer { [JsonIgnore] osBase? Datos { get; set; } void Resize(float width, float height); void Move(float Left, float Top); void Rotate(float Angle); void Highlight(bool State); int ZIndex(); } public class DataSaveToSerialize { private MainViewModel? _mainViewModel; private UserControl? VisualRepresentation; private SimulationManagerFP? simulationManager; public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerFP c ) { _mainViewModel = a; VisualRepresentation = b; simulationManager = c; } public void DataRestoreAfterSerialize(out MainViewModel a, out UserControl b, out SimulationManagerFP c) { a = _mainViewModel; b = VisualRepresentation; c = simulationManager; } } public abstract partial class osBase : ObservableObject { public virtual string Nombre { get; set; } = "osBase"; [JsonIgnore] private Storyboard _storyboard; [ObservableProperty] private float left; partial void OnLeftChanged(float value) { CanvasSetLeftinMeter(value); LeftChanged(value); } public virtual void LeftChanged(float value) { } [ObservableProperty] private float top; partial void OnTopChanged(float value) { CanvasSetTopinMeter(value); TopChanged(value); } public virtual void TopChanged(float value) { } public bool Inicializado = false; public bool AutoCreated = false; public bool RemoverDesdeSimulacion = false; // La simulacion indica que se debe remover [JsonIgnore] private DataSaveToSerialize DataSave; [JsonIgnore] protected UserControl? _visualRepresentation = null; [JsonIgnore] protected PLCModel? _plc = null; public virtual void UpdateControl(int elapsedMilliseconds) { } public virtual void UpdateGeometryStart() { // Se llama antes de la simulacion } public virtual void SimulationStop() { } public virtual void UpdateGeometryStep() { } public virtual void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { } public virtual void ucLoaded() { // El UserControl ya se ha cargado y podemos obtener las coordenadas para // crear el objeto de simulacion ActualizarLeftTop(); } public virtual void ucUnLoaded() { // El UserControl se esta eliminando // eliminar el objeto de simulacion } [JsonIgnore] public MainViewModel _mainViewModel; [JsonIgnore] public UserControl? VisualRepresentation { get => _visualRepresentation; set => _visualRepresentation = value; } [JsonIgnore] public SimulationManagerFP simulationManager; public void SalvarDatosNoSerializables() { DataSave = new DataSaveToSerialize(_mainViewModel,_visualRepresentation,simulationManager); _mainViewModel = null; _visualRepresentation = null; simulationManager = null; } public void RestaurarDatosNoSerializables() { if (DataSave == null) return; DataSave.DataRestoreAfterSerialize(out _mainViewModel,out _visualRepresentation,out simulationManager); } public void SetPLC(PLCModel plc) { _plc = plc; } protected osBase ObtenerLink(string NameLink, Type tipoOsBase) { if (!string.IsNullOrEmpty(NameLink) && _mainViewModel != null) { foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables) { if (tipoOsBase.IsInstanceOfType(objetoSimulable) && objetoSimulable.Nombre == NameLink) { return objetoSimulable; } } } return null; } protected void CrearAnimacionStoryBoardTrasnporte(System.Windows.Shapes.Rectangle transporte) { if (_visualRepresentation == null) return; if (transporte == null) return; _storyboard = new Storyboard(); var animation = new DoubleAnimation { From = 0, To = 20, // Total Pixels Brush Duration = TimeSpan.FromSeconds(PixelToMeter.Instance.calc.PixelsToMeters(20) * 60), RepeatBehavior = RepeatBehavior.Forever }; Storyboard.SetTarget(animation, transporte); Storyboard.SetTargetProperty(animation, new PropertyPath("(Rectangle.Fill).(VisualBrush.Transform).(TransformGroup.Children)[0].(TranslateTransform.X)")); _storyboard.Children.Add(animation); _storyboard.Begin(); _storyboard.SetSpeedRatio(0); } protected void ActualizarAnimacionStoryBoardTransporte(float velocidadActual) { if (_visualRepresentation == null) return; if (_storyboard == null) return; if (!_mainViewModel.IsSimulationRunning) _storyboard.SetSpeedRatio(0); else _storyboard.SetSpeedRatio(velocidadActual); } public void ActualizarLeftTop() { CanvasSetLeftinMeter(Left); CanvasSetTopinMeter(Top); } public bool LeerBitTag(string Tag) { if (this._plc == null) return false; if (!string.IsNullOrEmpty(Tag)) { if (Tag == "1") return true; else if (Tag == "0") return false; if (_plc != null) return _plc.LeerTagBool(Tag); } return false; } public void EscribirBitTag(string Tag, bool Value) { if (_plc == null) return; if (!string.IsNullOrEmpty(Tag)) if (_plc != null) _plc.EscribirTagBool(Tag, Value); } public void EscribirWordTagScaled(string Tag, float Value, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max) { if (_plc == null) return; if (!string.IsNullOrEmpty(Tag)) { SDataValue plcData = new SDataValue(); plcData.UInt16 = (ushort)((Value - IN_scale_Min) / (IN_scale_Max - IN_scale_Min) * (OUT_scale_Max - OUT_scale_Min) + OUT_scale_Min); _plc.EscribirTag(Tag, plcData); } } public float LeerWordTagScaled(PLCModel _plc, string Tag, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max) { if (_plc == null) return 0; if (!string.IsNullOrEmpty(Tag)) { if (float.TryParse(Tag, out float v)) return v; if (_plc != null) { SDataValue plcData = _plc.LeerTag(Tag); float Value = plcData.UInt16; // WORD return (Value - OUT_scale_Min) / (OUT_scale_Max - OUT_scale_Min) * (IN_scale_Max - IN_scale_Min) + IN_scale_Min; } } return 0; } public void CanvasSetLeftinMeter(float left) { if (_visualRepresentation != null) Canvas.SetLeft(_visualRepresentation, PixelToMeter.Instance.calc.MetersToPixels(left)); } public float CanvasGetLeftinMeter() { if (_visualRepresentation != null) return PixelToMeter.Instance.calc.PixelsToMeters((float)Canvas.GetLeft(_visualRepresentation)); else return 0f; } public void CanvasSetTopinMeter(float top) { if (_visualRepresentation != null) Canvas.SetTop(_visualRepresentation, PixelToMeter.Instance.calc.MetersToPixels(top)); } public float CanvasGetTopinMeter() { if (_visualRepresentation != null) return PixelToMeter.Instance.calc.PixelsToMeters((float)Canvas.GetTop(_visualRepresentation)); else return 0f; } public (Vector2 TopLeft, Vector2 BottomRight) GetRectangleCoordinatesInMeter(System.Windows.Shapes.Rectangle rect) { if (rect != null) { var _canvasLeft = CanvasGetLeftinMeter(); var _canvasTop = CanvasGetTopinMeter(); // Obtiene la transformada del objeto visual GeneralTransform transform = rect.TransformToAncestor(_visualRepresentation); // Obtiene la posición absoluta 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)); } else return (new Vector2(0, 0), new Vector2(0, 0)); } public (Vector2 Start, Vector2 End) GetCenterLineVectors(System.Windows.Shapes.Rectangle rect) { if (rect == null) return (new Vector2(0, 0), new Vector2(0, 0)); 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) Vector2 start = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.Y) + _canvasTop); Vector2 end = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.Y) + _canvasTop); return (start, end); } public Vector2 GetCurveCenterInMeter(float RadioExterno) { var _canvasLeft = CanvasGetLeftinMeter(); var _canvasTop = CanvasGetTopinMeter(); // El centro del Canvas double centerX = RadioExterno + _canvasLeft; double centerY = RadioExterno + _canvasTop; // Convertir a Vector2 return new Vector2((float)centerX, (float)centerY); } public Vector2 GetRectangleCenter(System.Windows.Shapes.Rectangle wpfRect) { var coords = GetRectangleCoordinatesInMeter(wpfRect); Vector2 topLeft = coords.TopLeft; Vector2 bottomRight = coords.BottomRight; // Calcular el centro, ancho y alto en metros return new Vector2((topLeft.X + bottomRight.X) / 2, (topLeft.Y + bottomRight.Y) / 2); } public void UpdateRectangle(simTransporte simRect, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo) { if (simRect != null) simRect.Create(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo); } public void UpdateRectangle(simBarrera simRect, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo) { if (simRect != null) simRect.Create(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo); } public void UpdateCurve(simCurve curva,float RadioInterno, float RadioExterno, float startAngle, float endAngle) { curva.Create(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno)); } public simCurve AddCurve(float RadioInterno, float RadioExterno, float startAngle, float endAngle) { return simulationManager.AddCurve(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno)); } public simTransporte AddRectangle(SimulationManagerFP simulationManager, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo) { return simulationManager.AddRectangle(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo); } public simBarrera AddBarrera(SimulationManagerFP simulationManager, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo) { return simulationManager.AddBarrera(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo); } public void UpdateOrCreateLine(simGuia simGuia, System.Windows.Shapes.Rectangle wpfRect) { if (simGuia != null) { var coords = GetCenterLineVectors(wpfRect); // Crear o actualizar simRectangle simGuia.Create(coords.Start, coords.End); // asumiendo que el ángulo inicial es 0 } } public simGuia AddLine(SimulationManagerFP simulationManager, System.Windows.Shapes.Rectangle wpfRect) { var coords = GetCenterLineVectors(wpfRect); return simulationManager.AddLine(coords.Start, coords.End); } public ImageSource ImageFromPath(string value) { if (value is string stringValue) { return new BitmapImage(new Uri(stringValue, UriKind.RelativeOrAbsolute)); } return null; } static protected T GetLastElement(List list) where T : class { if (list.Count > 0) { return list[list.Count - 1]; } else { return null; } } } [AttributeUsage(AttributeTargets.Property)] public class HiddenAttribute : Attribute { } }