Mejorado de las curvas. Se creo un overlapPercentage para las curvas.

This commit is contained in:
Miguel 2025-02-23 21:22:42 +01:00
parent d06607ccc6
commit 5f680b3a7a
5 changed files with 148 additions and 79 deletions

11
CtrEditor.code-workspace Normal file
View File

@ -0,0 +1,11 @@
{
"folders": [
{
"path": "."
},
{
"path": "../Libraries/LibS7Adv"
}
],
"settings": {}
}

View File

@ -746,7 +746,7 @@ namespace CtrEditor
}
stopwatch.Stop(); // Stop measuring time
Debug.WriteLine($"OnRefreshEvent: {stopwatch.Elapsed.TotalMilliseconds} ms");
// Debug.WriteLine($"OnRefreshEvent: {stopwatch.Elapsed.TotalMilliseconds} ms");
}
private void OpenWorkDirectory()

View File

@ -14,46 +14,36 @@ namespace CtrEditor.ObjetosSim
public partial class osBottGenerator : osBase, IosBase
{
TimerTON_TOFF _TON_TOFF = new TimerTON_TOFF();
// Otros datos y métodos relevantes para la simulación
private float TiempoRestante;
private osBotella UltimaBotella;
public static string NombreClase()
{
return "BottGenerator";
}
private string nombre = NombreClase();
public override string Nombre
{
get => nombre;
set => SetProperty(ref nombre, value);
}
public override string Nombre { get => nombre; set => SetProperty(ref nombre, value); }
[ObservableProperty]
private float offsetLeftSalida;
[ObservableProperty]
private float offsetTopSalida;
[ObservableProperty]
[property: Description("The bottle will be destroyed if fall outside transport.")]
[property: Category("Enable to Run:")]
private bool preserve_Outside_Transport;
[ObservableProperty]
[property: Description("PLC tag for consense to run. 1 => always")]
[property: Category("Enable to Run:")]
private string tag_consenso;
[ObservableProperty]
[property: Description("Consense to run.")]
[property: Category("Enable to Run:")]
private bool consenso;
partial void OnConsensoChanged(bool value)
{
_TON_TOFF.Senal = value;
}
[ObservableProperty]
[property: Description("Consense is Normally close.")]
[property: Category("Enable to Run:")]
@ -74,10 +64,8 @@ namespace CtrEditor.ObjetosSim
[property: Description("Filter OUT signal.")]
[property: Category("Enable to Run:")]
bool filter_Output;
[ObservableProperty]
private float botellas_hora;
partial void OnBotellas_horaChanged(float value)
{
Botellas_segundo = value / 3600;
@ -85,7 +73,6 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty]
private float botellas_segundo;
partial void OnBotellas_segundoChanged(float value)
{
Botellas_hora = value * 3600;
@ -95,21 +82,6 @@ namespace CtrEditor.ObjetosSim
private float velocidad_actual_percentual;
[ObservableProperty]
private float diametro_botella;
public osBottGenerator()
{
Ancho = 0.30f;
Alto = 0.30f;
Angulo = 0;
Velocidad_actual_percentual = 100;
Diametro_botella = 0.1f;
Botellas_hora = 10000;
Filtro_consenso_ON_s = 1;
Filtro_consenso_OFF_s = 0.1f;
Preserve_Outside_Transport = false;
}
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
{
if (Consenso_NC)
@ -118,67 +90,68 @@ namespace CtrEditor.ObjetosSim
Consenso = LeerBitTag(Tag_consenso);
}
private bool HayEspacioParaNuevaBotella(float X, float Y)
{
float radioMinimo = Diametro_botella / 4; // Distancia mínima entre centros
float radioMinimoCuadrado = radioMinimo * radioMinimo;
// Buscar todas las botellas cercanas
foreach (var obj in _mainViewModel.ObjetosSimulables)
{
if (obj is osBotella)
{
float distanciaCuadrada = (float)(Math.Pow(obj.Left - X, 2) + Math.Pow(obj.Top - Y, 2));
if (distanciaCuadrada < radioMinimoCuadrado)
{
return false; // Hay una botella demasiado cerca
}
}
}
return true; // No hay botellas cercanas
}
public override void UpdateControl(int elapsedMilliseconds)
{
bool habilitado;
_TON_TOFF.Tiempo_ON_s = Filtro_consenso_ON_s;
_TON_TOFF.Tiempo_OFF_s = Filtro_consenso_OFF_s;
if (Consenso_Filtrado)
habilitado = _TON_TOFF.SenalFiltrada();
else
habilitado = Consenso;
Filter_Output = habilitado;
if (habilitado && Velocidad_actual_percentual > 0)
{
if (PrimeraActualizacion)
{
TiempoEntreBotellas = 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
TiempoRestante = TiempoEntreBotellas;
PrimeraActualizacion = false;
}
TiempoRestante -= elapsedMilliseconds / 1000.0f;
if (TiempoRestante <= 0)
{
bool BotellaCreada = false;
var X = Left + OffsetLeftSalida;
var Y = Top + OffsetTopSalida;
if (UltimaBotella != null && UltimaBotella.RemoverDesdeSimulacion)
UltimaBotella = null;
if (UltimaBotella == null)
if (HayEspacioParaNuevaBotella(X, Y))
{
// No hay botellas, se puede crear una nueva directamente
var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
((osBotella)nuevaBotella).Diametro = Diametro_botella;
((osBotella)nuevaBotella).Preserve_Outside_Transport = Preserve_Outside_Transport;
((osBotella)nuevaBotella).AutoCreated = true;
nuevaBotella.AutoCreated = true;
UltimaBotella = (osBotella)nuevaBotella;
BotellaCreada = true;
}
else
{
// Calcular la distancia entre el centro de la última botella y la nueva posición
float distancia = (float)Math.Sqrt(Math.Pow(UltimaBotella.Left - X, 2) + Math.Pow(UltimaBotella.Top - Y, 2));
float distanciaMinima = Diametro_botella / 4; // Asumiendo que el diámetro de la nueva botella es similar
if (distancia > distanciaMinima)
{
osBotella nuevaBotella = (osBotella)_mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
nuevaBotella.Diametro = Diametro_botella;
((osBotella)nuevaBotella).Preserve_Outside_Transport = Preserve_Outside_Transport;
nuevaBotella.AutoCreated = true;
UltimaBotella = nuevaBotella;
BotellaCreada = true;
}
// Recalcular el tiempo entre botellas por si cambió la velocidad
TiempoEntreBotellas = 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
TiempoRestante = TiempoEntreBotellas;
}
if (BotellaCreada)
TiempoRestante += 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
}
}
else
{
TiempoRestante = 0;
PrimeraActualizacion = true;
}
}
@ -189,6 +162,13 @@ namespace CtrEditor.ObjetosSim
base.ucLoaded();
}
private float TiempoEntreBotellas; // Nuevo: almacena el intervalo calculado
private bool PrimeraActualizacion = true; // Nuevo: flag para la primera actualización
public override void SimulationStop()
{
PrimeraActualizacion = true; // Reset del flag al detener
base.SimulationStop();
}
}
public partial class ucBottGenerator : UserControl, IDataContainer
@ -202,19 +182,24 @@ namespace CtrEditor.ObjetosSim
this.Loaded += OnLoaded;
this.Unloaded += OnUnloaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Datos?.ucLoaded();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
Datos?.ucUnLoaded();
}
public void Highlight(bool State) { }
public void Highlight(bool State)
{
}
public ZIndexEnum ZIndex_Base()
{
return ZIndexEnum.Generadores;
}
}
}

