Skip to content

Commit

Permalink
Merge pull request #40 from itinero/features/islands
Browse files Browse the repository at this point in the history
Island detection support.
  • Loading branch information
xivk authored Feb 16, 2024
2 parents e39e907 + 2af24d6 commit e923256
Show file tree
Hide file tree
Showing 41 changed files with 2,214 additions and 244 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-092</PackageVersion>
<PackageVersion>2.0.0-alpha-100</PackageVersion>
<NeutralLanguage>en</NeutralLanguage>
<Description>Itinero - Routeplanning for .NET.</Description>
<Copyright>Itinero BV</Copyright>
Expand Down
1 change: 1 addition & 0 deletions Itinero.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=oneway/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Rabattestraat/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Routeable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=sland/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=snappable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=teirlinck/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
57 changes: 35 additions & 22 deletions src/Itinero/IO/Json/GeoJson/RouterDbExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using Itinero.Network.Attributes;
using Itinero.Network.Enumerators.Edges;
using Itinero.Network.Search;
using Itinero.Network.Search.Edges;
using Itinero.Profiles;

namespace Itinero.IO.Json.GeoJson;

Expand All @@ -21,11 +23,14 @@ public static class RouterDbExtensions
/// </summary>
/// <param name="routerDb">The router db.</param>
/// <param name="box">The bbox of the part of the network to extract.</param>
/// <param name="profiles">The profiles, if output related to profiles is needed.</param>
/// <returns>A string with geojson.</returns>
public static string ToGeoJson(this RoutingNetwork routerDb,
((double longitude, double latitude, float? e) topLeft, (double longitude, double latitude, float? e)
bottomRight)? box = null)
bottomRight)? box = null, IEnumerable<Profile>? profiles = null)
{
profiles ??= ArraySegment<Profile>.Empty;

using var stream = new MemoryStream();
using (var jsonWriter = new Utf8JsonWriter(stream))
{
Expand Down Expand Up @@ -99,7 +104,7 @@ public static void WriteFeatures(this Utf8JsonWriter jsonWriter, RoutingNetwork
var edge = edgeEnumerator.EdgeId;
if (!edges.Contains(edge))
{
jsonWriter.WriteEdgeFeature(routingNetwork.RouterDb, edgeEnumerator);
jsonWriter.WriteEdgeFeature(routingNetwork, edgeEnumerator);
edges.Add(edge);
}
}
Expand Down Expand Up @@ -127,7 +132,7 @@ public static void WriteFeatures(this Utf8JsonWriter jsonWriter, RoutingNetwork
var edge = edgeEnumerator.EdgeId;
if (!edges.Contains(edge))
{
jsonWriter.WriteEdgeFeature(routingNetwork.RouterDb, edgeEnumerator);
jsonWriter.WriteEdgeFeature(routingNetwork, edgeEnumerator);
edges.Add(edge);
}
}
Expand Down Expand Up @@ -158,7 +163,7 @@ public static void WriteVertexFeature(this Utf8JsonWriter jsonWriter, VertexId v
jsonWriter.WriteFeatureStart();
jsonWriter.WriteProperties(new (string key, string value)[]
{
("tile_id", vertexId.TileId.ToString()), ("local_id", vertexId.LocalId.ToString())
("_tile_id", vertexId.TileId.ToString()), ("_local_id", vertexId.LocalId.ToString())
});
jsonWriter.WritePropertyName("geometry");
jsonWriter.WritePoint(location);
Expand All @@ -169,40 +174,42 @@ public static void WriteVertexFeature(this Utf8JsonWriter jsonWriter, VertexId v
/// Writes an edge as a feature.
/// </summary>
/// <param name="jsonWriter">The json writer.</param>
/// <param name="routerDb">The router db.</param>
/// <param name="routingNetwork">The routing network db.</param>
/// <param name="enumerator">The enumerator.</param>
public static void WriteEdgeFeature(this Utf8JsonWriter jsonWriter,
RouterDb routerDb, IEdgeEnumerator enumerator)
RoutingNetwork routingNetwork, IEdgeEnumerator enumerator)
{
jsonWriter.WriteFeatureStart();
var attributes = enumerator.Attributes.ToList();
if (enumerator.Forward)
{
attributes.AddRange(new (string key, string value)[]
{
("tail_tile_id", enumerator.Tail.TileId.ToString()),
("tail_local_id", enumerator.Tail.LocalId.ToString()),
("head_tile_id", enumerator.Head.TileId.ToString()),
("head_local_id", enumerator.Head.LocalId.ToString()), ("edge_id", enumerator.EdgeId.ToString())
("_tail_tile_id", enumerator.Tail.TileId.ToString()),
("_tail_local_id", enumerator.Tail.LocalId.ToString()),
("_head_tile_id", enumerator.Head.TileId.ToString()),
("_head_local_id", enumerator.Head.LocalId.ToString()),
("_edge_id", enumerator.EdgeId.ToString())
});
}
else
{
attributes.AddRange(new (string key, string value)[]
{
("head_tile_id", enumerator.Tail.TileId.ToString()),
("head_local_id", enumerator.Tail.LocalId.ToString()),
("tail_tile_id", enumerator.Head.TileId.ToString()),
("tail_local_id", enumerator.Head.LocalId.ToString()), ("edge_id", enumerator.EdgeId.ToString())
("_head_tile_id", enumerator.Tail.TileId.ToString()),
("_head_local_id", enumerator.Tail.LocalId.ToString()),
("_tail_tile_id", enumerator.Head.TileId.ToString()),
("_tail_local_id", enumerator.Head.LocalId.ToString()),
("_edge_id", enumerator.EdgeId.ToString())
});
}

if (enumerator.TailOrder.HasValue) attributes.AddOrReplace("tail_order", enumerator.TailOrder.Value.ToString());
if (enumerator.HeadOrder.HasValue) attributes.AddOrReplace("head_order", enumerator.HeadOrder.Value.ToString());
if (enumerator.TailOrder.HasValue) attributes.AddOrReplace("_tail_order", enumerator.TailOrder.Value.ToString());
if (enumerator.HeadOrder.HasValue) attributes.AddOrReplace("_head_order", enumerator.HeadOrder.Value.ToString());

foreach (var profileName in routerDb.ProfileConfiguration.GetProfileNames())
foreach (var profileName in routingNetwork.RouterDb.ProfileConfiguration.GetProfileNames())
{
if (!routerDb.ProfileConfiguration.TryGetProfileHandlerEdgeTypesCache(profileName, out var edgeFactorCache,
if (!routingNetwork.RouterDb.ProfileConfiguration.TryGetProfileHandlerEdgeTypesCache(profileName, out var edgeFactorCache,
out _)) continue;

if (edgeFactorCache == null) continue;
Expand All @@ -211,14 +218,20 @@ public static void WriteEdgeFeature(this Utf8JsonWriter jsonWriter,
var factor = edgeFactorCache.Get(enumerator.EdgeTypeId.Value);
if (factor == null) continue;

attributes.AddOrReplace($"{profileName}_factor_forward",
attributes.AddOrReplace($"_{profileName}_factor_forward",
factor.Value.ForwardFactor.ToString(System.Globalization.CultureInfo.InvariantCulture));
attributes.AddOrReplace($"{profileName}_factor_backward",
attributes.AddOrReplace($"_{profileName}_factor_backward",
factor.Value.ForwardFactor.ToString(System.Globalization.CultureInfo.InvariantCulture));
attributes.AddOrReplace($"{profileName}_speed_forward",
attributes.AddOrReplace($"_{profileName}_speed_forward",
factor.Value.ForwardSpeedMeterPerSecond.ToString(System.Globalization.CultureInfo.InvariantCulture));
attributes.AddOrReplace($"{profileName}_speed_backward",
attributes.AddOrReplace($"_{profileName}_speed_backward",
factor.Value.BackwardSpeedMeterPerSecond.ToString(System.Globalization.CultureInfo.InvariantCulture));

if (!routingNetwork.IslandManager.TryGetIslandsFor(profileName, out var islands)) continue;
if (!islands.GetTileDone(enumerator.Tail.TileId)) continue;

if (factor.Value.ForwardFactor > 0) attributes.AddOrReplace($"_{profileName}_island",
islands.IsEdgeOnIsland(enumerator.EdgeId).ToString().ToLowerInvariant());
}

jsonWriter.WriteProperties(attributes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public bool MoveNext()

// get vertex, if it exists, return true.
// TODO: this check can be done faster without reading coordinates.
if (_tile.TryGetVertex(this.Current, out _, out _, out _))
if (_tile.HasVertex(this.Current))
{
return true;
}
Expand Down
3 changes: 3 additions & 0 deletions src/Itinero/Network/Mutation/IRoutingNetworkMutable.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Itinero.Data.Usage;
using Itinero.Network.DataStructures;
using Itinero.Network.Search.Islands;
using Itinero.Network.Tiles;

namespace Itinero.Network.Mutation;
Expand All @@ -8,6 +9,8 @@ internal interface IRoutingNetworkMutable
{
int Zoom { get; }

RoutingNetworkIslandManager IslandManager { get; }

RouterDb RouterDb { get; }

SparseArray<NetworkTile?> Tiles { get; }
Expand Down
11 changes: 10 additions & 1 deletion src/Itinero/Network/Mutation/RoutingNetworkMutator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Itinero.Network.DataStructures;
using Itinero.Network.Enumerators.Edges;
using Itinero.Network.Search.Islands;
using Itinero.Network.Tiles;
// ReSharper disable PossibleMultipleEnumeration

Expand All @@ -21,13 +22,16 @@ public class RoutingNetworkMutator : IDisposable, IEdgeEnumerable
private readonly SparseArray<bool> _modified;
private readonly SparseArray<NetworkTile?> _tiles;
private readonly IRoutingNetworkMutable _network;
private readonly RoutingNetworkIslandManager _islandManager;

internal RoutingNetworkMutator(IRoutingNetworkMutable network)
{
_network = network;

_tiles = _network.Tiles.Clone();
_modified = new SparseArray<bool>(_tiles.Length);

_islandManager = network.IslandManager.Clone();
}

NetworkTile? IEdgeEnumerable.GetTileForRead(uint localTileId)
Expand Down Expand Up @@ -165,6 +169,11 @@ internal IEnumerable<uint> GetTiles()
/// </summary>
public int Zoom => _network.Zoom;

/// <summary>
/// The max island size.
/// </summary>
internal RoutingNetworkIslandManager IslandManager => _network.IslandManager;

/// <summary>
/// Adds a new vertex.
/// </summary>
Expand Down Expand Up @@ -316,7 +325,7 @@ internal RoutingNetwork ToRoutingNetwork()
}

// create the new network.
var routingNetwork = new RoutingNetwork(_network.RouterDb, _tiles, _network.Zoom);
var routingNetwork = new RoutingNetwork(_network.RouterDb, _tiles, _network.Zoom, _islandManager);

// check if listeners need to be cloned/copied over.
foreach (var listener in _network.UsageNotifier.RegisteredListeners)
Expand Down
26 changes: 26 additions & 0 deletions src/Itinero/Network/RoutingNetwork.Islands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Itinero.Network.Mutation;
using Itinero.Network.Search.Islands;
using Itinero.Network.Writer;

namespace Itinero.Network;

public sealed partial class RoutingNetwork
{
internal readonly RoutingNetworkIslandManager IslandManager;

RoutingNetworkIslandManager IRoutingNetworkWritable.IslandManager
{
get
{
return IslandManager;
}
}

RoutingNetworkIslandManager IRoutingNetworkMutable.IslandManager
{
get
{
return IslandManager;
}
}
}
13 changes: 11 additions & 2 deletions src/Itinero/Network/RoutingNetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Itinero.Network.Enumerators.Edges;
using Itinero.Network.Enumerators.Vertices;
using Itinero.Network.Mutation;
using Itinero.Network.Search.Islands;
using Itinero.Network.Tiles;
using Itinero.Network.Writer;

Expand All @@ -22,18 +23,21 @@ public sealed partial class RoutingNetwork : IEdgeEnumerable, IRoutingNetworkMut
/// </summary>
/// <param name="routerDb"></param>
/// <param name="zoom"></param>
public RoutingNetwork(RouterDb routerDb, int zoom = 14)
/// <param name="maxIslandSize"></param>
public RoutingNetwork(RouterDb routerDb, int zoom = 14, int maxIslandSize = 1024)
{
this.Zoom = zoom;
this.RouterDb = routerDb;

IslandManager = new RoutingNetworkIslandManager(maxIslandSize);
_tiles = new SparseArray<NetworkTile?>(0);
}

internal RoutingNetwork(RouterDb routerDb, SparseArray<NetworkTile?> tiles, int zoom)
internal RoutingNetwork(RouterDb routerDb, SparseArray<NetworkTile?> tiles, int zoom, RoutingNetworkIslandManager islandManager)
{
this.Zoom = zoom;
this.RouterDb = routerDb;
IslandManager = islandManager;
_tiles = tiles;
}

Expand Down Expand Up @@ -81,6 +85,11 @@ internal IEnumerator<uint> GetTileEnumerator()
/// </summary>
public int Zoom { get; }

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

/// <summary>
/// Gets the routing network.
/// </summary>
Expand Down
26 changes: 26 additions & 0 deletions src/Itinero/Network/Search/Edges/EdgeChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Threading;
using System.Threading.Tasks;
using Itinero.Network.Enumerators.Edges;

namespace Itinero.Network.Search.Edges;

/// <summary>
/// Abstract definition of an edge checker.
/// </summary>
public interface IEdgeChecker
{
/// <summary>
/// A fast-path check that returns a boolean if the status of the edge is known, otherwise returns null and an advanced check needs to be done.
/// </summary>
/// <param name="edgeEnumerator"></param>
/// <returns></returns>
bool? IsAcceptable(IEdgeEnumerator<RoutingNetwork> edgeEnumerator);

/// <summary>
/// Runs the checks for the given edge.
/// </summary>
/// <param name="edgeEnumerator"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<bool> RunCheckAsync(IEdgeEnumerator<RoutingNetwork> edgeEnumerator, CancellationToken cancellationToken = default);
}
Loading

0 comments on commit e923256

Please sign in to comment.