Files
Oleksandr Bezdieniezhnykh 6f23120c49 [AZ-364] [AZ-360] Refactor C11+C08: decompose RouteProcessingService
Extracts RouteRegionMatcher, RouteCsvWriter, RouteSummaryWriter,
RouteImageRenderer, TilesZipBuilder, RegionFileCleaner from the
~750-LOC RouteProcessingService god-class. Moves TileInfo to its
own file as a sealed record. Replaces IServiceProvider scope-
locator with a direct IRegionService injection (folds AZ-360 / C08).
Updates DI registration and tests.

Tests: 133 / 133 unit + 5 / 5 smoke green; integration suite exit 0.
Pixel-equivalent stitched route image and byte-equivalent CSV /
summary / ZIP outputs verified through the smoke run.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 03:12:49 +03:00

40 lines
1.4 KiB
C#

using SatelliteProvider.Common.DTO;
using SatelliteProvider.Common.Utils;
using SatelliteProvider.DataAccess.Models;
namespace SatelliteProvider.Services.RouteManagement;
// AZ-364 / C11: extracted from RouteProcessingService.MatchRegionsToRoutePoints.
// Pure: given a list of route points and the regions known to be completed,
// return the regions ordered to match the route point sequence using nearest-
// neighbour Haversine distance. Each region is consumed at most once.
public class RouteRegionMatcher
{
public List<RegionEntity> Match(
IReadOnlyList<RoutePointEntity> routePoints,
IReadOnlyList<RegionEntity> regions)
{
ArgumentNullException.ThrowIfNull(routePoints);
ArgumentNullException.ThrowIfNull(regions);
var orderedRegions = new List<RegionEntity>(routePoints.Count);
var availableRegions = new List<RegionEntity>(regions);
foreach (var point in routePoints)
{
var pointGeo = new GeoPoint(point.Latitude, point.Longitude);
var matchedRegion = availableRegions
.OrderBy(r => GeoUtils.CalculateDistance(pointGeo, new GeoPoint(r.Latitude, r.Longitude)))
.FirstOrDefault();
if (matchedRegion != null)
{
orderedRegions.Add(matchedRegion);
availableRegions.Remove(matchedRegion);
}
}
return orderedRegions;
}
}