Skip to main content

Fast lon, lat to and from ETRS89 and BNG (OSGB36) using Rust FFI

Project description

|Build Status| |Coverage Status| |MIT licensed| |PyPI Version|

Description

A utility library for converting decimal WGS84 longitude and latitude coordinates into ETRS89 (EPSG:25830) and/or British National Grid (More correctly: OSGB36, or EPSG:27700) Eastings and Northings, and vice versa.

Conversion is handled by a Rust binary using FFI, and is quite fast. Some benchmarks can be found here.

Installation

pip install convertbng

Note

convertbng is currently available for 64-bit architectures as a manylinux wheel, an OS X wheel, and a Windows wheel. 32-bit Python on 64-bit Windows is also supported. The Rust DLL and the Cython extension used by this package have been built with a MinGW toolchain for Windows, so you shouldn’t need to install any additional runtimes in order for the wheel to work, but please open an issue if you encounter any errors.

Usage

The functions accept either a sequence (such as a list or numpy array) of longitude or easting values and a sequence of latitude or northing values, or a single longitude/easting value and single latitude/northing value. Note the return type: "returns a list of two lists containing floats, respectively"

NOTE: Coordinate pairs outside the BNG bounding box, or without OSTN02 coverage will return a result of [[nan], [nan]], which cannot be mapped. Since transformed coordinates are guaranteed to be returned in the same order as the input, it is trivial to check for this value. Alternatively, ensure your data fall within the bounding box before transforming them:

Latitude: East: 1.7800 West: -7.5600 Longitude: North: 60.8400 South: 49.9600

All functions try to be liberal about what containers they accept: list, tuple, array.array, numpy.ndarray, and pretty much anything that has the __iter__ attribute should work, including generators.

from convertbng.util import convert_bng, convert_lonlat

# convert a single value
res = convert_bng(lon, lat)

# convert lists of longitude and latitude values to OSGB36 Eastings and Northings, using OSTN02 corrections
lons = [lon1, lon2, lon3]
lats = [lat1, lat2, lat3]
res_list = convert_bng(lons, lats)

# convert lists of BNG Eastings and Northings to longitude, latitude
eastings = [easting1, easting2, easting3]
northings = [northing1, northing2, northing3]
res_list_en = convert_lonlat(eastings, northings)

# assumes numpy imported as np
lons_np = np.array(lons)
lats_np = np.array(lats)
res_list_np = convert_bng(lons_np, lats_np)

Experimental Cython Module

If you’re comfortable with restricting yourself to NumPy f64 arrays, you may use the Cython functions instead. These are identical to those listed below, and are selected by changing the import statement from convertbng.util import to ``from convertbng.cutil import``.

The conversion functions will accept most sequences which implement __iter__, as above (list, tuple, float, array.array, numpy.ndarray), but will always return ``NumPy f64 ndarray``. In addition, you must ensure that your inputs are float, f64, or d in the case of array.array.

This module is currently experimental, and should not be used in production unless you’re comfortable verifying the results by comparing them to the existing functions.

Available Conversions (AKA I Want To…)

  • transform longitudes and latitudes to OSGB36 Eastings and Northings very accurately:

    • use convert_bng()

  • transform OSGB36 Eastings and Northings to latitude and longitude, very accurately:

    • use convert_lonlat()

  • transform longitudes and latitudes to ETRS89 Eastings and Northings, very quickly (without OSTN02 corrections):

    • use convert_etrs89()

  • transform ETRS89 Eastings and Northings to ETRS89 latitude and longitude, very quickly (the transformation does not use OSTN02):

    • use convert_etrs89_to_lonlat()

  • convert ETRS89 Eastings and Northings to their most accurate real-world representation, using the OSTN02 corrections:

    • use convert_etrs89_to_osgb36()

Provided for completeness:

  • transform accurate OSGB36 Eastings and Northings to less-accurate ETRS89 Eastings and Northings:

    • use convert_osgb36_to_etrs89()

  • transform ETRS89 Eastings and Northings to ETRS89 longitude and latitude:

    • use convert_etrs89_to_lonlat()

Relationship between ETRS89 and WGS84

[…] In Europe, ETRS89 is a precise version of the better known WGS84 reference system optimised for use in Europe; however, for most purposes it can be considered equivalent to WGS84. Specifically, the motion of the European continental plate is not apparent in ETRS89, which allows a fixed relationship to be established between this system and Ordnance Survey mapping coordinate systems. Additional precise versions of WGS84 are currently in use, notably ITRS; these are not equivalent to ETRS89. The difference between ITRS and ETRS89 is in the order of 0.25 m (in 1999), and growing by 0.025 m per year in UK and Ireland. This effect is only relevant in international scientific applications. For all navigation, mapping, GIS, and engineering applications within the tectonically stable parts of Europe (including UK and Ireland), the term ETRS89 should be taken as synonymous with WGS84.

Transformations and OSGM02™, User guide, p7. Emphasis mine.

In essence, this means that anywhere you see ETRS89 in this README, you can substitute WGS84.

What CRS Are My Data In

  • if you have latitude and longitude coordinates:

    • They’re probably WGS84. Everything’s fine!

  • if you got your coordinates from a smartphone or a consumer GPS:

    • They’re probably WGS84. Everything’s fine!

  • if you have x and y coordinates, or you got your coordinates from Google Maps or Bing Maps and they look something like (-626172.1357121646, 6887893.4928337997), or the phrase “Spherical Mercator” is mentioned anywhere:

    • they’re probably in Web Mercator. You must convert them to WGS84 first. Use convert_epsg3857_to_wgs84([x_coordinates], [y_coordinates]) to do so.

