diff --git a/Documentation/MemoriadeEvolucion.md b/Documentation/MemoriadeEvolucion.md index 332f9f4..cff4b9f 100644 --- a/Documentation/MemoriadeEvolucion.md +++ b/Documentation/MemoriadeEvolucion.md @@ -30,3 +30,7 @@ simTransporte : Es un box por donde las botellas pueden desplazarse usando un tr * Se ha mejorado el sistema de guías curvas (`ucTransporteCurvaGuias`) para incluir apertura en cono en los extremos de entrada y salida. Se agregó el parámetro `AnguloAperturaGuias` (por defecto 5 grados) que permite configurar la apertura modificando los radios de las guías en los puntos extremos. En lugar de cambiar ángulos, se reduce el radio de la guía superior (externa) y se aumenta el radio de la guía inferior (interna) en los segmentos inicial y final, creando naturalmente la apertura en cono. La modificación del radio se calcula usando `Math.Sin(anguloApertura)` para obtener el desplazamiento apropiado. Esta apertura facilita la entrada y salida de botellas del transporte curvo, reduciendo atascos y mejorando el flujo de materiales manteniendo la continuidad geométrica de las guías. +* Se ha implementado un sistema de fricción dinámica que simula el comportamiento de fricción estática vs dinámica para contactos botella-transporte y botella-curva. El sistema calcula el deslizamiento relativo entre la botella y la superficie del transporte: cuando el deslizamiento es bajo (< 0.05 m/s), se aplica fricción estática alta para un arrastre efectivo; cuando el deslizamiento es alto, se aplica fricción dinámica menor para permitir un deslizamiento suave. Para curvas, se calcula la velocidad de superficie usando el producto vectorial (v = ω × r). Para contactos botella-botella, se usa detección de profundidad de penetración para aplicar materiales ultra-suaves cuando hay alta presión, previniendo acumulaciones explosivas. Este enfoque proactivo reemplaza el sistema reactivo de `PressureBuildup` y proporciona un comportamiento más físicamente realista y estable en acumulaciones de botellas. + +* Se ha reemplazado el sistema `ProcessPressureSystem` por un nuevo sistema de calibración visual `HighSlippery` que permite ajustar las fricciones de cada componente. Cada botella tiene una propiedad `HighSlippery` (rango 0-9) con sistema de heatup/cooldown que se incrementa durante deslizamiento y se decrementa durante adherencia. El valor se muestra como número en el centro de cada botella para calibración visual. Los `SpringSettings` se mantienen >= 30 para evitar compresiones irreales. El sistema permite calibrar las tasas de heatup/cooldown específicas para transportes (0.2/0.1) y curvas (0.15/0.08), y el umbral de cambio estático/dinámico (HighSlippery > 3). Este sistema elimina el problema del cooldown que reactivaba prematuramente la fricción estática. + diff --git a/ObjetosSim/Dinamicos/ucBotella.xaml b/ObjetosSim/Dinamicos/ucBotella.xaml index cd4b32c..d854a5c 100644 --- a/ObjetosSim/Dinamicos/ucBotella.xaml +++ b/ObjetosSim/Dinamicos/ucBotella.xaml @@ -5,8 +5,21 @@ - + + + + + + \ No newline at end of file diff --git a/ObjetosSim/Dinamicos/ucBotella.xaml.cs b/ObjetosSim/Dinamicos/ucBotella.xaml.cs index 1b65d0e..d52649b 100644 --- a/ObjetosSim/Dinamicos/ucBotella.xaml.cs +++ b/ObjetosSim/Dinamicos/ucBotella.xaml.cs @@ -93,6 +93,12 @@ namespace CtrEditor.ObjetosSim [property: Name("En Transporte con Freno")] private bool enTransporteConFreno; + [ObservableProperty] + [property: Category("Calibración")] + [property: Description("Nivel de deslizamiento/presión (0-9) para calibración de fricción")] + [property: Name("Nivel de Deslizamiento")] + private float nivelDeslizamiento; + [ObservableProperty] [property: Category("Simulación")] [property: Description("Masa del objeto en kg")] @@ -174,7 +180,7 @@ namespace CtrEditor.ObjetosSim // Sistema de colores jerarquizado para diferentes estados if (SimGeometria.isOnBrakeTransport) ColorButton_oculto = Brushes.Blue; // En transporte con freno (prioridad sobre presión) - else if (!SimGeometria.isOnBrakeTransport && SimGeometria.PressureBuildup>1) + else if (!SimGeometria.isOnBrakeTransport && SimGeometria.ContactPressure > 0) ColorButton_oculto = Brushes.Red; // La botella tiene mucha presion else ColorButton_oculto = Brushes.Gray; // 5. Estado libre @@ -189,6 +195,7 @@ namespace CtrEditor.ObjetosSim Inercia_desde_simulacion = SimGeometria.Mass; // En BEPU usamos masa en lugar de inercia directa Porcentaje_Traccion = SimGeometria.OverlapPercentage; EnTransporteConFreno = SimGeometria.isOnBrakeTransport; // Actualizar estado de freno + NivelDeslizamiento = SimGeometria.HighSlippery; // ✅ NUEVO: Mostrar nivel de deslizamiento para calibración } public override void ucLoaded() diff --git a/Simulacion/BEPU.cs b/Simulacion/BEPU.cs index bd92aa6..ce07f6e 100644 --- a/Simulacion/BEPU.cs +++ b/Simulacion/BEPU.cs @@ -124,9 +124,6 @@ namespace CtrEditor.Simulacion // ✅ CONTACTO BOTELLA-TRANSPORTE: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA if (botella != null && (transportA != null || transportB != null)) { - // 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; @@ -135,16 +132,11 @@ namespace CtrEditor.Simulacion 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 - 0.1f); - // ✅ Fricción ajustada para un arrastre firme pero no excesivo. var transport = transportA ?? transportB; if (transport.isBrake) { - botella.PressureBuildup = 0; // ✅ 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)) @@ -172,35 +164,23 @@ namespace CtrEditor.Simulacion } botella.isOnBrakeTransport = true; - pairMaterial.FrictionCoefficient = 14f; - pairMaterial.MaximumRecoveryVelocity = 1.0f; - pairMaterial.SpringSettings = new SpringSettings(80, 8); + pairMaterial.FrictionCoefficient = 4f; + pairMaterial.MaximumRecoveryVelocity = 0f; + pairMaterial.SpringSettings = new SpringSettings(120, 8f); } else { - if (botella.PressureBuildup > minPressureToLostFriction) - { - botella.isOnBrakeTransport = false; - pairMaterial.FrictionCoefficient = 0.1f; - pairMaterial.MaximumRecoveryVelocity = 1.0f; - pairMaterial.SpringSettings = new SpringSettings(80, 1); - } - else - { - botella.isOnBrakeTransport = false; - pairMaterial.FrictionCoefficient = 1.2f; - pairMaterial.MaximumRecoveryVelocity = 1.0f; - pairMaterial.SpringSettings = new SpringSettings(80, 1); - } + botella.isOnBrakeTransport = false; + // ✅ NUEVO: Usar fricción dinámica basada en deslizamiento + pairMaterial.FrictionCoefficient = CalculateTransportFriction(botella, transport, botellaCollidable); + pairMaterial.MaximumRecoveryVelocity = 0.1f; + pairMaterial.SpringSettings = new SpringSettings(80, 1f); } } // ✅ CONTACTO BOTELLA-CURVA: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA else if (botella != null && (curveA != null || curveB != null)) { - // 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; botella.isOnBrakeTransport = false; @@ -210,59 +190,38 @@ namespace CtrEditor.Simulacion 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 - 0.1f); - // ✅ Fricción ajustada para un arrastre firme pero no excesivo. - if (botella.PressureBuildup > minPressureToLostFriction) - { - pairMaterial.FrictionCoefficient = 0.1f; - pairMaterial.MaximumRecoveryVelocity = 1.0f; - pairMaterial.SpringSettings = new SpringSettings(80, 1); - }else - { - pairMaterial.FrictionCoefficient = 1f; - pairMaterial.MaximumRecoveryVelocity = 1.0f; - pairMaterial.SpringSettings = new SpringSettings(80, 1); - } + // ✅ NUEVO: Usar fricción dinámica basada en deslizamiento + var curve = curveA ?? curveB; + pairMaterial.FrictionCoefficient = CalculateCurveFriction(botella, curve, botellaCollidable); + pairMaterial.MaximumRecoveryVelocity = 0.1f; + pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Colision con la cinta por gravedad } // ✅ CONTACTO BOTELLA-GUÍA: Configuración específica de fricción else if (botella != null && (GetGuiaFromCollidable(pair.A) != null || GetGuiaFromCollidable(pair.B) != null)) { // Fricción baja para las guías, deben deslizar, no arrastrar. - pairMaterial.FrictionCoefficient = 0.01f; - pairMaterial.MaximumRecoveryVelocity = 2f; - pairMaterial.SpringSettings = new SpringSettings(20, 1); + pairMaterial.FrictionCoefficient = 0.1f; + pairMaterial.MaximumRecoveryVelocity = 0.8f; + pairMaterial.SpringSettings = new SpringSettings(50, 1f); // Rebote lateral moderado } - // ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Configuración más suave para evitar el comportamiento "pegajoso". + // ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Lógica de presión proactiva basada en la penetración. else if (botellaA != null && botellaB != null) { - if (botella.isOnBrakeTransport) - { - pairMaterial.FrictionCoefficient = 2.0f; // Un poco menos de fricción. - pairMaterial.MaximumRecoveryVelocity = 1.5f; // Menos rebote. - pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Muelle MUCHO más suave y críticamente amortiguado. - } - else - { - pairMaterial.FrictionCoefficient = 0.01f; // Un poco menos de fricción. - pairMaterial.MaximumRecoveryVelocity = 1.5f; // Menos rebote. - pairMaterial.SpringSettings = new SpringSettings(20, 0.5f); // Muelle MUCHO más suave y críticamente amortiguado. - } - // Si una botella tiene presion esta presion es transmitia a el resto para que el resto pierda el coeficiente de friccion sobre los transportes - if (botellaA.PressureBuildup > 0 && botellaB.PressureBuildup == 0) - botellaB.PressureBuildup = botellaA.PressureBuildup; - if (botellaB.PressureBuildup > 0 && botellaA.PressureBuildup == 0) - botellaA.PressureBuildup = botellaB.PressureBuildup; - + // ✅ NUEVO: Usar método especializado para contactos botella-botella + CalculateBottlePression(ref manifold, botellaA, botellaB); + pairMaterial.FrictionCoefficient = 0.1f; + pairMaterial.MaximumRecoveryVelocity = 0.03f; + pairMaterial.SpringSettings = new SpringSettings(80, 1f); // Rebote lateral moderado } // Ajustes básicos para otras botellas else if (botella != null) { + System.Diagnostics.Debug.WriteLine($"[ConfigureContactManifold] ERROR: contacto no resuelto!"); // Fricción moderada para colisiones entre botellas. pairMaterial.FrictionCoefficient = 0.3f; pairMaterial.MaximumRecoveryVelocity = 1f; - pairMaterial.SpringSettings = new SpringSettings(80, 1); + pairMaterial.SpringSettings = new SpringSettings(30, 1); } } @@ -348,11 +307,139 @@ namespace CtrEditor.Simulacion - /// - /// ✅ NUEVO MÉTODO: Aplicar fuerzas de frenado directamente en el manifold - /// + /// + /// ✅ NUEVO: Calcula la fricción dinámica para contactos botella-transporte basada en el deslizamiento relativo + /// + private float CalculateTransportFriction(simBotella botella, simTransporte transport, CollidableReference botellaCollidable) + { + try + { + 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 bottleVelocity = bottleBody.Velocity.Linear; + var transportVelocity = transport.CalcularVelocidadCinematica(); // La velocidad cinemática se actualiza en OnSubstepStarted + + var slipVelocity = bottleVelocity - transportVelocity; + slipVelocity.Z = 0; // Ignoramos el deslizamiento vertical + var slipSpeed = slipVelocity.Length(); + + float slipSpeedThreshold = transportVelocity.Length()*0.85f; // m/s - umbral para cambiar de fricción estática a dinámica + const float heatupRate = 1f; // Qué tan rápido sube HighSlippery + const float cooldownRate = 0.5f; // Qué tan rápido baja HighSlippery + const float staticFriction = 0.25f; + const float dynamicFriction = 0.10f; + + // Sistema de heatup/cooldown para HighSlippery + if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0 + botella.HighSlippery = Math.Min(9f, botella.HighSlippery + heatupRate); + else + botella.HighSlippery = Math.Max(0f, botella.HighSlippery - cooldownRate); + + // Calcular fricción basada en HighSlippery + // HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática + if (botella.HighSlippery > 3f) + return dynamicFriction; + else + return staticFriction; + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[CalculateTransportFriction] Error: {ex.Message}"); + } + + // Valor por defecto si hay algún error + return 1.0f; + } + + /// + /// ✅ NUEVO: Calcula la fricción dinámica para contactos botella-curva basada en el deslizamiento relativo + /// + private float CalculateCurveFriction(simBotella botella, simCurve curve, CollidableReference botellaCollidable) + { + try + { + if (botella?.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(botella.BodyHandle) && + curve?.BodyHandle.Value >= 0 && _simulationManager.simulation.Bodies.BodyExists(curve.BodyHandle)) + { + var bottleBody = _simulationManager.simulation.Bodies.GetBodyReference(botella.BodyHandle); + var curveBody = _simulationManager.simulation.Bodies.GetBodyReference(curve.BodyHandle); + + // Aproximamos la velocidad de la superficie de la curva en la posición de la botella. + // v = ω x r + var r = bottleBody.Pose.Position - curveBody.Pose.Position; + var curveVelocityAtPoint = Vector3.Cross(curve.CalcularVelocidadCinematica(), r); + + var slipVelocity = bottleBody.Velocity.Linear - curveVelocityAtPoint; + slipVelocity.Z = 0; // Ignoramos el deslizamiento vertical + var slipSpeed = slipVelocity.Length(); + + float slipSpeedThreshold = curveVelocityAtPoint.Length() * 0.85f; // m/s + const float heatupRate = 1f; // Qué tan rápido sube HighSlippery en curvas + const float cooldownRate = 0.5f; // Qué tan rápido baja HighSlippery en curvas + const float staticFriction = 0.20f; + const float dynamicFriction = 0.10f; + + // Sistema de heatup/cooldown para HighSlippery + if (slipSpeed > slipSpeedThreshold) // && botella.ContactPressure > 0 + botella.HighSlippery = Math.Min(9f, botella.HighSlippery + heatupRate); + else + botella.HighSlippery = Math.Max(0f, botella.HighSlippery - cooldownRate); + + // Calcular fricción basada en HighSlippery + // HighSlippery > 3 = fricción dinámica, <= 3 = fricción estática + if (botella.HighSlippery > 3f) + return dynamicFriction; + else + return staticFriction; + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[CalculateCurveFriction] Error: {ex.Message}"); + } + + // Valor por defecto si hay algún error + return 0.8f; + } + + /// + /// ✅ NUEVO: Calcula los parámetros de material para contactos botella-botella basado en la profundidad de penetración + /// + private void CalculateBottlePression(ref TManifold manifold, simBotella botellaA, simBotella botellaB) where TManifold : unmanaged, IContactManifold + { + var pairMaterial = new PairMaterialProperties(); + + try + { + const float penetrationDepthThreshold = 0.001f; // Umbral de penetración en metros para detectar alta presión. + + // Iteramos sobre todos los puntos de contacto en el manifold. + for (int i = 0; i < manifold.Count; ++i) + { + // Si la profundidad de la penetración supera nuestro umbral, + // consideramos que este contacto está bajo alta presión. + if (manifold.GetDepth(i) > penetrationDepthThreshold) + { + botellaA.ContactPressure = Math.Max(botellaA.ContactPressure, manifold.GetDepth(i) - penetrationDepthThreshold); + botellaB.ContactPressure = Math.Max(botellaB.ContactPressure, manifold.GetDepth(i) - penetrationDepthThreshold); + // break; // Un punto de alta presión es suficiente. + } + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[CalculateBottleToBottleMaterial] Error: {ex.Message}"); + // Valores por defecto seguros + } + } + public bool ConfigureContactManifold(int workerIndex, CollidablePair pair, int childIndexA, int childIndexB, ref ConvexContactManifold manifold) { return true; @@ -427,13 +514,54 @@ namespace CtrEditor.Simulacion var handle = _simulationManager.simulation.Bodies.ActiveSet.IndexToHandle[bodyIndex]; if (_simulationManager.CollidableData.TryGetValue(handle.Value, out simBase baseObj) && baseObj is simBotella) { - // B. DAMPING ANGULAR EXTRA EN EJE Z - // Para modificar un solo carril de un Vector, la forma más segura es extraer - // los valores a un array, modificar el índice y crear un nuevo Vector. - var zVel = new float[Vector.Count]; - velocity.Angular.Z.CopyTo(zVel, 0); - zVel[i] *= bottleZAngularDampingFactor; - velocity.Angular.Z = new Vector(zVel); + //// B. DAMPING ANGULAR EXTRA EN EJE Z + //// Para modificar un solo carril de un Vector, la forma más segura es extraer + //// los valores a un array, modificar el índice y crear un nuevo Vector. + //var zVel = new float[Vector.Count]; + //velocity.Angular.Z.CopyTo(zVel, 0); + //zVel[i] *= bottleZAngularDampingFactor; + //velocity.Angular.Z = new Vector(zVel); + // --- INICIO DE NUESTRA LÓGICA ANTI-SALTO Y ANTI-VUELCO --- + + // 1. EXTRAER VELOCIDADES DEL PAQUETE A ARRAYS + var linearX = new float[Vector.Count]; + var linearY = new float[Vector.Count]; + var linearZ = new float[Vector.Count]; + var angularX = new float[Vector.Count]; + var angularY = new float[Vector.Count]; + var angularZ = new float[Vector.Count]; + + velocity.Linear.X.CopyTo(linearX, 0); + velocity.Linear.Y.CopyTo(linearY, 0); + velocity.Linear.Z.CopyTo(linearZ, 0); + velocity.Angular.X.CopyTo(angularX, 0); + velocity.Angular.Y.CopyTo(angularY, 0); + velocity.Angular.Z.CopyTo(angularZ, 0); + + // 2. APLICAR RESTRICCIONES AL CARRIL 'i' (la botella) + + // ANTI-VUELCO: Anular cualquier velocidad angular que tumbe la botella. + angularX[i] = 0; + angularY[i] = 0; + + // ANTI-SALTO: Si la velocidad Z es positiva (hacia arriba), anularla. + // Esto permite que la gravedad actúe (Z negativo) pero impide saltos. + if (linearZ[i] > 0) + { + linearZ[i] = 0; + } + + // DAMPING ANGULAR EXTRA EN EJE Z (Tu lógica original) + angularZ[i] *= bottleZAngularDampingFactor; + + + // 3. RECONSTRUIR LOS VECTORES 'WIDE' CON LOS VALORES MODIFICADOS + velocity.Linear.X = new Vector(linearX); + velocity.Linear.Y = new Vector(linearY); + velocity.Linear.Z = new Vector(linearZ); + velocity.Angular.X = new Vector(angularX); + velocity.Angular.Y = new Vector(angularY); + velocity.Angular.Z = new Vector(angularZ); } } } @@ -511,6 +639,10 @@ namespace CtrEditor.Simulacion // ✅ NUEVOS - gestión automática de clasificación private void RegisterObjectHandle(simBase obj) { + if (obj != null && obj.BodyHandle.Value >= 0) + { + CollidableData[obj.BodyHandle.Value] = obj; + } switch (obj) { case simBotella bottle: @@ -540,6 +672,10 @@ namespace CtrEditor.Simulacion private void UnregisterObjectHandle(simBase obj) { + if (obj != null && obj.BodyHandle.Value >= 0) + { + CollidableData.Remove(obj.BodyHandle.Value); + } switch (obj) { case simBotella bottle: @@ -624,8 +760,8 @@ namespace CtrEditor.Simulacion // ✅ MODIFICADO: Pasar referencia de this al PoseIntegratorCallbacks var poseIntegratorCallbacks = new PoseIntegratorCallbacks( gravity: new Vector3(0, 0, -9.81f), // Gravedad en Z - linearDamping: 0.999f, // Amortiguamiento lineal suave - angularDamping: 0.995f, // Amortiguamiento angular más fuerte para detener rotaciones + linearDamping: 0.03f, // 0.999f, // Amortiguamiento lineal suave + angularDamping: 0.03f, // 0.995f, // Amortiguamiento angular más fuerte para detener rotaciones simulationManager: this // ✅ NUEVA REFERENCIA ); @@ -799,6 +935,7 @@ namespace CtrEditor.Simulacion foreach (var botella in Cuerpos.OfType()) { botella.IsTouchingTransport = false; + botella.ContactPressure = 0f; } // ✅ CONSERVAR - validación de deltaTime @@ -857,27 +994,26 @@ namespace CtrEditor.Simulacion - // ✅ CONSERVAR - limitación de rotación y mantener botellas despiertas - foreach (var cuerpo in Cuerpos.OfType().ToList()) - { - try - { - if (simulation.Bodies.BodyExists(cuerpo.BodyHandle)) - { - // cuerpo.LimitRotationToXYPlane(); - // simulation.Awakener.AwakenBody(cuerpo.BodyHandle); - } - } - catch (Exception ex) - { - // Error limiting rotation for bottle - continue - } - } + //// ✅ CONSERVAR - limitación de rotación y mantener botellas despiertas + //foreach (var cuerpo in Cuerpos.OfType().ToList()) + //{ + // try + // { + // if (simulation.Bodies.BodyExists(cuerpo.BodyHandle)) + // { + // // cuerpo.LimitRotationToXYPlane(); + // // simulation.Awakener.AwakenBody(cuerpo.BodyHandle); + // } + // } + // catch (Exception ex) + // { + // // Error limiting rotation for bottle - continue + // } + //} // ✅ CONSERVAR - sistemas que funcionan bien ProcessBarreraContacts(); ProcessDescarteContacts(); - ProcessPressureSystem(); ProcessCleanupSystem(); // ✅ SIMPLIFICAR - limpiar solo contactos que usamos @@ -904,59 +1040,7 @@ 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) diff --git a/Simulacion/simBotella.cs b/Simulacion/simBotella.cs index 3667b71..53b2b6d 100644 --- a/Simulacion/simBotella.cs +++ b/Simulacion/simBotella.cs @@ -33,9 +33,12 @@ namespace CtrEditor.Simulacion // ✅ NUEVO: Propiedades para control de flotación/presión public float? LastTransportCollisionZ { get; set; } - public float PressureBuildup { get; set; } = 0; public bool IsTouchingTransport { get; set; } = false; + // ✅ NUEVO: Sistema de fricción dinámica con cooldown/heatup + public float HighSlippery { get; set; } = 0f; // Rango 0-9, donde 9 es máxima presión/deslizamiento + public float ContactPressure { get; set; } = 0f; // Rango 0-9, donde 9 es mínima presión/deslizamiento + // ✅ NUEVO: Propiedades para la física personalizada public float BaseInverseMass { get; private set; } public Vector3 InitialPosition3D { get; private set; } diff --git a/Simulacion/simCurve.cs b/Simulacion/simCurve.cs index 496557a..746b01c 100644 --- a/Simulacion/simCurve.cs +++ b/Simulacion/simCurve.cs @@ -70,6 +70,23 @@ namespace CtrEditor.Simulacion ActualizarVelocidadCinematica(); } + + public Vector3 CalcularVelocidadCinematica() + { + float effectiveRadius = (_innerRadius + _outerRadius) / 2.0f; + if (effectiveRadius > 0.001f) + { + // La velocidad tangencial (Speed) se convierte a velocidad angular (ω = v / r) + // ✅ CORREGIDO: Convertir velocidad de m/min a m/s para la simulación + float angularSpeed = (Speed / SpeedConversionFactor) / effectiveRadius; + + // La rotación es alrededor del eje Z en el sistema de coordenadas de BEPU + return new Vector3(0, 0, angularSpeed); + } + return Vector3.Zero; // Si no hay cuerpo o radio efectivo es muy pequeño, no hay velocidad angular + } + + /// /// ✅ NUEVO: Aplica la velocidad angular al cuerpo cinemático de BEPU. /// @@ -79,20 +96,7 @@ namespace CtrEditor.Simulacion { var body = _simulation.Bodies.GetBodyReference(BodyHandle); - float effectiveRadius = (_innerRadius + _outerRadius) / 2.0f; - if (effectiveRadius > 0.001f) - { - // La velocidad tangencial (Speed) se convierte a velocidad angular (ω = v / r) - // ✅ CORREGIDO: Convertir velocidad de m/min a m/s para la simulación - float angularSpeed = (Speed / SpeedConversionFactor) / effectiveRadius; - - // La rotación es alrededor del eje Z en el sistema de coordenadas de BEPU - body.Velocity.Angular = new Vector3(0, 0, angularSpeed); - } - else - { - body.Velocity.Angular = Vector3.Zero; - } + body.Velocity.Angular = CalcularVelocidadCinematica(); } } diff --git a/Simulacion/simTransporte.cs b/Simulacion/simTransporte.cs index a298fb9..560f3ec 100644 --- a/Simulacion/simTransporte.cs +++ b/Simulacion/simTransporte.cs @@ -149,6 +149,14 @@ namespace CtrEditor.Simulacion ActualizarVelocidadCinematica(); } + /// + /// ✅ NUEVO: Aplica la velocidad al cuerpo cinemático de BEPU. + /// + public Vector3 CalcularVelocidadCinematica() + { + return this.DirectionVector * (this.Speed / SpeedConversionFactor); + } + /// /// ✅ NUEVO: Aplica la velocidad al cuerpo cinemático de BEPU. /// @@ -158,7 +166,7 @@ namespace CtrEditor.Simulacion { var body = _simulation.Bodies.GetBodyReference(BodyHandle); // ✅ CORREGIDO: Convertir velocidad de m/min a m/s para la simulación - body.Velocity.Linear = this.DirectionVector * (this.Speed / SpeedConversionFactor); + body.Velocity.Linear = CalcularVelocidadCinematica(); } }