/*public static IEnumerable<IMutableVertexAndEdgeListGraph<TVertex, TEdge>> StronglyConnectedComponents<TVertex, TEdge>(this IVertexListGraph<TVertex, TEdge> g, Func<IMutableVertexAndEdgeListGraph<TVertex, TEdge>> componentMaker) * where TEdge : QuickGraph.IEdge<TVertex> * { * g.StronglyConnectedComponents(out var scc); * * return scc.GroupBy(kv => kv.Value).Select(group => * { * var c = componentMaker(); * * group.ForEach(kv => c.AddVertex(kv.Key)); * * foreach (var v1 in c.Vertices) * foreach (var v2 in c.Vertices) * { * if (g.TryGetEdges(v1, v2, out var edges)) * edges.ForEach(e => c.AddEdge(e)); * } * }); * }*/ /// <summary> /// Returns the list of weakly connected components in a graph. A weakly connected component is one in which /// <list type="number"> /// <item>for every pair of vertices V,W, W is reachable from V, ignoring edge-direction, and </item> /// <item>one cannot add another node U such that the first property still holds.</item> /// </list> /// </summary> /// <typeparam name="TGraph">The type of the produced components.</typeparam> /// <typeparam name="TVertex">The type of the vertices.</typeparam> /// <typeparam name="TEdge">The type of the edges.</typeparam> /// <param name="g">The graph.</param> /// <param name="componentMaker">A producer-function for empty empty components.</param> public static IList <TGraph> WeaklyConnectedComponents <TGraph, TVertex, TEdge>(this GraphBase <TVertex, TEdge> g, Func <TGraph> componentMaker) where TEdge : class, IEdge <TVertex> where TGraph : GraphBase <TVertex, TEdge> { var undirected = new NonDirectedGraph <TVertex, NonDirectedEdge <TVertex> >(); g.Vertices.ForEach(undirected.Add); g.Edges.ForEach(e => undirected.Add(new NonDirectedEdge <TVertex>(e.StartVertex, e.EndVertex))); var subgraphs = new List <TGraph>(); //Find the subgraphs (connected components that are candidates for being turned into trees). var dcGraphFinder = new DisconnectedGraphsFinder <TVertex, NonDirectedEdge <TVertex> >( () => new SubGraphView <TVertex, NonDirectedEdge <TVertex> >(undirected), undirected); dcGraphFinder.FindDisconnectedGraphs(); foreach (var component in dcGraphFinder.FoundDisconnectedGraphs) { var subG = componentMaker(); component.Vertices.ForEach(subG.Add); foreach (var v1 in component.Vertices) { foreach (var v2 in component.Vertices) { g.GetEdges(v1, v2).ForEach(subG.Add); } } subgraphs.Add(subG); } return(subgraphs); }
/// <summary> /// Calculates witnesses from one source to multiple targets at once but using only one hop. /// </summary> /// <param name="graph"></param> /// <param name="from"></param> /// <param name="tos"></param> /// <param name="tosWeights"></param> /// <param name="maxSettles"></param> /// <param name="forwardExists"></param> /// <param name="backwardExists"></param> private void ExistsOneHop(GraphBase <CHEdgeData> graph, uint from, List <uint> tos, List <float> tosWeights, int maxSettles, ref bool[] forwardExists, ref bool[] backwardExists) { var toSet = new HashSet <uint>(); float maxWeight = 0; for (int idx = 0; idx < tosWeights.Count; idx++) { if (!forwardExists[idx] || !backwardExists[idx]) { toSet.Add(tos[idx]); if (maxWeight < tosWeights[idx]) { maxWeight = tosWeights[idx]; } } } if (toSet.Count > 0) { var neighbours = graph.GetEdges(from); while (neighbours.MoveNext()) { if (toSet.Contains(neighbours.Neighbour)) { // ok, this is a to-edge. int index = tos.IndexOf(neighbours.Neighbour); toSet.Remove(neighbours.Neighbour); var edgeData = neighbours.EdgeData; if (edgeData.CanMoveForward && edgeData.Weight < tosWeights[index]) { forwardExists[index] = true; } if (edgeData.CanMoveBackward && edgeData.Weight < tosWeights[index]) { backwardExists[index] = true; } if (toSet.Count == 0) { break; } } } } }
/// <summary> /// Gets an edge from the given graph taking into account 'can have duplicates'. /// </summary> /// <param name="graph"></param> /// <param name="from"></param> /// <param name="to"></param> /// <param name="existingData"></param> /// <param name="shape"></param> /// <returns></returns> private bool GetEdge(GraphBase <TEdgeData> graph, uint from, uint to, out TEdgeData existingData, out ICoordinateCollection shape) { if (!graph.CanHaveDuplicates) { graph.GetEdgeShape(from, to, out shape); return(graph.GetEdge(from, to, out existingData)); } else { var edges = graph.GetEdges(from, to); while (edges.MoveNext()) { if (edges.Neighbour == to) { existingData = edges.EdgeData; shape = edges.Intermediates; return(true); } } existingData = default(TEdgeData); shape = null; return(false); } }
/// <summary> /// Starts pre-processing all nodes /// </summary> public void Start() { //_witnessCalculator.HopLimit = 5; _missesQueue = new Queue <bool>(); _misses = 0; // calculate the entire queue. this.RecalculateQueue(); // loop over the priority queue until it's empty. uint total = _target.VertexCount; uint current = 1; uint? vertex = this.SelectNext(); float latestProgress = 0; while (vertex != null) { // contract the nodes. this.Contract(vertex.Value); // select the next vertex. vertex = this.SelectNext(); // calculate and log progress. float progress = (float)(System.Math.Floor(((double)current / (double)total) * 1000) / 10.0); if (progress > 99) { progress = (float)(System.Math.Floor(((double)current / (double)total) * 10000) / 100.0); } if (progress != latestProgress) { OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Pre-processing... {0}% [{1}/{2}]", progress, current, total); latestProgress = progress; if (progress % 1 == 0 || progress > 99) { int totaEdges = 0; int totalUncontracted = 0; int maxCardinality = 0; var neighbourCount = new Dictionary <uint, int>(); for (uint v = 0; v < _target.VertexCount; v++) { if (!this.IsContracted(v)) { neighbourCount.Clear(); var edges = _target.GetEdges(v); if (edges != null) { int edgesCount = edges.Count; //int edgesCount = 0; //foreach (var edge in edges) //{ // int nCount; // if (!neighbourCount.TryGetValue(edge.Neighbour, out nCount)) // { // neighbourCount.Add(edge.Neighbour, 1); // } // else // { // neighbourCount[edge.Neighbour] = nCount++; // } // if (nCount > 2) // { // throw new Exception(); // } // edgesCount++; //} totaEdges = edgesCount + totaEdges; if (maxCardinality < edgesCount) { maxCardinality = edgesCount; } } totalUncontracted++; } } var density = (double)totaEdges / (double)totalUncontracted; OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Average card uncontracted vertices: {0} with max {1}", density, maxCardinality); //if (density > 20 && // _witnessCalculator.HopLimit < 5) //{ // OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit."); // _witnessCalculator.HopLimit = 5; // this.RecalculateQueue(); //} //else if (density > 10 && // _witnessCalculator.HopLimit < 4) //{ // OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit."); // _witnessCalculator.HopLimit = 4; // this.RecalculateQueue(); //} //else if (density > 5 && // _witnessCalculator.HopLimit < 3) //{ // OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit."); // _witnessCalculator.HopLimit = 3; // this.RecalculateQueue(); //} //else if (density > 3.3 && // _witnessCalculator.HopLimit < 2) //{ // OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit."); // _witnessCalculator.HopLimit = 2; // this.RecalculateQueue(); //} } } current++; } OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Pre-processing finsihed!"); }
/// <summary> /// Calculates witnesses from on source to multiple targets at once. /// </summary> /// <param name="graph"></param> /// <param name="from"></param> /// <param name="tos"></param> /// <param name="tosWeights"></param> /// <param name="maxSettles"></param> /// <param name="forwardExists"></param> /// <param name="backwardExists"></param> /// <param name="toSkip"></param> public void Exists(GraphBase <CHEdgeData> graph, uint from, List <uint> tos, List <float> tosWeights, int maxSettles, ref bool[] forwardExists, ref bool[] backwardExists, uint toSkip) { int maxHops = _hopLimit; if (maxHops == 1) { this.ExistsOneHop(graph, from, tos, tosWeights, maxSettles, ref forwardExists, ref backwardExists); return; } // creates the settled list. var backwardSettled = new HashSet <uint>(); var forwardSettled = new HashSet <uint>(); var backwardToSet = new HashSet <uint>(); var forwardToSet = new HashSet <uint>(); float forwardMaxWeight = 0, backwardMaxWeight = 0; for (int idx = 0; idx < tosWeights.Count; idx++) { if (!forwardExists[idx]) { forwardToSet.Add(tos[idx]); if (forwardMaxWeight < tosWeights[idx]) { forwardMaxWeight = tosWeights[idx]; } } if (!backwardExists[idx]) { backwardToSet.Add(tos[idx]); if (backwardMaxWeight < tosWeights[idx]) { backwardMaxWeight = tosWeights[idx]; } } } if (forwardMaxWeight == 0 && backwardMaxWeight == 0) { // no need to search! return; } // creates the priorty queue. var forwardMinWeight = new Dictionary <uint, float>(); var backwardMinWeight = new Dictionary <uint, float>(); var heap = _reusableHeap; heap.Clear(); heap.Push(new SettledVertex(from, 0, 0, forwardMaxWeight > 0, backwardMaxWeight > 0), 0); // keep looping until the queue is empty or the target is found! while (heap.Count > 0) { // pop the first customer. var current = heap.Pop(); if (current.Hops + 1 < maxHops) { // the current vertex has net been settled. if (current.VertexId == toSkip) { continue; } bool forwardWasSettled = forwardSettled.Contains(current.VertexId); bool backwardWasSettled = backwardSettled.Contains(current.VertexId); if (forwardWasSettled && backwardWasSettled) { continue; } if (current.Forward) { // this is a forward settle. forwardSettled.Add(current.VertexId); forwardMinWeight.Remove(current.VertexId); if (forwardToSet.Contains(current.VertexId)) { int index = tos.IndexOf(current.VertexId); forwardExists[index] = current.Weight <= tosWeights[index]; //if (forwardExists[index]) //{ forwardToSet.Remove(current.VertexId); //} } } if (current.Backward) { // this is a backward settle. backwardSettled.Add(current.VertexId); backwardMinWeight.Remove(current.VertexId); if (backwardToSet.Contains(current.VertexId)) { int index = tos.IndexOf(current.VertexId); backwardExists[index] = current.Weight <= tosWeights[index]; //if (backwardExists[index]) //{ backwardToSet.Remove(current.VertexId); //} } } if (forwardToSet.Count == 0 && backwardToSet.Count == 0) { // there is nothing left to check. break; } if (forwardSettled.Count >= maxSettles && backwardSettled.Count >= maxSettles) { // do not continue searching. break; } bool doForward = current.Forward && forwardToSet.Count > 0 && !forwardWasSettled; bool doBackward = current.Backward && backwardToSet.Count > 0 && !backwardWasSettled; if (doForward || doBackward) { // get the neighbours. var neighbours = graph.GetEdges(current.VertexId); while (neighbours.MoveNext()) { // move next. var edgeData = neighbours.EdgeData; var neighbourWeight = current.Weight + edgeData.Weight; var doNeighbourForward = doForward && edgeData.CanMoveForward && neighbourWeight <= forwardMaxWeight && !forwardSettled.Contains(neighbours.Neighbour); var doNeighbourBackward = doBackward && edgeData.CanMoveBackward && neighbourWeight <= backwardMaxWeight && !backwardSettled.Contains(neighbours.Neighbour); if (doNeighbourBackward || doNeighbourForward) { float existingWeight; if (doNeighbourForward) { if (forwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight)) { if (existingWeight <= neighbourWeight) { doNeighbourForward = false; } else { forwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } else { forwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } if (doNeighbourBackward) { if (backwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight)) { if (existingWeight <= neighbourWeight) { doNeighbourBackward = false; } else { backwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } else { backwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } if (doNeighbourBackward || doNeighbourForward) { var neighbour = new SettledVertex(neighbours.Neighbour, neighbourWeight, current.Hops + 1, doNeighbourForward, doNeighbourBackward); heap.Push(neighbour, neighbour.Weight); } } } } } } }
/// <summary> /// Calculates witnesses from one source to multiple targets at once but using only one hop. /// </summary> /// <param name="graph"></param> /// <param name="from"></param> /// <param name="tos"></param> /// <param name="tosWeights"></param> /// <param name="maxSettles"></param> /// <param name="forwardExists"></param> /// <param name="backwardExists"></param> private void ExistsOneHop(GraphBase<CHEdgeData> graph, uint from, List<uint> tos, List<float> tosWeights, int maxSettles, ref bool[] forwardExists, ref bool[] backwardExists) { var toSet = new HashSet<uint>(); float maxWeight = 0; for (int idx = 0; idx < tosWeights.Count; idx++) { if (!forwardExists[idx] || !backwardExists[idx]) { toSet.Add(tos[idx]); if (maxWeight < tosWeights[idx]) { maxWeight = tosWeights[idx]; } } } if (toSet.Count > 0) { var neighbours = graph.GetEdges(from); while (neighbours.MoveNext()) { if (toSet.Contains(neighbours.Neighbour)) { // ok, this is a to-edge. int index = tos.IndexOf(neighbours.Neighbour); toSet.Remove(neighbours.Neighbour); var edgeData = neighbours.EdgeData; if (edgeData.CanMoveForward && edgeData.Weight < tosWeights[index]) { forwardExists[index] = true; } if (edgeData.CanMoveBackward && edgeData.Weight < tosWeights[index]) { backwardExists[index] = true; } if (toSet.Count == 0) { break; } } } } }
/// <summary> /// Calculates witnesses from on source to multiple targets at once. /// </summary> /// <param name="graph"></param> /// <param name="from"></param> /// <param name="tos"></param> /// <param name="tosWeights"></param> /// <param name="maxSettles"></param> /// <param name="forwardExists"></param> /// <param name="backwardExists"></param> /// <param name="toSkip"></param> public void Exists(GraphBase<CHEdgeData> graph, uint from, List<uint> tos, List<float> tosWeights, int maxSettles, ref bool[] forwardExists, ref bool[] backwardExists, uint toSkip) { int maxHops = _hopLimit; if (maxHops == 1) { this.ExistsOneHop(graph, from, tos, tosWeights, maxSettles, ref forwardExists, ref backwardExists); return; } // creates the settled list. var backwardSettled = new HashSet<uint>(); var forwardSettled = new HashSet<uint>(); var backwardToSet = new HashSet<uint>(); var forwardToSet = new HashSet<uint>(); float forwardMaxWeight = 0, backwardMaxWeight = 0; for (int idx = 0; idx < tosWeights.Count; idx++) { if (!forwardExists[idx]) { forwardToSet.Add(tos[idx]); if (forwardMaxWeight < tosWeights[idx]) { forwardMaxWeight = tosWeights[idx]; } } if (!backwardExists[idx]) { backwardToSet.Add(tos[idx]); if (backwardMaxWeight < tosWeights[idx]) { backwardMaxWeight = tosWeights[idx]; } } } if (forwardMaxWeight == 0 && backwardMaxWeight == 0) { // no need to search! return; } // creates the priorty queue. var forwardMinWeight = new Dictionary<uint, float>(); var backwardMinWeight = new Dictionary<uint, float>(); var heap = _reusableHeap; heap.Clear(); heap.Push(new SettledVertex(from, 0, 0, forwardMaxWeight > 0, backwardMaxWeight > 0), 0); // keep looping until the queue is empty or the target is found! while (heap.Count > 0) { // pop the first customer. var current = heap.Pop(); if (current.Hops + 1 < maxHops) { // the current vertex has net been settled. if(current.VertexId == toSkip) { continue; } bool forwardWasSettled = forwardSettled.Contains(current.VertexId); bool backwardWasSettled = backwardSettled.Contains(current.VertexId); if (forwardWasSettled && backwardWasSettled) { continue; } if (current.Forward) { // this is a forward settle. forwardSettled.Add(current.VertexId); forwardMinWeight.Remove(current.VertexId); if (forwardToSet.Contains(current.VertexId)) { int index = tos.IndexOf(current.VertexId); forwardExists[index] = current.Weight <= tosWeights[index]; //if (forwardExists[index]) //{ forwardToSet.Remove(current.VertexId); //} } } if (current.Backward) { // this is a backward settle. backwardSettled.Add(current.VertexId); backwardMinWeight.Remove(current.VertexId); if (backwardToSet.Contains(current.VertexId)) { int index = tos.IndexOf(current.VertexId); backwardExists[index] = current.Weight <= tosWeights[index]; //if (backwardExists[index]) //{ backwardToSet.Remove(current.VertexId); //} } } if (forwardToSet.Count == 0 && backwardToSet.Count == 0) { // there is nothing left to check. break; } if (forwardSettled.Count >= maxSettles && backwardSettled.Count >= maxSettles) { // do not continue searching. break; } bool doForward = current.Forward && forwardToSet.Count > 0 && !forwardWasSettled; bool doBackward = current.Backward && backwardToSet.Count > 0 && !backwardWasSettled; if (doForward || doBackward) { // get the neighbours. var neighbours = graph.GetEdges(current.VertexId); while (neighbours.MoveNext()) { // move next. var edgeData = neighbours.EdgeData; var neighbourWeight = current.Weight + edgeData.Weight; var doNeighbourForward = doForward && edgeData.CanMoveForward && neighbourWeight <= forwardMaxWeight && !forwardSettled.Contains(neighbours.Neighbour); var doNeighbourBackward = doBackward && edgeData.CanMoveBackward && neighbourWeight <= backwardMaxWeight && !backwardSettled.Contains(neighbours.Neighbour); if (doNeighbourBackward || doNeighbourForward) { float existingWeight; if (doNeighbourForward) { if (forwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight)) { if(existingWeight <= neighbourWeight) { doNeighbourForward = false; } else { forwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } else { forwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } if (doNeighbourBackward) { if (backwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight)) { if (existingWeight <= neighbourWeight) { doNeighbourBackward = false; } else { backwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } else { backwardMinWeight[neighbours.Neighbour] = neighbourWeight; } } if (doNeighbourBackward || doNeighbourForward) { var neighbour = new SettledVertex(neighbours.Neighbour, neighbourWeight, current.Hops + 1, doNeighbourForward, doNeighbourBackward); heap.Push(neighbour, neighbour.Weight); } } } } } } }
/// <summary> /// Calculates the priority of the given vertex. /// </summary> /// <param name="vertex">The vertex to calculate the priority for.</param> /// <param name="newEdges">The number of new edges that would be added.</param> /// <param name="removedEdges">The number of edges that would be removed.</param> /// <param name="depth">The depth of the vertex.</param> /// <param name="contracted">The number of contracted neighours.</param> public float Calculate(uint vertex, out int newEdges, out int removedEdges, out int depth, out int contracted) { newEdges = 0; removedEdges = 0; _contractionCount.TryGetValue(vertex, out contracted); // get all information from the source. var edges = _data.GetEdges(vertex).ToList(); // build the list of edges to replace. var edgesForContractions = new List <Edge <CHEdgeData> >(edges.Count); var tos = new List <uint>(edges.Count); var tosSet = new HashSet <uint>(); foreach (var edge in edges) { // use this edge for contraction. edgesForContractions.Add(edge); tos.Add(edge.Neighbour); tosSet.Add(edge.Neighbour); removedEdges++; } var toRequeue = new HashSet <uint>(); var forwardEdges = new CHEdgeData?[2]; var backwardEdges = new CHEdgeData?[2]; var existingEdgesToRemove = new HashSet <CHEdgeData>(); // loop over each combination of edges just once. var forwardWitnesses = new bool[edgesForContractions.Count]; var backwardWitnesses = new bool[edgesForContractions.Count]; var weights = new List <float>(edgesForContractions.Count); var edgesToY = new Dictionary <uint, Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> >(edgesForContractions.Count); for (int x = 1; x < edgesForContractions.Count; x++) { // loop over all elements first. var xEdge = edgesForContractions[x]; // get edges. edgesToY.Clear(); var rawEdgesToY = _data.GetEdges(xEdge.Neighbour); while (rawEdgesToY.MoveNext()) { var rawEdgeNeighbour = rawEdgesToY.Neighbour; if (tosSet.Contains(rawEdgeNeighbour)) { var rawEdgeData = rawEdgesToY.EdgeData; var rawEdgeForwardWeight = rawEdgeData.CanMoveForward ? rawEdgeData.Weight : float.MaxValue; var rawEdgeBackwardWeight = rawEdgeData.CanMoveBackward ? rawEdgeData.Weight : float.MaxValue; Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (!edgesToY.TryGetValue(rawEdgeNeighbour, out edgeTuple)) { edgeTuple = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>(rawEdgeData, null, null, rawEdgeForwardWeight, rawEdgeBackwardWeight); edgesToY.Add(rawEdgeNeighbour, edgeTuple); } else if (!edgeTuple.Item2.HasValue) { edgesToY[rawEdgeNeighbour] = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>( edgeTuple.Item1, rawEdgeData, null, rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4, rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5); } else { edgesToY[rawEdgeNeighbour] = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>( edgeTuple.Item1, edgeTuple.Item2, rawEdgeData, rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4, rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5); } } } // calculate max weight. weights.Clear(); var forwardUnknown = false; var backwardUnknown = false; for (int y = 0; y < x; y++) { // update maxWeight. var yEdge = edgesForContractions[y]; if (xEdge.Neighbour != yEdge.Neighbour) { // reset witnesses. var forwardWeight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight; forwardWitnesses[y] = !xEdge.EdgeData.CanMoveBackward || !yEdge.EdgeData.CanMoveForward; backwardWitnesses[y] = !xEdge.EdgeData.CanMoveForward || !yEdge.EdgeData.CanMoveBackward; weights.Add(forwardWeight); Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple)) { if (!forwardWitnesses[y]) { // check 1-hop witnesses. if (edgeTuple.Item4 <= forwardWeight) { forwardWitnesses[y] = true; } } if (!backwardWitnesses[y]) { // check 1-hop witnesses. if (edgeTuple.Item5 <= forwardWeight) { backwardWitnesses[y] = true; } } } forwardUnknown = !forwardWitnesses[y] || forwardUnknown; backwardUnknown = !backwardWitnesses[y] || backwardUnknown; } else { // already set this to true, not use calculating it's witness. forwardWitnesses[y] = true; backwardWitnesses[y] = true; weights.Add(0); } } // calculate witnesses. if (_witnessCalculator.HopLimit > 1) { // 1-hops already checked. if (forwardUnknown || backwardUnknown) { _witnessCalculator.Exists(_data, xEdge.Neighbour, tos, weights, int.MaxValue, ref forwardWitnesses, ref backwardWitnesses, vertex); } } for (int y = 0; y < x; y++) { // loop over all elements. var yEdge = edgesForContractions[y]; // add the combinations of these edges. if (xEdge.Neighbour != yEdge.Neighbour) { // there is a connection from x to y and there is no witness path. // create x-to-y data and edge. var canMoveForward = !forwardWitnesses[y] && (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward); var canMoveBackward = !backwardWitnesses[y] && (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward); if (canMoveForward || canMoveBackward) { // add the edge if there is usefull info or if there needs to be a neighbour relationship. // add contracted edges like normal. // calculate the total weights. var weight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight; // there are a few options now: // 1) No edges yet between xEdge.Neighbour and yEdge.Neighbour. // 1) There is no other contracted edge: just add as a duplicate. // 2) There is at least on other contracted edge: optimize information because there can only be 4 case between two vertices: // - One bidirectional edge. // - Two directed edges with different weights. // - One forward edge. // - One backward edge. // => all available information needs to be combined. // check existing data. var existingCanMoveForward = false; var existingCanMoveBackward = false; var existingForwardWeight = float.MaxValue; var existingBackwardWeight = float.MaxValue; uint existingForwardContracted = 0; uint existingBackwardContracted = 0; Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple)) { //var existingEdges = _data.GetEdges(xEdge.Neighbour, yEdge.Neighbour); existingEdgesToRemove.Clear(); // remove all existing stuff. var existingEdge = new CHEdgeData(); for (int idx = 0; idx < 3; idx++) { switch (idx) { case 0: existingEdge = edgeTuple.Item1.Value; break; case 1: if (!edgeTuple.Item2.HasValue) { idx = 2; break; } existingEdge = edgeTuple.Item2.Value; break; case 2: if (!edgeTuple.Item3.HasValue) { idx = 2; break; } existingEdge = edgeTuple.Item3.Value; break; } var existingEdgeData = existingEdge; if (existingEdgeData.IsContracted) { // this edge is contracted, collect it's information. existingEdgesToRemove.Add(existingEdgeData); if (existingEdgeData.CanMoveForward) { // can move forward, so at least one edge that can move forward. existingCanMoveForward = true; if (existingForwardWeight > existingEdgeData.Weight) { // update forward weight. existingForwardWeight = existingEdgeData.Weight; existingForwardContracted = existingEdgeData.ContractedId; } } if (existingEdgeData.CanMoveBackward) { // can move backward, so at least one edge that can move backward. existingCanMoveBackward = true; if (existingBackwardWeight > existingEdgeData.Weight) { // update backward weight. existingBackwardWeight = existingEdgeData.Weight; existingBackwardContracted = existingEdgeData.ContractedId; } } } } } if (existingCanMoveForward || existingCanMoveBackward) { // there is already another contraced edge. uint forwardContractedId = vertex; float forwardWeight = weight; // merge with existing data. if (existingCanMoveForward && ((weight > existingForwardWeight) || !canMoveForward)) { // choose the smallest weight. canMoveForward = true; forwardContractedId = existingForwardContracted; forwardWeight = existingForwardWeight; } uint backwardContractedId = vertex; float backwardWeight = weight; // merge with existing data. if (existingCanMoveBackward && ((weight > existingBackwardWeight) || !canMoveBackward)) { // choose the smallest weight. canMoveBackward = true; backwardContractedId = existingBackwardContracted; backwardWeight = existingBackwardWeight; } // add one of the 4 above case. forwardEdges[0] = null; forwardEdges[1] = null; backwardEdges[0] = null; backwardEdges[1] = null; if (canMoveForward && canMoveBackward && forwardWeight == backwardWeight && forwardContractedId == backwardContractedId) { // just add one edge. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, true, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, true, forwardWeight)); backwardEdges[0] = new CHEdgeData(backwardContractedId, true, true, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, true, backwardWeight)); } else if (canMoveBackward && canMoveForward) { // add two different edges. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight)); backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight)); forwardEdges[1] = new CHEdgeData(backwardContractedId, false, true, backwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight)); backwardEdges[1] = new CHEdgeData(backwardContractedId, true, false, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight)); } else if (canMoveForward) { // only add one forward edge. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight)); backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight)); } else if (canMoveBackward) { // only add one backward edge. forwardEdges[0] = new CHEdgeData(backwardContractedId, false, true, backwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight)); backwardEdges[0] = new CHEdgeData(backwardContractedId, true, false, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight)); } // remove all existing stuff. foreach (var existingEdgeToRemove in existingEdgesToRemove) { if (forwardEdges[0].Equals(existingEdgeToRemove)) { // this forward edge is to be kept. forwardEdges[0] = null; // it's already there. } else if (forwardEdges[1] != null && !forwardEdges[1].Equals(existingEdgeToRemove)) { // this forward edge is to be kept. forwardEdges[1] = null; // it's already there. } else { // yup, just remove it now. removedEdges++; } var existingEdgeToRemoveBackward = (CHEdgeData)existingEdgeToRemove.Reverse(); if (backwardEdges[0].Equals(existingEdgeToRemoveBackward)) { // this backward edge is to be kept. backwardEdges[0] = null; // it's already there. } else if (backwardEdges[1] != null && !backwardEdges[1].Equals(existingEdgeToRemoveBackward)) { // this backward edge is to be kept. backwardEdges[1] = null; // it's already there. } else { // yup, just remove it now. removedEdges++; } } // add remaining edges. if (forwardEdges[0].HasValue) { newEdges++; } if (forwardEdges[1].HasValue) { newEdges++; } if (backwardEdges[0].HasValue) { newEdges++; } if (backwardEdges[1].HasValue) { newEdges++; } } else { // there is no edge, just add the data. newEdges = newEdges + 2; } } } } } // get the depth. _depth.TryGetValue(vertex, out depth); return(1 * (newEdges - removedEdges) + (2 * depth) + (1 * contracted)); }
/// <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(); }