Build Status

Introduction

An attempt at speeding up the conversion between decimal longitude and latitude and British National Grid (epsg:27700) coordinates, using an external Rust binary and Python FFI.

Motivation

Python is relatively slow; this type of conversion is usually carried out in bulk, so an order-of-magnitude improvement could save precious minutes

Library Use

As a Rust Library

Add the following to your Cargo.toml (You'll have to look up the latest version on crates.io)

lonlat_bng = "0.1.9"

Full library documentation is available here

Note that lon, lat coordinates outside the UK bounding box will be transformed to (9999, 9999), which cannot be mapped.

The native functions exposed by the library are:

lonlat_bng::convert_bng(&f32, &f32) -> (i32, i32)
lonlat_bng::convert_lonlat(&i21 &i32) -> (f32, f32)

lonlat_bng::convert_to_bng_threaded_vec(Vec<(&f32, &f32)>) -> Vec<(i32, i32)>
lonlat_bng::convert_to_lonlat_threaded_vec(Vec<(&i32, &i32)>) -> Vec<(f32, f32)>

As an FFI Library

The FFI C-compatible functions exposed by the library are:
convert_to_bng_threaded(Array, Array) -> Array
convert_to_lonlat_threaded(Array, Array) -> Array

And for freeing the memory allocated by the above
drop_int_array(Array) -> Null
drop_float_array(Array) -> Null

The Arrays must contain 32-bit Floats and 32-bit Ints, respectively. For examples, see the Array struct and tests in lib.rs, and the _BNG_FFIArray class in convertbng.

FFI and Memory Management

If your FFI library implements convert_to_bng_threaded, it must also implement drop_int_array, and if it implements convert_to_lonlat_threaded, it must implement drop_float_array. Failing to do so will result in memory leaks.

Building the Shared Library

Running cargo build --release will build an artefact called liblonlat_bng.dylib on OSX, and liblonlat_bng.a on *nix systems. Note that you'll have to generate liblonlat_bng.so for *nix hosts using the following steps:

As a Python Package

convert_bng is available from PyPI for OSX and *nix:
pip install convertbng
More information is available in its repository

Benchmark

An IPython (sorry, Jupyter) notebook with some benchmarks is here

Installation Instructions

Results

Test machine:
- Late-2012 27" iMac - 3.4 GHz Intel Core i7 - 4 cores (8 logical CPUs) - 16GB 1600 MHz DDR3 RAM

| Coordinates | Method | Time (ms) | Speedup | |:---------------|:------:|:---------:|--------:| | 100k (50 runs) | Python | 547 | N/A | | |Rust| 73.9 |7.4x | | | Pyproj | 57.2 | 9.5x | | 1mm (50 runs) | Python | 5560 | N/A | | |Rust| 624 |8.9x | | | Pyproj | 510 | 10.9x | | 10mm (50 runs) | Python | 54500 | N/A | | |Rust| 6360 |8.6x | | | Pyproj | 4710 | 11.5 |

Conclusion

Using multithreading gives excellent performance (Pyproj – which is a compiled Cython binary – is now only ~20% faster than Rust, on average). Not bad, considering the relative youth of Rust as a language (let alone this library), and the maturity of the PROJ.4 project.

Accuracy

The Helmert transform used is accurate to within 7 metres on average, so this library is not suitable for calculations used in e.g. surveying. If higher accuracy is required, please use a product which incorporates the OSTN02 calculations, which adjust for local variation within the Terrestrial Reference Frame. See here for more information.

License

MIT

† Really, pyproj?
mediocre