public void TestTwoEdgesDirectedMiddleHighest() { // build graph. var graph = new DirectedDynamicGraph(ContractedEdgeDataSerializer.DynamicFixedSize); graph.AddEdge(0, 1, 100, true); graph.AddEdge(2, 1, 100, false); // create algorithm and run. var algorithm = new Itinero.Algorithms.Contracted.EdgeBased.BidirectionalDykstra(graph, new EdgePath <float>[] { new EdgePath <float>(0) }, new EdgePath <float>[] { new EdgePath <float>(2) }, x => null); algorithm.Run(); // check results. Assert.IsTrue(algorithm.HasRun); Assert.IsTrue(algorithm.HasSucceeded); Assert.AreEqual(1, algorithm.Best); EdgePath <float> visit; Assert.IsTrue(algorithm.TryGetForwardVisit(0, out visit)); Assert.AreEqual(0, visit.Weight); Assert.AreEqual(0, visit.Vertex); Assert.AreEqual(null, visit.From); Assert.IsTrue(algorithm.TryGetForwardVisit(1, out visit)); Assert.AreEqual(100, visit.Weight); Assert.AreEqual(1, visit.Vertex); Assert.IsNotNull(visit.From); Assert.AreEqual(0, visit.From.Vertex); Assert.IsTrue(algorithm.TryGetBackwardVisit(2, out visit)); Assert.AreEqual(0, visit.Weight); Assert.AreEqual(2, visit.Vertex); Assert.AreEqual(null, visit.From); Assert.IsTrue(algorithm.TryGetBackwardVisit(1, out visit)); Assert.AreEqual(100, visit.Weight); Assert.AreEqual(1, visit.Vertex); Assert.IsNotNull(visit.From); Assert.AreEqual(2, visit.From.Vertex); Assert.AreEqual(new List <uint>(new uint[] { 0, 1, 2 }), algorithm.GetPath()); }
/// <summary> /// Calculates a route between the two directed edges. The route starts in the direction of the edge and ends with an arrive in the direction of the target edge. /// </summary> /// <returns></returns> public sealed override Result <EdgePath <T> > TryCalculateRaw <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, long sourceDirectedEdge, long targetDirectedEdge, 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; } } var sourcePath = _db.GetPathForEdge(weightHandler, sourceDirectedEdge, true); var targetPath = _db.GetPathForEdge(weightHandler, targetDirectedEdge, false); if (sourceDirectedEdge == targetDirectedEdge) { // when edges match, path is always the edge itself. var edgePath = sourcePath; if (edgePath != null) { return(new Result <EdgePath <T> >(edgePath)); } } 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 (!contracted.HasEdgeBasedGraph) { Logging.Logger.Log("Router", Logging.TraceEventType.Warning, "There is a vertex-based contracted graph but it cannot be used to calculate routes with a start and end edge in a specific direction."); useContracted = false; } } if (useContracted) { // use the contracted graph. path = null; List <uint> vertexPath = null; if (!contracted.HasEdgeBasedGraph) { // use node-based routing. throw new Exception("Cannot use vertex-based contracted graph for edge-based calculations."); } else { // use edge-based routing. var bidirectionalSearch = new Algorithms.Contracted.EdgeBased.BidirectionalDykstra <T>(contracted.EdgeBasedGraph, weightHandler, new EdgePath <T>[] { sourcePath }, new EdgePath <T>[] { targetPath }, _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. var source = _db.CreateRouterPointForEdge(sourceDirectedEdge, true); var target = _db.CreateRouterPointForEdge(targetDirectedEdge, false); 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), new EdgePath <T>[] { sourcePath }, maxSearch, false); var targetSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, false), new EdgePath <T>[] { targetPath }, 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, new EdgePath <T>[] { sourcePath }, maxSearch, false); var targetSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, null, weightHandler, new EdgePath <T>[] { targetPath }, 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(); } } 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 directed edges. The route starts in the direction of the edge and ends with an arrive in the direction of the target edge. /// </summary> /// <returns></returns> public sealed override Result <EdgePath <T> > TryCalculateRaw <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, long sourceDirectedEdge, long targetDirectedEdge, 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; } } var sourcePath = _db.GetPathForEdge(weightHandler, sourceDirectedEdge, true); var targetPath = _db.GetPathForEdge(weightHandler, targetDirectedEdge, false); if (sourcePath == null) { return(new Result <EdgePath <T> >("Source edge cannot be routed along in the requested direction.")); } if (targetPath == null) { return(new Result <EdgePath <T> >("Target edge cannot be routed along in the requested direction.")); } if (sourceDirectedEdge == targetDirectedEdge) { // when edges match, path is always the edge itself. var edgePath = sourcePath; if (edgePath != null) { return(new Result <EdgePath <T> >(edgePath)); } } 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 && !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; } if (!contracted.HasEdgeBasedGraph && !contracted.NodeBasedIsEdgedBased) { Logging.Logger.Log("Router", Logging.TraceEventType.Warning, "There is a vertex-based contracted graph but it cannot be used to calculate routes with a start and end edge in a specific direction."); useContracted = false; } } if (useContracted) { // use the contracted graph. path = null; List <uint> vertexPath = null; if (contracted.HasEdgeBasedGraph) { // use edge-based routing. var bidirectionalSearch = new Algorithms.Contracted.EdgeBased.BidirectionalDykstra <T>(contracted.EdgeBasedGraph, weightHandler, new EdgePath <T>[] { sourcePath }, new EdgePath <T>[] { targetPath }, _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(); } else if (contracted.HasNodeBasedGraph && contracted.NodeBasedIsEdgedBased) { // use vertex-based graph for edge-based routing. var sourceDirectedId = new DirectedEdgeId(sourceDirectedEdge); var targetDirectedId = new DirectedEdgeId(targetDirectedEdge); var bidirectionalSearch = new Itinero.Algorithms.Contracted.BidirectionalDykstra <T>(contracted.NodeBasedGraph, null, weightHandler, new EdgePath <T>[] { new EdgePath <T>(sourceDirectedId.Raw) }, new EdgePath <T>[] { new EdgePath <T>(targetDirectedId.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>(); 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(); } if (vertexPath.Count == 0) { vertexPath.Add(original.Vertex1); } vertexPath.Add(original.Vertex2); } } else { throw new Exception("Cannot use vertex-based contracted graph for edge-based calculations."); } // expand vertex path using the regular graph. var source = _db.CreateRouterPointForEdge(sourceDirectedEdge, true); var target = _db.CreateRouterPointForEdge(targetDirectedEdge, false); path = _db.BuildEdgePath(weightHandler, source, target, vertexPath); } else { // use the regular graph. var sourceSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, true), new EdgePath <T>[] { sourcePath }, maxSearch, false); var targetSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, false), new EdgePath <T>[] { targetPath }, 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(); } return(new Result <EdgePath <T> >(path)); } catch (Exception ex) { return(new Result <EdgePath <T> >(ex.Message, (m) => ex)); } }