Beispiel #1
0
        /// <summary>
        /// Converts this candidate to a feature collection.
        /// </summary>
        public static FeatureCollection ToFeatures(this CandidatePathSegment candidate, RouterDb routerDb)
        {
            var features = new FeatureCollection();

            features.Add(candidate.Location.ToFeature(routerDb));

            return(features);
        }
Beispiel #2
0
        /// <summary>
        /// Calculates a route between the two given vertices.
        /// </summary>
        public static CandidateRoute FindCandidateRoute(this Coder coder, CandidatePathSegment from, CandidatePathSegment to, FunctionalRoadClass minimum,
                                                        bool invertTargetEdge = true)
        {
            var weightHandler = coder.Profile.Profile.DefaultWeightHandler(coder.Router);

            var directedEdgeFrom = from.Path.Edge;
            var directedEdgeTo   = -to.Path.Edge;

            if (!invertTargetEdge)
            {
                directedEdgeTo = -directedEdgeTo;
            }

            // TODO: probably the bug is one-edge routes.
            var path = coder.Router.TryCalculateRaw(coder.Profile.Profile, weightHandler,
                                                    directedEdgeFrom, directedEdgeTo, coder.Profile.RoutingSettings);

            if (Itinero.LocalGeo.Coordinate.DistanceEstimateInMeter(from.Location.Location(), to.Location.Location()) > coder.Profile.MaxSearch / 2)
            {
                try
                {
                    coder.Profile.RoutingSettings.SetMaxSearch(coder.Profile.Profile.FullName, coder.Profile.MaxSearch * 4);
                    path = coder.Router.TryCalculateRaw(coder.Profile.Profile, weightHandler,
                                                        directedEdgeFrom, directedEdgeTo, coder.Profile.RoutingSettings);
                }
                catch
                {
                    throw;
                }
                finally
                {
                    coder.Profile.RoutingSettings.SetMaxSearch(coder.Profile.Profile.FullName, coder.Profile.MaxSearch);
                }
            }

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

            var pathAsList = path.Value.ToList();
            var edges      = new List <long>();
            var vertices   = new List <uint>();

            for (var i = 0; i < pathAsList.Count; i++)
            {
                vertices.Add(pathAsList[i].Vertex);
                if (i > 0)
                {
                    if (pathAsList[i].Edge != Itinero.Constants.NO_EDGE &&
                        pathAsList[i].Edge != -Itinero.Constants.NO_EDGE)
                    {
                        edges.Add(pathAsList[i].Edge);
                    }
                    else
                    {
                        var   edgeEnumerator = coder.Router.Db.Network.GeometricGraph.Graph.GetEdgeEnumerator();
                        float best;
                        var   edge = edgeEnumerator.FindBestEdge(weightHandler, vertices[vertices.Count - 2],
                                                                 vertices[vertices.Count - 1], out best);
                        edges.Add(edge);
                    }
                }
            }

            var startLocation = from.Location;

            if (!from.Location.IsVertex())
            { // first vertex is virtual.
                vertices[0] = Itinero.Constants.NO_VERTEX;
            }
            else
            { // make sure routerpoint has same edge.
                startLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edges[0], vertices[0]);
            }

            var endLocation = to.Location;

            if (!to.Location.IsVertex())
            { // last vertex is virtual.
                vertices[vertices.Count - 1] = Itinero.Constants.NO_VERTEX;
            }
            else
            { // make sure routerpoint has the same edge.
                endLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edges[edges.Count - 1], vertices[vertices.Count - 1]);
            }

            return(new CandidateRoute()
            {
                Route = new ReferencedLine()
                {
                    Edges = edges.ToArray(),
                    Vertices = vertices.ToArray(),
                    StartLocation = startLocation,
                    EndLocation = endLocation
                },
                Score = Score.New(Score.CANDIDATE_ROUTE, "Candidate route quality.", 1, 1)
            });
        }
Beispiel #3
0
        /// <summary>
        /// Decodes the given location.
        /// </summary>
        public static ReferencedLine Decode(LineLocation location, Coder coder)
        {
            // get candidate vertices and edges.
            var candidates = new List <Itinero.Algorithms.Collections.SortedSet <CandidatePathSegment> >();
            var lrps       = new List <LocationReferencePoint>();

            // loop over all lrps.
            lrps.Add(location.First);
            candidates.Add(coder.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(coder.FindCandidatesFor(location.Intermediate[idx], true));
                }
            }
            lrps.Add(location.Last);
            candidates.Add(coder.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 Itinero.Algorithms.Collections.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;
                CandidatePathSegment bestSource = null;
                var targetIsLast = idx == lrps.Count - 2;
                while (combinedScores.Count > 0)
                {
                    // get the first pair.
                    var combinedScore = combinedScores[0];
                    combinedScores.RemoveAt(0);

                    // find a route.
                    var candidate = coder.FindCandidateRoute(combinedScore.Source, combinedScore.Target,
                                                             source.LowestFunctionalRoadClassToNext.Value, targetIsLast);

                    // 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(coder.Router.Db).Length();
                        var expectedDistance = source.DistanceToNext;

                        // default a perfect score, only compare large distances.
                        var 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) > coder.Profile.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);
                }

                if (!targetIsLast)
                { // strip last edge and vertex, these will overlap with the previous.
                    best.Route.Vertices = best.Route.Vertices.Range(0, best.Route.Vertices.Length - 1);
                    best.Route.Edges    = best.Route.Edges.Range(0, best.Route.Edges.Length - 1);
                }

                // keep the segment.
                lineLocationSegments.Insert(0, best.Route);

                // assign new next.
                target           = source;
                targetCandidates = new Itinero.Algorithms.Collections.SortedSet <CandidatePathSegment>();
                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 == null) ? 0 : location.PositiveOffsetPercentage.Value;
            lineLocation.NegativeOffsetPercentage = (location.NegativeOffsetPercentage == null) ? 0 : location.NegativeOffsetPercentage.Value;

            return(lineLocation);
        }