Skip to content

Commit

Permalink
Rebuild island detection algorithm with better stopping conditions.
Browse files Browse the repository at this point in the history
  • Loading branch information
xivk committed Feb 23, 2024
1 parent dbd979f commit db0e353
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 133 deletions.
2 changes: 1 addition & 1 deletion Itinero.Common.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<!--- Package information, Version -->
<PropertyGroup>
<PackageVersion>2.0.1-alpha-102</PackageVersion>
<PackageVersion>2.0.1-alpha-103</PackageVersion>
<NeutralLanguage>en</NeutralLanguage>
<Description>Itinero - Routeplanning for .NET.</Description>
<Copyright>Itinero BV</Copyright>
Expand Down
5 changes: 0 additions & 5 deletions src/Itinero/Network/RoutingNetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,6 @@ internal IEnumerator<uint> GetTileEnumerator()
/// </summary>
public int Zoom { get; }

public int GetMaxIslandSize()
{
throw new NotImplementedException();
}

/// <summary>
/// Gets the routing network.
/// </summary>
Expand Down
15 changes: 8 additions & 7 deletions src/Itinero/Network/Search/Islands/ICostFunctionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ internal static class ICostFunctionExtensions
{
/// <summary>
/// Gets the cost of a turn from the previous edges sequence to the given edge in the enumerator in a forward direction.
///
///
/// This does NOT include the cost of the previous edges.
/// </summary>
/// <param name="costFunction"></param>
/// <param name="enumerator"></param>
/// <param name="previousEdges"></param>
/// <returns></returns>
/// <param name="costFunction">The cost function.</param>
/// <param name="enumerator">The edge to test.</param>
/// <param name="forward">Then true, calculate the cost including turn cost from (previousEdge ->) enumerator.tail -> enumerator.edge -> enumerator.head, when false (previousEdge ->) enumerator.head -> enumerator.edge -> enumerator.tail</param>
/// <param name="previousEdges">A sequence of previously traversed edge, if any.</param>
/// <returns>True if the current edge is traversable and the turn cost allows the turn.</returns>
public static bool GetIslandBuilderCost(this ICostFunction costFunction,
RoutingNetworkEdgeEnumerator enumerator, IEnumerable<(EdgeId edgeId, byte? turn)>? previousEdges = null)
RoutingNetworkEdgeEnumerator enumerator, bool forward = true, IEnumerable<(EdgeId edgeId, byte? turn)>? previousEdges = null)
{
var cost = costFunction.Get(enumerator, true, previousEdges);
var cost = costFunction.Get(enumerator, forward, previousEdges);

return cost is { canAccess: true, turnCost: < double.MaxValue };
}
Expand Down
257 changes: 159 additions & 98 deletions src/Itinero/Network/Search/Islands/IslandBuilder.cs

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions src/Itinero/Network/Search/Islands/IslandLabels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@ internal class IslandLabels
/// - When edges are bidirectionally connected they get take on the lowest Id of their neighbour.
/// </summary>
private readonly Dictionary<EdgeId, uint> _labels = new();
private readonly Dictionary<uint, (uint size, bool statusNotFinal)> _islands = new(); // holds the size per island.
private readonly Dictionary<uint, (uint size, bool final)> _islands = new(); // holds the size per island.
private readonly IslandLabelGraph _labelGraph = new();
private readonly int _maxIslandSize;

internal IslandLabels(int maxIslandSize)
{
_maxIslandSize = maxIslandSize;
_islands.Add(0, (uint.MaxValue, false));
_islands.Add(0, (uint.MaxValue, true));
_labelGraph.AddVertex();
}

/// <summary>
/// Gets all the islands.
/// </summary>
public IEnumerable<(uint label, uint size, bool statusNotFinal)> Islands
public IEnumerable<(uint label, uint size, bool final)> Islands
{
get
{
foreach (var (label, (size, statusNotFinal)) in _islands)
foreach (var (label, (size, final)) in _islands)
{
yield return (label, size, statusNotFinal);
yield return (label, size, final);
}
}
}
Expand All @@ -47,16 +47,16 @@ internal IslandLabels(int maxIslandSize)
/// Creates a new label.
/// </summary>
/// <returns></returns>
public (uint label, uint size, bool statusNotFinal) AddNew(EdgeId edge, bool statusNotFinal = true)
public (uint label, uint size, bool final) AddNew(EdgeId edge, bool final = false)
{
if (_labels.ContainsKey(edge)) throw new ArgumentOutOfRangeException(nameof(edge));

var label = _labelGraph.AddVertex();

_labels[edge] = label;
_islands[label] = (1, statusNotFinal);
_islands[label] = (1, final);

return (label, 1, statusNotFinal);
return (label, 1, final);
}

