Пример #1
0
        /// <summary>
        /// Validates if the location is connected.
        /// </summary>
        /// <returns></returns>
        public static void ValidateConnected(this ReferencedLine line, Coder coder)
        {
            var profile = coder.Profile;

            var edges    = line.Edges;
            var vertices = line.Vertices;

            // 1: Is the path connected?
            // 2: Is the path traversable?
            for (int edgeIdx = 0; edgeIdx < edges.Length; edgeIdx++)
            {
                var from = vertices[edgeIdx];
                var to   = vertices[edgeIdx + 1];

                // find edge.
                var         found     = false;
                RoutingEdge foundEdge = null;
                foreach (var edge in coder.Router.Db.Network.GetEdges(from))
                {
                    if (edge.To == to &&
                        edge.IdDirected() == edges[edgeIdx])
                    { // edge was found, is valid.
                        found     = true;
                        foundEdge = edge;
                        break;
                    }
                }
                if (!found)
                { // edge is not found, path not connected.
                    throw new ArgumentOutOfRangeException(string.Format("Edge {0} cannot be found between vertex {1} and {2}. The given path is not connected.",
                                                                        edges[edgeIdx].ToInvariantString(), from, to));
                }

                // check whether the edge can traversed.
                var factor = profile.Profile.Factor(coder.Router.Db.EdgeProfiles.Get(foundEdge.Data.Profile));
                if (factor.Value == 0)
                { // oeps, cannot be traversed.
                    throw new ArgumentOutOfRangeException(string.Format("Edge at index {0} cannot be traversed by vehicle {1}.", edgeIdx, profile.Profile.Name));
                }

                // check whether the edge can be traversed in the correct direction.
                var canMoveForward = (factor.Direction == 0) ||
                                     (factor.Direction == 1 && !foundEdge.DataInverted) ||
                                     (factor.Direction == 2 && foundEdge.DataInverted);
                if (!canMoveForward)
                { // path cannot be traversed in this direction.
                    throw new ArgumentOutOfRangeException(string.Format("Edge at index {0} cannot be traversed by vehicle {1} in the direction given.", edgeIdx,
                                                                        profile.Profile.Name));
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Returns true if the sequence vertex1->vertex2 occurs on the shortest path between from and to.
        /// </summary>
        /// <returns></returns>
        public static bool IsOnShortestPath(this Coder coder, uint from, uint to, uint vertex1, uint vertex2)
        {
            var path = coder.FindShortestPath(from, to, true).ToListAsVertices();

            for (var i = 1; i < path.Count; i++)
            {
                if (path[i - 1] == vertex1 &&
                    path[i] == vertex2)
                {
                    return(true);
                }
            }
            return(false);
        }
Пример #3
0
        /// <summary>
        /// Adjusts this location by inserting intermediate LR-points if needed.
        /// </summary>
        ///
        public static void AdjustToValidDistance(this ReferencedLine line, Coder coder, List <int> points, int start = 0)
        {
            // get start/end vertex.
            var vertexIdx1 = points[start];
            var vertexIdx2 = points[start + 1];
            var count      = vertexIdx2 - vertexIdx1 + 1;

            // calculate length to begin with.
            var coordinates = line.GetCoordinates(coder.Router.Db, vertexIdx1, count);
            var length      = coordinates.Length();

            if (length > 15000)
            { // too long.
                // find the best intermediate point.
                var intermediatePoints = new SortedDictionary <double, int>();
                for (int idx = vertexIdx1 + 1; idx < vertexIdx1 + count - 2; idx++)
                {
                    var score = 0.0;
                    if (coder.IsVertexValid(line.Vertices[idx]))
                    { // a valid vertex is obviously a better choice!
                        score = score + 4096;
                    }

                    // the length is good when close to 15000 but not over.
                    var lengthBefore = line.GetCoordinates(coder.Router.Db, vertexIdx1, idx - vertexIdx1 + 1).Length();
                    if (lengthBefore < 15000)
                    { // not over!
                        score = score + (1024 * (lengthBefore / 15000));
                    }
                    var lengthAfter = line.GetCoordinates(coder.Router.Db, idx, count - idx).Length();
                    if (lengthAfter < 15000)
                    { // not over!
                        score = score + (1024 * (lengthAfter / 15000));
                    }

                    // add to sorted dictionary.
                    intermediatePoints[8192 - score] = idx;
                }

                // select the best point and insert it in between.
                var bestPoint = intermediatePoints.First().Value;
                points.Insert(start + 1, bestPoint);

                // test the two distances.
                line.AdjustToValidDistance(coder, points, start + 1);
                line.AdjustToValidDistance(coder, points, start);
            }
        }
Пример #4
0
        /// <summary>
        /// Builds the shortest path along all the given coordinates as a referenced line.
        /// </summary>
        public static ReferencedLine BuildLine(this Coder coder, Itinero.LocalGeo.Coordinate[] coordinates)
        {
            var   edgesTotal    = new List <long>();
            var   verticesTotal = new List <uint>();
            float pathDistance  = 0;
            var   sourceOffset  = 0f;
            var   targetOffset  = 0f;
            var   totalDistance = 0f;

            for (int w = 1; w < coordinates.Length; w++)
            {
                var coordinate1 = coordinates[w - 1];
                var coordinate2 = coordinates[w];

                // calculate raw path.
                var weightHandler = coder.Router.GetDefaultWeightHandler(coder.Profile.Profile);
                var source        = coder.Router.Resolve(coder.Profile.Profile, coordinate1, 100);
                var target        = coder.Router.Resolve(coder.Profile.Profile, coordinate2, 100);
                var path          = coder.Router.TryCalculateRaw(coder.Profile.Profile, weightHandler,
                                                                 source, target, coder.Profile.RoutingSettings);
                if (path.IsError)
                {
                    throw new InvalidOperationException("No route found.");
                }

                // build route.
                var route = coder.Router.BuildRoute(coder.Profile.Profile, weightHandler, source, target, path.Value).Value;
                //pathDistance += path.Value.Weight;
                pathDistance += route.TotalDistance;

                // build referenced line by building vertices and edge list.
                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);
                        }
                    }
                }

                if (vertices[0] == Constants.NO_VERTEX)
                {
                    var edge = coder.Router.Db.Network.GetEdge(edges[0]);
                    if (edge.From == vertices[1])
                    {
                        vertices[0] = edge.To;
                    }
                    else if (edge.To == vertices[1])
                    {
                        vertices[0] = edge.From;
                    }
                    else
                    {
                        throw new Exception("First edge does not match first vertex.");
                    }
                }

                if (vertices[vertices.Count - 1] == Constants.NO_VERTEX)
                {
                    var edge = coder.Router.Db.Network.GetEdge(edges[edges.Count - 1]);
                    if (edge.From == vertices[vertices.Count - 2])
                    {
                        vertices[vertices.Count - 1] = edge.To;
                    }
                    else if (edge.To == vertices[vertices.Count - 2])
                    {
                        vertices[vertices.Count - 1] = edge.From;
                    }
                    else
                    {
                        throw new Exception("Last edge does not match last vertex.");
                    }
                }

                if (edgesTotal.Count > 0)
                {
                    edges.RemoveAt(0);
                }
                edgesTotal.AddRange(edges);

                if (verticesTotal.Count > 0)
                {
                    vertices.RemoveAt(0);
                    vertices.RemoveAt(0);
                }
                verticesTotal.AddRange(vertices);
            }

            var edge_ = coder.Router.Db.Network.GetEdge(edgesTotal[0]);

            if (edge_.From == verticesTotal[1])
            {
                sourceOffset = Itinero.LocalGeo.Coordinate.DistanceEstimateInMeter(coordinates[0],
                                                                                   coder.Router.Db.Network.GetVertex(edge_.To));
            }
            else if (edge_.To == verticesTotal[1])
            {
                sourceOffset = Itinero.LocalGeo.Coordinate.DistanceEstimateInMeter(coordinates[0],
                                                                                   coder.Router.Db.Network.GetVertex(edge_.From));
            }
            else
            {
                throw new Exception("First edge does not match first vertex.");
            }

            edge_ = coder.Router.Db.Network.GetEdge(edgesTotal[edgesTotal.Count - 1]);
            if (edge_.From == verticesTotal[verticesTotal.Count - 2])
            {
                targetOffset = Itinero.LocalGeo.Coordinate.DistanceEstimateInMeter(coordinates[coordinates.Length - 1],
                                                                                   coder.Router.Db.Network.GetVertex(edge_.To));
            }
            else if (edge_.To == verticesTotal[verticesTotal.Count - 2])
            {
                targetOffset = Itinero.LocalGeo.Coordinate.DistanceEstimateInMeter(coordinates[coordinates.Length - 1],
                                                                                   coder.Router.Db.Network.GetVertex(edge_.From));
            }
            else
            {
                throw new Exception("Last edge does not match last vertex.");
            }

            totalDistance = pathDistance + sourceOffset + targetOffset;

            return(new ReferencedLine()
            {
                Edges = edgesTotal.ToArray(),
                Vertices = verticesTotal.ToArray(),
                NegativeOffsetPercentage = 100.0f * (targetOffset / totalDistance),
                PositiveOffsetPercentage = 100.0f * (sourceOffset / totalDistance),
                StartLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edgesTotal[0], verticesTotal[0]),
                EndLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edgesTotal[edgesTotal.Count - 1], verticesTotal[verticesTotal.Count - 1])
            });
        }
