Primera logica de simulacion

This commit is contained in:
Miguel 2024-05-06 17:31:45 +02:00
parent dd2b656c69
commit 3ba10b81c3
8 changed files with 355 additions and 89 deletions

View File

@ -32,6 +32,8 @@ namespace CtrEditor
public ObservableCollection<TipoSimulable> ListaOsBase { get; } = new ObservableCollection<TipoSimulable>(); public ObservableCollection<TipoSimulable> ListaOsBase { get; } = new ObservableCollection<TipoSimulable>();
private ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>(); private ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>();
private SimulationManager simulationManager = new SimulationManager();
private readonly DispatcherTimer _timerSimulacion; private readonly DispatcherTimer _timerSimulacion;
public ICommand StartSimulationCommand { get; } public ICommand StartSimulationCommand { get; }
@ -125,14 +127,18 @@ namespace CtrEditor
private void OnTickSimulacion(object sender, EventArgs e) private void OnTickSimulacion(object sender, EventArgs e)
{ {
var args = new TickSimulacionEventArgs();
OnTickSimulacion(args); simulationManager.Step((float)_timerSimulacion.Interval.TotalMilliseconds);
foreach (var objetoSimulable in ObjetosSimulables)
objetoSimulable.UpdateControl();
} }
protected virtual void OnTickSimulacion(TickSimulacionEventArgs e) //protected virtual void OnTickSimulacion(TickSimulacionEventArgs e)
{ //{
TickSimulacion?.Invoke(this, e); // TickSimulacion?.Invoke(this, e);
} //}
public string directorioTrabajo public string directorioTrabajo
{ {
@ -276,7 +282,7 @@ namespace CtrEditor
if (userControl != null) if (userControl != null)
{ {
// Asignar los datos al UserControl // Asignar los datos al UserControl
UserControlFactory.AssignDatos(userControl, osObjeto); UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager);
OnUserControlSelected?.Invoke(userControl); OnUserControlSelected?.Invoke(userControl);
return true; return true;

View File

@ -54,7 +54,7 @@ namespace CtrEditor
if (DataContext is MainViewModel viewModel) if (DataContext is MainViewModel viewModel)
{ {
viewModel.ImageSelected += ViewModel_ImageSelected; viewModel.ImageSelected += ViewModel_ImageSelected;
viewModel.TickSimulacion += MainViewModel_TickSimulacion; //viewModel.TickSimulacion += MainViewModel_TickSimulacion;
viewModel.OnUserControlSelected += AgregarUserControl; viewModel.OnUserControlSelected += AgregarUserControl;
viewModel?.LoadInitialData(); // Carga la primera imagen por defecto una vez cargada la ventana principal viewModel?.LoadInitialData(); // Carga la primera imagen por defecto una vez cargada la ventana principal
} }
@ -89,8 +89,8 @@ namespace CtrEditor
double top = centerY - (userControl.ActualHeight / 2); double top = centerY - (userControl.ActualHeight / 2);
// Establece la posición del UserControl // Establece la posición del UserControl
NuevoOS.Left = left; NuevoOS.Left = (float)left;
NuevoOS.Top = top; NuevoOS.Top = (float)top;
NuevoOS.Inicializado = true; NuevoOS.Inicializado = true;
} }
@ -215,7 +215,7 @@ namespace CtrEditor
var newY = Canvas.GetTop(_currentDraggingControl) + dy; var newY = Canvas.GetTop(_currentDraggingControl) + dy;
if (_currentDraggingControl is IDataContainer dataContainer) if (_currentDraggingControl is IDataContainer dataContainer)
dataContainer.Move(newX, newY); dataContainer.Move((float)newX,(float) newY);
_startPointUserControl = currentPosition; // Actualiza el punto inicial para el siguiente movimiento _startPointUserControl = currentPosition; // Actualiza el punto inicial para el siguiente movimiento
} }
@ -243,7 +243,7 @@ namespace CtrEditor
//rotateTransform.Angle = angle; // - _initialAngleUserControl; // Asegúrate de ajustar esta parte según cómo calcules el ángulo inicial //rotateTransform.Angle = angle; // - _initialAngleUserControl; // Asegúrate de ajustar esta parte según cómo calcules el ángulo inicial
if (control is IDataContainer dataContainer) if (control is IDataContainer dataContainer)
dataContainer.Rotate(angle); dataContainer.Rotate((float)angle);
// Actualizar el ángulo mostrado // Actualizar el ángulo mostrado
_angleDisplayTextBlock.Text = $"Ángulo: {angle:F2}°"; _angleDisplayTextBlock.Text = $"Ángulo: {angle:F2}°";
@ -267,7 +267,7 @@ namespace CtrEditor
control.Width = newWidth; // Asegurar que no sea menor que el mínimo control.Width = newWidth; // Asegurar que no sea menor que el mínimo
if (control is IDataContainer dataContainer) if (control is IDataContainer dataContainer)
dataContainer.Resize(newWidth, 0); dataContainer.Resize((float)newWidth, 0);
// Actualizar el punto de inicio para el próximo evento de movimiento // Actualizar el punto de inicio para el próximo evento de movimiento
_startPointUserControl = currentPosition; _startPointUserControl = currentPosition;
@ -423,20 +423,6 @@ namespace CtrEditor
} }
private void MainViewModel_TickSimulacion(object sender, TickSimulacionEventArgs e)
{
// aquí puedes agregar la lógica para actualizar tus UserControl
// en el ImagenEnTrabajoCanvas
foreach (var child in ImagenEnTrabajoCanvas.Children)
{
if (child is osBase uc)
{
// llama al método Update de cada UserControl
uc.Update();
}
}
}
private void MainWindow_Closed(object sender, EventArgs e) private void MainWindow_Closed(object sender, EventArgs e)
{ {
if (DataContext is MainViewModel viewModel) if (DataContext is MainViewModel viewModel)

View File

@ -45,13 +45,14 @@ namespace CtrEditor.ObjetosSim
return instance; return instance;
} }
public static void AssignDatos(UserControl userControl, osBase datos) public static void AssignDatos(UserControl userControl, osBase datos, SimulationManager simulationManager)
{ {
if (userControl is IDataContainer dataContainer) if (userControl is IDataContainer dataContainer)
{ {
dataContainer.Datos = datos; dataContainer.Datos = datos;
userControl.DataContext = datos; userControl.DataContext = datos;
datos.VisualRepresentation = userControl; datos.VisualRepresentation = userControl;
datos.ConnectSimManager(simulationManager);
} }
} }
} }

