namespace RobotNet10.NavigationTune.Shared.Models;
///
/// Base class for test scenarios
///
public abstract class TestScenario
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public TrajectoryType Type { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public bool IsDefault { get; set; }
///
/// Generate reference path for this scenario
///
public abstract List GenerateReferencePath();
///
/// Check if goal is reached
///
public abstract bool IsGoalReached(Pose2D currentPose, double tolerance = 0.05f);
///
/// Get goal pose
///
public abstract Pose2D GetGoalPose();
}
///
/// Trajectory type
///
public enum TrajectoryType
{
StraightLine = 1,
Circle = 2,
Square = 3,
SCurve = 4,
Custom = 99
}
///
/// Direction for robot movement
///
public enum RobotDirection
{
FORWARD,
BACKWARD
}
///
/// Point on reference path
///
public class PathPoint
{
public double X { get; set; }
public double Y { get; set; }
public RobotDirection Direction { get; set; } = RobotDirection.FORWARD;
public double DistanceFromStart { get; set; } // cumulative distance
}
///
/// Reference path
///
public class ReferencePath
{
public List Points { get; set; } = new();
public double TotalLength { get; set; }
public PathPoint? GetClosestPoint(Pose2D pose)
{
if (Points.Count == 0) return null;
double minDistance = double.MaxValue;
PathPoint? closest = null;
foreach (var point in Points)
{
double dx = pose.X - point.X;
double dy = pose.Y - point.Y;
double distance = Math.Sqrt(dx * dx + dy * dy);
if (distance < minDistance)
{
minDistance = distance;
closest = point;
}
}
return closest;
}
public PathPoint? GetPointAtDistance(double distance)
{
if (Points.Count == 0) return null;
if (distance <= 0) return Points[0];
if (distance >= TotalLength) return Points[^1];
// Find segment containing this distance
for (int i = 0; i < Points.Count - 1; i++)
{
if (distance >= Points[i].DistanceFromStart && distance <= Points[i + 1].DistanceFromStart)
{
// Interpolate
double segmentLength = Points[i + 1].DistanceFromStart - Points[i].DistanceFromStart;
double t = (distance - Points[i].DistanceFromStart) / segmentLength;
return new PathPoint
{
X = Points[i].X + t * (Points[i + 1].X - Points[i].X),
Y = Points[i].Y + t * (Points[i + 1].Y - Points[i].Y),
Direction = Points[i].Direction, // Use direction from start point
DistanceFromStart = distance
};
}
}
return Points[^1];
}
}