Se eliminaron archivos de documentación innecesarios en el proyecto y se realizaron ajustes en la visibilidad de métodos en la clase osBase, cambiando de privado a protegido. Se implementó un nuevo método para verificar las dimensiones de los descartes y se mejoró la lógica de actualización de geometrías en ucDescarte y ucGuia, utilizando un sistema inteligente para optimizar el rendimiento. Además, se corrigieron errores en la conversión de coordenadas y se restauró el factor de conversión de velocidad en BEPU.

This commit is contained in:
Miguel 2025-07-02 17:19:31 +02:00
parent fd215bc677
commit e38adc9f56
7 changed files with 2881 additions and 68 deletions

View File

@ -35,6 +35,7 @@
</ItemGroup>
<ItemGroup>
<Compile Remove="Documentation\BEPU Forces.cs" />
<Compile Remove="Documentation\PlantillaEstandarizacion.cs" />
<Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" />
</ItemGroup>
@ -84,6 +85,7 @@
</ItemGroup>
<ItemGroup>
<None Include="Documentation\BEPU Forces.cs" />
<None Include="Documentation\PlantillaEstandarizacion.cs" />
</ItemGroup>

2616
Documentation/BEPU Forces.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -41,7 +41,7 @@ namespace CtrEditor.ObjetosSim
partial void OnDiametroChanged(float value)
{
SimGeometria?.SetDiameter(Diametro);
ActualizarGeometrias();
}
public Vector2 GetCentro()
@ -73,8 +73,15 @@ namespace CtrEditor.ObjetosSim
{
if (SimGeometria != null)
{
// ✅ SISTEMA INTELIGENTE: Solo recrear si el diámetro cambió
if (HasDiscardDimensionsChanged(SimGeometria, Diametro))
{
System.Diagnostics.Debug.WriteLine($"[osDescarte] Recreando descarte por cambio de diámetro");
SimGeometria.SetDiameter(Diametro);
SimGeometria.SetPosition(GetCentro());
}
// ✅ USAR MÉTODO COORDINATECONVERTER
SimGeometria.UpdateFromWpfCenter(GetCentro());
}
}

View File

@ -37,16 +37,30 @@ namespace CtrEditor.ObjetosSim
[property: Name("Grosor de la Guía")]
public float altoGuia;
private void ActualizarGeometrias()
{
if (_visualRepresentation is ucGuia uc)
if (_visualRepresentation is ucGuia uc && SimGeometria != null)
{
// Actualizar las propiedades del objeto de simulación
if (SimGeometria != null)
var topLeft = new Vector2(Left, Top);
// ✅ SISTEMA INTELIGENTE: Solo recrear si las dimensiones han cambiado
if (HasGuideDimensionsChanged(SimGeometria, Ancho, AltoGuia))
{
SimGeometria.UpdateProperties(Ancho, AltoGuia, Angulo);
System.Diagnostics.Debug.WriteLine($"[osGuia] Recreando guía por cambio de dimensiones: {Ancho}x{AltoGuia}");
// ✅ RECREAR COMPLETAMENTE: Las dimensiones cambiaron
SimGeometria.Create(Ancho, AltoGuia, topLeft, Angulo);
SimGeometria.SetDimensions(Ancho, AltoGuia);
}
else
{
System.Diagnostics.Debug.WriteLine($"[osGuia] Solo actualizando posición/rotación: Left={Left}, Top={Top}, Angulo={Angulo}");
// ✅ SOLO ACTUALIZAR POSICIÓN/ROTACIÓN: Usar dimensiones reales para conversión correcta
SimGeometria.UpdateFromWpfParameters(topLeft, Angulo, Ancho, AltoGuia);
}
UpdateOrCreateLine(SimGeometria, uc.Guia);
}
}

View File

