Пример #1
0
        /// <summary>
        /// Checks if the given point is connected to the rest of the network. Use this to detect points on routing islands.
        /// </summary>
        /// <param name="radius">The radius metric, that can be a distance, time or custom metric.</param>
        /// <returns></returns>
        public sealed override Result <bool> TryCheckConnectivity(IProfileInstance profileInstance, RouterPoint point, float radius, bool?forward = null)
        {
            try
            {
                if (!_db.Supports(profileInstance.Profile))
                {
                    return(new Result <bool>("Routing profile is not supported.", (message) =>
                    {
                        return new Exception(message);
                    }));
                }

                // get the weight handler.
                var weightHandler = this.GetDefaultWeightHandler(profileInstance);

                var checkForward  = forward == null || forward.Value;
                var checkBackward = forward == null || !forward.Value;

                if (checkForward)
                { // build and run forward dykstra search.
                    var dykstra = new Dykstra(_db.Network.GeometricGraph.Graph, weightHandler, null,
                                              point.ToEdgePaths(_db, weightHandler, true), radius, false);
                    dykstra.Run();
                    if (!dykstra.HasSucceeded ||
                        !dykstra.MaxReached)
                    { // something went wrong or max not reached.
                        return(new Result <bool>(false));
                    }
                }


                if (checkBackward)
                { // build and run backward dykstra search.
                    var dykstra = new Dykstra(_db.Network.GeometricGraph.Graph, weightHandler, null,
                                              point.ToEdgePaths(_db, weightHandler, false), radius, true);
                    dykstra.Run();
                    if (!dykstra.HasSucceeded ||
                        !dykstra.MaxReached)
                    { // something went wrong or max not reached.
                        return(new Result <bool>(false));
                    }
                }
                return(new Result <bool>(true));
            }
            catch (Exception ex)
            {
                return(new Result <bool>(ex.Message, (m) => ex));
            }
        }
Пример #2
0
        /// <summary>
        /// Checks if the given point is connected to the rest of the network. Use this to detect points on routing islands.
        /// </summary>
        /// <returns></returns>
        public sealed override Result <bool> TryCheckConnectivity(IProfileInstance profileInstance, RouterPoint point, float radiusInMeters)
        {
            if (!_db.Supports(profileInstance.Profile))
            {
                return(new Result <bool>("Routing profile is not supported.", (message) =>
                {
                    return new Exception(message);
                }));
            }

            // get the weight handler.
            var weightHandler = this.GetDefaultWeightHandler(profileInstance);

            // build and run dykstra search.
            var dykstra = new Dykstra(_db.Network.GeometricGraph.Graph, weightHandler, null,
                                      point.ToEdgePaths(_db, weightHandler, true), radiusInMeters, false);

            dykstra.Run();
            if (!dykstra.HasSucceeded)
            { // something went wrong.
                return(new Result <bool>(false));
            }
            return(new Result <bool>(dykstra.MaxReached));
        }
