public GeocacheRoutingInformation(GeocacheRoutingInformation ObjectToCopy) { geocache = ObjectToCopy.geocache; DistanceToRoute = ObjectToCopy.DistanceToRoute; EstimatedExtraDistance = ObjectToCopy.EstimatedExtraDistance; ResolvedCoordinates = ObjectToCopy.ResolvedCoordinates; }
private RouteData FillRouteWithGeocachesUntilMaxDistanceIsReached(RouteData CompleteRouteData) { Fileoperations.Routerlog.AddSubSection("Entered filling route with geocaches"); //TODO Make MaxDistance to meters as well /////////////////////////////////////////////////////////////////////////////////////// //TAKE CARE RouteDistance is in m, MaxDistance in km!!! //////////////////////////////////////////////////////////////////////////////// GeocacheRoutingInformation GeocacheToAdd = null; do { //Values GeocacheToAdd = null; Route RouteToInsertIn = null; int IndexOfRouteToInsertIn = -1; #region Filter Geocaches /*Remove all Caches that definitely are not in Range (estimated distance, which is the shortest possible distance, bigger than distance set). * Meanwhile find best rated geocache and the route it is the closest to. * Only allow apercentage of the distance set, as the roads are most definitely not straight. * For the case they are, there is another routine that picks up the caches that are directly on the route. */ Parallel.For(0, CompleteRouteData.partialRoutes.Count, CurrentPartialRouteIndex => { PartialRoute CurrentPartialRoute = CompleteRouteData.partialRoutes[CurrentPartialRouteIndex]; List <GeocacheRoutingInformation> GeocachesToRemove = new List <GeocacheRoutingInformation>(); foreach (GeocacheRoutingInformation CurrentGeocache in CurrentPartialRoute.GeocachesInReach) { if (CurrentGeocache.EstimatedExtraDistance > (CompleteRouteData.Profile.MaxDistance * 1000 - CompleteRouteData.TotalDistance)) { GeocachesToRemove.Add(CurrentGeocache); } else if (CompleteRouteData.GeocachesOnRoute().Contains(CurrentGeocache.geocache)) { GeocachesToRemove.Add(CurrentGeocache); } else if (CurrentGeocache.EstimatedExtraDistance < CompleteRouteData.Profile.MaxDistance * 1000 - CompleteRouteData.TotalDistance) { /* If no cache is set as next geocache to insert * If the cache we stumbled accross has more routingpoints than the old cache */ if (GeocacheToAdd == null || CurrentGeocache.RoutingPoints > GeocacheToAdd.RoutingPoints) { lock (GeocacheToAddLocker) //Since one can't lock GeocacheToAdd directly, since it is not the same object that is locked and unlocked { GeocacheToAdd = CurrentGeocache; } lock (RouteToInsertInLocker) //See above { RouteToInsertIn = CurrentPartialRoute.partialRoute; } IndexOfRouteToInsertIn = CurrentPartialRouteIndex; } } } //Remove all geocaches that can't be reached or are already used foreach (GeocacheRoutingInformation Geocache_Info in GeocachesToRemove) { CurrentPartialRoute.GeocachesInReach.Remove(Geocache_Info); } }); #endregion //Won't be able to fit a geocache in if (CompleteRouteData.TotalTime + CompleteRouteData.Profile.TimePerGeocache * 60 > CompleteRouteData.Profile.MaxTime * 60) { GeocacheToAdd = null; } if (GeocacheToAdd != null) { Result <Tuple <Route, Route> > RoutingResult = GetPartialRoutes(CompleteRouteData, RouteToInsertIn, GeocacheToAdd.ResolvedCoordinates); if (!RoutingResult.IsError) { float NewDistance = CompleteRouteData.TotalDistance - RouteToInsertIn.TotalDistance + RoutingResult.Value.Item1.TotalDistance + RoutingResult.Value.Item2.TotalDistance; float NewTimeWithGeocaches = CompleteRouteData.TotalTime - RouteToInsertIn.TotalTime + RoutingResult.Value.Item1.TotalTime + RoutingResult.Value.Item2.TotalTime + (CompleteRouteData.GeocachesOnRoute().Count + 1) * CompleteRouteData.Profile.TimePerGeocache * 60; float NewRoutePoints = CompleteRouteData.TotalPoints + GeocacheToAdd.geocache.Rating; //calculate in meters if (NewDistance < CompleteRouteData.Profile.MaxDistance * 1000 && NewTimeWithGeocaches < CompleteRouteData.Profile.MaxTime * 60) { Debug.WriteLine("Added " + GeocacheToAdd.geocache); CompleteRouteData = ReplaceRoute(CompleteRouteData, RoutingResult.Value.Item1, RoutingResult.Value.Item2, IndexOfRouteToInsertIn); CompleteRouteData.AddGeocacheOnRoute(GeocacheToAdd.geocache); CompleteRouteData.TotalPoints = NewRoutePoints; //Overwrites the addition automatically made in the lne before, to make sure the DisplayPreliminaryRoute(CompleteRouteData); } else { Debug.WriteLine("Made calculation for nothing. Route was longer in distance or time than allowed"); CompleteRouteData.partialRoutes[IndexOfRouteToInsertIn].GeocachesInReach.Remove(GeocacheToAdd); //As the geocache doesn't help from this route } } else { Debug.WriteLine("Routing was errounous. Island detection score:" + FailedRouteCalculations); CompleteRouteData.partialRoutes[IndexOfRouteToInsertIn].GeocachesInReach.Remove(GeocacheToAdd); //Since trying to route to it results in an error } } } while (FailedRouteCalculations < FailedRouteCalculationsLimit && GeocacheToAdd != null); return(CompleteRouteData); }
private RouteData DirectionDecision(RouteData CompleteRouteData, List <Geocache> GeocachesToConsider) { GeocachesToConsider = GeocachesToConsider.OrderByDescending(x => x.Rating).ToList(); List <RouteData> Suggestions = new List <RouteData>(); int NumberofRouteslongerthanlimit = 0; int FirstGeocacheNotUsedAsSuggestionBase = Program.DB.RoutefindingWidth + 1; try { Parallel.For(0, Program.DB.RoutefindingWidth, NumberOfSuggestions => { Fileoperations.Routerlog.LogCollector Log = new Fileoperations.Routerlog.LogCollector("DirectionDecision" + NumberOfSuggestions); RouteData SuggestionRouteData; lock (CompleteRouteData) { SuggestionRouteData = CompleteRouteData.DeepCopy(); } lock (Suggestions) { Suggestions.Add(SuggestionRouteData); } int SuggestedCacheIndex = NumberOfSuggestions; //Add geocaches to suggested route, as long as the route is shorter than the min allowed length, but also make sure it doesn't get too long in time and distance while (SuggestionRouteData.TotalDistance < Program.DB.PercentageOfDistanceInAutoTargetselection_Min * SuggestionRouteData.Profile.MaxDistance * 1000 && SuggestedCacheIndex < GeocachesToConsider.Count) { Geocache SuggestedCache = GeocachesToConsider[SuggestedCacheIndex]; Log.AddMainInformation("Suggested " + SuggestedCache + " at Index Position " + SuggestedCacheIndex); #region Find shortest resulting route if cache is inserted Route int IndexOfRouteToInsertIn = 0; float MinEstimatedExtraRouteLength = -1; for (int PartialRouteIndex = 0; PartialRouteIndex < SuggestionRouteData.partialRoutes.Count; PartialRouteIndex++) //Thus each partial route { float Length = GetEstimatedExtraDistance(SuggestionRouteData.partialRoutes[PartialRouteIndex].partialRoute, new Coordinate(SuggestedCache.lat, SuggestedCache.lon)); //Whether this is the route the geocache is currently closest to if (MinEstimatedExtraRouteLength < 0 || Length < MinEstimatedExtraRouteLength) { IndexOfRouteToInsertIn = PartialRouteIndex; MinEstimatedExtraRouteLength = Length; } } #endregion Log.AddSubInformation("Estimated Route length: " + MinEstimatedExtraRouteLength); //Check if the Cache seems to be in range. Error_Percentage * Max_Percentage * Remaining Distance, since the roads to the cache are quite surely not in a straight line and we want to fill up to the percentage only if (MinEstimatedExtraRouteLength < Program.DB.PercentageOfDistanceInAutoTargetselection_Max * (SuggestionRouteData.Profile.MaxDistance * 1000 - SuggestionRouteData.TotalDistance)) { Result <RouterPoint> GeocacheToAddResolveResult = Router1.TryResolve(SuggestionRouteData.Profile.ItineroProfile.profile, SuggestedCache.lat, SuggestedCache.lon, SearchDistanceInMeters); Route RouteToInsertIn = SuggestionRouteData.partialRoutes[IndexOfRouteToInsertIn].partialRoute; GeocacheRoutingInformation SuggestionBaseCache_Info; if (!GeocacheToAddResolveResult.IsError) { SuggestionBaseCache_Info = new GeocacheRoutingInformation(SuggestedCache, MinEstimatedExtraRouteLength, GeocacheToAddResolveResult.Value); Result <Tuple <Route, Route> > RoutingResult = GetPartialRoutes(SuggestionRouteData, RouteToInsertIn, SuggestionBaseCache_Info.ResolvedCoordinates); if (!RoutingResult.IsError) { // So one doesn't have to iterate through all routes //TestRouteDistance, as one doesn't know wether this on is taken float NewDistance = SuggestionRouteData.TotalDistance - RouteToInsertIn.TotalDistance + RoutingResult.Value.Item1.TotalDistance + RoutingResult.Value.Item1.TotalDistance; float NewTime = SuggestionRouteData.TotalTime - RouteToInsertIn.TotalTime + RoutingResult.Value.Item1.TotalTime + RoutingResult.Value.Item1.TotalTime; if (NewDistance < Program.DB.PercentageOfDistanceInAutoTargetselection_Max * SuggestionRouteData.Profile.MaxDistance * 1000 && NewTime < Program.DB.PercentageOfDistanceInAutoTargetselection_Max * SuggestionRouteData.Profile.MaxTime * 60) { Log.AddSubInformation("Added the Geocache to the Route. New Distance:" + NewDistance); SuggestionRouteData = ReplaceRoute(SuggestionRouteData, RoutingResult.Value.Item1, RoutingResult.Value.Item2, IndexOfRouteToInsertIn); SuggestionRouteData.AddGeocacheOnRoute(SuggestedCache); } //Else just skip this cache. else { Log.AddSubInformation("The Resulting Distance was too long"); NumberofRouteslongerthanlimit++; } } } else //Couldn't resolve { Log.AddSubInformation("Couldn't resolve Geocache"); if (SuggestedCacheIndex == FirstGeocacheNotUsedAsSuggestionBase) { FirstGeocacheNotUsedAsSuggestionBase++; //To avoid using the same cache as base twice SuggestedCacheIndex = FirstGeocacheNotUsedAsSuggestionBase--; //Since ++ will happen } lock (GeocachesToConsider) { GeocachesToConsider.RemoveAt(SuggestedCacheIndex); //Since it will never be possible to resolve it } } } else { Log.AddSubInformation("Estimated Distance was too long"); } if (FailedRouteCalculations > FailedRouteCalculationsLimit) { break; } else { SuggestedCacheIndex++; } } Log.Write(); // Since this thread is done }); } catch (Exception) { Fileoperations.Routerlog.AddSubInformation("At least one exception has been caused."); } Fileoperations.Routerlog.AddSubInformation(NumberofRouteslongerthanlimit + " Routes have been to long."); if (Suggestions.Count != 0) { //Return best suggestion return(Suggestions.Find(x => x.TotalPoints == Suggestions.Max(y => y.TotalPoints))); } //If no suggestion has been found, just return the uncanged original Data return(CompleteRouteData); }