Beispiel #1
0
        /// <summary>
        /// Runs the island detection.
        /// </summary>
        protected override void DoRun()
        {
            _enumerator  = _routerDb.Network.GeometricGraph.Graph.GetEdgeEnumerator();
            _vertexFlags = new SparseLongIndex();
            var vertexCount = _routerDb.Network.GeometricGraph.Graph.VertexCount;

            // precalculate all edge types for the given profiles.
            _canTraverse = new HashSet <ushort>();
            for (ushort p = 0; p < _routerDb.EdgeProfiles.Count; p++)
            {
                if (this.CanTraverse(p))
                {
                    _canTraverse.Add(p);
                }
            }

            var  island = (ushort)1;
            uint lower  = 0;

            while (true)
            {
                // find the first vertex without an island assignment.
                var vertex = uint.MaxValue;
                for (uint v = lower; v < vertexCount; v++)
                {
                    if (_islands[v] == 0)
                    {
                        lower  = v;
                        vertex = v;
                        break;
                    }
                }

                if (vertex == uint.MaxValue)
                { // no more islands left.
                    break;
                }

                // expand island until no longer possible.
                var current = vertex;
                _islands[vertex] = island;
                _vertexFlags.Add(vertex);
                vertex = this.Expand(vertex, island);

                if (vertex == uint.MaxValue)
                { // expanding failed, still just the source vertex, this is an island of one.
                    _islands[current] = SINGLETON_ISLAND;
                }
                else
                {
                    while (vertex != uint.MaxValue)
                    {
                        _islands[vertex] = island;
                        _vertexFlags.Add(vertex);

                        vertex = this.Expand(vertex, island);

                        if (vertex < current)
                        {
                            current = vertex;
                        }

                        if (vertex == uint.MaxValue)
                        {
                            while (current < vertexCount)
                            {
                                if (_islands[current] == island &&
                                    !_vertexFlags.Contains(current))
                                { // part of island but has not been used to expand yet.
                                    vertex = current;
                                    break;
                                }
                                current++;
                            }
                        }
                    }

                    // island was no singleton, move to next island.
                    island++;
                }
            }
        }
