using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using LibS7Adv;
using CtrEditor.Simulacion;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using CtrEditor.FuncionesBase;
using System.Text.Json.Serialization;
namespace CtrEditor.ObjetosSim
{
///
/// Interaction logic for ucTransporteCurvaGuias.xaml
///
public partial class osTransporteCurvaGuias : osBase, IosBase
{
private osBase Motor = null;
private simCurve Simulation_TransporteCurvaGuias;
// Listas para almacenar los segmentos de las guías curvas
private List GuiasSuperiores = new List();
private List GuiasInferiores = new List();
private float _velocidadActual;
public static string NombreClase()
{
return "Transporte Curva Guias";
}
private string nombre = "Transporte Curva Guias";
public override string Nombre
{
get => nombre;
set => SetProperty(ref nombre, value);
}
[ObservableProperty]
public float velocidadActual;
partial void OnVelocidadActualChanged(float value)
{
SetSpeed();
}
[ObservableProperty]
bool invertirDireccion;
partial void OnInvertirDireccionChanged(bool value)
{
SetSpeed();
if (_visualRepresentation is ucTransporteCurvaGuias uc)
{
CrearAnimacionStoryBoardTrasnporteCircular(uc.Transporte.TransportePath, InvertirDireccion, Angulo);
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
}
void SetSpeed()
{
if (InvertirDireccion)
Simulation_TransporteCurvaGuias?.SetSpeed(-VelocidadActual);
else
Simulation_TransporteCurvaGuias?.SetSpeed(VelocidadActual);
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
[ObservableProperty]
private float radioExterno;
partial void OnRadioExternoChanged(float value)
{
// Update ancho and alto based on radioExterno
Ancho = value * 2;
Alto = value * 2;
// Ensure radioInterno maintains proper proportion if needed
if (RadioInterno >= value)
{
RadioInterno = value * 0.75f; // Default proportion
}
ActualizarGeometrias();
}
[ObservableProperty]
private float radioInterno;
partial void OnRadioInternoChanged(float value)
{
ActualizarGeometrias();
}
[ObservableProperty]
[property: Description("Número de segmentos para las guías (máximo 20)")]
[property: Category("Guías")]
private int numeroSegmentosGuias;
partial void OnNumeroSegmentosGuiasChanged(int value)
{
// Limitar entre 4 y 20 segmentos
if (value < 4) NumeroSegmentosGuias = 4;
if (value > 20) NumeroSegmentosGuias = 20;
ActualizarGeometrias();
}
[ObservableProperty]
[property: Description("Grosor de las guías")]
[property: Category("Guías")]
private float grosorGuias;
partial void OnGrosorGuiasChanged(float value)
{
ActualizarGeometrias();
}
[ObservableProperty]
[property: Description("Distancia de separación de las guías desde el borde")]
[property: Category("Guías")]
private float distanciaGuias;
partial void OnDistanciaGuiasChanged(float value)
{
ActualizarGeometrias();
}
[ObservableProperty]
[property: Description("Bit to enable Link to Motor")]
[property: Category("PLC link:")]
string tag_ReleActivatedMotor;
[ObservableProperty]
[property: Description("Link to Motor")]
[property: Category("PLC link:")]
[property: ItemsSource(typeof(osBaseItemsSource))]
string id_Motor;
[JsonIgnore]
private PropertyChangedEventHandler motorPropertyChangedHandler;
partial void OnId_MotorChanged(string value)
{
if (Motor != null && motorPropertyChangedHandler != null)
Motor.PropertyChanged -= motorPropertyChangedHandler;
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
{
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
if (Motor != null)
{
motorPropertyChangedHandler = (sender, e) =>
{
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
{
Id_Motor = ((osVMmotorSim)sender).Nombre;
}
};
Motor.PropertyChanged += motorPropertyChangedHandler;
}
}
}
public override void AnguloChanged(float value)
{
OnPropertyChanged(nameof(AnguloFinal));
ActualizarGeometrias();
}
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
private float arco_en_grados;
partial void OnArco_en_gradosChanged(float value)
{
ActualizarGeometrias();
}
[Hidden]
public float AnguloFinal
{
get => Angulo + Arco_en_grados;
}
private void ActualizarGeometrias()
{
if (_visualRepresentation is ucTransporteCurvaGuias uc)
{
UpdateCurve(Simulation_TransporteCurvaGuias, RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados);
ActualizarGuiasCurvas();
SetSpeed();
}
}
private void ActualizarGuiasCurvas()
{
// Limpiar guías existentes
EliminarGuiasExistentes();
// Crear nuevas guías
CrearGuiasCurvas();
}
private void EliminarGuiasExistentes()
{
foreach (var guia in GuiasSuperiores)
{
simulationManager?.Remove(guia);
}
foreach (var guia in GuiasInferiores)
{
simulationManager?.Remove(guia);
}
GuiasSuperiores.Clear();
GuiasInferiores.Clear();
}
private void CrearGuiasCurvas()
{
if (NumeroSegmentosGuias < 4 || simulationManager == null)
return;
float radioGuiaSuperior = RadioExterno + DistanciaGuias;
float radioGuiaInferior = RadioInterno - DistanciaGuias;
// Asegurar que el radio interior de la guía no sea negativo
if (radioGuiaInferior < 0.01f)
radioGuiaInferior = 0.01f;
// Convertir ángulos a radianes
float anguloInicioRad = simBase.GradosARadianes(Angulo);
float anguloFinalRad = simBase.GradosARadianes(AnguloFinal);
float rangoAngular = anguloFinalRad - anguloInicioRad;
// Calcular el paso angular entre segmentos
float pasoAngular = rangoAngular / NumeroSegmentosGuias;
// Obtener el centro una vez para todo el método
nkast.Aether.Physics2D.Common.Vector2 centro = GetCurveCenterInMeter(RadioExterno);
// Crear segmentos para guía superior (externa)
for (int i = 0; i < NumeroSegmentosGuias; i++)
{
float angulo1 = anguloInicioRad + i * pasoAngular;
float angulo2 = anguloInicioRad + (i + 1) * pasoAngular;
nkast.Aether.Physics2D.Common.Vector2 punto1 = new nkast.Aether.Physics2D.Common.Vector2(
radioGuiaSuperior * (float)Math.Cos(angulo1),
radioGuiaSuperior * (float)Math.Sin(angulo1)
);
nkast.Aether.Physics2D.Common.Vector2 punto2 = new nkast.Aether.Physics2D.Common.Vector2(
radioGuiaSuperior * (float)Math.Cos(angulo2),
radioGuiaSuperior * (float)Math.Sin(angulo2)
);
// Ajustar por la posición del objeto
punto1 += centro;
punto2 += centro;
simGuia guiaSegmento = simulationManager.AddLine(punto1, punto2);
GuiasSuperiores.Add(guiaSegmento);
}
// Crear segmentos para guía inferior (interna)
for (int i = 0; i < NumeroSegmentosGuias; i++)
{
float angulo1 = anguloInicioRad + i * pasoAngular;
float angulo2 = anguloInicioRad + (i + 1) * pasoAngular;
nkast.Aether.Physics2D.Common.Vector2 punto1 = new nkast.Aether.Physics2D.Common.Vector2(
radioGuiaInferior * (float)Math.Cos(angulo1),
radioGuiaInferior * (float)Math.Sin(angulo1)
);
nkast.Aether.Physics2D.Common.Vector2 punto2 = new nkast.Aether.Physics2D.Common.Vector2(
radioGuiaInferior * (float)Math.Cos(angulo2),
radioGuiaInferior * (float)Math.Sin(angulo2)
);
// Ajustar por la posición del objeto
punto1 += centro;
punto2 += centro;
simGuia guiaSegmento = simulationManager.AddLine(punto1, punto2);
GuiasInferiores.Add(guiaSegmento);
}
}
public override void OnMoveResizeRotate()
{
ActualizarGeometrias();
}
[ObservableProperty]
public float frictionCoefficient;
[ObservableProperty]
public float velMax50hz;
[ObservableProperty]
public float tiempoRampa;
[ObservableProperty]
public bool esMarcha;
public override void OnResize(float Delta_Width, float Delta_Height)
{
// Calculate the proportional change factor
float widthChangeFactor = (Ancho + Delta_Width) / Ancho;
float heightChangeFactor = (Alto + Delta_Height) / Alto;
// Use the average or minimum change factor to maintain aspect ratio
float changeFactor = Math.Min(widthChangeFactor, heightChangeFactor);
// Save the original radiuses for calculating position adjustments
float originalRadioExterno = RadioExterno;
// Apply the change factor to both radios
RadioExterno *= changeFactor;
RadioInterno *= changeFactor;
// Calculate position adjustment to keep the component centered
float radiusDifference = RadioExterno - originalRadioExterno;
// Adjust Left and Top to maintain center position
// We move by negative half the difference because the component expands outward
Left -= radiusDifference;
Top -= radiusDifference;
// Ensure minimums
if (RadioExterno < 0.1f)
RadioExterno = 0.1f;
if (RadioInterno < 0.05f)
RadioInterno = 0.05f;
// Ensure radioInterno is always less than radioExterno
if (RadioInterno >= RadioExterno)
RadioInterno = RadioExterno * 0.75f;
}
public osTransporteCurvaGuias()
{
RadioExterno = 1.3f;
RadioInterno = 1f;
Ancho = RadioExterno * 2; // Set initial width based on external radius
Alto = RadioExterno * 2; // Set initial height based on external radius
Arco_en_grados = 90;
Tag_ReleActivatedMotor = "1";
NumeroSegmentosGuias = 12; // Valor por defecto
GrosorGuias = 0.03f;
DistanciaGuias = 0.05f;
}
public override void UpdateGeometryStart()
{
// Se llama antes de la simulacion
ActualizarGeometrias();
}
public override void SimulationStop()
{
// Se llama al detener la simulacion
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
{
if (Motor != null)
{
if (Motor is osVMmotorSim motor)
if (LeerBitTag(Tag_ReleActivatedMotor))
VelocidadActual = motor.Velocidad;
else
VelocidadActual = 0;
}
}
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
if (_visualRepresentation is ucTransporteCurvaGuias uc)
{
Simulation_TransporteCurvaGuias = AddCurve(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados);
CrearGuiasCurvas(); // Crear las guías curvas
CrearAnimacionStoryBoardTrasnporteCircular(uc.Transporte.TransportePath, InvertirDireccion, Angulo);
}
}
public override void ucUnLoaded()
{
// El UserControl se esta eliminando
// eliminar el objeto de simulacion
simulationManager?.Remove(Simulation_TransporteCurvaGuias);
EliminarGuiasExistentes();
}
}
public partial class ucTransporteCurvaGuias : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public int zIndex_fromFrames { get; set; }
public ucTransporteCurvaGuias()
{
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_Base()
{
return ZIndexEnum.Estaticos;
}
}
}