コード例 #1
0
        /// <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));
                }
            }
        }
コード例 #2
0
        /// <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);
        }