using System; using System.Collections.Generic; using System.Linq; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; using FarseerPhysics.Dynamics; using FarseerPhysics.Factories; using FarseerPhysics.Collision.Shapes; using Microsoft.Xna.Framework; using CtrEditor.Convertidores; using FarseerPhysics.Common; using System.Windows; using System.Diagnostics; using System.Windows.Documents; using CtrEditor.ObjetosSim; using static System.Runtime.InteropServices.JavaScript.JSType; namespace CtrEditor.Simulacion { public class simDescarte { public Body Body { get; private set; } private float _radius; public World _world; public simDescarte(World world, float diameter, Vector2 position) { _world = world; _radius = diameter / 2; Create(position); } public void SetPosition(float x, float y) { Body.SetTransform(new Vector2(x, y), Body.Rotation); } public void SetDiameter(float diameter) { _radius = diameter / 2; Create(Body.Position); // Recrear el círculo con el nuevo tamaño } public void Create(Vector2 position) { if (Body != null) { _world.RemoveBody(Body); } Body = BodyFactory.CreateCircle(_world, _radius, 1f, position); Body.FixtureList[0].IsSensor = true; Body.BodyType = BodyType.Static; Body.UserData = this; // Importante para la identificación durante la colisión } } public class simTransporte { public Body Body { get; private set; } public float Speed { get; set; } // Velocidad para efectos de cinta transportadora public World _world; public simTransporte(World world, float width, float height, Vector2 position, float angle = 0) { _world = world; Create(width, height, position, angle); } public float Angle { get { return MathHelper.ToDegrees(Body.Rotation); } set { Body.Rotation = MathHelper.ToRadians(value); } } public void SetPosition(float x, float y) { Body.Position = new Vector2(x, y); } public void SetSpeed(float speed) { Speed = speed; } public void SetDimensions(float width, float height) { Body.DestroyFixture(Body.FixtureList[0]); var newShape = new PolygonShape(PolygonTools.CreateRectangle(width / 2, height / 2), 1f); Body.CreateFixture(newShape); } public void Create(float width, float height, Vector2 position, float angle = 0) { if (Body != null) { _world.RemoveBody(Body); } Body = BodyFactory.CreateRectangle(_world, width, height, 1f, position); Body.FixtureList[0].IsSensor = true; Body.BodyType = BodyType.Static; Body.Rotation = MathHelper.ToRadians(angle); Body.UserData = this; // Importante para la identificación durante la colisión } } public class simGuia { public Body Body { get; private set; } public World _world; public simGuia(World world, Vector2 start, Vector2 end) { _world = world; Create(start, end); } public void Create(Vector2 start, Vector2 end) { if (Body != null) { _world.RemoveBody(Body); // Elimina el cuerpo anterior si existe } Body = BodyFactory.CreateEdge(_world, start, end); Body.BodyType = BodyType.Static; Body.UserData = this; // Importante para la identificación durante la colisión } public void UpdateVertices(Vector2 newStart, Vector2 newEnd) { Create(newStart, newEnd); // Recrear la línea con nuevos vértices } } public class simBotella { public Body Body { get; private set; } public World _world; private float _radius; private float _mass; public bool Descartar = false; public simBotella(World world, float diameter, Vector2 position, float mass) { _world = world; _radius = diameter / 2; _mass = mass; Create(position); } public float CenterX { get { return Body.Position.X; } set { } } public float CenterY { get { return Body.Position.Y; } set { } } public Vector2 Center { get { return Body.Position; } } public float Mass { get { if (_mass <= 0) _mass = 1; return _mass; } set { _mass = value; } } private void Create(Vector2 position) { if (Body != null) { _world.RemoveBody(Body); // Remover el cuerpo anterior si existe } Body = BodyFactory.CreateCircle(_world, _radius, 1f, position); Body.BodyType = BodyType.Dynamic; // Restablecer manejador de eventos de colisión Body.OnCollision += HandleCollision; //Body.OnSeparation += HandleOnSeparation; Body.UserData = this; // Importante para la identificación durante la colisión // Configurar la fricción Body.Friction = 0.5f; // Ajustar según sea necesario para tu simulación // Configurar amortiguamiento Body.LinearDamping = 0f; // Ajustar para controlar la reducción de la velocidad lineal Body.AngularDamping = 0f; // Ajustar para controlar la reducción de la velocidad angular Body.Restitution = 0.2f; // Baja restitución para menos rebote Body.IsBullet = true; } public void SetPosition(float x, float y) { Body.SetTransform(new Vector2(x, y), Body.Rotation); } public void SetDiameter(float diameter) { _radius = diameter / 2; Create(Body.Position); // Recrear el círculo con el nuevo tamaño } public void SetMass(float mass) { Mass = mass; } private bool HandleCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact) { if (fixtureB.Body.UserData is simDescarte) { Descartar = true; return true; } else if (fixtureB.Body.UserData is simTransporte) { simTransporte conveyor = fixtureB.Body.UserData as simTransporte; CircleShape circleShape = fixtureA.Shape as CircleShape; PolygonShape polygonShape = fixtureB.Shape as PolygonShape; // Obtener centro y radio del círculo Vector2 centroCirculo = fixtureA.Body.Position; float radio = circleShape.Radius; // Obtener los vértices del polígono (rectángulo) Vector2[] vertices = new Vector2[polygonShape.Vertices.Count]; float cos = (float)Math.Cos(fixtureB.Body.Rotation); float sin = (float)Math.Sin(fixtureB.Body.Rotation); for (int i = 0; i < polygonShape.Vertices.Count; i++) { Vector2 vertex = polygonShape.Vertices[i]; float rotatedX = vertex.X * cos - vertex.Y * sin + fixtureB.Body.Position.X; float rotatedY = vertex.X * sin + vertex.Y * cos + fixtureB.Body.Position.Y; vertices[i] = new Vector2(rotatedX, rotatedY); } // Calcular el porcentaje de la superficie compartida float porcentajeCompartido = InterseccionCirculoRectangulo.CalcularSuperficieCompartida(vertices, centroCirculo, radio); // Aplicar el efecto del transportador usando el porcentaje calculado ApplyConveyorEffect(conveyor, fixtureA, porcentajeCompartido); return true; // No aplicar respuestas físicas } return true; // No aplicar respuestas físicas } private void HandleOnSeparation(Fixture fixtureA, Fixture fixtureB) { // Aquí puedes restablecer cualquier estado si es necesario al separarse de un simRectangle } private void ApplyConveyorEffect(simTransporte conveyor, Fixture circleFixture, float porcentajeCompartido) { float speedMetersPerSecond = conveyor.Speed / 60.0f; Vector2 desiredVelocity = new Vector2((float)Math.Cos(conveyor.Body.Rotation), (float)Math.Sin(conveyor.Body.Rotation)) * speedMetersPerSecond; circleFixture.Body.LinearVelocity += desiredVelocity * porcentajeCompartido; } } public class SimulationManagerFP { private World world; private Canvas simulationCanvas; public List circles; public List rectangles; public List lines; public List descartes; public Stopwatch stopwatch; public Canvas DebugCanvas { get => simulationCanvas; set => simulationCanvas = value; } public SimulationManagerFP() { world = new World(new Vector2(0, 0)); // Vector2.Zero circles = new List(); rectangles = new List(); lines = new List(); descartes = new List(); stopwatch = new Stopwatch(); } public void Clear() { circles.Clear(); rectangles.Clear(); lines.Clear(); world.Clear(); } public void Step() { // Detener el cronómetro y obtener el tiempo transcurrido en milisegundos stopwatch.Stop(); float elapsedMilliseconds = (float)stopwatch.Elapsed.TotalMilliseconds; // Reiniciar el cronómetro para la próxima medición stopwatch.Restart(); // Pasar el tiempo transcurrido al método Step world.Step(elapsedMilliseconds / 1000.0f); } public void Remove(object Objeto) { switch (Objeto) { case simBotella obj: circles.Remove(obj); break; case simTransporte obj: rectangles.Remove(obj); break; case simGuia obj: lines.Remove(obj); break; case simDescarte obj: descartes.Remove(obj); break; default: throw new InvalidOperationException("Tipo no soportado"); } } public simBotella AddCircle(float diameter, Vector2 position, float mass) { simBotella circle = new simBotella(world, diameter, position, mass); circles.Add(circle); return circle; } public simTransporte AddRectangle(float width, float height, Vector2 position, float angle) { simTransporte rectangle = new simTransporte(world, width, height, position, angle); rectangles.Add(rectangle); return rectangle; } public simGuia AddLine(Vector2 start, Vector2 end) { simGuia line = new simGuia(world, start, end); lines.Add(line); return line; } public simDescarte AddDescarte(float diameter, Vector2 position) { simDescarte descarte = new simDescarte(world, diameter, position); descartes.Add(descarte); return descarte; } public void Debug_DrawInitialBodies() { Debug_ClearSimulationShapes(); world.Step(0.01f); // Para actualizar la BodyList foreach (Body body in world.BodyList) { foreach (Fixture fixture in body.FixtureList) { DrawShape(fixture); } } } public void Debug_ClearSimulationShapes() { var simulationShapes = simulationCanvas.Children.OfType().Where(s => s.Tag as string == "Simulation").ToList(); foreach (var shape in simulationShapes) { simulationCanvas.Children.Remove(shape); } } private void DrawShape(Fixture fixture) { System.Windows.Shapes.Shape shape; switch (fixture.ShapeType) { case ShapeType.Circle: shape = DrawCircle(fixture); break; case ShapeType.Polygon: shape = DrawPolygon(fixture); break; case ShapeType.Edge: shape = DrawEdge(fixture); break; default: return; } shape.Tag = "Simulation"; // Marcar para simulación Canvas.SetZIndex(shape, 20); simulationCanvas.Children.Add(shape); } private float p(float x) { float c = PixelToMeter.Instance.calc.MetersToPixels(x); return c; } private System.Windows.Shapes.Shape DrawEdge(Fixture fixture) { EdgeShape edge = fixture.Shape as EdgeShape; Line line = new Line { X1 = p(edge.Vertex1.X + fixture.Body.Position.X), // Aplicar escala y posición Y1 = p(edge.Vertex1.Y + fixture.Body.Position.Y), X2 = p(edge.Vertex2.X + fixture.Body.Position.X), Y2 = p(edge.Vertex2.Y + fixture.Body.Position.Y), Stroke = Brushes.Black, StrokeThickness = 2 }; return line; } private System.Windows.Shapes.Shape DrawCircle(Fixture fixture) { CircleShape circle = fixture.Shape as CircleShape; Ellipse ellipse = new Ellipse { Width = p(circle.Radius * 2), // Escalado para visualización Height = p(circle.Radius * 2), // Escalado para visualización Stroke = Brushes.Black, StrokeThickness = 2 }; Canvas.SetLeft(ellipse, p(fixture.Body.Position.X - circle.Radius)); Canvas.SetTop(ellipse, p(fixture.Body.Position.Y - circle.Radius)); return ellipse; } private System.Windows.Shapes.Shape DrawPolygon(Fixture fixture) { Polygon polygon = new Polygon { Stroke = Brushes.Black, StrokeThickness = 2 }; PolygonShape polyShape = fixture.Shape as PolygonShape; float cos = (float)Math.Cos(fixture.Body.Rotation); float sin = (float)Math.Sin(fixture.Body.Rotation); foreach (Vector2 vertex in polyShape.Vertices) { float rotatedX = vertex.X * cos - vertex.Y * sin + fixture.Body.Position.X; float rotatedY = vertex.X * sin + vertex.Y * cos + fixture.Body.Position.Y; polygon.Points.Add(new Point(p(rotatedX), p(rotatedY))); } return polygon; } } }