/// <summary> /// Search forward from one vertex. /// </summary> /// <returns></returns> private void SearchForward(BinaryHeap <EdgePath <T> > queue, EdgePath <T> current) { if (current != null) { // there is a next vertex found. // check restrictions. if (_restrictions != null && _restrictions.Update(current.Vertex) && _restrictions.Restricts(current.Vertex)) { // vertex is restricted, don't settle. return; } // get the edge enumerator. var edgeEnumerator = _graph.GetEdgeEnumerator(); // add to the settled vertices. EdgePath <T> previousLinkedRoute; if (_forwardVisits.TryGetValue(current.Vertex, out previousLinkedRoute)) { if (_weightHandler.IsLargerThan(previousLinkedRoute.Weight, current.Weight)) { // settle the vertex again if it has a better weight. _forwardVisits[current.Vertex] = current; } } else { // settled the vertex. _forwardVisits.Add(current.Vertex, current); } // get neighbours. edgeEnumerator.MoveTo(current.Vertex); // add the neighbours to the queue. while (edgeEnumerator.MoveNext()) { bool?neighbourDirection; var neighbourWeight = _weightHandler.GetEdgeWeight(edgeEnumerator.Current, out neighbourDirection); if (neighbourDirection == null || neighbourDirection.Value) { // the edge is forward, and is to higher or was not contracted at all. var neighbourNeighbour = edgeEnumerator.Neighbour; if (!_forwardVisits.ContainsKey(neighbourNeighbour)) { // if not yet settled. var routeToNeighbour = new EdgePath <T>( neighbourNeighbour, _weightHandler.Add(current.Weight, neighbourWeight), current); queue.Push(routeToNeighbour, _weightHandler.GetMetric(routeToNeighbour.Weight)); } } } } }
/// <summary> /// Executes the actual algorithm. /// </summary> protected override void DoRun() { float distance; ushort edgeProfile; var enumerator1 = _source.GetEdgeEnumerator(); var enumerator2 = _source.GetEdgeEnumerator(); for (uint v = 0; v < _source.VertexCount; v++) { enumerator1.MoveTo(v); while (enumerator1.MoveNext()) { EdgeDataSerializer.Deserialize(enumerator1.Data0, out distance, out edgeProfile); var accessible1 = false; var weight1 = _weightHandler.CalculateWeightAndDir(edgeProfile, distance, out accessible1); if (enumerator1.DataInverted) { var dir = weight1.Direction; dir.Reverse(); weight1.Direction = dir; } if (!accessible1) { // not accessible. continue; } var direction1 = weight1.Direction; var edge1 = enumerator1.DirectedEdgeId(); // look at the neighbours of this edge. enumerator2.MoveTo(enumerator1.To); _restrictions.Update(enumerator1.To); while (enumerator2.MoveNext()) { var turn = new Turn(new OriginalEdge(v, enumerator1.To), Constants.NO_VERTEX); EdgeDataSerializer.Deserialize(enumerator2.Data0, out distance, out edgeProfile); var accessible2 = false; var weight2 = _weightHandler.CalculateWeightAndDir(edgeProfile, distance, out accessible2); if (enumerator2.DataInverted) { var dir = weight2.Direction; dir.Reverse(); weight2.Direction = dir; } if (!accessible2) { // not accessible. continue; } var direction2 = weight2.Direction; turn.Vertex3 = enumerator2.To; if (turn.IsUTurn) { // is a u-turn, leave this out! continue; } var direction = Dir.Combine(direction1, direction2); if (direction.F && turn.IsRestrictedBy(_restrictions)) { // turn is restricted. direction.F = false; } if (!direction.F) { // there is no possible combination for these two edges. continue; } // ok, we need to add this edge, it's a non-restricted turn, not a u-turn and edges are in correct direction. var edge2 = enumerator2.DirectedEdgeId(); _weightHandler.AddOrUpdateEdge(_target, edge1.Raw, edge2.Raw, Constants.NO_VERTEX, true, weight1.Weight); //direction.Reverse(); _weightHandler.AddOrUpdateEdge(_target, edge2.Raw, edge1.Raw, Constants.NO_VERTEX, false, weight1.Weight); } } } }
private IslandLabels _islandLabels; // island id's per edge id. /// <summary> /// Runs the island detection. /// </summary> protected override void DoRun(CancellationToken cancellationToken) { _islandLabels = new IslandLabels(); // do a run over each vertex and connect islands with bidirectional edges where possible. uint currentVertex = 0; var edgeEnumerator1 = _network.GetEdgeEnumerator(); var edgeEnumerator2 = _network.GetEdgeEnumerator(); var bestLabels = new Dictionary <uint, uint>(); while (currentVertex < _network.VertexCount) { if (!edgeEnumerator1.MoveTo(currentVertex)) { currentVertex++; continue; } // update restrictions. _restrictions?.Update(currentVertex); // log all connections. bestLabels.Clear(); var incomingOneWayEdge = -1L; uint incomingVertex = 0; var edges = 0; while (edgeEnumerator1.MoveNext()) { var edge1Factor = _profile(edgeEnumerator1.Data.Profile); if (edge1Factor.Value == 0) { // no access, don't evaluate neighbours. _islandLabels[edgeEnumerator1.Id] = IslandLabels.NoAccess; continue; } edges++; if (edge1Factor.Direction != 0) { if (incomingOneWayEdge != Constants.NO_EDGE) { // there was no bidirectional or second edge detected. if ((edgeEnumerator1.DataInverted && edge1Factor.Direction == 1) || (!edgeEnumerator1.DataInverted && edge1Factor.Direction == 2)) { if (incomingOneWayEdge < 0) { // keep edge. incomingOneWayEdge = edgeEnumerator1.Id; incomingVertex = edgeEnumerator1.To; } else { // oeps, a second incoming edge, don't keep. incomingOneWayEdge = Constants.NO_EDGE; } } } // only consider bidirectional edges in this first step. continue; } incomingOneWayEdge = Constants.NO_EDGE; // a bidirectional edge, not a candidate for one-way label propagation. // get label or provisionally set label to own id. if (!bestLabels.TryGetValue(edgeEnumerator1.Id, out var edge1Label)) { // label wasn't set yet locally, check globally. edge1Label = _islandLabels[edgeEnumerator1.Id]; if (edge1Label == IslandLabels.NotSet) { // provisionally set label to own id. edge1Label = edgeEnumerator1.Id; } bestLabels[edgeEnumerator1.Id] = edge1Label; } var turn = new Turn(new OriginalEdge(edgeEnumerator1.To, currentVertex), Constants.NO_VERTEX); // evaluate neighbours. edgeEnumerator2.MoveTo(currentVertex); while (edgeEnumerator2.MoveNext()) { if (edgeEnumerator1.Id == edgeEnumerator2.Id) { // don't evaluate u-turns. // TODO: what about loops? continue; } var edge2Factor = _profile(edgeEnumerator2.Data.Profile); if (edge2Factor.Value == 0) { // should be marked as no access in parent loop. continue; } if (edge2Factor.Direction != 0) { // only consider bidirectional edges in this first step. continue; } // check restrictions if needed. if (_restrictions != null) { turn.Vertex3 = edgeEnumerator2.To; if (turn.IsRestrictedBy(_restrictions)) { // turn is restricted. continue; } } // get label or provisionally set label to own id. if (!bestLabels.TryGetValue(edgeEnumerator2.Id, out var edge2Label)) { // label wasn't set locally, check globally. edge2Label = _islandLabels[edgeEnumerator2.Id]; if (edge2Label == IslandLabels.NotSet) { // provisionally set label to own id. edge2Label = edgeEnumerator2.Id; } bestLabels[edgeEnumerator2.Id] = edge2Label; } // bidirectional edge, choose best label. if (edge1Label < edge2Label) { bestLabels[edgeEnumerator2.Id] = edge1Label; } else { bestLabels[edgeEnumerator1.Id] = edge2Label; } } } if (incomingOneWayEdge != Constants.NO_EDGE && incomingOneWayEdge >= 0 && edges == 2) { // link sequences of oneways together. var edge1Id = (uint)incomingOneWayEdge; // we can also update neighbours if there is only one incoming edge. // get label or provisionally set label to own id. if (!bestLabels.TryGetValue(edge1Id, out var edge1Label)) { // label wasn't set yet locally, check globally. edge1Label = _islandLabels[edge1Id]; if (edge1Label == IslandLabels.NotSet) { // provisionally set label to own id. edge1Label = edge1Id; } bestLabels[edge1Id] = edge1Label; } var turn = new Turn(new OriginalEdge(incomingVertex, currentVertex), Constants.NO_VERTEX); // evaluate neighbours. edgeEnumerator2.MoveTo(currentVertex); while (edgeEnumerator2.MoveNext()) { if (edge1Id == edgeEnumerator2.Id) { // don't evaluate u-turns. // TODO: what about loops? continue; } var edge2Factor = _profile(edgeEnumerator2.Data.Profile); if (edge2Factor.Value == 0) { // should be marked as no access in parent loop. continue; } if ((edgeEnumerator2.DataInverted && edge2Factor.Direction == 1) || (!edgeEnumerator2.DataInverted && edge2Factor.Direction == 2)) { // REMARK: no need to check for bidirectionals, already done above. // only consider outgoing oneway edges. continue; } // check restrictions if needed. if (_restrictions != null) { turn.Vertex3 = edgeEnumerator2.To; if (turn.IsRestrictedBy(_restrictions)) { // turn is restricted. continue; } } // get label or provisionally set label to own id. if (!bestLabels.TryGetValue(edgeEnumerator2.Id, out var edge2Label)) { // label wasn't set locally, check globally. edge2Label = _islandLabels[edgeEnumerator2.Id]; if (edge2Label == IslandLabels.NotSet) { // provisionally set label to own id. edge2Label = edgeEnumerator2.Id; } bestLabels[edgeEnumerator2.Id] = edge2Label; } // choose best label. if (edge1Label < edge2Label) { bestLabels[edgeEnumerator2.Id] = edge1Label; } else { bestLabels[edge1Id] = edge2Label; } } } // update labels based on best labels. var labelsToUpdate = new HashSet <uint>(); foreach (var pair in bestLabels) { var edgeId = pair.Key; // the edge key. var label = pair.Value; var existing = _islandLabels[edgeId]; if (existing != IslandLabels.NotSet && existing != label && edgeId != existing) { // also make sure to update the existing label. _islandLabels[existing] = label; labelsToUpdate.Add(existing); } _islandLabels[edgeId] = label; labelsToUpdate.Add(edgeId); } foreach (var label in labelsToUpdate) { _islandLabels.UpdateLowest(label); } currentVertex++; } // update all labels to lowest possible. for (uint e = 0; e < _islandLabels.Count; e++) { _islandLabels.UpdateLowest(e); } // NOW ALL LABELLED EDGES ARE AT THEIR BEST. // do the one-way labels. var islandLabelGraph = new IslandLabelGraph(); currentVertex = 0; while (currentVertex < _network.VertexCount) { if (!edgeEnumerator1.MoveTo(currentVertex)) { currentVertex++; continue; } // update restrictions. _restrictions?.Update(currentVertex); // log all connections. while (edgeEnumerator1.MoveNext()) { var edge1Factor = _profile(edgeEnumerator1.Data.Profile); if (edge1Factor.Value == 0) { // no access, don't evaluate neighbours. _islandLabels[edgeEnumerator1.Id] = IslandLabels.NoAccess; continue; } if ((edgeEnumerator1.DataInverted && edge1Factor.Direction == 2) || !edgeEnumerator1.DataInverted && edge1Factor.Direction == 1) { // wrong direction, this edge is oneway away from current vertex. continue; } var turn = new Turn(new OriginalEdge(edgeEnumerator1.To, currentVertex), Constants.NO_VERTEX); // get label or set to own id. var edge1Label = _islandLabels[edgeEnumerator1.Id]; if (edge1Label == IslandLabels.NotSet) { edge1Label = edgeEnumerator1.Id; _islandLabels[edge1Label] = edge1Label; } // evaluate neighbours. edgeEnumerator2.MoveTo(currentVertex); while (edgeEnumerator2.MoveNext()) { if (edgeEnumerator1.Id == edgeEnumerator2.Id) { // don't evaluate u-turns. // TODO: what about loops? continue; } var edge2Factor = _profile(edgeEnumerator2.Data.Profile); if (edge2Factor.Value == 0) { // should be marked as no access in parent loop. continue; } if ((edgeEnumerator2.DataInverted && edge2Factor.Direction == 1) || !edgeEnumerator2.DataInverted && edge2Factor.Direction == 2) { // wrong direction, this edge is oneway away from current vertex. continue; } // check restrictions if needed. if (_restrictions != null) { turn.Vertex3 = edgeEnumerator2.To; if (turn.IsRestrictedBy(_restrictions)) { // turn is restricted. continue; } } // get label or set to own id. var edge2Label = _islandLabels[edgeEnumerator2.Id]; if (edge2Label == IslandLabels.NotSet) { edge2Label = edgeEnumerator2.Id; _islandLabels[edge2Label] = edge2Label; } if (edge1Label != edge2Label) { islandLabelGraph.Connect(edge1Label, edge2Label); } } } currentVertex++; } Itinero.Logging.Logger.Log($"{nameof(EdgeBasedIslandDetector)}.{nameof(Run)}", TraceEventType.Verbose, "Built directional graph."); // calculate all loops with increasing max settle settings until they are unlimited and all loops are removed. uint maxSettles = 1; Itinero.Logging.Logger.Log($"{nameof(EdgeBasedIslandDetector)}.{nameof(Run)}", TraceEventType.Verbose, $"Label graph has {islandLabelGraph.LabelCount} labels."); while (true) { Itinero.Logging.Logger.Log($"{nameof(EdgeBasedIslandDetector)}.{nameof(Run)}", TraceEventType.Verbose, $"Running loop detection with {maxSettles}."); var lastRun = maxSettles > islandLabelGraph.LabelCount; // find loops. islandLabelGraph.FindLoops(maxSettles, _islandLabels, (oldLabel, newLabel) => { _islandLabels[oldLabel] = newLabel; }); // update all labels to lowest possible. for (uint e = 0; e < _islandLabels.Count; e++) { _islandLabels.UpdateLowest(e); } if (lastRun) { break; } // reduce graph. var labelCount = islandLabelGraph.Reduce(_islandLabels); Itinero.Logging.Logger.Log($"{nameof(EdgeBasedIslandDetector)}.{nameof(Run)}", TraceEventType.Verbose, $"Label graph now has {labelCount} non-empty labels."); maxSettles = (uint)_network.EdgeCount; } this.HasSucceeded = true; }
/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { // while the visit list is not empty. var cPointer = uint.MaxValue; while (cPointer == uint.MaxValue) { // choose the next edge. if (_pointerHeap.Count == 0) { return(false); } cPointer = _pointerHeap.Pop(); } // get details. uint cEdge, cPreviousPointer; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cEdge, out cWeight, out cPreviousPointer); if (_visits.Contains(cEdge)) { return(true); } _visits.Add(cEdge); var cDirectedEdge = new DirectedEdgeId() { Raw = cEdge }; // signal was found. if (this.WasFound != null) { this.WasFound(cPointer, cDirectedEdge, cWeight); } // move to the current edge's target vertex. _edgeEnumerator.MoveToEdge(cDirectedEdge.EdgeId); var cOriginalEdge = new OriginalEdge(_edgeEnumerator.From, _edgeEnumerator.To); if (!cDirectedEdge.Forward) { cOriginalEdge = cOriginalEdge.Reverse(); } var cEdgeWeightAndDirection = _weightHandler.GetEdgeWeight(_edgeEnumerator); // calculate total weight. var totalWeight = _weightHandler.Add(cEdgeWeightAndDirection.Weight, cWeight); if (!_weightHandler.IsSmallerThan(totalWeight, _sourceMax)) { // weight is too big. this.MaxReached = true; return(true); } // loop over all neighbours. _edgeEnumerator.MoveTo(cOriginalEdge.Vertex2); var turn = new Turn(cOriginalEdge, Constants.NO_VERTEX); _restrictions.Update(turn.Vertex2); while (_edgeEnumerator.MoveNext()) { turn.Vertex3 = _edgeEnumerator.To; if (turn.IsUTurn || turn.IsRestrictedBy(_restrictions)) { // turn is restricted. continue; } var nDirectedEdgeId = _edgeEnumerator.DirectedEdgeId(); if (_visits.Contains(nDirectedEdgeId.Raw)) { // has already been choosen. continue; } // get the speed from cache or calculate. var nWeightAndDirection = _weightHandler.GetEdgeWeight(_edgeEnumerator); var nWeightMetric = _weightHandler.GetMetric(nWeightAndDirection.Weight); if (nWeightMetric <= 0) { // edge is not valid for profile. continue; } if (!_backward && !nWeightAndDirection.Direction.F) { // cannot do forward search on edge. continue; } if (_backward && !nWeightAndDirection.Direction.B) { // cannot do backward on edge. continue; } // update the visit list. _pointerHeap.Push(_weightHandler.AddPathTree(_pathTree, nDirectedEdgeId.Raw, totalWeight, cPointer), _weightHandler.GetMetric(totalWeight)); } return(true); }
/// <summary> /// Contracts the given vertex. /// </summary> private void Contract(uint vertex) { // get and keep edges. var edges = new List <MetaEdge>(_graph.GetEdgeEnumerator(vertex)); // remove 'downward' edge to vertex. var i = 0; while (i < edges.Count) { _graph.RemoveEdge(edges[i].Neighbour, vertex); if (_contractedFlags[edges[i].Neighbour]) { // neighbour was already contracted, remove 'downward' edge and exclude it. _graph.RemoveEdge(vertex, edges[i].Neighbour); edges.RemoveAt(i); } else { // move to next edge. i++; } } // check for a restriction, if vertex is restricted don't add shortcuts. if (_restrictions != null && _restrictions.Update(vertex)) { if (_restrictions.Restricts(vertex)) { return; } } // loop over all edge-pairs once. for (var j = 1; j < edges.Count; j++) { var edge1 = edges[j]; bool?edge1Direction; var edge1Weight = _weightHandler.GetEdgeWeight(edge1, out edge1Direction); var edge1CanMoveForward = edge1Direction == null || edge1Direction.Value; var edge1CanMoveBackward = edge1Direction == null || !edge1Direction.Value; // figure out what witness paths to calculate. var forwardWitnesses = new bool[j]; var backwardWitnesses = new bool[j]; var targets = new List <uint>(j); var targetWeights = new List <T>(j); var targetMetrics = new List <float>(j); for (var k = 0; k < j; k++) { var edge2 = edges[k]; bool?edge2Direction; var edge2Weight = _weightHandler.GetEdgeWeight(edge2, out edge2Direction); var edge2CanMoveForward = edge2Direction == null || edge2Direction.Value; var edge2CanMoveBackward = edge2Direction == null || !edge2Direction.Value; // use witness flags to represent impossible routes. forwardWitnesses[k] = !(edge1CanMoveBackward && edge2CanMoveForward); backwardWitnesses[k] = !(edge1CanMoveForward && edge2CanMoveBackward); targets.Add(edge2.Neighbour); var totalWeight = _weightHandler.Add(edge1Weight, edge2Weight); targetWeights.Add(totalWeight); targetMetrics.Add(_weightHandler.GetMetric(totalWeight)); } // calculate all witness paths. _witnessCalculator.Calculate(_graph.Graph, edge1.Neighbour, targets, targetMetrics, ref forwardWitnesses, ref backwardWitnesses, vertex); // add contracted edges if needed. for (var k = 0; k < j; k++) { var edge2 = edges[k]; if (edge1.Neighbour == edge2.Neighbour) { // do not try to add a shortcut between identical vertices. continue; } if (!forwardWitnesses[k] && !backwardWitnesses[k]) { // add bidirectional edge. _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, null, targetWeights[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // targetWeights[k], null, vertex); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, null, targetWeights[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // targetWeights[k], null, vertex); } else if (!forwardWitnesses[k]) { // add forward edge. _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, true, targetWeights[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // targetWeights[k], true, vertex); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, false, targetWeights[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // targetWeights[k], false, vertex); } else if (!backwardWitnesses[k]) { // add forward edge. _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, false, targetWeights[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // targetWeights[k], false, vertex); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, true, targetWeights[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // targetWeights[k], true, vertex); } } } _contractedFlags[vertex] = true; _priorityCalculator.NotifyContracted(vertex); }