/// <summary> /// Builds the reverse index for a directed graph. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <returns></returns> public static IDictionary <uint, List <uint> > BuildReverse <TEdgeData>(this GraphBase <TEdgeData> graph) where TEdgeData : struct, IGraphEdgeData { if (!graph.IsDirected) { throw new ArgumentException("Building a reverse index for a non-directed graph is not supported."); } var reverse = new Dictionary <uint, List <uint> >(); for (uint vertex = 1; vertex <= graph.VertexCount; vertex++) { foreach (var edge in graph.GetEdges(vertex)) { var to = edge.Neighbour; List <uint> neighbours; if (!reverse.TryGetValue(to, out neighbours)) { // create an entry here. neighbours = new List <uint>(); } neighbours.Add(vertex); reverse[to] = neighbours; // explicitly set again because this may be another kind of dictionary soon. } } return(reverse); }
/// <summary> /// Partions the vertices based on the pivot value. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="graph">The graph to sort.</param> /// <param name="n">The hilbert accuracy.</param> /// <param name="left">The first vertex to consider.</param> /// <param name="right">The last vertex to consider.</param> /// <return>The new left.</return> private static uint SortHilbertPartition <TEdgeData>(GraphBase <TEdgeData> graph, int n, uint left, uint right) where TEdgeData : struct, IGraphEdgeData { // get the pivot value. uint start = left; ulong pivotValue = graph.HilbertDistance(n, left); left++; while (true) { ulong leftValue = graph.HilbertDistance(n, left); while (left <= right && leftValue <= pivotValue) { // move the left to the first value bigger than pivot. left++; leftValue = graph.HilbertDistance(n, left); } ulong rightValue = graph.HilbertDistance(n, right); while (left <= right && rightValue > pivotValue) { // move the right to the first value smaller than pivot. right--; rightValue = graph.HilbertDistance(n, right); } if (left > right) { // we are done searching, left is to the right of right. // make sure the pivot value is where it is supposed to be. graph.Switch(start, left - 1); return(left); } // swith left<->right. graph.Switch(left, right); } }
/// <summary> /// Sorts the vertices in the given graph based on a hilbert curve. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static void BuildHilbertRank <TEdgeData>(this GraphBase <TEdgeData> graph, int n, HugeArrayBase <uint> ranks) where TEdgeData : struct, IGraphEdgeData { if (graph == null) { throw new ArgumentNullException("graph"); } if (graph.VertexCount != ranks.Length - 1) { throw new ArgumentException("Graph and ranks array must have equal sizes."); } for (uint i = 0; i <= graph.VertexCount; i++) { // fill with default data. ranks[i] = i; } if (graph.VertexCount == 1) { // just return the rank for the one vertex. ranks[0] = 0; ranks[1] = 1; } // sort the complete graph and keep the transformations. QuickSort.Sort((i) => graph.HilbertDistance(n, ranks[i]), (i, j) => { var temp = ranks[i]; ranks[i] = ranks[j]; ranks[j] = temp; }, 1, graph.VertexCount); }
/// <summary> /// Sorts the vertices in the given graph based on a hilbert curve using the default step count. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static HugeArrayBase <uint> BuildHilbertRank <TEdgeData>(this GraphBase <TEdgeData> graph) where TEdgeData : struct, IGraphEdgeData { var ranks = new HugeArray <uint>(graph.VertexCount + 1); graph.BuildHilbertRank(GraphExtensions.DefaultHilbertSteps, ranks); return(ranks); }
/// <summary> /// Sorts the vertices in the given graph based on a hilbert curve using the default step count. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static HugeArrayBase <uint> BuildHilbertRank <TEdgeData>(this GraphBase <TEdgeData> graph, int n) where TEdgeData : struct, IGraphEdgeData { var ranks = new HugeArray <uint>(graph.VertexCount + 1); graph.BuildHilbertRank(n, ranks); return(ranks); }
/// <summary> /// Returns the hibert distance for n and the given vertex. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="graph"></param> /// <param name="n"></param> /// <param name="vertex"></param> /// <returns></returns> public static ulong HilbertDistance <TEdgeData>(this GraphBase <TEdgeData> graph, int n, uint vertex) where TEdgeData : struct, IGraphEdgeData { float latitude, longitude; graph.GetVertex(vertex, out latitude, out longitude); return(OsmSharp.Math.Algorithms.HilbertCurve.HilbertDistance(latitude, longitude, n)); }
/// <summary> /// Switches the locations around for the two given vertices. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static void Switch <TEdgeData>(this GraphBase <TEdgeData> graph, uint vertex1, uint vertex2) where TEdgeData : struct, IGraphEdgeData { if (graph.IsDirected) { throw new ArgumentException("Cannot switch two vertices on a directed graph without it's reverse index."); } graph.Switch(vertex1, vertex2, null); }
/// <summary> /// Returns the hibert distance for n and the given vertex. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="graph"></param> /// <param name="n"></param> /// <param name="vertex"></param> /// <returns></returns> public static long HilbertDistance <TEdgeData>(this GraphBase <TEdgeData> graph, int n, uint vertex) where TEdgeData : struct, IGraphEdgeData { float latitude, longitude; if (!graph.GetVertex(vertex, out latitude, out longitude)) { throw new Exception(string.Format("Vertex {0} does not exist in graph.", vertex)); } return(HilbertCurve.HilbertDistance(latitude, longitude, n)); }
/// <summary> /// Returns all hibert distances for n. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <returns></returns> public static long[] HilbertDistances <TEdgeData>(this GraphBase <TEdgeData> graph, int n) where TEdgeData : struct, IGraphEdgeData { var distances = new long[graph.VertexCount]; for (uint vertex = 1; vertex <= graph.VertexCount; vertex++) { float latitude, longitude; graph.GetVertex(vertex, out latitude, out longitude); distances[vertex - 1] = HilbertCurve.HilbertDistance(latitude, longitude, n); } return(distances); }
/// <summary> /// Switches the data around for the two given vertices. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="graph"></param> /// <param name="vertex1"></param> /// <param name="vertex2"></param> public static void Switch <TEdgeData>(this GraphBase <TEdgeData> graph, uint vertex1, uint vertex2) where TEdgeData : struct, IGraphEdgeData { // get all existing data. var edges1 = new List <Edge <TEdgeData> >(graph.GetEdges(vertex1)); var edges2 = new List <Edge <TEdgeData> >(graph.GetEdges(vertex2)); float vertex1Latitude, vertex1Longitude; graph.GetVertex(vertex1, out vertex1Latitude, out vertex1Longitude); float vertex2Latitude, vertex2Longitude; graph.GetVertex(vertex2, out vertex2Latitude, out vertex2Longitude); // remove all edges. graph.RemoveEdges(vertex1); graph.RemoveEdges(vertex2); // update location. graph.SetVertex(vertex1, vertex2Latitude, vertex2Longitude); graph.SetVertex(vertex2, vertex1Latitude, vertex1Longitude); // add edges again. foreach (var edge in edges1) { // update existing data. if (edge.Neighbour == vertex1) { edge.Neighbour = vertex2; } else if (edge.Neighbour == vertex2) { edge.Neighbour = vertex1; } graph.AddEdge(vertex2, edge.Neighbour, edge.EdgeData, edge.Intermediates); } foreach (var edge in edges2) { // update existing data. if (edge.Neighbour == vertex1) { edge.Neighbour = vertex2; } else if (edge.Neighbour == vertex2) { edge.Neighbour = vertex1; } graph.AddEdge(vertex1, edge.Neighbour, edge.EdgeData, edge.Intermediates); } }
/// <summary> /// Creates a new osm memory router data source. /// </summary> /// <param name="graph"></param> /// <param name="tagsIndex"></param> /// <exception cref="ArgumentNullException"></exception> public RouterDataSource(GraphBase <TEdgeData> graph, ITagsIndex tagsIndex) { if (graph == null) { throw new ArgumentNullException("graph"); } if (tagsIndex == null) { throw new ArgumentNullException("tagsIndex"); } _graph = graph; _tagsIndex = tagsIndex; _supportedVehicles = new HashSet <Vehicle>(); }
/// <summary> /// Searches the graph for nearby vertices assuming it has been sorted. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static List <uint> SearchHilbert <TEdgeData>(this GraphBase <TEdgeData> graph, int n, float latitude, float longitude, float offset) where TEdgeData : struct, IGraphEdgeData { var targets = HilbertCurve.HilbertDistances( System.Math.Max(latitude - offset, -90), System.Math.Max(longitude - offset, -180), System.Math.Min(latitude + offset, 90), System.Math.Min(longitude + offset, 180), n); targets.Sort(); var vertices = new List <uint>(); var targetIdx = 0; var vertex1 = (uint)1; var vertex2 = (uint)graph.VertexCount; float vertexLat, vertexLon; while (targetIdx < targets.Count) { uint vertex; int count; if (GraphExtensions.SearchHilbert(graph, targets[targetIdx], n, vertex1, vertex2, out vertex, out count)) { // the search was successful. while (count > 0) { // there have been vertices found. if (graph.GetVertex((uint)vertex + (uint)(count - 1), out vertexLat, out vertexLon)) { // the vertex was found. if (System.Math.Abs(latitude - vertexLat) < offset && System.Math.Abs(longitude - vertexLon) < offset) { // within offset. vertices.Add((uint)vertex + (uint)(count - 1)); } } count--; } // update vertex1. vertex1 = vertex; } // move to next target. targetIdx++; } return(vertices); }
/// <summary> /// Sorts the vertices in the given graph based on a hilbert curve. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="graph"></param> /// <param name="n"></param> public static void SortHilbert <TEdgeData>(this GraphBase <TEdgeData> graph, int n) where TEdgeData : struct, IGraphEdgeData { if (graph == null) { throw new ArgumentNullException("graph"); } if (graph.VertexCount == 1) { return; } uint left = 1; uint right = graph.VertexCount; IGraphExtensions.SortHilbert(graph, n, left, right); }
/// <summary> /// Deserializes a graph router data source from the given stream. /// </summary> /// <param name="stream"></param> /// <param name="edgeDataSize"></param> /// <param name="mapFrom"></param> /// <param name="mapTo"></param> /// <returns></returns> public new static RouterDataSource <TEdgeData> Deserialize(System.IO.Stream stream, int edgeDataSize, MappedHugeArray <TEdgeData, uint> .MapFrom mapFrom, MappedHugeArray <TEdgeData, uint> .MapTo mapTo, bool copy) { // read size of graph and start location of tags. var longBytes = new byte[8]; stream.Read(longBytes, 0, 8); var position = BitConverter.ToInt64(longBytes, 0); // deserialize graph. var graph = GraphBase <TEdgeData> .Deserialize(new CappedStream(stream, 8, position - 8), edgeDataSize, mapFrom, mapTo, copy); // deserialize tags. stream.Seek(position, System.IO.SeekOrigin.Begin); var tagsIndex = global::OsmSharp.Collections.Tags.Index.TagsIndex.Deserialize( new LimitedStream(stream)); return(new RouterDataSource <TEdgeData>(graph, tagsIndex)); }
/// <summary> /// Copies all data from the given graph. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static void SortHilbert <TEdgeData>(this GraphBase <TEdgeData> graph, int n, Action <uint, uint> transform) where TEdgeData : struct, IGraphEdgeData { // build ranks. var ranks = graph.BuildHilbertRank(n); // invert ranks. var transformations = new HugeArray <uint>(ranks.Length); for (uint i = 0; i < ranks.Length; i++) { if (transform != null) { transform(ranks[i], i); } transformations[ranks[i]] = i; } // copy from the given graph but with sorted vertices. graph.Sort(transformations); }
/// <summary> /// Sorts the vertices in the given graph based on a hilbert curve. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="graph"></param> /// <param name="n"></param> private static void SortHilbert <TEdgeData>(GraphBase <TEdgeData> graph, int n, uint left, uint right) where TEdgeData : struct, IGraphEdgeData { if (graph == null) { throw new ArgumentNullException("graph"); } if (graph.VertexCount == 1) { return; } if (left < right) { // left is still to the left. uint pivot = IGraphExtensions.SortHilbertPartition(graph, n, left, right); if (left <= pivot && pivot <= right) { IGraphExtensions.SortHilbert(graph, n, left, pivot - 1); IGraphExtensions.SortHilbert(graph, n, pivot, right); } } }
/// <summary> /// Copies all data from the given graph. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="copyTo"></param> /// <param name="copyFrom"></param> public static void CopyFrom <TEdgeData>(this GraphBase <TEdgeData> copyTo, GraphBase <TEdgeData> copyFrom) where TEdgeData : struct, IGraphEdgeData { float latitude, longitude; for (uint vertex = 1; vertex <= copyFrom.VertexCount; vertex++) { copyFrom.GetVertex(vertex, out latitude, out longitude); uint newVertex = copyTo.AddVertex(latitude, longitude); if (newVertex != vertex) { throw new Exception("Graph should be empty when copy new data to it."); } } for (uint vertex = 1; vertex <= copyFrom.VertexCount; vertex++) { var edges = new List <Edge <TEdgeData> >(copyFrom.GetEdges(vertex)); foreach (var edge in edges) { copyTo.AddEdge(vertex, edge.Neighbour, edge.EdgeData, edge.Intermediates); } } }
/// <summary> /// Sorts the vertices in the given graph based on a hilbert curve using the default step count. /// </summary> /// <typeparam name="TEdgeData"></typeparam> /// <param name="graph"></param> /// <param name="n"></param> public static void SortHilbert <TEdgeData>(this GraphBase <TEdgeData> graph) where TEdgeData : struct, IGraphEdgeData { graph.SortHilbert(IGraphExtensions.DefaultHilbertSteps); }
/// <summary> /// Searches the graph for nearby vertices assuming it has been sorted. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static List <uint> SearchHilbert <TEdgeData>(this GraphBase <TEdgeData> graph, float latitude, float longitude, float offset) where TEdgeData : struct, IGraphEdgeData { return(GraphExtensions.SearchHilbert(graph, GraphExtensions.DefaultHilbertSteps, latitude, longitude, offset)); }
/// <summary> /// Searches the graph for nearby vertices assuming it has been sorted. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static bool SearchHilbert <TEdgeData>(this GraphBase <TEdgeData> graph, long hilbert, int n, uint vertex1, uint vertex2, out uint vertex, out int count) where TEdgeData : struct, IGraphEdgeData { var hilbert1 = GraphExtensions.HilbertDistance(graph, n, vertex1); var hilbert2 = GraphExtensions.HilbertDistance(graph, n, vertex2); while (vertex1 <= vertex2) { // check the current hilbert distances. if (hilbert1 > hilbert2) { // situation is impossible and probably the graph is not sorted. throw new Exception("Graph not sorted: Binary search using hilbert distance not possible."); } if (hilbert1 == hilbert) { // found at hilbert1. var lower = vertex1; while (hilbert1 == hilbert) { lower--; if (lower == 0) { // stop here, not more vertices lower. break; } hilbert1 = GraphExtensions.HilbertDistance(graph, n, lower); } lower++; var upper = vertex1; hilbert1 = GraphExtensions.HilbertDistance(graph, n, upper); while (hilbert1 == hilbert) { upper++; if (upper > graph.VertexCount) { // stop here, no more vertices higher. break; } hilbert1 = GraphExtensions.HilbertDistance(graph, n, upper); } upper--; vertex = lower; count = (int)(upper - lower) + 1; return(true); } if (hilbert2 == hilbert) { // found at hilbert2. var lower = vertex2; while (hilbert2 == hilbert) { lower--; if (lower == 0) { // stop here, not more vertices lower. break; } hilbert2 = GraphExtensions.HilbertDistance(graph, n, lower); } lower++; var upper = vertex2; hilbert2 = GraphExtensions.HilbertDistance(graph, n, upper); while (hilbert2 == hilbert) { upper++; if (upper > graph.VertexCount) { // stop here, no more vertices higher. break; } hilbert2 = GraphExtensions.HilbertDistance(graph, n, upper); } upper--; vertex = lower; count = (int)(upper - lower) + 1; return(true); } if (hilbert1 == hilbert2 || vertex1 == vertex2 || vertex1 == vertex2 - 1) { // search is finished. vertex = vertex1; count = 0; return(true); } // Binary search: calculate hilbert distance of the middle. var vertexMiddle = vertex1 + (uint)((vertex2 - vertex1) / 2); var hilbertMiddle = GraphExtensions.HilbertDistance(graph, n, vertexMiddle); if (hilbert <= hilbertMiddle) { // target is in first part. vertex2 = vertexMiddle; hilbert2 = hilbertMiddle; } else { // target is in the second part. vertex1 = vertexMiddle; hilbert1 = hilbertMiddle; } } vertex = vertex1; count = 0; return(false); }
/// <summary> /// Sorts the vertices in the given graph based on a hilbert curve using the default step count. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static void BuildHilbertRank <TEdgeData>(this GraphBase <TEdgeData> graph, HugeArrayBase <uint> ranks) where TEdgeData : struct, IGraphEdgeData { graph.BuildHilbertRank(GraphExtensions.DefaultHilbertSteps, ranks); }
/// <summary> /// Switches the locations around for the two given vertices. /// </summary> /// <typeparam name="TEdgeData"></typeparam> public static void Switch <TEdgeData>(this GraphBase <TEdgeData> graph, uint vertex1, uint vertex2, IDictionary <uint, List <uint> > reverse) where TEdgeData : struct, IGraphEdgeData { if (graph.IsDirected && reverse == null) { throw new ArgumentException("Cannot switch two vertices on a directed graph without it's reverse index."); } if (vertex1 == vertex2) { // switching identical vertices (?). return; } float vertex1Latitude, vertex1Longitude; graph.GetVertex(vertex1, out vertex1Latitude, out vertex1Longitude); float vertex2Latitude, vertex2Longitude; graph.GetVertex(vertex2, out vertex2Latitude, out vertex2Longitude); // update location. graph.SetVertex(vertex1, vertex2Latitude, vertex2Longitude); graph.SetVertex(vertex2, vertex1Latitude, vertex1Longitude); // switch and update edges, this is easy! var edges1 = new List <Edge <TEdgeData> >(); foreach (var edge in graph.GetEdges(vertex1)) { edges1.Add(new Edge <TEdgeData>() { EdgeData = edge.EdgeData, Neighbour = edge.Neighbour, Intermediates = edge.Intermediates != null ? new CoordinateArrayCollection <GeoCoordinateSimple>( edge.Intermediates.ToSimpleArray()) : null }); } var edges2 = new List <Edge <TEdgeData> >(); foreach (var edge in graph.GetEdges(vertex2)) { edges2.Add(new Edge <TEdgeData>() { EdgeData = edge.EdgeData, Neighbour = edge.Neighbour, Intermediates = edge.Intermediates != null ? new CoordinateArrayCollection <GeoCoordinateSimple>( edge.Intermediates.ToSimpleArray()) : null }); } graph.RemoveEdges(vertex1); graph.RemoveEdges(vertex2); foreach (var edge in edges1) { // update existing data. var neighbour = edge.Neighbour; var newNeighbour = edge.Neighbour; if (newNeighbour == vertex2) { newNeighbour = vertex1; } graph.AddEdge(vertex2, newNeighbour, edge.EdgeData, edge.Intermediates); if (reverse != null) { // update reverse set if present. List <uint> neighbours = null; if (reverse.TryGetValue(neighbour, out neighbours)) { // remove. neighbours.Remove(vertex1); reverse[neighbour] = neighbours; } if (reverse.TryGetValue(newNeighbour, out neighbours)) { // add. neighbours.Add(vertex2); } else { // add new. neighbours = new List <uint>(); neighbours.Add(vertex2); } reverse[newNeighbour] = neighbours; } } foreach (var edge in edges2) { // update existing data. var neighbour = edge.Neighbour; var newNeighbour = edge.Neighbour; if (newNeighbour == vertex1) { newNeighbour = vertex2; } graph.AddEdge(vertex1, newNeighbour, edge.EdgeData, edge.Intermediates); if (reverse != null) { // update reverse set if present. List <uint> neighbours = null; if (reverse.TryGetValue(neighbour, out neighbours)) { // remove. neighbours.Remove(vertex2); reverse[neighbour] = neighbours; } if (reverse.TryGetValue(newNeighbour, out neighbours)) { // add. neighbours.Add(vertex1); } else { // add new. neighbours = new List <uint>(); neighbours.Add(vertex1); } reverse[newNeighbour] = neighbours; } } if (graph.IsDirected) { // in a directed graph, there is more work to be done. var toUpdateSet = new HashSet <uint>(); List <uint> neighbours1 = null; if (reverse.TryGetValue(vertex1, out neighbours1)) { for (var i = 0; i < neighbours1.Count; i++) { if (neighbours1[i] == vertex2) { neighbours1[i] = vertex1; } else { toUpdateSet.Add(neighbours1[i]); } } reverse[vertex1] = neighbours1; } List <uint> neighbours2 = null; if (reverse.TryGetValue(vertex2, out neighbours2)) { for (var i = 0; i < neighbours2.Count; i++) { if (neighbours2[i] == vertex1) { neighbours2[i] = vertex2; } else { toUpdateSet.Add(neighbours2[i]); } } reverse[vertex2] = neighbours2; } // switch reverses. if (neighbours2 == null) { reverse.Remove(vertex1); } else { reverse[vertex1] = neighbours2; } if (neighbours1 == null) { reverse.Remove(vertex2); } else { reverse[vertex2] = neighbours1; } // update all edges in these vertices. var updatedEdges = new List <Edge <TEdgeData> >(); foreach (var toUpdate in toUpdateSet) { updatedEdges.Clear(); foreach (var edge in graph.GetEdges(toUpdate)) { if (edge.Neighbour == vertex1) { updatedEdges.Add(new Edge <TEdgeData>() { EdgeData = edge.EdgeData, Neighbour = vertex2, Intermediates = edge.Intermediates != null ? new CoordinateArrayCollection <GeoCoordinateSimple>( edge.Intermediates.ToSimpleArray()) : null }); } else if (edge.Neighbour == vertex2) { updatedEdges.Add(new Edge <TEdgeData>() { EdgeData = edge.EdgeData, Neighbour = vertex1, Intermediates = edge.Intermediates != null ? new CoordinateArrayCollection <GeoCoordinateSimple>( edge.Intermediates.ToSimpleArray()) : null }); } } graph.RemoveEdge(toUpdate, vertex1); graph.RemoveEdge(toUpdate, vertex2); foreach (var updatedEdge in updatedEdges) { graph.AddEdge(toUpdate, updatedEdge.Neighbour, updatedEdge.EdgeData, updatedEdge.Intermediates); } } } }