using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Numerics;
using System.Drawing;
using System.Windows.Controls;
using static JansenLegSimulator.Rod;
namespace JansenLegSimulator
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class Cálculos : Window
{
// Origen de cordenadas
Vector2 Center;
// Dimensiones de los segmentos (iniciales, se pueden modificar des de la interfaz)
public float SCALE { get; set; } = 2.0f;
public float a => 38.0f * SCALE;
public float b => 41.5f * SCALE;
public float c => 39.3f * SCALE;
public float d => 40.1f * SCALE;
public float e => 55.8f * SCALE;
public float f => 39.4f * SCALE;
public float g => 36.7f * SCALE;
public float h => 65.7f * SCALE;
public float i => 49.0f * SCALE;
public float j => 50.0f * SCALE;
public float k => 61.9f * SCALE;
public float l => 7.8f * SCALE;
public float m => 15.0f * SCALE;
private Rod B, C, D, E, F, G, H, I, J, K, M;
public float Omega { get; set; } = (2 * MathF.PI);
System.Timers.Timer t = new(15);
private System.Diagnostics.Stopwatch Chrono = new();
public List Elements { get; set; } = new List();
private List Points = new();
public int MaxPoints { get; set; } = 25;
#region Constructor y handlers de la ventana
public Cálculos()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
this.Closing += MainWindow_Closing;
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Environment.Exit(0);
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
DefineSystem();
DrawSystem();
t.Elapsed += Tick;
}
// Receptores de eventos de click de los botones de la interfaz
private void btnPlay_Click(object sender, RoutedEventArgs e) => StartSimulation();
private void btnPause_Click(object sender, RoutedEventArgs e) => PauseSimulation();
private void btnStop_Click(object sender, RoutedEventArgs e) => StopSimulation();
#endregion
// Receptor de evento de ciclo del reloj
private void Tick(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
// Actualizar el ángulo de la barra motriz
// con ω * t radianes
(Elements[0] as Rod).Alpha = (float)(Omega * Chrono.Elapsed.TotalSeconds) % 2 * MathF.PI;
lock (Points)
{
// Eliminar puntos antiguos si se ha superado el límite de puntos especificado
if (Points.Count > MaxPoints)
Points.RemoveAt(0);
}
// Ejecutar cálculos del sistema
CalculateSystem();
// Ejecutar renderizado del sistema en el hilo de principal
this.Dispatcher.Invoke(() => DrawSystem());
}
catch
{
// Si la geometría es inválida, se lanzará una excepción
// Detener simulación y mostrar el estado de error
this.Dispatcher.Invoke(() =>
{
StopSimulation();
SimulationStatus.Content = "Error";
});
}
}
#region Control de la simulación
// Inicia la simulación
public void StartSimulation()
{
SimulationStatus.Content = "Simulando...";
t.Start();
Chrono.Start();
}
// Pausa la simulación
public void PauseSimulation()
{
SimulationStatus.Content = "En pausa";
t.Stop();
Chrono.Stop();
}
// Detiene la simulación y reinicia las variables
// de tiempo
public void StopSimulation()
{
SimulationStatus.Content = "Detenido";
t.Stop();
Chrono.Stop();
Chrono.Reset();
}
#endregion
[STAThread]
public void DrawSystem()
{
plot.Children.Clear(); // Borrar el contenido anterior del lienzo
Center = new Vector2( // Calcular el centro del lienzo
(float)plot.ActualWidth / 2,
(float)plot.ActualHeight / 2);
foreach (var element in Elements) // Dibujar los elementos en el lienzo
{
if (element.GetType() == typeof(Rod))
DrawElement(element);
if (element.GetType() == typeof(MotorRod))
DrawElement(element);
}
// Registrar el punto que actualmente se ubica
// en el extremo final de la barra I
Points.Add(I.EndPosition);
lock (Points)
{
// Dibujar los puntos en el lienzo
foreach (Vector2 point in Points)
DrawPoint(point);
}
}
#region Inserción de objetos
public void DrawElement(object r) where Type : Rod
{
// Declarar una línea de color azul con 5px de grosos
// segmentada entre los dos extremos de la barra.
Line l = new Line()
{
Stroke = Brushes.Blue,
StrokeThickness = 5,
X1 = Center.X + (r as Type).StartPosition.X,
X2 = Center.X + (r as Type).EndPosition.X,
Y1 = Center.Y - (r as Type).StartPosition.Y,
Y2 = Center.Y - (r as Type).EndPosition.Y,
};
// Añadir la barra al lienzo
plot.Children.Add(l);
}
public void DrawPoint(Vector2 Location, double diameter = 5)
{
double r = diameter / 2; // Calcular radio del punto
// Declarar una elipse de color rojo con
// el mismo ancho que altura (diámetro).
Ellipse e = new Ellipse()
{
Fill = Brushes.Red,
Width = diameter,
Height = diameter
};
// Añadir la elipse al lienzo
plot.Children.Add(e);
// Situar la elipse dentro del lienzo.
// Los ejes de coordenadas del lienzo tienen origen en
// la esquina superior izquierda. El eje vertical se debe
// invertir.
Canvas.SetLeft(e, Center.X + Location.X - r);
Canvas.SetTop(e, plot.ActualHeight - (Center.Y + Location.Y - r));
}
#endregion
}
}