Compare commits
2 Commits
ef7d3e2618
...
643287583a
Author | SHA1 | Date |
---|---|---|
Miguel | 643287583a | |
Miguel | 294be7788f |
|
@ -12,6 +12,7 @@
|
||||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
|
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||||
|
<PackageReference Include="OpenCvSharp4.Windows" Version="4.9.0.20240103" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
|
@ -80,6 +82,21 @@ namespace CtrEditor.ObjetosSim
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class MeterToPixelConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
float meters = (float)value;
|
||||||
|
return PixelToMeter.Instance.calc.MetersToPixels(meters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
float pixels = (float)value;
|
||||||
|
return PixelToMeter.Instance.calc.PixelsToMeters(pixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class UnitConverter
|
public class UnitConverter
|
||||||
{
|
{
|
||||||
// La escala representa cuántos metros hay en un píxel
|
// La escala representa cuántos metros hay en un píxel
|
||||||
|
|
|
@ -58,6 +58,17 @@ namespace CtrEditor.ObjetosSim
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float Overlap
|
||||||
|
{
|
||||||
|
get => Data.Overlap;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Data.Overlap = value;
|
||||||
|
OnPropertyChanged(nameof(Overlap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public override float LeftPixels
|
public override float LeftPixels
|
||||||
{
|
{
|
||||||
get => PixelToMeter.Instance.calc.MetersToPixels(Data.Left);
|
get => PixelToMeter.Instance.calc.MetersToPixels(Data.Left);
|
||||||
|
@ -134,6 +145,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Top = Data.Top;
|
Top = Data.Top;
|
||||||
Left = Data.Left;
|
Left = Data.Left;
|
||||||
|
Overlap = Data.Overlap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Data.Length = value;
|
Data.Length = value;
|
||||||
|
OnPropertyChanged(nameof(AnchoPixels));
|
||||||
OnPropertyChanged(nameof(Ancho));
|
OnPropertyChanged(nameof(Ancho));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +98,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Data.Width = value;
|
Data.Width = value;
|
||||||
|
OnPropertyChanged(nameof(AltoPixels));
|
||||||
OnPropertyChanged(nameof(Alto));
|
OnPropertyChanged(nameof(Alto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,6 +108,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Data.Length = (float)PixelToMeter.Instance.calc.PixelsToMeters(value);
|
Data.Length = (float)PixelToMeter.Instance.calc.PixelsToMeters(value);
|
||||||
|
OnPropertyChanged(nameof(AnchoPixels));
|
||||||
OnPropertyChanged(nameof(Ancho));
|
OnPropertyChanged(nameof(Ancho));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,6 +118,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Data.Width = (float)PixelToMeter.Instance.calc.PixelsToMeters(value);
|
Data.Width = (float)PixelToMeter.Instance.calc.PixelsToMeters(value);
|
||||||
|
OnPropertyChanged(nameof(AltoPixels));
|
||||||
OnPropertyChanged(nameof(Alto));
|
OnPropertyChanged(nameof(Alto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +186,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public void Resize(float width, float height)
|
public void Resize(float width, float height)
|
||||||
{
|
{
|
||||||
if (Datos is osTransporteTTop datos)
|
if (Datos is osTransporteTTop datos)
|
||||||
datos.Ancho = width;
|
datos.AnchoPixels = width;
|
||||||
}
|
}
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
public void Move(float LeftPixels, float TopPixels)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using CtrEditor.ObjetosSim;
|
using CtrEditor.ObjetosSim;
|
||||||
|
using OpenCvSharp;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.Eventing.Reader;
|
using System.Diagnostics.Eventing.Reader;
|
||||||
|
@ -20,15 +21,16 @@ public class Circle
|
||||||
}
|
}
|
||||||
public float Diameter { get; set; }
|
public float Diameter { get; set; }
|
||||||
public float Mass { get; set; }
|
public float Mass { get; set; }
|
||||||
public float Angle { get; set; } // En grados
|
public float AngleofMovement { get; set; } // En grados
|
||||||
public float Speed { get; set; }
|
public float Speed { get; set; }
|
||||||
|
public float Overlap { get; set; }
|
||||||
|
|
||||||
public Circle(float left = 0, float top = 0, float diameter = 10, float mass = 1, float angle = 0, float speed = 0)
|
public Circle(float left = 0, float top = 0, float diameter = 10, float mass = 1, float angle = 0, float speed = 0)
|
||||||
{
|
{
|
||||||
position = new Vector2(left, top);
|
position = new Vector2(left, top);
|
||||||
Diameter = diameter;
|
Diameter = diameter;
|
||||||
Mass = mass;
|
Mass = mass;
|
||||||
Angle = angle;
|
AngleofMovement = angle;
|
||||||
Speed = speed;
|
Speed = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,13 +39,15 @@ public class Circle
|
||||||
// Convertir timeStep de milisegundos a segundos para la simulación
|
// Convertir timeStep de milisegundos a segundos para la simulación
|
||||||
float timeStepInSeconds = timeStep_ms / 1000.0f;
|
float timeStepInSeconds = timeStep_ms / 1000.0f;
|
||||||
bool isTracted = false; // Indicador para verificar si el círculo está siendo traccionado
|
bool isTracted = false; // Indicador para verificar si el círculo está siendo traccionado
|
||||||
|
Overlap = 0;
|
||||||
|
|
||||||
// Aplicar fuerza desde el rectángulo si está sobre uno
|
// Aplicar fuerza desde el rectángulo si está sobre uno
|
||||||
foreach (var rectangle in rectangles)
|
foreach (var rectangle in rectangles)
|
||||||
{
|
{
|
||||||
float overlap = CalculateOverlapPercentage(this, rectangle);
|
float overlap = CalculateOverlapPercentage(this, rectangle);
|
||||||
if (overlap > 0)
|
if (overlap > 10)
|
||||||
{
|
{
|
||||||
|
Overlap += overlap;
|
||||||
isTracted = true; // El círculo está siendo traccionado por un rectángulo
|
isTracted = true; // El círculo está siendo traccionado por un rectángulo
|
||||||
// Convertir la velocidad del rectángulo de metros por minuto a metros por segundo
|
// Convertir la velocidad del rectángulo de metros por minuto a metros por segundo
|
||||||
float rectangleSpeedInMetersPerSecond = rectangle.Speed / 60.0f;
|
float rectangleSpeedInMetersPerSecond = rectangle.Speed / 60.0f;
|
||||||
|
@ -60,7 +64,7 @@ public class Circle
|
||||||
Speed += (rectangleSpeedInMetersPerSecond - Speed) * (overlap / 100.0f) * timeStepInSeconds;
|
Speed += (rectangleSpeedInMetersPerSecond - Speed) * (overlap / 100.0f) * timeStepInSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
Angle = rectangle.Angle;
|
AngleofMovement = rectangle.Angle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +104,11 @@ public class Circle
|
||||||
float impactAngle = CalculateImpactAngle(this, line);
|
float impactAngle = CalculateImpactAngle(this, line);
|
||||||
if (impactAngle < 85)
|
if (impactAngle < 85)
|
||||||
{
|
{
|
||||||
Angle = line.Angle;
|
AngleofMovement = line.Angle;
|
||||||
}
|
}
|
||||||
else if (impactAngle > 95)
|
else if (impactAngle > 95)
|
||||||
{
|
{
|
||||||
Angle = line.Angle + 180; // Movimiento contrario
|
AngleofMovement = line.Angle + 180; // Movimiento contrario
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -114,7 +118,7 @@ public class Circle
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcular nueva posición
|
// Calcular nueva posición
|
||||||
Vector2 direction = new Vector2((float)Math.Cos(Angle * Math.PI / 180), (float)Math.Sin(Angle * Math.PI / 180));
|
Vector2 direction = new Vector2((float)Math.Cos(AngleofMovement * Math.PI / 180), (float)Math.Sin(AngleofMovement * Math.PI / 180));
|
||||||
Vector2 velocity = direction * Speed * timeStepInSeconds;
|
Vector2 velocity = direction * Speed * timeStepInSeconds;
|
||||||
position += velocity;
|
position += velocity;
|
||||||
}
|
}
|
||||||
|
@ -180,7 +184,7 @@ public class Circle
|
||||||
|
|
||||||
private float CalculateImpactAngle(Circle circle, Line line)
|
private float CalculateImpactAngle(Circle circle, Line line)
|
||||||
{
|
{
|
||||||
Vector2 movementDirection = new Vector2((float)Math.Cos(circle.Angle * Math.PI / 180), (float)Math.Sin(circle.Angle * Math.PI / 180));
|
Vector2 movementDirection = new Vector2((float)Math.Cos(circle.AngleofMovement * Math.PI / 180), (float)Math.Sin(circle.AngleofMovement * Math.PI / 180));
|
||||||
Vector2 lineDirection = line.end - line.start;
|
Vector2 lineDirection = line.end - line.start;
|
||||||
Vector2 lineNormal = new Vector2(-lineDirection.Y, lineDirection.X); // Rotar 90 grados para obtener normal
|
Vector2 lineNormal = new Vector2(-lineDirection.Y, lineDirection.X); // Rotar 90 grados para obtener normal
|
||||||
lineNormal = Vector2.Normalize(lineNormal);
|
lineNormal = Vector2.Normalize(lineNormal);
|
||||||
|
@ -193,69 +197,59 @@ public class Circle
|
||||||
return angle < 90 ? 90 - angle : angle - 90;
|
return angle < 90 ? 90 - angle : angle - 90;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float CalculateOverlapPercentage(Circle circle, Rectangle rectangle)
|
public static float CalculateOverlapPercentage(Circle circle, Rectangle rectangle)
|
||||||
{
|
{
|
||||||
// Convertir ángulo del rectángulo de grados a radianes
|
// Convertir el círculo en un cuadrado aproximado.
|
||||||
float angleRadians = (float)(rectangle.Angle * Math.PI / 180);
|
float squareSide = circle.Diameter / (float)Math.Sqrt(Math.PI);
|
||||||
|
RotatedRect square = new RotatedRect(
|
||||||
// Centro del círculo
|
new Point2f(circle.Left + circle.Diameter / 2, circle.Top + circle.Diameter / 2),
|
||||||
Vector2 circleCenter = new Vector2(circle.Left + circle.Diameter / 2, circle.Top + circle.Diameter / 2);
|
new Size2f(squareSide, squareSide),
|
||||||
float radius = circle.Diameter / 2;
|
0 // Sin rotación
|
||||||
|
|
||||||
// Pivot del rectángulo es el Top Left
|
|
||||||
Vector2 rectPivot = new Vector2(rectangle.Left, rectangle.Top);
|
|
||||||
|
|
||||||
// Rotar el centro del círculo respecto al pivote del rectángulo
|
|
||||||
Vector2 rotatedCircleCenter = RotatePoint(circleCenter, rectPivot, -angleRadians);
|
|
||||||
|
|
||||||
// Comprobar si el círculo rotado intersecta con el rectángulo alineado
|
|
||||||
// Rectángulo "alineado" asume que después de rotar el círculo, el rectángulo se comporta como si estuviera alineado con los ejes
|
|
||||||
if (IsCircleRectangleIntersecting(rotatedCircleCenter, radius, rectPivot, rectangle.Length, rectangle.Width))
|
|
||||||
{
|
|
||||||
float overlapArea = EstimateOverlapArea(rotatedCircleCenter, radius, rectPivot, rectangle.Length, rectangle.Width);
|
|
||||||
float circleArea = (float)(Math.PI * radius * radius);
|
|
||||||
return (overlapArea / circleArea) * 100;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private bool IsCircleRectangleIntersecting(Vector2 circleCenter, float radius, Vector2 rectTopLeft, float length, float width)
|
|
||||||
{
|
|
||||||
float closestX = Math.Max(rectTopLeft.X, Math.Min(circleCenter.X, rectTopLeft.X + length));
|
|
||||||
float closestY = Math.Max(rectTopLeft.Y, Math.Min(circleCenter.Y, rectTopLeft.Y + width));
|
|
||||||
|
|
||||||
float distanceX = circleCenter.X - closestX;
|
|
||||||
float distanceY = circleCenter.Y - closestY;
|
|
||||||
|
|
||||||
return (distanceX * distanceX + distanceY * distanceY) < (radius * radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private float EstimateOverlapArea(Vector2 circleCenter, float radius, Vector2 rectCenter, float length, float width)
|
|
||||||
{
|
|
||||||
// Esto es un placeholder: el cálculo real requiere un algoritmo geométrico complejo
|
|
||||||
// Puedes retornar una estimación basada en proporciones o usar una librería geométrica
|
|
||||||
return (float) (radius * radius * Math.PI * 0.25f); // Asumiendo un solapamiento del 25% como placeholder
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Vector2 RotatePoint(Vector2 point, Vector2 pivot, float angle)
|
|
||||||
{
|
|
||||||
float cosTheta = (float)Math.Cos(angle);
|
|
||||||
float sinTheta = (float)Math.Sin(angle);
|
|
||||||
// Ajustar punto por pivot antes de aplicar rotación
|
|
||||||
Vector2 translatedPoint = new Vector2(point.X - pivot.X, point.Y - pivot.Y);
|
|
||||||
// Rotar el punto
|
|
||||||
Vector2 rotatedPoint = new Vector2(
|
|
||||||
translatedPoint.X * cosTheta - translatedPoint.Y * sinTheta,
|
|
||||||
translatedPoint.X * sinTheta + translatedPoint.Y * cosTheta
|
|
||||||
);
|
);
|
||||||
// Traducir el punto de vuelta
|
|
||||||
return new Vector2(rotatedPoint.X + pivot.X, rotatedPoint.Y + pivot.Y);
|
// Ajustamos el rectángulo para que se considere rotado desde el centro, pero calculado desde Top-Left
|
||||||
|
RotatedRect rotatedRectangle = CreateRotatedRectFromTopLeft(rectangle);
|
||||||
|
|
||||||
|
// Usar OpenCV para encontrar la intersección.
|
||||||
|
using (var mat = new Mat())
|
||||||
|
{
|
||||||
|
var result = Cv2.RotatedRectangleIntersection(square, rotatedRectangle, mat);
|
||||||
|
if (result != RectanglesIntersectTypes.None)
|
||||||
|
{
|
||||||
|
// Calcular el área de la intersección
|
||||||
|
float intersectionArea = (float) Cv2.ContourArea(mat);
|
||||||
|
float circleArea = (float)(Math.PI * Math.Pow(circle.Diameter / 2, 2));
|
||||||
|
return (intersectionArea / circleArea) * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // No hay intersección
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RotatedRect CreateRotatedRectFromTopLeft(Rectangle rectangle)
|
||||||
|
{
|
||||||
|
// El punto de pivote es Top-Left, calculamos el centro sin rotar
|
||||||
|
float originalCenterX = rectangle.Left + rectangle.Length / 2.0f;
|
||||||
|
float originalCenterY = rectangle.Top + rectangle.Width / 2.0f;
|
||||||
|
|
||||||
|
// Convertimos el ángulo a radianes para la rotación
|
||||||
|
float angleRadians = rectangle.Angle * (float)Math.PI / 180;
|
||||||
|
|
||||||
|
// Calcular las nuevas coordenadas del centro después de la rotación
|
||||||
|
float rotatedCenterX = rectangle.Left + (originalCenterX - rectangle.Left) * (float)Math.Cos(angleRadians) - (originalCenterY - rectangle.Top) * (float)Math.Sin(angleRadians);
|
||||||
|
float rotatedCenterY = rectangle.Top + (originalCenterX - rectangle.Left) * (float)Math.Sin(angleRadians) + (originalCenterY - rectangle.Top) * (float)Math.Cos(angleRadians);
|
||||||
|
|
||||||
|
// Crear el RotatedRect con el nuevo centro y el tamaño original
|
||||||
|
RotatedRect rotatedRect = new RotatedRect(
|
||||||
|
new Point2f(rotatedCenterX, rotatedCenterY),
|
||||||
|
new Size2f(rectangle.Length, rectangle.Width),
|
||||||
|
rectangle.Angle
|
||||||
|
);
|
||||||
|
|
||||||
|
return rotatedRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +318,21 @@ public class Line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Square
|
||||||
|
{
|
||||||
|
public float Left { get; set; }
|
||||||
|
public float Top { get; set; }
|
||||||
|
public float Size { get; set; } // 'Size' es la longitud de un lado del cuadrado
|
||||||
|
|
||||||
|
public Square(float left, float top, float size)
|
||||||
|
{
|
||||||
|
Left = left;
|
||||||
|
Top = top;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Clase principal que gestiona la simulación
|
// Clase principal que gestiona la simulación
|
||||||
public class SimulationManager
|
public class SimulationManager
|
||||||
|
|
Loading…
Reference in New Issue