Пример #3
0
        /// <summary>
        /// Calculates a route between the two locations.
        /// </summary>
        /// <returns></returns>
        public sealed override Result <EdgePath <T> > TryCalculateRaw <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target,
                                                                          RoutingSettings <T> settings)
        {
            try
            {
                if (!_db.Supports(profileInstance.Profile))
                {
                    return(new Result <EdgePath <T> >("Routing profile is not supported.", (message) =>
                    {
                        return new Exception(message);
                    }));
                }

                var maxSearch = weightHandler.Infinite;
                if (settings != null)
                {
                    if (!settings.TryGetMaxSearch(profileInstance.Profile.FullName, out maxSearch))
                    {
                        maxSearch = weightHandler.Infinite;
                    }
                }

                EdgePath <T> path;
                ContractedDb contracted;

                bool useContracted = false;
                if (_db.TryGetContracted(profileInstance.Profile, out contracted))
                { // contracted calculation.
                    useContracted = true;
                    if (_db.HasComplexRestrictions(profileInstance.Profile) && !contracted.HasEdgeBasedGraph)
                    { // there is no edge-based graph for this profile but the db has complex restrictions, don't use the contracted graph.
                        Logging.Logger.Log("Router", Logging.TraceEventType.Warning,
                                           "There is a vertex-based contracted graph but also complex restrictions. Not using the contracted graph, add an edge-based contracted graph.");
                        useContracted = false;
                    }
                }

                if (useContracted)
                {  // use the contracted graph.
                    path = null;

                    List <uint> vertexPath = null;

                    if (!contracted.HasEdgeBasedGraph)
                    { // use node-based routing.
                        var bidirectionalSearch = new Itinero.Algorithms.Contracted.BidirectionalDykstra <T>(contracted.NodeBasedGraph, weightHandler,
                                                                                                             source.ToEdgePaths(_db, weightHandler, true), target.ToEdgePaths(_db, weightHandler, false));
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                            {
                                return new RouteNotFoundException(message);
                            }));
                        }
                        vertexPath = bidirectionalSearch.GetPath();
                    }
                    else
                    { // use edge-based routing.
                        var bidirectionalSearch = new Itinero.Algorithms.Contracted.EdgeBased.BidirectionalDykstra <T>(contracted.EdgeBasedGraph, weightHandler,
                                                                                                                       source.ToEdgePaths(_db, weightHandler, true), target.ToEdgePaths(_db, weightHandler, false), _db.GetGetRestrictions(profileInstance.Profile, null));
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                            {
                                return new RouteNotFoundException(message);
                            }));
                        }
                        vertexPath = bidirectionalSearch.GetPath();
                    }

                    // expand vertex path using the regular graph.
                    path = _db.BuildEdgePath(weightHandler, source, target, vertexPath);
                }
                else
                { // use the regular graph.
                    if (_db.HasComplexRestrictions(profileInstance.Profile))
                    {
                        var sourceSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler,
                                                                                        _db.GetGetRestrictions(profileInstance.Profile, true), source.ToEdgePaths(_db, weightHandler, true), maxSearch, false);
                        var targetSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler,
                                                                                        _db.GetGetRestrictions(profileInstance.Profile, false), target.ToEdgePaths(_db, weightHandler, false), maxSearch, true);

                        var bidirectionalSearch = new Algorithms.Default.EdgeBased.BidirectionalDykstra <T>(sourceSearch, targetSearch, weightHandler);
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                            {
                                return new RouteNotFoundException(message);
                            }));
                        }
                        path = bidirectionalSearch.GetPath();
                    }
                    else
                    {
                        var sourceSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, null, weightHandler,
                                                           source.ToEdgePaths(_db, weightHandler, true), maxSearch, false);
                        var targetSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, null, weightHandler,
                                                           target.ToEdgePaths(_db, weightHandler, false), maxSearch, true);

                        var bidirectionalSearch = new BidirectionalDykstra <T>(sourceSearch, targetSearch, weightHandler);
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                            {
                                return new RouteNotFoundException(message);
                            }));
                        }
                        path = bidirectionalSearch.GetPath();
                    }
                }

                if (source.EdgeId == target.EdgeId)
                { // check for a shorter path on the same edge.
                    var edgePath = source.EdgePathTo(_db, weightHandler, target);
                    if (edgePath != null &&
                        weightHandler.IsSmallerThan(edgePath.Weight, path.Weight))
                    {
                        path = edgePath;
                    }
                }
                return(new Result <EdgePath <T> >(path));
            }
            catch (Exception ex)
            {
                return(new Result <EdgePath <T> >(ex.Message, (m) => ex));
            }
        }
