Custom model - Areas

Hello,

I need to avoid points when routing. So far the only out of the box way in graphhopper i found are the Areas that can be added to a Custom model.
As there is no support for a simple Point, i put little bounding boxes around the points to avoid and fed them to the Custom model as a Multipolygon.

First question: I only saw docs and examples that used Polygons which where added separately with its own key. The multipolygon way seems to work so far, but is there something i should know about the implementation of graphhopper? Is there a reason why i should not do it?

    MultiPolygon multiPolygon = new GeometryFactory().createMultiPolygon(polygons);
    areas.put("avoid", new JsonFeature("avoid",
            "Feature",
            null,
            multiPolygon,
            new HashMap<>()));

    customModel.setAreas(areas);

    customModel.addToPriority(If("in_avoid", MULTIPLY, request.avoidPrio)); // 0.001 -> nearly total avoidance

Second question: For first tests i only imported Austria/Small countries and about 20k points/surrounding polygons.
In the end about 18 million points and whole europe should be used for this. Will this be possible? Or should i already search for an other way i maybe did not see in the documentation and examples?

Third question: Are the areas in the custom model added to the “routing-graph-cache” in the initialization step or are they only used later at routing? (Or: Is the heavy lifting done at preparation of the cache, or later)

Thanks in advance for help,
Max

This is an interesting use case. Avoiding 18 million points wasn’t done before so we don’t know how this performs in the custom weighting. Would be interesting if this works :slight_smile:

If you use a CH preparation then most of the heavy work is done at preparation time, but the “avoidance object” (a spatial index) is still created and also used for base graph edges.

If this makes problems you can define a custom area where the edges are marked with “areaX” which you can then use in the CustomWeighting without any heavy lookup.

Thanks for the answer.
I instantly upgraded from 3.2 to 4.0 and went for the custom areas.

GraphHopper hopper = new GraphHopper();
hopper.setCustomAreasDirectory(“C:\graphhopper\areas”);
For the geojson i used the country geojson that is already bundled with graphhopper for testing purposes.

Then i extended some of the classes of Graphhopper and used them to set some breakpoints and later modify the stuff:

EncodingManager encodingManager = EncodingManager.create(new MaxMotorcycleFlagEncoder());
hopper.setEncodedValueFactory(new MaxEncodedValueFactory());
hopper.setFlagEncoderFactory(new MaxFlagEncoderFactory());
hopper.setTagParserFactory(new MaxTagParserFactory());

When initializing Graphhopper, i jump into a Breakpoint in the handleWayTags in the FlagEncoder and there i find the custom area properties in: ReaderWay way

So far so good.

But now i am stuck. It seems that this custom area is on way level, but not on Node level. I do not want to prevent the whole way if it is hit by such a “avoid” box, but only this connection.

In the drawing below: If i route from Dot 1 to Dot 4, i want to give the connection from 1 to 2 a low weight, but not the whole way 1 (black ink dots 1-2-3-4)

photo_2021-10-14_13-46-04

Maybe i am blind but i do not find anything related to my problem here. Which Classes should i look into to extend / override / modify to get to my goal here?

Or: Did i fundamentally not understand the concept way in this case.

Is the way the original full OSM Way, or already an split part of an OSM Way from one connection to another, so more like an edge in a Graph?

No, your understanding is correct. The way is the full OSM way, yes. GraphHopper maintains ‘edge flags’ to store attributes of an edge of the routing graph. These edge flags are mostly determined by the OSM way tags, so calculating the edge flags once and applying them to all graph edges that a given OSM way is split into is correct and saves (some) time during the import. BUT there are cases where the edge flags of the different edges an OSM way is split into should still be different. Your case is one such case: If an OSM way crosses an area and that way is split into multiple edges it is no longer justified to assume the edge attributes of all these edges are supposed to be the same. Another example are edges that include nodes with certain tags (like traffic signals).

For the bundled country geojson file this is fine, because OSM ways typically stop at country borders, but for your custom areas this might not work indeed. Just like we only calculate the edge flags once per way (and not once per edge) we also do the custom area (or country) lookup only once per way (and not once per edge). So the first thing you would have to do is to postpone this area lookup until the OSM way is split into edges.

You need to move this code: https://github.com/graphhopper/graphhopper/blob/142b9adf4141014404f71e71c593250153d54c89/core/src/main/java/com/graphhopper/reader/osm/OSMReader.java#L359-L381 as well as the handleWayTags call here: https://github.com/graphhopper/graphhopper/blob/142b9adf4141014404f71e71c593250153d54c89/core/src/main/java/com/graphhopper/reader/osm/OSMReader.java#L382 further down into addEdge in OSMReader. But yes what you are trying to achieve is currently no designated functionality of GraphHopper, so you might have to tweak it a bit (but should be doable).

We are actually in the process of moving down this handleWayTags call currently, so maybe also follow the development in the master branch.

Using the method I described above you should be able to determine the custom area per edge (not only per way) and modify the edge flags accordingly. What would be a lot harder though is explicitly splitting the OSM ways at the borders of your custom areas.

Your use-case might actually be reason enough to postpone the area lookup and do it per edge instead of per way.

Thanks, things are a little bit clearer now.

Have to decide if i go this way now and stir around in the actual library code itself or follow the original path with the custom Model and Areas there.

But then i would have to ask: Does the original idea (first posting in this thread) also handle it on way basis or is that one on edge basis?

On edge basis.

Powered by Discourse