/// <summary> /// Calculate time range, when trip can be finished. /// </summary> /// <param name="tripTimeRange">TimeRange.</param> /// <returns>TimeRange.</returns> private TimeRange _GetTripPossibleFinishTimeRange(TimeRange tripTimeRange) { // Calculate route finish time window. TimeRange routeFinishTimeRange = new TimeRange(); // If we have breaks that must be visited. if (_route.Breaks.Count != 0 && _route.Breaks[0] is TimeWindowBreak) { // Route finish time window will be from trip earliest possible finish // to time when trip can be finished. // Calculate last break finish time window. TimeWindowBreak lastBreak = _GetSortedBreaks()[_route.Breaks.Count - 1] as TimeWindowBreak; TimeRange lastBreakTimeRange = new TimeRange(lastBreak.EffectiveFrom, lastBreak.EffectiveTo); TimeRange lastBreakFinishTimeRange = lastBreakTimeRange.Shift( TimeSpan.FromMinutes(lastBreak.Duration)); TimeRange lastBreakRealFinishTimeRange = lastBreakFinishTimeRange.Intersection(tripTimeRange); // Trip earliest finish is minimum time, when last break will be completed. var earliestTripFinish = lastBreakRealFinishTimeRange.From; routeFinishTimeRange = new TimeRange(earliestTripFinish, tripTimeRange.To); } // If we have no breaks to visit route finish time window will be equal to trip time window. else { routeFinishTimeRange = tripTimeRange; } return(routeFinishTimeRange); }
/////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Page loaded handler. /// </summary> private void fleetSetupWizardRoutesPage_Loaded(object sender, RoutedEventArgs e) { Debug.Assert(0 < DataKeeper.Locations.Count); // locations must present // If there are no default breaks - add default break to project configuration. if (DataKeeper.Project.BreaksSettings.BreaksType == null) { DataKeeper.Project.BreaksSettings.BreaksType = BreakType.TimeWindow; var timeWindowBreak = new TimeWindowBreak(); DataKeeper.Project.BreaksSettings.DefaultBreaks.Add(timeWindowBreak); } // init controls if (!_isInited) { _InitControls(); } _InitDataGridCollection(); // validate controls _UpdatePageState(); vehicleNumberTextBox.Focus(); vehicleNumberTextBox.SelectAll(); }
/// <summary> /// If we upgrading from old version of project we need to update breaks settings. /// So project's Breaks Type will be set to TimeWindowBreak and as a default break /// will be used default routes most popular break. /// </summary> private void _UpdateBreaksConfig() { // Check that we need to create default breaks. if (_projectCfg.BreaksSettings.BreaksType == null && DefaultRoutes.Count != 0) { var breaks = new List <MaxBreak>(); MaxBreak breakObj = null; // Analyze each route in project. foreach (Route route in DefaultRoutes) { // Check that route has break and this is TimeWindowBreak. if (route.Breaks.Count == 1 && route.Breaks[0] is TimeWindowBreak) { // Get route's break. TimeWindowBreak routeBreak = route.Breaks[0] as TimeWindowBreak; // If break isn't first, try find same break in list. if (breaks.Count != 0) { breakObj = breaks.FirstOrDefault(x => x.Break.To == routeBreak.To && x.Break.From == routeBreak.From && x.Break.Duration == routeBreak.Duration); } // If there is same break in a list - just increase records count. if (breakObj != null) { breakObj.Count++; } // If there is no such break - add new record to list. else { breaks.Add(new MaxBreak { Count = 1, Break = routeBreak }); } } } // Try to find most popular break in list. MaxBreak mostPopularBreak = breaks.FirstOrDefault (x => x.Count == breaks.Max(br => br.Count)); // Set default breaks type as timewindow break. _projectCfg.BreaksSettings.BreaksType = BreakType.TimeWindow; // If we found most popular break - set it as default, otherwise left default // breaks collection empty. if (mostPopularBreak != null) { _projectCfg.BreaksSettings.DefaultBreaks.Add( mostPopularBreak.Break.Clone() as TimeWindowBreak); } } }
/// <summary> /// Return index of break in original route collection. /// </summary> /// <param name="breakObj">Break which index must be detected.</param> /// <returns></returns> private int _IndexInUnsortedCollection(TimeWindowBreak breakObj) { for (int i = 0; i < _route.Breaks.Count; i++) { if ((_route.Breaks[i] as TimeWindowBreak).EffectiveFrom == breakObj.EffectiveFrom) { return(i); } } return(-1); }
/// <summary> /// Comparison for two Brakes. /// </summary> /// <param name="break1">First <c>Brake</c>.</param> /// <param name="break2">Second <c>Brake</c>.</param> /// <returns>-1 if first break less then second, 0 if they are equal /// and 1 if first break more then second. </returns> public static int Compare(Break break1, Break break2) { // If first break == null. if (break1 == null) { if (break2 == null) { return(0); } else { return(-1); } } else if (break2 == null) { return(1); } // If both not null. if (break1.GetType() != break2.GetType()) { return(0); // Breaks are not of the same type, cant compare. } else if (break1.GetType() == typeof(TimeWindowBreak)) { TimeWindowBreak br1 = break1 as TimeWindowBreak; TimeWindowBreak br2 = break2 as TimeWindowBreak; return(_TimeWindowBreakComparer(br1, br2)); } else if (break1.GetType() == typeof(WorkTimeBreak)) { WorkTimeBreak br1 = break1 as WorkTimeBreak; WorkTimeBreak br2 = break2 as WorkTimeBreak; return(_WorkTimeBreakComparer(br1, br2)); } else if (break1.GetType() == typeof(DriveTimeBreak)) { DriveTimeBreak br1 = break1 as DriveTimeBreak; DriveTimeBreak br2 = break2 as DriveTimeBreak; return(_DriveTimeBreakComparer(br1, br2)); } else { // Breaks are of unknown type, cant compare them. Debug.Assert(false); return(0); } }
/// <summary> /// Does validation. /// </summary> /// <param name="objectToValidate">Object to validation.</param> /// <param name="currentTarget">Current target (expected only /// <see cref="T:ESRI.ArcLogistics.DomainObjects.TimeWindowBreak"/>).</param> /// <param name="key">Ignored.</param> /// <param name="validationResults">Validation results.</param> protected override void DoValidate(TimeSpan objectToValidate, object currentTarget, string key, ValidationResults validationResults) { // Input parametrs check. Debug.Assert(currentTarget != null); if ((currentTarget as TimeWindowBreak).Breaks == null) { return; } // Detecting index of TimeWindowBreak in Breaks collection. var timeWindowBreak = currentTarget as TimeWindowBreak; int index = BreaksHelper.IndexOf(timeWindowBreak.Breaks, timeWindowBreak); // Detecting index of TimeWindowBreak in sorted collection. List <Break> sortedBreaks = BreaksHelper.GetSortedList(timeWindowBreak.Breaks); int sortedIndex = BreaksHelper.IndexOf(sortedBreaks, timeWindowBreak); // If it isn't last break in sorted collection, we can check it's // timewindow on intersection with next break. if (sortedIndex < sortedBreaks.Count - 1) { // Detecting index of next Break in input collection. TimeWindowBreak nextBreak = sortedBreaks[sortedIndex + 1] as TimeWindowBreak; int overlapIndex = BreaksHelper.IndexOf(timeWindowBreak.Breaks, nextBreak); // Checking next Break in collection on TimeWindow // intersection with current TimeWindowBreak. if (nextBreak.EffectiveFrom <= timeWindowBreak.EffectiveTo) { // Breaks time windows overlap. _AddString(Properties.Messages.Error_TimeWindowOverlap, index, overlapIndex, currentTarget, key, validationResults); } else { // Checking for time window + break time overlap. TimeSpan duration = TimeSpan.FromMinutes(timeWindowBreak.Duration); if (nextBreak.EffectiveFrom <= timeWindowBreak.EffectiveTo + duration) { // Break time window + duration overlap other break time window. _AddString(Properties.Messages.Error_TimeWindowPlusDurationOverlap, index, overlapIndex, currentTarget, key, validationResults); } } } }
/// <summary> /// Comparer for two <c>TimeWindowBrakes</c>. /// </summary> /// <param name="break1">First <c>Brake</c>.</param> /// <param name="break2">Second <c>Brake</c>.</param> /// <returns>Result of comparing. Breaks are compared by EffectiveFrom property.</returns> private static int _TimeWindowBreakComparer(TimeWindowBreak break1, TimeWindowBreak break2) { if (break1.EffectiveFrom > break2.EffectiveFrom) { return(1); } else if (break1.EffectiveFrom < break2.EffectiveFrom) { return(-1); } else { return(0); } }
/// <summary> /// Check that all route's breaks can be visited. /// For invalid breaks add error messages. /// </summary> /// <param name="tripTimeRange">Trip start time window.</param> /// <rereturns>'True' if all breaks can be visited, 'false' otherwise.</rereturns> private bool _CheckBreaksCanBeVisited(TimeRange tripTimeRange) { var result = true; // Prepare breaks for validation. Breaks sortedBreaks = _GetSortedBreaks(); // Collection with breaks, which cannot be completed at time. Breaks invalidBreaks = new Breaks(); // Check that all breaks can be completed in time. for (int i = 0; i < sortedBreaks.Count; i++) { TimeWindowBreak breakToCheck = sortedBreaks[i] as TimeWindowBreak; // Try to calculate break start. var breakStart = tripTimeRange.Intersection(breakToCheck.EffectiveFrom, breakToCheck.EffectiveTo); // If break cannot be started - it is invalid. Check next break. if (breakStart == null) { invalidBreaks.Add(breakToCheck); } // Check that break can be finished. else { // Try calculate break finish. var breakFinish = breakStart.Shift(TimeSpan.FromMinutes(breakToCheck.Duration)); breakFinish = breakFinish.Intersection(tripTimeRange); // If break cannot be finished - it is invalid. if (breakFinish == null) { invalidBreaks.Add(breakToCheck); } } } // If there was invalid breaks - show error messages. if (invalidBreaks.Count != 0) { _AddErrorMessages(invalidBreaks); result = false; } return(result); }
/// <summary> /// Get the time span when route must start to satisfy first break. /// </summary> /// <param name="startTimeRange">TimeRange in which route can left start location.</param> /// <param name="firstBreak">TimeWindowBreak.</param> /// <param name="tripMaxDuration">Max trip duration.</param> /// <returns>TimeSpan?.</returns> private TimeSpan?_GetRealStart(TimeRange startTimeRange, TimeWindowBreak firstBreak, TimeSpan tripMaxDuration) { // Calculate trip possible time range. var tripPossibleTimeRange = startTimeRange.Clone() as TimeRange; tripPossibleTimeRange.To += tripMaxDuration; // Get finishTimeRange of trip and break time ranges. var intersection = tripPossibleTimeRange.Intersection( new TimeRange(firstBreak.EffectiveFrom, firstBreak.EffectiveFrom)); // If they intersects - calculate trip start. if (intersection != null) { return(_MinTimeSpan(startTimeRange.To, intersection.To)); } else { return(null); } }
/// <summary> /// Method gets stops date from route. /// </summary> /// <param name="route">Route to get information.</param> /// <returns>Collection of stops data.</returns> private List <StopData> _GetStops(Route route) { Debug.Assert(route != null); IDataObjectCollection <Stop> stops = route.Stops; int stopsCount = stops.Count; var stopDatas = new List <StopData>(stopsCount); for (int index = 0; index < stopsCount; ++index) { Stop stop = stops[index]; StopData sd = new StopData(); sd.SequenceNumber = stop.SequenceNumber; sd.Distance = stop.Distance; sd.WaitTime = stop.WaitTime; sd.TimeAtStop = stop.TimeAtStop; sd.TravelTime = stop.TravelTime; sd.ArriveTime = (DateTime)stop.ArriveTime; if (stop.StopType == StopType.Lunch) { // Break. // ToDo - need update logic - now find only first TWBreak. var twBreaks = from currBreak in route.Breaks where currBreak is TimeWindowBreak select currBreak; TimeWindowBreak rtBreak = twBreaks.FirstOrDefault() as TimeWindowBreak; if (rtBreak != null && rtBreak.Duration > 0.0) { // TODO Break //// Time window. //DateTime? twStart = null; //DateTime? twEnd = null; //if (rtBreak.TimeWindow != null) // _ConvertTW(rtBreak.TimeWindow, out twStart, out twEnd); sd.TimeWindowStart1 = _TSToDate(rtBreak.From); sd.TimeWindowEnd1 = _TSToDate(rtBreak.To); } } else { Debug.Assert(stop.AssociatedObject != null); // Associated object id. sd.AssociatedObject = stop.AssociatedObject; // Geometry. Point pt = _GetStopPoint(stop); sd.Geometry = GPObjectHelper.PointToGPPoint(pt); // Time windows. DateTime?twStart1 = null; DateTime?twStart2 = null; DateTime?twEnd1 = null; DateTime?twEnd2 = null; // Type-specific data. if (stop.StopType == StopType.Order) { Order order = stop.AssociatedObject as Order; Debug.Assert(order != null); // Curbapproach. sd.NACurbApproach = CurbApproachConverter.ToNACurbApproach( _context.SolverSettings.GetDepotCurbApproach()); // Time window 1. if (order.TimeWindow != null) { _ConvertTW(order.TimeWindow, out twStart1, out twEnd1); } // Time window 2. if (order.TimeWindow2 != null) { _ConvertTW(order.TimeWindow2, out twStart2, out twEnd2); } } else if (stop.StopType == StopType.Location) { Location loc = stop.AssociatedObject as Location; Debug.Assert(loc != null); // Time window. if (loc.TimeWindow != null) { _ConvertTW(loc.TimeWindow, out twStart1, out twEnd1); } } sd.TimeWindowStart1 = twStart1; sd.TimeWindowStart2 = twStart2; sd.TimeWindowEnd1 = twEnd1; sd.TimeWindowEnd2 = twEnd2; } sd.RouteId = route.Id; sd.StopType = stop.StopType; stopDatas.Add(sd); } SolveHelper.ConsiderArrivalDelayInStops( _context.SolverSettings.ArriveDepartDelay, stopDatas); return(stopDatas); }