Пример #5
0
        /// <summary>
        /// Returns true if the given vertex is a valid candidate to use as a location reference point.
        /// </summary>
        public static bool IsVertexValid(this Coder coder, uint vertex)
        {
            var profile = coder.Profile;
            var edges   = coder.Router.Db.Network.GetEdges(vertex);

            // go over each arc and count the traversible arcs.
            var traversCount = 0;

            foreach (var edge in edges)
            {
                var factor = profile.Profile.Factor(coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile));
                if (factor.Value != 0)
                {
                    traversCount++;
                }
            }
            if (traversCount != 3)
            {     // no special cases, only 1=valid, 2=invalid or 4 and up=valid.
                if (traversCount == 2)
                { // only two traversable edges, no options here!
                    return(false);
                }
                return(true);
            }
            else
            { // special cases possible here, we need more info here.
                var incoming      = new List <Tuple <long, IAttributeCollection, uint> >();
                var outgoing      = new List <Tuple <long, IAttributeCollection, uint> >();
                var bidirectional = new List <Tuple <long, IAttributeCollection, uint> >();
                foreach (var edge in edges)
                {
                    var edgeProfile = coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile);
                    var factor      = profile.Profile.Factor(edgeProfile);
                    if (factor.Value != 0)
                    {
                        if (factor.Direction == 0)
                        { // bidirectional, can be used as incoming.
                            bidirectional.Add(new Tuple <long, IAttributeCollection, uint>(edge.From, edgeProfile, edge.Id));
                        }
                        else if ((factor.Direction == 2 && !edge.DataInverted) ||
                                 (factor.Direction == 1 && edge.DataInverted))
                        { // oneway is forward but arc is backward, arc is incoming.
                            // oneway is backward and arc is forward, arc is incoming.
                            incoming.Add(new Tuple <long, IAttributeCollection, uint>(edge.From, edgeProfile, edge.Id));
                        }
                        else if ((factor.Direction == 2 && edge.DataInverted) ||
                                 (factor.Direction == 1 && !edge.DataInverted))
                        { // oneway is forward and arc is forward, arc is outgoing.
                            // oneway is backward and arc is backward, arc is outgoing.
                            outgoing.Add(new Tuple <long, IAttributeCollection, uint>(edge.From, edgeProfile, edge.Id));
                        }
                    }
                }

                if (bidirectional.Count == 1 && incoming.Count == 1 && outgoing.Count == 1)
                { // all special cases are found here.
                    // get incoming's frc and fow.
                    FormOfWay           incomingFow, outgoingFow, bidirectionalFow;
                    FunctionalRoadClass incomingFrc, outgoingFrc, bidirectionalFrc;
                    if (profile.Extract(incoming[0].Item2, out incomingFrc, out incomingFow))
                    {
                        if (incomingFow == FormOfWay.Roundabout)
                        { // is this a roundabout, always valid.
                            return(true);
                        }
                        if (profile.Extract(outgoing[0].Item2, out outgoingFrc, out outgoingFow))
                        {
                            if (outgoingFow == FormOfWay.Roundabout)
                            { // is this a roundabout, always valid.
                                return(true);
                            }

                            if (incomingFrc != outgoingFrc)
                            { // is there a difference in frc.
                                return(true);
                            }

                            if (profile.Extract(bidirectional[0].Item2, out bidirectionalFrc, out bidirectionalFow))
                            {
                                if (incomingFrc != bidirectionalFrc)
                                { // is there a difference in frc.
                                    return(true);
                                }
                            }
                        }

                        // at this stage we have:
                        // - two oneways, in opposite direction
                        // - one bidirectional
                        // - all same frc.

                        // the only thing left to check is if the oneway edges go in the same general direction or not.
                        // compare bearings but only if distance is large enough.
                        var incomingShape = coder.Router.Db.Network.GetShape(coder.Router.Db.Network.GetEdge(incoming[0].Item3));
                        var outgoingShape = coder.Router.Db.Network.GetShape(coder.Router.Db.Network.GetEdge(outgoing[0].Item3));

                        if (incomingShape.Length() < 25 &&
                            outgoingShape.Length() < 25)
                        { // edges are too short to compare bearing in a way meaningful for determining this.
                            // assume not valid.
                            return(false);
                        }
                        var incomingBearing = BearingEncoder.EncodeBearing(incomingShape);
                        var outgoingBearing = BearingEncoder.EncodeBearing(outgoingShape);

                        if (OpenLR.Extensions.AngleSmallestDifference(incomingBearing, outgoingBearing) > 30)
                        { // edges are clearly not going in the same direction.
                            return(true);
                        }
                    }
                    return(false);
                }
                return(true);
            }
        }
