/// <summary> /// Calculates the edge path between this router point and the given router point. /// </summary> /// <param name="point">The source point.</param> /// <param name="db">The router db.</param> /// <param name="weightHandler">The weight handler.</param> /// <param name="sourceForward">The source forward flag, true if forward, false if backward, null if don't care.</param> /// <param name="target">The target point.</param> /// <param name="targetForward">The target forward flag, true if forward, false if backward, null if don't care.</param> public static EdgePath <T> EdgePathTo <T>(this RouterPoint point, RouterDb db, WeightHandler <T> weightHandler, bool?sourceForward, RouterPoint target, bool?targetForward) where T : struct { if (!sourceForward.HasValue && !targetForward.HasValue) { return(point.EdgePathTo(db, weightHandler, target)); } if (sourceForward.HasValue && targetForward.HasValue) { if (sourceForward.Value != targetForward.Value) { // impossible route inside one edge. return(null); } } if (sourceForward.HasValue) { return(point.EdgePathTo(db, weightHandler, target, !sourceForward.Value)); } return(point.EdgePathTo(db, weightHandler, target, !targetForward.Value)); }
/// <summary> /// Builds an edge path from a path consisiting of only vertices. /// </summary> public static EdgePath <T> BuildEdgePath <T>(this RouterDb routerDb, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target, List <uint> vertexPath) where T : struct { if (vertexPath == null || vertexPath.Count == 0) { return(null); } var path = new EdgePath <T>(vertexPath[0]); var i = 1; if (path.Vertex == Constants.NO_VERTEX) { // add first router point segment from source. path = source.EdgePathTo(routerDb, weightHandler, vertexPath[1]); i = 2; } var edgeEnumerator = routerDb.Network.GeometricGraph.Graph.GetEdgeEnumerator(); for (; i < vertexPath.Count; i++) { var vertex = vertexPath[i]; if (vertex == Constants.NO_VERTEX) { if (i != vertexPath.Count - 1) { throw new Exception("Invalid data found in vertex path: a non-vertex id was found at an invalid location."); } var toTarget = target.EdgePathTo(routerDb, weightHandler, path.Vertex, true); path = new EdgePath <T>(toTarget.Vertex, weightHandler.Add(toTarget.Weight, path.Weight), toTarget.Edge, path); break; } T weight; var best = edgeEnumerator.FindBestEdge(weightHandler, path.Vertex, vertexPath[i], out weight); if (best == Constants.NO_EDGE) { throw new Exception(string.Format("Cannot build vertex path, edge {0} -> {1} not found.", path.Vertex, vertexPath[i])); } path = new EdgePath <T>(vertexPath[i], weightHandler.Add(weight, path.Weight), best, path); } return(path); }
/// <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> /// 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; } } ContractedDb contracted; bool useContracted = false; if (_db.TryGetContracted(profileInstance.Profile, out contracted)) { // contracted calculation. useContracted = true; if (_db.HasComplexRestrictions(profileInstance.Profile) && (!contracted.HasEdgeBasedGraph && !contracted.NodeBasedIsEdgedBased)) { // 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; } } EdgePath <T> path = null; if (source.EdgeId == target.EdgeId) { // check for a path on the same edge. var edgePath = source.EdgePathTo(_db, weightHandler, target); if (edgePath != null) { path = edgePath; } } if (useContracted) { // use the contracted graph. List <uint> vertexPath = null; if (contracted.HasEdgeBasedGraph) { // 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) { if (path == null) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } } else { vertexPath = bidirectionalSearch.GetPath(); } } else if (contracted.NodeBasedIsEdgedBased) {// use vertex-based graph for edge-based routing. var sourceDirectedId1 = new DirectedEdgeId(source.EdgeId, true); var sourceDirectedId2 = new DirectedEdgeId(source.EdgeId, false); var targetDirectedId1 = new DirectedEdgeId(target.EdgeId, true); var targetDirectedId2 = new DirectedEdgeId(target.EdgeId, false); var bidirectionalSearch = new Itinero.Algorithms.Contracted.BidirectionalDykstra <T>(contracted.NodeBasedGraph, null, weightHandler, new EdgePath <T>[] { new EdgePath <T>(sourceDirectedId1.Raw), new EdgePath <T>(sourceDirectedId2.Raw) }, new EdgePath <T>[] { new EdgePath <T>(targetDirectedId1.Raw), new EdgePath <T>(targetDirectedId2.Raw) }); bidirectionalSearch.Run(); if (!bidirectionalSearch.HasSucceeded) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } var directedEdgePath = Algorithms.Dual.BidirectionalDykstraExtensions.GetDualPath(bidirectionalSearch); // convert directed edge-path to an original vertex path. var enumerator = _db.Network.GetEdgeEnumerator(); vertexPath = new List <uint>(); var edge = new List <OriginalEdge>(); for (var i = 0; i < directedEdgePath.Count; i++) { var e = new DirectedEdgeId() { Raw = directedEdgePath[i] }; enumerator.MoveToEdge(e.EdgeId); var original = new OriginalEdge(enumerator.From, enumerator.To); if (!e.Forward) { original = original.Reverse(); } edge.Add(original); if (vertexPath.Count == 0) { vertexPath.Add(original.Vertex1); } vertexPath.Add(original.Vertex2); } vertexPath[0] = Constants.NO_VERTEX; vertexPath[vertexPath.Count - 1] = Constants.NO_VERTEX; } else { // use node-based routing. var bidirectionalSearch = new Itinero.Algorithms.Contracted.BidirectionalDykstra <T>(contracted.NodeBasedGraph, _db.GetRestrictions(profileInstance.Profile), weightHandler, source.ToEdgePaths(_db, weightHandler, true), target.ToEdgePaths(_db, weightHandler, false)); bidirectionalSearch.Run(); if (!bidirectionalSearch.HasSucceeded) { if (path == null) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } } else { vertexPath = Algorithms.Contracted.BidirectionalDykstraExtensions.GetPath(bidirectionalSearch); } } // expand vertex path using the regular graph. if (vertexPath != null) { var localPath = _db.BuildEdgePath(weightHandler, source, target, vertexPath); if (path == null || weightHandler.IsSmallerThan(localPath.Weight, path.Weight)) { path = localPath; } } } else { // use the regular graph. EdgePath <T> localPath = null; 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) { if (path == null) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } } else { localPath = bidirectionalSearch.GetPath(); } } else { var sourceSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, _db.GetGetSimpleRestrictions(profileInstance.Profile), weightHandler, source.ToEdgePaths(_db, weightHandler, true), maxSearch, false); var targetSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, _db.GetGetSimpleRestrictions(profileInstance.Profile), weightHandler, target.ToEdgePaths(_db, weightHandler, false), maxSearch, true); var bidirectionalSearch = new BidirectionalDykstra <T>(sourceSearch, targetSearch, weightHandler); bidirectionalSearch.Run(); if (!bidirectionalSearch.HasSucceeded) { if (path == null) { return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } } else { localPath = bidirectionalSearch.GetPath(); } } // choose best path. if (localPath != null) { if (path == null || weightHandler.IsSmallerThan(localPath.Weight, path.Weight)) { path = localPath; } } } return(new Result <EdgePath <T> >(path)); } catch (Exception ex) { return(new Result <EdgePath <T> >(ex.Message, (m) => ex)); } }