/////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// public IList<RouteResult> Convert(GPRouteResult gpResult, BatchRouteSolveResponse routeResponse, SubmitVrpJobRequest request) { Debug.Assert(gpResult != null); Debug.Assert(request != null); var directionsFeatures = default(ILookup<Guid, GPFeature>); if (gpResult.Directions != null) { directionsFeatures = gpResult.Directions.Features.ToLookup(feature => _AttrToObjectId(NAAttribute.ROUTE_NAME, feature.Attributes)); } var hasDirections = routeResponse != null || directionsFeatures != null; // route results var results = new List<RouteResult>(); foreach (GPFeature feature in gpResult.Routes.Features) { // check violation status if (!_IsObjectViolated(feature)) { // route id Guid routeId = _AttrToObjectId(NAAttribute.NAME, feature.Attributes); // find route Route route = DataObjectHelper.FindObjectById<Route>(routeId, _schedule.Routes); if (route == null) { string message = Properties.Messages.Error_InvalidGPFeatureMapping; throw new RouteException(message); // exception } List<StopData> stops = _GetRouteStops(gpResult, route, request); // Get directions for route if (stops.Count != 0 && hasDirections) { var directions = default(IEnumerable<DirectionEx>); if (routeResponse != null) { // Use Routing service directions. var routeDirs = _FindRouteDirections(routeResponse, routeId); if (routeDirs == null || !_ContainsDirFeatures(routeDirs)) { // route has stops, so there must be directions throw _CreateNoDirectionsError(routeId); } directions = routeDirs.Features .Select(DirectionsHelper.ConvertToDirection) .ToList(); } else if (directionsFeatures != null) { // Use VRP service directions var directionFeatures = directionsFeatures[routeId]; // WORKAROUND: pass first stop geometry as geometry whihc will be used // in case if directions has no geometry. _FixGeometries(directionFeatures, routeId, stops.First().Geometry as GPPoint); directions = directionFeatures .Select(DirectionsHelper.ConvertToDirection) .ToList(); } // We should have either Routing or VRP service directions here. Debug.Assert(directions != null); DirectionsHelper.SetDirections(stops, directions); } // set order sequence values _SetOrderSequence(stops); // add route result results.Add(_CreateRouteResult(feature, route, stops)); } } return results; }
/////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Method gets stops collection from features collection. /// </summary> /// <param name="gpResult">GP Route result from server.</param> /// <param name="route">Route to get route info.</param> /// <param name="request">Vrp request.</param> /// <returns></returns> private List<StopData> _GetRouteStops( GPRouteResult gpResult, Route route, SubmitVrpJobRequest request) { Debug.Assert(gpResult != null); Debug.Assert(route != null); var stopsByType = gpResult.Stops.Features .ToLookup(feature => feature.Attributes.Get<NAStopType>(NAAttribute.StopType)); var stops = new List<StopData>(); // process orders stops.AddRange(_GetOrderStops(stopsByType[NAStopType.Order], route)); // process breaks stops.AddRange(_GetBreakStops(stopsByType[NAStopType.Break], route)); var renewals = request.Renewals == null ? Enumerable.Empty<GPFeature>() : request.Renewals.Features; // process depots stops.AddRange(_GetDepotStops( stopsByType[NAStopType.Depot], route, renewals)); SolveHelper.SortBySequence(stops); if (!stops.Any()) { return stops; } var isDepot = Functional.MakeLambda( (StopData stop) => stop.StopType == StopType.Location); var startingDepot = stops.FirstOrDefault(isDepot); if (startingDepot != null) { startingDepot.TimeAtStop = route.TimeAtStart; } var endingDepot = stops.LastOrDefault(isDepot); if (endingDepot != null) { endingDepot.TimeAtStop = route.TimeAtEnd; } return stops; }