Пример #4
0
        /// <summary>
        /// Converts the router point to paths leading to the closest 2 vertices.
        /// </summary>
        public static EdgePath <T>[] ToEdgePaths <T>(this RouterPoint point, RouterDb routerDb, WeightHandler <T> weightHandler, bool asSource, bool?forward)
            where T : struct
        {
            if (forward == null)
            { // don't-care direction, use default implementation.
                return(point.ToEdgePaths(routerDb, weightHandler, asSource));
            }

            var graph = routerDb.Network.GeometricGraph;
            var edge  = graph.GetEdge(point.EdgeId);

            float  distance;
            ushort profileId;

            EdgeDataSerializer.Deserialize(edge.Data[0], out distance, out profileId);
            Factor factor;
            var    edgeWeight = weightHandler.Calculate(profileId, distance, out factor);

            var offset = point.Offset / (float)ushort.MaxValue;

            if (factor.Direction == 0)
            { // bidirectional.
                if (forward.Value)
                {
                    return(new EdgePath <T>[] {
                        new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>())
                    });
                }
                return(new EdgePath <T>[] {
                    new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>())
                });
            }
            else if (factor.Direction == 1)
            { // edge is forward oneway.
                if (asSource)
                {
                    if (forward.Value)
                    {
                        return(new EdgePath <T>[] {
                            new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>())
                        });
                    }
                    return(new EdgePath <T> [0]);
                }
                if (forward.Value)
                {
                    return(new EdgePath <T> [0]);
                }
                return(new EdgePath <T>[] {
                    new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>())
                });
            }
            else
            { // edge is backward oneway.
                if (!asSource)
                {
                    if (forward.Value)
                    {
                        return(new EdgePath <T>[] {
                            new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>())
                        });
                    }
                    return(new EdgePath <T> [0]);
                }
                if (forward.Value)
                {
                    return(new EdgePath <T> [0]);
                }
                return(new EdgePath <T>[] {
                    new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>())
                });
            }
        }