Accuracy

convert_bng and convert_lonlat first use the standard seven-step Helmert transform to convert coordinates. This is fast, but not particularly accurate – it can introduce positional error up to approximately 5 metres. For most applications, this is not of particular concern – the input data (especially those originating with smartphone GPS) probably exceed this level of error in any case. In order to adjust for this, the OSTN02 adjustments for the kilometer-grid the ETRS89 point falls in are retrieved, and a linear interpolation to give final, accurate coordinates is carried out. This process happens in reverse for convert_lonlat.

OSTN02

OSTN02 data are used for highly accurate conversions from ETRS89 latitude and longitude, or ETRS89 Eastings and Northings to OSGB36 Eastings and Northings, and vice versa. These data will usually have been recorded using the National GPS Network:

Accuracy of Your Data

Conversion of your coordinates using OSTN02 transformations will be accurate, but if you’re using consumer equipment, or got your data off the web, be aware that you’re converting coordinates which probably weren’t accurately recorded in the first place. That’s because accurate surveying is difficult.

Accuracy of the OSTN02 transformation used in this library

  • ETRS89 longitude and latitude / Eastings and Northings to OSGB36 conversion agrees with the provided Ordnance Survey test data in 31 of the 42 test coordinates (excluding two coordinates designed to return no data; these correctly fail).

  • The 11 discrepancies are of 1mm in each case.

  • OSGB36 to ETRS89 longitude and latitude conversion is accurate to within 8 decimal places, or 1.1mm.

A Note on Ellipsoids

WGS84 and ETRS89 coordinates use the GRS80 ellipsoid, whereas OSGB36 uses the Airy 1830 ellipsoid, which provides a regional best fit for Britain. Positions for coordinates in Great Britain can differ by over 100m as a result. It is thus inadvisable to attempt calculations using mixed ETRS89 and OSGB36 coordinates.

|OSTN02|

Implementation

The main detail of interest is the FFI interface between Python and Rust, the Python side of which can be found in util.py, and the Rust side of which can be found in lib.rs. The ctypes library expects C-compatible data structures, which we define in Rust (see above). We then define methods which allow us to receive, safely access, return, and free data across the FFI boundary. Finally, we link the Rust conversion functions from util again. Note the errcheck assignments, which convert the FFI-compatible ctypes data structures to tuple lists.

Building the binary for local development

  • ensure you have Rust 1.x and Cargo installed

  • clone https://github.com/urschrei/lonlat_bng, and ensure it’s adjacent to this dir (i.e. code/witnessme/convertbng and code/witnessme/rust_bng)

  • in this dir, run make clean then make build

Tests

You can run the Python module tests by running “make test”. Tests require both numpy and nose.

License

MIT

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

convertbng-0.4.27-cp27-cp27mu-manylinux1_x86_64.whl (6.6 MB view details)

Uploaded CPython 2.7mu

convertbng-0.4.27-cp27-cp27m-win_amd64.whl (7.4 MB view details)

Uploaded CPython 2.7mWindows x86-64

convertbng-0.4.27-cp27-cp27m-win32.whl (7.2 MB view details)

Uploaded CPython 2.7mWindows x86

convertbng-0.4.27-cp27-cp27m-macosx_10_11_x86_64.whl (5.2 MB view details)

Uploaded CPython 2.7mmacOS 10.11+ x86-64

File details

Details for the file convertbng-0.4.27-cp27-cp27mu-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-0.4.27-cp27-cp27mu-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 a7464995fafd2ce90a179903223d7d4f7c6cacd5b3ccfa62e7683a6c4bcafae0
MD5 ba2d003f8bfb94d56e01fb2dee69532e
BLAKE2b-256 eeda52fee96485f56c642dbdc6580835db5544196a42de0dadc4c3d3172f7dfa

See more details on using hashes here.

File details

Details for the file convertbng-0.4.27-cp27-cp27m-win_amd64.whl.

File metadata

File hashes

Hashes for convertbng-0.4.27-cp27-cp27m-win_amd64.whl
Algorithm Hash digest
SHA256 cdd0098b39ed92d3bf7cfa4d3f77a80fe5c6ae2eedc81116bfa919e7cb618dfe
MD5 d96fa6e31d16a21d58429873d13d3dba
BLAKE2b-256 29b0b013d60579fc56b131151436184ae8087f333a6408135e2dc2b9c9378611

See more details on using hashes here.

File details

Details for the file convertbng-0.4.27-cp27-cp27m-win32.whl.

File metadata

File hashes

Hashes for convertbng-0.4.27-cp27-cp27m-win32.whl
Algorithm Hash digest
SHA256 830790b7813001f813369b5b31c47006ddd1de916c971ebe194c2aabfffc2859
MD5 3f7816bfd99c3169afa7a18f2caef7bc
BLAKE2b-256 62ff4031225f768ffba8aecd588162a4300ce00e0e01c38b3c7d9c7c86762e84

See more details on using hashes here.

File details

Details for the file convertbng-0.4.27-cp27-cp27m-macosx_10_11_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-0.4.27-cp27-cp27m-macosx_10_11_x86_64.whl
Algorithm Hash digest
SHA256 0080b9400130a664e27c7063802065f871602526ce726dbd1516cbf7ae1a6b81
MD5 6e666974ac68164c50b69b44d802bd71
BLAKE2b-256 2692c4797259b7a0d9eff60ee63d6a51ebd15521141c3c5291169491a0b6a273

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page