using LibS7Adv; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using CommunityToolkit.Mvvm.ComponentModel; using System.Diagnostics; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using System.ComponentModel; using CtrEditor.FuncionesBase; namespace CtrEditor.ObjetosSim { /// /// Interaction logic for ucGearEncoder.xaml /// public partial class osGearEncoder : osBase, IosBase { private osBase Motor = null; private Stopwatch Stopwatch = new Stopwatch(); private double stopwatch_last = 0; // Otros datos y métodos relevantes para la simulación public static string NombreClase() { return "Ruota Fonica"; } private string nombre = NombreClase(); public override string Nombre { get => nombre; set => SetProperty(ref nombre, value); } [ObservableProperty] public string tag; [ObservableProperty] public bool pulso; partial void OnPulsoChanged(bool value) { if (value) { var dTime = Stopwatch.ElapsedMilliseconds - stopwatch_last; stopwatch_last = Stopwatch.ElapsedMilliseconds; Tiempo_Pulso = (float)dTime; } EscribirBitTag(Tag, Pulso); if (value) Color_oculto = Brushes.LightGreen; else Color_oculto = Brushes.Gray; } [ObservableProperty] private Brush color_oculto; [ObservableProperty] public float velocidadActual; public override void AnguloChanged(float value) { // Generar pulsos cuadrados en función del ángulo Pulso = DetectarDiente(); } [ObservableProperty] public float tiempo_Pulso; [ObservableProperty] public float pulsos_Por_Segundo; partial void OnPulsos_Por_SegundoChanged(float value) { if (VelocidadActual > 0) Giros_segundo_a_100 = (float)((pulsos_Por_Segundo / Dientes) * 100 / VelocidadActual); } [ObservableProperty] private bool homing; partial void OnHomingChanged(bool value) { homing = false; Angulo = 0; } [ObservableProperty] public float dientes; [ObservableProperty] public float radio_Interno; [ObservableProperty] public float radio_Externo; [ObservableProperty] public float ancho_Dientes; [ObservableProperty] public float giros_segundo_a_100; public override void OnResize(float Delta_Width, float Delta_Height) { Radio_Externo += Delta_Width; Radio_Interno += Delta_Height; } [ObservableProperty] [property: Description("Link to Motor")] [property: Category("PLC link:")] [property: ItemsSource(typeof(osBaseItemsSource))] string id_Motor; partial void OnId_MotorChanged(string value) { if (Motor != null) Motor.PropertyChanged -= OnMotorPropertyChanged; if (_mainViewModel != null && value != null && value.Length > 0) { Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null); if (Motor != null) Motor.PropertyChanged += OnMotorPropertyChanged; } } private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(osVMmotorSim.Nombre)) { Id_Motor = ((osVMmotorSim)sender).Nombre; } } public osGearEncoder() { Ancho_Dientes = 0.5f; Dientes = 10; Radio_Interno = 0.5f; Radio_Externo = 0.6f; Color_oculto = Brushes.Gray; Stopwatch.Start(); } public override void UpdateGeometryStart() { // Se llama antes de la simulacion } public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) { if (Motor != null) { if (Motor is osVMmotorSim motor) { VelocidadActual = motor.Velocidad; // Calcular la cantidad de giros por segundo double girosPorSegundo = (VelocidadActual / 100.0) * Giros_segundo_a_100; // Calcular la fracción del segundo que ha pasado double segundosTranscurridos = elapsedMilliseconds / 1000.0; // Calcular el incremento de ángulo double incrementoAngulo = (girosPorSegundo * 360.0) * segundosTranscurridos; // Actualizar el ángulo Angulo = (float) (Angulo + incrementoAngulo) % 360; } } } public bool DetectarDiente() { double angleStep = 360.0 / Dientes; double halfToothWidthAngle = (angleStep * Ancho_Dientes) / 2; // Normalize the Angulo to be within 0-360 degrees double normalizedAngle = Angulo % 360; if (normalizedAngle < 0) normalizedAngle += 360; // Calculate the position of the first tooth's center at angle 0 double firstToothCenterAngle = 0; // Calculate the angular distance from the current angle to the first tooth's center double angularDistance = Math.Abs(firstToothCenterAngle - normalizedAngle); if (angularDistance > 180) angularDistance = 360 - angularDistance; // Check if the normalized angle falls within the segment of the first tooth if (angularDistance <= halfToothWidthAngle) { return true; } // Calculate the number of steps to reach the nearest tooth's center int steps = (int)Math.Round(normalizedAngle / angleStep); // Calculate the angular position of the nearest tooth's center double nearestToothCenterAngle = steps * angleStep; // Calculate the angular distance from the current angle to the nearest tooth's center angularDistance = Math.Abs(nearestToothCenterAngle - normalizedAngle); if (angularDistance > 180) angularDistance = 360 - angularDistance; // Check if the normalized angle falls within the segment of the nearest tooth return angularDistance <= halfToothWidthAngle; } public override void UpdateControl(int elapsedMilliseconds) { // Calculamos la velocidad } public override void ucLoaded() { // El UserControl ya se ha cargado y podemos obtener las coordenadas para // crear el objeto de simulacion base.ucLoaded(); OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor } } public partial class ucGearEncoder : UserControl, IDataContainer { public osBase? Datos { get; set; } public ucGearEncoder() { InitializeComponent(); this.Loaded += OnLoaded; this.Unloaded += OnUnloaded; } private void OnLoaded(object sender, RoutedEventArgs e) { Datos?.ucLoaded(); } private void OnUnloaded(object sender, RoutedEventArgs e) { Datos?.ucUnLoaded(); } public void Highlight(bool State) { } public ZIndexEnum ZIndex() { return ZIndexEnum.Estaticos; } } }