Beispiel #2
0
        private void StrongConnect(uint v)
        {
            var nextStack = new Collections.Stack <uint>();

            nextStack.Push(Constants.NO_VERTEX);
            nextStack.Push(v);

            while (nextStack.Count > 0)
            {
                v = nextStack.Pop();
                var parent = nextStack.Pop();

                if (_islands[v] != NO_ISLAND)
                {
                    continue;
                }

                // 2 options:
                // OPTION 1: vertex was already processed, check if it's a root vertex.
                if (_index[v * 2 + 0] != NO_DATA)
                { // vertex was already processed, do wrap-up.
                    if (parent != Constants.NO_VERTEX)
                    {
                        var vLowLink = _index[v * 2 + 1];
                        if (vLowLink < _index[parent * 2 + 1])
                        {
                            _index[parent * 2 + 1] = vLowLink;
                        }
                    }

                    if (_index[v * 2 + 0] == _index[v * 2 + 1])
                    { // this was a root node so this is an island!
                      // pop from stack until root reached.
                        var island = _nextIsland;
                        _nextIsland++;

                        uint size         = 0;
                        uint islandVertex = Constants.NO_VERTEX;
                        do
                        {
                            islandVertex = _stack.Pop();
                            _onStack.Remove(islandVertex);

                            size++;
                            _islands[islandVertex] = island;
                        } while (islandVertex != v);

                        if (size == 1)
                        {                  // only the root vertex, meaning this is a singleton.
                            _islands[v] = SINGLETON_ISLAND;
                            _nextIsland--; // reset island counter.
                        }
                        else
                        { // keep island size.
                            _islandSizes[island] = size;
                        }
                    }

                    continue;
                }

                // OPTION 2: vertex wasn't already processed, process it and queue it's neigbours.
                // push again to trigger OPTION1.
                nextStack.Push(parent);
                nextStack.Push(v);

                var enumerator = _routerDb.Network.GeometricGraph.Graph.GetEdgeEnumerator();
                enumerator.MoveTo(v);

                _index[v * 2 + 0] = _nextIndex;
                _index[v * 2 + 1] = _nextIndex;
                _nextIndex++;

                _stack.Push(v);
                _onStack.Add(v);

                if (enumerator.MoveTo(v))
                {
                    while (enumerator.MoveNext())
                    {
                        float  distance;
                        ushort edgeProfile;
                        EdgeDataSerializer.Deserialize(enumerator.Data0, out distance, out edgeProfile);

                        var access = this.GetAccess(edgeProfile);

                        if (enumerator.DataInverted)
                        {
                            if (access == Access.OnewayBackward)
                            {
                                access = Access.OnewayForward;
                            }
                            else if (access == Access.OnewayForward)
                            {
                                access = Access.OnewayBackward;
                            }
                        }

                        if (access != Access.OnewayForward &&
                            access != Access.Bidirectional)
                        {
                            continue;
                        }

                        var n = enumerator.To;

                        if (_islands[n] == RESTRICTED)
                        { // check if this neighbour is restricted, if so ignore.
                            continue;
                        }

                        var nIndex = _index[n * 2 + 0];
                        if (nIndex == NO_DATA)
                        { // queue parent and neighbour.
                            nextStack.Push(v);
                            nextStack.Push(n);
                        }
                        else if (_onStack.Contains(n))
                        {
                            if (nIndex < _index[v * 2 + 1])
                            {
                                _index[v * 2 + 1] = nIndex;
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Processes the given relation in the first pass.
        /// </summary>
        public void FirstPass(Relation relation)
        {
            var vehicleType = string.Empty;
            var positive    = false;

            if (!relation.IsRestriction(out vehicleType, out positive) ||
                relation.Members == null)
            {
                return;
            }

            long?from     = null;
            long?to       = null;
            long?via      = null;
            bool viaIsWay = false;

            foreach (var member in relation.Members)
            {
                if (member.Role == "via")
                {
                    viaIsWay = member.Type == OsmGeoType.Way;
                    via      = member.Id;
                }
                else if (member.Role == "from")
                {
                    from = member.Id;
                }
                else if (member.Role == "to")
                {
                    to = member.Id;
                }
            }

            if (from.HasValue && to.HasValue && via.HasValue)
            {
                if (positive)
                {
                    if (viaIsWay)
                    {
                        Logging.Logger.Log("RestrictionProcessor", Logging.TraceEventType.Warning,
                                           "A positive restriction (only_xxx) with a via-way not supported, relation {0} not processed!", relation.Id.Value);
                        return;
                    }
                    else
                    {
                        List <Relation> relations;
                        if (!_positiveRestrictions.TryGetValue(via.Value, out relations))
                        {
                            relations = new List <Relation>();
                            _positiveRestrictions.Add(via.Value, relations);
                        }
                        relations.Add(relation);
                    }

                    _restrictedWayIds.Add(from.Value);
                    // _restrictedWayIds.Add(to.Value); // don't keep to.
                    if (viaIsWay)
                    {
                        _restrictedWayIds.Add(via.Value);
                    }
                }
                else
                {
                    _restrictedWayIds.Add(from.Value);
                    _restrictedWayIds.Add(to.Value);
                    if (viaIsWay)
                    {
                        _restrictedWayIds.Add(via.Value);
                    }
                }
            }
        }
        /// <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 (_firstPass)
            { // just keep.
                if (this.Processors != null)
                {
                    foreach (var processor in this.Processors)
                    {
                        processor.FirstPass(way);
                    }
                }

                // check boundingbox and node count and descide on # stages.
                var box = new Box(
                    new Coordinate(_minLatitude, _minLongitude),
                    new Coordinate(_maxLatitude, _maxLongitude));
                var e = 0.00001f;
                if (_stages.Count == 0)
                {
                    if ((_nodeCount > 500000000 ||
                         _minimumStages > 1))
                    { // more than half a billion nodes, split in different stages.
                        var stages = System.Math.Max(System.Math.Ceiling((double)_nodeCount / 500000000), _minimumStages);

                        if (stages >= 4)
                        {
                            stages = 4;
                            _stages.Add(new Box(
                                            new Coordinate(_minLatitude, _minLongitude),
                                            new Coordinate(box.Center.Latitude, box.Center.Longitude)));
                            _stages[0] = _stages[0].Resize(e);
                            _stages.Add(new Box(
                                            new Coordinate(_minLatitude, box.Center.Longitude),
                                            new Coordinate(box.Center.Latitude, _maxLongitude)));
                            _stages[1] = _stages[1].Resize(e);
                            _stages.Add(new Box(
                                            new Coordinate(box.Center.Latitude, _minLongitude),
                                            new Coordinate(_maxLatitude, box.Center.Longitude)));
                            _stages[2] = _stages[2].Resize(e);
                            _stages.Add(new Box(
                                            new Coordinate(box.Center.Latitude, box.Center.Longitude),
                                            new Coordinate(_maxLatitude, _maxLongitude)));
                            _stages[3] = _stages[3].Resize(e);
                        }
                        else if (stages >= 2)
                        {
                            stages = 2;
                            _stages.Add(new Box(
                                            new Coordinate(_minLatitude, _minLongitude),
                                            new Coordinate(_maxLatitude, box.Center.Longitude)));
                            _stages[0] = _stages[0].Resize(e);
                            _stages.Add(new Box(
                                            new Coordinate(_minLatitude, box.Center.Longitude),
                                            new Coordinate(_maxLatitude, _maxLongitude)));
                            _stages[1] = _stages[1].Resize(e);
                        }
                        else
                        {
                            stages = 1;
                            _stages.Add(box);
                            _stages[0] = _stages[0].Resize(e);
                        }
                    }
                    else
                    {
                        _stages.Add(box);
                        _stages[0] = _stages[0].Resize(e);
                    }
                }

                if (_vehicles.AnyCanTraverse(way.Tags.ToAttributes()))
                { // way has some use.
                    for (var i = 0; i < way.Nodes.Length; i++)
                    {
                        var node = way.Nodes[i];
                        if (_allRoutingNodes.Contains(node) ||
                            _allNodesAreCore)
                        { // node already part of another way, definetly part of core.
                            _coreNodes.Add(node);
                        }
                        _allRoutingNodes.Add(node);
                    }
                    _coreNodes.Add(way.Nodes[0]);
                    _coreNodes.Add(way.Nodes[way.Nodes.Length - 1]);
                }
            }
            else
            {
                if (this.Processors != null)
                {
                    foreach (var processor in this.Processors)
                    {
                        processor.SecondPass(way);
                    }
                }

                if (_vehicles.AnyCanTraverse(way.Tags.ToAttributes()))
                {     // way has some use.
                    if (_processedWays.Contains(way.Id.Value))
                    { // way was already processed.
                        return;
                    }

                    // build profile and meta-data.
                    var profileTags = new AttributeCollection();
                    var metaTags    = new AttributeCollection();
                    foreach (var tag in way.Tags)
                    {
                        if (_vehicles.IsRelevantForProfile(tag.Key))
                        {
                            profileTags.Add(tag);
                        }
                        else
                        {
                            metaTags.Add(tag);
                        }
                    }

                    if (_normalizeTags)
                    { // normalize profile tags.
                        var normalizedProfileTags = new AttributeCollection();
                        if (!profileTags.Normalize(normalizedProfileTags, metaTags, _vehicles))
                        { // invalid data, no access, or tags make no sense at all.
                            return;
                        }
                        profileTags = normalizedProfileTags;
                    }

                    // get profile and meta-data id's.
                    var profile = _db.EdgeProfiles.Add(profileTags);
                    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;
                    while (node < way.Nodes.Length - 1)
                    {
                        // build edge to add.
                        var        intermediates = new List <Coordinate>();
                        var        distance      = 0.0f;
                        Coordinate coordinate;
                        if (!_stageCoordinates.TryGetValue(way.Nodes[node], out coordinate))
                        { // an incomplete way, node not in source.
                            // add all the others to the any stage index.
                            for (var i = 0; i < way.Nodes.Length; i++)
                            {
                                _anyStageNodes.Add(way.Nodes[i]);
                            }
                            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 (!_stageCoordinates.TryGetValue(way.Nodes[node], out coordinate))
                            { // an incomplete way, node not in source.
                                // add all the others to the any stage index.
                                for (var i = 0; i < way.Nodes.Length; i++)
                                {
                                    _anyStageNodes.Add(way.Nodes[i]);
                                }
                                return;
                            }
                            distance += Coordinate.DistanceEstimateInMeter(
                                previousCoordinate, coordinate);
                            if (_coreNodes.Contains(way.Nodes[node]))
                            { // 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);
                                }
                            }
                        }
                    }
                    _processedWays.Add(way.Id.Value);
                }
            }
        }