Se mejoró el sistema de guías curvas para incluir apertura en cono en los extremos, facilitando la entrada y salida de botellas. Se añadió un nuevo parámetro `AnguloAperturaGuias` para ajustar la apertura, optimizando el flujo de materiales. Además, se implementaron nuevas propiedades en `ucBottGenerator` para gestionar la distancia mínima sin botellas y se realizaron ajustes en la lógica de colisiones y visualización en 3D.

This commit is contained in:
Miguel 2025-07-06 00:07:36 +02:00
parent 83fc828a4c
commit d1ec7f4d12
6 changed files with 75 additions and 13 deletions

View File

@ -28,3 +28,5 @@ simTransporte : Es un box por donde las botellas pueden desplazarse usando un tr
* Se ha implementado un sistema de animaciones automáticas usando StoryBoard de WPF para los transportes en movimiento. Los transportes activos muestran una animación continua que combina: (1) rotación sutil muy lenta alrededor del eje Z (20 segundos por vuelta completa) y (2) pulsación cíclica del color del material (1.5 segundos por ciclo). Las animaciones se crean y destruyen automáticamente según el estado del transporte, sin necesidad de actualización manual en cada frame. El sistema gestiona las animaciones activas en un diccionario y las limpia correctamente cuando se eliminan objetos. Se resolvió el problema de `InvalidOperationException` al animar brushes inmutables creando una función `CreateAnimatableMaterial` que genera materiales específicamente diseñados para ser animados sin estar "frozen", proporcionando una experiencia visual fluida y eficiente.
* 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.

View File