View File

@ -14,52 +14,29 @@ namespace CtrEditor.ObjetosSim
public interface IosBase public interface IosBase
{ {
string Nombre { get; } string Nombre { get; }
void Update();
void ConnectSimManager(SimulationManager simulationManager);
void UpdateControl();
} }
public interface IDataContainer public interface IDataContainer
{ {
osBase? Datos { get; set; } osBase? Datos { get; set; }
void Resize(double width, double height); void Resize(float width, float height);
void Move(double Left, double Top); void Move(float Left, float Top);
void Rotate(double Angle); void Rotate(float Angle);
void Highlight(bool State); void Highlight(bool State);
} }
public abstract class osBase : INotifyPropertyChanged, IosBase public abstract class osBase : INotifyPropertyChanged, IosBase
{ {
private string _nombre = "Base"; private string _nombre = "Base";
public double _left; public abstract float Left { get; set; }
public double _top; public abstract float Top { get; set; }
public bool Inicializado = false; public bool Inicializado = false;
public double Left
{
get => _left;
set protected UserControl? _visualRepresentation = null;
{
_left = value;
if (_visualRepresentation != null)
Canvas.SetLeft(_visualRepresentation, _left);
OnPropertyChanged(nameof(Left));
}
}
public double Top
{
get => _top;
set
{
_top = value;
if (_visualRepresentation != null)
Canvas.SetTop(_visualRepresentation, _top);
OnPropertyChanged(nameof(Top));
}
}
private UserControl? _visualRepresentation = null;
public string Nombre public string Nombre
{ {
@ -74,7 +51,8 @@ namespace CtrEditor.ObjetosSim
} }
} }
public abstract void Update(); public abstract void ConnectSimManager(SimulationManager simulationManager);
public abstract void UpdateControl();
[JsonIgnore] [JsonIgnore]