/// <summary>
Expand All @@ -65,12 +65,12 @@ internal IslandLabels(int maxIslandSize)
/// <param name="label"></param>
/// <param name="edge"></param>
/// <returns></returns>
public (uint label, uint size, bool statusNotFinal) AddTo(uint label, EdgeId edge)
public (uint label, uint size, bool final) AddTo(uint label, EdgeId edge)
{
if (!_islands.TryGetValue(label, out var islandDetails)) throw new ArgumentOutOfRangeException(nameof(label));

if (islandDetails.size < uint.MaxValue) islandDetails.size += 1;
_islands[label] = (islandDetails.size, islandDetails.statusNotFinal);
_islands[label] = (islandDetails.size, final: islandDetails.final);
_labels[edge] = label;

if (_islands[label].size >= _maxIslandSize &&
Expand All @@ -79,12 +79,12 @@ internal IslandLabels(int maxIslandSize)
// this island just grew over the maximum.
this.Merge([label, NotAnIslandLabel]);
var labelDetails = _islands[NotAnIslandLabel];
return (NotAnIslandLabel, labelDetails.size, islandDetails.statusNotFinal);
return (NotAnIslandLabel, labelDetails.size, final: islandDetails.final);
}
else
{
var labelDetails = _islands[label];
return (label, labelDetails.size, islandDetails.statusNotFinal);
return (label, labelDetails.size, final: islandDetails.final);
}
}

Expand Down Expand Up @@ -153,28 +153,28 @@ public bool TryGet(EdgeId edge, out uint label)
/// <param name="edge"></param>
/// <param name="island"></param>
/// <returns></returns>
public bool TryGetWithDetails(EdgeId edge, out (uint label, uint size, bool statusNotFinal) island)
public bool TryGetWithDetails(EdgeId edge, out (uint label, uint size, bool final) island)
{
island = (0, 0, true);
island = (0, 0, false);
if (!_labels.TryGetValue(edge, out var label)) return false;

if (!_islands.TryGetValue(label, out var islandState))
throw new Exception("Island does not exist");

island = (label, islandState.size, statusNotFinal: islandState.statusNotFinal);
island = (label, islandState.size, final: islandState.final);
return true;
}

/// <summary>
/// Sets the given island as complete, it cannot grow any further.
/// Sets the given island as final, it cannot grow any further.
/// </summary>
/// <param name="label">The label of the island.</param>
public void SetAsComplete(uint label)
public void SetAsFinal(uint label)
{
if (!_islands.TryGetValue(label, out var islandState))
throw new Exception("Island does not exist");

_islands[label] = (islandState.size, false);
_islands[label] = (islandState.size, true);
}

private bool FindLoops(uint label)
Expand Down
2 changes: 1 addition & 1 deletion src/Itinero/Routing/Costs/ICostFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface ICostFunction
/// Gets the costs associated with the given network edge.
/// </summary>
/// <param name="edgeEnumerator">The edge enumerator.</param>
/// <param name="forward">The forward flag, when true the cost in the direction of the current edge enumerator, otherwise against. When null returns true if can stop is true in at least one direction.</param>
/// <param name="forward">The forward flag, when true the cost in the direction of the current edge enumerator, otherwise against.</param>
/// <param name="previousEdges">The previous edges. Should correspond with what the forward flag indicates.</param>
/// <returns>The access flags, stop flags, cost and turn cost.</returns>
public (bool canAccess, bool canStop, double cost, double turnCost) Get(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@ public async Task IslandBuilder_IsOnIsland_OneEdgeWithThreeEdgeLoop_ShouldBeOneI
{
await IslandBuilder.IsOnIslandAsync(routerDb.Latest, labels,
routerDb.Latest.GetCostFunctionFor(new DefaultProfile()), edge);
await IslandBuilder.IsOnIslandAsync(routerDb.Latest, labels,
routerDb.Latest.GetCostFunctionFor(new DefaultProfile()), edge);
}

Assert.Single(labels.Islands);
Expand Down Expand Up @@ -265,7 +263,7 @@ public async Task IslandBuilder_IsOnIsland_OneIslandWithNonConnectedEdge_ShouldB
}

[Fact]
public async Task IslandBuilder_IsOnIsland_EdgeConnectedToNoneIslandNeighbour_ShouldReturnFalse()
public async Task IslandBuilder_IsOnIsland_EdgeConnectedToNotOnIslandNeighbour_ShouldReturnFalse()
{
var routerDb = new RouterDb();
var edges = new List<EdgeId>();
Expand Down

0 comments on commit db0e353

Please sign in to comment.