예제 #1
0
        /// <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;
        }
예제 #2
0
        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);
        }
예제 #3
0
        /// <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);
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #4
0
        /// <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));
                    }
                }
            }
        }