View File

@ -202,10 +202,15 @@ namespace CtrEditor.ObjetosSim
if (DB_Motor == 0)
return;
// Read ControlWord in one operation
int controlWord = plc.LeerTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].ControlWord") ?? 0;
// Add timestamp to trace when the read occurs
var timestamp = DateTime.Now;
// Read ControlWord and track the raw response
var rawResponse = plc.LeerTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].ControlWord");
int controlWord = rawResponse ?? 0;
var control = VMMotorBitPacker.UnpackControlWord(controlWord);
// Update local state from ControlWord
OUT_Run = control.run;
OUT_Stop = control.stop;
@ -233,6 +238,7 @@ namespace CtrEditor.ObjetosSim
if (Data.VFD_Trip_NC)
STATUS_VFD_Trip = !STATUS_VFD_Trip;
// Pack all status bits and speed into StatusWord
int statusWord = VMMotorBitPacker.PackStatusWord(
_STATUS_VFD_Ready,

View File

@ -128,6 +128,43 @@ namespace CtrEditor.Simulacion
return verticesList;
}
private float CalculateAngleOverlap(Fixture bottle)
{
// Get bottle position relative to curve center
Vector2 centerToBottle = bottle.Body.Position - Body.Position;
// Calculate angle of bottle relative to curve center (in radians)
float bottleAngle = (float)Math.Atan2(centerToBottle.Y, centerToBottle.X);
// Normalize angle to be positive
if (bottleAngle < 0)
bottleAngle += 2 * (float)Math.PI;
// If bottle is outside the angle range, return 0
if (bottleAngle < _startAngle || bottleAngle > _endAngle)
return 0;
// Calculate distance from center
float distanceToCenter = centerToBottle.Length();
// If bottle is outside radius range, return 0
if (distanceToCenter < _innerRadius || distanceToCenter > _outerRadius)
return 0;
// Calculate how far the bottle is from the edges
float angleFromStart = bottleAngle - _startAngle;
float angleToEnd = _endAngle - bottleAngle;
// Use the minimum distance to either edge to calculate overlap
float minAngleDistance = Math.Min(angleFromStart, angleToEnd);
float totalAngle = _endAngle - _startAngle;
// Calculate overlap percentage based on angle proximity to edges
float overlapPercentage = Math.Min(minAngleDistance / (totalAngle * 0.1f), 1.0f);
return overlapPercentage;
}
public void ApplyCurveEffect(Fixture bottle)
{
Vector2 centerToBottle = bottle.Body.Position - Body.Position;
@ -135,17 +172,46 @@ namespace CtrEditor.Simulacion
if (distanceToCenter >= _innerRadius && distanceToCenter <= _outerRadius)
{
// Calcular la velocidad tangencial
float speedMetersPerSecond = Speed / 60.0f;
float angularVelocity = speedMetersPerSecond / distanceToCenter;
// Calculate overlap percentage
float overlapPercentage = CalculateAngleOverlap(bottle);
// Vector tangente (perpendicular al radio)
Vector2 tangent = new Vector2(-centerToBottle.Y, centerToBottle.X);
tangent.Normalize();
// Only apply effect if there's overlap
if (overlapPercentage > 0)
{
// Calculate the tangential velocity
float speedMetersPerSecond = Speed / 60.0f;
// Velocidad deseada
Vector2 desiredVelocity = tangent * angularVelocity * distanceToCenter;
bottle.Body.LinearVelocity = desiredVelocity;
// Vector tangent (perpendicular to radius)
Vector2 tangent = new Vector2(-centerToBottle.Y, centerToBottle.X);
tangent.Normalize();
// Adjust tangent direction based on speed sign
if (speedMetersPerSecond < 0)
tangent = -tangent;
// Current velocity magnitude
float currentSpeed = bottle.Body.LinearVelocity.Length();
// Desired conveyor speed
float conveyorSpeed = Math.Abs(speedMetersPerSecond);
// Use the larger of the two speeds as base speed
float targetSpeed = Math.Max(currentSpeed, conveyorSpeed);
// Lerp between current direction and curve direction
Vector2 currentDir = bottle.Body.LinearVelocity;
if (currentDir.LengthSquared() > 0)
currentDir.Normalize();
else
currentDir = tangent;
// Interpolate between current direction and curve direction
Vector2 newDirection = currentDir * (1 - overlapPercentage) + tangent * overlapPercentage;
newDirection.Normalize();
// Apply new velocity with combined speed
bottle.Body.LinearVelocity = newDirection * targetSpeed;
}
}
}
}
@ -574,8 +640,9 @@ namespace CtrEditor.Simulacion
foreach (var transporte in ListOnTransports)
{
if (transporte is simTransporte conveyorRect)
if (ApplyConveyorEffect(deltaTime_s, conveyorRect))
break;
ApplyConveyorEffect(deltaTime_s, conveyorRect);
// if (ApplyConveyorEffect(deltaTime_s, conveyorRect))
// break;
if (transporte is simCurve conveyorCurve)
conveyorCurve.ApplyCurveEffect(Body.FixtureList[0]);
}