Пример #6
0
        /// <summary>
        /// Builds the shortest path between the two coordinates as a referenced line.
        /// </summary>
        public static ReferencedLine BuildLine(this Coder coder, Itinero.LocalGeo.Coordinate coordinate1, Itinero.LocalGeo.Coordinate coordinate2)
        {
            Route route;

            return(coder.BuildLine(coordinate1, coordinate2, out route));
        }
Пример #7
0
 /// <summary>
 /// Encodes a set of coordinates as a point along line.
 /// </summary>
 public static string EncodeAsPointAlongLine(this Coder coder, float latitude, float longitude, out RouterPoint resolvedPoint)
 {
     return(coder.Encode(coder.BuildPointAlongLine(latitude, longitude, out resolvedPoint)));
 }
Пример #8
0
        /// <summary>
        /// Builds a point along line location.
        /// </summary>
        public static ReferencedPointAlongLine BuildPointAlongLine(this Coder coder, float latitude, float longitude, out RouterPoint resolvedPoint)
        {
            var routerPoint = coder.Router.TryResolve(coder.Profile.Profile, latitude, longitude);

            if (routerPoint.IsError)
            {
                throw new Exception("Could not build point along line: Could not find an edge close to the given location.");
            }
            resolvedPoint = routerPoint.Value;
            var locationOnNetwork = resolvedPoint.LocationOnNetwork(coder.Router.Db);

            // get edge info.
            var edge = coder.Router.Db.Network.GetEdge(routerPoint.Value.EdgeId);

            // check direction.
            var forward = true;
            var factor  = coder.Profile.Profile.Factor(coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile));

            if (factor.Direction == 2)
            {
                forward = false;
            }

            // build the location with one edge.
            ReferencedPointAlongLine referencedPointAlongLine = null;

            if (forward)
            {
                referencedPointAlongLine = new ReferencedPointAlongLine()
                {
                    Route = new ReferencedLine()
                    {
                        Edges         = new long[] { edge.IdDirected() },
                        Vertices      = new uint[] { edge.From, edge.To },
                        StartLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edge.IdDirected(), edge.From),
                        EndLocation   = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edge.IdDirected(), edge.To)
                    },
                    Latitude    = locationOnNetwork.Latitude,
                    Longitude   = locationOnNetwork.Longitude,
                    Orientation = Orientation.NoOrientation
                };
            }
            else
            {
                referencedPointAlongLine = new ReferencedPointAlongLine()
                {
                    Route = new ReferencedLine()
                    {
                        Edges         = new long[] { -edge.IdDirected() },
                        Vertices      = new uint[] { edge.To, edge.From },
                        StartLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edge.IdDirected(), edge.To),
                        EndLocation   = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edge.IdDirected(), edge.From)
                    },
                    Latitude    = locationOnNetwork.Latitude,
                    Longitude   = locationOnNetwork.Longitude,
                    Orientation = Orientation.NoOrientation
                };
            }

            // expand to valid location.
            referencedPointAlongLine.Route.AdjustToValidPoints(coder);
            referencedPointAlongLine.Route.StartLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(
                referencedPointAlongLine.Route.Edges[0], referencedPointAlongLine.Route.Vertices[0]);
            referencedPointAlongLine.Route.EndLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(
                referencedPointAlongLine.Route.Edges[referencedPointAlongLine.Route.Edges.Length - 1],
                referencedPointAlongLine.Route.Vertices[referencedPointAlongLine.Route.Vertices.Length - 1]);

            return(referencedPointAlongLine);
        }
