itinero / routing

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

Search problem #231

Closed fromm1990 closed 5 years ago

fromm1990 commented 5 years ago

Hi, if I do a feature search as follows:

using (var stream = new FileInfo("path/to/denmark-latest.routerdb").OpenRead())
{
    var routerDb = RouterDb.Deserialize(stream);
    var result = routerDb.GetFeaturesIn(57.01883402189333339f, 9.98327245393100071f, 57.0198080079025118f, 9.98551109193115494f);
}

I will receive an empty FeatureCollection. It is worth mentioning that my bounding box does not contain any vertices, however, it do intersect with an edge.

image

The image above, represents the search failing. The vertices closest to the two roads intersecting the bounding box is placed at the two roundabouts.

hilbersearchproblem

The above image illustrates an edge AB with the two vertices a and b. The green bounding boxes yields the vertex a, b and edge AB respectively where the red bounding box will yield no result. My assumption is that this is caused as the red bounding box is not in the same tile or even neighbourhood as one of the two vertices. Is this correct?

A temporary fix, I use, is to utilise the R-Tree implementation offered by NTS and then use the routerDb to gather the edges. However, this uses approximately twice the memory as the R-Tree has to be stored in memory. Also, building the R-Tree will add an delay to the startup of the process.

using (var stream = new FileInfo("path/to/denmark-latest.routerdb").OpenRead())
{
    var routerDb = RouterDb.Deserialize(stream);
    var searchTree = new STRtree<uint>();

    for (uint i = 0; i < routerDb.Network.EdgeCount; i++)
    {
        var edge = routerDb.GetFeatureForEdge(i);
        searchTree.Insert(edge.Geometry.EnvelopeInternal, i);
    }

    searchTree.Build();

    var query = new Envelope(9.98327245393100071, 9.98551109193115494, 57.0198080079025118, 57.01883402189333339);
    var queryResult = searchTree.Query(query);

    var finalResult = queryResult.Select(x => routerDb.GetFeatureForEdge(x)).ToList();
}

Is there a way to grab all edges intersecting an bounding box, without relying on the edges being nearby?

xivk commented 5 years ago

There is no way to search without going via the vertices.

There is however a way to remedy this because the routerdb has a parameter that sets the maximum length for an edge and it will split an edge when it's too long. This will limit the bbox you have to use to search to make sure you find all edges nearby but does introduce extra vertices.

It's a tradeoff between two imperfect solutions, the current one where searching for edges is not perfect or another where building an R-tree is needed with all the disadvantages that come with it.

fromm1990 commented 5 years ago

Thanks for the quick answer! What is the name of the mentioned "max length" parameter? Furthermore, do you recall its default value?

xivk commented 5 years ago

By default it's set here:

https://github.com/itinero/routing/blob/develop/src/Itinero/RouterDb.cs#L57

To this value:

https://github.com/itinero/routing/blob/develop/src/Itinero/Constants.cs#L44

fromm1990 commented 5 years ago

Thank you for the help!