/// <summary> /// Initializes and resets. /// </summary> public void Initialize() { // algorithm always succeeds, it may be dealing with an empty network and there are no targets. this.HasSucceeded = true; // initialize a dictionary of speeds per edge profile. _factors = new Dictionary <uint, Factor>(); // intialize dykstra data structures. _visits = new Dictionary <long, EdgePath <T> >(); _heap = new BinaryHeap <EdgePath <T> >(1000); _edgeRestrictions = new Dictionary <EdgePath <T>, LinkedRestriction>(); // initialize the edge enumerator. _edgeEnumerator = _graph.GetEdgeEnumerator(); // queue all sources. foreach (var source in _sources) { var queue = true; if (_getRestriction != null && source.Edge != Constants.NO_EDGE) { var sourceVertex = _edgeEnumerator.GetSourceVertex(source.Edge); var sourceVertexRestrictions = _getRestriction(sourceVertex); LinkedRestriction linkedRestriction = null; if (sourceVertexRestrictions != null) { foreach (var restriction in sourceVertexRestrictions) { if (restriction != null && restriction.Length > 1) { var targetVertex = _edgeEnumerator.GetTargetVertex(source.Edge); if (restriction.Length == 2) { // a restriction of two, an edge is forbidden. if (restriction[1] == targetVertex) { // don't queue this edge, it's forbidden. queue = false; break; } } else { // a restriction bigger than two, check if this edge is the first one. if (restriction[1] == targetVertex) { // this edge is the first, queue the restriction too. linkedRestriction = new LinkedRestriction() { Restriction = restriction.SubArray(1, restriction.Length - 1), Next = linkedRestriction }; _edgeRestrictions[source] = linkedRestriction; } } } } } } if (queue) { _heap.Push(source, _weightHandler.GetMetric(source.Weight)); } } }
/// <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); }