View File

@ -1,6 +1,6 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucBotella" <UserControl x:Class="CtrEditor.ObjetosSim.ucBotella"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
DataContext="{Binding RelativeSource={RelativeSource Self}}"> <Ellipse Height="{Binding Diametro}" Stroke="red" Fill="Gray" Width="{Binding Diametro}"/>
<Border Background="Brown" CornerRadius="10" Height="10" Width="10"/>
</UserControl> </UserControl>

View File

@ -12,6 +12,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using System.Numerics;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
@ -22,15 +23,63 @@ namespace CtrEditor.ObjetosSim
public class osBotella : osBase public class osBotella : osBase
{ {
public double diametro { get; set; } private Circle Data = new Circle();
// Otros datos y métodos relevantes para la simulación // Otros datos y métodos relevantes para la simulación
private string _nombre = "Botella"; private string _nombre = "Botella";
public override void Update()
public float Diametro {
get => Data.Diameter;
set
{ {
// implementation of Update method Data.Diameter = value;
OnPropertyChanged(nameof(Diametro));
} }
} }
public float Mass {
get => Data.Mass;
set
{
Data.Mass = value;
OnPropertyChanged(nameof(Mass));
}
}
public override float Left
{
get => Data.Center.X;
set
{
Data.Center = new Vector2(value,Top);
if (_visualRepresentation != null)
Canvas.SetLeft(_visualRepresentation, value);
OnPropertyChanged(nameof(Left));
}
}
public override float Top
{
get => Data.Center.Y;
set
{
Data.Center = new Vector2(Left, value);
if (_visualRepresentation != null)
Canvas.SetTop(_visualRepresentation, value);
OnPropertyChanged(nameof(Top));
}
}
public override void ConnectSimManager(SimulationManager simulationManager)
{
simulationManager.circles.Add(Data);
}
public override void UpdateControl()
{
Top = Data.Center.Y;
Left = Data.Center.X;
}
}
public partial class ucBotella : UserControl, IDataContainer public partial class ucBotella : UserControl, IDataContainer
{ {
@ -40,8 +89,8 @@ namespace CtrEditor.ObjetosSim
{ {
InitializeComponent(); InitializeComponent();
} }
public void Resize(double width, double height) { } public void Resize(float width, float height) { }
public void Move(double Left, double Top) public void Move(float Left, float Top)
{ {
if (Datos != null) if (Datos != null)
{ {
@ -49,7 +98,7 @@ namespace CtrEditor.ObjetosSim
Datos.Top = Top; Datos.Top = Top;
} }
} }
public void Rotate(double Angle) { } public void Rotate(float Angle) { }
public void Highlight(bool State) { } public void Highlight(bool State) { }
} }

View File

