using System.IO; using Azaion.Common.DTO; using Microsoft.Extensions.Options; namespace Azaion.Common.Services; public interface IGpsMatcherService { Task RunGpsMatching(string userRouteDir, double initialLatitude, double initialLongitude, CancellationToken detectToken = default); void StopGpsMatching(); Task SetGpsResult(GPSMatcherResultEvent result, CancellationToken detectToken = default); Task FinishGPS(GPSMatcherFinishedEvent notification, CancellationToken cancellationToken); } public class GpsMatcherService(IGpsMatcherClient gpsMatcherClient, ISatelliteDownloader satelliteTileDownloader, IOptions dirConfig) : IGpsMatcherService { private readonly DirectoriesConfig _dirConfig = dirConfig.Value; private const int ZOOM_LEVEL = 18; private const int POINTS_COUNT = 10; private const int DISTANCE_BETWEEN_POINTS_M = 100; private const double SATELLITE_RADIUS_M = DISTANCE_BETWEEN_POINTS_M * (POINTS_COUNT + 1); private string _routeDir = ""; private string _userRouteDir = ""; private List _allRouteImages = new(); private Dictionary _currentRouteImages = new(); private double _currentLat; private double _currentLon; private CancellationToken _detectToken; private int _currentIndex; public async Task RunGpsMatching(string userRouteDir, double initialLatitude, double initialLongitude, CancellationToken detectToken = default) { _routeDir = Path.Combine(SecurityConstants.EXTERNAL_GPS_DENIED_FOLDER, _dirConfig.GpsRouteDirectory); _userRouteDir = userRouteDir; _allRouteImages = Directory.GetFiles(userRouteDir) .OrderBy(x => x).ToList(); _currentLat = initialLatitude; _currentLon = initialLongitude; _detectToken = detectToken; await StartMatchingRound(0); } private async Task StartMatchingRound(int startIndex) { //empty route dir if (Directory.Exists(_routeDir)) Directory.Delete(_routeDir, true); Directory.CreateDirectory(_routeDir); _currentRouteImages = _allRouteImages .Skip(startIndex) .Take(POINTS_COUNT) .Select((fullName, index) => { var filename = Path.GetFileName(fullName); File.Copy(Path.Combine(_userRouteDir, filename), Path.Combine(_routeDir, filename)); return new { Filename = Path.GetFileNameWithoutExtension(fullName), Index = startIndex + index }; }) .ToDictionary(x => x.Filename, x => x.Index); await satelliteTileDownloader.GetTiles(_currentLat, _currentLon, SATELLITE_RADIUS_M, ZOOM_LEVEL, _detectToken); await gpsMatcherClient.StartMatching(new StartMatchingEvent { ImagesCount = POINTS_COUNT, Latitude = _currentLat, Longitude = _currentLon, SatelliteImagesDir = _dirConfig.GpsSatDirectory, RouteDir = _dirConfig.GpsRouteDirectory }); } public void StopGpsMatching() { gpsMatcherClient.Stop(); } public async Task SetGpsResult(GPSMatcherResultEvent result, CancellationToken detectToken = default) { _currentIndex = _currentRouteImages[result.Image]; _currentRouteImages.Remove(result.Image); _currentLat = result.Latitude; _currentLon = result.Longitude; await Task.CompletedTask; } public async Task FinishGPS(GPSMatcherFinishedEvent notification, CancellationToken cancellationToken) { if (_currentRouteImages.Count == 0 && _currentIndex < _allRouteImages.Count) await StartMatchingRound(_currentIndex); } }