Skip to main content

Fast lon, lat to and from ETRS89 and BNG (OSGB36) using the OS OSTN15 transform via Rust FFI

Project description

CI Status Coverage Status PyPI Version DownloadsDOI

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

  • uv add convertbng
  • pip install convertbng

Pre-built wheels are published for every supported platform (see Supported Platforms), so the commands above install a ready-to-use binary and compile nothing.

How the package is built

Coordinate conversion is performed by a pre-built Rust library, lonlat_bng, which convertbng links against over FFI. The Rust code is not compiled as part of this package: each wheel bundles the appropriate lonlat_bng shared library (.dylib, .so, or .dll) alongside the cbindgen-generated header.h.

Building from the source distribution (sdist)

The sdist deliberately does not bundle the shared library or header.h: these are platform-specific build artefacts rather than source, so a single sdist cannot carry the correct ones for every platform. Installing a wheel is the supported path for the platforms listed below; building from the sdist is for everyone else.

To build from the sdist, download the release archive for your platform from the lonlat_bng releases and extract its contents into src/convertbng/ before building. Each archive contains the shared library (liblonlat_bng.dylib, liblonlat_bng.so, or lonlat_bng.dll, plus the MSVC import library on Windows) and the matching header.h. This is the same step CI performs before building each wheel.

Installing for local development

  1. Ensure you have a copy of liblonlat_bng and header.h from https://github.com/urschrei/lonlat_bng/releases, and it's in the src/convertbng subdir
  2. run uv sync --dev
  3. run pytest .

Changes in pyx and pxd files, and the Rust library and header will bust the cache, triggering a rebuild when uv commands are run.

Supported Python Versions

convertbng supports all currently supported Python versions.

Binary wheels target the CPython Stable ABI (abi3): a single abi3 wheel per platform covers CPython 3.11 and later, while CPython 3.10 receives a standard version-specific wheel.

Supported Platforms

  • Linux (manylinux-compatible) x86_64 and aarch64
  • macOS Darwin x86_64 and arm64
  • Windows 64-bit

Windows Binaries

The Rust DLL and the Cython extension used by this package have been built with an MSVC toolchain. 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 OSTN15 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:

Longitude:
East: 1.7800
West: -7.5600
Latitude:
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 longitude and latitude to OSGB36 Eastings and Northings using OSTN15 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)

Accuracy

The Rust library produces the following results when round-tripping the 40 OSTN15 test points (only differences are shown)

Test Point Input OSGB36 E (m) Input OSGB36 N (m) Lon diff (°) Lat diff (°) E diff (m) N diff (m)
TP27 319188.434 670947.534 +0.001
TP31 9587.909 899448.996 +6×10⁻⁸ -3×10⁻⁸ +0.003 -0.004
TP32 71713.132 938516.404 +2×10⁻⁸ -1×10⁻⁸ +0.001 -0.002
TP37 180862.461 1029604.114 -0.001
TP38 421300.525 1072147.239 -0.001

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, but performance on large datasets is better. They 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.

But I Have a List of Coordinate Pairs

coords = [[1.0, 2.0], [3.0, 4.0]]
a, b = list(zip(*coords))
# a is (1.0, 3.0)
# b is (2.0, 4.0)

But I have Shapely Geometries

from convertbng.util import convert_etrs89_to_ll
from shapely.geometry import LineString
from shapely.ops import transform
from math import isnan
from functools import partial

def transform_protect_nan(f, xs, ys):
    # This function protects Shapely against NaN values in the output of the
    # transform, which would otherwise case a segfault.
    xs_t, ys_t = f(xs, ys)
    assert not any([isnan(x) for x in xs_t]), "Transformed xs contains NaNs"
    assert not any([isnan(y) for y in ys_t]), "Transformed ys contains NaNs"
    return xs_t, ys_t

convert_etrs89_to_lonlat_protect_nan = partial(transform_protect_nan, convert_etrs89_to_ll)

line = LineString([[651307.003, 313255.686], [651307.004, 313255.687]])