Пример #5
0
        /// <summary>
        /// Calculates a route between the two locations.
        /// </summary>
        /// <returns></returns>
        public sealed override Result <EdgePath <T> > TryCalculateRaw <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target,
                                                                          RoutingSettings <T> settings)
        {
            try
            {
                if (!_db.Supports(profileInstance.Profile))
                {
                    return(new Result <EdgePath <T> >("Routing profile is not supported.", (message) =>
                    {
                        return new Exception(message);
                    }));
                }

                var maxSearch = weightHandler.Infinite;
                if (settings != null)
                {
                    if (!settings.TryGetMaxSearch(profileInstance.Profile.FullName, out maxSearch))
                    {
                        maxSearch = weightHandler.Infinite;
                    }
                }

                ContractedDb contracted;

                bool useContracted = false;
                if (_db.TryGetContracted(profileInstance.Profile, out contracted))
                { // contracted calculation.
                    useContracted = true;
                    if (_db.HasComplexRestrictions(profileInstance.Profile) &&
                        (!contracted.HasEdgeBasedGraph && !contracted.NodeBasedIsEdgedBased))
                    { // there is no edge-based graph for this profile but the db has complex restrictions, don't use the contracted graph.
                        Logging.Logger.Log("Router", Logging.TraceEventType.Warning,
                                           "There is a vertex-based contracted graph but also complex restrictions. Not using the contracted graph, add an edge-based contracted graph.");
                        useContracted = false;
                    }
                }

                EdgePath <T> path = null;
                if (source.EdgeId == target.EdgeId)
                { // check for a path on the same edge.
                    var edgePath = source.EdgePathTo(_db, weightHandler, target);
                    if (edgePath != null)
                    {
                        path = edgePath;
                    }
                }

                if (useContracted)
                {  // use the contracted graph.
                    List <uint> vertexPath = null;

                    if (contracted.HasEdgeBasedGraph)
                    { // use edge-based routing.
                        var bidirectionalSearch = new Itinero.Algorithms.Contracted.EdgeBased.BidirectionalDykstra <T>(contracted.EdgeBasedGraph, weightHandler,
                                                                                                                       source.ToEdgePaths(_db, weightHandler, true), target.ToEdgePaths(_db, weightHandler, false), _db.GetGetRestrictions(profileInstance.Profile, null));
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            if (path == null)
                            {
                                return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                                {
                                    return new RouteNotFoundException(message);
                                }));
                            }
                        }
                        else
                        {
                            vertexPath = bidirectionalSearch.GetPath();
                        }
                    }
                    else if (contracted.NodeBasedIsEdgedBased)
                    {// use vertex-based graph for edge-based routing.
                        var sourceDirectedId1 = new DirectedEdgeId(source.EdgeId, true);
                        var sourceDirectedId2 = new DirectedEdgeId(source.EdgeId, false);
                        var targetDirectedId1 = new DirectedEdgeId(target.EdgeId, true);
                        var targetDirectedId2 = new DirectedEdgeId(target.EdgeId, false);

                        var bidirectionalSearch = new Itinero.Algorithms.Contracted.BidirectionalDykstra <T>(contracted.NodeBasedGraph, null, weightHandler,
                                                                                                             new EdgePath <T>[] { new EdgePath <T>(sourceDirectedId1.Raw), new EdgePath <T>(sourceDirectedId2.Raw) },
                                                                                                             new EdgePath <T>[] { new EdgePath <T>(targetDirectedId1.Raw), new EdgePath <T>(targetDirectedId2.Raw) });
                        bidirectionalSearch.Run();

                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                            {
                                return new RouteNotFoundException(message);
                            }));
                        }

                        var directedEdgePath = Algorithms.Dual.BidirectionalDykstraExtensions.GetDualPath(bidirectionalSearch);

                        // convert directed edge-path to an original vertex path.
                        var enumerator = _db.Network.GetEdgeEnumerator();
                        vertexPath = new List <uint>();
                        var edge = new List <OriginalEdge>();
                        for (var i = 0; i < directedEdgePath.Count; i++)
                        {
                            var e = new DirectedEdgeId()
                            {
                                Raw = directedEdgePath[i]
                            };

                            enumerator.MoveToEdge(e.EdgeId);
                            var original = new OriginalEdge(enumerator.From, enumerator.To);
                            if (!e.Forward)
                            {
                                original = original.Reverse();
                            }
                            edge.Add(original);
                            if (vertexPath.Count == 0)
                            {
                                vertexPath.Add(original.Vertex1);
                            }
                            vertexPath.Add(original.Vertex2);
                        }

                        vertexPath[0] = Constants.NO_VERTEX;
                        vertexPath[vertexPath.Count - 1] = Constants.NO_VERTEX;
                    }
                    else
                    {  // use node-based routing.
                        var bidirectionalSearch = new Itinero.Algorithms.Contracted.BidirectionalDykstra <T>(contracted.NodeBasedGraph, _db.GetRestrictions(profileInstance.Profile), weightHandler,
                                                                                                             source.ToEdgePaths(_db, weightHandler, true), target.ToEdgePaths(_db, weightHandler, false));
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            if (path == null)
                            {
                                return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                                {
                                    return new RouteNotFoundException(message);
                                }));
                            }
                        }
                        else
                        {
                            vertexPath = Algorithms.Contracted.BidirectionalDykstraExtensions.GetPath(bidirectionalSearch);
                        }
                    }

                    // expand vertex path using the regular graph.
                    if (vertexPath != null)
                    {
                        var localPath = _db.BuildEdgePath(weightHandler, source, target, vertexPath);
                        if (path == null ||
                            weightHandler.IsSmallerThan(localPath.Weight, path.Weight))
                        {
                            path = localPath;
                        }
                    }
                }
                else
                { // use the regular graph.
                    EdgePath <T> localPath = null;

                    if (_db.HasComplexRestrictions(profileInstance.Profile))
                    {
                        var sourceSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler,
                                                                                        _db.GetGetRestrictions(profileInstance.Profile, true), source.ToEdgePaths(_db, weightHandler, true), maxSearch, false);
                        var targetSearch = new Algorithms.Default.EdgeBased.Dykstra <T>(_db.Network.GeometricGraph.Graph, weightHandler,
                                                                                        _db.GetGetRestrictions(profileInstance.Profile, false), target.ToEdgePaths(_db, weightHandler, false), maxSearch, true);

                        var bidirectionalSearch = new Algorithms.Default.EdgeBased.BidirectionalDykstra <T>(sourceSearch, targetSearch, weightHandler);
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            if (path == null)
                            {
                                return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                                {
                                    return new RouteNotFoundException(message);
                                }));
                            }
                        }
                        else
                        {
                            localPath = bidirectionalSearch.GetPath();
                        }
                    }
                    else
                    {
                        var sourceSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, _db.GetGetSimpleRestrictions(profileInstance.Profile), weightHandler,
                                                           source.ToEdgePaths(_db, weightHandler, true), maxSearch, false);
                        var targetSearch = new Dykstra <T>(_db.Network.GeometricGraph.Graph, _db.GetGetSimpleRestrictions(profileInstance.Profile), weightHandler,
                                                           target.ToEdgePaths(_db, weightHandler, false), maxSearch, true);

                        var bidirectionalSearch = new BidirectionalDykstra <T>(sourceSearch, targetSearch, weightHandler);
                        bidirectionalSearch.Run();
                        if (!bidirectionalSearch.HasSucceeded)
                        {
                            if (path == null)
                            {
                                return(new Result <EdgePath <T> >(bidirectionalSearch.ErrorMessage, (message) =>
                                {
                                    return new RouteNotFoundException(message);
                                }));
                            }
                        }
                        else
                        {
                            localPath = bidirectionalSearch.GetPath();
                        }
                    }

                    // choose best path.
                    if (localPath != null)
                    {
                        if (path == null ||
                            weightHandler.IsSmallerThan(localPath.Weight, path.Weight))
                        {
                            path = localPath;
                        }
                    }
                }
                return(new Result <EdgePath <T> >(path));
            }
            catch (Exception ex)
            {
                return(new Result <EdgePath <T> >(ex.Message, (m) => ex));
            }
        }
