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>
<ItemGroup> <ItemGroup>
<Compile Remove="Documentation\BEPU Forces.cs" />
<Compile Remove="Documentation\PlantillaEstandarizacion.cs" /> <Compile Remove="Documentation\PlantillaEstandarizacion.cs" />
<Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" /> <Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" />
</ItemGroup> </ItemGroup>
@ -84,6 +85,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Documentation\BEPU Forces.cs" />
<None Include="Documentation\PlantillaEstandarizacion.cs" /> <None Include="Documentation\PlantillaEstandarizacion.cs" />
</ItemGroup> </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) partial void OnDiametroChanged(float value)
{ {
SimGeometria?.SetDiameter(Diametro); ActualizarGeometrias();
} }
public Vector2 GetCentro() public Vector2 GetCentro()
@ -73,8 +73,15 @@ namespace CtrEditor.ObjetosSim
{ {
if (SimGeometria != null) if (SimGeometria != null)
{ {
SimGeometria.SetDiameter(Diametro); // ✅ SISTEMA INTELIGENTE: Solo recrear si el diámetro cambió
SimGeometria.SetPosition(GetCentro()); if (HasDiscardDimensionsChanged(SimGeometria, Diametro))
{
System.Diagnostics.Debug.WriteLine($"[osDescarte] Recreando descarte por cambio de diámetro");
SimGeometria.SetDiameter(Diametro);
}
// ✅ USAR MÉTODO COORDINATECONVERTER
SimGeometria.UpdateFromWpfCenter(GetCentro());
} }
} }

View File

@ -37,16 +37,30 @@ namespace CtrEditor.ObjetosSim
[property: Name("Grosor de la Guía")] [property: Name("Grosor de la Guía")]
public float altoGuia; public float altoGuia;
private void ActualizarGeometrias() private void ActualizarGeometrias()
{ {
if (_visualRepresentation is ucGuia uc) if (_visualRepresentation is ucGuia uc && SimGeometria != null)
{ {
// Actualizar las propiedades del objeto de simulación var topLeft = new Vector2(Left, Top);
if (SimGeometria != null)
// ✅ 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> /// <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> /// </summary>
private void ActualizarPosicionBEPU() private void ActualizarPosicionBEPU()
{ {
if (Simulation_TransporteCurvaGuias != null) 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); 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 // Recrear las guías en la nueva posición
ActualizarGuiasCurvas(); ActualizarGuiasCurvas();
@ -286,7 +286,12 @@ namespace CtrEditor.ObjetosSim
{ {
if (_visualRepresentation is ucTransporteCurvaGuias uc) 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(); ActualizarGuiasCurvas();
SetSpeed(); SetSpeed();
} }
@ -327,7 +332,7 @@ namespace CtrEditor.ObjetosSim
if (radioGuiaInferior < 0.01f) if (radioGuiaInferior < 0.01f)
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 anguloInicioRad = simBase.GradosARadianes(Angulo);
float anguloFinalRad = simBase.GradosARadianes(AnguloFinal); float anguloFinalRad = simBase.GradosARadianes(AnguloFinal);
float rangoAngular = anguloFinalRad - anguloInicioRad; float rangoAngular = anguloFinalRad - anguloInicioRad;
@ -390,7 +395,7 @@ namespace CtrEditor.ObjetosSim
} }
/// <summary> /// <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 /// Convierte dos puntos Vector2 a los parámetros requeridos por AddLine
/// </summary> /// </summary>
private simGuia CrearGuiaDesdeDosPuntos(Vector2 punto1, Vector2 punto2) private simGuia CrearGuiaDesdeDosPuntos(Vector2 punto1, Vector2 punto2)
@ -404,10 +409,10 @@ namespace CtrEditor.ObjetosSim
if (longitud < 0.001f) // Evitar líneas de longitud cero if (longitud < 0.001f) // Evitar líneas de longitud cero
return null; 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; 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); return simulationManager.AddLine(longitud, GrosorGuias, punto1, angulo);
} }
catch (Exception ex) catch (Exception ex)
@ -532,7 +537,7 @@ namespace CtrEditor.ObjetosSim
if (_visualRepresentation is ucTransporteCurvaGuias uc) 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); var topLeft = new Vector2(Left, Top);
Simulation_TransporteCurvaGuias = simulationManager?.AddCurve(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados, topLeft, 0); Simulation_TransporteCurvaGuias = simulationManager?.AddCurve(RadioInterno, RadioExterno, Angulo, Angulo + Arco_en_grados, topLeft, 0);
CrearGuiasCurvas(); // Crear las guías curvas CrearGuiasCurvas(); // Crear las guías curvas