@ -258,15 +258,15 @@ namespace CtrEditor.ObjetosSim
}
/// <summary>
/// ✅ NUEVO: Actualizar posición en BEPU cuando cambia la posición del objeto
/// ✅ CORREGIDO: Actualizar posición en BEPU usando métodos de conversión apropiados
/// </summary>
private void ActualizarPosicionBEPU()
{
if (Simulation_TransporteCurvaGuias != null)
{
// Recrear la curva con nueva posición usando el mismo patrón que ucTransporteCurva
// ✅ USAR MÉTODOS DE COORDINATECONVERTER
var topLeft = new Vector2(Left, Top);
Simulation_TransporteCurvaGuias.Create(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados, topLeft, 0);
Simulation_TransporteCurvaGuias.UpdateFromWpfParameters(topLeft, 0f, RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados);
// Recrear las guías en la nueva posición
ActualizarGuiasCurvas();
@ -286,7 +286,12 @@ namespace CtrEditor.ObjetosSim
{
if (_visualRepresentation is ucTransporteCurvaGuias uc)
{
Simulation_TransporteCurvaGuias?.UpdateCurve(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados);
// ✅ USAR MÉTODO DE COORDINATECONVERTER PARA ACTUALIZACIÓN COMPLETA
if (Simulation_TransporteCurvaGuias != null)
{
var topLeft = new Vector2(Left, Top);
Simulation_TransporteCurvaGuias.UpdateFromWpfParameters(topLeft, 0f, RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados);
}
ActualizarGuiasCurvas();
SetSpeed();
}
@ -327,7 +332,7 @@ namespace CtrEditor.ObjetosSim
if (radioGuiaInferior < 0.01f)
radioGuiaInferior = 0.01f;
// Convertir ángulos a radianes
// ✅ CORREGIDO: Convertir ángulos a radianes usando método estándar
float anguloInicioRad = simBase.GradosARadianes(Angulo);
float anguloFinalRad = simBase.GradosARadianes(AnguloFinal);
float rangoAngular = anguloFinalRad - anguloInicioRad;
@ -390,7 +395,7 @@ namespace CtrEditor.ObjetosSim
}
/// <summary>
/// Método helper para crear una guía desde dos puntos
/// ✅ CORREGIDO: Método helper para crear una guía desde dos puntos usando conversiones apropiadas
/// Convierte dos puntos Vector2 a los parámetros requeridos por AddLine
/// </summary>
private simGuia CrearGuiaDesdeDosPuntos(Vector2 punto1, Vector2 punto2)
@ -404,10 +409,10 @@ namespace CtrEditor.ObjetosSim
if (longitud < 0.001f) // Evitar líneas de longitud cero
return null;
// Calcular el ángulo de la línea
// ✅ CORREGIDO: Calcular el ángulo de la línea correctamente para WPF
float angulo = (float)Math.Atan2(direccion.Y, direccion.X) * 180f / (float)Math.PI;
// Usar punto1 como topLeft y la longitud como width
// ✅ USAR punto1 como topLeft - simulationManager.AddLine ya maneja las conversiones WPF->BEPU
return simulationManager.AddLine(longitud, GrosorGuias, punto1, angulo);
}
catch (Exception ex)
@ -532,7 +537,7 @@ namespace CtrEditor.ObjetosSim
if (_visualRepresentation is ucTransporteCurvaGuias uc)
{
// ✅ CORRIGIDO: Usar simulationManager?.AddCurve con todos los parámetros requeridos
// ✅ CORREGIDO: Usar simulationManager?.AddCurve con conversión WPF correcta
var topLeft = new Vector2(Left, Top);
Simulation_TransporteCurvaGuias = simulationManager?.AddCurve(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados, topLeft, 0);
CrearGuiasCurvas(); // Crear las guías curvas

View File

@ -1747,7 +1747,7 @@ namespace CtrEditor.ObjetosSim
/// <summary>
/// Verifica si las dimensiones de un transporte han cambiado
/// </summary>
private bool HasTransportDimensionsChanged(simTransporte transport, float newWidth, float newHeight)
protected bool HasTransportDimensionsChanged(simTransporte transport, float newWidth, float newHeight)
{
if (transport == null) return true;
@ -1780,7 +1780,7 @@ namespace CtrEditor.ObjetosSim
/// <summary>
/// Verifica si las dimensiones de una barrera han cambiado
/// </summary>
private bool HasBarrierDimensionsChanged(simBarrera barrier, float newWidth, float newHeight)
protected bool HasBarrierDimensionsChanged(simBarrera barrier, float newWidth, float newHeight)
{
if (barrier == null) return true;
@ -1813,7 +1813,7 @@ namespace CtrEditor.ObjetosSim
/// <summary>
/// Verifica si las dimensiones de una guía han cambiado
/// </summary>
private bool HasGuideDimensionsChanged(simGuia guide, float newWidth, float newHeight)
protected bool HasGuideDimensionsChanged(simGuia guide, float newWidth, float newHeight)
{
if (guide == null) return true;
@ -1843,6 +1843,41 @@ namespace CtrEditor.ObjetosSim
}
}
/// <summary>
/// ✅ NUEVO - Sistema inteligente de verificación de dimensiones de descartes
/// Verifica si el diámetro de un descarte ha cambiado
/// </summary>
protected bool HasDiscardDimensionsChanged(simDescarte discard, float newDiameter)
{
if (discard == null) return true;
var newDimensions = new SimObjectDimensions
{
Width = newDiameter,
Height = newDiameter,
Radius = newDiameter / 2f,
ObjectType = 4 // Tipo 4 = Descarte
};
if (_lastKnownDimensions.TryGetValue(discard, out var lastDimensions))
{
bool changed = !newDimensions.Equals(lastDimensions);
if (changed)
{
_lastKnownDimensions[discard] = newDimensions;
System.Diagnostics.Debug.WriteLine($"[Dimensions] Discard dimensions CHANGED: Ø{newDiameter}");
}
return changed;
}
else
{
// Primera vez - consideramos como cambio
_lastKnownDimensions[discard] = newDimensions;
System.Diagnostics.Debug.WriteLine($"[Dimensions] Discard first time: Ø{newDiameter}");
return true;
}
}
/// <summary>
/// Limpia las dimensiones almacenadas para un objeto específico
/// </summary>

View File

@ -231,8 +231,8 @@ namespace CtrEditor.Simulacion
public Simulation _simulation;
protected bool _bodyCreated = false; // Bandera para saber si hemos creado un cuerpo
// ✅ NUEVA CONSTANTE - unificar conversión de velocidad
public const float SPEED_CONVERSION_FACTOR = 1f; //18.5f; // Factor de conversión de velocidad interna a m/s
// ✅ CORREGIDO: Restaurar factor de conversión correcto
public const float SPEED_CONVERSION_FACTOR = 1/2f; // Factor de conversión de velocidad interna a m/s - Para LinearAxisMotor es 0.5f
// Constantes para las posiciones Z de los objetos 3D
public const float zPos_Transporte = 0f; // Z de la parte baja
@ -390,6 +390,20 @@ namespace CtrEditor.Simulacion
}
}
/// <summary>
/// ✅ SOBRESCRITO: SetRotation que actualiza automáticamente las propiedades cacheadas
/// </summary>
public new void SetRotation(float wpfAngle)
{
base.SetRotation(wpfAngle);
// ✅ CRÍTICO: Actualizar propiedades cacheadas después del cambio de rotación
UpdateCachedProperties();
// ✅ CRÍTICO: Disparar evento para actualizar motores activos con nueva dirección
OnSpeedChanged?.Invoke(this);
}
public new void SetPosition(float x, float y, float z = 0)
{
base.SetPosition(x, y, z);
@ -398,7 +412,7 @@ namespace CtrEditor.Simulacion
/// <summary>
/// ✅ NUEVO: Actualiza posición desde Top-Left WPF con dimensiones y ángulo actuales
/// </summary>
public void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft)
internal void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft)
{
var currentWpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
var zPosition = GetPosition().Z; // Mantener Z actual
@ -409,7 +423,7 @@ namespace CtrEditor.Simulacion
/// <summary>
/// ✅ NUEVO: Obtiene Top-Left WPF desde la posición actual
/// </summary>
public Vector2 GetWpfTopLeft()
internal Vector2 GetWpfTopLeft()
{
var bepuCenter = GetPosition();
var wpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
@ -419,22 +433,53 @@ namespace CtrEditor.Simulacion
/// <summary>
/// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF
/// </summary>
public void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle)
internal void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle)
{
var zPosition = GetPosition().Z; // Mantener Z actual
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, Width, Height, wpfAngle, zPosition);
CoordinateConverter.UpdateBepuBodyPose(_simulation, BodyHandle, bepuCenter, wpfAngle);
// Actualizar propiedades cacheadas después del cambio
// ✅ CRÍTICO: Actualizar propiedades cacheadas después del cambio de orientación
UpdateCachedProperties();
// ✅ CRÍTICO: Disparar evento para actualizar motores activos con nueva dirección
OnSpeedChanged?.Invoke(this);
}
// ✅ NUEVO MÉTODO - actualizar propiedades cacheadas
public void UpdateCachedProperties()
internal void UpdateCachedProperties()
{
// Calcular dirección basada en rotación actual
var angle = GetRotationZ();
DirectionVector = new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0);
// ✅ CORREGIDO: La dirección siempre es UnitX rotado por el ángulo del transporte
// NO depende de las dimensiones (Width >= Height) sino solo de la rotación
if (_simulation != null && _simulation.Bodies.BodyExists(BodyHandle))
{
var bodyReference = _simulation.Bodies.GetBodyReference(BodyHandle);
var bepuQuaternion = bodyReference.Pose.Orientation;
// ✅ SIEMPRE usar UnitX y aplicar la rotación
DirectionVector = Vector3.Transform(Vector3.UnitX, bepuQuaternion);
// 🔍 DEBUG: Agregar información detallada
var wpfAngle = GetRotationZ();
System.Diagnostics.Debug.WriteLine($"[UpdateCached] WPF Angle: {wpfAngle}°, DirectionVector: {DirectionVector}, Length: {DirectionVector.Length()}");
}
else
{
// ✅ CORREGIDO: Aplicar conversión de coordenadas WPF→BEPU en el vector
var wpfAngle = GetRotationZ(); // Ángulo WPF en grados
var wpfAngleRadians = GradosARadianes(wpfAngle);
// Calcular el vector en coordenadas WPF
var wpfX = (float)Math.Cos(wpfAngleRadians);
var wpfY = (float)Math.Sin(wpfAngleRadians);
// ✅ APLICAR CONVERSIÓN Y: En WPF Y+ es abajo, en BEPU Y+ es arriba
DirectionVector = new Vector3(wpfX, -wpfY, 0); // Invertir Y para conversión WPF→BEPU
// 🔍 DEBUG: Agregar información detallada
System.Diagnostics.Debug.WriteLine($"[UpdateCached-Fallback] WPF Angle: {wpfAngle}°, WPF Vector: ({wpfX:F3}, {wpfY:F3}), BEPU DirectionVector: {DirectionVector}, Length: {DirectionVector.Length()}");
}
SpeedMetersPerSecond = Speed / SPEED_CONVERSION_FACTOR;
}
@ -485,6 +530,12 @@ namespace CtrEditor.Simulacion
var shapeIndex = _simulation.Shapes.Add(box);
ChangeBodyShape(shapeIndex);
}
// ✅ CRÍTICO: Actualizar propiedades cacheadas después del cambio de dimensiones
UpdateCachedProperties();
// ✅ CRÍTICO: Disparar evento para actualizar motores activos con nueva dirección
OnSpeedChanged?.Invoke(this);
}
public void Create(float width, float height, Vector2 wpfTopLeft, float wpfAngle = 0)
@ -549,6 +600,9 @@ namespace CtrEditor.Simulacion
BodyHandle = _simulation.Bodies.Add(bodyDescription);
_bodyCreated = true; // Marcar que hemos creado un cuerpo
// ✅ CRÍTICO: Actualizar propiedades cacheadas después de crear el body
UpdateCachedProperties();
}
}
@ -598,7 +652,7 @@ namespace CtrEditor.Simulacion
/// <summary>
/// ✅ NUEVO: Actualiza posición desde Top-Left WPF con dimensiones y ángulo actuales
/// </summary>
public void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft)
internal void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft)
{
var currentWpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
var zPosition = GetPosition().Z; // Mantener Z actual
@ -609,7 +663,7 @@ namespace CtrEditor.Simulacion
/// <summary>
/// ✅ NUEVO: Obtiene Top-Left WPF desde la posición actual
/// </summary>
public Vector2 GetWpfTopLeft()
internal Vector2 GetWpfTopLeft()
{
var bepuCenter = GetPosition();
var wpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
@ -619,7 +673,7 @@ namespace CtrEditor.Simulacion
/// <summary>
/// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF
/// </summary>
public void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle)
internal void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle)
{
var zPosition = GetPosition().Z; // Mantener Z actual
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, Width, Height, wpfAngle, zPosition);
@ -735,20 +789,39 @@ namespace CtrEditor.Simulacion
}
/// <summary>
/// ✅ NUEVO - Actualiza solo la posición sin recrear el objeto usando CoordinateConverter
/// ✅ CORREGIDO - Actualiza solo la posición sin recrear el objeto usando CoordinateConverter
/// Requiere las dimensiones reales para conversión correcta Top-Left → Center
/// </summary>
public void SetPosition(Vector2 wpfTopLeft, float wpfAngle = 0)
public void SetPosition(Vector2 wpfTopLeft, float wpfAngle, float actualWidth, float actualHeight)
{
// ✅ USAR COORDINATECONVERTER para conversión centralizada
// ✅ USAR COORDINATECONVERTER para conversión centralizada con dimensiones reales
var zPosition = zAltura_Guia / 2 + zPos_Guia;
// Usar las dimensiones actuales de la guía
var width = GuideThickness; // Para guías, el ancho puede ser derivado del espesor
var height = GuideThickness;
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, width, height, wpfAngle, zPosition);
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, actualWidth, actualHeight, wpfAngle, zPosition);
// Actualizar posición y rotación simultáneamente
CoordinateConverter.UpdateBepuBodyPose(_simulation, BodyHandle, bepuCenter, wpfAngle);
}
/// <summary>
/// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF (sobrecarga para compatibilidad)
/// </summary>
internal void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle, float width, float height)
{
// Usar el método SetPosition con dimensiones correctas
SetPosition(wpfTopLeft, wpfAngle, width, height);
// Actualizar propiedades internas
GuideThickness = height;
}
/// <summary>
/// ✅ LEGACY - Mantener compatibilidad con versión anterior (usar dimensiones almacenadas)
/// </summary>
public void SetPosition(Vector2 wpfTopLeft, float wpfAngle = 0)
{
// Fallback: usar GuideThickness como aproximación si no se proporcionan dimensiones
SetPosition(wpfTopLeft, wpfAngle, GuideThickness * 10f, GuideThickness);
}
}
public class simBotella : simBase
@ -785,9 +858,8 @@ namespace CtrEditor.Simulacion
_neckRadius = neckRadius;
ListOnTransports = new List<simBase>();
// Convertir Vector2 a Vector3 con Z=0.2 (altura estándar para botellas)
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba)
var position3D = new Vector3(position.X, -position.Y, Radius + zPos_Transporte + zAltura_Transporte);
// ✅ USAR COORDINATECONVERTER para conversión centralizada
var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), Radius + zPos_Transporte + zAltura_Transporte);
Create(position3D);
}
@ -808,14 +880,14 @@ namespace CtrEditor.Simulacion
{
get
{
// Invertir Y de vuelta para convertir de 3D (Y hacia arriba) a WPF (Y hacia abajo)
return -GetPosition().Y;
// ✅ USAR COORDINATECONVERTER para conversión centralizada
return CoordinateConverter.BepuYToWpfY(GetPosition().Y);
}
set
{
var pos = GetPosition();
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba)
SetPosition(pos.X, -value, pos.Z);
// ✅ USAR COORDINATECONVERTER para conversión centralizada
SetPosition(pos.X, CoordinateConverter.WpfYToBepuY(value), pos.Z);
}
}
@ -824,15 +896,15 @@ namespace CtrEditor.Simulacion
get
{
var pos3D = GetPosition();
// Invertir Y de vuelta para convertir de 3D (Y hacia arriba) a WPF (Y hacia abajo)
return new Vector2(pos3D.X, -pos3D.Y);
// ✅ USAR COORDINATECONVERTER para conversión centralizada
return CoordinateConverter.BepuVector3ToWpfVector2(pos3D);
}
set
{
// Mantener la Z actual, solo cambiar X, Y
var currentPos = GetPosition();
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba)
SetPosition(value.X, -value.Y, currentPos.Z);
// ✅ USAR COORDINATECONVERTER para conversión centralizada
SetPosition(value.X, CoordinateConverter.WpfYToBepuY(value.Y), currentPos.Z);
}
}
@ -1022,8 +1094,8 @@ namespace CtrEditor.Simulacion
public float InnerRadius => _innerRadius;
public float OuterRadius => _outerRadius;
public float StartAngle => _startAngle;
public float EndAngle => _endAngle;
public float StartAngle => RadianesAGrados(_startAngle); // Convertir de radianes BEPU internos a grados WPF
public float EndAngle => RadianesAGrados(_endAngle); // Convertir de radianes BEPU internos a grados WPF
/// <summary>
/// ✅ NUEVO: Expone los triángulos originales para visualización debug
@ -1037,9 +1109,9 @@ namespace CtrEditor.Simulacion
_simulationManager = simulationManager; // ✅ NUEVA REFERENCIA
_innerRadius = innerRadius;
_outerRadius = outerRadius;
// ✅ SENTIDO HORARIO: Convertir ángulos para que vayan en sentido horario
_startAngle = GradosARadianes(startAngle);
_endAngle = GradosARadianes(endAngle);
// ✅ CORREGIDO: Usar conversión WPF a BEPU y luego a radianes para consistencia
_startAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(startAngle));
_endAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(endAngle));
_triangleBodyHandles = new List<BodyHandle>();
_originalTriangles = new List<List<Vector3>>(); // ✅ NUEVO: Inicializar lista de triángulos
@ -1059,14 +1131,57 @@ namespace CtrEditor.Simulacion
{
_innerRadius = innerRadius;
_outerRadius = outerRadius;
_startAngle = GradosARadianes(startAngle);
_endAngle = GradosARadianes(endAngle);
// ✅ CORREGIDO: Usar conversión WPF a BEPU consistente
_startAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(startAngle));
_endAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(endAngle));
// Recrear la curva con nuevos parámetros manteniendo posición actual
var currentPosition = GetPosition();
Create(currentPosition);
}
/// <summary>
/// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF
/// </summary>
internal void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle, float innerRadius, float outerRadius, float startAngle, float endAngle)
{
// Actualizar parámetros de la curva
_innerRadius = innerRadius;
_outerRadius = outerRadius;
// ✅ CORREGIDO: Usar conversión WPF a BEPU consistente
_startAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(startAngle));
_endAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(endAngle));
// ✅ USAR COORDINATECONVERTER para conversión centralizada
var curveSize = outerRadius * 2f;
var zPosition = zAltura_Curve / 2f + zPos_Curve;
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, curveSize, curveSize, 0f, zPosition);
Create(bepuCenter);
}
/// <summary>
/// ✅ NUEVO: Actualiza posición desde Top-Left WPF manteniendo parámetros actuales
/// </summary>
internal void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft)
{
var curveSize = _outerRadius * 2f;
var zPosition = GetPosition().Z; // Mantener Z actual
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, curveSize, curveSize, 0f, zPosition);
Create(bepuCenter);
}
/// <summary>
/// ✅ NUEVO: Obtiene Top-Left WPF desde la posición actual
/// </summary>
internal Vector2 GetWpfTopLeft()
{
var bepuCenter = GetPosition();
var curveSize = _outerRadius * 2f;
return CoordinateConverter.CalculateWpfTopLeftFromBepuCenter(bepuCenter, curveSize, curveSize, 0f);
}
public new void RemoverBody()
{
// ✅ CRÍTICO: Limpiar todos los motors conectados a esta curva ANTES de eliminar los bodies
@ -1135,8 +1250,9 @@ namespace CtrEditor.Simulacion
// Actualizar parámetros internos
_innerRadius = innerRadius;
_outerRadius = outerRadius;
_startAngle = GradosARadianes(startAngle);
_endAngle = GradosARadianes(endAngle);
// ✅ CORREGIDO: Usar conversión WPF a BEPU consistente
_startAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(startAngle));
_endAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(endAngle));
// ✅ USAR COORDINATECONVERTER para conversión centralizada
// Para curvas, el "tamaño" es el diámetro del radio exterior
@ -1343,9 +1459,8 @@ namespace CtrEditor.Simulacion
_radius = diameter / 2f;
ListSimBotellaContact = new List<simBotella>();
// Convertir Vector2 a Vector3 con Z=0.3 (altura para detectar botellas)
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba)
var position3D = new Vector3(position.X, -position.Y, zPos_Descarte + _radius);
// ✅ USAR COORDINATECONVERTER para conversión centralizada
var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), zPos_Descarte + _radius);
Create(position3D);
}
@ -1373,12 +1488,22 @@ namespace CtrEditor.Simulacion
public void Create(Vector2 position)
{
// Convertir Vector2 a Vector3 con Z=0.3 (altura para detectar botellas)
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba)
var position3D = new Vector3(position.X, -position.Y, zPos_Descarte + _radius);
// ✅ USAR COORDINATECONVERTER para conversión centralizada
var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), zPos_Descarte + _radius);
Create(position3D);
}
/// <summary>
/// ✅ NUEVO: Actualiza posición usando coordenadas WPF apropiadas
/// </summary>
internal void UpdateFromWpfCenter(Vector2 wpfCenter)
{
var position3D = new Vector3(wpfCenter.X, CoordinateConverter.WpfYToBepuY(wpfCenter.Y), zPos_Descarte + _radius);
// Actualizar solo posición manteniendo orientación
CoordinateConverter.UpdateBepuBodyPosition(_simulation, BodyHandle, position3D);
}
private void Create(Vector3 position)
{
RemoverBody();
@ -1674,16 +1799,25 @@ namespace CtrEditor.Simulacion
if (transport.DirectionVector.Length() < 0.001f)
return;
// ✅ SIMPLIFICAR - Usar LinearAxisMotor básico
// ✅ CORREGIDO - LocalAxis debe estar en coordenadas locales del transporte
// Para transportes, el eje local de movimiento es siempre UnitX (eje largo)
var localAxis = Vector3.UnitX; // Siempre UnitX en coordenadas locales del transporte
var motor = new LinearAxisMotor()
{
LocalOffsetA = Vector3.Zero,
LocalOffsetB = Vector3.Zero,
LocalAxis = transport.DirectionVector,
LocalAxis = localAxis, // ✅ Usar eje local, no mundial
TargetVelocity = transport.SpeedMetersPerSecond,
Settings = new MotorSettings(Math.Max(bottle.Mass * 30f, 10f), 5f)
};
// 🔍 DEBUG: Comparar eje local vs mundial
System.Diagnostics.Debug.WriteLine($"[Motor] Transport angle: {transport.GetRotationZ()}°");
System.Diagnostics.Debug.WriteLine($"[Motor] World DirectionVector: {transport.DirectionVector}");
System.Diagnostics.Debug.WriteLine($"[Motor] Local Axis: {localAxis}");
System.Diagnostics.Debug.WriteLine($"[Motor] Target Velocity: {transport.SpeedMetersPerSecond}");
var motorHandle = _simulationManager.simulation.Solver.Add(
transport.BodyHandle,
bottle.BodyHandle,