/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { if (_pointerHeap.Count == 0) { return(false); } var cPointer = _pointerHeap.Pop(); uint cVertex, cPrevious; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPrevious); if (_visited.Contains(cVertex)) { return(true); } _visited.Add(cVertex); if (this.WasFound != null) { if (this.WasFound(cPointer, cVertex, cWeight)) { // when true is returned, the listener signals it knows what it wants to know. return(false); } } _edgeEnumerator.MoveTo(cVertex); while (_edgeEnumerator.MoveNext()) { var nWeight = _weightHandler.GetEdgeWeight(_edgeEnumerator); if ((!_backward && nWeight.Direction.F) || (_backward && nWeight.Direction.B)) { // the edge is forward, and is to higher or was not contracted at all. var nVertex = _edgeEnumerator.Neighbour; var totalWeight = _weightHandler.Add(nWeight.Weight, cWeight); if (!_weightHandler.IsSmallerThan(totalWeight, _max)) { continue; } var nPointer = _weightHandler.AddPathTree(_pathTree, nVertex, totalWeight, cPointer); _pointerHeap.Push(nPointer, _weightHandler.GetMetric(totalWeight)); } } return(true); }
/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { // while the visit list is not empty. var cPointer = uint.MaxValue; while (cPointer == uint.MaxValue) { // choose the next edge. if (_pointerHeap.Count == 0) { return(false); } cPointer = _pointerHeap.Pop(); } // get details. uint cEdge, cPreviousPointer; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cEdge, out cWeight, out cPreviousPointer); if (_visits.Contains(cEdge)) { return(true); } _visits.Add(cEdge); var cDirectedEdge = new DirectedEdgeId() { Raw = cEdge }; // signal was found. if (this.WasFound != null) { this.WasFound(cPointer, cDirectedEdge, cWeight); } // move to the current edge's target vertex. _edgeEnumerator.MoveToEdge(cDirectedEdge.EdgeId); var cOriginalEdge = new OriginalEdge(_edgeEnumerator.From, _edgeEnumerator.To); if (!cDirectedEdge.Forward) { cOriginalEdge = cOriginalEdge.Reverse(); } var cEdgeWeightAndDirection = _weightHandler.GetEdgeWeight(_edgeEnumerator); // calculate total weight. var totalWeight = _weightHandler.Add(cEdgeWeightAndDirection.Weight, cWeight); if (!_weightHandler.IsSmallerThan(totalWeight, _sourceMax)) { // weight is too big. this.MaxReached = true; return(true); } // loop over all neighbours. _edgeEnumerator.MoveTo(cOriginalEdge.Vertex2); var turn = new Turn(cOriginalEdge, Constants.NO_VERTEX); _restrictions.Update(turn.Vertex2); while (_edgeEnumerator.MoveNext()) { turn.Vertex3 = _edgeEnumerator.To; if (turn.IsUTurn || turn.IsRestrictedBy(_restrictions)) { // turn is restricted. continue; } var nDirectedEdgeId = _edgeEnumerator.DirectedEdgeId(); if (_visits.Contains(nDirectedEdgeId.Raw)) { // has already been choosen. continue; } // get the speed from cache or calculate. var nWeightAndDirection = _weightHandler.GetEdgeWeight(_edgeEnumerator); var nWeightMetric = _weightHandler.GetMetric(nWeightAndDirection.Weight); if (nWeightMetric <= 0) { // edge is not valid for profile. continue; } if (!_backward && !nWeightAndDirection.Direction.F) { // cannot do forward search on edge. continue; } if (_backward && !nWeightAndDirection.Direction.B) { // cannot do backward on edge. continue; } // update the visit list. _pointerHeap.Push(_weightHandler.AddPathTree(_pathTree, nDirectedEdgeId.Raw, totalWeight, cPointer), _weightHandler.GetMetric(totalWeight)); } return(true); }
/// <summary> /// Executes the actual run. /// </summary> protected override void DoRun(CancellationToken cancellationToken) { // keep settled vertices. _pathTree = new PathTree(); // initialize the queues. var forwardQueue = new BinaryHeap <uint>(); var backwardQueue = new BinaryHeap <uint>(); // queue sources. if (_source.Vertex1 != Constants.NO_VERTEX) { forwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _source.Vertex1, _source.Weight1, uint.MaxValue), 0); } if (_source.Vertex2 != Constants.NO_VERTEX) { forwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _source.Vertex2, _source.Weight2, uint.MaxValue), 0); } // queue targets. if (_target.Vertex1 != Constants.NO_VERTEX) { backwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _target.Vertex1, _target.Weight1, uint.MaxValue), 0); } if (_target.Vertex2 != Constants.NO_VERTEX) { backwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _target.Vertex2, _target.Weight2, uint.MaxValue), 0); } // update best with current visits. _best = new Tuple <uint, uint, T>(uint.MaxValue, uint.MaxValue, _weightHandler.Infinite); // calculate stopping conditions. var queueBackwardWeight = backwardQueue.PeekWeight(); var queueForwardWeight = forwardQueue.PeekWeight(); while (true) { // keep looping until stopping conditions. if (backwardQueue.Count == 0 && forwardQueue.Count == 0) { // stop the search; both queues are empty. break; } var bestItem2 = _weightHandler.GetMetric(_best.Item3); if (bestItem2 < queueForwardWeight && bestItem2 < queueBackwardWeight) { // stop the search: it now became impossible to find a shorter route by further searching. break; } // do a forward search. if (forwardQueue.Count > 0) { // first check for better path. // get the current queued with the smallest weight that hasn't been visited yet. var cPointer = forwardQueue.Pop(); uint cVertex, cPreviousPointer; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); while (_forwardVisits.ContainsKey(cVertex)) { // keep trying. if (forwardQueue.Count == 0) { cPointer = uint.MaxValue; } else { cPointer = forwardQueue.Pop(); _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); } } if (cPointer != uint.MaxValue) { uint bPointer; if (_backwardVisits.TryGetValue(cVertex, out bPointer)) { // check for a new best. uint bVertex, bPreviousPointer; T bWeight; _weightHandler.GetPathTree(_pathTree, bPointer, out bVertex, out bWeight, out bPreviousPointer); var total = _weightHandler.Add(cWeight, bWeight); if (_weightHandler.IsSmallerThan(total, _best.Item2)) { // a better path was found. _best = new Tuple <uint, uint, T>(cPointer, bPointer, total); this.HasSucceeded = true; } } this.SearchForward(forwardQueue, cPointer, cVertex, cWeight); } } // do a backward search. if (backwardQueue.Count > 0) {// first check for better path. // get the current queued with the smallest weight that hasn't been visited yet. var cPointer = backwardQueue.Pop(); uint cVertex, cPreviousPointer; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); while (_backwardVisits.ContainsKey(cVertex)) { // keep trying. if (backwardQueue.Count == 0) { cPointer = uint.MaxValue; } else { cPointer = backwardQueue.Pop(); _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); } } if (cPointer != uint.MaxValue) { uint bPointer; // best pointer. if (_forwardVisits.TryGetValue(cVertex, out bPointer)) { // check for a new best. uint bVertex, bPreviousPointer; T bWeight; _weightHandler.GetPathTree(_pathTree, bPointer, out bVertex, out bWeight, out bPreviousPointer); var total = _weightHandler.Add(cWeight, bWeight); if (_weightHandler.IsSmallerThan(total, _best.Item2)) { // a better path was found. _best = new Tuple <uint, uint, T>(bPointer, cPointer, total); this.HasSucceeded = true; } } this.SearchBackward(backwardQueue, cPointer, cVertex, cWeight); } } // calculate stopping conditions. if (forwardQueue.Count > 0) { queueForwardWeight = forwardQueue.PeekWeight(); } if (backwardQueue.Count > 0) { queueBackwardWeight = backwardQueue.PeekWeight(); } } }