/// <summary> /// Executes the actual algorithm. /// </summary> protected override void DoRun() { foreach (var vehicle in _vehicles) { _routerDb.AddSupportedVehicle(vehicle); } var nodeToVertex = new Dictionary <long, uint>(); // read all vertices. var startTicks = DateTime.Now.Ticks; for (int readerIdx = 0; readerIdx < _shapefileReaders.Count; readerIdx++) { var reader = _shapefileReaders[readerIdx]; var header = new Dictionary <string, int>(); // make sure the header is loaded. if (header.Count == 0) { // build header. for (int idx = 0; idx < reader.DbaseHeader.Fields.Length; idx++) { header.Add(reader.DbaseHeader.Fields[idx].Name, idx + 1); } // check if all columns are in the header. if (!header.ContainsKey(_sourceVertexColumn)) { // no node from column. throw new InvalidOperationException(string.Format("No column with name {0} found.", _sourceVertexColumn)); } if (!header.ContainsKey(_targetVertexColumn)) { // no node to column. throw new InvalidOperationException(string.Format("No column with name {0} found.", _targetVertexColumn)); } } // read all vertices. double latestProgress = 0; int current = 0; while (reader.Read()) { _points += 2; // get the geometry. var lineString = reader.Geometry as LineString; // read nodes long fromId = reader.GetInt64(header[_sourceVertexColumn]); if (!nodeToVertex.ContainsKey(fromId)) { // the node has not been processed yet. var vertexId = _routerDb.Network.VertexCount; _routerDb.Network.AddVertex(vertexId, (float)lineString.Coordinates[0].Y, (float)lineString.Coordinates[0].X); nodeToVertex.Add(fromId, vertexId); } long toId = reader.GetInt64(header[_targetVertexColumn]); if (!nodeToVertex.ContainsKey(toId)) { // the node has not been processed yet. var vertexId = _routerDb.Network.VertexCount; _routerDb.Network.AddVertex(vertexId, (float)lineString.Coordinates[lineString.Coordinates.Length - 1].Y, (float)lineString.Coordinates[lineString.Coordinates.Length - 1].X); nodeToVertex.Add(toId, vertexId); } // report progress. float progress = (float)System.Math.Round((((double)current / (double)reader.RecordCount) * 100)); current++; if (progress != latestProgress) { var pointSpan = new TimeSpan(DateTime.Now.Ticks - startTicks); var pointPerSecond = System.Math.Round((double)_points / pointSpan.TotalSeconds, 0); Itinero.Logging.Logger.Log("ShapeFileReader", TraceEventType.Information, "Reading vertices from file {1}/{2}... {0}% @ {3}/s", progress, readerIdx + 1, _shapefileReaders.Count, pointPerSecond); latestProgress = progress; } } } // read all edges. startTicks = DateTime.Now.Ticks; var attributes = new AttributeCollection(); for (int readerIdx = 0; readerIdx < _shapefileReaders.Count; readerIdx++) { var reader = _shapefileReaders[readerIdx]; var header = new Dictionary <string, int>(); // make sure the header is loaded. if (header.Count == 0) { // build header. for (int idx = 0; idx < reader.DbaseHeader.Fields.Length; idx++) { header.Add(reader.DbaseHeader.Fields[idx].Name, idx + 1); } } // reset reader and read all edges/arcs. double latestProgress = 0; int current = 0; reader.Reset(); while (reader.Read()) { _lineStrings++; // get the geometry. var lineString = reader.Geometry as LineString; // read nodes long vertex1Shape = reader.GetInt64(header[_sourceVertexColumn]); long vertex2Shape = reader.GetInt64(header[_targetVertexColumn]); uint vertex1, vertex2; if (nodeToVertex.TryGetValue(vertex1Shape, out vertex1) && nodeToVertex.TryGetValue(vertex2Shape, out vertex2)) { // the node has not been processed yet. // add intermediates. var intermediates = new List <Coordinate>(lineString.Coordinates.Length); for (int i = 1; i < lineString.Coordinates.Length - 1; i++) { intermediates.Add(new Coordinate() { Latitude = (float)lineString.Coordinates[i].Y, Longitude = (float)lineString.Coordinates[i].X }); } // calculate the distance. float distance = 0; float latitudeFrom, latitudeTo, longitudeFrom, longitudeTo; if (_routerDb.Network.GetVertex(vertex1, out latitudeFrom, out longitudeFrom) && _routerDb.Network.GetVertex(vertex2, out latitudeTo, out longitudeTo)) { // calculate distance. var fromLocation = new Coordinate(latitudeFrom, longitudeFrom); for (int i = 0; i < intermediates.Count; i++) { var currentLocation = new Coordinate(intermediates[i].Latitude, intermediates[i].Longitude); distance = distance + Coordinate.DistanceEstimateInMeter(fromLocation, currentLocation); fromLocation = currentLocation; } var toLocation = new Coordinate(latitudeTo, longitudeTo); distance = distance + Coordinate.DistanceEstimateInMeter(fromLocation, toLocation); } // get profile and meta attributes. var profile = new AttributeCollection(); var meta = new AttributeCollection(); var profileWhiteList = new Whitelist(); attributes.Clear(); reader.AddToAttributeCollection(attributes); _vehicleCache.AddToWhiteList(attributes, profileWhiteList); for (var i = 1; i < reader.FieldCount; i++) { var name = reader.GetName(i); var value = reader.GetValue(i); var valueString = string.Empty; if (value != null) { valueString = value.ToInvariantString(); } if (profileWhiteList.Contains(name) || _vehicles.IsOnProfileWhiteList(name)) { profile.AddOrReplace(name, valueString); } else if (_vehicles.IsOnMetaWhiteList(name)) { meta.AddOrReplace(name, valueString); } } // add edge. var profileId = _routerDb.EdgeProfiles.Add(profile); if (profileId >= Data.Edges.EdgeDataSerializer.MAX_PROFILE_COUNT) { throw new Exception("Maximum supported profiles exeeded, make sure only routing attributes are included in the profiles."); } var metaId = _routerDb.EdgeMeta.Add(meta); if (vertex1 != vertex2) { if (distance > _routerDb.Network.MaxEdgeDistance) { // edge is too long to fit into the network, adding an itermediate vertex. var shape = intermediates; if (shape == null) { // make sure there is a shape. shape = new List <Coordinate>(); } shape = new List <Coordinate>(shape); shape.Insert(0, _routerDb.Network.GetVertex(vertex1)); shape.Add(_routerDb.Network.GetVertex(vertex2)); var tooBig = true; while (tooBig) { tooBig = false; for (var s = 1; s < shape.Count; s++) { var localDistance = Coordinate.DistanceEstimateInMeter(shape[s - 1], shape[s]); if (localDistance >= _routerDb.Network.MaxEdgeDistance) { // insert a new intermediate. shape.Insert(s, new Coordinate() { Latitude = (float)(((double)shape[s - 1].Latitude + (double)shape[s].Latitude) / 2.0), Longitude = (float)(((double)shape[s - 1].Longitude + (double)shape[s].Longitude) / 2.0), }); tooBig = true; s--; } } } var i = 0; var shortShape = new List <Coordinate>(); var shortDistance = 0.0f; uint shortVertex = Constants.NO_VERTEX; Coordinate?shortPoint; i++; while (i < shape.Count) { var localDistance = Coordinate.DistanceEstimateInMeter(shape[i - 1], shape[i]); if (localDistance + shortDistance > _routerDb.Network.MaxEdgeDistance) { // ok, previous shapepoint was the maximum one. shortPoint = shortShape[shortShape.Count - 1]; shortShape.RemoveAt(shortShape.Count - 1); // add vertex. shortVertex = _routerDb.Network.VertexCount; _routerDb.Network.AddVertex(shortVertex, shortPoint.Value.Latitude, shortPoint.Value.Longitude); // add edge. _routerDb.Network.AddEdge(vertex1, shortVertex, new Data.Network.Edges.EdgeData() { Distance = (float)shortDistance, MetaId = metaId, Profile = (ushort)profileId }, shortShape); vertex1 = shortVertex; // set new short distance, empty shape. shortShape.Clear(); shortShape.Add(shape[i]); shortDistance = localDistance; i++; } else { // just add short distance and move to the next shape point. shortShape.Add(shape[i]); shortDistance += localDistance; i++; } } // add final segment. if (shortShape.Count > 0) { shortShape.RemoveAt(shortShape.Count - 1); } // add edge. _routerDb.Network.AddEdge(vertex1, vertex2, new Data.Network.Edges.EdgeData() { Distance = (float)shortDistance, MetaId = metaId, Profile = (ushort)profileId }, shortShape); } else { this.AddEdge(vertex1, vertex2, new Data.Network.Edges.EdgeData() { Distance = distance, MetaId = metaId, Profile = (ushort)profileId }, intermediates); } } } // report progress. float progress = (float)System.Math.Round((((double)current / (double)reader.RecordCount) * 100)); current++; if (progress != latestProgress) { var span = new TimeSpan(DateTime.Now.Ticks - startTicks); var perSecond = System.Math.Round((double)_lineStrings / span.TotalSeconds, 0); Itinero.Logging.Logger.Log("ShapeFileReader", TraceEventType.Information, "Reading edges {1}/{2}... {0}% @ {3}/s", progress, readerIdx + 1, _shapefileReaders.Count, perSecond); latestProgress = progress; } } } // sort the network. Itinero.Logging.Logger.Log("ShapeFileReader", TraceEventType.Information, "Sorting vertices..."); _routerDb.Sort(); this.HasSucceeded = true; }
private static (ushort profile, uint meta) AddProfileAndMeta(RouterDb routerDb, VehicleCache vehicleCache, AttributeCollection attributes) { // add the edge if the attributes are of use to the vehicles defined. var wayAttributes = attributes; var profileWhiteList = new Whitelist(); if (!vehicleCache.AddToWhiteList(wayAttributes, profileWhiteList)) { return(ushort.MaxValue, uint.MaxValue); } // way has some use. // build profile and meta-data. var profileTags = new AttributeCollection(); var metaTags = new AttributeCollection(); foreach (var tag in wayAttributes) { if (profileWhiteList.Contains(tag.Key)) { profileTags.AddOrReplace(tag); } else if (vehicleCache.Vehicles.IsOnProfileWhiteList(tag.Key)) { metaTags.AddOrReplace(tag); } else if (vehicleCache.Vehicles.IsOnMetaWhiteList(tag.Key)) { metaTags.AddOrReplace(tag); } } if (!vehicleCache.AnyCanTraverse(profileTags)) { // way has no use of any profile. return(ushort.MaxValue, uint.MaxValue); } // get profile and meta-data id's. var profileCount = routerDb.EdgeProfiles.Count; var profile = routerDb.EdgeProfiles.Add(profileTags); if (profileCount != routerDb.EdgeProfiles.Count) { var stringBuilder = new StringBuilder(); foreach (var att in profileTags) { stringBuilder.Append(att.Key); stringBuilder.Append('='); stringBuilder.Append(att.Value); stringBuilder.Append(' '); } Logger.Log(nameof(TileParser), Logging.TraceEventType.Information, "Normalized: # profiles {0}: {1}", routerDb.EdgeProfiles.Count, stringBuilder.ToInvariantString()); } if (profile > Data.Edges.EdgeDataSerializer.MAX_PROFILE_COUNT) { throw new Exception( "Maximum supported profiles exceeded, make sure only routing tags are included in the profiles."); } var meta = routerDb.EdgeMeta.Add(metaTags); return((ushort)profile, meta); }
/// <summary> /// Adds a way. /// </summary> public override void AddWay(Way way) { if (way == null) { return; } if (way.Nodes == null) { return; } if (way.Nodes.Length == 0) { return; } if (way.Tags == null || way.Tags.Count == 0) { return; } if (_firstPass) { // just keep. if (this.Processors != null) { foreach (var processor in this.Processors) { processor.FirstPass(way); } } if (_vehicleCache.AnyCanTraverse(way.Tags.ToAttributes())) { // way has some use, add all of it's nodes to the index. _nodeIndex.AddId(way.Nodes[0]); for (var i = 0; i < way.Nodes.Length; i++) { _nodeIndex.AddId(way.Nodes[i]); } _nodeIndex.AddId(way.Nodes[way.Nodes.Length - 1]); } } else { if (this.Processors != null) { foreach (var processor in this.Processors) { processor.SecondPass(way); } } var wayAttributes = way.Tags.ToAttributes(); var profileWhiteList = new Whitelist(); if (_vehicleCache.AddToWhiteList(wayAttributes, profileWhiteList)) { // way has some use. // build profile and meta-data. var profileTags = new AttributeCollection(); var metaTags = new AttributeCollection(); foreach (var tag in way.Tags) { if (profileWhiteList.Contains(tag.Key) || _vehicleCache.Vehicles.IsOnProfileWhiteList(tag.Key)) { profileTags.Add(tag); } if (_vehicleCache.Vehicles.IsOnMetaWhiteList(tag.Key)) { metaTags.Add(tag); } } // get profile and meta-data id's. var profileCount = _db.EdgeProfiles.Count; var profile = _db.EdgeProfiles.Add(profileTags); if (profileCount != _db.EdgeProfiles.Count) { var stringBuilder = new StringBuilder(); foreach (var att in profileTags) { stringBuilder.Append(att.Key); stringBuilder.Append('='); stringBuilder.Append(att.Value); stringBuilder.Append(' '); } Itinero.Logging.Logger.Log("RouterDbStreamTarget", Logging.TraceEventType.Information, "Normalized: # profiles {0}: {1}", _db.EdgeProfiles.Count, stringBuilder.ToInvariantString()); } if (profile > Data.Edges.EdgeDataSerializer.MAX_PROFILE_COUNT) { throw new Exception("Maximum supported profiles exeeded, make sure only routing tags are included in the profiles."); } var meta = _db.EdgeMeta.Add(metaTags); // convert way into one or more edges. var node = 0; var isCore = false; while (node < way.Nodes.Length - 1) { // build edge to add. var intermediates = new List <Coordinate>(); var distance = 0.0f; Coordinate coordinate; if (!this.TryGetValue(way.Nodes[node], out coordinate, out isCore)) { // an incomplete way, node not in source. return; } var fromVertex = this.AddCoreNode(way.Nodes[node], coordinate.Latitude, coordinate.Longitude); var fromNode = way.Nodes[node]; var previousCoordinate = coordinate; node++; var toVertex = uint.MaxValue; var toNode = long.MaxValue; while (true) { if (!this.TryGetValue(way.Nodes[node], out coordinate, out isCore)) { // an incomplete way, node not in source. return; } distance += Coordinate.DistanceEstimateInMeter( previousCoordinate, coordinate); if (isCore) { // node is part of the core. toVertex = this.AddCoreNode(way.Nodes[node], coordinate.Latitude, coordinate.Longitude); toNode = way.Nodes[node]; break; } intermediates.Add(coordinate); previousCoordinate = coordinate; node++; } // try to add edge. if (fromVertex == toVertex) { // target and source vertex are identical, this must be a loop. if (intermediates.Count == 1) { // there is just one intermediate, add that one as a vertex. var newCoreVertex = _db.Network.VertexCount; _db.Network.AddVertex(newCoreVertex, intermediates[0].Latitude, intermediates[0].Longitude); this.AddCoreEdge(fromVertex, newCoreVertex, new Data.Network.Edges.EdgeData() { MetaId = meta, Distance = Coordinate.DistanceEstimateInMeter( _db.Network.GetVertex(fromVertex), intermediates[0]), Profile = (ushort)profile }, null); } else if (intermediates.Count >= 2) { // there is more than one intermediate, add two new core vertices. var newCoreVertex1 = _db.Network.VertexCount; _db.Network.AddVertex(newCoreVertex1, intermediates[0].Latitude, intermediates[0].Longitude); var newCoreVertex2 = _db.Network.VertexCount; _db.Network.AddVertex(newCoreVertex2, intermediates[intermediates.Count - 1].Latitude, intermediates[intermediates.Count - 1].Longitude); var distance1 = Coordinate.DistanceEstimateInMeter( _db.Network.GetVertex(fromVertex), intermediates[0]); var distance2 = Coordinate.DistanceEstimateInMeter( _db.Network.GetVertex(toVertex), intermediates[intermediates.Count - 1]); intermediates.RemoveAt(0); intermediates.RemoveAt(intermediates.Count - 1); this.AddCoreEdge(fromVertex, newCoreVertex1, new Data.Network.Edges.EdgeData() { MetaId = meta, Distance = distance1, Profile = (ushort)profile }, null); this.AddCoreEdge(newCoreVertex1, newCoreVertex2, new Data.Network.Edges.EdgeData() { MetaId = meta, Distance = distance - distance2 - distance1, Profile = (ushort)profile }, intermediates); this.AddCoreEdge(newCoreVertex2, toVertex, new Data.Network.Edges.EdgeData() { MetaId = meta, Distance = distance2, Profile = (ushort)profile }, null); } continue; } var edge = _db.Network.GetEdgeEnumerator(fromVertex).FirstOrDefault(x => x.To == toVertex); if (edge == null && fromVertex != toVertex) { // just add edge. this.AddCoreEdge(fromVertex, toVertex, new Data.Network.Edges.EdgeData() { MetaId = meta, Distance = distance, Profile = (ushort)profile }, intermediates); } else { // oeps, already an edge there. if (edge.Data.Distance == distance && edge.Data.Profile == profile && edge.Data.MetaId == meta) { // do nothing, identical duplicate data. } else { // try and use intermediate points if any. // try and use intermediate points. var splitMeta = meta; var splitProfile = profile; var splitDistance = distance; if (intermediates.Count == 0 && edge != null && edge.Shape != null) { // no intermediates in current edge. // save old edge data. intermediates = new List <Coordinate>(edge.Shape); fromVertex = edge.From; toVertex = edge.To; splitMeta = edge.Data.MetaId; splitProfile = edge.Data.Profile; splitDistance = edge.Data.Distance; // just add edge. _db.Network.RemoveEdges(fromVertex, toVertex); // make sure to overwrite and not add an extra edge. this.AddCoreEdge(fromVertex, toVertex, new EdgeData() { MetaId = meta, Distance = System.Math.Max(distance, 0.0f), Profile = (ushort)profile }, null); } if (intermediates.Count > 0) { // intermediates found, use the first intermediate as the core-node. var newCoreVertex = _db.Network.VertexCount; _db.Network.AddVertex(newCoreVertex, intermediates[0].Latitude, intermediates[0].Longitude); // calculate new distance and update old distance. var newDistance = Coordinate.DistanceEstimateInMeter( _db.Network.GetVertex(fromVertex), intermediates[0]); splitDistance -= newDistance; // add first part. this.AddCoreEdge(fromVertex, newCoreVertex, new EdgeData() { MetaId = splitMeta, Distance = System.Math.Max(newDistance, 0.0f), Profile = (ushort)splitProfile }, null); // add second part. intermediates.RemoveAt(0); this.AddCoreEdge(newCoreVertex, toVertex, new EdgeData() { MetaId = splitMeta, Distance = System.Math.Max(splitDistance, 0.0f), Profile = (ushort)splitProfile }, intermediates); } else { // no intermediate or shapepoint found in either one. two identical edge overlayed with different profiles. // add two other vertices with identical positions as the ones given. // connect them with an edge of length '0'. var fromLocation = _db.Network.GetVertex(fromVertex); var newFromVertex = this.AddNewCoreNode(fromNode, fromLocation.Latitude, fromLocation.Longitude); this.AddCoreEdge(fromVertex, newFromVertex, new EdgeData() { Distance = 0, MetaId = splitMeta, Profile = (ushort)splitProfile }, null); var toLocation = _db.Network.GetVertex(toVertex); var newToVertex = this.AddNewCoreNode(toNode, toLocation.Latitude, toLocation.Longitude); this.AddCoreEdge(newToVertex, toVertex, new EdgeData() { Distance = 0, MetaId = splitMeta, Profile = (ushort)splitProfile }, null); this.AddCoreEdge(newFromVertex, newToVertex, new EdgeData() { Distance = splitDistance, MetaId = splitMeta, Profile = (ushort)splitProfile }, null); } } } } } } }
/// <summary> /// Adds a way. /// </summary> public override void AddWay(Way way) { if (way == null) { return; } if (way.Nodes == null) { return; } if (way.Nodes.Length == 0) { return; } if (way.Tags == null || way.Tags.Count == 0) { return; } if (_firstPass) { // just keep. if (this.Processors != null) { foreach (var processor in this.Processors) { processor.FirstPass(way); } } if (_vehicleCache.AnyCanTraverse(way.Tags.ToAttributes())) { // way has some use, add all of it's nodes to the index. _nodeIndex.AddId(way.Nodes[0]); for (var i = 0; i < way.Nodes.Length; i++) { _nodeIndex.AddId(way.Nodes[i]); } _nodeIndex.AddId(way.Nodes[way.Nodes.Length - 1]); } } else { if (this.Processors != null) { foreach (var processor in this.Processors) { processor.SecondPass(way); } } var wayAttributes = way.Tags.ToAttributes(); var profileWhiteList = new Whitelist(); if (_vehicleCache.AddToWhiteList(wayAttributes, profileWhiteList)) { // way has some use. // build profile and meta-data. var profileTags = new AttributeCollection(); var metaTags = new AttributeCollection(); foreach (var tag in way.Tags) { if (profileWhiteList.Contains(tag.Key)) { profileTags.Add(tag); } else if (_vehicleCache.Vehicles.IsOnProfileWhiteList(tag.Key)) { profileTags.Add(tag); } else if (_vehicleCache.Vehicles.IsOnMetaWhiteList(tag.Key)) { metaTags.Add(tag); } } if (!_vehicleCache.AnyCanTraverse(profileTags)) { // way has some use, add all of it's nodes to the index. return; } // get profile and meta-data id's. var profileCount = _db.EdgeProfiles.Count; var profile = _db.EdgeProfiles.Add(profileTags); if (profileCount != _db.EdgeProfiles.Count) { var stringBuilder = new StringBuilder(); foreach (var att in profileTags) { stringBuilder.Append(att.Key); stringBuilder.Append('='); stringBuilder.Append(att.Value); stringBuilder.Append(' '); } Itinero.Logging.Logger.Log("RouterDbStreamTarget", Logging.TraceEventType.Information, "New edge profile: # profiles {0}: {1}", _db.EdgeProfiles.Count, stringBuilder.ToInvariantString()); } if (profile > Data.Edges.EdgeDataSerializer.MAX_PROFILE_COUNT) { throw new Exception("Maximum supported profiles exeeded, make sure only routing tags are included in the profiles."); } var meta = _db.EdgeMeta.Add(metaTags); // convert way into one or more edges. var node = 0; var fromNodeIdx = 0; var isCore = false; while (node < way.Nodes.Length - 1) { fromNodeIdx = node; // build edge to add. var intermediates = new List <Coordinate>(); var distance = 0.0f; Coordinate coordinate; if (!this.TryGetValue(way.Nodes[node], out coordinate, out isCore)) { // an incomplete way, node not in source. return; } var fromVertex = this.AddCoreNode(way.Nodes[node], coordinate.Latitude, coordinate.Longitude); var fromNode = way.Nodes[node]; var previousCoordinate = coordinate; node++; var toVertex = uint.MaxValue; var toNode = long.MaxValue; while (true) { if (!this.TryGetValue(way.Nodes[node], out coordinate, out isCore)) { // an incomplete way, node not in source. return; } distance += Coordinate.DistanceEstimateInMeter( previousCoordinate, coordinate); if (isCore) { // node is part of the core. toVertex = this.AddCoreNode(way.Nodes[node], coordinate.Latitude, coordinate.Longitude); toNode = way.Nodes[node]; break; } intermediates.Add(coordinate); previousCoordinate = coordinate; node++; } // just add edge. // duplicates are allowed, one-edge loops are allowed, and too long edges are added with max-length. // these data-issues are fixed in another processing step. this.AddCoreEdge(fromVertex, toVertex, new Data.Network.Edges.EdgeData() { MetaId = meta, Distance = distance, Profile = (ushort)profile }, intermediates, way.Id.Value, (ushort)(fromNodeIdx)); } } } }