202 lines
6.8 KiB
C#
202 lines
6.8 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
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<Rod> Elements { get; set; } = new List<Rod>();
|
|
private List<Vector2> 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<Rod>(element);
|
|
if (element.GetType() == typeof(MotorRod))
|
|
DrawElement<MotorRod>(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<Type>(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
|
|
}
|
|
}
|