new_line = transform(convert_etrs89_to_lonlat_protect_nan, line)

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 longitude and latitude, very accurately:
    • use convert_lonlat()
  • transform longitudes and latitudes to ETRS89 Eastings and Northings, very quickly (without OSTN15 corrections):
    • use convert_to_etrs89()
  • transform ETRS89 Eastings and Northings to ETRS89 longitude and latitude, very quickly (the transformation does not use OSTN15):
    • use convert_etrs89_to_lonlat()
  • convert ETRS89 Eastings and Northings to their most accurate real-world representation, using the OSTN15 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()

Relationship between ETRS89 and WGS84

From the Ordnance Survey Transformations and OSGM02™ User guide, p7. Emphasis mine.

[…] 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.

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 OSTN15 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.

OSTN15

OSTN15 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 OS Net GNSS reference station network:

Accuracy of Your Data

Conversion of your coordinates using OSTN15 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 OSTN15 transformation used in this library

  • Round-tripping the 40 OSTN15 test points produces a perfect match at 35 of them; the remaining 5 differ by at most 4mm in Eastings/Northings (see table above). The two test points designed to return no data correctly fail.
  • Longitude/latitude residuals are at most ~6×10⁻⁸° (a few mm at this latitude).

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.

OSTN15

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 (the ctypes implementation), cutil.pyx (the cython implementation), and the Rust side of which can be found in ffi.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.py again. Note the errcheck assignments, which convert the FFI-compatible ctypes data structures to tuple lists.

Building for local development

You do not need a Rust toolchain: the lonlat_bng library is pre-built and downloaded from its releases; this package only compiles the Cython extension and links against it. See Installing for local development above for the steps.

Tests

  • install pytest
  • run pytest

License

Blue Oak Model License

Citing Convertbng

If Convertbng has been significant in your research, and you would like to acknowledge the project in your academic publication, we suggest citing it as follows (example in APA style, 7th edition):

Hügel, S. (2021). Convertbng (Version X.Y.Z) [Computer software]. https://doi.org/10.5281/zenodo.5774931

In Bibtex format:

