Ejemplo n.º 1
0
        /// <summary>
        /// Calculates a route between the two given vertices.
        /// </summary>
        /// <returns></returns>
        public override CandidateRoute FindCandidateRoute(CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum,
                                                          bool ignoreFromEdge = false, bool ignoreToEdge = false)
        {
            var edgeInterpreter = new ShapefileEdgeInterpreter();
            var interpreter     = new ShapefileRoutingInterpreter();
            var path            = this.GetRouter().Calculate(this.Graph, interpreter, this.Vehicle, from, to, minimum,
                                                             ignoreFromEdge, ignoreToEdge);

            // if no route is found, score is 0.
            if (path == null)
            {
                return(new CandidateRoute()
                {
                    Route = null,
                    Score = Score.New(Score.CANDIDATE_ROUTE, "Candidate route quality.", 0, 1)
                });
            }

            var edges    = new List <LiveEdge>();
            var vertices = new List <long>();

            vertices.Add(path.VertexId);
            while (path.From != null)
            {
                // add to vertices list.
                vertices.Add(path.From.VertexId);

                // get edge between current and from.
                var fromVertex = path.From.VertexId;
                var toVertex   = path.VertexId;

                var      edgeDistance = double.MaxValue;
                var      arcs         = this.Graph.GetEdges(fromVertex);
                LiveEdge?edge         = null;
                foreach (var arc in arcs)
                {
                    if (arc.Key == toVertex &&
                        arc.Value.Distance < edgeDistance)
                    { // there is a candidate arc.
                        edgeDistance = arc.Value.Distance;
                        edge         = arc.Value;
                    }
                }

                if (!edge.HasValue)
                { // this should be impossible.
                    throw new Exception("No edge found between two consequtive vertices on a route.");
                }
                edges.Add(edge.Value);


                // move to next segment.
                path = path.From;
            }

            // reverse lists.
            edges.Reverse();
            vertices.Reverse();

            // fill shapes.
            var edgeShapes = new GeoCoordinateSimple[edges.Count][];

            for (int i = 0; i < edges.Count; i++)
            {
                edgeShapes[i] = this.Graph.GetEdgeShape(vertices[i], vertices[i + 1]);
            }

            return(new CandidateRoute()
            {
                Route = new ReferencedLine(this.Graph)
                {
                    Edges = edges.ToArray(),
                    EdgeShapes = edgeShapes,
                    Vertices = vertices.ToArray()
                },
                Score = Score.New(Score.CANDIDATE_ROUTE, "Candidate route quality.", 1, 1)
            });
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Calculates a route between the two given vertices.
 /// </summary>
 /// <returns></returns>
 public abstract CandidateRoute FindCandidateRoute(CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum,
                                                   bool ignoreFromEdge = false, bool ignoreToEdge = false);
Ejemplo n.º 3
0
 /// <summary>
 /// Calculates a path between the two candidates using the information in the candidates.
 /// </summary>
 public PathSegment <long> Calculate(BasicRouterDataSource <LiveEdge> graph, IRoutingInterpreter interpreter,
                                     Vehicle vehicle, CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum,
                                     bool ignoreFromEdge, bool ignoreToEdge)
 {
     return(this.Calculate(graph, interpreter, vehicle, from, to, minimum, MaxSettles, ignoreFromEdge, ignoreToEdge));
 }
Ejemplo n.º 4
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);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Decodes an OpenLR-encoded unreferenced raw OpenLR location into a referenced Location.
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        public override ReferencedLine Decode(LineLocation location)
        {
            // get candidate vertices and edges.
            var candidates = new List <SortedSet <CandidateVertexEdge> >();
            var lrps       = new List <LocationReferencePoint>();

            // loop over all lrps.
            lrps.Add(location.First);
            candidates.Add(this.MainDecoder.FindCandidatesFor(location.First, true));
            if (location.Intermediate != null)
            { // there are intermediates.
                for (int idx = 0; idx < location.Intermediate.Length; idx++)
                {
                    lrps.Add(location.Intermediate[idx]);
                    candidates.Add(this.MainDecoder.FindCandidatesFor(location.Intermediate[idx], true));
                }
            }
            lrps.Add(location.Last);
            candidates.Add(this.MainDecoder.FindCandidatesFor(location.Last, false));

            // find a route between each pair of sequential points.
            // start with the last two points and move backwards.
            var target               = lrps[lrps.Count - 1];
            var targetCandidates     = candidates[candidates.Count - 1];
            var lineLocationSegments = new List <ReferencedLine>();

            for (int idx = lrps.Count - 2; idx >= 0; idx--)
            {
                var source           = lrps[idx];
                var sourceCandidates = candidates[idx];

                // build a list of combined scores.
                var combinedScoresSet = new SortedSet <CombinedScore>(new CombinedScoreComparer());
                foreach (var targetCandidate in targetCandidates)
                {
                    foreach (var currentCandidate in sourceCandidates)
                    {
                        combinedScoresSet.Add(new CombinedScore()
                        {
                            Source = currentCandidate,
                            Target = targetCandidate
                        });
                    }
                }
                var combinedScores = new List <CombinedScore>(combinedScoresSet);

                // find the best candidate route.
                CandidateRoute      best       = null;
                CandidateVertexEdge bestSource = null;
                while (combinedScores.Count > 0)
                {
                    // get the first pair.
                    var combinedScore = combinedScores[0];
                    combinedScores.RemoveAt(0);

                    // find a route.
                    var candidate = this.MainDecoder.FindCandidateRoute(combinedScore.Source, combinedScore.Target,
                                                                        source.LowestFunctionalRoadClassToNext.Value, false, idx < lrps.Count - 2);

                    // bring score of from/to also into the mix.
                    candidate.Score = candidate.Score + combinedScore.Score;

                    // verify bearing by adding it to the score.
                    if (candidate != null && candidate.Route != null)
                    { // calculate bearing and compare with reference bearing.
                        // calculate distance and compare with distancetonext.
                        var distance         = candidate.Route.GetCoordinates(this.MainDecoder.Graph).Length().Value;
                        var expectedDistance = source.DistanceToNext;

                        // default a perfect score, only compare large distances.
                        Score deviation = Score.New(Score.DISTANCE_COMPARISON,
                                                    "Compares expected location distance with decoded location distance (1=perfect, 0=difference bigger than total distance)", 1, 1);
                        if (expectedDistance > 200 || distance > 200)
                        { // non-perfect score.
                            // don't care about difference smaller than 200m, the binary encoding only handles segments of about 50m.
                            var distanceDiff = System.Math.Max(System.Math.Abs(distance - expectedDistance) - 200, 0);
                            deviation = Score.New(Score.DISTANCE_COMPARISON, "Compares expected location distance with decoded location distance (1=prefect, 0=difference bigger than total distance)",
                                                  1 - System.Math.Min(System.Math.Max(distanceDiff / expectedDistance, 0), 1), 1);
                        }

                        // add deviation-score.
                        candidate.Score = candidate.Score * deviation;

                        if ((candidate.Score.Value / candidate.Score.Reference) > this.MainDecoder.ScoreThreshold)
                        {
                            // check candidate.
                            if (best == null)
                            { // there was no previous candidate or candidate has no route.
                                best       = candidate;
                                bestSource = combinedScore.Source;
                            }
                            else if (best.Score.Value < candidate.Score.Value)
                            { // the new candidate is better.
                                best       = candidate;
                                bestSource = combinedScore.Source;
                            }
                            else if (best.Score.Value > candidate.Score.Value)
                            { // the current candidate is better.
                                break;
                            }

                            if (best.Score.Value == 1)
                            { // stop search on a perfect scrore!
                                break;
                            }
                        }
                    }
                }

                // append the current best.
                if (best == null || best.Route == null)
                { // no location reference found between two points.
                    return(null);
                }
                // keep the segment.
                lineLocationSegments.Insert(0, best.Route);

                // assign new next.
                target           = source;
                targetCandidates = new SortedSet <CandidateVertexEdge>();
                targetCandidates.Add(bestSource); // only the best source can be re-used for the next segment.
            }

            // build the line location from the segments.
            var lineLocation = lineLocationSegments[0];

            for (var i = 1; i < lineLocationSegments.Count; i++)
            {
                lineLocation.Add(lineLocationSegments[i]);
            }

            lineLocation.PositiveOffsetPercentage = location.PositiveOffsetPercentage.Value;
            lineLocation.NegativeOffsetPercentage = location.NegativeOffsetPercentage.Value;

            return(lineLocation);
        }