Agregar archivos de proyecto.
This commit is contained in:
25
JansenLegViewer.sln
Normal file
25
JansenLegViewer.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.31727.386
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JansenLegSimulator", "JansenLegViewer\JansenLegSimulator.csproj", "{85D59382-1D81-41E1-8213-CAAF5D8F6B2C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{85D59382-1D81-41E1-8213-CAAF5D8F6B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{85D59382-1D81-41E1-8213-CAAF5D8F6B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{85D59382-1D81-41E1-8213-CAAF5D8F6B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{85D59382-1D81-41E1-8213-CAAF5D8F6B2C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B0ECD860-46CD-477E-ADA8-2F17A594387D}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
9
JansenLegViewer/App.xaml
Normal file
9
JansenLegViewer/App.xaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<Application x:Class="JansenLegViewer.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:JansenLegViewer"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
17
JansenLegViewer/App.xaml.cs
Normal file
17
JansenLegViewer/App.xaml.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace JansenLegViewer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
10
JansenLegViewer/AssemblyInfo.cs
Normal file
10
JansenLegViewer/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
75
JansenLegViewer/CosasQueNoSeExplicanEnMatesDePrimero.cs
Normal file
75
JansenLegViewer/CosasQueNoSeExplicanEnMatesDePrimero.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using static System.Math;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Función que permite obtener las posiciones de las
|
||||||
|
posibles intersecciones entre dos circulos.
|
||||||
|
|
||||||
|
PD: le debeo un café a alguien random de internet
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace JansenLegSimulator
|
||||||
|
{
|
||||||
|
public class CosasQueNoSeExplicanEnMatesDePrimero
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the intersections of two circles
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="center1">The first circle's center</param>
|
||||||
|
/// <param name="center2">The second circle's center</param>
|
||||||
|
/// <param name="radius1">The first circle's radius</param>
|
||||||
|
/// <param name="radius2">The second circle's radius. If omitted, assumed to equal the first circle's radius</param>
|
||||||
|
/// <returns>An array of intersection points. May have zero, one, or two values</returns>
|
||||||
|
/// <remarks>Adapted from http://csharphelper.com/blog/2014/09/determine-where-two-circles-intersect-in-c/</remarks>
|
||||||
|
public static Vector2[] CalculateCircleIntersections(Vector2 center1, Vector2 center2, double radius1, double? radius2 = null)
|
||||||
|
{
|
||||||
|
// Definir radios. Si sólo se ha dado R1,
|
||||||
|
// asignar valor de R1 a los dos radios
|
||||||
|
var (r1, r2) = (radius1, radius2 ?? radius1);
|
||||||
|
|
||||||
|
// Definir centros de los circulos.
|
||||||
|
(double x1, double y1, double x2, double y2) = (center1.X, center1.Y, center2.X, center2.Y);
|
||||||
|
|
||||||
|
// Determinar la distancia entre los dos centros.
|
||||||
|
// Es el módulo del vector que une los dos centros.
|
||||||
|
double d = Sqrt(Pow(x1 - x2, 2) + Pow(y1 - y2, 2));
|
||||||
|
|
||||||
|
// Si la suma de radios es menor a la distancia que
|
||||||
|
// une los centros, devolver un array vacío.
|
||||||
|
// No existe intersección.
|
||||||
|
if (!(Abs(r1 - r2) <= d && d <= r1 + r2)) { return new Vector2[0]; }
|
||||||
|
|
||||||
|
// En este momento, se dan las condiciones para que
|
||||||
|
// por lo menos exista una intersección
|
||||||
|
var dsq = d * d; // Caucular el cuadrado de la distancia (d^2)
|
||||||
|
var (r1sq, r2sq) = (r1 * r1, r2 * r2); // Calcular los cuadrados de los radios (r^2)
|
||||||
|
var r1sq_r2sq = r1sq - r2sq; // Calcular la diferencia de los r^2 (incR^2)
|
||||||
|
var a = r1sq_r2sq / (2 * dsq); // Calcular la división (incR^2)/(2*d^2)
|
||||||
|
|
||||||
|
var c = Sqrt(2 * (r1sq + r2sq) / dsq - (r1sq_r2sq * r1sq_r2sq) / (dsq * dsq) - 1);
|
||||||
|
|
||||||
|
// Calcular las componentes de los resultados
|
||||||
|
var fx = (x1 + x2) / 2 + a * (x2 - x1);
|
||||||
|
var gx = c * (y2 - y1) / 2;
|
||||||
|
|
||||||
|
var fy = (y1 + y2) / 2 + a * (y2 - y1);
|
||||||
|
var gy = c * (x1 - x2) / 2;
|
||||||
|
|
||||||
|
// Generar los vectores de las intersecciones resultado
|
||||||
|
var i1 = new Vector2((float)(fx + gx), (float)(fy + gy));
|
||||||
|
var i2 = new Vector2((float)(fx - gx), (float)(fy - gy));
|
||||||
|
|
||||||
|
// Si son la misma solucción deveolver sólo i1.
|
||||||
|
// Si son ditintas, devolver ambas soluciones.
|
||||||
|
return i1 == i2 ?
|
||||||
|
new Vector2[] { i1 } :
|
||||||
|
new Vector2[] { i1, i2 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
JansenLegViewer/Cálculos.cs
Normal file
73
JansenLegViewer/Cálculos.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static JansenLegSimulator.Rod;
|
||||||
|
|
||||||
|
namespace JansenLegSimulator
|
||||||
|
{
|
||||||
|
public partial class Cálculos
|
||||||
|
{
|
||||||
|
private void DefineSystem()
|
||||||
|
{
|
||||||
|
// Definir las barra motriz
|
||||||
|
M = new Rod(new Vector2(a, l)) { Length = m, RodName = "M" };
|
||||||
|
|
||||||
|
// Definir las barras semi-independientes
|
||||||
|
// Aquellas que tienen un extremo fijado a una coordenada
|
||||||
|
B = new Rod(new Vector2(0, 0)) { Length = b, RodName = "B" };
|
||||||
|
C = new Rod(new Vector2(0, 0)) { Length = c, RodName = "C" };
|
||||||
|
D = new Rod(new Vector2(0, 0)) { Length = d, RodName = "D" };
|
||||||
|
|
||||||
|
// Definir y conectar los inicios de las barras flotantes
|
||||||
|
// Aquellas cuyos dos extremos están conectados a otra barra
|
||||||
|
J = new Rod() { Length = j, RodName = "J" }; J.ConnectBegin(ref M);
|
||||||
|
K = new Rod() { Length = k, RodName = "K" }; K.ConnectBegin(ref M);
|
||||||
|
E = new Rod() { Length = e, RodName = "E" }; E.ConnectBegin(ref B);
|
||||||
|
|
||||||
|
G = new Rod() { Length = g, RodName = "G" }; G.ConnectBegin(ref C);
|
||||||
|
F = new Rod() { Length = f, RodName = "F" }; F.ConnectBegin(ref D);
|
||||||
|
|
||||||
|
H = new Rod() { Length = h, RodName = "H" }; H.ConnectBegin(ref G);
|
||||||
|
I = new Rod() { Length = i, RodName = "I" }; I.ConnectBegin(ref C);
|
||||||
|
|
||||||
|
// Añadir las barras definidas a la lista
|
||||||
|
// de elementos móviles.
|
||||||
|
Elements.Add(M);
|
||||||
|
Elements.Add(J);
|
||||||
|
Elements.Add(B);
|
||||||
|
|
||||||
|
Elements.Add(C);
|
||||||
|
Elements.Add(K);
|
||||||
|
|
||||||
|
Elements.Add(E);
|
||||||
|
Elements.Add(D);
|
||||||
|
|
||||||
|
Elements.Add(G);
|
||||||
|
Elements.Add(F);
|
||||||
|
|
||||||
|
Elements.Add(H);
|
||||||
|
Elements.Add(I);
|
||||||
|
}
|
||||||
|
|
||||||
|
[STAThread]
|
||||||
|
public void CalculateSystem()
|
||||||
|
{
|
||||||
|
// Para cada par de barras calcular y asignar los
|
||||||
|
// ángulos de rotación necesarios para unirlas
|
||||||
|
|
||||||
|
// Articulación JB
|
||||||
|
(J.Alpha, B.Alpha) = GetIntersectionAlphas(J, B);
|
||||||
|
// Articulación CK
|
||||||
|
(C.Alpha, K.Alpha) = GetIntersectionAlphas(C, K);
|
||||||
|
// Articulación ED
|
||||||
|
(E.Alpha, D.Alpha) = GetIntersectionAlphas(E, D);
|
||||||
|
// Articulación FG
|
||||||
|
(F.Alpha, G.Alpha) = GetIntersectionAlphas(F, G);
|
||||||
|
// Articulación HI
|
||||||
|
(H.Alpha, I.Alpha) = GetIntersectionAlphas(H, I);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
JansenLegViewer/JansenLegSimulator.csproj
Normal file
9
JansenLegViewer/JansenLegSimulator.csproj
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net5.0-windows</TargetFramework>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
BIN
JansenLegViewer/JansenLegSimulator.zip
Normal file
BIN
JansenLegViewer/JansenLegSimulator.zip
Normal file
Binary file not shown.
56
JansenLegViewer/MainWindow.xaml
Normal file
56
JansenLegViewer/MainWindow.xaml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<Window x:Class="JansenLegSimulator.Cálculos"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:JansenLegViewer"
|
||||||
|
Name="thisWindow"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="MainWindow" Height="450" Width="800">
|
||||||
|
<Grid Margin="1,0,-1,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="80*" />
|
||||||
|
<ColumnDefinition Width="20*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition/>
|
||||||
|
<RowDefinition Height="26"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Canvas Name="plot" Grid.Column="0"/>
|
||||||
|
<GridSplitter BorderBrush="LightGray" BorderThickness="3"/>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="1">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Button Name="btnPlay" Content=">" Click="btnPlay_Click"/>
|
||||||
|
<Button Name="btnPause" Content="| |" Click="btnPause_Click"/>
|
||||||
|
<Button Name="btnStop" Content="#" Click="btnStop_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
<Label Content="ω rotor (rad/s)"/>
|
||||||
|
<TextBox Text="{Binding ElementName=thisWindow, Path=Omega, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label Content="Número de puntos"/>
|
||||||
|
<Label Content="{Binding ElementName=sbPoints, Path=Value}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<ScrollBar Name="sbPoints" Orientation="Horizontal" Value="{Binding ElementName=thisWindow, Path=MaxPoints, UpdateSourceTrigger=PropertyChanged}" Minimum="0" Maximum="500"/>
|
||||||
|
|
||||||
|
<ListView ItemsSource="{Binding ElementName=thisWindow, Path=Elements}">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate DataType="local:Rod">
|
||||||
|
<Grid>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBox Text="{Binding RodName, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
|
||||||
|
<TextBox Text="{Binding Length, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
</StackPanel>
|
||||||
|
<StatusBar Grid.Row="1" Grid.ColumnSpan="2">
|
||||||
|
<StatusBarItem Name="SimulationStatus"/>
|
||||||
|
<StatusBarItem Name="Time"/>
|
||||||
|
</StatusBar>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
201
JansenLegViewer/MainWindow.xaml.cs
Normal file
201
JansenLegViewer/MainWindow.xaml.cs
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
15
JansenLegViewer/Motor.cs
Normal file
15
JansenLegViewer/Motor.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace JansenLegSimulator
|
||||||
|
{
|
||||||
|
public class MotorRod : Rod
|
||||||
|
{
|
||||||
|
public override Vector2 StartPosition { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
199
JansenLegViewer/Rod.cs
Normal file
199
JansenLegViewer/Rod.cs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace JansenLegSimulator
|
||||||
|
{
|
||||||
|
public class Rod
|
||||||
|
{
|
||||||
|
#region Constructores
|
||||||
|
// Constructor de barra libre
|
||||||
|
public Rod() { }
|
||||||
|
|
||||||
|
// Constructor de barra con un extremo fijado a un punto
|
||||||
|
public Rod(Vector2 begining)
|
||||||
|
{
|
||||||
|
_startPosition = begining;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region Conexiones
|
||||||
|
/// <summary>
|
||||||
|
/// Barra a la que se une por el extremo inicial
|
||||||
|
/// </summary>
|
||||||
|
private Rod JointBegining { get; set; } = null;
|
||||||
|
/// <summary>
|
||||||
|
/// Barras a las cuales se une por el extremo final
|
||||||
|
/// </summary>
|
||||||
|
private List<Rod> JointsEnding { get; set; } = new();
|
||||||
|
/// <summary>
|
||||||
|
/// Conecta el inicio de una barra a otra barra
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="linkage">La barra a la cual se unirá esta</param>
|
||||||
|
public void ConnectBegin(ref Rod linkage)
|
||||||
|
{
|
||||||
|
if (linkage == null) throw new NullReferenceException("The rod cannot be null");
|
||||||
|
if (JointBegining != null) throw new Exception("The beginning is already assigned");
|
||||||
|
JointBegining = linkage;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Conecta el final de una barra a otra barra
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="linkage">La barra a la cual se unirá esta</param>
|
||||||
|
public void ConnectEnd(ref Rod linkage)
|
||||||
|
{
|
||||||
|
if (linkage == null) throw new NullReferenceException("The rod cannot be null");
|
||||||
|
if (!JointsEnding.Contains(linkage))
|
||||||
|
JointsEnding.Add(linkage);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Desconecta (si está conectada) la barra especificada
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="linkage">Barra a ser desconectada</param>
|
||||||
|
public void Disconnect(ref Rod linkage)
|
||||||
|
{
|
||||||
|
if (JointBegining == linkage) JointBegining = null;
|
||||||
|
if (JointsEnding.Contains(linkage)) JointsEnding.Remove(linkage);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Propiedades de la barra
|
||||||
|
public string RodName { get; set; } = "Unnamed";
|
||||||
|
/// <summary>
|
||||||
|
/// Longitud de la barra
|
||||||
|
/// </summary>
|
||||||
|
public float Length { get; set; } = 20;
|
||||||
|
|
||||||
|
private float? _alpha = null;
|
||||||
|
/// <summary>
|
||||||
|
/// Ángulo de rotación de la barra. Si no se establece será 0 radianes.
|
||||||
|
/// </summary>
|
||||||
|
public float Alpha
|
||||||
|
{
|
||||||
|
get => (_alpha != null) ? (float)_alpha : 0;
|
||||||
|
set => _alpha = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2? _startPosition = null;
|
||||||
|
/// <summary>
|
||||||
|
/// Posición de incio (eje de esta barra).
|
||||||
|
/// Si se ha unido el inicio a otra barra, se calculará a partir de la posición final de la barra sobre la cual está
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector2 StartPosition
|
||||||
|
{
|
||||||
|
get => (_startPosition != null) ? (Vector2)_startPosition :
|
||||||
|
(JointBegining != null) ? JointBegining.EndPosition : new Vector2(0, 0);
|
||||||
|
set => _startPosition = value;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Posición final.
|
||||||
|
/// Se calcula a partir de la posición inicial, el ángulo y la longitud.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector2 EndPosition
|
||||||
|
{
|
||||||
|
get => new Vector2(
|
||||||
|
StartPosition.X + Length * MathF.Cos(Alpha),
|
||||||
|
StartPosition.Y + Length * MathF.Sin(Alpha)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Posición central.
|
||||||
|
/// Se calcula a partir de la posición inicial, el ángulo y la longitud.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector2 Center
|
||||||
|
{
|
||||||
|
get => new Vector2(
|
||||||
|
StartPosition.X + Length * MathF.Cos(Alpha) / 2,
|
||||||
|
StartPosition.Y + Length * MathF.Sin(Alpha) / 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calcula el punto de intersección entre dos barras de longitud y eje de rotación determinados.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="A">Primera barra</param>
|
||||||
|
/// <param name="B">Segunda barra</param>
|
||||||
|
/// <param name="solution">En caso de que existan dos intersecciones, número de la intersección a elegir</param>
|
||||||
|
/// <returns>El vector que representa el punto en el que se unen las dos barras.</returns>
|
||||||
|
/// <exception cref="RodsDoNotIntersectException">Si las barras no intersecan en ningún punto, lanzará una excepción.</exception>
|
||||||
|
/// <exception cref="IntersectionOutOfRangeException">Si las barras intersecan pero no se encuentra la intersección especificada, lanzará una excepción.</exception>
|
||||||
|
public static Vector2 GetIntersection(Rod A, Rod B, int solution = -1)
|
||||||
|
{
|
||||||
|
Vector2[] intersects = CosasQueNoSeExplicanEnMatesDePrimero.CalculateCircleIntersections(
|
||||||
|
A.StartPosition,
|
||||||
|
B.StartPosition,
|
||||||
|
A.Length,
|
||||||
|
B.Length);
|
||||||
|
|
||||||
|
return (intersects.Length == 0) ? throw new RodsDoNotIntersectException("No existe conexión posible entre estas dos barras. Pruebe a darles la vuelta.") :
|
||||||
|
(intersects.Length == 1 || solution < 0) ? intersects[0] :
|
||||||
|
(intersects.Length > solution) ? intersects[solution] :
|
||||||
|
throw new IntersectionOutOfRangeException("La intersección especificada no existe. Pruebe con las soluciones 0 y 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calcula la diferencia entre dos vectores
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="A">Vector final</param>
|
||||||
|
/// <param name="B">Vector inicial</param>
|
||||||
|
/// <returns>Vector final - Vector inicial</returns>
|
||||||
|
public static Vector2 Delta(Vector2 A, Vector2 B) => A - B;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calcula para cada elemento el ángulo de la intersección de dos vectores a su posición respecto el 0 en el primer cuadrante.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="A">Vector 1</param>
|
||||||
|
/// <param name="B">Vector 2</param>
|
||||||
|
/// <param name="solution">Devuelve los angulos de cada eje a la intersección</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static (float, float) GetIntersectionAlphas(Rod A, Rod B, int solution = -1)
|
||||||
|
{
|
||||||
|
(float, float) result = new();
|
||||||
|
|
||||||
|
// Calcular las intersecciones y los vectores de
|
||||||
|
// incremento entre el eje de la barra y su unión.
|
||||||
|
Vector2
|
||||||
|
I = GetIntersection(A, B, solution),
|
||||||
|
DeltaA = Delta(I, A.StartPosition),
|
||||||
|
DeltaB = Delta(I, B.StartPosition);
|
||||||
|
|
||||||
|
// Obtener los ángulos mediante la inversa del coseno
|
||||||
|
result.Item1 = MathF.Acos(DeltaA.X / DeltaA.Length());
|
||||||
|
result.Item2 = MathF.Acos(DeltaB.X / DeltaB.Length());
|
||||||
|
// Voltear verticalmente según la dirección vertical
|
||||||
|
// del vector incremento
|
||||||
|
if (DeltaA.Y < 0) result.Item1 *= -1.0f;
|
||||||
|
if (DeltaB.Y < 0) result.Item2 *= -1.0f;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class RodsDoNotIntersectException : Exception
|
||||||
|
{
|
||||||
|
public RodsDoNotIntersectException() { }
|
||||||
|
public RodsDoNotIntersectException(string message) : base(message) { }
|
||||||
|
public RodsDoNotIntersectException(string message, Exception inner) : base(message, inner) { }
|
||||||
|
protected RodsDoNotIntersectException(
|
||||||
|
System.Runtime.Serialization.SerializationInfo info,
|
||||||
|
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class IntersectionOutOfRangeException : Exception
|
||||||
|
{
|
||||||
|
public IntersectionOutOfRangeException() { }
|
||||||
|
public IntersectionOutOfRangeException(string message) : base(message) { }
|
||||||
|
public IntersectionOutOfRangeException(string message, Exception inner) : base(message, inner) { }
|
||||||
|
protected IntersectionOutOfRangeException(
|
||||||
|
System.Runtime.Serialization.SerializationInfo info,
|
||||||
|
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user