using BepuPhysics.Collidables; using BepuPhysics.Constraints; using BepuPhysics; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Text; using System.Threading.Tasks; using DocumentFormat.OpenXml.Spreadsheet; using System.Windows.Media.Media3D; using System.Windows.Shapes; namespace CtrEditor.Simulacion { public class simBotella : simBase { public float Radius; public float Height; // Altura para la visualización del cilindro en Helix private float _mass; public bool Descartar = false; public int isOnTransports; public List ListOnTransports; public bool isRestricted; public bool isNoMoreRestricted; public simTransporte ConveyorRestrictedTo; public float OverlapPercentage; public float _neckRadius; public bool isOnBrakeTransport; // Nueva propiedad para marcar si está en un transporte con freno public simTransporte CurrentBrakeTransport { get; set; } // ✅ NUEVA: Referencia al transporte de freno actual // ✅ NUEVO: Propiedades para la física personalizada public float BaseInverseMass { get; private set; } public Vector3 InitialPosition3D { get; private set; } private List _deferredActions; public simBotella(Simulation simulation, List deferredActions, float diameter, Vector2 position, float mass, float neckRadius = 0) { _simulation = simulation; _deferredActions = deferredActions; Radius = diameter / 2f; Height = diameter; // Altura igual al diámetro para mantener proporciones similares _mass = mass; _neckRadius = neckRadius; ListOnTransports = new List(); // ✅ USAR COORDINATECONVERTER para conversión centralizada var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), Radius + zPos_Transporte + zAltura_Transporte); Create(position3D); } public float CenterX { get { return GetPosition().X; } set { var pos = GetPosition(); SetPosition(value, pos.Y, pos.Z); } } public float CenterY { get { // ✅ USAR COORDINATECONVERTER para conversión centralizada return CoordinateConverter.BepuYToWpfY(GetPosition().Y); } set { var pos = GetPosition(); // ✅ USAR COORDINATECONVERTER para conversión centralizada SetPosition(pos.X, CoordinateConverter.WpfYToBepuY(value), pos.Z); } } public Vector2 Center { get { var pos3D = GetPosition(); // ✅ USAR COORDINATECONVERTER para conversión centralizada return CoordinateConverter.BepuVector3ToWpfVector2(pos3D); } set { // Mantener la Z actual, solo cambiar X, Y var currentPos = GetPosition(); // ✅ USAR COORDINATECONVERTER para conversión centralizada SetPosition(value.X, CoordinateConverter.WpfYToBepuY(value.Y), currentPos.Z); } } public float Mass { get { if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle)) { var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle); return 1f / bodyReference.LocalInertia.InverseMass; } return _mass; } set { _mass = value; if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle)) { // Usar esfera simple - sin complejidad de inercia personalizada var sphere = new Sphere(Radius); var inertia = sphere.ComputeInertia(value); _simulation.Bodies.SetLocalInertia(BodyHandle, inertia); } } } private void Create(Vector3 position) { RemoverBody(); // Usar ESFERA en BEPU para simplicidad matemática y eficiencia var sphere = new Sphere(Radius); var shapeIndex = _simulation.Shapes.Add(sphere); // Inercia estándar de esfera - sin complejidad adicional var inertia = sphere.ComputeInertia(_mass); // NUNCA DORMIR - Valor negativo significa que las botellas JAMÁS entran en sleep mode // Esto es crítico para detección continua de barreras, transportes y descartes var activityDescription = new BodyActivityDescription(-1f); // -1 = NUNCA dormir var bodyDescription = BodyDescription.CreateDynamic( new RigidPose(position), new BodyVelocity(), inertia, // Inercia estándar de esfera new CollidableDescription(shapeIndex, 0.001f), activityDescription ); BodyHandle = _simulation.Bodies.Add(bodyDescription); _bodyCreated = true; // Marcar que hemos creado un cuerpo // ✅ NUEVO: Almacenar la masa inversa base después de crear el cuerpo // Esto nos sirve como referencia para la lógica de masa dinámica. var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle); this.BaseInverseMass = bodyReference.LocalInertia.InverseMass; // ✅ CORREGIDO: Usar el diccionario del SimulationManager y la clave .Value del handle. if (_simulationManager != null) _simulationManager.CollidableData[BodyHandle.Value] = this; } public void SetDiameter(float diameter) { Radius = diameter / 2f; Height = diameter; // Mantener altura igual al diámetro para proporciones consistentes // ✅ CORREGIDO: Usar ChangeBodyShape para limpiar la forma anterior if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle)) { var sphere = new Sphere(Radius); var shapeIndex = _simulation.Shapes.Add(sphere); ChangeBodyShape(shapeIndex); } } public void SetHeight(float height) { Height = height; // ✅ CORREGIDO: Usar ChangeBodyShape para limpiar la forma anterior if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle)) { var sphere = new Sphere(Radius); var shapeIndex = _simulation.Shapes.Add(sphere); ChangeBodyShape(shapeIndex); } } public void SetMass(float mass) { Mass = mass; } /// /// Limita la rotación de la botella solo al plano XY (siempre "de pie") /// Esto simplifica enormemente la simulación y es más realista para botellas /// public void LimitRotationToXYPlane() { if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle)) { var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle); // Extraer solo la rotación en Z (plano XY) y eliminar las rotaciones en X e Y var currentOrientation = bodyReference.Pose.Orientation; // Convertir a ángulo en Z solamente var rotationZ = GetRotationZ(); // ✅ CORREGIDO: Calificar explícitamente para evitar ambigüedad de tipos. var correctedOrientation = System.Numerics.Quaternion.CreateFromAxisAngle(Vector3.UnitZ, rotationZ); // Aplicar la orientación corregida bodyReference.Pose.Orientation = correctedOrientation; // También limitar la velocidad angular a solo rotación en Z var angularVelocity = bodyReference.Velocity.Angular; bodyReference.Velocity.Angular = new Vector3(0, 0, angularVelocity.Z); } } public void ApplyLinearVelocity(Vector3 velocity) { if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle)) { var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle); bodyReference.Velocity.Linear = velocity; } } public Vector3 GetLinearVelocity() { if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle)) { var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle); return bodyReference.Velocity.Linear; } return Vector3.Zero; } public void CenterFixtureOnConveyor() { // Implementar lógica de centrado si es necesario } public bool IsOnAnyTransport() { return isOnTransports > 0; } /// /// ✅ SIMPLIFICADO: RemoverBody que confía en BEPU para limpiar constraints /// public new void RemoverBody() { base.RemoverBody(); } } }