GIScience / openrouteservice

🌍 The open source route planner api with plenty of features.
https://openrouteservice.org
GNU General Public License v3.0
1.33k stars 379 forks source link

Extra Info - Surface returns paved instead of grass #1779

Closed michalgwo closed 1 month ago

michalgwo commented 2 months ago

Is there an existing issue for this?

Where did you encounter this issue?

live API

Request URL

https://api.openrouteservice.org/v2/directions/foot-hiking

POST Request Body

{"coordinates":[[22.073188748039968,50.07627785073141],[22.070565109315112,50.07965530579527]],"elevation":true,"extra_info":["steepness","surface","waytype","traildifficulty","green","noise","shadow"],"instructions":false}

Response

Response ```JSON {"bbox":[22.070557,50.076361,192.39,22.075215,50.07975,193.79],"routes":[{"summary":{"distance":1042.2,"duration":750.4,"ascent":1.9,"descent":1.4},"bbox":[22.070557,50.076361,192.39,22.075215,50.07975,193.79],"geometry":"gpspH_dveCyvd@CICMKEeAAKSGIy@]F_@UB]a@BQUHs@aBn@[aA`@[_B@GO?OADc@@D_AV@i@T@m@f@Pw@b@`@WZNADDHLBf@p@IlAtAk@rDT_BXFMPVCPj@MFl@ABt@MClAGCx@IWz@MW^Ec@ZYw@^OuFXh@KDRELNBxA{@","way_points":[0,39],"warnings":[{"code":4,"message":"Extra info requested but not available: shadow"}],"extras":{"green":{"values":[[0,39,10]],"summary":[{"value":10.0,"distance":1042.2,"amount":100.0}]},"surface":{"values":[[0,39,1]],"summary":[{"value":1.0,"distance":1042.2,"amount":100.0}]},"waytypes":{"values":[[0,39,5]],"summary":[{"value":5.0,"distance":1042.2,"amount":100.0}]},"steepness":{"values":[[0,39,0]],"summary":[{"value":0.0,"distance":1042.2,"amount":100.0}]},"noise":{"values":[[0,39,7]],"summary":[{"value":7.0,"distance":1042.2,"amount":100.0}]},"traildifficulty":{"values":[[0,39,0]],"summary":[{"value":0.0,"distance":1042.2,"amount":100.0}]}}}],"metadata":{"attribution":"openrouteservice.org | OpenStreetMap contributors","service":"routing","timestamp":1712934136795,"query":{"coordinates":[[22.073188748039968,50.07627785073141],[22.070565109315112,50.07965530579527]],"profile":"foot-hiking","format":"json","elevation":true,"extra_info":["steepness","surface","waytype","traildifficulty","green","noise","shadow"]},"engine":{"version":"8.0.0","build_date":"2024-03-21T13:55:54Z","graph_date":"2024-04-08T23:04:37Z"}}} ```

Current behavior

The problem is with extra info - surface value. Currently, it returns paved, but the value in OpenStreetMap is grass.

Same behaviour you can observe in the Maps Tool: https://maps.openrouteservice.org/#/directions/Stary%20Wislok,Krasne,PK,Poland/Stary%20Wislok,Krasne,PK,Poland/data/55,130,32,198,15,97,4,224,38,9,96,59,2,24,5,192,166,6,113,0,184,64,38,124,3,160,1,128,118,1,152,1,103,192,70,42,200,3,159,51,236,113,128,104,5,97,52,178,3,100,111,223,21,90,1,57,25,137,44,192,55,33,62,180,89,117,107,68,151,49,203,186,247,40,202,149,126,37,197,141,171,76,151,16,28,64,64,0,234,158,4,68,216,114,128,5,229,0,45,174,90,253,47,94,129,0,12,222,0,6,221,23,4,0,42,21,0,22,128,2,222,0,26,201,0,28,194,196,15,221,0,61,26,29,17,12,12,47,7,50,29,221,215,54,29,22,4,0,23,202,168,0

image

After creating this issue I found 2 more cases with the wrong surface.

In this case, the surface is not set, so it should be unknown, but returns paved again: https://maps.openrouteservice.org/#/directions/%C5%81%C4%85ka%2050,%C5%81%C4%85ka,PK,Poland/%C5%81%C4%85ka%2055,%C5%81%C4%85ka,PK,Poland/data/55,130,32,198,15,97,4,224,38,9,96,59,2,24,5,192,166,6,113,0,184,64,38,124,3,160,1,128,78,1,25,240,21,159,0,56,72,25,129,252,1,99,32,26,106,77,46,178,73,32,13,144,73,106,1,217,5,212,16,27,144,169,50,52,41,208,104,53,184,218,140,184,247,33,76,173,65,253,89,140,102,76,72,14,32,32,0,117,79,2,34,108,57,64,2,242,128,22,215,5,65,22,175,64,128,12,222,0,6,221,23,4,31,202,21,0,22,128,2,222,0,26,201,0,28,220,196,23,221,31,221,26,29,17,12,20,47,27,50,13,205,199,54,29,22,4,0,23,210,168,0,0

In this case, OpenRouteService returns unpaved, but OSM tags are cycleway:surface=asphalt + footway:surface=paving_stones (there is no surface tag): https://maps.openrouteservice.org/#/directions/Warszawska,G%C5%82og%C3%B3w%20Ma%C5%82opolski%20Obszar%20Wiejski,PK,Poland/Zaczernie%20811A,Zaczernie,PK,Poland/data/55,130,32,198,15,97,4,224,38,9,96,59,2,24,5,192,166,6,113,0,184,64,38,1,24,3,160,19,128,14,1,152,1,100,32,118,124,24,21,128,54,58,234,114,128,104,152,1,152,222,228,234,23,201,84,175,118,249,198,150,160,27,136,153,114,133,10,183,171,210,139,37,164,152,247,235,212,148,150,164,89,180,45,92,185,38,32,184,128,128,1,213,60,8,137,176,229,0,11,202,0,91,92,133,72,219,182,128,128,3,55,128,1,183,69,193,6,10,133,64,5,160,0,183,128,6,178,64,7,54,177,4,15,70,15,70,135,68,67,4,139,199,204,130,242,240,45,135,69,129,0,5,245,170,0,0

Expected behavior

In the first case, the surface should return grass. In the second one - unknown In the third case, ideally, it should return asphalt for bicycle profiles and paving stones for foot profiles, but if you choose not to support cycleway:surface and footway:surface tags it's better to return unknown than unpaved

Openrouteservice Version

8.0.0

Build date

2024-03-21T13:55:54Z

Graph date

2024-04-08T23:04:37Z

Forum Topic Link

No response

aoles commented 2 months ago

Thanks for filing the issue. The result from your first example is indeed unexpected and needs to be investigated further. For reference here's the direct link to the OSM way.

As for your other examples, it's actually not a 🐛 but a feature 😂 This is so because in the first case the way which is tagged as highway=service is categorized as WayType.STREET and as such receives the assumed surface type paved according to the logic in WaySurfaceTypeGraphStorageBuilder: https://github.com/GIScience/openrouteservice/blob/dfd578819ca3c27b682406eb5573f071c9f63285/ors-engine/src/main/java/org/heigit/ors/routing/graphhopper/extensions/storages/builders/WaySurfaceTypeGraphStorageBuilder.java#L63-L69

In the case of the cycleway and footway the OSM tag highway=path translates to WayType.PATH which is assumed to be unpaved by the above logic. This happens because tags such as footway:surface or cycleway:surface are currently not being parsed, just the surface one.

michalgwo commented 2 months ago

As for your other examples, it's actually not a 🐛 but a feature 😂 This is so because in the first case the way which is tagged as highway=service is categorized as WayType.STREET and as such receives the assumed surface type paved according to the logic in WaySurfaceTypeGraphStorageBuilder:

But this is wrong. Not every highway=service is paved. One example could be a driveway which is supposed to be tagged as highway=service + service=driveway, but in many cases is not paved, at least in Poland (wiki).

In the case of the cycleway and footway the OSM tag highway=path translates to WayType.PATH which is assumed to be unpaved by the above logic. This happens because tags such as footway:surface or cycleway:surface are currently not being parsed, just the surface one.

Same as above, highway=path doesn't mean the surface is unpaved. A good example is shared foot and bicycle paths, which are tagged highway=path + bicycle=designated + foot=designated and are often made of asphalt or paving stones (wiki).

Anyway, road classification doesn't imply surface in any case, so I think this feature should be disabled.

sfendrich commented 1 month ago

There is a systematic bug affecting these surface types:

    public static final int WOODCHIPS = 16;
    public static final int GRASS = 17;
    public static final int GRASS_PAVER = 18;

(https://github.com/GIScience/openrouteservice/blob/2740e85106c96eb9f869a5a19698724f5b135424/ors-engine/src/main/java/org/heigit/ors/routing/graphhopper/extensions/SurfaceType.java#L36C1-L39C1)

The surface type is stored with 4 bits, which allows for a maximum of 15 different types. Interestingly, way type and surface type are just or-ed together so that for these three surface types, the way type becomes wrong, too.

    public void setEdgeValue(int edgeId, WaySurfaceDescription wayDesc) {
        edgesCount++;
        ensureEdgesIndex(edgeId);

        // add entry
        long edgePointer = (long) edgeId * edgeEntryBytes;
        byteValues[0] = (byte) ((wayDesc.getWayType() << 4) | wayDesc.getSurfaceType() & 0xff);
        orsEdges.setBytes(edgePointer + efWaytype, byteValues, 1);
    }

(https://github.com/GIScience/openrouteservice/blob/2740e85106c96eb9f869a5a19698724f5b135424/ors-engine/src/main/java/org/heigit/ors/routing/graphhopper/extensions/storages/WaySurfaceTypeGraphStorage.java#L90C1-L99C1)