@ -87,6 +87,7 @@ namespace CtrEditor.ObjetosSim
[property: Category("Información")]
[property: Name("Salida Filtro")]
bool filter_Output;
[ObservableProperty]
[property: Description("Cantidad de botellas generadas por hora")]
[property: Category("Configuración")]
@ -113,11 +114,32 @@ namespace CtrEditor.ObjetosSim
[property: Name("Velocidad Actual (%)")]
private float velocidad_actual_percentual;
[ObservableProperty]
[property: Description("Distancia libre minima sin botellas sobre el transporte para colocar otra botella")]
[property: Category("Simulación")]
[property: Name("Diametro libre minimo")]
private float distancia_libre;
[ObservableProperty]
[property: Description("Diámetro de las botellas generadas")]
[property: Category("Configuración")]
[property: Name("Diámetro Botella")]
private float diametro_botella;
public osBottGenerator()
{
Ancho = 0.40f;
Alto = 0.40f;
Angulo = 0;
Velocidad_actual_percentual = 100;
Diametro_botella = 0.1f;
Botellas_hora = 10000;
Consenso = true;
Distancia_libre = 0.1f;
}
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
{
if (Consenso_NC)
@ -128,7 +150,7 @@ namespace CtrEditor.ObjetosSim
private bool HayEspacioParaNuevaBotella(float X, float Y)
{
float radioMinimo = Diametro_botella / 4; // Distancia mínima entre centros
float radioMinimo = Distancia_libre; // Distancia mínima entre centros
float radioMinimoCuadrado = radioMinimo * radioMinimo;
// Buscar todas las botellas cercanas

View File

@ -48,7 +48,7 @@ namespace CtrEditor.ObjetosSim
// ✅ SISTEMA INTELIGENTE: Solo recrear si las dimensiones han cambiado
if (HasGuideDimensionsChanged(SimGeometria, Ancho, AltoGuia))
{
System.Diagnostics.Debug.WriteLine($"[osGuia] Recreando guía por cambio de dimensiones: {Ancho}x{AltoGuia}");
//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);
@ -56,7 +56,7 @@ namespace CtrEditor.ObjetosSim
}
else
{
System.Diagnostics.Debug.WriteLine($"[osGuia] Solo actualizando posición/rotación: Left={Left}, Top={Top}, Angulo={Angulo}");
// 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);

View File

@ -134,6 +134,17 @@ namespace CtrEditor.ObjetosSim
ActualizarGeometrias();
}
[ObservableProperty]
[property: Category("Configuración")]
[property: Description("Ángulo de apertura en grados para los extremos de las guías")]
[property: Name("Ángulo Apertura Guías")]
private float anguloAperturaGuias = 5f;
partial void OnAnguloAperturaGuiasChanged(float value)
{
ActualizarGeometrias();
}
[ObservableProperty]
[property: Category("Configuración")]
[property: Description("Distancia de separación de las guías desde el borde")]
@ -336,6 +347,7 @@ namespace CtrEditor.ObjetosSim
float anguloInicioRad = simBase.GradosARadianes(Angulo);
float anguloFinalRad = simBase.GradosARadianes(AnguloFinal);
float rangoAngular = anguloFinalRad - anguloInicioRad;
float anguloAperturaRad = simBase.GradosARadianes(AnguloAperturaGuias);
// Calcular el paso angular entre segmentos
float pasoAngular = rangoAngular / NumeroSegmentosGuias;
@ -349,14 +361,27 @@ namespace CtrEditor.ObjetosSim
float angulo1 = anguloInicioRad + i * pasoAngular;
float angulo2 = anguloInicioRad + (i + 1) * pasoAngular;
// Calcular radios ajustados para crear apertura en cono
// Para guía superior: reducir radio en los extremos para crear apertura
float radio1 = radioGuiaSuperior;
float radio2 = radioGuiaSuperior;
// Calcular reducción del radio basada en el ángulo de apertura
float reduccionRadio = radioGuiaSuperior * (float)Math.Sin(anguloAperturaRad/10);
if (InvertirDireccion && i == 0) // Primer segmento
radio1 += reduccionRadio;
if (!InvertirDireccion && i == NumeroSegmentosGuias - 1) // Último segmento
radio2 += reduccionRadio;
Vector2 punto1 = new Vector2(
radioGuiaSuperior * (float)Math.Cos(angulo1),
radioGuiaSuperior * (float)Math.Sin(angulo1)
radio1 * (float)Math.Cos(angulo1),
radio1 * (float)Math.Sin(angulo1)
);
Vector2 punto2 = new Vector2(
radioGuiaSuperior * (float)Math.Cos(angulo2),
radioGuiaSuperior * (float)Math.Sin(angulo2)
radio2 * (float)Math.Cos(angulo2),
radio2 * (float)Math.Sin(angulo2)
);
// Ajustar por la posición del objeto
@ -374,14 +399,27 @@ namespace CtrEditor.ObjetosSim
float angulo1 = anguloInicioRad + i * pasoAngular;
float angulo2 = anguloInicioRad + (i + 1) * pasoAngular;
// Calcular radios ajustados para crear apertura en cono
// Para guía inferior: aumentar radio en los extremos para crear apertura
float radio1 = radioGuiaInferior;
float radio2 = radioGuiaInferior;
// Calcular aumento del radio basada en el ángulo de apertura
float aumentoRadio = radioGuiaInferior * (float)Math.Sin(anguloAperturaRad/10);
if (InvertirDireccion && i == 0) // Primer segmento
radio1 -= aumentoRadio;
if (InvertirDireccion && i == NumeroSegmentosGuias - 1) // Último segmento
radio2 -= aumentoRadio;
Vector2 punto1 = new Vector2(
radioGuiaInferior * (float)Math.Cos(angulo1),
radioGuiaInferior * (float)Math.Sin(angulo1)
radio1 * (float)Math.Cos(angulo1),
radio1 * (float)Math.Sin(angulo1)
);
Vector2 punto2 = new Vector2(
radioGuiaInferior * (float)Math.Cos(angulo2),
radioGuiaInferior * (float)Math.Sin(angulo2)
radio2 * (float)Math.Cos(angulo2),
radio2 * (float)Math.Sin(angulo2)
);
// Ajustar por la posición del objeto

View File

@ -865,7 +865,7 @@ namespace CtrEditor.Simulacion
if (simulation.Bodies.BodyExists(cuerpo.BodyHandle))
{
// cuerpo.LimitRotationToXYPlane();
simulation.Awakener.AwakenBody(cuerpo.BodyHandle);
// simulation.Awakener.AwakenBody(cuerpo.BodyHandle);
}
}
catch (Exception ex)

View File

@ -457,7 +457,7 @@ namespace CtrEditor.Simulacion
}
// ✅ CORREGIDO: Usar altura más visible y verificar coordenadas
const float curveHeight = 0.02f; // 2cm de altura para que sea claramente visible
const float curveHeight = 0.0f; // 0.02f; // 2cm de altura para que sea claramente visible
int triangleCount = 0;
foreach (var triangle in localTriangles)