Trigpointing and

One interesting email I received after posting geolocation and path cross asked if the module could be used for quick visualisation when trigpointing. Now that I’ve found out what trigpointing is I believe it can, and I’ve added a couple of extra features to make it easier for trigpointers to use the upoints module.

Firstly, for those who don’t know, trigpointing is the activity of tracking down trigpoints and recording them. I guess you could make a parallel to trainspotting, but with a navigational slant. Some people apparently use GPS units to track down the trigpoints, that I’d suggest makes it just hiking with trigpoints as waypoints. And some people, like Robert Johnson who mailed me, prefer to do the navigation with just an ordnance survey map and a compass which in my eyes makes it a little more interesting. Also, a few sites I’ve found with Google seem to suggest that many trigpointers like to use triangulation, although I suspect some mean trilateration, to travel between trigpoints as a navigational challenge.


Robert tells me that TrigpointingUK is a popular website among trigpointers in the UK. It contains information about many of the trigpoints you can find, such as the one closest to me at Bygrave

Anybody who knows me well will attest that that I’m quite the navigation geek, mostly just as a curiosity being that what we’re really talking about is just applications of specific branches of math. As such, I actually find the concept of trigpointing by hand quite intriguing. That being said technology is here to assist us, and with that let me introduce trigpoints a simple extension over the original script.

>>> from upoints import trigpoints
>>> database_location = urllib.urlopen("")
>>> Trigpoints = trigpoints.Trigpoints(database_location)
>>> print(len(Trigpoints))

Thanks to the online database we now have the locations of all the Ordnance Survey trigpoints in an easy to use format – a Python dictionary.

If I’d like to see trigpoints close to me, say within 20kM, and less than 60m above sea level I could tap the following in to my IPython session:

>>> Home = trigpoints.point.Point(52.015, -0.221)
>>> for identifier, trigpoint in sorted(Trigpoints.items()):
...     if Home.__eq__(trigpoint, 20) and trigpoint.altitude < 60:
...         print("%s - %s" % (identifier, trigpoint))
500936 - Broom Farm (52°03'57"N, 000°16'53"W alt 37m)
501822 - Crane Hill (52°11'10"N, 000°14'51"W alt 58m)
503750 - Limlow Hill (52°03'31"N, 000°04'20"W alt 59m)
505681 - Sutton (52°06'24"N, 000°11'57"W alt 55m)

Or we can display all the trigpoints within a given region. For example, to show trigpoints within the region from 51°52‘15”N, 000°28‘29”W to 52°09‘07”N, 000°01‘52”W.

>>> latitude_min = trigpoints.utils.to_dd(51, 52, 15)
>>> longitude_min = trigpoints.utils.to_dd(0, -28, -29)
>>> latitude_max = trigpoints.utils.to_dd(52, 9, 7)
>>> longitude_max = trigpoints.utils.to_dd(0, -1, -52)
>>> for identifier, trigpoint in sorted(Trigpoints.items()):
...     if latitude_min < trigpoint.latitude < latitude_max \
...       and longitude_min < trigpoint.longitude < longitude_max:
...         print("%s - %s" % (identifier, trigpoint))
500928 - Bromley Common (51°52'17"N, 000°06'14"W alt 118m)
500936 - Broom Farm (52°03'57"N, 000°16'53"W alt 37m)
501097 - Bygrave (52°00'38"N, 000°10'24"W alt 97m)
501417 - Cherrys Green (51°55'13"N, 000°01'52"W alt 126m)
501428 - Chicksands North Radio Mast (52°02'46"N, 000°22'17"W alt 62m)
501928 - Croydon Hill (52°07'37"N, 000°05'26"W alt 78m)
502034 - Deacon Hill (51°57'19"N, 000°21'46"W alt 173m)
502908 - Hammer Hill Farm (52°04'32"N, 000°24'05"W alt 89m)
503138 - Higham Gobion (51°58'48"N, 000°23'55"W alt 75m)
503750 - Limlow Hill (52°03'31"N, 000°04'20"W alt 59m)
503774 - Little Easthall Farm (51°53'23"N, 000°15'23"W alt 140m)
504024 - Marsh Farm Mh (51°55'24"N, 000°27'39"W alt 152m)
505392 - Sish Lane (51°54'39"N, 000°11'11"W alt 136m)
505681 - Sutton (52°06'24"N, 000°11'57"W alt 55m)
505852 - Therfield (52°01'03"N, 000°03'38"W alt 168m)
506163 - Warden Hill (51°55'20"N, 000°24'53"W alt 195m)
506165 - Warden Tunnel (52°05'15"N, 000°22'30"W alt 84m)

Or we could generate a file to use with xearth that contains all the trigpoints above 1000m above sea level:

>>> from upoints.utils import dump_xearth_markers
>>> high_markers = {}
>>> for identifier, trigpoint in Trigpoints.items():
...     if trigpoint.altitude > 1000:
...         high_markers[identifier] = trigpoint
>>> f = open("high_markers.txt", "w")
>>> f.write("\n".join(dump_xearth_markers(high_markers)))
>>> f.close()
xearth showing trigpoints higher than 1000m in Scotland

Now we can use xearth, or xplanet, to visualise the trigpoints that are higher than 1000m. If you start xearth with the command xearth -pos "fixed 57 -4" -mag 25 -noroot -markerfile high_markers.txt you will see an image similar to the one on the right.

You could, of course, use dump_xearth_markers() to dump the entire trigpoint database, but with over 6000 locations the result is just going to be a sea of blurred text when rendered.

And it is possible to fold the generation of the high_markers dictionary in to a single operation using lambda expressions and filter() such as:

>>> high_markers = dict(filter(lambda x: x[1].altitude > 1000,
...                            Trigpoints.items()))

However, you opinion on whether this is cleaner or not depends a lot on your background. If only you could run filter() on a dictionary directly, this would definitely be the better solution. I’m going to continue using the unrolled version on this page because it seems more people are comfortable with them in spite of me favouring the filter() and lambda() version, but it is just a matter of taste and yours may vary.

Using trigpoints you could generate marker file for locations with an altitude of between 900m and 910m using their location names as labels.

>>> display_markers = {}
>>> for identifier, trigpoint in Trigpoints.items():
...     if 900 < trigpoint.altitude < 910:
...         display_markers[identifier] = trigpoint
>>> f = open("display_markers.txt", "w")
>>> f.write("\n".join(dump_xearth_markers(display_markers,
...                                            "name")))
>>> f.close()

The result of how that query could be shown with xplanet can be found to the right.

xplanet showing trigpoints with altitudes in the range 900-910m

The Trigpoint class inherits from the Point class, and therefore has all the same methods it does. You can calculate distances and bearings between trigpoints. I suggest reading the HTML files generated by Sphinx that are included in the tarball to see how it all works, including some more examples.


And on a slight tangent, in my mind one of the best reasons for using Python is now evident, Nokia provide Python builds for some of their “smartphone” handsets. This means it is possible to use trigpoints on the move using only the mobile phone in your pocket, and it makes for a fun diversion from Snake 3D. Even as a simple database it can be surprisingly useful, especially given the difficulty of finding the minuscule trigpoint symbol on Ordnance Survey’s Explorer series maps.

We’re on a journey now, so if you can think of any cool uses for any of the classes and functions in the upoints tarball drop me a mail.