For a printed topographic hiking map it is nice to have an indication of distances between trail junctions. This feature, seemingly easy to obtain, actually has a number of issues that I have not yet fully worked out.
Being unimaginative, I follow the lead of some other maps by putting a red dot on trail junctions and then mileage text along the trail between junctions.
To render the maps I had already setup PostgreSQL, and Postgis and have been loading regional .pbf extracts of OpenStreetMap (OSM) data into the database using osm2pgsql. So I have the ways and the Postgis ST_Length() function seemed to do what I wanted.
Except that I missed the part of the ST_Length() description that said, “The units of length is determined by the spatial reference system of the geometry.” osm2pgsql sets up its tables to use a spherical mercator projection so at my latitude the east-west measurements are longer than they should be. Not enough to jump out at you as wrong, just maybe 10% off.
Also, there did not seem to be an easy way to render the points at the end of each way with the little red dots.
But one thing this first try did remind me is that OSM ways, in their raw form, are not exactly what I want. There are two big issues:
- Ways do not always end at intersections. The OSM way for a through trail may be many miles long and have a number of intersections with cross trails. So the mileage displayed was not for the distance between intersections but for the whole way.
- The reverse is also true to: Between intersections a trail may be broken into many shorter ways. Sometimes this is a result of the editing history. But in others it may be because the surface, visibility, or SAC scale changed or some other valid reason.
It seemed to me that what I needed was a “nodes and edges graph” for the ways of interest. This comes straight out of the field of route calculations. Searching for “OpenStreetMap, routing, Postgresql, Postgis” led me to pgrouting and osm2pgrouting.
It took me a bit to integrate this as osm2pgrouting seems to only take .osm files (which can be huge). But it seemed I could use osmconvert to take the .pbf file to a compressed .o5m format. That, in turn can be used by osmfilter to remove everything I don’t want (land use, buildings, motorways, etc.) and leave me with a tolerably sized .osm file for osm2pgrouting to import into my database.
What I ended up with in my database was a set of tables with edges representing highway=path, highway=footway, and highway=steps. And nodes (junctions) for where they intersect.
osm2pgrouting nicely splits ways at intersections so my first issue above was addressed. And it creates a field on each edge (way) with the actual length in meters addressing another issue.
I thought I could use the nodes for my little red dots and use the edges for rendering the mileage. The edges have a field for geometry so the mileage text can even follow the curves of the OSM way.
But where my map extended into urban and suburban areas I noticed an issue: The footways and stair cases were too short to render the mileage text so all we had were dots all over the area. Looked like those areas of the map had measles.
Changing my filters to use only highway=path resolved that. Unfortunately that resulted in a different issue.
How can a renderer distinguish between a footway in an office park and a trail in the woods with the existing OpenStreetMap tagging and how mappers are actually tagging things in the field?
I thought I could look at the surface tag and consider a unpaved footway the same as a path. But it isn’t just unpaved, it might be “ground”, “earth”, “dirt”, etc. I could handle that. But then I found some mountain trails tagged as footway with no other tags at all. No surface, width, smoothness or SAC scale tags. Nothing. Exactly the same tagging as I see on many footways in a suburban park.
Maybe I should look into seeing if the footway/path is in a urban area. But there is no clear cut way to do that as administrative boundaries are not always defined. In my area there are wilderness parks with hiking trails in the same administrative boundary as residential and office areas and traditional style urban parks with paved walkways. I suppose one could look at the density of other map features (buildings, motor vehicle roadways, etc.) and determine if the area was urban or not but that seems like it would have issues too and is beyond my current GIS abilities.
My current work around is to only put junction marking dots at the ends of ways that are long enough that I will try to render the distance. It helps remove some of the clutter from parks and office complexes but is unsatisfying.
Maybe I am now done. For many mountain trails the presentation is okay and where my maps extend into developed areas there are not too many places with red dot measles.
But there some nagging issues remain. First among them: Ways split for reasons I don’t care to render resulting in sequential distances the map user has to manually add.
So far the fixes I’ve found for this require importing the data into something like QGIS and running a “heal” operation. I strongly desire to have everything scripted and haven’t yet figured out how to automate this though I am certain there must be a way.
If the routing graph is “healed” the map may lose some useful data. At present many trails happen to be split where they cross some other type of highway. That allows a distance to a formal or informal trailhead to be shown. I think I’ll need to import all of the various highway=* ways into my pgrouting database before healing and then just display distances on the paths and footways.