/// <summary> /// Gets the path to the given stop. /// </summary> public EdgePath <float> GetPath(uint stop) { EdgePath <float> best = null; var bestWeight = float.MaxValue; _stopLinksDbEnumerator.MoveTo(stop); while (_stopLinksDbEnumerator.MoveNext()) { var point = new RouterPoint(0, 0, _stopLinksDbEnumerator.EdgeId, _stopLinksDbEnumerator.Offset); if (point.EdgeId == _routerPoint.EdgeId) { // on the same edge. EdgePath <float> path; if (_backward) { // from stop -> source. path = point.EdgePathTo(_multimodalDb.RouterDb, new DefaultWeightHandler(_getFactor), _routerPoint); } else { // from source -> stop. path = _routerPoint.EdgePathTo(_multimodalDb.RouterDb, new DefaultWeightHandler(_getFactor), point); } if (path.Weight < bestWeight) { // set as best because improvement. best = path; bestWeight = path.Weight; } } else { // on different edge, to the usual. var paths = point.ToEdgePaths(_multimodalDb.RouterDb, new DefaultWeightHandler(_getFactor), _backward); EdgePath <float> visit; if (_dykstra.TryGetVisit(paths[0].Vertex, out visit)) { // check if this one is better. if (visit.Weight + paths[0].Weight < bestWeight) { // concatenate paths and set best. if (paths[0].Weight == 0) { // just use the visit. best = visit; } else { // there is a distance/weight. best = new EdgePath <float>(Itinero.Constants.NO_VERTEX, paths[0].Weight + visit.Weight, visit); } bestWeight = best.Weight; } } if (paths.Length > 1 && _dykstra.TryGetVisit(paths[1].Vertex, out visit)) { // check if this one is better. if (visit.Weight + paths[1].Weight < bestWeight) { // concatenate paths and set best. if (paths[1].Weight == 0) { // just use the visit. best = visit; } else { // there is a distance/weight. best = new EdgePath <float>(Itinero.Constants.NO_VERTEX, paths[1].Weight + visit.Weight, visit); } bestWeight = best.Weight; } } } } return(best); }
/// <summary> /// Builds a route. /// </summary> public static Route Build(RouterDb db, Profile profile, RouterPoint source, RouterPoint target, EdgePath <float> path) { return(CompleteRouteBuilder.Build(db, profile, source, target, path, CancellationToken.None)); }
/// <summary> /// Builds a route. /// </summary> public static Route Build(RouterDb db, Profile profile, RouterPoint source, RouterPoint target, EdgePath <float> path) { return(CompleteRouteBuilder.TryBuild(db, profile, source, target, path).Value); }
/// <summary> /// Returns a coverage of the given edge. /// </summary> /// <returns></returns> public static List <EdgeCover> CoveredEdges(this Router router, RouterPoint origin, RouterPoint target, EdgePath <float> path) { // TODO: (optional) parameter validation. // TODO: (optional) make sure the routerpoints match the path. var pathList = path.ToList(); var edges = new List <EdgeCover>(pathList.Count - 1); // loop over all pairs, or in other words over all edges. EdgePath <float> previous = null; for (var i = 0; i < pathList.Count; i++) { var current = pathList[i]; if (previous != null) { var startPercentage = 0f; if (previous.Vertex == Constants.NO_VERTEX) { startPercentage = ((float)origin.Offset / ushort.MaxValue) * 100.0f; if (current.Edge < 0) { startPercentage = 100 - startPercentage; } } var endPercentage = 100f; if (current.Vertex == Constants.NO_VERTEX) { endPercentage = ((float)target.Offset / ushort.MaxValue) * 100.0f; if (current.Edge < 0) { endPercentage = 100 - endPercentage; } } if (current.Vertex != Constants.NO_VERTEX && previous.Vertex != Constants.NO_VERTEX) { var edge = router.Db.Network.GetEdgeEnumerator(previous.Vertex).First(x => x.To == current.Vertex); } edges.Add(new EdgeCover() { DirectedEdgeId = new DirectedEdgeId(current.Edge), EndPercentage = endPercentage, StartPercentage = startPercentage }); } previous = current; } return(edges); }
/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { // while the visit list is not empty. _current = null; if (_heap.Count > 0) { // choose the next vertex. _current = _heap.Pop(); while (_current != null && _visits.ContainsKey(_current.Vertex)) { // keep dequeuing. if (_heap.Count == 0) { // nothing more to pop. return(false); } if (this.Visit != null && this.Visit(_current)) { // edge was found and true was returned, this search should stop. return(false); } _current = _heap.Pop(); } } else { // no more visits possible. return(false); } if (_current == null) { // route is not found, there are no vertices left return(false); } // check for restrictions. var restriction = Constants.NO_VERTEX; if (_getRestriction != null) { restriction = _getRestriction(_current.Vertex); } if (restriction != Constants.NO_VERTEX) { // this vertex is restricted, step is a success but just move // to the next one because this vertex's neighbours are not allowed. return(true); } // we visit this one, set visit _visits[_current.Vertex] = _current; if (this.WasFound != null && this.WasFound(_current.Vertex, _current.Weight)) { // vertex was found and true was returned, this search should stop. return(false); } if (this.Visit != null && this.Visit(_current)) { // edge was found and true was returned, this search should stop. return(false); } // get neighbours and queue them. _edgeEnumerator.MoveTo(_current.Vertex); while (_edgeEnumerator.MoveNext()) { var edge = _edgeEnumerator; var neighbour = edge.To; // is this edge closed? if (_closures.Contains(edge.Id)) { // bypass continue; } if (_current.From != null && _current.From.Vertex == neighbour) { // don't go back continue; } if (this.Visit == null) { if (_visits.ContainsKey(neighbour)) { // has already been choosen continue; } } // get the speed from cache or calculate. float distance; ushort edgeProfile; EdgeDataSerializer.Deserialize(edge.Data0, out distance, out edgeProfile); var factor = Factor.NoFactor; var totalWeight = _weightHandler.Add(_current.Weight, edgeProfile, distance, out factor); // check the tags against the interpreter. if (factor.Value > 0 && (factor.Direction == 0 || (!_backward && (factor.Direction == 1) != edge.DataInverted) || (_backward && (factor.Direction == 1) == edge.DataInverted))) { // it's ok; the edge can be traversed by the given vehicle. // calculate neighbors weight. var edgeWeight = (distance * factor.Value); if (_weightHandler.IsSmallerThan(totalWeight, _sourceMax)) { // update the visit list. _heap.Push(new EdgePath <T>(neighbour, totalWeight, edge.IdDirected(), _current), _weightHandler.GetMetric(totalWeight)); } else { // the maxium was reached. this.MaxReached = true; } } } return(true); }
/// <summary> /// Builds a route based on a raw path. /// </summary> public abstract Result <Route> BuildRoute <T>(IProfileInstance profile, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target, EdgePath <T> path) where T : struct;
/// <summary> /// Calculates witness paths with just one hop. /// </summary> public void ExistsOneHop(DirectedDynamicGraph graph, uint source, List <uint> targets, List <T> weights, ref EdgePath <T>[] forwardExists, ref EdgePath <T>[] backwardExists) { var targetsToCalculate = new HashSet <uint>(); var maxWeight = _weightHandler.Zero; for (int idx = 0; idx < weights.Count; idx++) { if (forwardExists[idx] == null || backwardExists[idx] == null) { targetsToCalculate.Add(targets[idx]); if (_weightHandler.IsSmallerThan(maxWeight, weights[idx])) { maxWeight = weights[idx]; } } if (forwardExists[idx] == null) { forwardExists[idx] = new EdgePath <T>(); } if (backwardExists[idx] == null) { backwardExists[idx] = new EdgePath <T>(); } } if (targetsToCalculate.Count > 0) { var edgeEnumerator = graph.GetEdgeEnumerator(source); while (edgeEnumerator.MoveNext()) { var neighbour = edgeEnumerator.Neighbour; if (targetsToCalculate.Contains(neighbour)) { // ok, this is a to-edge. var index = targets.IndexOf(neighbour); targetsToCalculate.Remove(neighbour); bool?neighbourDirection; var neighbourWeight = _weightHandler.GetEdgeWeight(edgeEnumerator.Current, out neighbourDirection); var neighbourCanMoveForward = neighbourDirection == null || neighbourDirection.Value; var neighbourCanMoveBackward = neighbourDirection == null || !neighbourDirection.Value; if (neighbourCanMoveForward && _weightHandler.IsSmallerThan(neighbourWeight, weights[index])) { forwardExists[index] = new EdgePath <T>(neighbour, neighbourWeight, edgeEnumerator.IdDirected(), new EdgePath <T>(source)); } if (neighbourCanMoveBackward && _weightHandler.IsSmallerThan(neighbourWeight, weights[index])) { backwardExists[index] = new EdgePath <T>(neighbour, neighbourWeight, edgeEnumerator.IdDirected(), new EdgePath <T>(source));; } if (targetsToCalculate.Count == 0) { break; } } } } }
/// <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)); } }
/// <summary> /// Calculates all routes between all sources and all targets. /// </summary> /// <returns></returns> public sealed override Result <EdgePath <T>[][]> TryCalculateRaw <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, RouterPoint[] sources, RouterPoint[] targets, 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; EdgePath <T>[][] paths = null; 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 (!weightHandler.CanUse(contracted)) { // there is a contracted graph but it is not equipped to handle this weight-type. Logging.Logger.Log("Router", Logging.TraceEventType.Warning, "There is a contracted graph but it's not built for the given weight calculations, using the default but slow implementation."); useContracted = false; } } if (useContracted) { if (contracted.HasEdgeBasedGraph) { // use edge-based routing. var algorithm = new Itinero.Algorithms.Contracted.EdgeBased.ManyToManyBidirectionalDykstra <T>(_db, profileInstance.Profile, weightHandler, sources, targets, maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <EdgePath <T>[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } // build all routes. paths = new EdgePath <T> [sources.Length][]; for (var s = 0; s < sources.Length; s++) { paths[s] = new EdgePath <T> [targets.Length]; for (var t = 0; t < targets.Length; t++) { paths[s][t] = algorithm.GetPath(s, t); } } } else if (contracted.HasNodeBasedGraph && contracted.NodeBasedIsEdgedBased) { // use vertex-based graph for edge-based routing. var algorithm = new Itinero.Algorithms.Contracted.Dual.ManyToMany.VertexToVertexAlgorithm <T>(contracted.NodeBasedGraph, weightHandler, Itinero.Algorithms.Contracted.Dual.RouterPointExtensions.ToDualDykstraSources(sources, _db, weightHandler, true), Itinero.Algorithms.Contracted.Dual.RouterPointExtensions.ToDualDykstraSources(targets, _db, weightHandler, false), maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <EdgePath <T>[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } // build all routes. paths = new EdgePath <T> [sources.Length][]; for (var s = 0; s < sources.Length; s++) { paths[s] = new EdgePath <T> [targets.Length]; for (var t = 0; t < targets.Length; t++) { var path = algorithm.GetPath(s, t); if (path != null) { path = _db.BuildDualEdgePath(weightHandler, sources[s], targets[t], path); } paths[s][t] = path; } } } else { // use node-based routing. var algorithm = new Itinero.Algorithms.Contracted.ManyToManyBidirectionalDykstra <T>(_db, profileInstance.Profile, weightHandler, sources, targets, maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <EdgePath <T>[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } // build all routes. paths = new EdgePath <T> [sources.Length][]; for (var s = 0; s < sources.Length; s++) { paths[s] = new EdgePath <T> [targets.Length]; for (var t = 0; t < targets.Length; t++) { paths[s][t] = algorithm.GetPath(s, t); } } } } if (paths == null) { // use non-contracted calculation. var algorithm = new Itinero.Algorithms.Default.ManyToMany <T>(_db, weightHandler, sources, targets, maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <EdgePath <T>[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } // build all routes. paths = new EdgePath <T> [sources.Length][]; for (var s = 0; s < sources.Length; s++) { paths[s] = new EdgePath <T> [targets.Length]; for (var t = 0; t < targets.Length; t++) { paths[s][t] = algorithm.GetPath(s, t); } } } return(new Result <EdgePath <T>[][]>(paths)); } catch (Exception ex) { return(new Result <EdgePath <T>[][]>(ex.Message, (m) => ex)); } }
/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { // while the visit list is not empty. _current = null; if (_heap.Count > 0) { // choose the next vertex. _current = _heap.Pop(); while (_current != null && _visits.ContainsKey(_current.Edge)) { // keep dequeuing. if (_heap.Count == 0) { // nothing more to pop. break; } _current = _heap.Pop(); } } if (_current != null) { // we visit this one, set visit. if (_current.Edge != Constants.NO_EDGE) { _visits[_current.Edge] = _current; // report on visit. if (this.Visit != null) { if (this.Visit(_current)) { return(true); } } } } else { // route is not found, there are no vertices left // or the search went outside of the max bounds. return(false); } // move to the current edge's target vertex. _edgeEnumerator.MoveTo(_current.Vertex); // get new restrictions at the current vertex. LinkedRestriction restrictions = null; if (_edgeRestrictions.TryGetValue(_current, out restrictions)) { _edgeRestrictions.Remove(_current); } if (_getRestriction != null) { var targetVertexRestriction = _getRestriction(_current.Vertex); if (targetVertexRestriction != null) { foreach (var restriction in targetVertexRestriction) { if (restriction != null && restriction.Length > 0) { if (restriction.Length == 1) { // a simple restriction, restricted vertex, no need to check outgoing edges. return(true); } else { // a complex restriction. restrictions = new LinkedRestriction() { Restriction = restriction, Next = restrictions }; } } } } } while (_edgeEnumerator.MoveNext()) { var edge = _edgeEnumerator; var directedEdgeId = _edgeEnumerator.IdDirected(); var neighbour = edge.To; if (directedEdgeId == -_current.Edge) { // don't go back. continue; } if (_visits.ContainsKey(directedEdgeId)) { // has already been choosen. continue; } // get the speed from cache or calculate. float distance; ushort edgeProfile; EdgeDataSerializer.Deserialize(edge.Data0, out distance, out edgeProfile); var factor = Factor.NoFactor; var edgeWeight = _weightHandler.Calculate(edgeProfile, distance, out factor); // check the tags against the interpreter. if (factor.Value > 0 && (factor.Direction == 0 || (!_backward && (factor.Direction == 1) != edge.DataInverted) || (_backward && (factor.Direction == 1) == edge.DataInverted))) { // it's ok; the edge can be traversed by the given vehicle. // verify restriction(s). var currentRestriction = restrictions; var forbidden = false; LinkedRestriction newRestrictions = null; while (currentRestriction != null) { // check if some restriction prohibits this move or if we need add a new restriction // for the current edge. if (currentRestriction.Restriction[1] == _edgeEnumerator.To) { // ok restrictions applies to this edge and the previous one. if (currentRestriction.Restriction.Length == 2) { // ok this is the last edge in this restriction, prohibit this move. forbidden = true; break; } else { // append this restriction to the restrictions in for the current edge. newRestrictions = new LinkedRestriction() { Restriction = currentRestriction.Restriction.SubArray(1, currentRestriction.Restriction.Length - 1), Next = newRestrictions }; } } currentRestriction = currentRestriction.Next; } if (forbidden) { // move to next neighbour. continue; } // calculate neighbors weight. var totalWeight = _weightHandler.Add(_current.Weight, edgeWeight); if (_weightHandler.IsSmallerThan(totalWeight, _sourceMax)) { // update the visit list. var path = new EdgePath <T>(neighbour, totalWeight, directedEdgeId, _current); if (newRestrictions != null) { _edgeRestrictions[path] = newRestrictions; } _heap.Push(path, _weightHandler.GetMetric(totalWeight)); } else { // the maxium was reached. this.MaxReached = true; } } } return(true); }
/// <summary> /// Returns true if the given edge was visited and sets the visit output parameters with the actual visit data. /// </summary> public bool TryGetVisit(long edge, out EdgePath <T> visit) { return(_visits.TryGetValue(edge, out visit)); }
/// <summary> /// Executes the actual run of the algorithm. /// </summary> protected override void DoRun() { _best = new EdgePath <T> [_targets.Count]; // register the targets and determine one-edge-paths. var sourcePaths = _source.ToEdgePaths(_routerDb, _weightHandler, true); var targetIndexesPerVertex = new Dictionary <uint, LinkedTarget>(); var targetPaths = new IEnumerable <EdgePath <T> > [_targets.Count]; for (var i = 0; i < _targets.Count; i++) { var targets = _targets[i].ToEdgePaths(_routerDb, _weightHandler, false); targetPaths[i] = targets; // determine one-edge-paths. if (_source.EdgeId == _targets[i].EdgeId) { // on same edge. _best[i] = _source.EdgePathTo(_routerDb, _weightHandler, _targets[i]); } // register targets. for (var t = 0; t < targets.Length; t++) { var target = targetIndexesPerVertex.TryGetValueOrDefault(targets[t].Vertex); targetIndexesPerVertex[targets[t].Vertex] = new LinkedTarget() { Target = i, Next = target }; } } // determine the best max search radius. var max = _weightHandler.Zero; for (var s = 0; s < _best.Length; s++) { if (_best[s] == null) { max = _maxSearch; } else { if (_weightHandler.IsLargerThan(_best[s].Weight, max)) { max = _best[s].Weight; } } } // run the search. var dykstra = new Dykstra <T>(_routerDb.Network.GeometricGraph.Graph, null, _weightHandler, sourcePaths, max, _closures, false); dykstra.WasFound += (vertex, weight) => { LinkedTarget target; if (targetIndexesPerVertex.TryGetValue(vertex, out target)) { // there is a target for this vertex. while (target != null) { var best = _best[target.Target]; foreach (var targetPath in targetPaths[target.Target]) { EdgePath <T> path; dykstra.TryGetVisit(vertex, out path); if (targetPath.Vertex == vertex) { // there is a path here. var total = _weightHandler.Add(targetPath.Weight, weight); if (best == null || _weightHandler.IsSmallerThan(total, best.Weight)) { // not a best path yet, just add this one. if (_targets[target.Target].IsVertex(_routerDb, path.Vertex)) { // target is the exact vertex. best = path; } else { // target is not the exact vertex. best = new EdgePath <T>(_targets[target.Target].VertexId(_routerDb), total, path); } } break; } } // set again. _best[target.Target] = best; // move to next target. target = target.Next; } } return(false); }; dykstra.Run(); this.HasSucceeded = true; }
/// <summary> /// Builds a route. /// </summary> public static Result <Route> TryBuild(RouterDb db, Profile profile, Func <ushort, Profiles.Factor> getFactor, RouterPoint source, RouterPoint target, EdgePath <float> path) { var pathList = new List <uint>(); path.AddToListAsVertices(pathList); return(FastRouteBuilder.TryBuild(db, profile, getFactor, source, target, pathList)); }
/// <summary> /// Builds a route. /// </summary> public static Route Build(RouterDb db, Profile profile, Func <ushort, Profiles.Factor> getFactor, RouterPoint source, RouterPoint target, EdgePath <float> path) { return(FastRouteBuilder.TryBuild(db, profile, getFactor, source, target, path).Value); }
public override Result <Route> BuildRoute <T>(IProfileInstance profile, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target, EdgePath <T> path) { var route = new Route(); route.Shape = new Coordinate[] { source.Location(), target.Location() }; return(new Result <Route>(route)); }
/// <summary> /// Builds a route. /// </summary> public override sealed Result <Route> BuildRoute <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target, EdgePath <T> path) { try { if (this.CustomRouteBuilder != null) { // there is a custom route builder. return(this.CustomRouteBuilder.TryBuild(_db, profileInstance.Profile, source, target, path)); } // use the default. return(CompleteRouteBuilder.TryBuild(_db, profileInstance.Profile, source, target, path)); } catch (Exception ex) { return(new Result <Route>(ex.Message, (m) => ex)); } }
/// <summary> /// Calculates the priority of the given vertex. /// </summary> public float Calculate(BitArray32 contractedFlags, Func <uint, IEnumerable <uint[]> > getRestrictions, uint vertex) { var removed = 0; var added = 0; // get and keep edges. var edges = new List <DynamicEdge>(_graph.GetEdgeEnumerator(vertex)); // check if this vertex has a potential restrictions. var restrictions = getRestrictions(vertex); var hasRestrictions = restrictions != null && restrictions.Any(); // remove 'downward' edge to vertex. var i = 0; while (i < edges.Count) { var edgeEnumerator = _graph.GetEdgeEnumerator(edges[i].Neighbour); edgeEnumerator.Reset(); while (edgeEnumerator.MoveNext()) { if (edgeEnumerator.Neighbour == vertex) { removed++; } } if (contractedFlags[edges[i].Neighbour]) { // neighbour was already contracted, remove 'downward' edge and exclude it. edgeEnumerator.MoveTo(vertex); edgeEnumerator.Reset(); while (edgeEnumerator.MoveNext()) { if (edgeEnumerator.Neighbour == edges[i].Neighbour) { removed++; } } edges.RemoveAt(i); } else { // move to next edge. i++; } } // loop over all edge-pairs once. for (var j = 1; j < edges.Count; j++) { var edge1 = edges[j]; bool?edge1Direction; var edge1Weight = _weightHandler.GetEdgeWeight(edge1, out edge1Direction); var edge1CanMoveForward = edge1Direction == null || edge1Direction.Value; var edge1CanMoveBackward = edge1Direction == null || !edge1Direction.Value; // figure out what witness paths to calculate. var forwardWitnesses = new EdgePath <T> [j]; var backwardWitnesses = new EdgePath <T> [j]; var targets = new List <uint>(j); var targetWeights = new List <T>(j); for (var k = 0; k < j; k++) { var edge2 = edges[k]; bool?edge2Direction; var edge2Weight = _weightHandler.GetEdgeWeight(edge2, out edge2Direction); var edge2CanMoveForward = edge2Direction == null || edge2Direction.Value; var edge2CanMoveBackward = edge2Direction == null || !edge2Direction.Value; if (!(edge1CanMoveBackward && edge2CanMoveForward)) { forwardWitnesses[k] = new EdgePath <T>(); } if (!(edge1CanMoveForward && edge2CanMoveBackward)) { backwardWitnesses[k] = new EdgePath <T>(); } targets.Add(edge2.Neighbour); if (hasRestrictions) { // weight can potentially be bigger. targetWeights.Add(_weightHandler.Infinite); } else { // weight can max be the sum of the two edges. targetWeights.Add(_weightHandler.Add(edge1Weight, edge2Weight)); } } // calculate all witness paths. _witnessCalculator.Calculate(_graph, getRestrictions, edge1.Neighbour, targets, targetWeights, ref forwardWitnesses, ref backwardWitnesses, Constants.NO_VERTEX); // add contracted edges if needed. for (var k = 0; k < j; k++) { var edge2 = edges[k]; var removedLocal = 0; var addedLocal = 0; if (forwardWitnesses[k].HasVertex(vertex) && backwardWitnesses[k].HasVertex(vertex)) { // add bidirectional edge. _graph.TryAddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, _weightHandler.GetMetric(targetWeights[k]), null, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; _graph.TryAddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, _weightHandler.GetMetric(targetWeights[k]), null, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; } else if (forwardWitnesses[k].HasVertex(vertex)) { // add forward edge. _graph.TryAddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, _weightHandler.GetMetric(targetWeights[k]), true, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; _graph.TryAddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, _weightHandler.GetMetric(targetWeights[k]), false, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; } else if (backwardWitnesses[k].HasVertex(vertex)) { // add forward edge. _graph.TryAddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, _weightHandler.GetMetric(targetWeights[k]), false, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; _graph.TryAddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, _weightHandler.GetMetric(targetWeights[k]), true, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; } } } var contracted = 0; _contractionCount.TryGetValue(vertex, out contracted); var depth = 0; _depth.TryGetValue(vertex, out depth); return(this.DifferenceFactor * (added - removed) + (this.DepthFactor * depth) + (this.ContractedFactor * contracted)); }
/// <summary> /// Search backward from one vertex. /// </summary> /// <returns></returns> private void SearchBackward(DirectedDynamicGraph.EdgeEnumerator edgeEnumerator, EdgePath <T> current, IEnumerable <uint[]> restrictions) { if (current != null) { // there is a next vertex found. // get the edge enumerator. var currentSequence = current.GetSequence2(edgeEnumerator); currentSequence = currentSequence.Append(current.Vertex); // get neighbours. edgeEnumerator.MoveTo(current.Vertex); // add the neighbours to the queue. while (edgeEnumerator.MoveNext()) { bool?neighbourDirection; var neighbourWeight = _weightHandler.GetEdgeWeight(edgeEnumerator.Current, out neighbourDirection); if (neighbourDirection == null || !neighbourDirection.Value) { // the edge is forward, and is to higher or was not contracted at all. var neighbourNeighbour = edgeEnumerator.Neighbour; var neighbourSequence = Constants.EMPTY_SEQUENCE; if (edgeEnumerator.IsOriginal()) { // original edge. if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourNeighbour) { // this is a u-turn. continue; } if (restrictions != null) { neighbourSequence = currentSequence.Append(neighbourNeighbour); } } else { // not an original edge, use the sequence. neighbourSequence = edgeEnumerator.GetSequence1(); if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourSequence[0]) { // this is a u-turn. continue; } if (restrictions != null) { neighbourSequence = currentSequence.Append(neighbourSequence); } } if (restrictions != null) { // check restrictions. neighbourSequence.Reverse(); if (!restrictions.IsSequenceAllowed(neighbourSequence)) { continue; } } // build route to neighbour and check if it has been visited already. var routeToNeighbour = new EdgePath <T>( neighbourNeighbour, _weightHandler.Add(current.Weight, neighbourWeight), edgeEnumerator.IdDirected(), current); LinkedEdgePath edgePath = null; if (!_backwardVisits.TryGetValue(current.Vertex, out edgePath) || !edgePath.HasPath(routeToNeighbour)) { // this vertex has not been visited in this way before. _backwardQueue.Push(routeToNeighbour, _weightHandler.GetMetric(routeToNeighbour.Weight)); } } } } }
/// <summary> /// Executes the algorithm. /// </summary> protected sealed override void DoRun() { // run mass resolver if needed. if (!_massResolver.HasRun) { _massResolver.Run(); } // create error and resolved point management data structures. _correctedResolvedPoints = _massResolver.RouterPoints; _errors = new Dictionary <int, RouterPointError>(_correctedResolvedPoints.Count); _correctedIndices = new List <int>(_correctedResolvedPoints.Count); // convert sources into directed paths. _sourcePaths = new EdgePath <T> [_correctedResolvedPoints.Count * 2]; for (var i = 0; i < _correctedResolvedPoints.Count; i++) { _correctedIndices.Add(i); var paths = _correctedResolvedPoints[i].ToEdgePathsDirectedFixed(_router.Db, _weightHandler, true); if (paths.Length == 0) { this.ErrorMessage = string.Format("Source at {0} could not be resolved properly.", i); return; } _sourcePaths[i * 2 + 0] = paths[0]; _sourcePaths[i * 2 + 1] = paths[1]; } // convert targets into directed paths. _targetPaths = new EdgePath <T> [_correctedResolvedPoints.Count * 2]; for (var i = 0; i < _correctedResolvedPoints.Count; i++) { var paths = _correctedResolvedPoints[i].ToEdgePathsDirectedFixed(_router.Db, _weightHandler, false); if (paths.Length == 0) { this.ErrorMessage = string.Format("Target at {0} could not be resolved properly.", i); return; } _targetPaths[i * 2 + 0] = paths[1]; _targetPaths[i * 2 + 1] = paths[0]; } // put in default weights and weights for one-edge-paths. _weights = new T[_sourcePaths.Length][]; for (var i = 0; i < _sourcePaths.Length; i++) { var source = _sourcePaths[i]; _weights[i] = new T[_targetPaths.Length]; for (var j = 0; j < _targetPaths.Length; j++) { var target = _targetPaths[j]; _weights[i][j] = _weightHandler.Infinite; if (source == null || target == null) { continue; } if (target.Edge == -source.Edge) { var s = i / 2; var t = j / 2; var sourcePoint = _correctedResolvedPoints[s]; var targetPoint = _correctedResolvedPoints[t]; EdgePath <T> newPath = null; if (source.Edge > 0 && sourcePoint.Offset <= targetPoint.Offset) { newPath = sourcePoint.EdgePathTo(_router.Db, _weightHandler, targetPoint); } else if (source.Edge < 0 && sourcePoint.Offset >= targetPoint.Offset) { newPath = sourcePoint.EdgePathTo(_router.Db, _weightHandler, targetPoint); } if (newPath != null) { if (_weightHandler.IsLargerThan(_weights[i][j], newPath.Weight)) { _weights[i][j] = newPath.Weight; } } } } } // run the actual calculations. if (_graph != null) { this.DoEdgeBased(); } else { this.DoDualBased(); } // check for invalids. var originalInvalids = new HashSet <int>(); var invalidTargetCounts = new int[_weights.Length / 2]; for (var s = 0; s < _weights.Length / 2; s++) { var invalids = 0; for (var t = 0; t < _weights[s * 2].Length / 2; t++) { if (t != s) { if (_weightHandler.GetMetric(_weights[s * 2 + 0][t * 2 + 0]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 0][t * 2 + 1]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 1][t * 2 + 0]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 1][t * 2 + 1]) == float.MaxValue) { invalids++; invalidTargetCounts[t]++; if (invalidTargetCounts[t] > ((_weights.Length / 2) - 1) / 2) { originalInvalids.Add(t); } } } } if (invalids > ((_weights.Length / 2) - 1) / 2) { originalInvalids.Add(s); } } // take into account the non-null invalids now. if (originalInvalids.Count > 0) { // shrink lists and add errors. _correctedResolvedPoints = _correctedResolvedPoints.ShrinkAndCopyList(originalInvalids); _correctedIndices = _correctedIndices.ShrinkAndCopyList(originalInvalids); // convert back to the path indexes. var nonNullInvalids = new HashSet <int>(); foreach (var invalid in originalInvalids) { nonNullInvalids.Add(invalid * 2); nonNullInvalids.Add(invalid * 2 + 1); _errors[invalid] = new RouterPointError() { Code = RouterPointErrorCode.NotRoutable, Message = "Location could not routed to or from." }; } _weights = _weights.SchrinkAndCopyMatrix(nonNullInvalids); _sourcePaths = _sourcePaths.ShrinkAndCopyArray(nonNullInvalids); _targetPaths = _targetPaths.ShrinkAndCopyArray(nonNullInvalids); } this.HasSucceeded = true; }
/// <summary> /// Tries to get the path from source to target. /// </summary> public bool TryGetPath(int source, int target, out EdgePath <T> path) { this.CheckHasRunAndHasSucceeded(); return(_sourceSearches[source].TryGetPath(target, out path)); }
/// <summary> /// Calculates witness paths. /// </summary> public void Calculate(DirectedDynamicGraph graph, Func <uint, IEnumerable <uint[]> > getRestrictions, uint source, List <uint> targets, List <T> weights, ref EdgePath <T>[] forwardWitness, ref EdgePath <T>[] backwardWitness, uint vertexToSkip) { if (_hopLimit == 1) { this.ExistsOneHop(graph, source, targets, weights, ref forwardWitness, ref backwardWitness); return; } // creates the settled list. var backwardSettled = new HashSet <EdgePath <T> >(); var forwardSettled = new HashSet <EdgePath <T> >(); var backwardTargets = new HashSet <uint>(); var forwardTargets = new HashSet <uint>(); T forwardMaxWeight = _weightHandler.Zero, backwardMaxWeight = _weightHandler.Zero; for (int idx = 0; idx < weights.Count; idx++) { if (forwardWitness[idx] == null) { forwardWitness[idx] = new EdgePath <T>(); forwardTargets.Add(targets[idx]); if (_weightHandler.IsSmallerThan(forwardMaxWeight, weights[idx])) { forwardMaxWeight = weights[idx]; } } if (backwardWitness[idx] == null) { backwardWitness[idx] = new EdgePath <T>(); backwardTargets.Add(targets[idx]); if (_weightHandler.IsSmallerThan(backwardMaxWeight, weights[idx])) { backwardMaxWeight = weights[idx]; } } } if (_weightHandler.GetMetric(forwardMaxWeight) == 0 && _weightHandler.GetMetric(backwardMaxWeight) == 0) { // no need to search! return; } // creates the priorty queue. var forwardMinWeight = new Dictionary <EdgePath <T>, T>(); var backwardMinWeight = new Dictionary <EdgePath <T>, T>(); _heap.Clear(); _heap.Push(new SettledEdge(new EdgePath <T>(source), 0, _weightHandler.GetMetric(forwardMaxWeight) > 0, _weightHandler.GetMetric(backwardMaxWeight) > 0), 0); // keep looping until the queue is empty or the target is found! var edgeEnumerator = graph.GetEdgeEnumerator(); while (_heap.Count > 0) { // pop the first customer. var current = _heap.Pop(); if (current.Hops + 1 < _hopLimit) { if (current.Path.Vertex == vertexToSkip) { // this is the vertex being contracted. continue; } var forwardWasSettled = forwardSettled.Contains(current.Path); var backwardWasSettled = backwardSettled.Contains(current.Path); if (forwardWasSettled && backwardWasSettled) { // both are already settled. continue; } if (current.Forward) { // this is a forward settle. forwardSettled.Add(current.Path); forwardMinWeight.Remove(current.Path); if (forwardTargets.Contains(current.Path.Vertex)) { for (var i = 0; i < targets.Count; i++) { if (targets[i] == current.Path.Vertex && _weightHandler.IsSmallerThanOrEqual(current.Path.Weight, weights[i])) { // TODO: check if this is a proper stop condition. if (forwardWitness[i] == null || forwardWitness[i].Vertex == Constants.NO_VERTEX || _weightHandler.IsSmallerThan(current.Path.Weight, forwardWitness[i].Weight)) { forwardWitness[i] = current.Path; forwardTargets.Remove(current.Path.Vertex); } } } } } if (current.Backward) { // this is a backward settle. backwardSettled.Add(current.Path); backwardMinWeight.Remove(current.Path); if (backwardTargets.Contains(current.Path.Vertex)) { for (var i = 0; i < targets.Count; i++) { if (targets[i] == current.Path.Vertex && _weightHandler.IsSmallerThanOrEqual(current.Path.Weight, weights[i])) { // TODO: check if this is a proper stop condition. if (backwardWitness[i] == null || backwardWitness[i].Vertex == Constants.NO_VERTEX || _weightHandler.IsSmallerThan(current.Path.Weight, backwardWitness[i].Weight)) { backwardWitness[i] = current.Path; backwardTargets.Remove(current.Path.Vertex); } } } } } if (forwardTargets.Count == 0 && backwardTargets.Count == 0) { // there is nothing left to check. break; } if (forwardSettled.Count >= _maxSettles && backwardSettled.Count >= _maxSettles) { // do not continue searching. break; } var doForward = current.Forward && forwardTargets.Count > 0 && !forwardWasSettled; var doBackward = current.Backward && backwardTargets.Count > 0 && !backwardWasSettled; if (doForward || doBackward) { // get the neighbours. // check for a restriction and if need build the original sequence. var restrictions = getRestrictions(current.Path.Vertex); var sequence = current.Path.GetSequence2(edgeEnumerator); sequence = sequence.Append(current.Path.Vertex); // move to the current vertex. edgeEnumerator.MoveTo(current.Path.Vertex); while (edgeEnumerator.MoveNext()) { // move next. var neighbour = edgeEnumerator.Neighbour; bool?neighbourDirection; var neighbourWeight = _weightHandler.GetEdgeWeight(edgeEnumerator, out neighbourDirection); var neighbourCanMoveForward = neighbourDirection == null || neighbourDirection.Value; var neighbourCanMoveBackward = neighbourDirection == null || !neighbourDirection.Value; var totalNeighbourWeight = _weightHandler.Add(current.Path.Weight, neighbourWeight); var neighbourPath = new EdgePath <T>(neighbour, totalNeighbourWeight, edgeEnumerator.IdDirected(), current.Path); var doNeighbourForward = doForward && neighbourCanMoveForward && _weightHandler.IsSmallerThanOrEqual(totalNeighbourWeight, forwardMaxWeight) && !forwardSettled.Contains(neighbourPath); var doNeighbourBackward = doBackward && neighbourCanMoveBackward && _weightHandler.IsSmallerThanOrEqual(totalNeighbourWeight, backwardMaxWeight) && !backwardSettled.Contains(neighbourPath); if (doNeighbourBackward || doNeighbourForward) { T existingWeight; uint[] sequenceAlongNeighbour = null; if ((doNeighbourBackward || doNeighbourForward) && sequence.Length > 0) { if (edgeEnumerator.IsOriginal()) { if (sequence.Length > 1 && sequence[sequence.Length - 2] == neighbour) { // a t-turn! continue; } sequenceAlongNeighbour = sequence.Append(neighbour); } else { var sequence1Length = edgeEnumerator.GetSequence1(ref _sequence1); //var neighbourSequence = edgeEnumerator.GetSequence1(); if (sequence.Length > 1 && sequence[sequence.Length - 2] == _sequence1[0]) { // a t-turn! continue; } sequenceAlongNeighbour = sequence.Append(_sequence1, sequence1Length); } } if (doNeighbourForward) { if (sequence.Length == 0 || restrictions.IsSequenceAllowed(sequenceAlongNeighbour)) { // restrictions ok. if (forwardMinWeight.TryGetValue(neighbourPath, out existingWeight)) { if (_weightHandler.IsSmallerThanOrEqual(existingWeight, totalNeighbourWeight)) { doNeighbourForward = false; } else { forwardMinWeight[neighbourPath] = totalNeighbourWeight; } } else { forwardMinWeight[neighbourPath] = totalNeighbourWeight; } } else { doNeighbourForward = false; } } if (doNeighbourBackward) { if (sequenceAlongNeighbour != null) { sequenceAlongNeighbour.Reverse(); } if (sequence.Length == 0 || restrictions.IsSequenceAllowed(sequenceAlongNeighbour)) { // restrictions ok. if (backwardMinWeight.TryGetValue(neighbourPath, out existingWeight)) { if (_weightHandler.IsSmallerThanOrEqual(existingWeight, totalNeighbourWeight)) { doNeighbourBackward = false; } else { backwardMinWeight[neighbourPath] = totalNeighbourWeight; } } else { backwardMinWeight[neighbourPath] = totalNeighbourWeight; } } else { doNeighbourBackward = false; } } if (doNeighbourBackward || doNeighbourForward) { // add to heap. var newSettle = new SettledEdge(neighbourPath, current.Hops + 1, doNeighbourForward, doNeighbourBackward); _heap.Push(newSettle, _weightHandler.GetMetric(neighbourPath.Weight)); } } } } } } }
/// <summary> /// Builds a route. /// </summary> public override sealed Result <Route> BuildRoute <T>(Profile profile, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target, EdgePath <T> path) { if (this.CustomRouteBuilder != null) { // there is a custom route builder. return(this.CustomRouteBuilder.TryBuild(_db, profile, source, target, path)); } // use the default. return(CompleteRouteBuilder.TryBuild(_db, profile, source, target, path)); }
/// <summary> /// Executes the actual run. /// </summary> protected override void DoRun(CancellationToken cancellationToken) { var router = new Router(_db); router.VerifyAllStoppable = true; // resolve locations as vertices. // WARNING: use RouterPointEmbedder first. var points = new RouterPoint[_locations.Length]; for (var i = 0; i < points.Length; i++) { var resolver = new Itinero.Algorithms.Search.ResolveVertexAlgorithm(_db.Network.GeometricGraph, _locations[i].Latitude, _locations[i].Longitude, 500, 3000, router.GetIsAcceptable(_profile)); resolver.Run(cancellationToken); if (!resolver.HasSucceeded) { throw new System.Exception(string.Format("Could not resolve shortcut location at index {1}: {0}.", resolver.ErrorMessage, i)); } points[i] = resolver.Result; } // use non-contracted calculation. var weightHandler = _profile.AugmentedWeightHandlerCached(_db); var algorithm = new Itinero.Algorithms.Default.ManyToMany <Weight>(_db, weightHandler, points, points, new Weight() { Distance = float.MaxValue, Time = _maxShortcutDuration, Value = _maxShortcutDuration }); algorithm.Run(cancellationToken); if (!algorithm.HasSucceeded) { this.ErrorMessage = "Many to many calculation failed: " + algorithm.ErrorMessage; } // build shortcuts db. _shortcutsDb = new ShortcutsDb(_profile.FullName); for (var i = 0; i < points.Length; i++) { _shortcutsDb.AddStop(points[i].VertexId(_db), _locationsMeta[i]); } var routes = new EdgePath <float> [_locations.Length][]; _shortcutIds = new uint[_locations.Length][]; var pathList = new List <uint>(); var shortcutProfile = _db.EdgeProfiles.Add(new AttributeCollection( new Attribute(ShortcutExtensions.SHORTCUT_KEY, _name))); var edgeEnumerator = _db.Network.GetEdgeEnumerator(); for (var i = 0; i < _locations.Length; i++) { _shortcutIds[i] = new uint[_locations.Length]; for (var j = 0; j < _locations.Length; j++) { _shortcutIds[i][j] = uint.MaxValue; if (i == j) { continue; } EdgePath <Weight> path; if (algorithm.TryGetPath(i, j, out path)) { pathList.Clear(); path.AddToListAsVertices(pathList); if (path.Weight.Time < _minShortcutSize) { // don't add very short shortcuts. continue; } if (pathList.Count < 2) { Itinero.Logging.Logger.Log("ShortcutBuilder", TraceEventType.Warning, "Shortcut consists of only one vertex from {0}@{1} -> {2}@{3}!", i, _locations[i], j, _locations[j]); continue; } if (pathList[0] == pathList[pathList.Count - 1]) { Itinero.Logging.Logger.Log("ShortcutBuilder", TraceEventType.Warning, "Shortcut has the same start and end vertex from {0}@{1} -> {2}@{3}!", i, _locations[i], j, _locations[j]); continue; } // add the shortcut and keep the id. var shortcutId = _shortcutsDb.Add(pathList.ToArray(), null); _shortcutIds[i][j] = shortcutId; // add the shortcut as an edge. if (edgeEnumerator.MoveTo(pathList[0])) { var edgeExists = false; while (edgeEnumerator.MoveNext()) { if (edgeEnumerator.To == pathList[pathList.Count - 1]) { var json = edgeEnumerator.Current.ToGeoJson(router.Db); edgeExists = true; break; } } if (edgeExists) { continue; } } _db.Network.AddEdge(pathList[0], pathList[pathList.Count - 1], new Data.Network.Edges.EdgeData() { Distance = path.Weight.Time + _switchPentaly, MetaId = 0, Profile = (ushort)shortcutProfile }, null); } else { Itinero.Logging.Logger.Log("ShortcutBuilder", TraceEventType.Warning, "Shortcut not found from {0}@{1} -> {2}@{3}!", i, _locations[i], j, _locations[j]); } } } }
/// <summary> /// Gets the weights. /// </summary> public EdgePath <T> GetPath(int source, int target) { this.CheckHasRunAndHasSucceeded(); var solution = _solutions[source][target]; if (solution.Path == null) { if (solution.Path1 == null || solution.Path2 == null) { return(null); } if (solution.Path != null) { return(solution.Path); } var fromSource = solution.Path1; var toTarget = solution.Path2; var vertices = new List <uint>(); // add vertices from source. vertices.Add(fromSource.Vertex); while (fromSource.From != null) { if (fromSource.From.Vertex != Constants.NO_VERTEX) { // this should be the end of the path. if (fromSource.Edge == Constants.NO_EDGE) { // only expand when there is no edge id. _graph.ExpandEdge(fromSource.From.Vertex, fromSource.Vertex, vertices, false, true); } } vertices.Add(fromSource.From.Vertex); fromSource = fromSource.From; } vertices.Reverse(); // and add vertices to target. while (toTarget.From != null) { if (toTarget.From.Vertex != Constants.NO_VERTEX) { // this should be the end of the path. if (toTarget.Edge == Constants.NO_EDGE) { // only expand when there is no edge id. _graph.ExpandEdge(toTarget.From.Vertex, toTarget.Vertex, vertices, false, false); } } vertices.Add(toTarget.From.Vertex); toTarget = toTarget.From; } var path = new EdgePath <T>(vertices[0]); for (var i = 1; i < vertices.Count; i++) { path = new EdgePath <T>(vertices[i], default(T), path); } solution.Path = path; } return(solution.Path); }
/// <summary> /// Returns true if the given vertex was visited and sets the visit output parameters with the actual visit data. /// </summary> /// <returns></returns> public bool TryGetVisit(uint vertex, out EdgePath <T> visit) { return(_visits.TryGetValue(vertex, out visit)); }
/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { if (_heap.Count == 0) { return(false); } _current = _heap.Pop(); while (_current != null) { // keep trying. LinkedEdgePath <T> edgePath = null; if (!_visits.TryGetValue(_current.Vertex, out edgePath)) { // this vertex has not been visited before. _visits.Add(_current.Vertex, new LinkedEdgePath <T>() { Path = _current }); break; } else { // vertex has been visited before, check if edge has. if (!edgePath.HasPath(_current)) { // current edge has not been used to get to this vertex. _visits[_current.Vertex] = new LinkedEdgePath <T>() { Path = _current, Next = edgePath }; break; } } _current = _heap.Pop(); } if (_current == null) { return(false); } if (this.WasFound != null) { this.WasFound(_current.Vertex, _current.Weight); } // get relevant restrictions. var restrictions = _getRestrictions(_current.Vertex); // get the edge enumerator. var currentSequence = _current.GetSequence2(_edgeEnumerator); currentSequence = currentSequence.Append(_current.Vertex); // get neighbours. _edgeEnumerator.MoveTo(_current.Vertex); // add the neighbours to the queue. while (_edgeEnumerator.MoveNext()) { bool?neighbourDirection; var neighbourWeight = _weightHandler.GetEdgeWeight(_edgeEnumerator.Current, out neighbourDirection); if (neighbourDirection == null || (neighbourDirection.Value != _backward)) { // the edge is forward, and is to higher or was not contracted at all. var neighbourNeighbour = _edgeEnumerator.Neighbour; var neighbourSequence = Constants.EMPTY_SEQUENCE; if (_edgeEnumerator.IsOriginal()) { // original edge. if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourNeighbour) { // this is a u-turn. continue; } if (restrictions != null) { neighbourSequence = currentSequence.Append(neighbourNeighbour); } } else { // not an original edge, use the sequence. neighbourSequence = _edgeEnumerator.GetSequence1(); if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourSequence[0]) { // this is a u-turn. continue; } if (restrictions != null) { neighbourSequence = currentSequence.Append(neighbourSequence); } } if (restrictions != null) { // check restrictions. if (!restrictions.IsSequenceAllowed(neighbourSequence)) { continue; } } // build route to neighbour and check if it has been visited already. var routeToNeighbour = new EdgePath <T>( neighbourNeighbour, _weightHandler.Add(_current.Weight, neighbourWeight), _edgeEnumerator.IdDirected(), _current); LinkedEdgePath <T> edgePath = null; if (!_visits.TryGetValue(_current.Vertex, out edgePath) || !edgePath.HasPath(routeToNeighbour)) { // this vertex has not been visited in this way before. if (_weightHandler.IsLargerThan(routeToNeighbour.Weight, _max)) { continue; } _heap.Push(routeToNeighbour, _weightHandler.GetMetric(routeToNeighbour.Weight)); } } } return(true); }
/// <summary> /// Builds a route. /// </summary> public static Result <Route> TryBuild <T>(RouterDb db, Profile profile, RouterPoint source, RouterPoint target, EdgePath <T> path) { return(CompleteRouteBuilder.TryBuild(db, profile, source, target, path, CancellationToken.None)); }
/// <summary> /// Returns true if the given vertex was visited and sets the visit output parameters with the actual visit data. /// </summary> /// <returns></returns> public bool TryGetBackwardVisit(uint vertex, out EdgePath <T> visit) { this.CheckHasRunAndHasSucceeded(); return(_backwardVisits.TryGetValue(vertex, out visit)); }
/// <summary> /// Builds a route. /// </summary> public static Result <Route> TryBuild <T>(RouterDb db, Profile profile, RouterPoint source, RouterPoint target, EdgePath <T> path) { var pathList = new List <uint>(); path.AddToListAsVertices(pathList); return(CompleteRouteBuilder.TryBuild(db, profile, source, target, pathList)); }
/// <summary> /// Contracts the given vertex. /// </summary> private void Contract(uint vertex) { // get and keep edges. var enumerator = _graph.GetEdgeEnumerator(vertex); var edges = new List <DynamicEdge>(enumerator); // check if this vertex has a potential restrictions. var hasRestrictions = _restrictionFlags[vertex]; // loop over all edge-pairs once. for (var j = 1; j < edges.Count; j++) { var edge1 = edges[j]; bool?edge1Direction; var edge1Weight = _weightHandler.GetEdgeWeight(edge1, out edge1Direction); var edge1CanMoveForward = edge1Direction == null || edge1Direction.Value; var edge1CanMoveBackward = edge1Direction == null || !edge1Direction.Value; // figure out what witness paths to calculate. var forwardWitnesses = new EdgePath <T> [j]; var backwardWitnesses = new EdgePath <T> [j]; var targets = new List <uint>(j); var targetWeights = new List <T>(j); for (var k = 0; k < j; k++) { var edge2 = edges[k]; bool?edge2Direction; var edge2Weight = _weightHandler.GetEdgeWeight(edge2, out edge2Direction); var edge2CanMoveForward = edge2Direction == null || edge2Direction.Value; var edge2CanMoveBackward = edge2Direction == null || !edge2Direction.Value; // use witness flags to represent impossible routes. if (!(edge1CanMoveBackward && edge2CanMoveForward)) { forwardWitnesses[k] = new EdgePath <T>(); } if (!(edge1CanMoveForward && edge2CanMoveBackward)) { backwardWitnesses[k] = new EdgePath <T>(); } targets.Add(edge2.Neighbour); if (hasRestrictions) { targetWeights.Add(_weightHandler.Infinite); } else { targetWeights.Add(_weightHandler.Add(edge1Weight, edge2Weight)); } } // calculate all witness paths. _witnessCalculator.Calculate(_graph, _getRestrictions, edge1.Neighbour, targets, targetWeights, ref forwardWitnesses, ref backwardWitnesses, Constants.NO_VERTEX); // get all sequences where needed. var s1forward = new uint[forwardWitnesses.Length][]; var s2forward = new uint[forwardWitnesses.Length][]; var s1backward = new uint[backwardWitnesses.Length][]; var s2backward = new uint[backwardWitnesses.Length][]; for (var k = 0; k < j; k++) { if (forwardWitnesses[k].HasVertex(vertex)) { // get forward sequences. s1forward[k] = forwardWitnesses[k].GetSequence1(enumerator, 1); s2forward[k] = forwardWitnesses[k].GetSequence2(enumerator, 1); } if (backwardWitnesses[k].HasVertex(vertex)) { // get backward sequences. s1backward[k] = backwardWitnesses[k].GetSequence1(enumerator, 1); s2backward[k] = backwardWitnesses[k].GetSequence2(enumerator, 1); } } // add contracted edges if needed. for (var k = 0; k < j; k++) { var edge2 = edges[k]; if (edge1.Neighbour == edge2.Neighbour) { // do not try to add a shortcut between identical vertices. continue; } if (s1forward[k] != null && s1backward[k] != null && System.Math.Abs(_weightHandler.GetMetric(forwardWitnesses[k].Weight) - _weightHandler.GetMetric(backwardWitnesses[k].Weight)) < E) { // paths in both direction are possible and with the same weight, add just one edge in each direction. s1backward[k].Reverse(); s2backward[k].Reverse(); _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, null, forwardWitnesses[k].Weight, s1forward[k], s2forward[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // forwardWitnesses[k].Weight, null, vertex, s1forward[k], s2forward[k]); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, null, backwardWitnesses[k].Weight, s2backward[k], s1backward[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // backwardWitnesses[k].Weight, null, vertex, s2backward[k], s1backward[k]); } else { // add two edge per direction. if (s1forward[k] != null) { // add forward edge. _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, true, forwardWitnesses[k].Weight, s1forward[k], s2forward[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // forwardWitnesses[k].Weight, true, vertex, s1forward[k], s2forward[k]); s1forward[k].Reverse(); s2forward[k].Reverse(); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, false, forwardWitnesses[k].Weight, s2forward[k], s1forward[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // forwardWitnesses[k].Weight, false, vertex, s2forward[k], s1forward[k]); } if (s1backward[k] != null) { // add forward edge. _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, false, backwardWitnesses[k].Weight, s2backward[k], s1backward[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // backwardWitnesses[k].Weight, false, vertex, s2backward[k], s1backward[k]); s1backward[k].Reverse(); s2backward[k].Reverse(); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, true, backwardWitnesses[k].Weight, s1backward[k], s2backward[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // backwardWitnesses[k].Weight, true, vertex, s1backward[k], s2backward[k]); } } } } // remove 'downward' edge to vertex. var i = 0; while (i < edges.Count) { _graph.RemoveEdge(edges[i].Neighbour, vertex); if (_contractedFlags[edges[i].Neighbour]) { // neighbour was already contracted, remove 'downward' edge and exclude it. _graph.RemoveEdge(vertex, edges[i].Neighbour); edges.RemoveAt(i); } else { // move to next edge. i++; } } _contractedFlags[vertex] = true; _priorityCalculator.NotifyContracted(vertex); }