bool UpdateFromProvider(CachedDistance distance) { if (ErrorWays.Any(x => x.FromHash == distance.FromGeoHash && x.ToHash == distance.ToGeoHash)) { //logger.Warn("Повторный запрос дистанции с ошибкой расчета. Пропускаем..."); return(false); } //logger.Info("Запрашиваем путь {0}->{1} у сервиса {0}.", distance.FromGeoHash, distance.ToGeoHash, Provider); List <PointOnEarth> points = new List <PointOnEarth>(); double latitude, longitude; CachedDistance.GetLatLon(distance.FromGeoHash, out latitude, out longitude); points.Add(new PointOnEarth(latitude, longitude)); CachedDistance.GetLatLon(distance.ToGeoHash, out latitude, out longitude); points.Add(new PointOnEarth(latitude, longitude)); bool ok = false; if (Provider == DistanceProvider.Osrm) { var result = OsrmMain.GetRoute(points, false, GeometryOverview.Full); ok = result?.Code == "Ok"; if (ok && result.Routes.Any()) { distance.DistanceMeters = result.Routes.First().TotalDistance; distance.TravelTimeSec = result.Routes.First().TotalTimeSeconds; distance.PolylineGeometry = result.Routes.First().RouteGeometry; } } else { var result = SputnikMain.GetRoute(points, false, true); ok = result.Status == 0; if (ok) { distance.DistanceMeters = result.RouteSummary.TotalDistance; distance.TravelTimeSec = result.RouteSummary.TotalTimeSeconds; distance.PolylineGeometry = result.RouteGeometry; } } if (ok) { lock (uow) { AddNewCacheDistance(distance); uow.TrySave(distance); uow.Commit(); } addedCached++; return(true); } ErrorWays.Add(new WayHash(distance.FromGeoHash, distance.ToGeoHash)); totalErrors++; return(false); }
private void RecountMileage() { var pointsToRecalculate = new List <PointOnEarth>(); var pointsToBase = new List <PointOnEarth>(); var baseLat = (double)Entity.GeographicGroups.FirstOrDefault().BaseLatitude.Value; var baseLon = (double)Entity.GeographicGroups.FirstOrDefault().BaseLongitude.Value; decimal totalDistanceTrack = 0; IEnumerable <RouteListItem> completedAddresses = Entity.Addresses.Where(x => x.Status == RouteListItemStatus.Completed); if (!completedAddresses.Any()) { ServicesConfig.InteractiveService.ShowMessage(ImportanceLevel.Warning, "Для МЛ нет завершенных адресов, невозможно расчитать трек", ""); return; } if (completedAddresses.Count() > 1) { foreach (RouteListItem address in Entity.Addresses.OrderBy(x => x.StatusLastUpdate)) { if (address.Status == RouteListItemStatus.Completed) { pointsToRecalculate.Add(new PointOnEarth((double)address.Order.DeliveryPoint.Latitude, (double)address.Order.DeliveryPoint.Longitude)); } } var recalculatedTrackResponse = OsrmMain.GetRoute(pointsToRecalculate, false, GeometryOverview.Full); var recalculatedTrack = recalculatedTrackResponse.Routes.First(); totalDistanceTrack = recalculatedTrack.TotalDistanceKm; } else { var point = Entity.Addresses.First(x => x.Status == RouteListItemStatus.Completed).Order.DeliveryPoint; pointsToRecalculate.Add(new PointOnEarth((double)point.Latitude, (double)point.Longitude)); } pointsToBase.Add(pointsToRecalculate.Last()); pointsToBase.Add(new PointOnEarth(baseLat, baseLon)); pointsToBase.Add(pointsToRecalculate.First()); var recalculatedToBaseResponse = OsrmMain.GetRoute(pointsToBase, false, GeometryOverview.Full); var recalculatedToBase = recalculatedToBaseResponse.Routes.First(); Entity.RecalculatedDistance = decimal.Round(totalDistanceTrack + recalculatedToBase.TotalDistanceKm); }
public virtual RouteResponse CalculateDistanceToBase() { var lastAddress = RouteList.Addresses .Where(x => x.Status == RouteListItemStatus.Completed) .OrderByDescending(x => x.StatusLastUpdate) .FirstOrDefault(); if (lastAddress == null) { DistanceToBase = null; return(null); } var points = new List <PointOnEarth>(); var lastPoint = lastAddress.Order.DeliveryPoint; points.Add(new PointOnEarth(lastPoint.Latitude.Value, lastPoint.Longitude.Value)); //Координаты базы if (lastPoint.District == null) { logger.Warn("Для точки доставки не удалось подобрать часть города. Расчёт расстояния до центра СПб"); points.Add(new PointOnEarth(Constants.CenterOfCityLatitude, Constants.CenterOfCityLongitude)); } else if (lastPoint.District != null && lastPoint.District.GeographicGroup.BaseCoordinatesExist) { var gg = lastPoint.District.GeographicGroup; points.Add(new PointOnEarth((double)gg.BaseLatitude.Value, (double)gg.BaseLongitude.Value)); } else { logger.Error("В подобранной части города не указаны координаты базы"); return(null); } var response = OsrmMain.GetRoute(points, false, GeometryOverview.Simplified); if (response.Code == "Ok") { DistanceToBase = (double)response.Routes.First().TotalDistanceKm; } else { logger.Error("Ошибка при получении расстояния до базы {0}: {1}", response.Code, response.Message); } return(response); }
private CachedDistance LoadDistanceFromService(long fromHash, long toHash) { CachedDistance cachedValue = null; bool ok = false; if (fromHash == toHash) { cachedValue = new CachedDistance { DistanceMeters = 0, TravelTimeSec = 0, FromGeoHash = fromHash, ToGeoHash = toHash }; AddNewCacheDistance(cachedValue); addedCached++; ok = true; } if (!ok) { List <PointOnEarth> points = new List <PointOnEarth> { CachedDistance.GetPointOnEarth(fromHash), CachedDistance.GetPointOnEarth(toHash) }; if (Provider == DistanceProvider.Osrm) { var result = OsrmMain.GetRoute(points, false, GeometryOverview.False); ok = result?.Code == "Ok"; if (ok && result.Routes.Any()) { cachedValue = new CachedDistance { DistanceMeters = result.Routes.First().TotalDistance, TravelTimeSec = result.Routes.First().TotalTimeSeconds, FromGeoHash = fromHash, ToGeoHash = toHash }; } } else { var result = SputnikMain.GetRoute(points, false, false); ok = result.Status == 0; if (ok) { cachedValue = new CachedDistance { DistanceMeters = result.RouteSummary.TotalDistance, TravelTimeSec = result.RouteSummary.TotalTimeSeconds, FromGeoHash = fromHash, ToGeoHash = toHash }; } } } if (MultiTaskLoad && ok) { lock (UoW) { UoW.TrySave(cachedValue as CachedDistance, false); unsavedItems++; if (unsavedItems >= SaveBy) { FlushCache(); } AddNewCacheDistance(cachedValue); addedCached++; } return(cachedValue); } if (ok) { AddNewCacheDistance(cachedValue); addedCached++; return(cachedValue); } ErrorWays.Add(new WayHash(fromHash, toHash)); totalErrors++; //FIXME Реализовать запрос манхентанского расстояния. return(null); }
public static DeliveryPriceNode Calculate(decimal?latitude, decimal?longitude, int?bottlesCount) { IList <District> districts; DeliveryPriceNode result = new DeliveryPriceNode(); //Топливо using (var uow = UnitOfWorkFactory.CreateWithoutRoot("Расчет стоимости доставки")) { var fuel = FuelRepository.GetDefaultFuel(uow); if (fuel == null) { result.ErrorMessage = string.Format("Топливо по умолчанию «АИ-92» не найдено в справочке."); return(result); } fuelCost = (double)fuel.Cost; //Районы districts = ScheduleRestrictionRepository.GetDistrictsWithBorder(uow); result.WageDistrict = deliveryPoint?.District?.WageDistrict?.Name ?? "Неизвестно"; //Координаты if (!latitude.HasValue || !longitude.HasValue) { result.ErrorMessage = string.Format("Не указаны координаты. Невозможно расчитать расстояние."); return(result); } //Расчет растояния if (deliveryPoint == null) { var gg = GeographicGroupRepository.GeographicGroupByCoordinates((double)latitude.Value, (double)longitude.Value, districts); var route = new List <PointOnEarth>(2); if (gg != null && gg.BaseCoordinatesExist) { route.Add(new PointOnEarth((double)gg.BaseLatitude, (double)gg.BaseLongitude)); } else if (gg == null) { //если не найдена часть города, то расстояние считается до его центра route.Add(new PointOnEarth(Constants.CenterOfCityLatitude, Constants.CenterOfCityLongitude)); } else { result.ErrorMessage = "В подобранной части города не указаны координаты базы"; return(result); } route.Add(new PointOnEarth(latitude.Value, longitude.Value)); var osrmResult = OsrmMain.GetRoute(route, false, GeometryOverview.False); if (osrmResult == null) { result.ErrorMessage = "Ошибка на сервере расчета расстояний, невозможно расчитать расстояние."; return(result); } if (osrmResult.Code != "Ok") { result.ErrorMessage = $"Сервер расчета расстояний вернул следующее сообщение: {osrmResult.StatusMessageRus}"; return(result); } distance = osrmResult.Routes[0].TotalDistance / 1000d; } else { distance = (deliveryPoint.DistanceFromBaseMeters ?? 0) / 1000d; } result.Distance = distance.ToString("N1") + " км"; result.Prices = Enumerable.Range(1, 100) .Select( x => new DeliveryPriceRow { Amount = x, Price = PriceByDistance(x).ToString("C2") } ).ToList(); //Расчет цены var point = new Point((double)latitude, (double)longitude); var district = districts.FirstOrDefault(x => x.DistrictBorder.Contains(point)); result.DistrictName = district?.DistrictName ?? string.Empty; result.GeographicGroups = district?.GeographicGroup != null ? district.GeographicGroup.Name : "Неизвестно"; result.ByDistance = district == null || district.PriceType == DistrictWaterPrice.ByDistance; result.WithPrice = (district != null && district.PriceType != DistrictWaterPrice.ByDistance) || (result.ByDistance && bottlesCount.HasValue); if (result.ByDistance) { if (bottlesCount.HasValue) { result.Price = PriceByDistance(bottlesCount.Value).ToString("C2"); } } else if (district?.PriceType == DistrictWaterPrice.FixForDistrict) { result.Price = district.WaterPrice.ToString("C2"); } else if (district?.PriceType == DistrictWaterPrice.Standart) { result.Price = "прайс"; } result.MinBottles = district?.MinBottles.ToString(); result.Schedule = district != null && district.HaveRestrictions ? string.Join(", ", district.GetSchedulesString(true)) : "любой день"; } return(result); }
protected void OnButtonRecountMileageClicked(object sender, EventArgs e) { var pointsToRecalculate = new List <PointOnEarth>(); var pointsToBase = new List <PointOnEarth>(); var baseLat = (double)routeList.GeographicGroups.FirstOrDefault().BaseLatitude.Value; var baseLon = (double)routeList.GeographicGroups.FirstOrDefault().BaseLongitude.Value; decimal totalDistanceTrack = 0; tracksOverlay.Clear(); trackToBaseOverlay.Clear(); IEnumerable <RouteListItem> completedAddresses = routeList.Addresses.Where(x => x.Status == RouteListItemStatus.Completed); if (!completedAddresses.Any()) { ServicesConfig.InteractiveService.ShowMessage(ImportanceLevel.Warning, "Для МЛ нет завершенных адресов, невозможно расчитать трек", ""); return; } if (completedAddresses.Count() > 1) { foreach (RouteListItem address in routeList.Addresses.OrderBy(x => x.StatusLastUpdate)) { if (address.Status == RouteListItemStatus.Completed) { pointsToRecalculate.Add(new PointOnEarth((double)address.Order.DeliveryPoint.Latitude, (double)address.Order.DeliveryPoint.Longitude)); } } var recalculatedTrackResponse = OsrmMain.GetRoute(pointsToRecalculate, false, GeometryOverview.Full); var recalculatedTrack = recalculatedTrackResponse.Routes.First(); var decodedPoints = Polyline.DecodePolyline(recalculatedTrack.RouteGeometry); var pointsRecalculated = decodedPoints.Select(p => new PointLatLng(p.Latitude, p.Longitude)).ToList(); var routeRecalculated = new GMapRoute(pointsRecalculated, "RecalculatedRoute") { Stroke = new Pen(Color.Red) { Width = 4, DashStyle = System.Drawing.Drawing2D.DashStyle.Solid } }; tracksOverlay.Routes.Add(routeRecalculated); totalDistanceTrack = recalculatedTrack.TotalDistanceKm; } else { var point = routeList.Addresses.First(x => x.Status == RouteListItemStatus.Completed).Order.DeliveryPoint; pointsToRecalculate.Add(new PointOnEarth((double)point.Latitude, (double)point.Longitude)); } pointsToBase.Add(pointsToRecalculate.Last()); pointsToBase.Add(new PointOnEarth(baseLat, baseLon)); pointsToBase.Add(pointsToRecalculate.First()); var recalculatedToBaseResponse = OsrmMain.GetRoute(pointsToBase, false, GeometryOverview.Full); var recalculatedToBase = recalculatedToBaseResponse.Routes.First(); var decodedToBase = Polyline.DecodePolyline(recalculatedToBase.RouteGeometry); var pointsRecalculatedToBase = decodedToBase.Select(p => new PointLatLng(p.Latitude, p.Longitude)).ToList(); var routeRecalculatedToBase = new GMapRoute(pointsRecalculatedToBase, "RecalculatedToBase") { Stroke = new Pen(Color.Blue) { Width = 4, DashStyle = System.Drawing.Drawing2D.DashStyle.Solid } }; trackToBaseOverlay.Routes.Add(routeRecalculatedToBase); var text = new List <string> { string.Format("Дистанция трека: {0:N1} км.", totalDistanceTrack), string.Format("Дистанция до базы: {0:N1} км.", recalculatedToBase.TotalDistanceKm), string.Format("Общее расстояние: {0:N1} км.", totalDistanceTrack + recalculatedToBase.TotalDistanceKm) }; labelDistance.LabelProp = string.Join("\n", text); routeList.RecalculatedDistance = decimal.Round(totalDistanceTrack + recalculatedToBase.TotalDistanceKm); UoW.Save(routeList); UoW.Commit(); }
protected void OnButtonRecountMileageClicked(object sender, EventArgs e) { var pointsToRecalculate = new List <PointOnEarth>(); var pointsToBase = new List <PointOnEarth>(); decimal totalDistanceTrack = 0; tracksOverlay.Clear(); trackToBaseOverlay.Clear(); if (routeList.Addresses.Where(x => x.Status == RouteListItemStatus.Completed).Count() > 1) { foreach (RouteListItem address in routeList.Addresses.OrderBy(x => x.StatusLastUpdate)) { if (address.Status == RouteListItemStatus.Completed) { pointsToRecalculate.Add(new PointOnEarth((double)address.Order.DeliveryPoint.Latitude, (double)address.Order.DeliveryPoint.Longitude)); } } var recalculatedTrackResponse = OsrmMain.GetRoute(pointsToRecalculate, false, GeometryOverview.Full); var recalculatedTrack = recalculatedTrackResponse.Routes.First(); var decodedPoints = Polyline.DecodePolyline(recalculatedTrack.RouteGeometry); var pointsRecalculated = decodedPoints.Select(p => new PointLatLng(p.Latitude, p.Longitude)).ToList(); var routeRecalculated = new GMapRoute(pointsRecalculated, "RecalculatedRoute"); routeRecalculated.Stroke = new System.Drawing.Pen(System.Drawing.Color.Red); routeRecalculated.Stroke.Width = 4; routeRecalculated.Stroke.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; tracksOverlay.Routes.Add(routeRecalculated); totalDistanceTrack = recalculatedTrack.TotalDistanceKm; } else { var point = routeList.Addresses.Where(x => x.Status == RouteListItemStatus.Completed).First().Order.DeliveryPoint; pointsToRecalculate.Add(new PointOnEarth((double)point.Latitude, (double)point.Longitude)); } pointsToBase.Add(pointsToRecalculate.Last()); pointsToBase.Add(new PointOnEarth(Constants.BaseLatitude, Constants.BaseLongitude)); pointsToBase.Add(pointsToRecalculate.First()); var recalculatedToBaseResponse = OsrmMain.GetRoute(pointsToBase, false, GeometryOverview.Full); var recalculatedToBase = recalculatedToBaseResponse.Routes.First(); var decodedToBase = Polyline.DecodePolyline(recalculatedToBase.RouteGeometry); var pointsRecalculatedToBase = decodedToBase.Select(p => new PointLatLng(p.Latitude, p.Longitude)).ToList(); var routeRecalculatedToBase = new GMapRoute(pointsRecalculatedToBase, "RecalculatedToBase"); routeRecalculatedToBase.Stroke = new System.Drawing.Pen(System.Drawing.Color.Blue); routeRecalculatedToBase.Stroke.Width = 4; routeRecalculatedToBase.Stroke.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; trackToBaseOverlay.Routes.Add(routeRecalculatedToBase); var text = new List <string>(); text.Add(String.Format("Дистанция трека: {0:N1} км.", totalDistanceTrack)); text.Add(String.Format("Дистанция до базы: {0:N1} км.", recalculatedToBase.TotalDistanceKm)); text.Add(String.Format("Общее расстояние: {0:N1} км.", totalDistanceTrack + recalculatedToBase.TotalDistanceKm)); labelDistance.LabelProp = String.Join("\n", text); routeList.RecalculatedDistance = totalDistanceTrack + recalculatedToBase.TotalDistanceKm; UoW.Save(routeList); UoW.Commit(); }
protected void OnButtonFindGapClicked(object sender, EventArgs e) { trackOnGapOverlay.Clear(); tracksDistance.RemoveAll(x => x.Id == "MissingTrack"); string message = "Найдены разрывы в треке:"; double replacedDistance = 0; TrackPoint lastPoint = null; foreach (var point in track.TrackPoints) { if (lastPoint == null) { lastPoint = point; continue; } var distance = GMapProviders.EmptyProvider.Projection.GetDistance( new PointLatLng(lastPoint.Latitude, lastPoint.Longitude), new PointLatLng(point.Latitude, point.Longitude)); if (distance > 0.5) { _logger.Info("Найден разрыв в треке расстоянием в {0}", distance); message += string.Format("\n* разрыв c {1:t} по {2:t} — {0:N1} км.", distance, lastPoint.TimeStamp, point.TimeStamp ); replacedDistance += distance; var addressesByCompletion = routeList.Addresses .Where(x => x.Status == RouteListItemStatus.Completed) .OrderBy(x => x.StatusLastUpdate) .ToList(); RouteListItem addressBeforeGap = addressesByCompletion.LastOrDefault(x => x.StatusLastUpdate < lastPoint.TimeStamp.AddMinutes(2)); RouteListItem addressAfterGap = addressesByCompletion.FirstOrDefault(x => x.StatusLastUpdate > point.TimeStamp.AddMinutes(-2)); var beforeIndex = addressBeforeGap == null ? -1 : addressesByCompletion.IndexOf(addressBeforeGap); var afterIndex = addressAfterGap == null ? addressesByCompletion.Count : addressesByCompletion.IndexOf(addressAfterGap); var routePoints = new List <PointOnEarth> { new PointOnEarth(lastPoint.Latitude, lastPoint.Longitude) }; if (afterIndex - beforeIndex > 1) { var throughAddress = addressesByCompletion.GetRange(beforeIndex + 1, afterIndex - beforeIndex - 1); _logger.Info("В разрыве найдены выполенные адреса порядковый(е) номер(а) {0}", String.Join(", ", throughAddress.Select(x => x.IndexInRoute))); routePoints.AddRange( throughAddress.Where(x => x.Order?.DeliveryPoint?.Latitude != null && x.Order?.DeliveryPoint?.Longitude != null) .Select(x => new PointOnEarth(x.Order.DeliveryPoint.Latitude.Value, x.Order.DeliveryPoint.Longitude.Value))); message += $" c выполненными адресами({beforeIndex + 2}-{afterIndex}) п/п в МЛ " + String.Join(", ", throughAddress.Select(x => x.IndexInRoute)); } routePoints.Add(new PointOnEarth(point.Latitude, point.Longitude)); var missedTrack = OsrmMain.GetRoute(routePoints, false, GeometryOverview.Simplified); if (missedTrack == null) { MessageDialogHelper.RunErrorDialog("Не удалось получить ответ от сервиса \"Спутник\""); return; } if (missedTrack.Code != "Ok") { MessageDialogHelper.RunErrorDialog("Cервис \"Спутник\" сообщил об ошибке {0}: {1}", missedTrack.Code, missedTrack.StatusMessageRus); return; } var decodedPoints = Polyline.DecodePolyline(missedTrack.Routes.First().RouteGeometry); var points = decodedPoints.Select(p => new PointLatLng(p.Latitude * 0.1, p.Longitude * 0.1)).ToList(); var route = new GMapRoute(points, "MissedRoute") { Stroke = new Pen(Color.DarkMagenta) { Width = 4, DashStyle = System.Drawing.Drawing2D.DashStyle.Dot } }; trackOnGapOverlay.Routes.Add(route); } lastPoint = point; } if (trackOnGapOverlay.Routes.Count > 0) { var distanceLayout = MakeDistanceLayout(trackOnGapOverlay.Routes.ToArray()); distanceLayout.Id = "MissingTrack"; tracksDistance.Add(distanceLayout); var oldDistance = track.DistanceEdited ? trackRoute.Distance : track.Distance; var missedRouteDistance = trackOnGapOverlay.Routes.Sum(x => x.Distance); var newDistance = oldDistance - replacedDistance + missedRouteDistance; var diffDistance = newDistance - oldDistance; message += $"\n Старая длинна трека:{oldDistance:N1} км." + $"\n Новая длинна трека: {newDistance:N1} км.(+{diffDistance:N1})" + "\n Сохранить изменения длинны трека?"; if (MessageDialogHelper.RunQuestionDialog(message)) { track.Distance = newDistance; track.DistanceEdited = true; UoW.Save(track); UoW.Commit(); UpdateDistanceLabel(); } } else { MessageDialogHelper.RunInfoDialog("Разрывов в треке не найдено."); } }