Esempio n. 1
0
        /// <summary>
        /// Returns the weight between two points on an edge with the given tags for the vehicle.
        /// </summary>
        /// <param name="tags"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        public virtual float Weight(TagsCollection tags, GeoCoordinate from, GeoCoordinate to)
        {
            var distance = from.DistanceEstimate(to).Value;

            return (float)(distance / (this.ProbableSpeed(tags).Value) * 3.6);
        }
Esempio n. 2
0
 /// <summary>
 /// Returns the weight between two points on an edge with the given tags for the vehicle.
 /// </summary>
 /// <param name="tags"></param>
 /// <param name="from"></param>
 /// <param name="to"></param>
 /// <returns></returns>
 public virtual float Weight(TagsCollectionBase tags, GeoCoordinate from, GeoCoordinate to)
 {
     var distance = (float)from.DistanceEstimate(to).Value;
     return this.Weight(tags, distance);
 }
Esempio n. 3
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (this.IsContracted(vertex))
            {
                throw new Exception("Is already contracted!");
            }

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

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

            // replace the adjacent edges with edges that are point up.
            var edgesForContractions = new List<Edge<CHEdgeData>>(edges.Count);
            var tos = new List<uint>(edges.Count);
            foreach (var edge in edges)
            {
                if (!edge.EdgeData.ToLower)
                { // the edge is not to lower or higher.
                    // use this edge for contraction.
                    edgesForContractions.Add(edge);
                    tos.Add(edge.Neighbour);

                    // overwrite the old edge making it point 'to higher' only.
                    var toHigherData = edge.EdgeData;
                    toHigherData.SetContractedDirection(true, false);
                    ICoordinateCollection shape = null;
                    if (!_target.GetEdgeShape(vertex, edge.Neighbour, out shape))
                    {
                        shape = null;
                    }
                    _target.AddEdge(vertex, edge.Neighbour, toHigherData, shape);
                }
            }

            // loop over each combination of edges just once.
            int newEdge = 0;
            var witnesses = new bool[edgesForContractions.Count];
            var tosWeights = new List<float>(edgesForContractions.Count);
            var toRequeue = new HashSet<uint>();
            for (int x = 0; x < edgesForContractions.Count; x++)
            { // loop over all elements first.
                var xEdge = edgesForContractions[x];
                if (!xEdge.EdgeData.Backward) { continue; }

                // calculate max weight.
                tosWeights.Clear();
                for (int idx = 0; idx < edgesForContractions.Count; idx++)
                {
                    // update maxWeight.
                    var yEdge = edgesForContractions[idx];
                    if (xEdge.Neighbour != yEdge.Neighbour &&
                        yEdge.EdgeData.Forward)
                    {
                        // reset witnesses.
                        float weight = (float)xEdge.EdgeData.BackwardWeight + (float)yEdge.EdgeData.ForwardWeight;
                        witnesses[idx] = false;
                        tosWeights.Add(weight);
                    }
                    else
                    { // already set this to true, not use calculating it's witness.
                        witnesses[idx] = true;
                        tosWeights.Add(0);
                    }
                }

                _contractionWitnessCalculator.Exists(_target, xEdge.Neighbour, tos, tosWeights, int.MaxValue, ref witnesses);

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

                    // add the combinations of these edges.
                    if (yEdge.EdgeData.Forward &&
                        xEdge.Neighbour != yEdge.Neighbour)
                    { // there is a connection from x to y and there is no witness path.
                        // create x-to-y data and edge.
                        var forward = (xEdge.EdgeData.Backward && yEdge.EdgeData.Forward) && !witnesses[y];

                        if (forward)
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            // calculate the total weight.
                            var forwardWeight = xEdge.EdgeData.BackwardWeight + yEdge.EdgeData.ForwardWeight;

                            CHEdgeData data;
                            if (_target.GetEdge(xEdge.Neighbour, yEdge.Neighbour, out data))
                            { // there already is an edge; evaluate for each direction.
                                if (forward && data.ForwardWeight > forwardWeight)
                                { // replace forward edge.
                                    ICoordinateCollection shape;
                                    if (data.RepresentsNeighbourRelations &&
                                        _target.GetEdgeShape(xEdge.Neighbour, yEdge.Neighbour, out shape) &&
                                        shape != null && shape.Count > 0)
                                    { // an edge that represents a relation between two neighbours and has shapes should never be replaced.
                                        // TODO: keep existing edge by inserting a dummy vertex for one of the shapes.
                                        // TODO: check if this is still needed because these case are supposed to be remove in osm->graph conversions.
                                        // WARNING: The assumption here is that the weight is in direct relation with the distance.
                                        var shapeCoordinates = new List<GeoCoordinateSimple>(shape.ToSimpleArray());
                                        float latitude, longitude;
                                        _target.GetVertex(xEdge.Neighbour, out latitude, out longitude);
                                        var previousCoordinate = new GeoCoordinate(shapeCoordinates[0]);
                                        var distanceFirst = (new GeoCoordinate(latitude, longitude)).DistanceEstimate(previousCoordinate).Value;
                                        var totalDistance = distanceFirst;
                                        for(int idx = 1; idx < shapeCoordinates.Count; idx++)
                                        {
                                            var currentCoordinate = new GeoCoordinate(shapeCoordinates[idx]);
                                            totalDistance = totalDistance + currentCoordinate.DistanceEstimate(previousCoordinate).Value;

                                            previousCoordinate = currentCoordinate;
                                        }
                                        _target.GetVertex(yEdge.Neighbour, out latitude, out longitude);
                                        totalDistance = totalDistance + previousCoordinate.DistanceEstimate(new GeoCoordinate(latitude, longitude)).Value;

                                        // calculate the new edge data's.
                                        float firstPartRatio = (float)(distanceFirst / totalDistance);
                                        float secondPartRatio = 1 - firstPartRatio;
                                        // REMARK: the edge being split can never have contracted id's because it would not have a shape.
                                        var firstPartEdgeData = new CHEdgeData()
                                        {
                                            BackwardContractedId = data.BackwardContractedId,
                                            BackwardWeight = data.BackwardWeight,
                                            ForwardContractedId = data.ForwardContractedId,
                                            ForwardWeight = data.ForwardWeight,
                                            Tags = data.Tags,
                                            TagsForward = data.TagsForward
                                        };
                                        var secondPartEdgeData = new CHEdgeData()
                                        {
                                            BackwardContractedId = data.BackwardContractedId,
                                            BackwardWeight = data.BackwardWeight,
                                            ForwardContractedId = data.ForwardContractedId,
                                            ForwardWeight = data.ForwardWeight,
                                            Tags = data.Tags,
                                            TagsForward = data.TagsForward
                                        };
                                        // calculate firstpart weights.
                                        if(data.Backward)
                                        {
                                            firstPartEdgeData.BackwardWeight = firstPartEdgeData.BackwardWeight * firstPartRatio;
                                            secondPartEdgeData.BackwardWeight = secondPartEdgeData.BackwardWeight * secondPartRatio;
                                        }
                                        if (data.Forward)
                                        {
                                            firstPartEdgeData.ForwardWeight = firstPartEdgeData.ForwardWeight * firstPartRatio;
                                            secondPartEdgeData.ForwardWeight = secondPartEdgeData.ForwardWeight * secondPartRatio;
                                        }

                                        // add intermediate vertex.
                                        var newVertex = _target.AddVertex(shapeCoordinates[0].Latitude, shapeCoordinates[0].Longitude);
                                        toRequeue.Add(newVertex); // immidiately queue for contraction.

                                        // add edge before.
                                        _target.AddEdge(xEdge.Neighbour, newVertex, firstPartEdgeData, null);

                                        // add edge after.
                                        var secondPartShape = shapeCoordinates.GetRange(1, shapeCoordinates.Count - 1);
                                        _target.AddEdge(newVertex, yEdge.Neighbour, secondPartEdgeData, new CoordinateArrayCollection<GeoCoordinateSimple>(secondPartShape.ToArray()));

                                        // remove original edge.
                                        _target.RemoveEdge(xEdge.Neighbour, yEdge.Neighbour);
                                    }

                                    toRequeue.Add(xEdge.Neighbour);
                                    newEdge++;
                                    data.ForwardWeight = forwardWeight;
                                    data.ForwardContractedId = vertex;
                                    _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, data, null, _comparer);
                                }
                            }
                            else
                            { // there is no edge, just add the data.
                                var dataXToY = new CHEdgeData();
                                dataXToY.BackwardWeight = float.MaxValue;

                                dataXToY.SetContractedDirection(false, false);

                                toRequeue.Add(xEdge.Neighbour);
                                newEdge++;
                                dataXToY.ForwardWeight = forwardWeight;
                                dataXToY.ForwardContractedId = vertex;
                                _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, dataXToY, null, _comparer);
                            }
                        }
                    }
                }
            }

            // update priority of direct neighbours.
            foreach (var neighbour in toRequeue)
            {
                this.ReQueue(neighbour);
            }

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

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

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