itinero / routing

The routing core of itinero.
Apache License 2.0
222 stars 70 forks source link

Ability to add edge to RouterDb with profile #287

Open EngineerCoding opened 4 years ago

EngineerCoding commented 4 years ago

Hi Ben,

I am currently developing an app which uses Itinero for it's navigation, and therefore I am loading the RouterDb with a RouterDbProfile when deserializing. For my use I have to dynamically add and remove edges to this database. While removing an edge removes the edge in the underlying routerdb file, adding an edge is currently not possible, as I get the following exception:

11-29 17:10:48.253 E/mono-rt (29975): [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Array cannot be resized.
11-29 17:10:48.253 E/mono-rt (29975):   at Reminiscence.Arrays.Array`1[T].Resize (System.Int64 size) [0x00013] in <34cbb9d2f37d48ed99d5ae90724baee0>:0 
11-29 17:10:48.253 E/mono-rt (29975):   at Itinero.Extensions.IncreaseMinimumSize[T] (Reminiscence.Arrays.ArrayBase`1[T] array, System.Int64 minimumSize, System.Boolean fillEnd, T fillValueIfNeeded) [0x00022] in <bd12cef2a4d44ab0ad982e4dcdee54b1>:0 
11-29 17:10:48.253 E/mono-rt (29975):   at Itinero.Extensions.EnsureMinimumSize[T] (Reminiscence.Arrays.ArrayBase`1[T] array, System.Int64 minimumSize, T fillValue) [0x00009] in <bd12cef2a4d44ab0ad982e4dcdee54b1>:0 
11-29 17:10:48.253 E/mono-rt (29975):   at Itinero.Graphs.Graph.AddEdge (System.UInt32 vertex1, System.UInt32 vertex2, System.UInt32[] data) [0x0017a] in <bd12cef2a4d44ab0ad982e4dcdee54b1>:0 
11-29 17:10:48.253 E/mono-rt (29975):   at Itinero.Graphs.Geometric.GeometricGraph.AddEdge (System.UInt32 vertex1, System.UInt32 vertex2, System.UInt32[] data, Itinero.Graphs.Geometric.Shapes.ShapeBase shape) [0x00000] in <bd12cef2a4d44ab0ad982e4dcdee54b1>:0 
11-29 17:10:48.253 E/mono-rt (29975):   at Itinero.Data.Network.RoutingNetwork.AddEdge (System.UInt32 vertex1, System.UInt32 vertex2, Itinero.Data.Network.Edges.EdgeData data, Itinero.Graphs.Geometric.Shapes.ShapeBase shape) [0x00035] in <bd12cef2a4d44ab0ad982e4dcdee54b1>:0 

After some digging, I found out this is because the underlying Reminiscence.Arrays.Array is created without a _createAccessor parameter, which results in the above exception.

When the RouterDb is loaded without profile, I can make modifications to the RoutingNetwork however I please, as it is loaded in memory and therefore does not make modifications on the underlying RouterDb. As I am developing for mobile I would like to avoid loading the whole routerdb into memory. Is it possible to add support for adding edges to the RoutingNetwork? And if you don't have time, where should I start if I were to make a PR?

I also have a suggestion in case this is not possible at all: please make changes to the RoutingNetwork consistent depending on how the RouterDb is loaded; if you are only able to delete edges (which are persisted) and not able to add edges, is there a real point to this?

Later edit

I dug deeper and realised that you don't allow adding edges to those files dynamically simply for the fact that you cannot actually expand the array on file, because there is presumably more date behind the edge data which you can't dynamically move with ease. So ignore my suggestion.

For my use case I am only deleting and adding edges back again; never beyond the array limit. Because I am saving the EdgeId, I can simply update the edge with data again and it magically should work, at least, there is one caveat: when a Edge in the network is removed, the shape is removed as well. This shape can never be updated again similar to the edge data (at least not cleanly, I can always Reflection if I really wanted). Therefore I would like to ask for this support: updating shape data in the RoutingNetwork, which is actually fairly easy to implement.

Some thought later:

Since the reference to the Graph (through the exposed GeometricGraph in RoutingNetwork) is available, I can just delete the edge in that object instead of from the RoutingNetwork, maintaining the Shape data.

TL;DR: I found a solution to my problem. I will leave this open in case you get some ideas from this to implement; feel free to close this.

This actually won't work as vertex data is modified as well (such as pointers to the next edge). It would be nice to be able to replace an Edge in the Graph object; that should solve all my issues.