Пример #9
0
        /// <summary>
        /// Builds a point along line location.
        /// </summary>
        public static ReferencedPointAlongLine BuildPointAlongLine(this Coder coder, float latitude, float longitude)
        {
            RouterPoint resolvedPoint;

            return(coder.BuildPointAlongLine(latitude, longitude, out resolvedPoint));
        }
Пример #10
0
 /// <summary>
 /// Builds a point along line location.
 /// </summary>
 public static ReferencedPointAlongLine BuildPointAlongLine(this Coder coder, Itinero.LocalGeo.Coordinate coordinate, out RouterPoint resolvedPoint)
 {
     return(coder.BuildPointAlongLine(coordinate.Latitude, coordinate.Longitude, out resolvedPoint));
 }
Пример #11
0
        /// <summary>
        /// Finds a valid vertex for the given vertex but does not search in the direction of the target neighbour.
        /// </summary>
        public static EdgePath <float> FindValidVertexFor(this Coder coder, uint vertex, long targetDirectedEdgeId, uint targetVertex, HashSet <uint> excludeSet, bool searchForward)
        {
            var profile = coder.Profile.Profile;

            // GIST: execute a dykstra search to find a vertex that is valid.
            // this will return a vertex that is on the shortest path:
            // foundVertex -> vertex -> targetNeighbour.

            var targetEdge = Itinero.Constants.NO_EDGE;

            if (targetDirectedEdgeId > 0)
            {
                targetEdge = (uint)(targetDirectedEdgeId - 1);
            }
            else
            {
                targetEdge = (uint)((-targetDirectedEdgeId) - 1);
            }

            // initialize settled set.
            var settled = new HashSet <long>();

            settled.Add(targetVertex);

            // initialize heap.
            var heap = new BinaryHeap <EdgePath <float> >(10);

            heap.Push(new EdgePath <float>((uint)vertex), 0);

            // find the path to the closest valid vertex.
            EdgePath <float> pathTo = null;
            var edgeEnumerator      = coder.Router.Db.Network.GetEdgeEnumerator();

            while (heap.Count > 0)
            {
                // get next.
                var current = heap.Pop();
                if (settled.Contains(current.Vertex))
                { // don't consider vertices twice.
                    continue;
                }
                settled.Add(current.Vertex);

                // limit search.
                if (settled.Count > coder.Profile.MaxSettles)
                { // not valid vertex found.
                    return(null);
                }

                // check if valid.
                if (current.Vertex != vertex &&
                    coder.IsVertexValid(current.Vertex))
                { // ok! vertex is valid.
                    pathTo = current;
                }
                else
                { // continue search.
                    // add unsettled neighbours.
                    edgeEnumerator.MoveTo(current.Vertex);
                    foreach (var edge in edgeEnumerator)
                    {
                        if (!excludeSet.Contains(edge.To) &&
                            !settled.Contains(edge.To) &&
                            !(edge.Id == targetEdge))
                        { // ok, new neighbour, and ok, not the edge and neighbour to ignore.
                            var edgeProfile = coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile);
                            var factor      = profile.Factor(edgeProfile);

                            if (factor.Value > 0 && (factor.Direction == 0 ||
                                                     (searchForward && (factor.Direction == 1) != edge.DataInverted) ||
                                                     (!searchForward && (factor.Direction == 1) == edge.DataInverted)))
                            { // ok, we can traverse this edge and no oneway or oneway reversed.
                                var weight = current.Weight + factor.Value * edge.Data.Distance;
                                var path   = new EdgePath <float>(edge.To, weight, edge.IdDirected(), current);
                                heap.Push(path, (float)path.Weight);
                            }
                        }
                    }
                }
            }

            // ok, is there a path found.
            if (pathTo == null)
            { // oeps, probably something wrong with network-topology.
                // just take the default option.
                //throw new Exception(
                //    string.Format("Could not find a valid vertex for invalid vertex [{0}].", vertex));
                return(null);
            }

            // add the path to the given location.
            return(pathTo);
        }
Пример #12
0
        /// <summary>
        /// Builds a location referenced point for the last vertex.
        /// </summary>
        /// <returns></returns>
        public static Model.LocationReferencePoint BuildLocationReferencePointLast(this ReferencedLine referencedLocation, Coder coder, int before)
        {
            Model.FormOfWay           fow;
            Model.FunctionalRoadClass frc;

            var end = referencedLocation.Vertices.Length - 1;

            // get all coordinates along the sequence starting at 'before' and ending at 'end'.
            var coordinates = referencedLocation.GetCoordinates(coder.Router.Db, before, end - before + 1);

            // create location reference point.
            var locationReferencedPoint = new Model.LocationReferencePoint();

            locationReferencedPoint.Coordinate = coder.Router.Db.Network.GetVertex(referencedLocation.Vertices[end]).ToCoordinate();
            var edgeProfile = coder.Router.Db.EdgeProfiles.Get(coder.Router.Db.Network.GetEdge(referencedLocation.Edges[end - 1]).Data.Profile);

            if (!coder.Profile.Extract(edgeProfile, out frc, out fow))
            {
                throw new ReferencedEncodingException(referencedLocation,
                                                      "Could not find frc and/or fow for the given tags.");
            }
            locationReferencedPoint.FormOfWay          = fow;
            locationReferencedPoint.FuntionalRoadClass = frc;
            locationReferencedPoint.Bearing            = (int)BearingEncoder.EncodeBearing(coordinates, true);

            return(locationReferencedPoint);
        }
Пример #13
0
        /// <summary>
        /// Builds a location referenced point for the vertex at the given start-index.
        /// </summary>
        /// <returns></returns>
        public static Model.LocationReferencePoint BuildLocationReferencePoint(this ReferencedLine referencedLocation, Coder coder, int start, int end)
        {
            Model.FormOfWay           fow;
            Model.FunctionalRoadClass frc;

            // get all coordinates along the sequence starting at 'start' and ending at 'end'.
            var coordinates = referencedLocation.GetCoordinates(coder.Router.Db, start, end - start + 1);

            // create location reference point.
            var locationReferencePoint = new Model.LocationReferencePoint();

            locationReferencePoint.Coordinate = coder.Router.Db.Network.GetVertex(referencedLocation.Vertices[start]).ToCoordinate();
            var edgeProfile = coder.Router.Db.EdgeProfiles.Get(coder.Router.Db.Network.GetEdge(referencedLocation.Edges[start]).Data.Profile);

            if (!coder.Profile.Extract(edgeProfile, out frc, out fow))
            {
                throw new ReferencedEncodingException(referencedLocation,
                                                      "Could not find frc and/or fow for the given tags.");
            }
            locationReferencePoint.FormOfWay          = fow;
            locationReferencePoint.FuntionalRoadClass = frc;
            locationReferencePoint.Bearing            = (int)BearingEncoder.EncodeBearing(coordinates);
            locationReferencePoint.DistanceToNext     = (int)coordinates.Length();
            Model.FunctionalRoadClass?lowest = null;
            for (var edge = start; edge < end; edge++)
            {
                edgeProfile = coder.Router.Db.EdgeProfiles.Get(coder.Router.Db.Network.GetEdge(referencedLocation.Edges[edge]).Data.Profile);
                if (!coder.Profile.Extract(edgeProfile, out frc, out fow))
                {
                    throw new ReferencedEncodingException(referencedLocation,
                                                          "Could not find frc and/or fow for the given tags.");
                }

                if (!lowest.HasValue ||
                    frc > lowest)
                {
                    lowest = frc;
                }
            }
            locationReferencePoint.LowestFunctionalRoadClassToNext = lowest;

            return(locationReferencePoint);
        }
Пример #14
0
        /// <summary>
        /// Tries to adjust this location backwards to a valid point.
        /// </summary>
        /// <returns></returns>
        public static bool TryAdjustToValidPointBackwards(this ReferencedLine line, Coder coder, uint vertex1, uint vertex2,
                                                          HashSet <uint> exclude)
        {
            var length = line.Length(coder.Router.Db);
            var positiveOffsetLength = (line.PositiveOffsetPercentage / 100) * length;

            exclude = new HashSet <uint>(exclude);
            foreach (var vertex in line.Vertices)
            {
                exclude.Add(vertex);
            }

            if (!coder.IsVertexValid(line.Vertices[0]))
            { // from is not valid, try to find a valid point.
                var pathToValid = coder.FindValidVertexFor(line.Vertices[0], line.Edges[0], line.Vertices[1],
                                                           exclude, false);

                // build edges list.
                if (pathToValid != null)
                { // path found check if on shortest route.
                    var shortestRoute = coder.FindShortestPath(line.Vertices[1], pathToValid.Vertex, false);
                    while (shortestRoute != null && !shortestRoute.HasVertex(line.Vertices[0]))
                    { // the vertex that should be on this shortest route, isn't anymore.
                        // exclude the current target vertex,
                        exclude.Add(pathToValid.Vertex);
                        // calulate a new path-to-valid.
                        pathToValid = coder.FindValidVertexFor(line.Vertices[0], line.Edges[0], line.Vertices[1],
                                                               exclude, false);
                        if (pathToValid == null)
                        { // a new path was not found.
                            break;
                        }
                        shortestRoute = coder.FindShortestPath(line.Vertices[1], pathToValid.Vertex, false);
                    }
                    if (pathToValid != null)
                    { // no path found, just leave things as is.
                        var pathToValidAsList = pathToValid.ToList();
                        var newVertices       = new List <uint>();
                        var newEdges          = new List <long>();
                        for (int idx = 0; idx < pathToValidAsList.Count; idx++)
                        { // loop over edges.
                            newVertices.Add(pathToValidAsList[idx].Vertex);
                            if (idx > 0)
                            {
                                newEdges.Add(-pathToValidAsList[idx].Edge); // need the reverse edges.
                            }
                        }
                        newEdges.Reverse();
                        newVertices.Reverse();

                        // create new location.
                        var edgesArray = new long[newEdges.Count + line.Edges.Length];
                        newEdges.CopyTo(0, edgesArray, 0, newEdges.Count);
                        line.Edges.CopyTo(0, edgesArray, newEdges.Count, line.Edges.Length);
                        var vertexArray = new uint[newVertices.Count - 1 + line.Vertices.Length];
                        newVertices.CopyTo(0, vertexArray, 0, newVertices.Count - 1);
                        line.Vertices.CopyTo(0, vertexArray, newVertices.Count - 1, line.Vertices.Length);

                        line.Edges    = edgesArray;
                        line.Vertices = vertexArray;

                        // adjust offset length.
                        var newLength = (float)line.Length(coder.Router.Db);
                        positiveOffsetLength = positiveOffsetLength + (newLength - length);
                        length = newLength;
                    }
                    else
                    { // no valid path was found.
                        return(false);
                    }
                }
                else
                { // no valid path was found.
                    return(false);
                }
            }

            // update offset percentage.
            line.PositiveOffsetPercentage = (float)((positiveOffsetLength / length) * 100.0);

            return(true);
        }
Пример #15
0
        /// <summary>
        /// Converts the referenced line location to a list of sorted coordinates.
        /// </summary>
        /// <returns></returns>
        public static List <Coordinate> GetCoordinates(this ReferencedLine route, Coder coder, float offsetRatio,
                                                       out int offsetEdgeIdx, out Coordinate offsetLocation, out float offsetLength, out float offsetEdgeLength, out float edgeLength)
        {
            if (route == null)
            {
                throw new ArgumentNullException("route");
            }
            if (route.Edges == null || route.Edges.Length == 0)
            {
                throw new ArgumentOutOfRangeException("route", "Route has no edges.");
            }
            if (route.Vertices == null || route.Vertices.Length == 0)
            {
                throw new ArgumentOutOfRangeException("route", "Route has no vertices.");
            }
            if (route.Vertices.Length != route.Edges.Length + 1)
            {
                throw new ArgumentOutOfRangeException("route", "Route is invalid: there should be n vertices and n-1 edges.");
            }

            // calculate the total length first.
            var totalLength = route.GetCoordinates(coder.Router.Db).Length();

            // calculate the lenght at the offst.
            offsetLength     = (float)(totalLength * offsetRatio);
            offsetEdgeLength = -1;
            offsetEdgeIdx    = -1;
            edgeLength       = -1;

            // loop over all coordinates and collect offsetLocation and offsetEdgeIdx.
            float currentOffsetLength = 0;
            float currentEdgeLength   = 0;
            var   coordinates         = new List <Coordinate>();

            for (var i = 0; i < route.Edges.Length; i++)
            {
                List <Coordinate> shape = null;
                currentEdgeLength = 0;
                if (i == 0 && route.Vertices[0] == Itinero.Constants.NO_VERTEX)
                {     // shape from startlocation -> vertex1.
                    if (route.Edges.Length == 1)
                    { // only 1 edge, shape from startLocation -> endLocation.
                        shape = route.StartLocation.ShapePointsTo(coder.Router.Db, route.EndLocation);
                        shape.Insert(0, route.StartLocation.LocationOnNetwork(coder.Router.Db));
                        shape.Add(route.EndLocation.LocationOnNetwork(coder.Router.Db));
                    }
                    else
                    { // just get shape to first vertex.
                        shape = route.StartLocation.ShapePointsTo(coder.Router.Db, route.Vertices[1]);
                        shape.Insert(0, route.StartLocation.LocationOnNetwork(coder.Router.Db));
                        shape.Add(coder.Router.Db.Network.GetVertex(route.Vertices[1]));
                    }
                }
                else if (i == route.Edges.Length - 1 && route.Vertices[route.Vertices.Length - 1] == Itinero.Constants.NO_VERTEX)
                { // shape from second last vertex -> endlocation.
                    shape = route.EndLocation.ShapePointsTo(coder.Router.Db, route.Vertices[route.Vertices.Length - 2]);
                    shape.Reverse();
                    shape.Insert(0, coder.Router.Db.Network.GetVertex(route.Vertices[route.Vertices.Length - 2]));
                    shape.Add(route.EndLocation.LocationOnNetwork(coder.Router.Db));
                }
                else
                { // regular 2 vertices and edge.
                    shape = coder.Router.Db.Network.GetShape(coder.Router.Db.Network.GetEdge(route.Edges[i]));
                    if (route.Edges[i] < 0)
                    {
                        shape.Reverse();
                    }
                }
                if (shape != null)
                {
                    currentEdgeLength = currentEdgeLength + shape.Length();
                    if (coordinates.Count > 0)
                    {
                        coordinates.RemoveAt(coordinates.Count - 1);
                    }
                    for (var j = 0; j < shape.Count; j++)
                    {
                        coordinates.Add(shape[j]);
                    }
                }

                // add current edge length to current offset.
                if ((currentOffsetLength + currentEdgeLength) >= offsetLength &&
                    edgeLength < 0)
                { // it's this edge that has the valuable info.
                    offsetEdgeIdx    = i;
                    offsetEdgeLength = offsetLength - currentOffsetLength;
                    edgeLength       = currentEdgeLength;
                }
                currentOffsetLength = currentOffsetLength + currentEdgeLength;
            }

            // choose the last edge.
            if (edgeLength < 0)
            { // it's this edge that has the valuable info.
                offsetEdgeIdx    = route.Edges.Length - 1;
                offsetEdgeLength = offsetLength - currentOffsetLength;
                edgeLength       = currentEdgeLength;
            }

            // calculate actual offset position.
            offsetLocation = coordinates.GetPositionLocation(offsetRatio);
            return(coordinates);
        }