@software{Hugel_Convertbng_2021,
author = {Hügel, Stephan},
doi = {10.5281/zenodo.5774931},
license = {MIT},
month = {12},
title = {{Convertbng}},
url = {https://github.com/urschrei/convertbng},
version = {X.Y.Z},
year = {2021}
}

Project details


Release history Release notifications | RSS feed

This version

1.0.0

Download files

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

Source Distribution

convertbng-1.0.0.tar.gz (48.6 kB view details)

Uploaded Source

Built Distributions

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

convertbng-1.0.0-cp311-abi3-win_amd64.whl (13.8 MB view details)

Uploaded CPython 3.11+Windows x86-64

convertbng-1.0.0-cp311-abi3-manylinux_2_28_x86_64.whl (13.6 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ x86-64

convertbng-1.0.0-cp311-abi3-manylinux_2_28_aarch64.whl (13.6 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

convertbng-1.0.0-cp311-abi3-macosx_11_0_x86_64.whl (13.5 MB view details)

Uploaded CPython 3.11+macOS 11.0+ x86-64

convertbng-1.0.0-cp311-abi3-macosx_11_0_arm64.whl (13.8 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

convertbng-1.0.0-cp310-cp310-win_amd64.whl (13.8 MB view details)

Uploaded CPython 3.10Windows x86-64

convertbng-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl (13.6 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

convertbng-1.0.0-cp310-cp310-manylinux_2_28_aarch64.whl (13.6 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ ARM64

convertbng-1.0.0-cp310-cp310-macosx_11_0_x86_64.whl (13.6 MB view details)

Uploaded CPython 3.10macOS 11.0+ x86-64

convertbng-1.0.0-cp310-cp310-macosx_11_0_arm64.whl (13.8 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

File details

Details for the file convertbng-1.0.0.tar.gz.

File metadata

  • Download URL: convertbng-1.0.0.tar.gz
  • Upload date:
  • Size: 48.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for convertbng-1.0.0.tar.gz
Algorithm Hash digest
SHA256 d2dfd9869feeafe01eb42454a364fdd8ad971667a0641f03918d98d2c96a2557
MD5 9839beebd1408c9b17a6b4f43d871f96
BLAKE2b-256 9dbaa0a24e3eb00176f92d089e0f67f28f5e8c9fa36baf86ad10b515493d02ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0.tar.gz:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: convertbng-1.0.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 13.8 MB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for convertbng-1.0.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 fde4b27ca8a42de07b0ee1e5a79acb522ab12a802627988d6a0355c716c42045
MD5 8e67e679d08d15e33cedc5edee7d0255
BLAKE2b-256 da38f36629ab488846fb9d9b942ccac1a2a3929f59b277e4c0140aefa11f33ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp311-abi3-win_amd64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp311-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp311-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ff58d32e1ca4df1dedbe204167aba93182ac47227b03437e9cfec0a87c29d36c
MD5 e7610d3ef2fd7ca2b983dbb409c6d02b
BLAKE2b-256 f7bf71b57fc3484b0abbd82a13dc8d43e1d72409cc66db2c3ee69f517166d8c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp311-abi3-manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp311-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 daac0e78c8eaaacf1d8daa7c57e938a2e3209b164a706bc83cfc8efab3a16c30
MD5 b6bbf85f202b428089395ba78c40daf6
BLAKE2b-256 113a70b3df8024fce7a1b285dca5c5ec1050fb94c0944450672fc081739912f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp311-abi3-manylinux_2_28_aarch64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp311-abi3-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp311-abi3-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 af8b7bc50242d7fe401faf65c92cbc334a504bb4c903b8fe0d011d2bb226e403
MD5 8d59a9bc1745d1522655d704bf86ea6f
BLAKE2b-256 d97a7a28a7c3c35287bd2a5080b91155043fe1b2387e6d578d4da64dc5a8960d

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp311-abi3-macosx_11_0_x86_64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e5cf5572b45eb8cd7c6d69e774e279aced14dd3cdff004f4d32bedd1142bc4b6
MD5 66c19bc5a81dded2634a488850317f37
BLAKE2b-256 51c57c66ecd26823ba02803281c07422288a0149bbaed95ea156b7388dde9a56

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: convertbng-1.0.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 13.8 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for convertbng-1.0.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 f51f705aaf0fde5cffd2387803781b7311531fe986b05f6b09c782434660f24a
MD5 e7338c582879e85449dcfe1569aaecf2
BLAKE2b-256 66c798f05b18d3f0ea60b9fbcc574267507715cc456ba64826188c32b127680a

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp310-cp310-win_amd64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 82f518824866a4ff4b416a6845b5028ac5db9d8f018edca7678fbe58bbd10d2f
MD5 266d102f2cf8f83ea3a91b2c03af84c9
BLAKE2b-256 7e167cdb57dc9e65d07389adb7537c7f3994835569f504aba29e62ece3873c03

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp310-cp310-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp310-cp310-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 1247e3bd196c866b71160e7ad55ee5fcf70bc9288cecd1ef9ec7054ce2eadb45
MD5 d2366fbc53290c9444041f9deff607f7
BLAKE2b-256 09553d2b836ad18d76ab00c29cdbc462097595a6244cdaf2fbc6ef491b94f942

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp310-cp310-manylinux_2_28_aarch64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp310-cp310-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp310-cp310-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 8760e3173bb36d149abcad4bb8daf319e1871344847a6ae965478a3ec83045e6
MD5 f26250f27371f521cc3bf01136c185d3
BLAKE2b-256 4c1199e970de9461ed089a743a180734d426ce84a561928b9b2095ab48f69379

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp310-cp310-macosx_11_0_x86_64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file convertbng-1.0.0-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for convertbng-1.0.0-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8a81cb9e257b4a8ef6788322955a592fdb5339bdbc0812a4b515cf4711d0bf76
MD5 6cbb4e7690edde02355c3f4e87b11776
BLAKE2b-256 3de6510b203d908a1112f35ce28157d80e736d56a6183e3ff9cc34e1932f9c7b

See more details on using hashes here.

Provenance

The following attestation bundles were made for convertbng-1.0.0-cp310-cp310-macosx_11_0_arm64.whl:

Publisher: wheels.yml on urschrei/convertbng

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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