Ejemplo n.º 1
0
        /// <summary>
        /// Calculate the best organization of the tasks.
        /// It will seperate tasks based on service type, and then push the ordered task collections when complete.
        /// This will open the AlgorithmProgress window.
        /// </summary>
        /// <param name="unroutedRouteTasks">The task holders to order.</param>
        /// <param name="serviceTypes">The service types to consider.</param>
        /// <returns>An observable to stay asynchronous. The result is pushed once, so take the first item.</returns>
        public IObservable<IEnumerable<IEnumerable<RouteTask>>> OrderTasks(IEnumerable<RouteTask> unroutedRouteTasks, IEnumerable<string> serviceTypes)
        {
            var algorithmStatus = new AlgorithmStatus { AlgorithmVM = this };
            var result = new Subject<IEnumerable<IEnumerable<RouteTask>>>();

            //Organize the unroutedRouteTasks by ServiceTemplateName
            //only choose task holders that have LocationIds, a ServiceName, and a Latitude and a Longitude
            var RouteTasksToRoute =
                unroutedRouteTasks.Where(th =>
                    th.LocationId.HasValue && th.Name != null && th.Location.Latitude.HasValue && th.Location.Longitude.HasValue)
                    .ToArray();

            //Find which service types should be routed by choosing the (distinct) ServiceTypes of the unroutedRouteTasks
            //only choose the types that should be routes
            //Then only choose route types Make sure each of those service types have at least one route with that RouteType
            var distinctServiceTemplates = RouteTasksToRoute.Select(th => th.Name).Distinct()
                .Where(st => serviceTypes.Any(t => t == st))
                .ToArray();

            //Seperate the RouteTasks by ServiceTemplate Name to prevent routing different service types together
            var RouteTaskCollections =
                distinctServiceTemplates.Select(serviceTemplateName => RouteTasksToRoute.Where(th => th.Name == serviceTemplateName));

            #region Depot no longer used
            ////If there is not a depot set. Default to FoundOPS, 1305 Cumberland Ave, 47906: 40.460335, -86.929840
            //var depot = new GeoLocation(40.460335, -86.929840);

            ////Try to get the depot from the business account
            //var ownerBusinessAccount = Manager.Context.OwnerAccount as BusinessAccount;
            //if (ownerBusinessAccount != null && ownerBusinessAccount.Depots.Any())
            //{
            //    var depotLocation = ownerBusinessAccount.Depots.First();
            //    if (depotLocation.Latitude.HasValue && depotLocation.Longitude.HasValue)
            //        depot = new GeoLocation((double)depotLocation.Latitude.Value, (double)depotLocation.Longitude.Value);
            //}
            #endregion

            int totalTasksToRoute = RouteTaskCollections.Select(RouteTaskCollection => RouteTaskCollection.Count()).Sum();

            if (totalTasksToRoute <= 0)
                return Observable.Empty<IEnumerable<IEnumerable<RouteTask>>>();

            //Setup countdown timer
            //a) aggregate the total time to route
            //b) countdown
            TotalCalculationTime = TimeToCalculate(totalTasksToRoute);
            this.TimeRemaining = TotalCalculationTime;
            var dispatcherTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
            dispatcherTimer.Tick += (s, e) =>
            {
                TimeRemaining -= TimeSpan.FromSeconds(1);

                if (TimeRemaining > new TimeSpan()) return;

                //When there is no TimeRemaining
                //a) reset TimeRemaining to 0 seconds
                //b) stop the countdown
                TimeRemaining = new TimeSpan();
                dispatcherTimer.Stop();
            };
            dispatcherTimer.Start();

            //Calculate the order, one collection at a time
            //peform the calculations asynchronously
            if (totalTasksToRoute >= 0)
                Observable.Start(() =>
                {
                    PerformNextCalcuation(RouteTaskCollections, 0, new List<IEnumerable<RouteTask>>(), algorithmStatus, result);
                });

            algorithmStatus.Show();
            return result.AsObservable();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// A recursive method that will calculate the order of the routes, one route at a time
        /// </summary>
        /// <param name="geoLocationCollections">The collections to order</param>
        /// <param name="index">The index of the collection to calculate</param>
        /// <param name="orderedRouteTaskCollections">The ordered RouteTask collections</param>
        /// <param name="statusWindow">The window to close when complete</param>
        /// <param name="resultSubject">The subject to push when complete</param>
        private void PerformNextCalcuation(IEnumerable<IEnumerable<IGeoLocation>> geoLocationCollections, int index, List<IEnumerable<RouteTask>> orderedRouteTaskCollections,
            AlgorithmStatus statusWindow, Subject<IEnumerable<IEnumerable<RouteTask>>> resultSubject)
        {
            //if all routes have been calculated, close the algorithm status window and return
            if (index >= geoLocationCollections.Count())
            {
                statusWindow.Close();
                resultSubject.OnNext(orderedRouteTaskCollections);
                return;
            }

            var collectionToCalculate = geoLocationCollections.ElementAt(index).ToList();

            var timeToCalculate = TimeToCalculate(collectionToCalculate.Count);
            var calculator = new HiveRouteCalculator();
            var foundSolution = calculator.Search(collectionToCalculate);
            IList<IGeoLocation> bestSolution = null;
            foundSolution.Subscribe(solutionMessage =>
            {
                if (solutionMessage == null)
                    return;

                bestSolution = solutionMessage.Solution;

                ////convert meters to miles
                //CurrentDistance = (int)(solutionMessage.Quality / 0.000621371192);
            });

            //Stop the algorithm after timeToCalculate is up
            //then perform the next calculation
            var stopAlgorithmDisposable = Rxx3.RunDelayed(timeToCalculate, () =>
            {
                calculator.StopSearch();
                //add the best solution found to the collection
                orderedRouteTaskCollections.Add(bestSolution.Cast<RouteTask>());
                index++;
                PerformNextCalcuation(geoLocationCollections, index, orderedRouteTaskCollections, statusWindow, resultSubject);
            });

            //Stop the algorithm on cancel search and return
            CancelCommand.Subscribe(_ =>
            {
                //since the algorithm was cancelled, prevent the time from stopping the algorithm
                stopAlgorithmDisposable.Dispose();

                calculator.StopSearch();
                statusWindow.Close();
            });
        }