Пример #16
0
        /// <summary>
        /// Adjusts this location to use valid LR-points.
        /// </summary>
        public static void AdjustToValidPoints(this ReferencedLine line, Coder coder)
        {
            if (line.Vertices.Length <= 1)
            {
                throw new ArgumentException("Cannot adjust a line location with only one vertex.");
            }

            var vertex1Valid = coder.IsVertexValid(line.Vertices[0]);
            var vertex2Valid = coder.IsVertexValid(line.Vertices[line.Vertices.Length - 1]);

            if (vertex1Valid && vertex2Valid)
            { // already valid.
                return;
            }
            if (line.Vertices.Length > 2)
            {
                return;
            }                                         // line was already adjusted.

            var vertex1 = line.Vertices[0];
            var vertex2 = line.Vertices[1];

            if (!coder.IsOnShortestPath(line.Vertices[0], line.Vertices[line.Vertices.Length - 1],
                                        vertex1, vertex2))
            { // impossible to expand edge.
                return;
            }

            // make sure the original sequence is still there on the shortest path.
            ReferencedLine validCopy          = null;
            var            backwardExcludeSet = line.GetVerticesSet();

            while (true)
            {
                // search backward.
                var workingCopy = line.Clone() as ReferencedLine;
                if (!workingCopy.TryAdjustToValidPointBackwards(coder, vertex1, vertex2, backwardExcludeSet))
                { // no more options exist, impossible to expand edge, just keep the edge itself.
                    return;
                }

                if (!vertex2Valid)
                { // search forward.
                    var forwardExcludeSet = workingCopy.GetVerticesSet();
                    do
                    {
                        var forwardWorkingCopy = workingCopy.Clone() as ReferencedLine;
                        if (!forwardWorkingCopy.TryAdjustToValidPointForwards(coder, vertex1, vertex2, forwardExcludeSet))
                        { // no more forward options for the current backward.
                            break;
                        }

                        // check valid.
                        if (coder.IsOnShortestPath(forwardWorkingCopy.Vertices[0], forwardWorkingCopy.Vertices[forwardWorkingCopy.Vertices.Length - 1],
                                                   vertex1, vertex2))
                        { // current location is valid.
                            validCopy = forwardWorkingCopy;
                            break;
                        }

                        // not valid here, exclude current forward.
                        forwardExcludeSet.Add(forwardWorkingCopy.Vertices[forwardWorkingCopy.Vertices.Length - 1]);
                    } while (true);
                }
                else
                { // check valid.
                    if (coder.IsOnShortestPath(workingCopy.Vertices[0], workingCopy.Vertices[workingCopy.Vertices.Length - 1],
                                               vertex1, vertex2))
                    { // current location is valid.
                        validCopy = workingCopy;
                        break;
                    }
                }

                if (validCopy != null)
                { // current location is valid.
                    break;
                }

                if (vertex1Valid)
                { // vertex1 was already valid, no reason to continue searching.
                    return;
                }

                // exclude current backward and continue.
                backwardExcludeSet.Add(workingCopy.Vertices[0]);
            }

            // copy from working copy.
            line.Edges    = validCopy.Edges;
            line.Vertices = validCopy.Vertices;
            line.NegativeOffsetPercentage = validCopy.NegativeOffsetPercentage;
            line.PositiveOffsetPercentage = validCopy.PositiveOffsetPercentage;
        }