Mejorado de las curvas. Se creo un overlapPercentage para las curvas.
This commit is contained in:
parent
d06607ccc6
commit
5f680b3a7a
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "../Libraries/LibS7Adv"
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue