aboutsummaryrefslogtreecommitdiff
path: root/src/Costasdev.Busurbano.Backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/Costasdev.Busurbano.Backend')
-rw-r--r--src/Costasdev.Busurbano.Backend/Controllers/VigoController.cs76
-rw-r--r--src/Costasdev.Busurbano.Backend/Services/ShapeTraversalService.cs30
-rw-r--r--src/Costasdev.Busurbano.Backend/Types/ConsolidatedCirculation.cs1
3 files changed, 91 insertions, 16 deletions
diff --git a/src/Costasdev.Busurbano.Backend/Controllers/VigoController.cs b/src/Costasdev.Busurbano.Backend/Controllers/VigoController.cs
index 151baa3..1f81bf1 100644
--- a/src/Costasdev.Busurbano.Backend/Controllers/VigoController.cs
+++ b/src/Costasdev.Busurbano.Backend/Controllers/VigoController.cs
@@ -49,18 +49,60 @@ public class VigoController : ControllerBase
[HttpGet("GetShape")]
public async Task<IActionResult> GetShape(
[FromQuery] string shapeId,
- [FromQuery] int startPointIndex = 0
+ [FromQuery] int? startPointIndex = null,
+ [FromQuery] double? busLat = null,
+ [FromQuery] double? busLon = null,
+ [FromQuery] int? busShapeIndex = null,
+ [FromQuery] double? stopLat = null,
+ [FromQuery] double? stopLon = null,
+ [FromQuery] int? stopShapeIndex = null
)
{
- // Include a significant number of previous points to ensure continuity and context
- // Backtrack 15 points to cover any potential gaps or dense point sequences
- var adjustedStartIndex = Math.Max(0, startPointIndex - 15);
- var path = await _shapeService.GetShapePathAsync(shapeId, adjustedStartIndex);
+ var path = await _shapeService.GetShapePathAsync(shapeId, 0);
if (path == null)
{
return NotFound();
}
+ // Determine bus point
+ object? busPoint = null;
+ if (busShapeIndex.HasValue && busShapeIndex.Value >= 0 && busShapeIndex.Value < path.Count)
+ {
+ var p = path[busShapeIndex.Value];
+ busPoint = new { lat = p.Latitude, lon = p.Longitude, index = busShapeIndex.Value };
+ }
+ else if (busLat.HasValue && busLon.HasValue)
+ {
+ var idx = await _shapeService.FindClosestPointIndexAsync(shapeId, busLat.Value, busLon.Value);
+ if (idx.HasValue && idx.Value >= 0 && idx.Value < path.Count)
+ {
+ var p = path[idx.Value];
+ busPoint = new { lat = p.Latitude, lon = p.Longitude, index = idx.Value };
+ }
+ }
+ else if (startPointIndex.HasValue && startPointIndex.Value >= 0 && startPointIndex.Value < path.Count)
+ {
+ var p = path[startPointIndex.Value];
+ busPoint = new { lat = p.Latitude, lon = p.Longitude, index = startPointIndex.Value };
+ }
+
+ // Determine stop point
+ object? stopPoint = null;
+ if (stopShapeIndex.HasValue && stopShapeIndex.Value >= 0 && stopShapeIndex.Value < path.Count)
+ {
+ var p = path[stopShapeIndex.Value];
+ stopPoint = new { lat = p.Latitude, lon = p.Longitude, index = stopShapeIndex.Value };
+ }
+ else if (stopLat.HasValue && stopLon.HasValue)
+ {
+ var idx = await _shapeService.FindClosestPointIndexAsync(shapeId, stopLat.Value, stopLon.Value);
+ if (idx.HasValue && idx.Value >= 0 && idx.Value < path.Count)
+ {
+ var p = path[idx.Value];
+ stopPoint = new { lat = p.Latitude, lon = p.Longitude, index = idx.Value };
+ }
+ }
+
// Convert to GeoJSON LineString
var coordinates = path.Select(p => new[] { p.Longitude, p.Latitude }).ToList();
@@ -72,7 +114,11 @@ public class VigoController : ControllerBase
type = "LineString",
coordinates = coordinates
},
- properties = new { }
+ properties = new
+ {
+ busPoint,
+ stopPoint
+ }
};
return Ok(geoJson);
@@ -214,7 +260,7 @@ public class VigoController : ControllerBase
// 2) From the valid trips, pick the one with smallest Abs(TimeDiff).
// This handles "as late as it gets" (large negative TimeDiff) by preferring smaller delays if available,
// but accepting large delays if that's the only option (and better than an invalid early trip).
- const int maxEarlyArrivalMinutes = 3;
+ const int maxEarlyArrivalMinutes = 5;
var bestMatch = possibleCirculations
.Select(c => new
@@ -259,6 +305,7 @@ public class VigoController : ControllerBase
var isRunning = closestCirculation.StartingDateTime()!.Value <= now;
Position? currentPosition = null;
+ int? stopShapeIndex = null;
// Calculate bus position only for realtime trips that have already departed
if (isRunning && !string.IsNullOrEmpty(closestCirculation.ShapeId))
@@ -266,7 +313,9 @@ public class VigoController : ControllerBase
var shape = await _shapeService.LoadShapeAsync(closestCirculation.ShapeId);
if (shape != null && stopLocation != null)
{
- currentPosition = _shapeService.GetBusPosition(shape, stopLocation, estimate.Meters);
+ var result = _shapeService.GetBusPosition(shape, stopLocation, estimate.Meters);
+ currentPosition = result.BusPosition;
+ stopShapeIndex = result.StopIndex;
}
}
@@ -288,7 +337,8 @@ public class VigoController : ControllerBase
Minutes = estimate.Minutes,
Distance = estimate.Meters
},
- CurrentPosition = currentPosition
+ CurrentPosition = currentPosition,
+ StopShapeIndex = stopShapeIndex
});
usedTripIds.Add(closestCirculation.TripId);
@@ -310,6 +360,12 @@ public class VigoController : ControllerBase
continue; // already represented via a matched realtime
}
+ var minutes = (int)(sched.CallingDateTime()!.Value - now).TotalMinutes;
+ if (minutes == 0)
+ {
+ continue;
+ }
+
consolidatedCirculations.Add(new ConsolidatedCirculation
{
Line = sched.Line,
@@ -317,7 +373,7 @@ public class VigoController : ControllerBase
Schedule = new ScheduleData
{
Running = sched.StartingDateTime()!.Value <= now,
- Minutes = (int)(sched.CallingDateTime()!.Value - now).TotalMinutes,
+ Minutes = minutes,
TripId = sched.TripId,
ServiceId = sched.ServiceId,
ShapeId = sched.ShapeId,
diff --git a/src/Costasdev.Busurbano.Backend/Services/ShapeTraversalService.cs b/src/Costasdev.Busurbano.Backend/Services/ShapeTraversalService.cs
index 37b76ee..7263ad0 100644
--- a/src/Costasdev.Busurbano.Backend/Services/ShapeTraversalService.cs
+++ b/src/Costasdev.Busurbano.Backend/Services/ShapeTraversalService.cs
@@ -68,27 +68,45 @@ public class ShapeTraversalService
var result = new List<Position>();
// Ensure startIndex is within bounds
if (startIndex < 0) startIndex = 0;
+ // If startIndex is beyond the end, return empty list
if (startIndex >= shape.Points.Count) return result;
for (int i = startIndex; i < shape.Points.Count; i++)
{
- result.Add(TransformToLatLng(shape.Points[i]));
+ var pos = TransformToLatLng(shape.Points[i]);
+ pos.ShapeIndex = i;
+ result.Add(pos);
}
return result;
}
+ public async Task<int?> FindClosestPointIndexAsync(string shapeId, double lat, double lon)
+ {
+ var shape = await LoadShapeAsync(shapeId);
+ if (shape == null) return null;
+
+ // Transform input WGS84 to EPSG:25829
+ // Input is [Longitude, Latitude]
+ var inverseTransform = _transformation.MathTransform.Inverse();
+ var transformed = inverseTransform.Transform(new[] { lon, lat });
+
+ var location = new Epsg25829 { X = transformed[0], Y = transformed[1] };
+
+ return FindClosestPointIndex(shape.Points, location);
+ }
+
/// <summary>
/// Calculates the bus position by reverse-traversing the shape from the stop location
/// </summary>
/// <param name="shape">The shape points (in EPSG:25829 meters)</param>
/// <param name="stopLocation">The stop location (in EPSG:25829 meters)</param>
/// <param name="distanceMeters">Distance in meters from the stop to traverse backwards</param>
- /// <returns>The lat/lng position of the bus, or null if not calculable</returns>
- public Position? GetBusPosition(Shape shape, Epsg25829 stopLocation, int distanceMeters)
+ /// <returns>The lat/lng position of the bus and the stop index on the shape</returns>
+ public (Position? BusPosition, int StopIndex) GetBusPosition(Shape shape, Epsg25829 stopLocation, int distanceMeters)
{
if (shape.Points.Count == 0 || distanceMeters <= 0)
{
- return null;
+ return (null, -1);
}
// Find the closest point on the shape to the stop
@@ -99,7 +117,7 @@ public class ShapeTraversalService
if (busPoint == null)
{
- return null;
+ return (null, closestPointIndex);
}
var forwardPoint = shape.Points[forwardIndex];
@@ -114,7 +132,7 @@ public class ShapeTraversalService
var pos = TransformToLatLng(busPoint);
pos.OrientationDegrees = (int)Math.Round(bearing);
pos.ShapeIndex = forwardIndex;
- return pos;
+ return (pos, closestPointIndex);
}
/// <summary>
diff --git a/src/Costasdev.Busurbano.Backend/Types/ConsolidatedCirculation.cs b/src/Costasdev.Busurbano.Backend/Types/ConsolidatedCirculation.cs
index 2ac3206..ff6dbde 100644
--- a/src/Costasdev.Busurbano.Backend/Types/ConsolidatedCirculation.cs
+++ b/src/Costasdev.Busurbano.Backend/Types/ConsolidatedCirculation.cs
@@ -8,6 +8,7 @@ public class ConsolidatedCirculation
public ScheduleData? Schedule { get; set; }
public RealTimeData? RealTime { get; set; }
public Position? CurrentPosition { get; set; }
+ public int? StopShapeIndex { get; set; }
public string[] NextStreets { get; set; } = [];
}