Пример #6
0
        /// <summary>
        /// Checks if the given point is connected to the rest of the network. Use this to detect points on routing islands.
        /// </summary>
        /// <param name="radiusInMeter">The radius metric, that's always a distance in meters.</param>
        /// <returns></returns>
        public sealed override Result <bool> TryCheckConnectivity(IProfileInstance profileInstance, RouterPoint point, float radiusInMeter, bool?forward = null)
        {
            try
            {
                if (!_db.Supports(profileInstance.Profile))
                {
                    return(new Result <bool>("Routing profile is not supported.", (message) =>
                    {
                        return new Exception(message);
                    }));
                }

                // get the weight handler.
                var getGetFactor = this.GetDefaultGetFactor(profileInstance);
                Func <ushort, Factor> getShortestFactor = (p) =>
                { // only keep directional information, get factor to 1 for distance metrics only.
                    var factor = getGetFactor(p);
                    if (factor.Value == 0)
                    {
                        return(new Factor()
                        {
                            Direction = factor.Direction,
                            Value = 0
                        });
                    }
                    return(new Factor()
                    {
                        Direction = factor.Direction,
                        Value = 1
                    });
                };
                var weightHandler = new DefaultWeightHandler(getShortestFactor);

                var checkForward  = forward == null || forward.Value;
                var checkBackward = forward == null || !forward.Value;

                if (checkForward)
                { // build and run forward dykstra search.
                    var dykstra = new Algorithms.Default.EdgeBased.Dykstra(_db.Network.GeometricGraph.Graph, weightHandler,
                                                                           _db.GetGetRestrictions(profileInstance.Profile, true), point.ToEdgePaths(_db, weightHandler, true), radiusInMeter, false);
                    dykstra.Run();
                    if (!dykstra.HasSucceeded ||
                        !dykstra.MaxReached)
                    { // something went wrong or max not reached.
                        return(new Result <bool>(false));
                    }
                }


                if (checkBackward)
                { // build and run backward dykstra search.
                    var dykstra = new Algorithms.Default.EdgeBased.Dykstra(_db.Network.GeometricGraph.Graph, weightHandler,
                                                                           _db.GetGetRestrictions(profileInstance.Profile, false), point.ToEdgePaths(_db, weightHandler, false), radiusInMeter, true);
                    dykstra.Run();
                    if (!dykstra.HasSucceeded ||
                        !dykstra.MaxReached)
                    { // something went wrong or max not reached.
                        return(new Result <bool>(false));
                    }
                }
                return(new Result <bool>(true));
            }
            catch (Exception ex)
            {
                return(new Result <bool>(ex.Message, (m) => ex));
            }
        }