/// <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).ToList(); if (edges.Count == 2) { // find one of the neighbours that is usefull. vertexToProcess = edges[0].Neighbour; edges = _graph.GetEdges(vertexToProcess).ToList(); verticesList.Clear(); verticesList.Add(vertexToProcess); while (edges.Count == 2) { // keep looping until there is a vertex that is usefull. vertexToProcess = edges[0].Neighbour; if (verticesList.Contains(vertexToProcess)) { // take the other vertex. vertexToProcess = edges[1].Neighbour; if (verticesList.Contains(vertexToProcess)) { // an island was detected with only vertices having two neighbours. // TODO: find a way to handle this! edges = new List <Edge <Edge> >(0); break; } } verticesList.Add(vertexToProcess); edges = _graph.GetEdges(vertexToProcess).ToList(); } } if (edges.Count > 0) { // ok, the vertex was not already processed. nextPosition++; var oldEdges = new List <Edge <Edge> >(edges); var ignoreList = new HashSet <uint>(); foreach (var oldEdge in oldEdges) { if (ignoreList.Contains(oldEdge.Neighbour)) { // ignore this edge: already removed in a previous iteration. break; } // don't re-process edges that already have coordinates. ICoordinateCollection oldEdgeValueCoordinates; _graph.GetEdgeShape(vertexToProcess, oldEdge.Neighbour, 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.EdgeData.Distance; var current = oldEdge.Neighbour; 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).ToList(); while (nextEdges.Count == 2) { // ok the current vertex can be removed. var nextEdge = nextEdges[0]; if (nextEdge.Neighbour == previous) { // it's the other edge! nextEdge = nextEdges[1]; } // compare edges. if (nextEdge.EdgeData.Forward != oldEdge.EdgeData.Forward || nextEdge.EdgeData.Tags != oldEdge.EdgeData.Tags) { // oeps, edges are different! break; } // check for intermediates. ICoordinateCollection nextEdgeValueCoordinates; _graph.GetEdgeShape(current, nextEdge.Neighbour, 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.EdgeData.Distance; // set current/previous. previous = current; current = nextEdge.Neighbour; vertices.Add(current); // get next edges. nextEdges = _graph.GetEdges(current).ToList(); } // check if the edge contains intermediate points. if (vertices.Count == 2) { // no intermediate points: add the empty coordinate list. var oldEdgeValue = oldEdge.EdgeData; // keep edges that already have intermediates. ICoordinateCollection edgeToKeepValueCoordinates = null; var edgesToKeep = new List <Tuple <uint, Edge, ICoordinateCollection> >(); foreach (var edgeToKeep in _graph.GetEdges(vertexToProcess).ToList()) { edgeToKeepValueCoordinates = null; if (edgeToKeep.Neighbour == oldEdge.Neighbour && _graph.GetEdgeShape(vertexToProcess, edgeToKeep.Neighbour, out edgeToKeepValueCoordinates)) { edgesToKeep.Add(new Tuple <uint, Edge, ICoordinateCollection>( edgeToKeep.Neighbour, edgeToKeep.EdgeData, edgeToKeepValueCoordinates)); } } // delete olds arcs. _graph.RemoveEdge(vertexToProcess, oldEdge.Neighbour); // add new arc. if (oldEdgeValue.Forward) { _graph.AddEdge(vertexToProcess, oldEdge.Neighbour, oldEdgeValue, null); } else { _graph.AddEdge(vertexToProcess, oldEdge.Neighbour, (Edge)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.EdgeData.Forward) { _graph.AddEdge(vertices[0], vertices[vertices.Count - 1], new Edge() { Forward = oldEdge.EdgeData.Forward, Tags = oldEdge.EdgeData.Tags, Distance = distance }, new CoordinateArrayCollection <GeoCoordinateSimple>(coordinates)); } else { var reverse = new GeoCoordinateSimple[coordinates.Length]; coordinates.CopyToReverse(reverse, 0); _graph.AddEdge(vertices[vertices.Count - 1], vertices[0], new Edge() { Forward = !oldEdge.EdgeData.Forward, Tags = oldEdge.EdgeData.Tags, Distance = distance }, new CoordinateArrayCollection <GeoCoordinateSimple>(reverse)); } } } } // 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("Preprocessor", TraceEventType.Information, "Removing edges... {0}%", progress); latestProgress = progress; } } // compress the graph. this.CompressGraph(); }