View File

@ -1747,7 +1747,7 @@ namespace CtrEditor.ObjetosSim
/// <summary> /// <summary>
/// Verifica si las dimensiones de un transporte han cambiado /// Verifica si las dimensiones de un transporte han cambiado
/// </summary> /// </summary>
private bool HasTransportDimensionsChanged(simTransporte transport, float newWidth, float newHeight) protected bool HasTransportDimensionsChanged(simTransporte transport, float newWidth, float newHeight)
{ {
if (transport == null) return true; if (transport == null) return true;
@ -1780,7 +1780,7 @@ namespace CtrEditor.ObjetosSim
/// <summary> /// <summary>
/// Verifica si las dimensiones de una barrera han cambiado /// Verifica si las dimensiones de una barrera han cambiado
/// </summary> /// </summary>
private bool HasBarrierDimensionsChanged(simBarrera barrier, float newWidth, float newHeight) protected bool HasBarrierDimensionsChanged(simBarrera barrier, float newWidth, float newHeight)
{ {
if (barrier == null) return true; if (barrier == null) return true;
@ -1813,7 +1813,7 @@ namespace CtrEditor.ObjetosSim
/// <summary> /// <summary>
/// Verifica si las dimensiones de una guía han cambiado /// Verifica si las dimensiones de una guía han cambiado
/// </summary> /// </summary>
private bool HasGuideDimensionsChanged(simGuia guide, float newWidth, float newHeight) protected bool HasGuideDimensionsChanged(simGuia guide, float newWidth, float newHeight)
{ {
if (guide == null) return true; 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> /// <summary>
/// Limpia las dimensiones almacenadas para un objeto específico /// Limpia las dimensiones almacenadas para un objeto específico
/// </summary> /// </summary>

View File

@ -231,8 +231,8 @@ namespace CtrEditor.Simulacion
public Simulation _simulation; public Simulation _simulation;
protected bool _bodyCreated = false; // Bandera para saber si hemos creado un cuerpo protected bool _bodyCreated = false; // Bandera para saber si hemos creado un cuerpo
// ✅ NUEVA CONSTANTE - unificar conversión de velocidad // ✅ CORREGIDO: Restaurar factor de conversión correcto
public const float SPEED_CONVERSION_FACTOR = 1f; //18.5f; // Factor de conversión de velocidad interna a m/s 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 // Constantes para las posiciones Z de los objetos 3D
public const float zPos_Transporte = 0f; // Z de la parte baja 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) public new void SetPosition(float x, float y, float z = 0)
{ {
base.SetPosition(x, y, z); base.SetPosition(x, y, z);
@ -398,7 +412,7 @@ namespace CtrEditor.Simulacion
/// <summary> /// <summary>
/// ✅ NUEVO: Actualiza posición desde Top-Left WPF con dimensiones y ángulo actuales /// ✅ NUEVO: Actualiza posición desde Top-Left WPF con dimensiones y ángulo actuales
/// </summary> /// </summary>
public void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft) internal void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft)
{ {
var currentWpfAngle = GetRotationZ(); // Ya usa CoordinateConverter var currentWpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
var zPosition = GetPosition().Z; // Mantener Z actual var zPosition = GetPosition().Z; // Mantener Z actual
@ -409,7 +423,7 @@ namespace CtrEditor.Simulacion
/// <summary> /// <summary>
/// ✅ NUEVO: Obtiene Top-Left WPF desde la posición actual /// ✅ NUEVO: Obtiene Top-Left WPF desde la posición actual
/// </summary> /// </summary>
public Vector2 GetWpfTopLeft() internal Vector2 GetWpfTopLeft()
{ {
var bepuCenter = GetPosition(); var bepuCenter = GetPosition();
var wpfAngle = GetRotationZ(); // Ya usa CoordinateConverter var wpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
@ -419,22 +433,53 @@ namespace CtrEditor.Simulacion
/// <summary> /// <summary>
/// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF /// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF
/// </summary> /// </summary>
public void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle) internal void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle)
{ {
var zPosition = GetPosition().Z; // Mantener Z actual var zPosition = GetPosition().Z; // Mantener Z actual
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, Width, Height, wpfAngle, zPosition); var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, Width, Height, wpfAngle, zPosition);
CoordinateConverter.UpdateBepuBodyPose(_simulation, BodyHandle, bepuCenter, wpfAngle); 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(); UpdateCachedProperties();
// ✅ CRÍTICO: Disparar evento para actualizar motores activos con nueva dirección
OnSpeedChanged?.Invoke(this);
} }
// ✅ NUEVO MÉTODO - actualizar propiedades cacheadas // ✅ NUEVO MÉTODO - actualizar propiedades cacheadas
public void UpdateCachedProperties() internal void UpdateCachedProperties()
{ {
// Calcular dirección basada en rotación actual // ✅ CORREGIDO: La dirección siempre es UnitX rotado por el ángulo del transporte
var angle = GetRotationZ(); // NO depende de las dimensiones (Width >= Height) sino solo de la rotación
DirectionVector = new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0); 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; SpeedMetersPerSecond = Speed / SPEED_CONVERSION_FACTOR;
} }
@ -485,6 +530,12 @@ namespace CtrEditor.Simulacion
var shapeIndex = _simulation.Shapes.Add(box); var shapeIndex = _simulation.Shapes.Add(box);
ChangeBodyShape(shapeIndex); 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) public void Create(float width, float height, Vector2 wpfTopLeft, float wpfAngle = 0)
@ -549,6 +600,9 @@ namespace CtrEditor.Simulacion
BodyHandle = _simulation.Bodies.Add(bodyDescription); BodyHandle = _simulation.Bodies.Add(bodyDescription);
_bodyCreated = true; // Marcar que hemos creado un cuerpo _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> /// <summary>
/// ✅ NUEVO: Actualiza posición desde Top-Left WPF con dimensiones y ángulo actuales /// ✅ NUEVO: Actualiza posición desde Top-Left WPF con dimensiones y ángulo actuales
/// </summary> /// </summary>
public void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft) internal void SetPositionFromWpfTopLeft(Vector2 wpfTopLeft)
{ {
var currentWpfAngle = GetRotationZ(); // Ya usa CoordinateConverter var currentWpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
var zPosition = GetPosition().Z; // Mantener Z actual var zPosition = GetPosition().Z; // Mantener Z actual
@ -609,7 +663,7 @@ namespace CtrEditor.Simulacion
/// <summary> /// <summary>
/// ✅ NUEVO: Obtiene Top-Left WPF desde la posición actual /// ✅ NUEVO: Obtiene Top-Left WPF desde la posición actual
/// </summary> /// </summary>
public Vector2 GetWpfTopLeft() internal Vector2 GetWpfTopLeft()
{ {
var bepuCenter = GetPosition(); var bepuCenter = GetPosition();
var wpfAngle = GetRotationZ(); // Ya usa CoordinateConverter var wpfAngle = GetRotationZ(); // Ya usa CoordinateConverter
@ -619,7 +673,7 @@ namespace CtrEditor.Simulacion
/// <summary> /// <summary>
/// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF /// ✅ NUEVO: Actualiza tanto posición como rotación desde parámetros WPF
/// </summary> /// </summary>
public void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle) internal void UpdateFromWpfParameters(Vector2 wpfTopLeft, float wpfAngle)
{ {
var zPosition = GetPosition().Z; // Mantener Z actual var zPosition = GetPosition().Z; // Mantener Z actual
var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, Width, Height, wpfAngle, zPosition); var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, Width, Height, wpfAngle, zPosition);
@ -735,20 +789,39 @@ namespace CtrEditor.Simulacion
} }
/// <summary> /// <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> /// </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; var zPosition = zAltura_Guia / 2 + zPos_Guia;
// Usar las dimensiones actuales de la guía var bepuCenter = CoordinateConverter.CalculateBepuCenterFromWpfTopLeft(wpfTopLeft, actualWidth, actualHeight, wpfAngle, zPosition);
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);
// Actualizar posición y rotación simultáneamente // Actualizar posición y rotación simultáneamente
CoordinateConverter.UpdateBepuBodyPose(_simulation, BodyHandle, bepuCenter, wpfAngle); 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 public class simBotella : simBase
@ -785,9 +858,8 @@ namespace CtrEditor.Simulacion
_neckRadius = neckRadius; _neckRadius = neckRadius;
ListOnTransports = new List<simBase>(); ListOnTransports = new List<simBase>();
// Convertir Vector2 a Vector3 con Z=0.2 (altura estándar para botellas) // ✅ USAR COORDINATECONVERTER para conversión centralizada
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba) var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), Radius + zPos_Transporte + zAltura_Transporte);
var position3D = new Vector3(position.X, -position.Y, Radius + zPos_Transporte + zAltura_Transporte);
Create(position3D); Create(position3D);
} }
@ -808,14 +880,14 @@ namespace CtrEditor.Simulacion
{ {
get get
{ {
// Invertir Y de vuelta para convertir de 3D (Y hacia arriba) a WPF (Y hacia abajo) // ✅ USAR COORDINATECONVERTER para conversión centralizada
return -GetPosition().Y; return CoordinateConverter.BepuYToWpfY(GetPosition().Y);
} }
set set
{ {
var pos = GetPosition(); var pos = GetPosition();
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba) // ✅ USAR COORDINATECONVERTER para conversión centralizada
SetPosition(pos.X, -value, pos.Z); SetPosition(pos.X, CoordinateConverter.WpfYToBepuY(value), pos.Z);
} }
} }
@ -824,15 +896,15 @@ namespace CtrEditor.Simulacion
get get
{ {
var pos3D = GetPosition(); var pos3D = GetPosition();
// Invertir Y de vuelta para convertir de 3D (Y hacia arriba) a WPF (Y hacia abajo) // ✅ USAR COORDINATECONVERTER para conversión centralizada
return new Vector2(pos3D.X, -pos3D.Y); return CoordinateConverter.BepuVector3ToWpfVector2(pos3D);
} }
set set
{ {
// Mantener la Z actual, solo cambiar X, Y // Mantener la Z actual, solo cambiar X, Y
var currentPos = GetPosition(); var currentPos = GetPosition();
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba) // ✅ USAR COORDINATECONVERTER para conversión centralizada
SetPosition(value.X, -value.Y, currentPos.Z); SetPosition(value.X, CoordinateConverter.WpfYToBepuY(value.Y), currentPos.Z);
} }
} }
@ -1022,8 +1094,8 @@ namespace CtrEditor.Simulacion
public float InnerRadius => _innerRadius; public float InnerRadius => _innerRadius;
public float OuterRadius => _outerRadius; public float OuterRadius => _outerRadius;
public float StartAngle => _startAngle; public float StartAngle => RadianesAGrados(_startAngle); // Convertir de radianes BEPU internos a grados WPF
public float EndAngle => _endAngle; public float EndAngle => RadianesAGrados(_endAngle); // Convertir de radianes BEPU internos a grados WPF
/// <summary> /// <summary>
/// ✅ NUEVO: Expone los triángulos originales para visualización debug /// ✅ NUEVO: Expone los triángulos originales para visualización debug
@ -1037,9 +1109,9 @@ namespace CtrEditor.Simulacion
_simulationManager = simulationManager; // ✅ NUEVA REFERENCIA _simulationManager = simulationManager; // ✅ NUEVA REFERENCIA
_innerRadius = innerRadius; _innerRadius = innerRadius;
_outerRadius = outerRadius; _outerRadius = outerRadius;
// ✅ SENTIDO HORARIO: Convertir ángulos para que vayan en sentido horario // ✅ CORREGIDO: Usar conversión WPF a BEPU y luego a radianes para consistencia
_startAngle = GradosARadianes(startAngle); _startAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(startAngle));
_endAngle = GradosARadianes(endAngle); _endAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(endAngle));
_triangleBodyHandles = new List<BodyHandle>(); _triangleBodyHandles = new List<BodyHandle>();
_originalTriangles = new List<List<Vector3>>(); // ✅ NUEVO: Inicializar lista de triángulos _originalTriangles = new List<List<Vector3>>(); // ✅ NUEVO: Inicializar lista de triángulos
@ -1059,14 +1131,57 @@ namespace CtrEditor.Simulacion
{ {
_innerRadius = innerRadius; _innerRadius = innerRadius;
_outerRadius = outerRadius; _outerRadius = outerRadius;
_startAngle = GradosARadianes(startAngle); // ✅ CORREGIDO: Usar conversión WPF a BEPU consistente
_endAngle = GradosARadianes(endAngle); _startAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(startAngle));
_endAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(endAngle));
// Recrear la curva con nuevos parámetros manteniendo posición actual // Recrear la curva con nuevos parámetros manteniendo posición actual
var currentPosition = GetPosition(); var currentPosition = GetPosition();
Create(currentPosition); 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() public new void RemoverBody()
{ {
// ✅ CRÍTICO: Limpiar todos los motors conectados a esta curva ANTES de eliminar los bodies // ✅ 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 // Actualizar parámetros internos
_innerRadius = innerRadius; _innerRadius = innerRadius;
_outerRadius = outerRadius; _outerRadius = outerRadius;
_startAngle = GradosARadianes(startAngle); // ✅ CORREGIDO: Usar conversión WPF a BEPU consistente
_endAngle = GradosARadianes(endAngle); _startAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(startAngle));
_endAngle = GradosARadianes(CoordinateConverter.WpfAngleToBepuAngle(endAngle));
// ✅ USAR COORDINATECONVERTER para conversión centralizada // ✅ USAR COORDINATECONVERTER para conversión centralizada
// Para curvas, el "tamaño" es el diámetro del radio exterior // Para curvas, el "tamaño" es el diámetro del radio exterior
@ -1343,9 +1459,8 @@ namespace CtrEditor.Simulacion
_radius = diameter / 2f; _radius = diameter / 2f;
ListSimBotellaContact = new List<simBotella>(); ListSimBotellaContact = new List<simBotella>();
// Convertir Vector2 a Vector3 con Z=0.3 (altura para detectar botellas) // ✅ USAR COORDINATECONVERTER para conversión centralizada
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba) var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), zPos_Descarte + _radius);
var position3D = new Vector3(position.X, -position.Y, zPos_Descarte + _radius);
Create(position3D); Create(position3D);
} }
@ -1373,12 +1488,22 @@ namespace CtrEditor.Simulacion
public void Create(Vector2 position) public void Create(Vector2 position)
{ {
// Convertir Vector2 a Vector3 con Z=0.3 (altura para detectar botellas) // ✅ USAR COORDINATECONVERTER para conversión centralizada
// Invertir Y para convertir de WPF (Y hacia abajo) a 3D (Y hacia arriba) var position3D = new Vector3(position.X, CoordinateConverter.WpfYToBepuY(position.Y), zPos_Descarte + _radius);
var position3D = new Vector3(position.X, -position.Y, zPos_Descarte + _radius);
Create(position3D); 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) private void Create(Vector3 position)
{ {
RemoverBody(); RemoverBody();
@ -1674,16 +1799,25 @@ namespace CtrEditor.Simulacion
if (transport.DirectionVector.Length() < 0.001f) if (transport.DirectionVector.Length() < 0.001f)
return; 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() var motor = new LinearAxisMotor()
{ {
LocalOffsetA = Vector3.Zero, LocalOffsetA = Vector3.Zero,
LocalOffsetB = Vector3.Zero, LocalOffsetB = Vector3.Zero,
LocalAxis = transport.DirectionVector, LocalAxis = localAxis, // ✅ Usar eje local, no mundial
TargetVelocity = transport.SpeedMetersPerSecond, TargetVelocity = transport.SpeedMetersPerSecond,
Settings = new MotorSettings(Math.Max(bottle.Mass * 30f, 10f), 5f) 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( var motorHandle = _simulationManager.simulation.Solver.Add(
transport.BodyHandle, transport.BodyHandle,
bottle.BodyHandle, bottle.BodyHandle,