Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 5
0
        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);
        }
Exemplo n.º 6
0
        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();
        }
Exemplo n.º 7
0
        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();
        }
Exemplo n.º 8
0
        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("Разрывов в треке не найдено.");
            }
        }