That site (used for finding gaps in route relations) isn’t available right now. Is there an alternative with similar functionality?
If it’s a recreational route, Waymarked Trails recently added some functionality for spotting discontinuities.
For PtV2, you have Geofabrik OSM Inspector.
What that says for https://hiking.waymarkedtrails.org/#route?id=9491877&map=13.0/53.5687/-3.0883 is as follows:
This relation has 2 segments.
●Open end in the route.
●More than two segments of the route meet in this point.
●Point where route is interrupted because relation is not sorted. The red dashed lines shows where the route continues.
None of which is wrong, but it doesn’t actually tell me if there is a gap or not. It says that it isn’t sorted (most aren’t) and there are clearly two alternatives here, but I don’t know which one is an alternative to the other (and for the sake of filling in gaps, it’s not really relevant).
Looks like it’s back up again
Still down for me, but maybe whatever issues there are are being worked through so that we might see a bit of instability until it is properly back.
Incidentally, normally when things like this happen I’d think “can I just set up a local copy of it”, but when I read build instructions like “To build the Relation Analyzer launch: mvn package. This will create a WAR file in the target folder with the name “relation-analyzer.war”. Place this file in the webapps folder of your servlet container http://tomcat.apache.org and launch the server” I think “perhaps not”
.
This QLever query for gaps in route=historic relations can be adapted to tell you exactly where the gaps are in a specific route relation:
PREFIX osmkey: <https://www.openstreetmap.org/wiki/Key:>
PREFIX osmrel: <https://www.openstreetmap.org/relation/>
PREFIX ogc: <http://www.opengis.net/rdf#>
SELECT DISTINCT ?route ?pos ?highway ?next_highway WHERE {
# Compute the last member position of the route
{
SELECT ?route (MAX(?pos) AS ?last_pos) WHERE {
BIND(osmrel:9491877 AS ?route)
?route osmrel:member [ osmrel:member_id ?last_highway ; osmrel:member_pos ?pos ] .
?last_highway osmkey:highway [] .
}
GROUP BY ?route
}
# Get each member of the route
?route osmrel:member [ osmrel:member_id ?highway ; osmrel:member_pos ?pos ] .
# as long as it’s a highway
?highway osmkey:highway [] .
# and it isn’t the route’s last member
FILTER NOT EXISTS {
?route osmrel:member [ osmrel:member_id ?highway ; osmrel:member_pos ?last_pos ] .
}
# Get the route’s next member
?route osmrel:member [ osmrel:member_id ?next_highway ; osmrel:member_pos ?next_pos ] .
FILTER(?next_pos = ?pos + 1)
# as long as the two members don’t touch
FILTER NOT EXISTS {
?route osmrel:member/osmrel:member_id ?next_highway .
?highway ogc:sfTouches ?next_highway .
}
}
ORDER BY ?route ?pos
QLever has a heatmap view but otherwise doesn’t do a lot of visualization. You’d have to copy the query into Ultra for more options. The other catch is that QLever is up to a couple weeks behind, making it a good tool for checking up on existing data but not the edit you just saved.
I’ve just run that ^^ but changed the relation ID in it to 77161. That was in 7 pieces in an osm2pgsql database and is now in 9. The results https://qlever.dev/osm-planet/19iLhf list 14 lines of output listing “?route, ?pos, ?highway and ?next_highway” but I’m not sure what I am supposed to do to see where the gaps are?
Something that might work in some circumstances is JOSM’s relation editor (see this other question), but alas it fails with unsorted and unsortable relations.
The greater number of discrepancies is probably because the query is fairly simplistic, requiring the relation to be strictly linear and ordered. The query is supposed to return the ways before and after the gap, which you can plot on a map. But for some reason I’m unable to get this modified query to return in reasonable time for that route. ![]()
OK, how about a much simpler query:
PREFIX osmrel: <https://www.openstreetmap.org/relation/>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
SELECT * WHERE {
BIND(osmrel:77161 AS ?route)
?route geo:hasGeometry/geo:asWKT ?geometry .
}
If you click “Map view” (or, since Petrimaps is currently down, what luck, dump that into Ultra instead) and export the result as GeoJSON and copy it into geojson.io, each LineString within the FeatureCollection represents a disconnected segment. You can grab the coordinate pair at the beginning or end of each segment and open it in an editor. A bit more roundabout but a lot less dependent on behind-the-scenes magic.
I’ve just tried that with https://www.openstreetmap.org/relation/14638771#map=16/53.99006/-1.14157 (which I know does have a gap in it). https://geojson.io/#map=15.91/53.990528/-1.142335 (which the geojson dropped on it) :
Where do I see that?
https://qlever.dev/petrimaps/?query=PREFIX+osmrel%3A+<https%3A%2F%2Fwww.openstreetmap.org%2Frelation%2F>+PREFIX+geo%3A+<http%3A%2F%2Fwww.opengis.net%2Font%2Fgeosparql%23>+SELECT+*+WHERE+{+BIND+(osmrel%3A14638771+AS+%3Froute)+%3Froute+geo%3AhasGeometry%2Fgeo%3AasWKT+%3Fgeometry+})&backend=https%3A%2F%2Fqlever.dev%2Fapi%2Fosm-planet
seems to work now.
In geojson.io, you can uplaod the data and here each sgement (or node appart) is highlighted with a pin.
Argh, that’s annoying, the FeatureCollection generated by QLever just contains each way as a LineString without any coalescing. So this solution is no better than just plotting the relation on the main OSM map. I had been hoping it would coalesce each connected subgraph, similar to the visualization in JOSM’s relation window. Strike two for me. I’m going to sleep on it before coming back with another half-baked response. ![]()
Third time’s the charm. This QLever query returns each endpoint of the Maelor Way route relation. Click Execute. The links under the ?node column go to the individual endpoint nodes in OSM. Click on Map View to see them on an interactive map.
PREFIX osmway: <https://www.openstreetmap.org/way/>
PREFIX osmrel: <https://www.openstreetmap.org/relation/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
SELECT ?node (SAMPLE(?geometry) AS ?sample_geometry) WHERE {
{
# Get the starting point of each member way.
SELECT ?node WHERE {
osmrel:77161 osmrel:member/osmrel:member_id ?way .
?way osmway:member [ osmway:member_id ?node ; osmway:member_pos "0"^^xsd:int ].
}
}
# Get each reference to the node within the route relation structure.
osmrel:77161 osmrel:member/osmrel:member_id ?way .
?way osmway:member/osmway:member_id ?node .
# Get the node’s geometry.
?node geo:hasGeometry/geo:asWKT ?geometry .
}
GROUP BY ?node
# Only a node that’s an endpoint of only one way.
HAVING(COUNT(?way) < 2)
This query doesn’t care whether the relation is properly sorted. Any actual gap in the route would appear as an additional two endpoints. The Maelor Way has four endpoints because of the two spurs, but otherwise the route is fully connected.
If you do care about sorting, then this query comes up with the nine remaining gaps that you were expecting:
PREFIX osmrel: <https://www.openstreetmap.org/relation/>
PREFIX ogc: <http://www.opengis.net/rdf#>
SELECT ?prev_way ?next_way WHERE {
# Get a member of the route and the next member sequentially.
BIND(osmrel:77161 AS ?route)
?route osmrel:member [ osmrel:member_id ?prev_way ; osmrel:member_pos ?prev_member_pos ].
BIND(?prev_member_pos + 1 AS ?next_member_pos)
?route osmrel:member [ osmrel:member_id ?next_way ; osmrel:member_pos ?next_member_pos ].
# Subtract the members that intersect.
MINUS {
# Get a member of the route and the next member sequentially.
BIND(osmrel:77161 AS ?route)
?route osmrel:member [ osmrel:member_id ?prev_way ; osmrel:member_pos ?prev_member_pos ].
BIND(?prev_member_pos + 1 AS ?next_member_pos)
?route osmrel:member [ osmrel:member_id ?next_way ; osmrel:member_pos ?next_member_pos ].
# The two members must intersect.
?prev_way ogc:sfIntersects ?next_way .
}
}
That query returns the way before and after each gap, which is similar to the detail that JOSM’s relation editor gives you. I provided a similar query the other day, but it returned more results than you expected because it relied on ogc:sfTouches. Normally ogc:sfIntersects is adequate, but in this case, at least one way is a member of the relation twice over. (These are DE-9IM predicates, in case you’re wondering.)
If you want to drill down deeper, this more complicated version of the query returns the endpoints of each of the ways involved. Once again, you can click Map View to see the points on a map. It’d be up to you to manually inspect the endpoints to see where the gap actually lies.
PREFIX osmrel: <https://www.openstreetmap.org/relation/>
PREFIX ogc: <http://www.opengis.net/rdf#>
PREFIX osmway: <https://www.openstreetmap.org/way/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
SELECT ?way ?node ?geometry WHERE {
# Find gaps in the route relation.
{
SELECT ?prev_way ?next_way WHERE {
# Get a member of the route and the next member sequentially.
BIND(osmrel:77161 AS ?route)
?route osmrel:member [ osmrel:member_id ?prev_way ; osmrel:member_pos ?prev_member_pos ].
BIND(?prev_member_pos + 1 AS ?next_member_pos)
?route osmrel:member [ osmrel:member_id ?next_way ; osmrel:member_pos ?next_member_pos ].
# Subtract the members that intersect.
MINUS {
# Get a member of the route and the next member sequentially.
BIND(osmrel:77161 AS ?route)
?route osmrel:member [ osmrel:member_id ?prev_way ; osmrel:member_pos ?prev_member_pos ].
BIND(?prev_member_pos + 1 AS ?next_member_pos)
?route osmrel:member [ osmrel:member_id ?next_way ; osmrel:member_pos ?next_member_pos ].
# The two members must intersect.
?prev_way ogc:sfIntersects ?next_way .
}
}
}
# Get the end vertex position of each member way of the route.
{
SELECT ?way (COUNT(?node) - 1 AS ?max_vertex_pos) WHERE {
BIND(osmrel:77161 AS ?route)
?route osmrel:member/osmrel:member_id ?way .
?way osmway:member ?node .
}
GROUP BY ?way
}
# Get the start and end vertices of each way.
FILTER(?way = ?prev_way || ?way = ?next_way)
?way osmway:member ?vertex .
?vertex osmway:member_pos ?pos .
FILTER(?pos = "0"^^xsd:int || ?pos = ?max_vertex_pos)
# Get the vertex’s node geometry.
?vertex osmway:member_id ?node .
?node geo:hasGeometry/geo:asWKT ?geometry .
}
The query has to return two points per way, not just the endpoints of the gap. This route relation doesn’t travel in the same direction as each of the member ways, which would normally be fine, but it also lacks forward and backward roles. It would be difficult to construct a SPARQL query that figures out which end the gap is on. It would be more effective to imperatively walk the relation to figure that out. Ultra’s transform option can be useful for that, if you’re willing to write a bit of JavaScript.
Thanks - that does show the endpoints. You need to combine it with https://www.openstreetmap.org/relation/77161 to see the rest of the geometry though - and when you do you can see that there are no gaps in that example.
