diff --git a/.cursor/rules/reglas.mdc b/.cursor/rules/reglas.mdc index 024a32f..ba09dd3 100644 --- a/.cursor/rules/reglas.mdc +++ b/.cursor/rules/reglas.mdc @@ -1,4 +1,4 @@ --- alwaysApply: true --- -Quisiera que con los conocimientos importantes y desiciones importantes que hemos adquirido y utilizado los agregues a @MemoriadeEvolucion.md manteniendo el estilo que ya tenemos de texto simple sin demasiado codigo y una semantica resumida. \ No newline at end of file +Quisiera que con los conocimientos importantes y desiciones importantes que hemos adquirido y utilizado los agregues a Documentation\MemoriadeEvolucion.md manteniendo el estilo que ya tenemos de texto simple sin demasiado codigo y una semantica resumida. \ No newline at end of file diff --git a/Documentation/MemoriadeEvolucion.md b/Documentation/MemoriadeEvolucion.md index 0b7e7c3..10d6d6e 100644 --- a/Documentation/MemoriadeEvolucion.md +++ b/Documentation/MemoriadeEvolucion.md @@ -6,6 +6,9 @@ simBase : Clase base que da un marco a el resto de los objetos simBarrera : Simula una fotocelula con un espejo usando RayCast simBotella : Simula una botella que puede transitar por los transportes simTransporte o simCurve simCurve : Simula una curva o arco de curva de transporte +simDescarte : Permite la eliminacion localizada de botellas en un punto del mundo +simGuia : Es un box con el que las botellas pueden colisionar y cambiar de direccion. +simTransporte : Es un box por donde las botellas pueden desplazarse usando un truco de aplicar la Velocity.Linear pero sin integrar esta velocidad para que no se mueva el objeto transporte. * Se usaron esferas en vez de cilindros para mejorar la eficiencia. En el Debug3D si se usan cilindros. **Revertido**: Se ha vuelto a usar `Cylinder` para las `simBotella` ya que el nuevo sistema de fricción debería prevenir la rotación indeseada que ocurría con los `LinearAxisMotor`. @@ -17,3 +20,7 @@ simCurve : Simula una curva o arco de curva de transporte * La unica clase que se ha terminado de refactorizar respecto a el cambio de coordenadas es simBarrera y ucPhotocell. El concepto es poder separar usando metodos de SimulationManagerBEPU y estructuras como BarreraData la conversion de coordenadas de WPF a coordenadas BEPU. Para esto se usa CoordinateConverter que permite bidireccionalmente convertir las coordenadas pero esto solo se debe usar en SimulationManagerBEPU las clases derivadas de osBase solo deben manejar coordenadas WPF, mientras que las clases dervadas de simBase solo deben almacenar y usar coordenadas BEPU. La z tambien es algo que se debe transferir a SimulationManagerBEPU ya que los objetos simBase deberian recibir tambien sus coordenadas de Z desde SimulationManagerBEPU y ser SimulationManagerBEPU el que gestione las Z. +* Se ha implementado un sistema para evitar que las botellas (`simBotella`) "floten" o se eleven de manera irreal por la acumulación de presión en la simulación. Cada botella ahora registra si está en contacto con un transporte y almacena la última coordenada Z válida durante dicho contacto. Si la botella deja de tener contacto con transportes por varios frames consecutivos, se incrementa un contador de "presión". Al superar un umbral, el sistema reestablece la posición Z de la botella a su última altura conocida, previniendo la flotación. Este contador de presión se decrementa rápidamente al volver a hacer contacto con un transporte. + +* Cuando una botella (`simBotella`) entra en contacto con un transporte de frenado (`simTransporte` con `isBrake = true`), su posición se ajusta automáticamente para centrarla en el eje longitudinal del transporte. Esto se realiza una única vez, en el primer contacto, para asegurar un acoplamiento suave y predecible. La posición de la botella se proyecta sobre la línea central del transporte y su velocidad lateral se anula, evitando que la botella se desvíe mientras frena y se alinea con el flujo de salida. + diff --git a/Simulacion/BEPU.cs b/Simulacion/BEPU.cs index 2fcc8b1..a9f3b4a 100644 --- a/Simulacion/BEPU.cs +++ b/Simulacion/BEPU.cs @@ -126,10 +126,49 @@ namespace CtrEditor.Simulacion // La velocidad del cuerpo cinemático del transporte se establece directamente // en la clase simTransporte. El motor de físicas se encarga del resto. + // ✅ NUEVO: Lógica de control de presión/flotación + botella.IsTouchingTransport = true; + var botellaCollidable = GetBotellaFromCollidable(pair.A) != null ? pair.A : pair.B; + if (botellaCollidable.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(botellaCollidable.BodyHandle)) + { + var body = _simulationManager.simulation.Bodies.GetBodyReference(botellaCollidable.BodyHandle); + botella.LastTransportCollisionZ = body.Pose.Position.Z; + } + // Decrementamos la presión acumulada al tocar un transporte. Se reduce más rápido de lo que aumenta. + botella.PressureBuildup = Math.Max(0, botella.PressureBuildup - 5); + // ✅ Fricción ajustada para un arrastre firme pero no excesivo. var transport = transportA ?? transportB; if (transport.isBrake) { + // ✅ NUEVO: Centrar la botella en el transporte de frenado la primera vez que entra. + // if (!botella.isOnBrakeTransport) + { + if (botella.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(botella.BodyHandle) && + transport.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(transport.BodyHandle)) + { + var bottleBody = _simulationManager.simulation.Bodies.GetBodyReference(botella.BodyHandle); + var transportBody = _simulationManager.simulation.Bodies.GetBodyReference(transport.BodyHandle); + + var bottlePose = bottleBody.Pose; + var transportPose = transportBody.Pose; + + // Proyectar la posición de la botella sobre el eje longitudinal del transporte. + Vector3 transportForward = transport.DirectionVector; + Vector3 vectorToBottle = bottlePose.Position - transportPose.Position; + float projectionLength = Vector3.Dot(vectorToBottle, transportForward); + Vector3 newPositionOnCenterline = transportPose.Position + transportForward * projectionLength; + + // Crear la nueva pose manteniendo la Z original de la botella para no hundirla. + var newBottlePosition = new Vector3(newPositionOnCenterline.X, newPositionOnCenterline.Y, bottlePose.Position.Z); + bottleBody.Pose.Position = newBottlePosition; + + // Opcional: Anular la velocidad lateral para un acoplamiento más suave. + var lateralVelocity = Vector3.Dot(bottleBody.Velocity.Linear, transport.DirectionVector); + bottleBody.Velocity.Linear = transport.DirectionVector * lateralVelocity; + } + } + botella.isOnBrakeTransport = true; pairMaterial.FrictionCoefficient = 14f; pairMaterial.MaximumRecoveryVelocity = 1.0f; @@ -150,6 +189,17 @@ namespace CtrEditor.Simulacion // El motor de físicas usará la velocidad angular del cuerpo cinemático de la curva // para calcular las fuerzas de fricción y arrastrar la botella. + // ✅ NUEVO: Lógica de control de presión/flotación + botella.IsTouchingTransport = true; + var botellaCollidable = GetBotellaFromCollidable(pair.A) != null ? pair.A : pair.B; + if (botellaCollidable.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(botellaCollidable.BodyHandle)) + { + var body = _simulationManager.simulation.Bodies.GetBodyReference(botellaCollidable.BodyHandle); + botella.LastTransportCollisionZ = body.Pose.Position.Z; + } + // Decrementamos la presión acumulada al tocar una curva. + botella.PressureBuildup = Math.Max(0, botella.PressureBuildup - 5); + // ✅ Fricción ajustada para un arrastre firme pero no excesivo. pairMaterial.FrictionCoefficient = 1f; pairMaterial.MaximumRecoveryVelocity = 1.0f; @@ -717,7 +767,13 @@ namespace CtrEditor.Simulacion try { _frameCount++; - + + // ✅ NUEVO: Resetear el estado de contacto para el sistema de presión + foreach (var botella in Cuerpos.OfType()) + { + botella.IsTouchingTransport = false; + } + // ✅ CONSERVAR - validación de deltaTime var currentTime = stopwatch.Elapsed.TotalMilliseconds; var deltaTime = (float)((currentTime - stopwatch_last) / 1000.0); @@ -794,6 +850,7 @@ namespace CtrEditor.Simulacion // ✅ CONSERVAR - sistemas que funcionan bien ProcessBarreraContacts(); ProcessDescarteContacts(); + ProcessPressureSystem(); ProcessCleanupSystem(); // ✅ SIMPLIFICAR - limpiar solo contactos que usamos @@ -820,6 +877,60 @@ namespace CtrEditor.Simulacion + /// + /// ✅ NUEVO: Sistema para controlar la "presión" y evitar que las botellas floten + /// Si una botella no toca un transporte por varios frames, se reestablece su altura. + /// + private void ProcessPressureSystem() + { + try + { + var botellas = Cuerpos.OfType().ToList(); + + foreach (var botella in botellas) + { + try + { + if (botella == null || !simulation.Bodies.BodyExists(botella.BodyHandle)) + continue; + + if (!botella.IsTouchingTransport && botella.LastTransportCollisionZ.HasValue) + { + var body = simulation.Bodies.GetBodyReference(botella.BodyHandle); + var currentZ = body.Pose.Position.Z; + + // ✅ NUEVA CONDICIÓN: Solo actuar si la botella ha subido + if (currentZ > botella.LastTransportCollisionZ.Value) + { + // Incrementar el contador de presión. + botella.PressureBuildup++; + + // Si se acumula suficiente presión (más de 2 frames sin contacto y subiendo), + // es un indicio de que está flotando. La reestablecemos a su última Z conocida. + if (botella.PressureBuildup > 2) + { + var pose = body.Pose; + pose.Position.Z = botella.LastTransportCollisionZ.Value; + body.Pose = pose; + + // Opcional: resetear el contador para no aplicarlo constantemente en cada frame + // botella.PressureBuildup = 0; + } + } + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[ProcessPressureSystem] Error processing bottle {botella?.BodyHandle}: {ex.Message}"); + } + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[ProcessPressureSystem] Critical error: {ex.Message}"); + } + } + /// /// ✅ NUEVO: Marca un objeto para eliminación diferida (más seguro) /// @@ -1035,9 +1146,6 @@ namespace CtrEditor.Simulacion } } - // ✅ ELIMINADO: CalculateBarreraDetectionGeometric - ya no se usa - // El nuevo sistema usa RayCast nativo de BEPU a través de simBarrera.PerformRaycast() - /// /// Procesa contactos de descarte para eliminar botellas marcadas usando detección geométrica /// diff --git a/Simulacion/simBotella.cs b/Simulacion/simBotella.cs index a9c00fe..5de6494 100644 --- a/Simulacion/simBotella.cs +++ b/Simulacion/simBotella.cs @@ -31,6 +31,11 @@ namespace CtrEditor.Simulacion 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 control de flotación/presión + public float? LastTransportCollisionZ { get; set; } + public int PressureBuildup { get; set; } = 0; + public bool IsTouchingTransport { get; set; } = false; + // ✅ NUEVO: Propiedades para la física personalizada public float BaseInverseMass { get; private set; } public Vector3 InitialPosition3D { get; private set; }