/// <summary> /// Sets directions. /// </summary> /// <param name="dirs">Directions.</param> /// <param name="stops">Stop datas as direction keeper (for update).</param> private static void _SetDirections(IList <Direction[]> dirs, IEnumerable <StopData> stops) { Debug.Assert(stops != null); Debug.Assert(dirs != null); // sort stops respecting sequence var sortedStops = new List <StopData>(stops); SolveHelper.SortBySequence(sortedStops); int nDir = 0; // starts from fisrt, 0 element do not have directions for (int index = 1; index < sortedStops.Count; ++index) { StopData stop = sortedStops[index]; if (stop.StopType != StopType.Lunch) { if (nDir >= dirs.Count) { throw new RouteException(Properties.Messages.Error_InvalidDirectionsNumber); // exception } Direction[] stopDirs = dirs[nDir]; // set path if (_IsDirGeometryValid(stopDirs)) { // build path from compact geometry stop.Path = _BuildPath(stopDirs); } else { // NOTE: in some cases compact geometry is not set, for example when // route contains one order which point is the same as start and end // locations points // set geometry of associated object var gc = stop.AssociatedObject as IGeocodable; if (gc != null && gc.IsGeocoded) { stop.Path = new Polyline(new Point[] { (Point)gc.GeoLocation }); } else { throw new RouteException(Properties.Messages.Error_BuildStopPathFailed); // exception } } // set directions stop.Directions = stopDirs; ++nDir; } } }
/// <summary> /// Method do merge of every Lunch directions with Next stop directions. /// Not maneuver, Break Arrive and Break Depart directions are passed. /// </summary> /// <param name="dirs">Directions.</param> /// <param name="stops">Stops.</param> /// <returns>Merged directions.</returns> private static IList <Direction[]> _MergeBreaksDirections( IList <DirectionEx[]> dirs, IEnumerable <StopData> stops) { Debug.Assert(dirs != null); Debug.Assert(stops != null); // Sort stops respecting sequence. var sortedStops = new List <StopData>(stops); SolveHelper.SortBySequence(sortedStops); int stopIndex = 0; var lunchDirections = new List <DirectionEx>(); // Flag is needed for cases when breaks goes one by one. bool isLunchFoundBefore = false; // Flag means that route started from Lunch (route with Virtual Depot). bool lunchAtStart = true; if (sortedStops[0].StopType != StopType.Lunch) { lunchAtStart = false; } // Start from first element since zero element doesn't have directions. for (int index = 1; index < sortedStops.Count; ++index) { if (stopIndex >= dirs.Count) { throw new RouteException( Properties.Messages.Error_InvalidDirectionsNumber); } DirectionEx[] stopDirections = dirs[stopIndex]; // Find all Lunch Stops. if (sortedStops[index].StopType == StopType.Lunch) { if (isLunchFoundBefore) { // This lunch goes after another one: merge lunch directions. lunchDirections.AddRange( _FilterManeuverDirections(stopDirections, StopManeuverType.Stop, StopManeuverType.Depart)); // Remove current lunch directions (if it is), to stay with merged ones. if (_IsBreakDirection(dirs[stopIndex])) { dirs.RemoveAt(stopIndex); } } else { if (lunchAtStart) { // First lunch is first on route at all: get only Maneuver directions. lunchDirections = _FilterManeuverDirections(stopDirections, StopManeuverType.Stop, StopManeuverType.Depart); } else { // First lunch in stops queue: get only Maneuver and Depart directions. lunchDirections = _FilterManeuverDirections(stopDirections, StopManeuverType.Stop); } // Remove current lunch directions, to stay with merged ones. dirs.RemoveAt(stopIndex); } // Set flag to consider case when breaks goes one by one. isLunchFoundBefore = true; } // Remove Depart of last Break and merge all found Lunch directions // with stop directions. else { lunchAtStart = false; if (isLunchFoundBefore) { // Final lunch direction: merge lunch and stops directions. var stopsWithoutDepart = _FilterManeuverDirections(stopDirections, StopManeuverType.Depart); lunchDirections.AddRange(stopsWithoutDepart); dirs[stopIndex] = lunchDirections.ToArray(); lunchDirections.Clear(); isLunchFoundBefore = false; } ++stopIndex; } } return(_ConvertToDirectionsWithoutType(dirs)); }
/////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Builds stop features. /// </summary> /// <param name="stops">Stops.</param> /// <returns>Created route stops recordset for stops.</returns> private RouteStopsRecordSet _BuildStopFeatures(IList <StopData> stops) { Debug.Assert(stops != null); // Sort stops respecting sequence. var sortedStops = new List <StopData>(stops); SolveHelper.SortBySequence(sortedStops); Debug.Assert(_context != null); SolveHelper.ConsiderArrivalDelayInStops( _context.SolverSettings.ArriveDepartDelay, sortedStops); // Format impedance attribute name. string impedanceAttrName = null; if (!string.IsNullOrEmpty(_context.NetworkDescription.ImpedanceAttributeName)) { impedanceAttrName = string.Format(IMPEDANCE_ATTR_FORMAT, _context.NetworkDescription.ImpedanceAttributeName); } var features = new List <GPFeature>(); for (int index = 0; index < sortedStops.Count; ++index) { var feature = new GPFeature(); // Attributes. feature.Attributes = new AttrDictionary(); StopData sd = sortedStops[index]; Guid objectId = Guid.Empty; if (sd.AssociatedObject != null) { objectId = sd.AssociatedObject.Id; } feature.Attributes.Add(NAAttribute.NAME, objectId.ToString()); feature.Attributes.Add(NAAttribute.ROUTE_NAME, sd.RouteId.ToString()); // Effective time window. DateTime?twStart = null; DateTime?twEnd = null; _GetEffectiveTW(sd, out twStart, out twEnd); // NOTE: ignore result feature.Attributes.Add(NAAttribute.TW_START, _FormatStopTime(twStart)); feature.Attributes.Add(NAAttribute.TW_END, _FormatStopTime(twEnd)); // Service time. if (impedanceAttrName != null) { feature.Attributes.Add(impedanceAttrName, sd.TimeAtStop); } var geometry = new GeometryHolder(); geometry.Value = sd.Geometry; if (sd.StopType == StopType.Lunch) { var actualStop = SolveHelper.GetActualLunchStop(sortedStops, index); geometry.Value = actualStop.Geometry; } // Set curb approach. var curbApproach = CurbApproachConverter.ToNACurbApproach( _context.SolverSettings.GetOrderCurbApproach()); if (sd.StopType == StopType.Location) { curbApproach = CurbApproachConverter.ToNACurbApproach( _context.SolverSettings.GetDepotCurbApproach()); } feature.Attributes.Add(NAAttribute.CURB_APPROACH, (int)curbApproach); feature.Geometry = geometry; features.Add(feature); } var rs = new RouteStopsRecordSet(); rs.Features = features.ToArray(); // TODO: will be changed later when support custom AddLocations tool rs.DoNotLocateOnRestrictedElements = _context.SolverSettings.ExcludeRestrictedStreets; return(rs); }