using System; using System.Collections.Generic; using System.DirectoryServices; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Forms; using System.Windows.Media; using System.Windows.Shapes; using CtrEditor.Convertidores; using CtrEditor.ObjetosSim; using FarseerPhysics.Collision.Shapes; using FarseerPhysics.Common; using FarseerPhysics.Dynamics; using FarseerPhysics.Dynamics.Contacts; using FarseerPhysics.Factories; using Microsoft.Xna.Framework; using OpenCvSharp; using Siemens.Simatic.Simulation.Runtime; using static System.Windows.Forms.DataFormats; using Point = System.Windows.Point; namespace CtrEditor.Simulacion { public class simRectangle { public Body Body { get; private set; } public float Speed { get; set; } // Velocidad para efectos de cinta transportadora public World _world; public simRectangle(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) { // Primero, elimina el fixture antiguo Body.DestroyFixture(Body.FixtureList[0]); // Crea un nuevo fixture con las nuevas dimensiones 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 } // Otros métodos según sea necesario, como mover, rotar, etc. } public class simLine { public Body Body { get; private set; } public World _world; public simLine(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 simCircle { public Body Body { get; private set; } public World _world; private float _radius; private float _mass; public simCircle(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, 10f, 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 = 0.01f; // Ajustar para controlar la reducción de la velocidad lineal Body.AngularDamping = 1f; // Ajustar para controlar la reducción de la velocidad angular Body.Restitution = 0.2f; // Baja restitución para menos rebote Body.IsBullet = true; } private void HandleOnSeparation(Fixture fixtureA, Fixture fixtureB) { Body.LinearDamping = 5f; // Ajustar para controlar la reducción de la velocidad lineal } public void SetPosition(float x, float y) { // Usar el ángulo actual, ya que no es relevante para un círculo en este contexto 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 simRectangle) { simRectangle conveyor = fixtureB.Body.UserData as simRectangle; ApplyConveyorEffect(conveyor, fixtureA, contact); return true; // No aplicar respuestas fisicas } return true; // No aplicar respuestas fisicas } private void ApplyConveyorEffect(simRectangle conveyor, Fixture circleFixture, FarseerPhysics.Dynamics.Contacts.Contact contact) { // Calcular la velocidad deseada en metros por segundo float speedMetersPerSecond = conveyor.Speed / 60.0f; Vector2 desiredVelocity = new Vector2((float)Math.Cos(conveyor.Body.Rotation), (float)Math.Sin(conveyor.Body.Rotation)) * speedMetersPerSecond; // Calcular la fuerza necesaria para alcanzar esa velocidad Vector2 velocityChange = desiredVelocity - circleFixture.Body.LinearVelocity; float timeStep = 1.0f / 60.0f; // Asumiendo 60 Hz de tasa de actualización Vector2 acceleration = velocityChange / timeStep; Vector2 force = acceleration / Mass; // Aplicar la fuerza al círculo circleFixture.Body.ApplyForce(force); } } public class SimulationManagerFP { private World world; private Canvas simulationCanvas; public List circles; public List rectangles; public List lines; 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(); } public simCircle AddCircle(float diameter, Vector2 position, float mass) { simCircle circle = new simCircle(world, diameter, position, mass); circles.Add(circle); return circle; } public simRectangle AddRectangle(float width, float height, Vector2 position, float angle) { simRectangle rectangle = new simRectangle(world, width, height, position, angle); rectangles.Add(rectangle); return rectangle; } public simLine AddLine(Vector2 start, Vector2 end) { simLine line = new simLine(world, start, end); lines.Add(line); return line; } // Otros métodos para agregar círculos y ejecutar la simulación public void Step(float timeStep) { world.Step(timeStep/1000.0f); // Actualiza y gestiona otras lógicas si es necesario } public void Debug_DrawInitialBodies() { ClearSimulationShapes(); world.Step(0.01f); // Para actualizar la BodyList foreach (Body body in world.BodyList) { foreach (Fixture fixture in body.FixtureList) { DrawShape(fixture); } } } private void 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) { // Aplicar la rotación alrededor del origen y luego trasladar 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; } } }