@ -13,6 +13,8 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using static System.Runtime.InteropServices.JavaScript.JSType; using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Numerics;
using System.Windows.Markup;
namespace CtrEditor.ObjetosSim namespace CtrEditor.ObjetosSim
{ {
@ -25,36 +27,74 @@ namespace CtrEditor.ObjetosSim
{ {
private string _nombre = "Transporte TTOP"; private string _nombre = "Transporte TTOP";
private double _Ancho; private float frictionCoefficient;
private double _Alto; private float velMax50hz; // en metros por minuto
private double _Angulo; private float tiempoRampa;
private bool esMarcha;
public double diametro { get; set; } private Rectangle Data = new Rectangle();
public double Ancho {
get { return _Ancho; } public override float Left
{
get => Data.Left;
set set
{ {
_Ancho = value; Data.Left = value;
if (_visualRepresentation != null)
Canvas.SetLeft(_visualRepresentation, value);
OnPropertyChanged(nameof(Left));
}
}
public override float Top
{
get => Data.Top;
set
{
Data.Top = value;
if (_visualRepresentation != null)
Canvas.SetTop(_visualRepresentation, value);
OnPropertyChanged(nameof(Top));
}
}
public float Ancho {
get => Data.Width;
set
{
Data.Width = value;
OnPropertyChanged(nameof(Ancho)); OnPropertyChanged(nameof(Ancho));
} }
} }
public double Alto { public float Alto {
get { return _Alto; } get => Data.Height;
set set
{ {
_Alto = value; Data.Height = value;
OnPropertyChanged(nameof(Alto)); OnPropertyChanged(nameof(Alto));
} }
} }
public double Angulo public float Angulo
{ {
get { return _Angulo; } get => Data.Angle;
set set
{ {
_Angulo = value; Data.Angle = value;
OnPropertyChanged(nameof(Angulo)); OnPropertyChanged(nameof(Angulo));
} }
} }
public float VelocidadActual
{
get => Data.Speed;
set {
Data.Speed = value;
OnPropertyChanged(nameof(VelocidadActual));
}
}
public float FrictionCoefficient { get => frictionCoefficient; set => frictionCoefficient = value; }
public float VelMax50hz { get => velMax50hz; set => velMax50hz = value; }
public float TiempoRampa { get => tiempoRampa; set => tiempoRampa = value; }
public bool EsMarcha { get => esMarcha; set => esMarcha = value; }
public osTransporteTTop() public osTransporteTTop()
{ {
@ -62,10 +102,14 @@ namespace CtrEditor.ObjetosSim
Alto = 10; Alto = 10;
} }
public override void Update() public override void ConnectSimManager(SimulationManager simulationManager)
{ {
// implementation of Update method simulationManager.rectangles.Add(Data);
} }
public override void UpdateControl()
{
}
} }
public partial class ucTransporteTTop : UserControl, IDataContainer public partial class ucTransporteTTop : UserControl, IDataContainer
@ -76,12 +120,12 @@ namespace CtrEditor.ObjetosSim
{ {
InitializeComponent(); InitializeComponent();
} }
public void Resize(double width, double height) public void Resize(float width, float height)
{ {
if (Datos is osTransporteTTop datos) if (Datos is osTransporteTTop datos)
datos.Ancho = width; datos.Ancho = width;
} }
public void Move(double Left, double Top) public void Move(float Left, float Top)
{ {
if (Datos != null) if (Datos != null)
{ {
@ -89,7 +133,7 @@ namespace CtrEditor.ObjetosSim
Datos.Top = Top; Datos.Top = Top;
} }
} }
public void Rotate(double Angle) { public void Rotate(float Angle) {
if (Datos != null) if (Datos != null)
if (Datos is osTransporteTTop datos) if (Datos is osTransporteTTop datos)
datos.Angulo = Angle; datos.Angulo = Angle;

View File

@ -0,0 +1,202 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Numerics;
// Definición de la clase Circle
public class Circle : ObjetoGeometrico
{
public Vector2 Center { get; set; }
public float Diameter { get; set; }
public float Mass { get; set; }
[JsonIgnore]
public Vector2 Velocity { get; set; }
public Circle(Vector2 center, float diameter, float mass, Vector2 velocity)
{
Center = center;
Diameter = diameter;
Mass = mass;
Velocity = velocity;
}
public Circle() {
Center = new Vector2(0,0);
Center.X = 0;
Diameter = 10;
Mass = 1;
Velocity = new Vector2(0,0);
}
// Método para calcular la nueva posición del círculo en función del tiempo
public void Move(float timeStep, List<Circle> circles, List<Rectangle> rectangles, List<Line> lines)
{
Vector2 totalForce = new Vector2(0, 0);
// Aplicar fuerza de los rectángulos
foreach (var rectangle in rectangles)
{
totalForce += rectangle.ApplyForce(this);
}
// Aplicar fuerza a otros círculos
foreach (var otherCircle in circles)
{
if (otherCircle != this)
{
totalForce += ApplyForceToOtherCircle(otherCircle);
}
}
// Aplicar fuerza debido a la inercia (ejemplo simple)
Vector2 inertiaForce = -0.1f * Velocity; // coeficiente de inercia
totalForce += inertiaForce;
// Calcular la aceleración
if (Mass <= 0)
Mass = 1;
Vector2 acceleration = totalForce / Mass;
// Actualizar la velocidad y la posición
Velocity += acceleration * timeStep / 1000;
Center += Velocity * timeStep;
// Controlar la colisión con las líneas
foreach (var line in lines)
{
line.HandleCollision(this);
}
}
private Vector2 ApplyForceToOtherCircle(Circle other)
{
Vector2 direction = other.Center - this.Center;
float distance = direction.Length();
float overlap = this.Diameter / 2 + other.Diameter / 2 - distance;
if (overlap > 0)
{
Vector2 forceDirection = Vector2.Normalize(direction);
float transferVelocity = 0.5f * this.Velocity.Length(); // Ejemplo de transferencia de parte de la velocidad
if (transferVelocity == 0)
transferVelocity = 0.01f;
other.Velocity += forceDirection * transferVelocity; // Asumiendo una simplificación del impacto
return -forceDirection * transferVelocity; // Retorno de fuerza opuesta aplicada a este círculo
}
return Vector2.Zero;
}
}
// Definición de la clase Rectangle
public class Rectangle : ObjetoGeometrico
{
public Vector2 AnchorPoint { get; set; }
public float Left { get; set; }
public float Top { get; set; }
public float Width { get; set; }
public float Height { get; set; }
public float Angle { get; set; }
public float Speed { get; set; }
public Rectangle(Vector2 anchorPoint, float width, float height, float angle)
{
AnchorPoint = anchorPoint;
Width = width;
Height = height;
Angle = angle;
}
public Rectangle()
{
AnchorPoint = new Vector2(0,0);
Width = 1;
Height = 1;
Angle = 0;
}
public Vector2 ApplyForce(Circle circle)
{
// Transformar el centro del círculo al sistema de coordenadas del rectángulo
Vector2 circlePositionRelative = Vector2.Transform(circle.Center - AnchorPoint, Matrix3x2.CreateRotation(-Angle));
// Verificar si el círculo está dentro del rectángulo
float halfWidth = Width / 2;
float halfHeight = Height / 2;
if (Math.Abs(circlePositionRelative.X) <= halfWidth && Math.Abs(circlePositionRelative.Y) <= halfHeight)
{
// Calcular fuerza basada en la proximidad al centro del rectángulo
float distanceFromCenter = circlePositionRelative.Length();
float forceMagnitude = Math.Max(0, (Width - distanceFromCenter) / Width); // Simplificación de la magnitud de la fuerza
Vector2 forceDirection = Vector2.Transform(new Vector2(1, 0), Matrix3x2.CreateRotation(Angle)); // Fuerza en la dirección del rectángulo
return forceDirection * forceMagnitude;
}
return Vector2.Zero;
}
}
// Definición de la clase Line
public class Line : ObjetoGeometrico
{
public Vector2 StartPoint { get; set; }
public Vector2 EndPoint { get; set; }
public Line(Vector2 startPoint, Vector2 endPoint)
{
StartPoint = startPoint;
EndPoint = endPoint;
}
public void HandleCollision(Circle circle)
{
Vector2 closestPoint = ClosestPoint(circle.Center);
float radius = circle.Diameter / 2;
if (Vector2.Distance(circle.Center, closestPoint) < radius)
{
Vector2 lineDirection = Vector2.Normalize(EndPoint - StartPoint);
Vector2 normal = new Vector2(-lineDirection.Y, lineDirection.X); // Normal perpendicular a la dirección de la línea
circle.Velocity = Vector2.Reflect(circle.Velocity, normal);
}
}
private Vector2 ClosestPoint(Vector2 point)
{
Vector2 AP = point - StartPoint;
Vector2 AB = EndPoint - StartPoint;
float magnitudeAB = AB.LengthSquared();
float ABAPproduct = Vector2.Dot(AP, AB);
float distance = ABAPproduct / magnitudeAB;
return StartPoint + AB * Math.Clamp(distance, 0, 1);
}
}
public class ObjetoGeometrico
{ }
// Clase principal que gestiona la simulación
public class SimulationManager
{
public List<Circle> circles;
public List<Rectangle> rectangles;
public List<Line> lines;
public SimulationManager()
{
circles = new List<Circle>();
rectangles = new List<Rectangle>();
lines = new List<Line>();
}
public void Step(float timeStep)
{
foreach (var circle in circles)
{
circle.Move(timeStep, circles, rectangles, lines);
}
}
}