/// <summary> /// Adjusts the given location by inserting an intermediate LR-point at the point representing pointIdx. /// </summary> public void AdjustToValidDistance(ReferencedEncoderBase encoder, List <int> points, int start) { // 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 = this.GetCoordinates(encoder.Graph, vertexIdx1, count); var length = coordinates.Length().Value; 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 (encoder.IsVertexValid(this.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 = this.GetCoordinates(encoder.Graph, vertexIdx1, idx - vertexIdx1 + 1).Length(); if (lengthBefore.Value < 15000) { // not over! score = score + (1024 * (lengthBefore.Value / 15000)); } var lengthAfter = this.GetCoordinates(encoder.Graph, idx, count - idx).Length(); if (lengthAfter.Value < 15000) { // not over! score = score + (1024 * (lengthAfter.Value / 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. this.AdjustToValidDistance(encoder, points, start + 1); this.AdjustToValidDistance(encoder, points, start); } }
/// <summary> /// Validates if the location is connected. /// </summary> /// <returns></returns> public void ValidateConnected(ReferencedEncoderBase mainEncoder) { var edges = this.Edges; var vertices = this.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]; bool found = false; foreach (var edge in mainEncoder.Graph.GetEdges(from)) { if (edge.Key == to && edge.Value.Equals(edges[edgeIdx])) { // edge was found, is valid. found = true; 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 tags = mainEncoder.Graph.TagsIndex.Get(edges[edgeIdx].Tags); if (!mainEncoder.Vehicle.CanTraverse(tags)) { // oeps, cannot be traversed. throw new ArgumentOutOfRangeException(string.Format("Edge at index {0} cannot be traversed by vehicle {1}.", edgeIdx, mainEncoder.Vehicle.UniqueName)); } // check whether the edge can be traversed in the correct direction. var oneway = mainEncoder.Vehicle.IsOneWay(tags); var canMoveForward = (oneway == null) || (oneway.Value == edges[edgeIdx].Forward); 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, mainEncoder.Vehicle.UniqueName)); } } }
/// <summary> /// Creates a new dynamic graph encoder. /// </summary> /// <param name="mainEncoder"></param> /// <param name="rawEncoder"></param> public ReferencedEncoder(ReferencedEncoderBase mainEncoder, OpenLR.Encoding.LocationEncoder <TLocation> rawEncoder) : base(rawEncoder) { _mainEncoder = mainEncoder; }
/// <summary> /// Creates a point along line referenced encoder. /// </summary> /// <param name="mainEncoder"></param> /// <param name="rawEncoder"></param> public ReferencedPointAlongLineEncoder(ReferencedEncoderBase mainEncoder, OpenLR.Encoding.LocationEncoder <PointAlongLineLocation> rawEncoder) : base(mainEncoder, rawEncoder) { }
///// <summary> ///// Adjusts this location to use valid LR-points. ///// </summary> //private bool TryAdjustToValidPoints(ReferencedEncoderBase encoder, long vertex1, long vertex2, // HashSet<long> excludeBackward, HashSet<long> excludeForward) //{ // var length = (float)this.Length(encoder).Value; // var positiveOffsetLength = (this.PositiveOffsetPercentage / 100) * length; // var negativeOffsetLength = (this.NegativeOffsetPercentage / 100) * length; // var exclude = new HashSet<long>(excludeForward); // if (!encoder.IsVertexValid(this.Vertices[0])) // { // from is not valid, try to find a valid point. // var pathToValid = encoder.FindValidVertexFor(this.Vertices[0], this.Edges[0], this.Vertices[1], // exclude, false); // // build edges list. // if (pathToValid != null) // { // no path found, just leave things as is. // var shortestRoute = encoder.FindShortestPath(this.Vertices[1], pathToValid.Vertex, false); // while (shortestRoute != null && !shortestRoute.Contains(this.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 = encoder.FindValidVertexFor(this.Vertices[0], this.Edges[0], this.Vertices[1], // exclude, false); // if (pathToValid == null) // { // a new path was not found. // break; // } // shortestRoute = encoder.FindShortestPath(this.Vertices[1], pathToValid.Vertex, false); // } // if (pathToValid != null) // { // no path found, just leave things as is. // var newVertices = pathToValid.ToArray().Reverse().ToList(); // var newEdges = new List<LiveEdge>(); // for (int idx = 0; idx < newVertices.Count - 1; idx++) // { // loop over edges. // var edge = newVertices[idx].Edge; // // Next OsmSharp version: use closest.Value.Value.Reverse()? // var reverseEdge = new LiveEdge(); // reverseEdge.Tags = edge.Tags; // reverseEdge.Forward = !edge.Forward; // reverseEdge.Distance = edge.Distance; // edge = reverseEdge; // newEdges.Add(edge); // } // // create new location. // var edgesArray = new LiveEdge[newEdges.Count + this.Edges.Length]; // newEdges.CopyTo(0, edgesArray, 0, newEdges.Count); // this.Edges.CopyTo(0, edgesArray, newEdges.Count, this.Edges.Length); // var vertexArray = new long[newVertices.Count - 1 + this.Vertices.Length]; // newVertices.ConvertAll(x => (long)x.Vertex).CopyTo(0, vertexArray, 0, newVertices.Count - 1); // this.Vertices.CopyTo(0, vertexArray, newVertices.Count - 1, this.Vertices.Length); // this.Edges = edgesArray; // this.Vertices = vertexArray; // // adjust offset length. // var newLength = (float)this.Length(encoder).Value; // positiveOffsetLength = positiveOffsetLength + (newLength - length); // length = newLength; // } // } // } // exclude = new HashSet<long>(excludeBackward); // if (!encoder.IsVertexValid(this.Vertices[this.Vertices.Length - 1])) // { // from is not valid, try to find a valid point. // var vertexCount = this.Vertices.Length; // var pathToValid = encoder.FindValidVertexFor(this.Vertices[vertexCount - 1], this.Edges[ // this.Edges.Length - 1].ToReverse(), this.Vertices[vertexCount - 2], exclude, true); // // build edges list. // if (pathToValid != null) // { // no path found, just leave things as is. // var shortestRoute = encoder.FindShortestPath(this.Vertices[vertexCount - 2], pathToValid.Vertex, true); // while (shortestRoute != null && !shortestRoute.Contains(this.Vertices[vertexCount - 1])) // { // 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 = encoder.FindValidVertexFor(this.Vertices[vertexCount - 1], this.Edges[ // this.Edges.Length - 1].ToReverse(), this.Vertices[vertexCount - 2], exclude, true); // if (pathToValid == null) // { // a new path was not found. // break; // } // shortestRoute = encoder.FindShortestPath(this.Vertices[vertexCount - 2], pathToValid.Vertex, true); // } // if (pathToValid != null) // { // no path found, just leave things as is. // var newVertices = pathToValid.ToArray().ToList(); // var newEdges = new List<LiveEdge>(); // for (int idx = 1; idx < newVertices.Count; idx++) // { // loop over edges. // var edge = newVertices[idx].Edge; // newEdges.Add(edge); // } // // create new location. // var edgesArray = new LiveEdge[newEdges.Count + this.Edges.Length]; // this.Edges.CopyTo(0, edgesArray, 0, this.Edges.Length); // newEdges.CopyTo(0, edgesArray, this.Edges.Length, newEdges.Count); // var vertexArray = new long[newVertices.Count - 1 + this.Vertices.Length]; // this.Vertices.CopyTo(0, vertexArray, 0, this.Vertices.Length); // newVertices.ConvertAll(x => (long)x.Vertex).CopyTo(1, vertexArray, this.Vertices.Length, newVertices.Count - 1); // this.Edges = edgesArray; // this.Vertices = vertexArray; // // adjust offset length. // var newLength = (float)this.Length(encoder).Value; // negativeOffsetLength = negativeOffsetLength + (newLength - length); // length = newLength; // } // } // } // // update offset percentags. // this.PositiveOffsetPercentage = (float)((positiveOffsetLength / length) * 100.0); // this.NegativeOffsetPercentage = (float)((negativeOffsetLength / length) * 100.0); // // fill shapes. // this.EdgeShapes = new GeoCoordinateSimple[this.Edges.Length][]; // for (int i = 0; i < this.Edges.Length; i++) // { // this.EdgeShapes[i] = encoder.Graph.GetEdgeShape( // this.Vertices[i], this.Vertices[i + 1]); // } // return true; //} /// <summary> /// Adjusts this location by inserting intermediate LR-points if needed. /// </summary> /// public void AdjustToValidDistances(ReferencedEncoderBase encoder, List <int> points) { this.AdjustToValidDistance(encoder, points, 0); }
private bool TryAdjustToValidPointForwards(ReferencedEncoderBase encoder, long vertex1, long vertex2, HashSet <long> exclude) { var length = (float)this.Length(encoder).Value; var negativeOffsetLength = (this.NegativeOffsetPercentage / 100) * length; exclude = new HashSet <long>(exclude); foreach (var vertex in this.Vertices) { exclude.Add(vertex); } if (!encoder.IsVertexValid(this.Vertices[this.Vertices.Length - 1])) { // from is not valid, try to find a valid point. var vertexCount = this.Vertices.Length; var pathToValid = encoder.FindValidVertexFor(this.Vertices[vertexCount - 1], this.Edges[ this.Edges.Length - 1].ToReverse(), this.Vertices[vertexCount - 2], exclude, true); // build edges list. if (pathToValid != null) { // no path found, just leave things as is. var shortestRoute = encoder.FindShortestPath(this.Vertices[vertexCount - 2], pathToValid.Vertex, true); while (shortestRoute != null && !shortestRoute.Contains(this.Vertices[vertexCount - 1])) { // 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 = encoder.FindValidVertexFor(this.Vertices[vertexCount - 1], this.Edges[ this.Edges.Length - 1].ToReverse(), this.Vertices[vertexCount - 2], exclude, true); if (pathToValid == null) { // a new path was not found. break; } shortestRoute = encoder.FindShortestPath(this.Vertices[vertexCount - 2], pathToValid.Vertex, true); } if (pathToValid != null) { // no path found, just leave things as is. var newVertices = pathToValid.ToArray().ToList(); var newEdges = new List <LiveEdge>(); for (int idx = 1; idx < newVertices.Count; idx++) { // loop over edges. var edge = newVertices[idx].Edge; newEdges.Add(edge); } // create new location. var edgesArray = new LiveEdge[newEdges.Count + this.Edges.Length]; this.Edges.CopyTo(0, edgesArray, 0, this.Edges.Length); newEdges.CopyTo(0, edgesArray, this.Edges.Length, newEdges.Count); var vertexArray = new long[newVertices.Count - 1 + this.Vertices.Length]; this.Vertices.CopyTo(0, vertexArray, 0, this.Vertices.Length); newVertices.ConvertAll(x => (long)x.Vertex).CopyTo(1, vertexArray, this.Vertices.Length, newVertices.Count - 1); this.Edges = edgesArray; this.Vertices = vertexArray; // adjust offset length. var newLength = (float)this.Length(encoder).Value; negativeOffsetLength = negativeOffsetLength + (newLength - length); length = newLength; } else { // no valid path was found. return(false); } } else { // no valid path was found. return(false); } } // update offset percentage this.NegativeOffsetPercentage = (float)((negativeOffsetLength / length) * 100.0); return(true); }
/// <summary> /// Adjusts this location to use valid LR-points. /// </summary> public void AdjustToValidPoints(ReferencedEncoderBase encoder) { if (this.Vertices.Length <= 1) { throw new ArgumentException("Cannot adjust a line location with only one vertex."); } var vertex1Valid = encoder.IsVertexValid(this.Vertices[0]); var vertex2Valid = encoder.IsVertexValid(this.Vertices[this.Vertices.Length - 1]); if (vertex1Valid && vertex2Valid) { // already valid. return; } if (this.Vertices.Length > 2) { return; } // line was already adjusted. var vertex1 = this.Vertices[0]; var vertex2 = this.Vertices[1]; if (!encoder.IsOnShortestPath(this.Vertices[0], this.Vertices[this.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 = this.GetVerticesSet(); while (true) { // search backward. var workingCopy = this.Clone() as ReferencedLine; if (!workingCopy.TryAdjustToValidPointBackwards(encoder, 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(encoder, vertex1, vertex2, forwardExcludeSet)) { // no more forward options for the current backward. break; } // check valid. if (encoder.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 (encoder.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. this.Edges = validCopy.Edges; this.Vertices = validCopy.Vertices; this.NegativeOffsetPercentage = validCopy.NegativeOffsetPercentage; this.PositiveOffsetPercentage = validCopy.PositiveOffsetPercentage; // fill shapes. this.EdgeShapes = new GeoCoordinateSimple[this.Edges.Length][]; for (int i = 0; i < this.Edges.Length; i++) { this.EdgeShapes[i] = encoder.Graph.GetEdgeShape( this.Vertices[i], this.Vertices[i + 1]); } }
/// <summary> /// Validates the location for encoding in binary format. /// </summary> public void ValidateBinary(ReferencedEncoderBase mainEncoder) { }
/// <summary> /// Validates the offsets. /// </summary> public void ValidateOffsets(ReferencedEncoderBase mainEncoder) { }