Friday 28 December 2012

Finding a road

I've been working on a project in the City of Hull. Part of that needs to find a specific road in the city. I wanted to use a type-ahead style search, showing a list of roads that meet a partial match of whatever is typed - a fairly normal modern requirement. In OSM we have the Nominatim search, but it is intended for searching the World - my requirements are more modest.

I extracted a list of road names from an OSM extract for Hull to take a look at. The first hassle is that there seemed to be loads and loads of duplicates. These mostly turn out to be roads that have small spurs with the same name and small 'T' or 'Y' endings of dead ends which again get tagged with the road name. The next next hassle is that I need to be able to zoom a map to show the selected road, so I thought I needed to know the centre point of each road. I thought about creating a bounding rectangle for the road and then calculating the centre point. Suddenly that rang a bell.

That format is what the open data OS Locator is presented as. So I decided to see what was needed to use that. First I extracted the roads for Hull from the GB dataset, converting the OSGB grid references to longitude and latitude in the OSM projection. There were a few duplicate road names. OS break a road at an administrative boundary, so as a road crosses a ward boundary it is split. There were about 160 of these (a tiny fraction of the OSM duplicate names) which I recombined into a single rectangle and recalculated the centre point.

One thing I know about in OS Locator data is that there are mistakes. Having surveyed all of Hull and recorded the anomalies with the not:name tags I could use these to correct the OS Locator data to reflect the names on the ground. I then changed the OS names to title case (lowercase with capitalised names) and removed apostrophes which would make searching harder. I then added all these roads with their centre points, about 2700, into a database table. Python scripts made short work of all of this.

I wrote a quick couple of lookups to make the jQuery ajax type ahead work, one returns the list of matches of road names based on a search term and one returns the details for a specific named road. I used the longitude and latitude of the centre point to zoom to that location on the map. Quickly I realised that didn't work well for all roads, because the zoom level needed to vary to show the whole road, some are much longer than others.  Fortunately the OS Locator data holds the rectangle that encloses the road, so I zoomed the map to the maximum zoom that shows that rectangle. The Leaflet library makes all of this pretty simple.

You can see an example of the end result here.  I chose the Mapquest Open tiles because they will suit another part of the project, more of that another time ...