mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-04-22 09:16:39 +00:00
route in progress, region stitching is disabled by default
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SatelliteProvider.Common.DTO;
|
||||
using SatelliteProvider.Common.Interfaces;
|
||||
using SatelliteProvider.Common.Utils;
|
||||
using SatelliteProvider.DataAccess.Models;
|
||||
using SatelliteProvider.DataAccess.Repositories;
|
||||
|
||||
namespace SatelliteProvider.Services;
|
||||
|
||||
public class RouteService : IRouteService
|
||||
{
|
||||
private readonly IRouteRepository _routeRepository;
|
||||
private readonly ILogger<RouteService> _logger;
|
||||
private const double MAX_POINT_SPACING_METERS = 200.0;
|
||||
|
||||
public RouteService(
|
||||
IRouteRepository routeRepository,
|
||||
ILogger<RouteService> logger)
|
||||
{
|
||||
_routeRepository = routeRepository;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<RouteResponse> CreateRouteAsync(CreateRouteRequest request)
|
||||
{
|
||||
if (request.Points.Count < 2)
|
||||
{
|
||||
throw new ArgumentException("Route must have at least 2 points");
|
||||
}
|
||||
|
||||
if (request.RegionSizeMeters < 100 || request.RegionSizeMeters > 10000)
|
||||
{
|
||||
throw new ArgumentException("Region size must be between 100 and 10000 meters");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.Name))
|
||||
{
|
||||
throw new ArgumentException("Route name is required");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Creating route {RouteId} with {PointCount} original points",
|
||||
request.Id, request.Points.Count);
|
||||
|
||||
var allPoints = new List<RoutePointDto>();
|
||||
var totalDistance = 0.0;
|
||||
var sequenceNumber = 0;
|
||||
|
||||
for (int segmentIndex = 0; segmentIndex < request.Points.Count; segmentIndex++)
|
||||
{
|
||||
var currentPoint = request.Points[segmentIndex];
|
||||
var isStart = segmentIndex == 0;
|
||||
var isEnd = segmentIndex == request.Points.Count - 1;
|
||||
|
||||
var geoPoint = new GeoPoint(currentPoint.Latitude, currentPoint.Longitude);
|
||||
|
||||
double? distanceFromPrevious = null;
|
||||
if (segmentIndex > 0)
|
||||
{
|
||||
var prevPoint = request.Points[segmentIndex - 1];
|
||||
var prevGeoPoint = new GeoPoint(prevPoint.Latitude, prevPoint.Longitude);
|
||||
distanceFromPrevious = GeoUtils.CalculateDistance(prevGeoPoint, geoPoint);
|
||||
totalDistance += distanceFromPrevious.Value;
|
||||
}
|
||||
|
||||
var pointType = isStart ? "start" : (isEnd ? "end" : "waypoint");
|
||||
|
||||
allPoints.Add(new RoutePointDto
|
||||
{
|
||||
Latitude = currentPoint.Latitude,
|
||||
Longitude = currentPoint.Longitude,
|
||||
PointType = pointType,
|
||||
SequenceNumber = sequenceNumber++,
|
||||
SegmentIndex = segmentIndex,
|
||||
DistanceFromPrevious = distanceFromPrevious
|
||||
});
|
||||
|
||||
if (!isEnd)
|
||||
{
|
||||
var nextPoint = request.Points[segmentIndex + 1];
|
||||
var startGeo = new GeoPoint(currentPoint.Latitude, currentPoint.Longitude);
|
||||
var endGeo = new GeoPoint(nextPoint.Latitude, nextPoint.Longitude);
|
||||
|
||||
var intermediatePoints = GeoUtils.CalculateIntermediatePoints(startGeo, endGeo, MAX_POINT_SPACING_METERS);
|
||||
|
||||
_logger.LogInformation("Segment {SegmentIndex}: Adding {Count} intermediate points",
|
||||
segmentIndex, intermediatePoints.Count);
|
||||
|
||||
foreach (var intermediateGeo in intermediatePoints)
|
||||
{
|
||||
var prevGeo = sequenceNumber == 1 ? startGeo : new GeoPoint(
|
||||
allPoints[sequenceNumber - 1].Latitude,
|
||||
allPoints[sequenceNumber - 1].Longitude);
|
||||
|
||||
var distFromPrev = GeoUtils.CalculateDistance(prevGeo, intermediateGeo);
|
||||
totalDistance += distFromPrev;
|
||||
|
||||
allPoints.Add(new RoutePointDto
|
||||
{
|
||||
Latitude = intermediateGeo.Lat,
|
||||
Longitude = intermediateGeo.Lon,
|
||||
PointType = "intermediate",
|
||||
SequenceNumber = sequenceNumber++,
|
||||
SegmentIndex = segmentIndex,
|
||||
DistanceFromPrevious = distFromPrev
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Route {RouteId}: Total {TotalPoints} points (original + intermediate), distance {Distance:F2}m",
|
||||
request.Id, allPoints.Count, totalDistance);
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var routeEntity = new RouteEntity
|
||||
{
|
||||
Id = request.Id,
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
RegionSizeMeters = request.RegionSizeMeters,
|
||||
ZoomLevel = request.ZoomLevel,
|
||||
TotalDistanceMeters = totalDistance,
|
||||
TotalPoints = allPoints.Count,
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
};
|
||||
|
||||
await _routeRepository.InsertRouteAsync(routeEntity);
|
||||
|
||||
var pointEntities = allPoints.Select(p => new RoutePointEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
RouteId = request.Id,
|
||||
SequenceNumber = p.SequenceNumber,
|
||||
Latitude = p.Latitude,
|
||||
Longitude = p.Longitude,
|
||||
PointType = p.PointType,
|
||||
SegmentIndex = p.SegmentIndex,
|
||||
DistanceFromPrevious = p.DistanceFromPrevious,
|
||||
CreatedAt = now
|
||||
}).ToList();
|
||||
|
||||
await _routeRepository.InsertRoutePointsAsync(pointEntities);
|
||||
|
||||
_logger.LogInformation("Route {RouteId} created successfully", request.Id);
|
||||
|
||||
return new RouteResponse
|
||||
{
|
||||
Id = routeEntity.Id,
|
||||
Name = routeEntity.Name,
|
||||
Description = routeEntity.Description,
|
||||
RegionSizeMeters = routeEntity.RegionSizeMeters,
|
||||
ZoomLevel = routeEntity.ZoomLevel,
|
||||
TotalDistanceMeters = routeEntity.TotalDistanceMeters,
|
||||
TotalPoints = routeEntity.TotalPoints,
|
||||
Points = allPoints,
|
||||
CreatedAt = routeEntity.CreatedAt,
|
||||
UpdatedAt = routeEntity.UpdatedAt
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<RouteResponse?> GetRouteAsync(Guid id)
|
||||
{
|
||||
var route = await _routeRepository.GetByIdAsync(id);
|
||||
if (route == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var points = await _routeRepository.GetRoutePointsAsync(id);
|
||||
|
||||
return new RouteResponse
|
||||
{
|
||||
Id = route.Id,
|
||||
Name = route.Name,
|
||||
Description = route.Description,
|
||||
RegionSizeMeters = route.RegionSizeMeters,
|
||||
ZoomLevel = route.ZoomLevel,
|
||||
TotalDistanceMeters = route.TotalDistanceMeters,
|
||||
TotalPoints = route.TotalPoints,
|
||||
Points = points.Select(p => new RoutePointDto
|
||||
{
|
||||
Latitude = p.Latitude,
|
||||
Longitude = p.Longitude,
|
||||
PointType = p.PointType,
|
||||
SequenceNumber = p.SequenceNumber,
|
||||
SegmentIndex = p.SegmentIndex,
|
||||
DistanceFromPrevious = p.DistanceFromPrevious
|
||||
}).ToList(),
|
||||
CreatedAt = route.CreatedAt,
|
||||
UpdatedAt = route.UpdatedAt
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user