/// <summary> /// Starts pre-processing all nodes. /// </summary> public void Start() { // build the empty coordinate list. var emptyCoordinateList = new GeoCoordinateSimple[0]; var verticesList = new HashSet <uint>(); // initialize status variables. uint nextToProcess = 0; uint nextPosition = 0; // search edge until a real node. double latestProgress = 0; while (nextToProcess < _graph.VertexCount) { // keep looping until all vertices have been processed. // select a new vertext to select. var vertexToProcess = nextToProcess; var edges = _graph.GetEdges(vertexToProcess); if (edges.Length == 2) { // find one of the neighbours that is usefull. vertexToProcess = edges[0].Key; edges = _graph.GetEdges(vertexToProcess); verticesList.Clear(); verticesList.Add(vertexToProcess); while (edges.Length == 2) { // keep looping until there is a vertex that is usefull. vertexToProcess = edges[0].Key; if (verticesList.Contains(vertexToProcess)) { // take the other vertex. vertexToProcess = edges[1].Key; if (verticesList.Contains(vertexToProcess)) { // an island was detected with only vertices having two neighbours. // TODO: find a way to handle this! edges = new KeyValuePair <uint, LiveEdge> [0]; break; } } verticesList.Add(vertexToProcess); edges = _graph.GetEdges(vertexToProcess); } } if (edges.Length > 0) { // ok, the vertex was not already processed. nextPosition++; var oldEdges = edges.Clone() as KeyValuePair <uint, LiveEdge>[]; var ignoreList = new HashSet <uint>(); foreach (var oldEdge in oldEdges) { if (ignoreList.Contains(oldEdge.Key)) { // ignore this edge: already removed in a previous iteration. break; } // don't re-process edges that already have coordinates. GeoCoordinateSimple[] oldEdgeValueCoordinates; _graph.GetEdgeShape(vertexToProcess, oldEdge.Key, out oldEdgeValueCoordinates); if (oldEdgeValueCoordinates != null) { // this edge has already been processed. break; } // STEP1: Build list of vertices that are only for form. // set current/previous. var distance = oldEdge.Value.Distance; var current = oldEdge.Key; var previous = vertexToProcess; // build list of vertices. var vertices = new List <uint>(); vertices.Add(previous); vertices.Add(current); // get next edges list. var nextEdges = _graph.GetEdges(current); while (nextEdges.Length == 2) { // ok the current vertex can be removed. var nextEdge = nextEdges[0]; if (nextEdge.Key == previous) { // it's the other edge! nextEdge = nextEdges[1]; } // compare edges. if (nextEdge.Value.Forward != oldEdge.Value.Forward || nextEdge.Value.Tags != oldEdge.Value.Tags) { // oeps, edges are different! break; } // check for intermediates. GeoCoordinateSimple[] nextEdgeValueCoordinates; _graph.GetEdgeShape(current, nextEdge.Key, out nextEdgeValueCoordinates); if (nextEdgeValueCoordinates != null) { // oeps, there are intermediates already, this can occur when two osm-ways are drawn on top of eachother. break; } // add distance. distance = distance + nextEdge.Value.Distance; // set current/previous. previous = current; current = nextEdge.Key; vertices.Add(current); // get next edges. nextEdges = _graph.GetEdges(current); } // check if the edge contains intermediate points. if (vertices.Count == 2) { // no intermediate points: add the empty coordinate list. var oldEdgeValue = oldEdge.Value; // keep edges that already have intermediates. GeoCoordinateSimple[] edgeToKeepValueCoordinates = null; var edgesToKeep = new List <Tuple <uint, LiveEdge, GeoCoordinateSimple[]> >(); foreach (var edgeToKeep in _graph.GetEdges(vertexToProcess)) { edgeToKeepValueCoordinates = null; if (edgeToKeep.Key == oldEdge.Key && _graph.GetEdgeShape(vertexToProcess, edgeToKeep.Key, out edgeToKeepValueCoordinates)) { edgesToKeep.Add(new Tuple <uint, LiveEdge, GeoCoordinateSimple[]>( edgeToKeep.Key, edgeToKeep.Value, edgeToKeepValueCoordinates)); } } // delete olds arcs. _graph.RemoveEdge(vertexToProcess, oldEdge.Key); // add new arc. if (oldEdgeValue.Forward) { _graph.AddEdge(vertexToProcess, oldEdge.Key, oldEdgeValue, null); } else { _graph.AddEdge(vertexToProcess, oldEdge.Key, (LiveEdge)oldEdgeValue.Reverse(), null); } // add edges to keep. foreach (var edgeToKeep in edgesToKeep) { _graph.AddEdge(vertexToProcess, edgeToKeep.Item1, edgeToKeep.Item2, edgeToKeep.Item3); } } else { // intermediate points: build array. // STEP2: Build array of coordinates. var coordinates = new GeoCoordinateSimple[vertices.Count - 2]; float latitude, longitude; for (int idx = 1; idx < vertices.Count - 1; idx++) { _graph.GetVertex(vertices[idx], out latitude, out longitude); coordinates[idx - 1] = new GeoCoordinateSimple() { Latitude = latitude, Longitude = longitude }; } // STEP3: Remove all unneeded edges. _graph.RemoveEdge(vertices[0], vertices[1]); // remove first edge. for (int idx = 1; idx < vertices.Count - 1; idx++) { // delete all intermidiate arcs. _graph.RemoveEdges(vertices[idx]); } _graph.RemoveEdge(vertices[vertices.Count - 1], vertices[vertices.Count - 2]); // remove last edge. if (vertices[0] == vertices[vertices.Count - 1]) { // also remove outgoing edge. ignoreList.Add(vertices[vertices.Count - 2]); // make sure this arc is ignored in next iteration. } // STEP4: Add new edge. if (oldEdge.Value.Forward) { _graph.AddEdge(vertices[0], vertices[vertices.Count - 1], new LiveEdge() { Forward = oldEdge.Value.Forward, Tags = oldEdge.Value.Tags, Distance = distance }, coordinates, this); } else { var reverse = new GeoCoordinateSimple[coordinates.Length]; coordinates.CopyToReverse(reverse, 0); _graph.AddEdge(vertices[vertices.Count - 1], vertices[0], new LiveEdge() { Forward = !oldEdge.Value.Forward, Tags = oldEdge.Value.Tags, Distance = distance }, reverse, this); } } } } // move to the next position. nextToProcess++; // report progress. float progress = (float)System.Math.Round((((double)nextToProcess / (double)_graph.VertexCount) * 100)); if (progress != latestProgress) { OsmSharp.Logging.Log.TraceEvent("LiveEdgePreprocessor", TraceEventType.Information, "Removing edges... {0}%", progress); latestProgress = progress; } } // compress the graph. this.CompressGraph(); }
/// <summary> /// Removes all arcs starting at vertex. /// </summary> /// <param name="vertex"></param> public void RemoveEdges(uint vertex) { _graph.RemoveEdges(vertex); }