/// <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); } }
/// <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); }
/// <summary> /// Builds a location referenced point for the last vertex. /// </summary> /// <returns></returns> public LocationReferencePoint BuildLocationReferencePointLast(ReferencedLine referencedLocation, int before) { FormOfWay fow; 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(this.Graph, before, end - before + 1); // create location reference point. var locationReferencedPoint = new LocationReferencePoint(); locationReferencedPoint.Coordinate = this.GetVertexLocation(referencedLocation.Vertices[end]); var tags = this.GetTags(referencedLocation.Edges[end - 1].Tags); if (!this.TryMatching(tags, 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).Value; return(locationReferencedPoint); }
public void TestReferencedLineGetCoordinates2() { var routerDb = new RouterDb(); routerDb.LoadTestNetwork( System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream( "OpenLR.Test.test_data.networks.network2.geojson")); // build a referenced line 0->1->2->5. var enumerator = routerDb.Network.GetEdgeEnumerator(); enumerator.MoveTo(0); enumerator.MoveNextUntil(x => x.To == 1); var edge01Directed = enumerator.IdDirected(); var edge01 = enumerator.Id; enumerator.MoveTo(1); enumerator.MoveNextUntil(x => x.To == 2); var edge12Directed = enumerator.IdDirected(); var edge12 = enumerator.Id; enumerator.MoveTo(2); enumerator.MoveNextUntil(x => x.To == 5); var edge25Directed = enumerator.IdDirected(); var edge25 = enumerator.Id; var vertex0 = routerDb.Network.GetVertex(0); var vertex1 = routerDb.Network.GetVertex(1); var vertex2 = routerDb.Network.GetVertex(2); var vertex5 = routerDb.Network.GetVertex(5); var line = new ReferencedLine() { Edges = new long[] { edge01Directed, edge12Directed, edge25Directed }, Vertices = new uint[] { 0, 1, 2, 5 }, StartLocation = routerDb.CreateRouterPointForVertex(0, Itinero.Osm.Vehicles.Vehicle.Car.Shortest()), EndLocation = routerDb.CreateRouterPointForVertex(5, Itinero.Osm.Vehicles.Vehicle.Car.Shortest()) }; var shape = line.GetCoordinates(routerDb); Assert.IsNotNull(shape); Assert.AreEqual(4, shape.Count); Assert.AreEqual(vertex0.Latitude, shape[0].Latitude); Assert.AreEqual(vertex0.Longitude, shape[0].Longitude); Assert.AreEqual(vertex1.Latitude, shape[1].Latitude); Assert.AreEqual(vertex1.Longitude, shape[1].Longitude); Assert.AreEqual(vertex2.Latitude, shape[2].Latitude); Assert.AreEqual(vertex2.Longitude, shape[2].Longitude); Assert.AreEqual(vertex5.Latitude, shape[3].Latitude); Assert.AreEqual(vertex5.Longitude, shape[3].Longitude); }
/// <summary> /// Builds a location referenced point for the vertex at the given start-index. /// </summary> /// <returns></returns> public LocationReferencePoint BuildLocationReferencePoint(ReferencedLine referencedLocation, int start, int end) { FormOfWay fow; FunctionalRoadClass frc; // get all coordinates along the sequence starting at 'start' and ending at 'end'. var coordinates = referencedLocation.GetCoordinates(this.Graph, start, end - start + 1); // create location reference point. var locationReferencePoint = new LocationReferencePoint(); locationReferencePoint.Coordinate = this.GetVertexLocation(referencedLocation.Vertices[start]); var tags = this.GetTags(referencedLocation.Edges[start].Tags); if (!this.TryMatching(tags, 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).Value; locationReferencePoint.DistanceToNext = (int)coordinates.Length().Value; FunctionalRoadClass?lowest = null; for (var edge = start; edge < end; edge++) { tags = this.GetTags(referencedLocation.Edges[edge].Tags); if (!this.TryMatching(tags, 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); }
/// <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); }
/// <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); }
/// <summary> /// Converts the referenced line location to features. /// </summary> public static List <Coordinate> GetCoordinates(this ReferencedLine referencedLine, RouterDb routerDb) { return(referencedLine.GetCoordinates(routerDb, 0, referencedLine.Vertices.Length)); }
/// <summary> /// Gets the negative offset location. /// </summary> public static Coordinate GetNegativeOffsetLocation(this ReferencedLine referencedLine, RouterDb routerDb) { var coordinates = referencedLine.GetCoordinates(routerDb); return(coordinates.GetPositionLocation(1f - (referencedLine.NegativeOffsetPercentage / 100.0f))); }
/// <summary> /// Encodes the given location. /// </summary> public static LineLocation Encode(ReferencedLine referencedLocation, Coder coder, EncodingSettings settings) { try { // Step – 1: Check validity of the location and offsets to be encoded. // validate connected and traversal. referencedLocation.ValidateConnected(coder); // validate offsets. referencedLocation.ValidateOffsets(); // validate for binary. referencedLocation.ValidateBinary(); // Step – 2 Adjust start and end node of the location to represent valid map nodes. referencedLocation.AdjustToValidPoints(coder); // keep a list of LR-point. var points = new List <int>(new int[] { 0, referencedLocation.Vertices.Length - 1 }); // Step – 3 Determine coverage of the location by a shortest-path. // Step – 4 Check whether the calculated shortest-path covers the location completely. // Go to step 5 if the location is not covered completely, go to step 7 if the location is covered. // Step – 5 Determine the position of a new intermediate location reference point so that the part of the // location between the start of the shortest-path calculation and the new intermediate is covered // completely by a shortest-path. // Step – 6 Go to step 3 and restart shortest path calculation between the new intermediate location reference // point and the end of the location. if (settings.VerifyShortestPath) { bool isOnShortestPath = false; while (!isOnShortestPath) { // keep on adding intermediates until all paths between intermediates are on shortest paths. isOnShortestPath = true; // loop over all LRP-pairs. for (var i = 0; i < points.Count - 1; i++) { var fromPoint = points[i]; var toPoint = points[i + 1]; var fromEdge = referencedLocation.Edges[fromPoint]; var toEdge = referencedLocation.Edges[toPoint - 1]; var edgeCount = toPoint - fromPoint; // calculate shortest path between their first and last edge. var pathResult = coder.Router.TryCalculateRaw(coder.Profile.Profile, coder.Router.GetDefaultWeightHandler(coder.Profile.Profile), fromEdge, toEdge, coder.Profile.RoutingSettings); if (pathResult.IsError) { try { coder.Profile.RoutingSettings.SetMaxSearch(coder.Profile.Profile.FullName, float.MaxValue); pathResult = coder.Router.TryCalculateRaw(coder.Profile.Profile, coder.Router.GetDefaultWeightHandler(coder.Profile.Profile), fromEdge, toEdge, coder.Profile.RoutingSettings); if (pathResult.IsError) { throw new Exception("No path found between two edges of the line location."); } } catch { throw; } finally { coder.Profile.RoutingSettings.SetMaxSearch(coder.Profile.Profile.FullName, coder.Profile.MaxSearch); } } var path = pathResult.Value; var edges = new List <long>(); while (path.From != null) { edges.Add(path.Edge); path = path.From; } edges.Reverse(); // calculate converage. var splitAt = -1; for (var j = 0; j < edges.Count; j++) { var locationEdgeIdx = j + fromPoint; if (locationEdgeIdx >= referencedLocation.Edges.Length || edges[j] != referencedLocation.Edges[locationEdgeIdx]) { splitAt = j + fromPoint + 1; break; } } // split if needed. if (splitAt != -1) { points.Add(splitAt); points.Sort(); isOnShortestPath = false; break; } } } } // Step – 7 Concatenate the calculated shortest-paths for a complete coverage of the location and form an // ordered list of location reference points (from the start to the end of the location). // Step – 8 Check validity of the location reference path. If the location reference path is invalid then go // to step 9, if the location reference path is valid then go to step 10. // Step – 9 Add a sufficient number of additional intermediate location reference points if the distance // between two location reference points exceeds the maximum distance. Remove the start/end LR-point // if the positive/negative offset value exceeds the length of the corresponding path. referencedLocation.AdjustToValidDistance(coder, points); // Step – 10 Create physical representation of the location reference. var coordinates = referencedLocation.GetCoordinates(coder.Router.Db); var length = coordinates.Length(); // 3: The actual encoding now! // initialize location. var location = new LineLocation(); // build lrp's. var locationReferencePoints = new List <LocationReferencePoint>(); for (var idx = 0; idx < points.Count - 1; idx++) { locationReferencePoints.Add(referencedLocation.BuildLocationReferencePoint(coder, points[idx], points[idx + 1])); } locationReferencePoints.Add(referencedLocation.BuildLocationReferencePointLast( coder, points[points.Count - 2])); // build location. location.First = locationReferencePoints[0]; location.Intermediate = new LocationReferencePoint[locationReferencePoints.Count - 2]; for (var idx = 1; idx < locationReferencePoints.Count - 1; idx++) { location.Intermediate[idx - 1] = locationReferencePoints[idx]; } location.Last = locationReferencePoints[locationReferencePoints.Count - 1]; // set offsets. location.PositiveOffsetPercentage = referencedLocation.PositiveOffsetPercentage; location.NegativeOffsetPercentage = referencedLocation.NegativeOffsetPercentage; return(location); } catch (ReferencedEncodingException) { // rethrow referenced encoding exception. throw; } catch (Exception ex) { // unhandled exception! throw new ReferencedEncodingException(referencedLocation, string.Format("Unhandled exception during ReferencedLineEncoder: {0}", ex.ToString()), ex); } }
public void TestReferencedLineGetCoordinates1() { var routerDb = new RouterDb(); routerDb.LoadTestNetwork( System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream( "OpenLR.Test.test_data.networks.network1.geojson")); var line = new ReferencedLine() { Edges = new long[] { 1 }, Vertices = new uint[] { 0, 1 }, StartLocation = new RouterPoint(0, 0, 0, 0), EndLocation = new RouterPoint(1, 1, 0, ushort.MaxValue) }; var shape = line.GetCoordinates(routerDb); Assert.IsNotNull(shape); Assert.AreEqual(2, shape.Count); var vertex0 = routerDb.Network.GetVertex(0); Assert.AreEqual(vertex0.Latitude, shape[0].Latitude); Assert.AreEqual(vertex0.Longitude, shape[0].Longitude); var vertex1 = routerDb.Network.GetVertex(1); Assert.AreEqual(vertex1.Latitude, shape[1].Latitude); Assert.AreEqual(vertex1.Longitude, shape[1].Longitude); line = new ReferencedLine() { Edges = new long[] { 1 }, Vertices = new uint[] { Itinero.Constants.NO_VERTEX, 1 }, StartLocation = new RouterPoint(0, 0, 0, (ushort)(ushort.MaxValue * 0.25)), EndLocation = new RouterPoint(1, 1, 0, ushort.MaxValue) }; shape = line.GetCoordinates(routerDb); Assert.IsNotNull(shape); Assert.AreEqual(2, shape.Count); var resolvedLocation = line.StartLocation.LocationOnNetwork(routerDb); Assert.AreEqual(resolvedLocation.Latitude, shape[0].Latitude); Assert.AreEqual(resolvedLocation.Longitude, shape[0].Longitude); Assert.AreEqual(vertex1.Latitude, shape[1].Latitude); Assert.AreEqual(vertex1.Longitude, shape[1].Longitude); line = new ReferencedLine() { Edges = new long[] { 1 }, Vertices = new uint[] { Itinero.Constants.NO_VERTEX, 1 }, StartLocation = new RouterPoint(0, 0, 0, 0), EndLocation = new RouterPoint(1, 1, 0, (ushort)(ushort.MaxValue * 0.75)) }; shape = line.GetCoordinates(routerDb); Assert.IsNotNull(shape); Assert.AreEqual(2, shape.Count); Assert.AreEqual(vertex0.Latitude, shape[0].Latitude); Assert.AreEqual(vertex0.Longitude, shape[0].Longitude); resolvedLocation = line.EndLocation.LocationOnNetwork(routerDb); Assert.AreEqual(resolvedLocation.Latitude, shape[1].Latitude); Assert.AreEqual(resolvedLocation.Longitude, shape[1].Longitude); line = new ReferencedLine() { Edges = new long[] { 1 }, Vertices = new uint[] { Itinero.Constants.NO_VERTEX, 1 }, StartLocation = new RouterPoint(0, 0, 0, (ushort)(ushort.MaxValue * 0.25)), EndLocation = new RouterPoint(1, 1, 0, (ushort)(ushort.MaxValue * 0.75)) }; shape = line.GetCoordinates(routerDb); Assert.IsNotNull(shape); Assert.AreEqual(2, shape.Count); resolvedLocation = line.StartLocation.LocationOnNetwork(routerDb); Assert.AreEqual(resolvedLocation.Latitude, shape[0].Latitude); Assert.AreEqual(resolvedLocation.Longitude, shape[0].Longitude); resolvedLocation = line.EndLocation.LocationOnNetwork(routerDb); Assert.AreEqual(resolvedLocation.Latitude, shape[1].Latitude); Assert.AreEqual(resolvedLocation.Longitude, shape[1].Longitude); }