/// <summary> /// Adds an edge. /// </summary> /// <param name="forward"></param> /// <param name="from"></param> /// <param name="to"></param> /// <param name="tags"></param> /// <param name="intermediates"></param> protected virtual void AddRoadEdge(TagsCollectionBase tags, bool forward, uint from, uint to, List <GeoCoordinateSimple> intermediates) { 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, intermediates); _dynamicGraph.AddEdge(from, to, edgeData, intermediates.ToArray(), _edgeComparer); } }
/// <summary> /// Adds an edge. /// </summary> /// <param name="forward"></param> /// <param name="from"></param> /// <param name="to"></param> /// <param name="tags"></param> /// <param name="intermediates"></param> protected virtual void AddRoadEdge(TagsCollectionBase tags, uint from, uint to, List <GeoCoordinateSimple> intermediates) { 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 existingData; ICoordinateCollection forwardShape; if (this.GetEdge(_dynamicGraph, from, to, out existingData, out forwardShape)) { // oeps, an edge already exists! if (intermediates != null && intermediates.Count > 0) { // add one of the intermediates as new vertex. uint newVertex; if (forwardShape != null && forwardShape.Count > 0) { // the other edge also has a shape, make sure to also split it. var existingIntermediates = new List <GeoCoordinateSimple>(forwardShape.ToSimpleArray()); newVertex = _dynamicGraph.AddVertex(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude); // add edge before. var beforeEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true, fromCoordinate, new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), null); _dynamicGraph.AddEdge(from, newVertex, beforeEdgeData, null); if (_dynamicGraph.IsDirected) { // also the need to add the reverse edge. beforeEdgeData = (TEdgeData)beforeEdgeData.Reverse(); _dynamicGraph.AddEdge(newVertex, from, beforeEdgeData, null); } // add edge after. var afterIntermediates = existingIntermediates.GetRange(1, existingIntermediates.Count - 1); var afterEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true, new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), toCoordinate, afterIntermediates); _dynamicGraph.AddEdge(newVertex, to, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray())); if (_dynamicGraph.IsDirected) { // also the need to add the reverse edge. afterIntermediates.Reverse(); afterEdgeData = (TEdgeData)afterEdgeData.Reverse(); _dynamicGraph.AddEdge(to, newVertex, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray())); } // remove original edge. _dynamicGraph.RemoveEdge(from, to, existingData); if (_dynamicGraph.IsDirected && _dynamicGraph.CanHaveDuplicates) { // also remove opposite edges. _dynamicGraph.RemoveEdge(to, from, (TEdgeData)existingData.Reverse()); } } newVertex = _dynamicGraph.AddVertex(intermediates[0].Latitude, intermediates[0].Longitude); var newEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true, fromCoordinate, new GeoCoordinate(intermediates[0].Latitude, intermediates[0].Longitude), null); _dynamicGraph.AddEdge(from, newVertex, newEdgeData, null); if (_dynamicGraph.IsDirected) { // also the need to add the reverse edge. newEdgeData = (TEdgeData)newEdgeData.Reverse(); _dynamicGraph.AddEdge(newVertex, from, newEdgeData, null); } from = newVertex; fromCoordinate = new GeoCoordinate(intermediates[0].Latitude, intermediates[0].Longitude); intermediates = intermediates.GetRange(1, intermediates.Count - 1); } else { // hmm, no intermediates, the other edge should have them. if (forwardShape != null && forwardShape.Count > 0) { // there is a shape, add one of the intermediates as a new vertex. var existingIntermediates = new List <GeoCoordinateSimple>(forwardShape.ToSimpleArray()); var newVertex = _dynamicGraph.AddVertex(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude); // add edge before. var beforeEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true, fromCoordinate, new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), null); _dynamicGraph.AddEdge(from, newVertex, beforeEdgeData, null); if (_dynamicGraph.IsDirected) { // also the need to add the reverse edge. beforeEdgeData = (TEdgeData)beforeEdgeData.Reverse(); _dynamicGraph.AddEdge(newVertex, from, beforeEdgeData, null); } // add edge after. var afterIntermediates = existingIntermediates.GetRange(1, existingIntermediates.Count - 1); var afterEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true, new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), toCoordinate, afterIntermediates); _dynamicGraph.AddEdge(newVertex, to, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray())); if (_dynamicGraph.IsDirected) { // also the need to add the reverse edge. afterIntermediates.Reverse(); afterEdgeData = (TEdgeData)afterEdgeData.Reverse(); _dynamicGraph.AddEdge(to, newVertex, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray())); } if (_dynamicGraph.CanHaveDuplicates) { // make sure to remove the existing edge if graph allows duplicates. _dynamicGraph.RemoveEdge(from, to); if (_dynamicGraph.IsDirected) { // also remove the reverse. _dynamicGraph.RemoveEdge(to, from); } } } else { // do nothing just overwrite what is there, probably a bug in OSM, two overlapping ways, sharing nodes. } } // edge was there already but was removed,split or needs to be replaced. var edgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true, fromCoordinate, toCoordinate, intermediates); _dynamicGraph.AddEdge(from, to, edgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray())); if (_dynamicGraph.IsDirected) { // also the need to add the reverse edge. intermediates.Reverse(); edgeData = (TEdgeData)edgeData.Reverse(); _dynamicGraph.AddEdge(to, from, edgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray())); } } else { // edge is not there yet, just add it. ICoordinateCollection intermediatesCollection = null; if (intermediates != null) { intermediatesCollection = new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray()); } // add new edge. var edgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true, fromCoordinate, toCoordinate, intermediates); _dynamicGraph.AddEdge(from, to, edgeData, intermediatesCollection); if (_dynamicGraph.IsDirected) { // also the need to add the reverse edge. if (intermediates != null) { intermediates.Reverse(); intermediatesCollection = new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray()); } edgeData = (TEdgeData)edgeData.Reverse(); _dynamicGraph.AddEdge(to, from, edgeData, intermediatesCollection); } } } }
/// <summary> /// Contracts the given vertex. /// </summary> /// <param name="vertex"></param> public void Contract(uint vertex) { if (_contracted.Length > vertex && _contracted[vertex]) { throw new Exception("Is already contracted!"); } // keep the neighbours. var neighbours = new HashSet <KeyValuePair <uint, CHEdgeData> >(); // get all information from the source. var edges = _target.GetEdges(vertex); // report the before contraction event. this.OnBeforeContraction(vertex, edges); // replace the adjacent edges with edges that are point up. var edgesForContractions = new List <KeyValuePair <uint, CHEdgeData> >(edges.Length); foreach (var edge in edges) { if (!edge.Value.ToLower && !edge.Value.ToHigher) { // the edge is not to lower or higher. // use this edge for contraction. edgesForContractions.Add(edge); // overwrite the old edge making it point 'to higher' only. _target.AddEdge(vertex, edge.Key, new CHEdgeData(edge.Value.Weight, edge.Value.Forward, edge.Value.Backward, true, edge.Value.ContractedVertexId, edge.Value.Tags), null); } } // loop over each combination of edges just once. for (int x = 1; x < edgesForContractions.Count; x++) { // loop over all elements first. var xEdge = edgesForContractions[x]; for (int y = 0; y < x; y++) { // loop over all elements. var yEdge = edgesForContractions[y]; // calculate the total weight. var weight = xEdge.Value.Weight + yEdge.Value.Weight; // add the combinations of these edges. if (((xEdge.Value.Backward && yEdge.Value.Forward) || (yEdge.Value.Backward && xEdge.Value.Forward)) && (xEdge.Key != yEdge.Key)) { // there is a connection from x to y and there is no witness path. var witnessXToY = _contractionWitnessCalculator.Exists(_target, xEdge.Key, yEdge.Key, vertex, weight, int.MaxValue); var witnessYToX = _contractionWitnessCalculator.Exists(_target, yEdge.Key, xEdge.Key, vertex, weight, int.MaxValue); // create x-to-y data and edge. var dataXToY = new CHEdgeData(); var forward = (xEdge.Value.Backward && yEdge.Value.Forward) && !witnessXToY; var backward = (yEdge.Value.Backward && xEdge.Value.Forward) && !witnessYToX; if ((forward || backward) || !_target.ContainsEdge(xEdge.Key, yEdge.Key)) { // add the edge if there is usefull info or if there needs to be a neighbour relationship. dataXToY.SetDirection(forward, backward); dataXToY.Weight = weight; dataXToY.ContractedVertexId = vertex; _target.AddEdge(xEdge.Key, yEdge.Key, dataXToY, null, _comparer); } } } } // mark the vertex as contracted. this.MarkContracted(vertex); // notify a contracted neighbour. _calculator.NotifyContracted(vertex); // report the after contraction event. this.OnAfterContraction(vertex, edges); }