예제 #1
0
        /// <summary>
        /// Adds an edge.
        /// </summary>
        /// <param name="forward"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="tags"></param>
        /// <param name="intermediates"></param>
        protected virtual void AddRoadEdge(TagsCollectionBase tags, bool forward, uint from, uint to, List <GeoCoordinateSimple> intermediates)
        {
            float         latitude;
            float         longitude;
            GeoCoordinate fromCoordinate = null;

            if (_dynamicGraph.GetVertex(from, out latitude, out longitude))
            { //
                fromCoordinate = new GeoCoordinate(latitude, longitude);
            }
            GeoCoordinate toCoordinate = null;

            if (_dynamicGraph.GetVertex(to, out latitude, out longitude))
            { //
                toCoordinate = new GeoCoordinate(latitude, longitude);
            }

            if (fromCoordinate != null && toCoordinate != null)
            { // calculate the edge data.
                TEdgeData edgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, forward, fromCoordinate, toCoordinate, intermediates);

                _dynamicGraph.AddEdge(from, to, edgeData, intermediates.ToArray(), _edgeComparer);
            }
        }
예제 #2
0
        /// <summary>
        /// Adds an edge.
        /// </summary>
        /// <param name="forward"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="tags"></param>
        /// <param name="intermediates"></param>
        protected virtual void AddRoadEdge(TagsCollectionBase tags, uint from, uint to, List <GeoCoordinateSimple> intermediates)
        {
            float         latitude;
            float         longitude;
            GeoCoordinate fromCoordinate = null;

            if (_dynamicGraph.GetVertex(from, out latitude, out longitude))
            { //
                fromCoordinate = new GeoCoordinate(latitude, longitude);
            }
            GeoCoordinate toCoordinate = null;

            if (_dynamicGraph.GetVertex(to, out latitude, out longitude))
            { //
                toCoordinate = new GeoCoordinate(latitude, longitude);
            }

            if (fromCoordinate != null && toCoordinate != null)
            { // calculate the edge data.
                TEdgeData             existingData;
                ICoordinateCollection forwardShape;
                if (this.GetEdge(_dynamicGraph, from, to, out existingData, out forwardShape))
                {     // oeps, an edge already exists!
                    if (intermediates != null && intermediates.Count > 0)
                    { // add one of the intermediates as new vertex.
                        uint newVertex;
                        if (forwardShape != null && forwardShape.Count > 0)
                        { // the other edge also has a shape, make sure to also split it.
                            var existingIntermediates = new List <GeoCoordinateSimple>(forwardShape.ToSimpleArray());
                            newVertex = _dynamicGraph.AddVertex(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude);

                            // add edge before.
                            var beforeEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true,
                                                                        fromCoordinate, new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), null);
                            _dynamicGraph.AddEdge(from, newVertex, beforeEdgeData, null);
                            if (_dynamicGraph.IsDirected)
                            { // also the need to add the reverse edge.
                                beforeEdgeData = (TEdgeData)beforeEdgeData.Reverse();
                                _dynamicGraph.AddEdge(newVertex, from, beforeEdgeData, null);
                            }

                            // add edge after.
                            var afterIntermediates = existingIntermediates.GetRange(1, existingIntermediates.Count - 1);
                            var afterEdgeData      = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true,
                                                                            new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), toCoordinate, afterIntermediates);
                            _dynamicGraph.AddEdge(newVertex, to, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray()));
                            if (_dynamicGraph.IsDirected)
                            { // also the need to add the reverse edge.
                                afterIntermediates.Reverse();
                                afterEdgeData = (TEdgeData)afterEdgeData.Reverse();
                                _dynamicGraph.AddEdge(to, newVertex, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray()));
                            }

                            // remove original edge.
                            _dynamicGraph.RemoveEdge(from, to, existingData);
                            if (_dynamicGraph.IsDirected && _dynamicGraph.CanHaveDuplicates)
                            { // also remove opposite edges.
                                _dynamicGraph.RemoveEdge(to, from, (TEdgeData)existingData.Reverse());
                            }
                        }

                        newVertex = _dynamicGraph.AddVertex(intermediates[0].Latitude, intermediates[0].Longitude);
                        var newEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true,
                                                                 fromCoordinate, new GeoCoordinate(intermediates[0].Latitude, intermediates[0].Longitude), null);
                        _dynamicGraph.AddEdge(from, newVertex, newEdgeData, null);
                        if (_dynamicGraph.IsDirected)
                        { // also the need to add the reverse edge.
                            newEdgeData = (TEdgeData)newEdgeData.Reverse();
                            _dynamicGraph.AddEdge(newVertex, from, newEdgeData, null);
                        }

                        from           = newVertex;
                        fromCoordinate = new GeoCoordinate(intermediates[0].Latitude, intermediates[0].Longitude);
                        intermediates  = intermediates.GetRange(1, intermediates.Count - 1);
                    }
                    else
                    {     // hmm, no intermediates, the other edge should have them.
                        if (forwardShape != null && forwardShape.Count > 0)
                        { // there is a shape, add one of the intermediates as a new vertex.
                            var existingIntermediates = new List <GeoCoordinateSimple>(forwardShape.ToSimpleArray());
                            var newVertex             = _dynamicGraph.AddVertex(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude);

                            // add edge before.
                            var beforeEdgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true,
                                                                        fromCoordinate, new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), null);
                            _dynamicGraph.AddEdge(from, newVertex, beforeEdgeData, null);
                            if (_dynamicGraph.IsDirected)
                            { // also the need to add the reverse edge.
                                beforeEdgeData = (TEdgeData)beforeEdgeData.Reverse();
                                _dynamicGraph.AddEdge(newVertex, from, beforeEdgeData, null);
                            }

                            // add edge after.
                            var afterIntermediates = existingIntermediates.GetRange(1, existingIntermediates.Count - 1);
                            var afterEdgeData      = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true,
                                                                            new GeoCoordinate(existingIntermediates[0].Latitude, existingIntermediates[0].Longitude), toCoordinate, afterIntermediates);
                            _dynamicGraph.AddEdge(newVertex, to, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray()));
                            if (_dynamicGraph.IsDirected)
                            { // also the need to add the reverse edge.
                                afterIntermediates.Reverse();
                                afterEdgeData = (TEdgeData)afterEdgeData.Reverse();
                                _dynamicGraph.AddEdge(to, newVertex, afterEdgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(afterIntermediates.ToArray()));
                            }

                            if (_dynamicGraph.CanHaveDuplicates)
                            { // make sure to remove the existing edge if graph allows duplicates.
                                _dynamicGraph.RemoveEdge(from, to);
                                if (_dynamicGraph.IsDirected)
                                { // also remove the reverse.
                                    _dynamicGraph.RemoveEdge(to, from);
                                }
                            }
                        }
                        else
                        {
                            // do nothing just overwrite what is there, probably a bug in OSM, two overlapping ways, sharing nodes.
                        }
                    }

                    // edge was there already but was removed,split or needs to be replaced.
                    var edgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true,
                                                          fromCoordinate, toCoordinate, intermediates);
                    _dynamicGraph.AddEdge(from, to, edgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray()));
                    if (_dynamicGraph.IsDirected)
                    { // also the need to add the reverse edge.
                        intermediates.Reverse();
                        edgeData = (TEdgeData)edgeData.Reverse();
                        _dynamicGraph.AddEdge(to, from, edgeData, new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray()));
                    }
                }
                else
                { // edge is not there yet, just add it.
                    ICoordinateCollection intermediatesCollection = null;
                    if (intermediates != null)
                    {
                        intermediatesCollection = new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray());
                    }

                    // add new edge.
                    var edgeData = this.CalculateEdgeData(_interpreter.EdgeInterpreter, _tagsIndex, tags, true,
                                                          fromCoordinate, toCoordinate, intermediates);
                    _dynamicGraph.AddEdge(from, to, edgeData, intermediatesCollection);
                    if (_dynamicGraph.IsDirected)
                    { // also the need to add the reverse edge.
                        if (intermediates != null)
                        {
                            intermediates.Reverse();
                            intermediatesCollection = new CoordinateArrayCollection <GeoCoordinateSimple>(intermediates.ToArray());
                        }
                        edgeData = (TEdgeData)edgeData.Reverse();
                        _dynamicGraph.AddEdge(to, from, edgeData, intermediatesCollection);
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (_contracted.Length > vertex && _contracted[vertex])
            {
                throw new Exception("Is already contracted!");
            }

            // keep the neighbours.
            var neighbours = new HashSet <KeyValuePair <uint, CHEdgeData> >();

            // get all information from the source.
            var edges = _target.GetEdges(vertex);

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // replace the adjacent edges with edges that are point up.
            var edgesForContractions = new List <KeyValuePair <uint, CHEdgeData> >(edges.Length);

            foreach (var edge in edges)
            {
                if (!edge.Value.ToLower && !edge.Value.ToHigher)
                { // the edge is not to lower or higher.
                    // use this edge for contraction.
                    edgesForContractions.Add(edge);

                    // overwrite the old edge making it point 'to higher' only.
                    _target.AddEdge(vertex, edge.Key,
                                    new CHEdgeData(edge.Value.Weight, edge.Value.Forward, edge.Value.Backward, true, edge.Value.ContractedVertexId, edge.Value.Tags), null);
                }
            }

            // loop over each combination of edges just once.
            for (int x = 1; x < edgesForContractions.Count; x++)
            { // loop over all elements first.
                var xEdge = edgesForContractions[x];

                for (int y = 0; y < x; y++)
                { // loop over all elements.
                    var yEdge = edgesForContractions[y];

                    // calculate the total weight.
                    var weight = xEdge.Value.Weight + yEdge.Value.Weight;

                    // add the combinations of these edges.
                    if (((xEdge.Value.Backward && yEdge.Value.Forward) ||
                         (yEdge.Value.Backward && xEdge.Value.Forward)) &&
                        (xEdge.Key != yEdge.Key))
                    { // there is a connection from x to y and there is no witness path.
                        var witnessXToY = _contractionWitnessCalculator.Exists(_target, xEdge.Key,
                                                                               yEdge.Key, vertex, weight, int.MaxValue);
                        var witnessYToX = _contractionWitnessCalculator.Exists(_target, yEdge.Key,
                                                                               xEdge.Key, vertex, weight, int.MaxValue);

                        // create x-to-y data and edge.
                        var dataXToY = new CHEdgeData();
                        var forward  = (xEdge.Value.Backward && yEdge.Value.Forward) &&
                                       !witnessXToY;
                        var backward = (yEdge.Value.Backward && xEdge.Value.Forward) &&
                                       !witnessYToX;
                        if ((forward || backward) ||
                            !_target.ContainsEdge(xEdge.Key, yEdge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            dataXToY.SetDirection(forward, backward);
                            dataXToY.Weight             = weight;
                            dataXToY.ContractedVertexId = vertex;

                            _target.AddEdge(xEdge.Key, yEdge.Key, dataXToY, null, _comparer);
                        }
                    }
                }
            }

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // report the after contraction event.
            this.OnAfterContraction(vertex, edges);
        }