/// <summary> /// Adds an edge. /// </summary> /// <param name="forward"></param> /// <param name="from"></param> /// <param name="to"></param> /// <param name="tags"></param> private bool AddRoadEdge(TagsCollection tags, bool forward, uint from, uint to) { float latitude; float longitude; GeoCoordinate fromCoordinate = null; if (_dynamicGraph.GetVertex(from, out latitude, out longitude)) { // fromCoordinate = new GeoCoordinate(latitude, longitude); } GeoCoordinate toCoordinate = null; if (_dynamicGraph.GetVertex(to, out latitude, out longitude)) { // toCoordinate = new GeoCoordinate(latitude, longitude); } if (fromCoordinate != null && toCoordinate != null) { // calculate the edge data. TEdgeData edgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, forward, fromCoordinate, toCoordinate); _dynamicGraph.AddArc(from, to, edgeData, _edgeComparer); } return(false); }
/// <summary> /// Rebuilds the vertex index. /// </summary> public void RebuildVertexIndex() { _vertexIndex = new QuadTree <GeoCoordinate, uint>(); for (uint vertex = 0; vertex <= _graph.VertexCount; vertex++) { float latitude, longitude; if (_graph.GetVertex(vertex, out latitude, out longitude)) { _vertexIndex.Add(new GeoCoordinate(latitude, longitude), vertex); } } }
/// <summary> /// Creates a new osm memory router data source. /// </summary> /// <param name="graph"></param> /// <param name="tagsIndex"></param> /// <exception cref="ArgumentNullException"></exception> public DynamicGraphRouterDataSource(IDynamicGraph <TEdgeData> graph, ITagsIndex tagsIndex) { if (graph == null) { throw new ArgumentNullException("graph"); } if (tagsIndex == null) { throw new ArgumentNullException("tagsIndex"); } _graph = graph; _vertexIndex = new QuadTree <GeoCoordinate, uint>(); _tagsIndex = tagsIndex; _supportedVehicles = new HashSet <Vehicle>(); // add the current graph's vertices to the vertex index. for (uint newVertexId = 1; newVertexId < graph.VertexCount + 1; newVertexId++) { // add to the CHRegions. float latitude, longitude; graph.GetVertex(newVertexId, out latitude, out longitude); _vertexIndex.Add(new GeoCoordinate(latitude, longitude), newVertexId); } }
public void TestLiveEdgeDynamicGraphVertex() { IDynamicGraph <LiveEdge> graph = this.CreateGraph(); uint vertex = graph.AddVertex(51, 4); float latitude, longitude; graph.GetVertex(vertex, out latitude, out longitude); Assert.AreEqual(51, latitude); Assert.AreEqual(4, longitude); KeyValuePair <uint, LiveEdge>[] arcs = graph.GetArcs(vertex); Assert.AreEqual(0, arcs.Length); }
public void TestLiveEdgeDynamicGraphVertex10000() { IDynamicGraph <LiveEdge> graph = this.CreateGraph(); int count = 10000; while (count > 0) { uint vertex = graph.AddVertex(51, 4); float latitude, longitude; graph.GetVertex(vertex, out latitude, out longitude); Assert.AreEqual(51, latitude); Assert.AreEqual(4, longitude); KeyValuePair <uint, LiveEdge>[] arcs = graph.GetArcs(vertex); Assert.AreEqual(0, arcs.Length); count--; } Assert.AreEqual((uint)10000, graph.VertexCount); }
/// <summary> /// Returns true if a given vertex is in the graph. /// </summary> /// <param name="id"></param> /// <param name="latitude"></param> /// <param name="longitude"></param> /// <returns></returns> public bool GetVertex(uint id, out float latitude, out float longitude) { return(_graph.GetVertex(id, out latitude, out longitude)); }
/// <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> /// Returns a topologically sorted version of the given graph. /// </summary> /// <param name="graph"></param> /// <returns></returns> public static IDynamicGraph <CHEdgeData> SortGraph(IDynamicGraph <CHEdgeData> graph) { // also add all downward edges. graph.AddDownwardEdges(); // sort the topologically ordered vertices into bins representing a certain height range. List <uint>[] heightBins = new List <uint> [1000]; foreach (var vertexDepth in new CHDepthFirstEnumerator(graph)) { // enumerates all vertixes depth-first. int binIdx = (int)(vertexDepth.Depth / HeightBinSize); if (heightBins.Length < binIdx) { // resize bin array if needed. Array.Resize(ref heightBins, System.Math.Max(heightBins.Length + 1000, binIdx + 1)); } // add to the current bin. List <uint> bin = heightBins[binIdx]; if (bin == null) { // create new bin. bin = new List <uint>(); heightBins[binIdx] = bin; } bin.Add(vertexDepth.VertexId); } // temp test. MemoryDynamicGraph <CHEdgeData> sortedGraph = new MemoryDynamicGraph <CHEdgeData>(); Dictionary <uint, uint> currentBinIds = new Dictionary <uint, uint>(); uint newVertexId; for (int idx = 0; idx < heightBins.Length; idx++) { List <uint> bin = heightBins[idx]; if (bin != null) { // translate ids. // fill current bin ids and add vertices to the new graph. foreach (uint binVertexId in bin) { float latitude, longitude; graph.GetVertex(binVertexId, out latitude, out longitude); newVertexId = sortedGraph.AddVertex(latitude, longitude); currentBinIds.Add(binVertexId, newVertexId); // add to the current bin index. } } } // rebuild the CH graph based on the new ordering and build the CHRegions. newVertexId = 0; for (int idx = 0; idx < heightBins.Length; idx++) { List <uint> bin = heightBins[idx]; if (bin != null) { // translate ids. // fill current bin ids and add vertices to the new graph. //foreach (uint binVertexId in bin) //{ // float latitude, longitude; // graph.GetVertex(binVertexId, out latitude, out longitude); // newVertexId = sortedGraph.AddVertex(latitude, longitude); // currentBinIds.Add(binVertexId, newVertexId); // add to the current bin index. //} foreach (uint binVertexId in bin) { currentBinIds.TryGetValue(binVertexId, out newVertexId); // get the higher arcs and convert their ids. KeyValuePair <uint, CHEdgeData>[] arcs = graph.GetArcsHigher(binVertexId); foreach (KeyValuePair <uint, CHEdgeData> arc in arcs) { // get target vertex. uint nextVertexArcId = CHEdgeDataDataSourceSerializer.SearchVertex(arc.Key, currentBinIds, heightBins); // convert edge. CHEdgeData newEdge = new CHEdgeData(); newEdge.Direction = arc.Value.Direction; if (arc.Value.HasContractedVertex) { // contracted info. newEdge.ContractedVertexId = CHEdgeDataDataSourceSerializer.SearchVertex(arc.Value.ContractedVertexId, currentBinIds, heightBins); } else { // no contracted info. newEdge.ContractedVertexId = 0; } newEdge.Tags = arc.Value.Tags; newEdge.Weight = arc.Value.Weight; sortedGraph.AddArc(newVertexId, nextVertexArcId, newEdge, null); } } } } return(sortedGraph); }
/// <summary> /// Does the v2 serialization. /// </summary> /// <param name="stream"></param> /// <param name="graph"></param> /// <returns></returns> protected override void DoSerialize(LimitedStream stream, DynamicGraphRouterDataSource <CHEdgeData> graph) { // sort the graph. IDynamicGraph <CHEdgeData> sortedGraph = CHEdgeDataDataSourceSerializer.SortGraph(graph); // create the regions. SortedDictionary <ulong, List <uint> > regions = new SortedDictionary <ulong, List <uint> >(); for (uint newVertexId = 1; newVertexId < sortedGraph.VertexCount + 1; newVertexId++) { // add to the CHRegions. float latitude, longitude; sortedGraph.GetVertex(newVertexId, out latitude, out longitude); Tile tile = Tile.CreateAroundLocation(new GeoCoordinate( latitude, longitude), RegionZoom); List <uint> regionVertices; if (!regions.TryGetValue(tile.Id, out regionVertices)) { regionVertices = new List <uint>(); regions.Add(tile.Id, regionVertices); } regionVertices.Add(newVertexId); } // serialize the sorted graph. // [START_OF_BLOCKS][[SIZE_OF_REGION_INDEX][REGION_INDEX][REGIONS]][[SIZE_OF_BLOCK_INDEX][BLOCK_INDEX][BLOCKS]] // STRART_OF_BLOCKS: 4bytes // SIZE_OF_REGION_INDEX: 4bytes // REGION_INDEX: see SIZE_OF_REGION_INDEX // REGIONS: see START_OF_BLOCKS - 4bytes // SIZE_OF_BLOCK_INDEX: 4bytes // BLOCK_INDEX: see SIZE_OF_BLOCK_INDEX. // BLOCKS: from START_OF_BLOCKS + 4bytes + SIZE_OF_BLOCKS_INDEX until END. // serialize regions and build their index. CHVertexRegionIndex chRegionIndex = new CHVertexRegionIndex(); chRegionIndex.LocationIndex = new int[regions.Count]; chRegionIndex.RegionIds = new ulong[regions.Count]; var memoryStream = new MemoryStream(); int regionIdx = 0; foreach (KeyValuePair <ulong, List <uint> > region in regions) { // serialize. CHVertexRegion chRegion = new CHVertexRegion(); chRegion.Vertices = region.Value.ToArray(); _runtimeTypeModel.Serialize(memoryStream, chRegion); // set index. chRegionIndex.LocationIndex[regionIdx] = (int)memoryStream.Position; chRegionIndex.RegionIds[regionIdx] = region.Key; regionIdx++; } stream.Seek(8, SeekOrigin.Begin); // move to beginning of [REGION_INDEX] _runtimeTypeModel.Serialize(stream, chRegionIndex); // write region index. int sizeRegionIndex = (int)(stream.Position - 8); // now at beginning of [REGIONS] memoryStream.Seek(0, SeekOrigin.Begin); memoryStream.WriteTo(stream); // write regions. memoryStream.Dispose(); int startOfBlocks = (int)stream.Position; // now at beginning of [SIZE_OF_BLOCK_INDEX] stream.Seek(0, SeekOrigin.Begin); // move to beginning stream.Write(BitConverter.GetBytes(startOfBlocks), 0, 4); // write start position of blocks. Now at [SIZE_OF_REGION_INDEX] stream.Write(BitConverter.GetBytes(sizeRegionIndex), 0, 4); // write size of blocks index. // serialize the blocks and build their index. memoryStream = new MemoryStream(); List <int> blockLocations = new List <int>(); uint vertexId = 1; while (vertexId < sortedGraph.VertexCount) { uint blockId = vertexId; List <CHArc> blockArcs = new List <CHArc>(); List <CHVertex> blockVertices = new List <CHVertex>(); while (vertexId < blockId + BlockVertexSize && vertexId < sortedGraph.VertexCount + 1) { // create this block. CHVertex chVertex = new CHVertex(); float latitude, longitude; sortedGraph.GetVertex(vertexId, out latitude, out longitude); chVertex.Latitude = latitude; chVertex.Longitude = longitude; chVertex.ArcIndex = (ushort)(blockArcs.Count); foreach (KeyValuePair <uint, CHEdgeData> sortedArc in sortedGraph.GetArcs(vertexId)) { CHArc chArc = new CHArc(); chArc.TargetId = sortedArc.Key; chArc.ShortcutId = sortedArc.Value.ContractedVertexId; chArc.Weight = sortedArc.Value.Weight; chArc.Direction = sortedArc.Value.Direction; blockArcs.Add(chArc); } chVertex.ArcCount = (ushort)(blockArcs.Count - chVertex.ArcIndex); blockVertices.Add(chVertex); vertexId++; // move to the next vertex. } // create block. CHBlock block = new CHBlock(); block.Arcs = blockArcs.ToArray(); block.Vertices = blockVertices.ToArray(); // TODO: get rid of the list and create an array to begin with. // write blocks. _runtimeTypeModel.Serialize(memoryStream, block); blockLocations.Add((int)memoryStream.Position); } CHBlockIndex blockIndex = new CHBlockIndex(); blockIndex.LocationIndex = blockLocations.ToArray(); stream.Seek(startOfBlocks + 4, SeekOrigin.Begin); // move to beginning of [BLOCK_INDEX] _runtimeTypeModel.Serialize(stream, blockIndex); // write region index. int sizeBlockIndex = (int)(stream.Position - (startOfBlocks + 4)); // now at beginning of [BLOCKS] memoryStream.Seek(0, SeekOrigin.Begin); memoryStream.WriteTo(stream); // write blocks. memoryStream.Dispose(); stream.Seek(startOfBlocks, SeekOrigin.Begin); // move to [SIZE_OF_BLOCK_INDEX] stream.Write(BitConverter.GetBytes(sizeBlockIndex), 0, 4); // write start position of blocks. Now at [SIZE_OF_REGION_INDEX] stream.Flush(); }