/// <summary> /// Fills time window properties for the specified tracking stop using data from /// the specified stop. /// </summary> /// <param name="stop">The reference to the stop object to read time window properties /// from.</param> /// <param name="plannedDate">The date/time when time window should be applied.</param> /// <param name="trackingStop">The reference to the tracking stop object to /// fill time window properties for.</param> private static void _FillTimeWindows( Stop stop, DateTime plannedDate, DM.Stop trackingStop) { Debug.Assert(stop != null); switch (stop.StopType) { case StopType.Order: { // Use time windows from Order associated with the stop. var order = (Order)stop.AssociatedObject; var timeWindow = order.TimeWindow.ToDateTime(plannedDate); trackingStop.TimeWindowStart1 = timeWindow.Item1.ToUniversalTime(); trackingStop.TimeWindowEnd1 = timeWindow.Item2.ToUniversalTime(); timeWindow = order.TimeWindow2.ToDateTime(plannedDate); trackingStop.TimeWindowStart2 = timeWindow.Item1.ToUniversalTime(); trackingStop.TimeWindowEnd2 = timeWindow.Item2.ToUniversalTime(); } break; case StopType.Location: { // Use time windows from Location associated with the stop. var location = (Location)stop.AssociatedObject; var timeWindow = location.TimeWindow.ToDateTime(plannedDate); trackingStop.TimeWindowStart1 = timeWindow.Item1.ToUniversalTime(); trackingStop.TimeWindowEnd1 = timeWindow.Item2.ToUniversalTime(); } break; case StopType.Lunch: { // Use time windows from Break associated with the stop's Route. var lunch = stop.Route.Breaks .OfType <TimeWindowBreak>() .Where(item => item.Duration > 0.0) .FirstOrDefault(); if (lunch != null) { // TODO: implement good breaks support. trackingStop.TimeWindowStart1 = null; trackingStop.TimeWindowEnd1 = null; } } break; default: break; } }
/// <summary> /// Creates tracking stops for the specified stops collection. /// </summary> /// <param name="deviceId">The object ID of the device to create stops for.</param> /// <param name="currentVersion">The version of stops to be created.</param> /// <param name="plannedDate">The date/time to create stops for.</param> /// <param name="routeStops">A collection of route stops sorted by their sequence /// number to create tracking stops for.</param> /// <returns>A collection of tracking stops corresponding to the specified route /// stops.</returns> private IEnumerable <DM.Stop> _CreateTrackingStops( long deviceId, int currentVersion, DateTime plannedDate, IList <Stop> routeStops) { Debug.Assert(routeStops != null); var propertyFilter = Functional.MakeLambda((string _) => true); var stopInfos = RouteExporter.ExportStops( routeStops, _project.CapacitiesInfo, _project.OrderCustomPropertiesInfo, _geocoder.AddressFields, _solver, propertyFilter).ToList(); var trackingStops = routeStops .Select((stop, index) => { var stopInfo = stopInfos[index]; var objectId = 0; var trackingStop = new DM.Stop { ObjectID = objectId, Version = currentVersion, // Name of the stop can exceed 50 chars, so we need to trim excess chars. Name = _TrimStringField(stopInfo.Name), Location = stopInfo.Location, OrderType = stopInfo.OrderType, Priority = stopInfo.Priority, CurbApproach = stopInfo.CurbApproach, Address = _ToCollection(stopInfo.Address), Capacities = _ToCollection(stopInfo.Capacities), CustomOrderProperties = _ToCollection(stopInfo.CustomOrderProperties), Type = _GetStopType(stop, routeStops), PlannedDate = plannedDate, DeviceID = deviceId, SequenceNumber = stop.SequenceNumber, ServiceTime = (int)stop.TimeAtStop, MaxViolationTime = stopInfo.MaxViolationTime, ArriveTime = stopInfo.ArriveTime.ToUniversalTime(), }; _FillTimeWindows(stop, plannedDate, trackingStop); return(trackingStop); }); return(trackingStops); }
/// <summary> /// Applies arrival delay to stops: /// Adds Arrival Delay value to Service Time value for every stop, /// which has unique locations except last one stop. /// </summary> /// <param name="arrivalDelay">Arrival delay value.</param> /// <param name="stops">Stops collection to update.</param> internal static void ApplyArrivalDelayToStops(int arrivalDelay, IList <DM.Stop> stops) { Debug.Assert(stops != null); if (stops.Count == 0) { return; } // Get last stop. int startIndex = stops.Count - 1; DM.Stop last = stops[startIndex]; // Remember location point from last stop. Point?prevStopPoint = null; if (DM.StopType.Break != last.Type) { prevStopPoint = last.Location.GetValueOrDefault(); } // Start from previous stop, // because we don't need to consider Arrival Delay at last one. --startIndex; for (int index = startIndex; index >= 0; index--) { DM.Stop stop = stops[index]; Point currentPoint = stop.Location.GetValueOrDefault(); // Apply arrival delay for every unique location. if (DM.StopType.Break == stop.Type || currentPoint == prevStopPoint) { continue; } stop.ServiceTime += arrivalDelay; prevStopPoint = currentPoint; } }
/// <summary> /// Gets tracking server stop type for the specified stop. /// </summary> /// <param name="stop">The reference to the stop object to get /// tracking server stop type for.</param> /// <param name="sortedStops">The reference to the list of route stops /// sorted by their sequence number.</param> /// <returns>Tracking server stop type.</returns> private DM.StopType _GetStopType(Stop stop, IList<Stop> sortedStops) { Debug.Assert(stop != null); Debug.Assert(sortedStops != null); switch (stop.StopType) { case StopType.Order: return DM.StopType.Order; case StopType.Lunch: return DM.StopType.Break; case StopType.Location: if (stop == sortedStops.First()) { return DM.StopType.StartLocation; } else if (stop == sortedStops.Last()) { return DM.StopType.FinishLocation; } else { return DM.StopType.RenewalLocation; } default: Debug.Assert(false); return DM.StopType.Order; } }
/// <summary> /// Creates tracking stops for the specified stops collection. /// </summary> /// <param name="deviceId">The object ID of the device to create stops for.</param> /// <param name="currentVersion">The version of stops to be created.</param> /// <param name="plannedDate">The date/time to create stops for.</param> /// <param name="routeStops">A collection of route stops sorted by their sequence /// number to create tracking stops for.</param> /// <returns>A collection of tracking stops corresponding to the specified route /// stops.</returns> private IEnumerable<DM.Stop> _CreateTrackingStops( long deviceId, int currentVersion, DateTime plannedDate, IList<Stop> routeStops) { Debug.Assert(routeStops != null); var propertyFilter = Functional.MakeLambda((string _) => true); var stopInfos = RouteExporter.ExportStops( routeStops, _project.CapacitiesInfo, _project.OrderCustomPropertiesInfo, _geocoder.AddressFields, _solver, propertyFilter).ToList(); var trackingStops = routeStops .Select((stop, index) => { var stopInfo = stopInfos[index]; var objectId = 0; var trackingStop = new DM.Stop { ObjectID = objectId, Version = currentVersion, // Name of the stop can exceed 50 chars, so we need to trim excess chars. Name = _TrimStringField(stopInfo.Name), Location = stopInfo.Location, OrderType = stopInfo.OrderType, Priority = stopInfo.Priority, CurbApproach = stopInfo.CurbApproach, Address = _ToCollection(stopInfo.Address), Capacities = _ToCollection(stopInfo.Capacities), CustomOrderProperties = _ToCollection(stopInfo.CustomOrderProperties), Type = _GetStopType(stop, routeStops), PlannedDate = plannedDate, DeviceID = deviceId, SequenceNumber = stop.SequenceNumber, ServiceTime = (int)stop.TimeAtStop, MaxViolationTime = stopInfo.MaxViolationTime, ArriveTime = stopInfo.ArriveTime.ToUniversalTime(), }; _FillTimeWindows(stop, plannedDate, trackingStop); return trackingStop; }); return trackingStops; }
/// <summary> /// Fills time window properties for the specified tracking stop using data from /// the specified stop. /// </summary> /// <param name="stop">The reference to the stop object to read time window properties /// from.</param> /// <param name="plannedDate">The date/time when time window should be applied.</param> /// <param name="trackingStop">The reference to the tracking stop object to /// fill time window properties for.</param> private static void _FillTimeWindows( Stop stop, DateTime plannedDate, DM.Stop trackingStop) { Debug.Assert(stop != null); switch (stop.StopType) { case StopType.Order: { // Use time windows from Order associated with the stop. var order = (Order)stop.AssociatedObject; var timeWindow = order.TimeWindow.ToDateTime(plannedDate); trackingStop.TimeWindowStart1 = timeWindow.Item1.ToUniversalTime(); trackingStop.TimeWindowEnd1 = timeWindow.Item2.ToUniversalTime(); timeWindow = order.TimeWindow2.ToDateTime(plannedDate); trackingStop.TimeWindowStart2 = timeWindow.Item1.ToUniversalTime(); trackingStop.TimeWindowEnd2 = timeWindow.Item2.ToUniversalTime(); } break; case StopType.Location: { // Use time windows from Location associated with the stop. var location = (Location)stop.AssociatedObject; var timeWindow = location.TimeWindow.ToDateTime(plannedDate); trackingStop.TimeWindowStart1 = timeWindow.Item1.ToUniversalTime(); trackingStop.TimeWindowEnd1 = timeWindow.Item2.ToUniversalTime(); } break; case StopType.Lunch: { // Use time windows from Break associated with the stop's Route. var lunch = stop.Route.Breaks .OfType<TimeWindowBreak>() .Where(item => item.Duration > 0.0) .FirstOrDefault(); if (lunch != null) { // TODO: implement good breaks support. trackingStop.TimeWindowStart1 = null; trackingStop.TimeWindowEnd1 = null; } } break; default: break; } }