Skip to main content

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

Project description

Coverage Status PyPI Version MIT licensed

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
Please use an up-to-date version of pip (8.1.2 as of June 2016)

Supported Platforms

The package has been built for and tested on the following platforms:

  • Linux 64-bit Python 3.{7, 8, 9, 10} a manylinux1 wheel
  • macOS Darwin 64-bit, Python 3.{7, 8, 9, 10} as a wheel for versions 10.6 and above
  • Windows 32-bit and 64-bit Python 3.{6, 7}

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 lists of longitude and latitude values 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)

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)

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.

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_ll()
  • 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 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 National GPS 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

  • ETRS89 longitude and latitude / Eastings and Northings to OSGB36 conversion agrees with the provided Ordnance Survey test data in 39 of the 40 test coordinates (excluding two coordinates designed to return no data; these correctly fail).
  • The only discrepancy – in point TP31– is 1mm.
  • 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.

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 the binary for local development

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.6.35-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (14.0 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.12+ x86-64manylinux: glibc 2.5+ x86-64

convertbng-0.6.35-cp310-cp310-macosx_10_9_x86_64.whl (13.7 MB view details)

Uploaded CPython 3.10macOS 10.9+ x86-64

convertbng-0.6.35-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (14.0 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.12+ x86-64manylinux: glibc 2.5+ x86-64

convertbng-0.6.35-cp39-cp39-macosx_10_9_x86_64.whl (13.7 MB view details)

Uploaded CPython 3.9macOS 10.9+ x86-64

convertbng-0.6.35-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (14.0 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.12+ x86-64manylinux: glibc 2.5+ x86-64

convertbng-0.6.35-cp38-cp38-macosx_10_9_x86_64.whl (13.7 MB view details)

Uploaded CPython 3.8macOS 10.9+ x86-64

convertbng-0.6.35-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (13.9 MB view details)

Uploaded CPython 3.7mmanylinux: glibc 2.12+ x86-64manylinux: glibc 2.5+ x86-64

convertbng-0.6.35-cp37-cp37m-macosx_10_9_x86_64.whl (13.7 MB view details)

Uploaded CPython 3.7mmacOS 10.9+ x86-64

File details

Details for the file convertbng-0.6.35-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-0.6.35-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 473cc4bbfc7ecf4c68652157120c9a1cacffbb6916a30747fa99cba064aa22ba
MD5 f714a7bf562b7151fbd6ea4dce992de3
BLAKE2b-256 ba9f3c2d3fc310e37e2bd9b5ae4c53d5302277b8f8eec5dc1542214c814a1ae0

See more details on using hashes here.

File details

Details for the file convertbng-0.6.35-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: convertbng-0.6.35-cp310-cp310-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 13.7 MB
  • Tags: CPython 3.10, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

File hashes

Hashes for convertbng-0.6.35-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 8c0f60f43182631852b1bdc364125e335db1a404a92a4529a401cf41538d74d9
MD5 43b462c65c86a34e006c3b3e03dfbaf5
BLAKE2b-256 23b4a918a180d6107325df6186832490955c02760d29763080b383e4d744cc6b

See more details on using hashes here.

File details

Details for the file convertbng-0.6.35-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-0.6.35-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 ebc845f3cb85a20a8978e23e3c5e9243e6621222e7f0617f6956a89199032a63
MD5 4f1d1e0268c344c5f002e0a470a49071
BLAKE2b-256 3360a5f6ccda358ca8912d523e3ce434aae7eec8ebcbd69cffa0cc933e32ad79

See more details on using hashes here.

File details

Details for the file convertbng-0.6.35-cp39-cp39-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: convertbng-0.6.35-cp39-cp39-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 13.7 MB
  • Tags: CPython 3.9, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

File hashes

Hashes for convertbng-0.6.35-cp39-cp39-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 9bdac5e0b0f5eea9826b7d252ed4a75a47ca772f34c116d7d8a314e1ab559522
MD5 87bb7be99cedc7d293c5a6662c5bfc8e
BLAKE2b-256 7f69d7c16fc22aca033109e71bd37e2b73a4320ac433da8c89331e814bc5dcd0

See more details on using hashes here.

File details

Details for the file convertbng-0.6.35-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-0.6.35-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 f9f5d6afd8d574f121bc905827e18b0a3ac5bfb0d9ed6182c70f6636e06b533c
MD5 765b03df457bbbb14ec5feab3d874d80
BLAKE2b-256 7f8854c37f24ccd92b0983464ab87885367124fe9b3b1537fbae36a4d91d136a

See more details on using hashes here.

File details

Details for the file convertbng-0.6.35-cp38-cp38-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: convertbng-0.6.35-cp38-cp38-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 13.7 MB
  • Tags: CPython 3.8, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

File hashes

Hashes for convertbng-0.6.35-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 bfc7a0fcd49f3151d987b87de0890dccf1d112aa4b2be8ecfd70599e04859d0f
MD5 c07acf1852e8aa1a5e81880f73e20d53
BLAKE2b-256 b2dab06fb69be591db0c842782f2537d1a00e1b86ab06e5df61d956124b263fd

See more details on using hashes here.

File details

Details for the file convertbng-0.6.35-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for convertbng-0.6.35-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 a47a5cd34894046f74a52af57e0ca7085ed7f8e8c498ef77283e3741e07764e3
MD5 7326b34fc8e352094dfb3b07f7551870
BLAKE2b-256 b2be6c58190b2f71ea8095afe10a1ce317bef63ab0f9e7ca543210acc411fc31

See more details on using hashes here.

File details

Details for the file convertbng-0.6.35-cp37-cp37m-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: convertbng-0.6.35-cp37-cp37m-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 13.7 MB
  • Tags: CPython 3.7m, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

File hashes

Hashes for convertbng-0.6.35-cp37-cp37m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 90cb6cf86bc6dc4ac54c16025be06bfdfa7bfe19cd32d86223b9023140e4e272
MD5 a0a0057e258ad5568b3f1f389ad46bbf
BLAKE2b-256 e194b68c4bd9ec39a45a3eabfe86545a5790f9090d358d9c8f3b4d14ebfcc0f1

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