/// <summary> /// Calculates a route between the two locations. /// </summary> /// <returns></returns> public sealed override Result <EdgePath <T> > TryCalculateRaw <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target, RoutingSettings <T> settings) { try { if (!_db.Supports(profileInstance.Profile)) { return(new Result <EdgePath <T> >("Routing profile is not supported.", (message) => { return new Exception(message); })); } var maxSearch = weightHandler.Infinite; if (settings != null) { if (!settings.TryGetMaxSearch(profileInstance.Profile.FullName, out maxSearch)) { maxSearch = weightHandler.Infinite; } } EdgePath <T> path; ContractedDb contracted; bool useContracted = false; if (_db.TryGetContracted(profileInstance.Profile, out contracted)) { // contracted calculation. useContracted = true; if (_db.HasComplexRestrictions(profileInstance.Profile) && !contracted.HasEdgeBasedGraph) { // there is no edge-based graph for this profile but the db has complex restrictions, don't use the contracted graph. Logging.Logger.Log("Router", Logging.TraceEventType.Warning, "There is a vertex-based contracted graph but also complex restrictions. Not using the contracted graph, add an edge-based contracted graph."); useContracted = false; } } if (useContracted) { // use the contracted graph. path = null; List <uint> vertexPath = null; if (!contracted.HasEdgeBasedGraph) { // use node-based routing. var bidirectionalSearch = new Itinero.Algorithms.Contracted.BidirectionalDykstra <T>(contracted.NodeBasedGraph, weightHandler, source.ToEdgePaths(_db, weightHandler, true), target.ToEdgePaths(_db, weightHandler, false)); bidirectionalSearch.Run(); if (!bidirectionalSearch.HasSucceeded) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } vertexPath = bidirectionalSearch.GetPath(); } else { // use edge-based routing. var bidirectionalSearch = new Itinero.Algorithms.Contracted.EdgeBased.BidirectionalDykstra <T>(contracted.EdgeBasedGraph, weightHandler, source.ToEdgePaths(_db, weightHandler, true), target.ToEdgePaths(_db, weightHandler, false), _db.GetGetRestrictions(profileInstance.Profile, null)); bidirectionalSearch.Run(); if (!bidirectionalSearch.HasSucceeded) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } vertexPath = bidirectionalSearch.GetPath(); } // expand vertex path using the regular graph. path = _db.BuildEdgePath(weightHandler, source, target, vertexPath); } else { // use the regular graph. if (_db.HasComplexRestrictions(profileInstance.Profile)) { var sourceSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, true), source.ToEdgePaths(_db, weightHandler, true), maxSearch, false); var targetSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, false), target.ToEdgePaths(_db, weightHandler, false), maxSearch, true); var bidirectionalSearch = new Algorithms.Default.EdgeBased.BidirectionalDykstra <T>(sourceSearch, targetSearch, weightHandler); bidirectionalSearch.Run(); if (!bidirectionalSearch.HasSucceeded) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } path = bidirectionalSearch.GetPath(); } else { var sourceSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, null, weightHandler, source.ToEdgePaths(_db, weightHandler, true), maxSearch, false); var targetSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, null, weightHandler, target.ToEdgePaths(_db, weightHandler, false), maxSearch, true); var bidirectionalSearch = new BidirectionalDykstra <T>(sourceSearch, targetSearch, weightHandler); bidirectionalSearch.Run(); if (!bidirectionalSearch.HasSucceeded) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } path = bidirectionalSearch.GetPath(); } } if (source.EdgeId == target.EdgeId) { // check for a shorter path on the same edge. var edgePath = source.EdgePathTo(_db, weightHandler, target); if (edgePath != null && weightHandler.IsSmallerThan(edgePath.Weight, path.Weight)) { path = edgePath; } } return(new Result <EdgePath <T> >(path)); } catch (Exception ex) { return(new Result <EdgePath <T> >(ex.Message, (m) => ex)); } }
/// <summary> /// Creates a new contracted graph and adds it to the router db for the given profile. /// </summary> public static void AddContracted <T>(this RouterDb db, Profiles.Profile profile, WeightHandler <T> weightHandler, bool forceEdgeBased = false) where T : struct { // create the raw directed graph. ContractedDb contractedDb = null; lock (db) { if (forceEdgeBased) { // edge-based is needed when complex restrictions found. var contracted = new DirectedDynamicGraph(weightHandler.DynamicSize); var directedGraphBuilder = new Itinero.Algorithms.Contracted.EdgeBased.DirectedGraphBuilder <T>(db.Network.GeometricGraph.Graph, contracted, weightHandler); directedGraphBuilder.Run(); // contract the graph. var priorityCalculator = new Itinero.Algorithms.Contracted.EdgeBased.EdgeDifferencePriorityCalculator <T>(contracted, weightHandler, new Itinero.Algorithms.Contracted.EdgeBased.Witness.DykstraWitnessCalculator <T>(weightHandler, int.MaxValue)); priorityCalculator.DifferenceFactor = 5; priorityCalculator.DepthFactor = 5; priorityCalculator.ContractedFactor = 8; var hierarchyBuilder = new Itinero.Algorithms.Contracted.EdgeBased.HierarchyBuilder <T>(contracted, priorityCalculator, new Itinero.Algorithms.Contracted.EdgeBased.Witness.DykstraWitnessCalculator <T>(weightHandler, int.MaxValue), weightHandler, db.GetGetRestrictions(profile, null)); hierarchyBuilder.Run(); contractedDb = new ContractedDb(contracted); } else { // vertex-based is ok when no complex restrictions found. var contracted = new DirectedMetaGraph(ContractedEdgeDataSerializer.Size, weightHandler.MetaSize); var directedGraphBuilder = new DirectedGraphBuilder <T>(db.Network.GeometricGraph.Graph, contracted, weightHandler); directedGraphBuilder.Run(); // contract the graph. var priorityCalculator = new EdgeDifferencePriorityCalculator(contracted, new DykstraWitnessCalculator(int.MaxValue)); priorityCalculator.DifferenceFactor = 5; priorityCalculator.DepthFactor = 5; priorityCalculator.ContractedFactor = 8; var hierarchyBuilder = new HierarchyBuilder <T>(contracted, priorityCalculator, new DykstraWitnessCalculator(int.MaxValue), weightHandler); hierarchyBuilder.Run(); contractedDb = new ContractedDb(contracted); } } // add the graph. lock (db) { db.AddContracted(profile, contractedDb); } }
/// <summary> /// Checks if the given point is connected to the rest of the network. Use this to detect points on routing islands. /// </summary> /// <param name="radiusInMeter">The radius metric, that's always a distance in meters.</param> /// <returns></returns> public sealed override Result <bool> TryCheckConnectivity(IProfileInstance profileInstance, RouterPoint point, float radiusInMeter, bool?forward = null) { try { if (!_db.Supports(profileInstance.Profile)) { return(new Result <bool>("Routing profile is not supported.", (message) => { return new Exception(message); })); } // get the weight handler. var getGetFactor = this.GetDefaultGetFactor(profileInstance); Func <ushort, Factor> getShortestFactor = (p) => { // only keep directional information, get factor to 1 for distance metrics only. var factor = getGetFactor(p); if (factor.Value == 0) { return(new Factor() { Direction = factor.Direction, Value = 0 }); } return(new Factor() { Direction = factor.Direction, Value = 1 }); }; var weightHandler = new DefaultWeightHandler(getShortestFactor); var checkForward = forward == null || forward.Value; var checkBackward = forward == null || !forward.Value; if (checkForward) { // build and run forward dykstra search. var dykstra = new Algorithms.Default.EdgeBased.Dykstra(_db.Network.GeometricGraph.Graph, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, true), point.ToEdgePaths(_db, weightHandler, true), radiusInMeter, false); dykstra.Run(); if (!dykstra.HasSucceeded || !dykstra.MaxReached) { // something went wrong or max not reached. return(new Result <bool>(false)); } } if (checkBackward) { // build and run backward dykstra search. var dykstra = new Algorithms.Default.EdgeBased.Dykstra(_db.Network.GeometricGraph.Graph, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, false), point.ToEdgePaths(_db, weightHandler, false), radiusInMeter, true); dykstra.Run(); if (!dykstra.HasSucceeded || !dykstra.MaxReached) { // something went wrong or max not reached. return(new Result <bool>(false)); } } return(new Result <bool>(true)); } catch (Exception ex) { return(new Result <bool>(ex.Message, (m) => ex)); } }