using AsbCloudApp.Data.Trajectory; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.Trajectory; abstract class TrajectoryBaseService<TGeo, TCartesian> where TGeo : TrajectoryGeoDto where TCartesian : TrajectoryCartesianDto, new() { private readonly ITrajectoryRepository<TGeo> repository; public TrajectoryBaseService(ITrajectoryRepository<TGeo> repository) { this.repository = repository; } protected class Location { public double North { get; set; } public double East { get; set; } public double Depth { get; set; } public TrajectoryGeoDto Trajectory { get; set; } = null!; } public async Task<IEnumerable<TCartesian>?> GetAsync(int idWell, CancellationToken token) { var geoCoords = await repository.GetAsync(idWell, token); var locs = TrajectoryBaseService<TGeo, TCartesian>.GetTrajectoryVisualisation(geoCoords); var dtos = locs.Select(l => Convert(l)); return dtos; } private static IEnumerable<Location> GetTrajectoryVisualisation(IEnumerable<TrajectoryGeoDto> geoCoordinates) { var geoCoordinatesLength = geoCoordinates.Count(); if (geoCoordinatesLength < 2) return Enumerable.Empty<Location>(); var cartesianCoordinates = new Location[geoCoordinatesLength]; cartesianCoordinates[0] = new(); var geoCoordinatesArray = geoCoordinates.OrderBy(c => c.WellboreDepth).ToArray(); for (var i = 1; i < geoCoordinatesLength; i++) { var coordinates = TrajectoryBaseService<TGeo, TCartesian>.Calculate(cartesianCoordinates[i - 1], geoCoordinatesArray[i - 1], geoCoordinatesArray[i]); cartesianCoordinates[i] = coordinates; } return cartesianCoordinates; } protected static Location Calculate(Location prevLocation, TrajectoryGeoDto prev, TrajectoryGeoDto current) { var intervalGeoParams = prev; var deltaWellLength = current.WellboreDepth - intervalGeoParams.WellboreDepth; var projectionLengthToXYSurface = deltaWellLength * Math.Sin(intervalGeoParams.ZenithAngle * Math.PI / 180); var dDepth = deltaWellLength * Math.Cos(intervalGeoParams.ZenithAngle * Math.PI / 180); var dNorth = projectionLengthToXYSurface * Math.Sin(intervalGeoParams.AzimuthGeo * Math.PI / 180); var dEast = projectionLengthToXYSurface * Math.Cos(intervalGeoParams.AzimuthGeo * Math.PI / 180); return new() { North = prevLocation.North + dNorth, East = prevLocation.East + dEast, Depth = prevLocation.Depth + dDepth, Trajectory = current, }; } protected virtual TCartesian Convert(Location location) { var result = new TCartesian() { X = location.East, Y = -location.Depth, Z = -location.North, }; return result; } } class TrajectoryPlanService: TrajectoryBaseService<TrajectoryGeoPlanDto, TrajectoryCartesianPlanDto> { public TrajectoryPlanService(ITrajectoryEditableRepository<TrajectoryGeoPlanDto> repository) :base(repository) {} protected override TrajectoryCartesianPlanDto Convert(Location location) { var result = base.Convert(location); if (location.Trajectory is TrajectoryGeoPlanDto trajectoryPlan) { result.Radius = trajectoryPlan.Radius; result.Comment = trajectoryPlan.Comment; } return result; } } class TrajectoryFactService : TrajectoryBaseService<TrajectoryGeoFactDto, TrajectoryCartesianFactDto> { public TrajectoryFactService(ITrajectoryEditableRepository<TrajectoryGeoFactDto> repository) : base(repository) { } } class TrajectoryNnbService : TrajectoryBaseService<TrajectoryGeoFactDto, TrajectoryCartesianFactDto> { public TrajectoryNnbService(ITrajectoryNnbRepository repository) : base(repository) { } } public class TrajectoryService { private readonly TrajectoryPlanService trajectoryPlanService; private readonly TrajectoryFactService trajectoryFactService; private readonly TrajectoryNnbService trajectoryNnbService; public TrajectoryService( ITrajectoryEditableRepository<TrajectoryGeoPlanDto> planRepository, ITrajectoryEditableRepository<TrajectoryGeoFactDto> factRepository, ITrajectoryNnbRepository nnbRepository) { trajectoryPlanService = new TrajectoryPlanService(planRepository); trajectoryFactService = new TrajectoryFactService(factRepository); trajectoryNnbService = new TrajectoryNnbService(nnbRepository); } /// <summary> /// Получение плановой и фактической траектории по скважине /// </summary> /// <param name="idWell">ключ скважины</param> /// <param name="token"></param> /// <returns></returns> public async Task<TrajectoryPlanFactDto<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>>> GetTrajectoryCartesianAsync(int idWell, CancellationToken token) { var result = new TrajectoryPlanFactDto<IEnumerable<TrajectoryCartesianPlanDto>, IEnumerable<TrajectoryCartesianFactDto>> { Plan = await trajectoryPlanService.GetAsync(idWell, token), FactManual = await trajectoryFactService.GetAsync(idWell, token), FactNnb = await trajectoryNnbService.GetAsync(idWell, token) }; return result; } }