Eliminación del archivo "Memoria de evolución" y cambios en la creación de botellas en la simulación. Se reemplazó el método AddCircle por AddBotella en ucBotella y ucBotellaCuello, y se ajustaron propiedades en simBotella para mejorar la gestión de inercia y fricción. Se eliminaron referencias a barreras físicas en BEPU, optimizando la lógica de colisiones y ajustando parámetros de fricción para mejorar la simulación.
This commit is contained in:
parent
de0e3ce5f0
commit
eb6ed62d5b
|
@ -0,0 +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.
|
|
@ -1,10 +0,0 @@
|
|||
### Aqui se mantiene la memoria de evolucion de las distintas decisiones que fueron tomadas y porque
|
||||
|
||||
* Se usan esferas en vez de cilindros para mejorar la eficiencia. En el Debug3D si se usan cilindros
|
||||
|
||||
* Se usaron LinearAxisMotors originalmente sobre las botellas para crear un movimiento segun las colisicones con los transportes. Luego se busco un sistema que represente mejor la fisica y por cuestiones de eficiencia en vez de crear placas en movimiento real, se usaron cuerpos Box y Triangulos kinematic con velocidad lineal o angular per se interviene en el Integrador para que antes de integrar la velocidad se quite la velocidad y antes del proximo Step se vuelve a aplicar la velocidad. Esto permite que el integrador no mueva los objetos kinetic pero si aplique velocidad por friccion a los objetos dinamic ( simBotella )
|
||||
|
||||
* Originalmente se habia puesto todos los objetos en awaken para poder usar las colisiones constantemente incluso con objetos en modo sleep para que los simBarrera puedan detectar las colisiones. Ahora que se usar RayCast podemos dejar que las simBotellas se duerman
|
||||
|
||||
* 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.
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
### Aqui se mantiene la memoria de evolucion de las distintas decisiones que fueron tomadas y porque
|
||||
|
||||
BEPU.cs : SimulationManagerBEPU gestor de la simulacion con el motor BEPUphysics y punto de creacion y modificacion de los objetos dentro del mundo que se derivan des simBase
|
||||
|
||||
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
|
||||
|
||||
* 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`.
|
||||
|
||||
* Se reemplazó el sistema de `LinearAxisMotor` que actuaba sobre las `simBotella` por un sistema basado en fricción. Los transportes (`simTransporte` y `simCurve`) ahora son cuerpos cinemáticos que no se mueven de su sitio. Para lograr que arrastren a las botellas, se les asigna una velocidad (`Velocity.Linear` o `Velocity.Angular`) justo antes de que el solver se ejecute (en `OnSubstepStarted`) y se les quita justo después (en `OnSubstepEnded`). Esto permite que los cuerpos cinemáticos transmitan su velocidad a través de la fricción durante la simulación, pero evita que el `PoseIntegrator` los desplace de su posición original, ya que su velocidad es cero cuando se integra la pose.
|
||||
|
||||
* Para aumentar la estabilidad de las `simBotella` y evitar que roten descontroladamente sobre su eje Z al ser arrastradas, se implementó un callback `IntegrateVelocity` personalizado. Este callback identifica las botellas durante la integración y les aplica un amortiguamiento angular (`AngularDamping`) adicional solo en el eje Z. Se descartó la idea inicial de modificar dinámicamente la masa de las botellas dentro de este callback, ya que la arquitectura de BEPUphysics no permite cambiar la masa o la inercia de un cuerpo durante la fase de integración de velocidad.
|
||||
|
||||
* Originalmente se habia puesto todos los objetos en awaken para poder usar las colisiones constantemente incluso con objetos en modo sleep para que los simBarrera puedan detectar las colisiones. Ahora que se usar RayCast podemos dejar que las simBotellas se duerman
|
||||
|
||||
* 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.
|
||||
|
|
@ -146,7 +146,9 @@ namespace CtrEditor.ObjetosSim
|
|||
// Se llama cuando inicia la simulación - crear geometría si no existe
|
||||
if (SimGeometria == null)
|
||||
{
|
||||
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
|
||||
SimGeometria = simulationManager.AddBotella(Diametro, GetCentro(), Mass);
|
||||
SimGeometria.SimObjectType = "Botella";
|
||||
SimGeometria.WpfObject = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -196,7 +198,7 @@ namespace CtrEditor.ObjetosSim
|
|||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
base.ucLoaded();
|
||||
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
|
||||
SimGeometria = simulationManager.AddBotella(Diametro, GetCentro(), Mass);
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace CtrEditor.ObjetosSim
|
|||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
base.ucLoaded();
|
||||
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
|
||||
SimGeometria = simulationManager.AddBotella(Diametro, GetCentro(), Mass);
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
|
|
|
@ -98,19 +98,10 @@ namespace CtrEditor.Simulacion
|
|||
{
|
||||
var botellaA = GetBotellaFromCollidable(pair.A);
|
||||
var botellaB = GetBotellaFromCollidable(pair.B);
|
||||
// ✅ ELIMINADO: Las barreras ya no tienen body físico
|
||||
// var barreraA = GetBarreraFromCollidable(pair.A);
|
||||
// var barreraB = GetBarreraFromCollidable(pair.B);
|
||||
var descarteA = GetDescarteFromCollidable(pair.A);
|
||||
var descarteB = GetDescarteFromCollidable(pair.B);
|
||||
var botella = botellaA ?? botellaB;
|
||||
|
||||
// ✅ ELIMINADO: Las barreras ya no participan en colisiones físicas
|
||||
// if (barreraA != null || barreraB != null)
|
||||
// {
|
||||
// return false; // NO generar contacto físico
|
||||
// }
|
||||
|
||||
// ✅ DESCARTES como sensores puros
|
||||
if (descarteA != null || descarteB != null)
|
||||
{
|
||||
|
@ -136,9 +127,9 @@ namespace CtrEditor.Simulacion
|
|||
// en la clase simTransporte. El motor de físicas se encarga del resto.
|
||||
|
||||
// ✅ Fricción ajustada para un arrastre firme pero no excesivo.
|
||||
pairMaterial.FrictionCoefficient = 1.5f;
|
||||
pairMaterial.MaximumRecoveryVelocity = 2.0f;
|
||||
pairMaterial.SpringSettings = new SpringSettings(30, 1);
|
||||
pairMaterial.FrictionCoefficient = 1.2f;
|
||||
pairMaterial.MaximumRecoveryVelocity = 1.0f;
|
||||
pairMaterial.SpringSettings = new SpringSettings(80, 1);
|
||||
}
|
||||
// ✅ CONTACTO BOTELLA-CURVA: USAR FRICCIÓN Y VELOCIDAD CINEMÁTICA
|
||||
else if (botella != null && (curveA != null || curveB != null))
|
||||
|
@ -147,9 +138,9 @@ namespace CtrEditor.Simulacion
|
|||
// para calcular las fuerzas de fricción y arrastrar la botella.
|
||||
|
||||
// ✅ Fricción ajustada para un arrastre firme pero no excesivo.
|
||||
pairMaterial.FrictionCoefficient = 1.5f;
|
||||
pairMaterial.MaximumRecoveryVelocity = 2.0f;
|
||||
pairMaterial.SpringSettings = new SpringSettings(30, 1);
|
||||
pairMaterial.FrictionCoefficient = 1f;
|
||||
pairMaterial.MaximumRecoveryVelocity = 1.0f;
|
||||
pairMaterial.SpringSettings = new SpringSettings(80, 1);
|
||||
}
|
||||
// ✅ CONTACTO BOTELLA-GUÍA: Configuración específica de fricción
|
||||
else if (botella != null && (GetGuiaFromCollidable(pair.A) != null || GetGuiaFromCollidable(pair.B) != null))
|
||||
|
@ -157,7 +148,14 @@ namespace CtrEditor.Simulacion
|
|||
// Fricción baja para las guías, deben deslizar, no arrastrar.
|
||||
pairMaterial.FrictionCoefficient = 0.1f;
|
||||
pairMaterial.MaximumRecoveryVelocity = 1f;
|
||||
pairMaterial.SpringSettings = new SpringSettings(80, 6);
|
||||
pairMaterial.SpringSettings = new SpringSettings(20, 1);
|
||||
}
|
||||
// ✅ NUEVO: CONTACTO BOTELLA-BOTELLA: Configuración más suave para evitar el comportamiento "pegajoso".
|
||||
else if (botellaA != null && botellaB != null)
|
||||
{
|
||||
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.
|
||||
}
|
||||
// Ajustes básicos para otras botellas
|
||||
else if (botella != null)
|
||||
|
@ -165,7 +163,7 @@ namespace CtrEditor.Simulacion
|
|||
// Fricción moderada para colisiones entre botellas.
|
||||
pairMaterial.FrictionCoefficient = 0.3f;
|
||||
pairMaterial.MaximumRecoveryVelocity = 1f;
|
||||
pairMaterial.SpringSettings = new SpringSettings(80, 6);
|
||||
pairMaterial.SpringSettings = new SpringSettings(80, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,7 +759,7 @@ namespace CtrEditor.Simulacion
|
|||
{
|
||||
if (simulation.Bodies.BodyExists(cuerpo.BodyHandle))
|
||||
{
|
||||
cuerpo.LimitRotationToXYPlane();
|
||||
// cuerpo.LimitRotationToXYPlane();
|
||||
simulation.Awakener.AwakenBody(cuerpo.BodyHandle);
|
||||
}
|
||||
}
|
||||
|
@ -805,48 +803,24 @@ namespace CtrEditor.Simulacion
|
|||
/// </summary>
|
||||
public void Remove(simBase Objeto)
|
||||
{
|
||||
if (Objeto == null) return;
|
||||
|
||||
try
|
||||
if (Objeto != null)
|
||||
{
|
||||
// ✅ SIMPLIFICADO - eliminar lógica de masa especial
|
||||
UnregisterObjectHandle(Objeto); // ✅ NUEVO
|
||||
Objeto.RemoverBody(); // ✅ CONSERVAR - remover el cuerpo de BEPU
|
||||
|
||||
// ✅ NUEVO - Limpiar dimensiones almacenadas en osBase
|
||||
CtrEditor.ObjetosSim.osBase.ClearStoredDimensions(Objeto);
|
||||
|
||||
|
||||
// ✅ REMOVER de la lista inmediatamente para evitar referencias colgantes
|
||||
Cuerpos.Remove(Objeto);
|
||||
|
||||
if (Is3DUpdateEnabled)
|
||||
// Aplazar la eliminación para evitar problemas de concurrencia
|
||||
_deferredActions.Add(() =>
|
||||
{
|
||||
Visualization3DManager?.SynchronizeWorld();
|
||||
}
|
||||
|
||||
//System.Diagnostics.Debug.WriteLine($"[Remove] ✅ Objeto marcado para eliminación diferida: {Objeto.GetType().Name}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[Remove] ❌ Error marcando objeto {Objeto?.GetType().Name}: {ex.Message}");
|
||||
|
||||
// ✅ CRÍTICO: Siempre remover de la lista incluso si falló
|
||||
Cuerpos.Remove(Objeto);
|
||||
UnregisterObjectHandle(Objeto);
|
||||
Objeto.RemoverBody();
|
||||
Cuerpos.Remove(Objeto);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public simBotella AddCircle(float diameter, Vector2 position, float mass)
|
||||
public simBotella AddBotella(float diameter, Vector2 position, float mass)
|
||||
{
|
||||
var botella = new simBotella(simulation, _deferredActions, diameter, position, mass);
|
||||
Cuerpos.Add(botella);
|
||||
RegisterObjectHandle(botella); // ✅ NUEVO
|
||||
|
||||
if (Is3DUpdateEnabled)
|
||||
{
|
||||
Visualization3DManager?.SynchronizeWorld();
|
||||
}
|
||||
RegisterObjectHandle(botella);
|
||||
return botella;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace CtrEditor.Simulacion
|
|||
{
|
||||
public class simBase
|
||||
{
|
||||
public object WpfObject { get; set; }
|
||||
public string SimObjectType { get; set; }
|
||||
public BodyHandle BodyHandle { get; protected set; }
|
||||
public Simulation _simulation;
|
||||
protected bool _bodyCreated = false; // Bandera para saber si hemos creado un cuerpo
|
||||
|
|
|
@ -113,9 +113,16 @@ namespace CtrEditor.Simulacion
|
|||
_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);
|
||||
var cylinder = new Cylinder(Radius, Height);
|
||||
var inertia = cylinder.ComputeInertia(_mass);
|
||||
|
||||
// Modificamos el tensor de inercia para evitar que la botella vuelque.
|
||||
var inverseInertia = inertia.InverseInertiaTensor;
|
||||
inverseInertia.XX = 0f; // Resistencia infinita a la rotación en el eje X (vuelco).
|
||||
inverseInertia.YY = 0f; // Resistencia infinita a la rotación en el eje Y (vuelco).
|
||||
// La resistencia en ZZ (eje Z) se mantiene, permitiendo que la botella gire sobre su base.
|
||||
inertia.InverseInertiaTensor = inverseInertia;
|
||||
|
||||
_simulation.Bodies.SetLocalInertia(BodyHandle, inertia);
|
||||
}
|
||||
}
|
||||
|
@ -125,27 +132,30 @@ namespace CtrEditor.Simulacion
|
|||
{
|
||||
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 cylinder = new Cylinder(Radius, Height);
|
||||
var shapeIndex = _simulation.Shapes.Add(cylinder);
|
||||
|
||||
// 1. Creamos el cuerpo con una inercia por defecto.
|
||||
var defaultInertia = cylinder.ComputeInertia(_mass);
|
||||
var activityDescription = new BodyActivityDescription(-1f);
|
||||
var bodyDescription = BodyDescription.CreateDynamic(
|
||||
new RigidPose(position),
|
||||
new BodyVelocity(),
|
||||
inertia, // Inercia estándar de esfera
|
||||
new CollidableDescription(shapeIndex, 0.001f),
|
||||
defaultInertia,
|
||||
new CollidableDescription(shapeIndex, 0),
|
||||
activityDescription
|
||||
);
|
||||
|
||||
BodyHandle = _simulation.Bodies.Add(bodyDescription);
|
||||
_bodyCreated = true; // Marcar que hemos creado un cuerpo
|
||||
_bodyCreated = true;
|
||||
|
||||
// 2. Inmediatamente después de crearlo, aplicamos la inercia personalizada.
|
||||
// Esto asegura que SetLocalInertia se llame para todos los objetos nuevos.
|
||||
var inertia = cylinder.ComputeInertia(_mass);
|
||||
var inverseInertia = inertia.InverseInertiaTensor;
|
||||
inverseInertia.XX = 0f;
|
||||
inverseInertia.YY = 0f;
|
||||
inertia.InverseInertiaTensor = inverseInertia;
|
||||
_simulation.Bodies.SetLocalInertia(BodyHandle, inertia);
|
||||
|
||||
// ✅ 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.
|
||||
|
@ -165,8 +175,8 @@ namespace CtrEditor.Simulacion
|
|||
// ✅ 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);
|
||||
var cylinder = new Cylinder(Radius, Height);
|
||||
var shapeIndex = _simulation.Shapes.Add(cylinder);
|
||||
ChangeBodyShape(shapeIndex);
|
||||
}
|
||||
}
|
||||
|
@ -178,8 +188,8 @@ namespace CtrEditor.Simulacion
|
|||
// ✅ 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);
|
||||
var cylinder = new Cylinder(Radius, Height);
|
||||
var shapeIndex = _simulation.Shapes.Add(cylinder);
|
||||
ChangeBodyShape(shapeIndex);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue