Пример #1
0
        /// <summary>
        /// Finds all candidate vertex/edge pairs for a given location reference point.
        /// </summary>
        public static Itinero.Algorithms.Collections.SortedSet <CandidatePathSegment> FindCandidatesFor(this Coder coder, LocationReferencePoint lrp, bool forward, float maxVertexDistance = 40)
        {
            var vertexEdgeCandidates = new Itinero.Algorithms.Collections.SortedSet <CandidatePathSegment>(new CandidateVertexEdgeComparer());
            var vertexCandidates     = coder.FindCandidateLocationsFor(lrp, maxVertexDistance);

            foreach (var vertexCandidate in vertexCandidates)
            {
                var edgeCandidates = coder.FindCandidatePathSegmentsFor(vertexCandidate, forward, lrp.FormOfWay.Value, lrp.FuntionalRoadClass.Value,
                                                                        lrp.Bearing.Value);
                foreach (var edgeCandidate in edgeCandidates)
                {
                    vertexEdgeCandidates.Add(edgeCandidate);
                }
            }
            return(vertexEdgeCandidates);
        }
        /// <summary>
        /// Decodes the given location.
        /// </summary>
        public static ReferencedPointAlongLine Decode(PointAlongLineLocation location, Coder coder)
        {
            CandidateRoute best             = null;
            CombinedScore  bestCombinedEdge = null;

            // get candidate vertices and edges.
            var candidates           = new List <Itinero.Algorithms.Collections.SortedSet <CandidatePathSegment> >();
            var lrps                 = new List <LocationReferencePoint>();
            var fromBearingReference = location.First.Bearing;
            var toBearingReference   = location.Last.Bearing;

            // loop over all lrps.
            lrps.Add(location.First);
            var firstCandidates = coder.FindCandidatesFor(location.First, true);

            candidates.Add(firstCandidates);
            var lastCandidates = coder.FindCandidatesFor(location.Last, false);

            candidates.Add(lastCandidates);

            // build a list of combined scores.
            var combinedScoresSet = new Itinero.Algorithms.Collections.SortedSet <CombinedScore>(new CombinedScoreComparer());

            foreach (var previousCandidate in candidates[0])
            {
                foreach (var currentCandidate in candidates[1])
                {
                    if (previousCandidate.Location.EdgeId != currentCandidate.Location.EdgeId ||
                        previousCandidate.Location.Offset != currentCandidate.Location.Offset)
                    { // make sure vertices are different.
                        combinedScoresSet.Add(new CombinedScore()
                        {
                            Source = previousCandidate,
                            Target = currentCandidate
                        });
                    }
                }
            }

            // find the best candidate route.
            var combinedScores = new List <CombinedScore>(combinedScoresSet);

            while (combinedScores.Count > 0)
            {
                // get the first pair.
                var combinedScore = combinedScores.First();
                combinedScores.Remove(combinedScore);

                // find a route.
                var candidate = coder.FindCandidateRoute(combinedScore.Source, combinedScore.Target,
                                                         lrps[0].LowestFunctionalRoadClassToNext.Value);

                // 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 = location.First.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 > Parameters.DONT_CARE_DISTANCE || distance > Parameters.DONT_CARE_DISTANCE)
                    { // non-perfect score.
                        // don't care about difference smaller than Parameters.DONT_CARE_DISTANCE, the binary encoding only handles segments of about 50m.
                        var distanceDiff = System.Math.Max(System.Math.Abs(distance - expectedDistance) - Parameters.DONT_CARE_DISTANCE, 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)
                    { // ok, candidate is good enough.
                        // check candidate.
                        if (best == null)
                        { // there was no previous candidate.
                            best             = candidate;
                            bestCombinedEdge = combinedScore;
                        }
                        else if (best.Score.Value < candidate.Score.Value)
                        { // the new candidate is better.
                            best             = candidate;
                            bestCombinedEdge = combinedScore;
                        }
                        else if (best.Score.Value > candidate.Score.Value)
                        { // the current candidate is better.
                            break;
                        }
                    }
                }
            }

            // check if a location was found or not.
            if (best == null || best.Route == null)
            { // no location could be found.
                throw new ReferencedDecodingException(location, "No valid location was found.");
            }

            // calculate total score.
            var totalScore = bestCombinedEdge.Score + best.Score;

            // calculate the percentage value.
            var offsetRatio = 0.0f;

            if (location.PositiveOffsetPercentage.HasValue)
            { // there is a percentage set.
                offsetRatio = location.PositiveOffsetPercentage.Value / 100.0f;
            }

            // calculate the actual location and take into account the shape.
            int offsetEdgeIdx;

            Itinero.LocalGeo.Coordinate offsetLocation;
            float offsetLength;
            float offsetEdgeLength;
            float edgeLength;
            var   coordinates = best.Route.GetCoordinates(coder, offsetRatio,
                                                          out offsetEdgeIdx, out offsetLocation, out offsetLength, out offsetEdgeLength, out edgeLength);

            var longitudeReference = offsetLocation.Longitude;
            var latitudeReference  = offsetLocation.Latitude;

            // create the referenced location.
            var pointAlongLineLocation = new ReferencedPointAlongLine();

            pointAlongLineLocation.Score     = totalScore;
            pointAlongLineLocation.Route     = best.Route;
            pointAlongLineLocation.Latitude  = latitudeReference;
            pointAlongLineLocation.Longitude = longitudeReference;
            if (location.Orientation.HasValue)
            {
                pointAlongLineLocation.Orientation = location.Orientation.Value;
            }
            else
            {
                pointAlongLineLocation.Orientation = Orientation.NoOrientation;
            }

            // add the edge meta data.
            pointAlongLineLocation.EdgeMeta = new EdgeMeta()
            {
                Idx    = offsetEdgeIdx,
                Length = edgeLength,
                Offset = offsetEdgeLength
            };

            return(pointAlongLineLocation);
        }
Пример #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);
        }