CtrEditor/Simulacion/GeometrySimulator.cs

203 lines
6.1 KiB
C#

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);
}
}
}