Beispiel #1
0
        /// <summary>
        /// Search forward from one vertex.
        /// </summary>
        /// <returns></returns>
        private void SearchForward(BinaryHeap <EdgePath <T> > queue, EdgePath <T> current)
        {
            if (current != null)
            { // there is a next vertex found.
                // check restrictions.
                if (_restrictions != null &&
                    _restrictions.Update(current.Vertex) &&
                    _restrictions.Restricts(current.Vertex))
                { // vertex is restricted, don't settle.
                    return;
                }

                // get the edge enumerator.
                var edgeEnumerator = _graph.GetEdgeEnumerator();

                // add to the settled vertices.
                EdgePath <T> previousLinkedRoute;
                if (_forwardVisits.TryGetValue(current.Vertex, out previousLinkedRoute))
                {
                    if (_weightHandler.IsLargerThan(previousLinkedRoute.Weight, current.Weight))
                    { // settle the vertex again if it has a better weight.
                        _forwardVisits[current.Vertex] = current;
                    }
                }
                else
                { // settled the vertex.
                    _forwardVisits.Add(current.Vertex, current);
                }

                // 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;
                        if (!_forwardVisits.ContainsKey(neighbourNeighbour))
                        { // if not yet settled.
                            var routeToNeighbour = new EdgePath <T>(
                                neighbourNeighbour, _weightHandler.Add(current.Weight, neighbourWeight), current);
                            queue.Push(routeToNeighbour, _weightHandler.GetMetric(routeToNeighbour.Weight));
                        }
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Search forward from one vertex.
        /// </summary>
        /// <returns></returns>
        private void SearchForward(BinaryHeap <uint> queue, uint cPointer, uint cVertex, T cWeight)
        {
            if (cPointer != uint.MaxValue)
            {                  // there is a next vertex found.
                // add to the settled vertices.
                uint ePointer; // the existing pointer.
                if (_forwardVisits.TryGetValue(cVertex, out ePointer))
                {
                    uint eVertex, ePreviousPointer;
                    T    eWeight;
                    _weightHandler.GetPathTree(_pathTree, ePointer, out eVertex, out eWeight, out ePreviousPointer);
                    if (_weightHandler.IsLargerThan(eWeight, cWeight))
                    { // settle the vertex again if it has a better weight.
                        _forwardVisits[cVertex] = cPointer;
                    }
                    else
                    { // this is a worse settled, don't continue the search.
                        return;
                    }
                }
                else
                { // settled the vertex.
                    _forwardVisits.Add(cVertex, cPointer);
                }

                // get neighbours.
                var edgeEnumerator = _graph.GetEdgeEnumerator();
                edgeEnumerator.MoveTo(cVertex);

                // add the neighbours to the queue.
                while (edgeEnumerator.MoveNext())
                {
                    var nWeightAndDirection = _weightHandler.GetEdgeWeight(edgeEnumerator.Current);

                    if (nWeightAndDirection.Direction.F)
                    {
                        var nVertex = edgeEnumerator.Neighbour;
                        if (!_forwardVisits.ContainsKey(nVertex))
                        { // if not yet settled.
                            var nWeight  = _weightHandler.Add(cWeight, nWeightAndDirection.Weight);
                            var nPointer = _weightHandler.AddPathTree(_pathTree, nVertex, nWeight,
                                                                      cPointer);
                            queue.Push(nPointer, _weightHandler.GetMetric(nWeight));
                        }
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Executes one step in the search.
        /// </summary>
        public bool Step()
        {
            if (_heap.Count == 0)
            {
                return(false);
            }
            _current = _heap.Pop();
            if (_current != null)
            {
                while (_visits.ContainsKey(_current.Vertex))
                {
                    _current = _heap.Pop();
                    if (_current == null)
                    {
                        return(false);
                    }
                }
            }
            else
            {
                return(false);
            }
            _visits.Add(_current.Vertex, _current);

            if (this.WasFound != null)
            {
                this.WasFound(_current);
            }

            _edgeEnumerator.MoveTo(_current.Vertex);
            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;
                    if (!_visits.ContainsKey(neighbourNeighbour))
                    { // if not yet settled.
                        var routeToNeighbour = new EdgePath <T>(
                            neighbourNeighbour, _weightHandler.Add(_current.Weight, neighbourWeight), _current);
                        if (_weightHandler.IsLargerThan(routeToNeighbour.Weight, _max))
                        {
                            continue;
                        }
                        _heap.Push(routeToNeighbour, _weightHandler.GetMetric(routeToNeighbour.Weight));
                    }
                }
            }
            return(true);
        }
Beispiel #4
0
        /// <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].ToEdgePathsDirected(_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];
                if (paths.Length == 2)
                {
                    _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].ToEdgePathsDirected(_router.Db, _weightHandler, false);
                if (paths.Length == 0)
                {
                    this.ErrorMessage = string.Format("Target at {0} could not be resolved properly.", i);
                    return;
                }

                // make sure paths are the opposive of the sources.
                if (paths[0].Edge == _sourcePaths[i * 2 + 0].Edge)
                { // switchs.
                    _targetPaths[i * 2 + 1] = paths[0];
                    if (paths.Length == 2)
                    {
                        _targetPaths[i * 2 + 0] = paths[1];
                    }
                }
                else
                { // keep.
                    _targetPaths[i * 2 + 0] = paths[0];
                    if (paths.Length == 2)
                    {
                        _targetPaths[i * 2 + 1] = paths[1];
                    }
                }
            }

            // 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;
                            }
                        }
                    }
                }
            }

            // do forward searches into buckets.
            for (var i = 0; i < _sourcePaths.Length; i++)
            {
                var path = _sourcePaths[i];
                if (path != null)
                {
                    var forward = new Itinero.Algorithms.Contracted.EdgeBased.Dykstra <T>(_graph, _weightHandler, new EdgePath <T>[] { path }, (v) => null, false, _max);
                    forward.WasFound += (foundPath) =>
                    {
                        LinkedEdgePath <T> visits;
                        forward.TryGetVisits(foundPath.Vertex, out visits);
                        return(this.ForwardVertexFound(i, foundPath.Vertex, visits));
                    };
                    forward.Run();
                }
            }

            // do backward searches into buckets.
            for (var i = 0; i < _targetPaths.Length; i++)
            {
                var path = _targetPaths[i];
                if (path != null)
                {
                    var backward = new Itinero.Algorithms.Contracted.EdgeBased.Dykstra <T>(_graph, _weightHandler, new EdgePath <T>[] { path }, (v) => null, true, _max);
                    backward.WasFound += (foundPath) =>
                    {
                        LinkedEdgePath <T> visits;
                        backward.TryGetVisits(foundPath.Vertex, out visits);
                        return(this.BackwardVertexFound(i, foundPath.Vertex, visits));
                    };
                    backward.Run();
                }
            }

            // 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;
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        /// <summary>
        /// Executes the algorithm.
        /// </summary>
        protected sealed override void DoRun(CancellationToken cancellationToken)
        {
            // run mass resolver if needed.
            if (!_massResolver.HasRun)
            {
                _massResolver.Run(cancellationToken);
            }

            // 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(cancellationToken);
            }
            else
            {
                this.DoDualBased(cancellationToken);
            }

            // 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;
        }