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]); } }