コード例 #1
0
        /// <summary>
        /// Calculates the shortest path between the two given vertices.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="vehicle">The vehicle profile.</param>
        /// <param name="from">The source vertex.</param>
        /// <param name="to">The target vertex.</param>
        /// <param name="searchForward">Flag indicating search direction.</param>
        /// <param name="maxSettles"></param>
        /// <returns></returns>
        public PathSegment Calculate(BasicRouterDataSource <LiveEdge> graph, Vehicle vehicle,
                                     long from, long to, bool searchForward, uint maxSettles)
        {
            // first check for the simple stuff.
            if (from == to)
            { // route consists of one vertex.
                return(new PathSegment(from));
            }

            // initialize the heap/visit list.
            var heap    = new BinaryHeap <PathSegment>(100);
            var visited = new HashSet <long>();

            // set the target.
            var target       = to;
            var targetWeight = double.MaxValue;

            // create a path segment from the from-candidate.
            heap.Push(new PathSegment(from), (float)0);

            // keep searching for the target.
            while (true)
            {
                // get the next vertex.
                var current = heap.Pop();
                if (current == null)
                { // there is nothing more in the queue, target will not be found.
                    break;
                }
                if (visited.Contains(current.Vertex))
                { // move to the next neighbour.
                    continue;
                }
                visited.Add(current.Vertex);

                // check for the target.
                if (current.Vertex == target)
                { // target was found.
                    return(current);
                }

                // check if the maximum settled vertex count has been reached.
                if (visited.Count >= maxSettles)
                { // stop search, target will not be found.
                    break;
                }

                // add the neighbours to queue.
                var neighbours = graph.GetEdges(current.Vertex);
                if (neighbours != null)
                { // neighbours exist.
                    foreach (var neighbour in neighbours)
                    {
                        // check if the neighbour was settled before.
                        if (visited.Contains(neighbour.Key))
                        { // move to the next neighbour.
                            continue;
                        }

                        // get tags and check traversability and oneway.
                        var tags = graph.TagsIndex.Get(neighbour.Value.Tags);
                        if (vehicle.CanTraverse(tags))
                        { // yay! can traverse.
                            var onway = vehicle.IsOneWay(tags);
                            if (onway == null ||
                                !(onway.Value == neighbour.Value.Forward ^ searchForward))
                            {
                                // create path to neighbour and queue it.
                                var weight = vehicle.Weight(graph.TagsIndex.Get(neighbour.Value.Tags), neighbour.Value.Distance);
                                var path   = new PathSegment(neighbour.Key, current.Weight + weight, neighbour.Value, current);
                                if (path.Weight < targetWeight)
                                { // the weight of the neighbour is smaller than the first neighbour found.
                                    heap.Push(path, (float)path.Weight);

                                    // save distance.
                                    if (path.Vertex == target)
                                    {     // the target is already found, no use of queuing neigbours that have a higher weight.
                                        if (targetWeight > path.Weight)
                                        { // set the weight.
                                            targetWeight = path.Weight;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return(null);
        }
コード例 #2
0
        /// <summary>
        /// Calculates a path between the two candidates using the information in the candidates.
        /// </summary>
        /// <returns></returns>
        public PathSegment <long> Calculate(BasicRouterDataSource <LiveEdge> graph, IRoutingInterpreter interpreter,
                                            Vehicle vehicle, CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum, uint maxSettles,
                                            bool ignoreFromEdge, bool ignoreToEdge)
        {
            // first check for the simple stuff.
            if (from.Vertex == to.Vertex)
            { // route consists of one vertex.
                return(new PathSegment <long>(from.Vertex));
            }

            // check paths.
            var fromPath = new PathSegment <long>(from.TargetVertex, vehicle.Weight(graph.TagsIndex.Get(from.Edge.Tags),
                                                                                    from.Edge.Distance), new PathSegment <long>(from.Vertex));

            if (!ignoreFromEdge || !ignoreToEdge)
            { // do not check paths when one of the edges need to be ignored.
                if (from.Vertex == to.TargetVertex &&
                    to.Vertex == from.TargetVertex)
                { // edges are the same,
                    return(fromPath);
                }
            }
            if (ignoreFromEdge)
            { // ignore from edge, just use the from-vertex.
                fromPath = new PathSegment <long>(from.Vertex);
            }

            // initialize the heap/visit list.
            var heap    = new BinaryHeap <PathSegment <long> >(maxSettles / 4);
            var visited = new HashSet <long>();

            visited.Add(from.Vertex);

            // set target.
            var target       = to.Vertex;
            var targetWeight = double.MaxValue;

            if (!ignoreToEdge)
            { // also add the target to the visit list and actually search for the target candidate edge ending.
                target = to.TargetVertex;
                visited.Add(to.Vertex);
            }

            // create a path segment from the from-candidate.
            heap.Push(fromPath, (float)fromPath.Weight);

            // keep searching for the target.
            while (true)
            {
                // get the next vertex.
                var current = heap.Pop();
                if (current == null)
                { // there is nothing more in the queue, target will not be found.
                    break;
                }
                if (visited.Contains(current.VertexId))
                { // move to the next neighbour.
                    continue;
                }
                visited.Add(current.VertexId);

                // check for the target.
                if (current.VertexId == target)
                { // target was found.
                    if (ignoreToEdge)
                    {
                        return(current);
                    }
                    return(new PathSegment <long>(to.Vertex, current.Weight, current));
                }

                // check if the maximum settled vertex count has been reached.
                if (visited.Count >= maxSettles)
                { // stop search, target will not be found.
                    break;
                }

                // add the neighbours to queue.
                var neighbours = graph.GetEdges(current.VertexId);
                if (neighbours != null)
                { // neighbours exist.
                    foreach (var neighbour in neighbours)
                    {
                        // check if the neighbour was settled before.
                        if (visited.Contains(neighbour.Key))
                        { // move to the next neighbour.
                            continue;
                        }

                        // get tags and check traversability and oneway.
                        var tags = graph.TagsIndex.Get(neighbour.Value.Tags);
                        if (vehicle.CanTraverse(tags))
                        { // yay! can traverse.
                            var oneway = vehicle.IsOneWay(tags);
                            if (oneway == null ||
                                oneway.Value == neighbour.Value.Forward)
                            {
                                // create path to neighbour and queue it.
                                var weight = vehicle.Weight(graph.TagsIndex.Get(neighbour.Value.Tags), neighbour.Value.Distance);
                                var path   = new PathSegment <long>(neighbour.Key, current.Weight + weight, current);
                                if (path.Weight < targetWeight)
                                { // the weight of the neighbour is smaller than the first neighbour found.
                                    heap.Push(path, (float)path.Weight);

                                    // save distance.
                                    if (path.VertexId == target)
                                    {     // the target is already found, no use of queuing neigbours that have a higher weight.
                                        if (targetWeight > path.Weight)
                                        { // set the weight.
                                            targetWeight = path.Weight;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return(null);
        }
コード例 #3
0
        /// <summary>
        /// Calculates the shortest path between the two given 'virtual' vertices described by pre-calculate path segments.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="vehicle">The vehicle profile.</param>
        /// <param name="fromPaths">The paths to the source.</param>
        /// <param name="toPaths">The paths to the target.</param>
        /// <param name="searchForward">Flag indicating search direction.</param>
        /// <param name="maxSettles"></param>
        /// <returns></returns>
        public PathSegment Calculate(BasicRouterDataSource <LiveEdge> graph, Vehicle vehicle,
                                     List <PathSegment> fromPaths, List <PathSegment> toPaths, bool searchForward, uint maxSettles)
        {
            if (fromPaths.Count == 0)
            {
                return(null);
            }
            if (toPaths.Count == 0)
            {
                return(null);
            }

            // initialize the heap/visit list.
            var heap    = new BinaryHeap <PathSegment>(maxSettles);
            var visited = new HashSet <long>();

            // queue the from-paths.
            heap.Push(fromPaths[0], (float)fromPaths[0].Weight);
            for (int i = 1; i < fromPaths.Count; i++)
            {
                if (fromPaths[0].From.Vertex != fromPaths[i].From.Vertex)
                {
                    throw new ArgumentException("When multiple from paths they should be one-hop away from a common vertex.");
                }
                heap.Push(fromPaths[i], (float)fromPaths[i].Weight);
            }

            // enumerate and store target-paths.
            var toPathDictonary = new Dictionary <long, PathSegment>();

            foreach (var toPath in toPaths)
            {
                if (toPath.From != null)
                {
                    toPathDictonary.Add(toPath.From.Vertex, toPath);
                }
                else
                {
                    toPathDictonary.Add(toPath.Vertex, toPath);
                }
            }

            // keep searching for the target.
            PathSegment bestToTarget = null;

            while (true)
            {
                // get the next vertex.
                var current = heap.Pop();

                if (current == null)
                {     // there is nothing more in the queue, target will not be found.
                    break;
                }
                if (visited.Contains(current.Vertex))
                {     // move to the next neighbour.
                    continue;
                }
                visited.Add(current.Vertex);

                // check for the target.
                PathSegment foundToPath;
                if (toPathDictonary.TryGetValue(current.Vertex, out foundToPath))
                {     // target was found.
                    toPathDictonary.Remove(current.Vertex);
                    if (bestToTarget == null ||
                        current.Weight + foundToPath.Weight < bestToTarget.Weight)
                    {     // ok, this path is better!
                        if (foundToPath.From != null)
                        {
                            bestToTarget = new PathSegment(foundToPath.Vertex, foundToPath.Weight + current.Weight, foundToPath.Edge, current);
                        }
                        else
                        {
                            bestToTarget = current;
                        }
                    }
                    if (toPathDictonary.Count == 0)
                    {     // no more targets let, this has to be it.
                        return(bestToTarget);
                    }
                }

                // check if the maximum settled vertex count has been reached.
                if (visited.Count >= maxSettles)
                {     // stop search, target will not be found.
                    break;
                }

                // add the neighbours to queue.
                var neighbours = graph.GetEdges(current.Vertex);
                if (neighbours != null)
                {     // neighbours exist.
                    foreach (var neighbour in neighbours)
                    {
                        // check if the neighbour was settled before.
                        if (visited.Contains(neighbour.Key))
                        {     // move to the next neighbour.
                            continue;
                        }

                        // get tags and check traversability and oneway.
                        var tags = graph.TagsIndex.Get(neighbour.Value.Tags);
                        if (vehicle.CanTraverse(tags))
                        {     // yay! can traverse.
                            var onway = vehicle.IsOneWay(tags);
                            if (onway == null ||
                                !(onway.Value == neighbour.Value.Forward ^ searchForward))
                            {
                                // create path to neighbour and queue it.
                                var weight = vehicle.Weight(graph.TagsIndex.Get(neighbour.Value.Tags), neighbour.Value.Distance);
                                var path   = new PathSegment(neighbour.Key, current.Weight + weight, neighbour.Value, current);
                                if (bestToTarget == null ||
                                    path.Weight < bestToTarget.Weight)
                                {     // the weight of the neighbour is smaller than the first neighbour found.
                                    heap.Push(path, (float)path.Weight);
                                }
                            }
                        }
                    }
                }
            }
            return(bestToTarget);
        }