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.
Python is relatively slow; this type of conversion is usually carried out in bulk, so an order-of-magnitude improvement could save precious minutes
cargo build --release
from the repo rootipython notebook
, and open rust_BNG
.An IPython (sorry, Jupyter) notebook with some benchmarks is here
Python: 10000 loops, best of 10: 31 µs per loop
Rust: 100000 loops, best of 10: 2.04 µs per loop* 💅
Pyproj: 100000 loops, best of 10: 11.8 µs per loop†
*Test warns that intermediate results may have been cached
Convert 10,000000 sets of random coordinates
Python: 1 loops, best of 10: 804 ms per loop
Rust: 1 loops, best of 10: 204 ms per loop
Pyproj: 10 loops, best of 10: 99.5 ms per loop 💅
Rust (threaded): 10 loops, best of 10: 162.5 ms per loop
Using multithreading, we can get much closer (pyproj is now only 65% faster). Not bad, considering the relative youth of Rust as a language (let alone this library), and the maturity of the PROJ.4 project.
The Helmert transform used is accurate to within 4 – 5 metres, 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.
Add the following to your Cargo.toml
(You'll have to look up the latest version on crates.io)
lonlat_bng = "0.1.8"
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)>
The FFI C-compatible functions exposed by the library are:
convert_to_bng_threaded(Array, Array) -> Array
convert_to_bng_threaded(Array, Array) -> Array
The Array
s must contain 32-bit Float
s and 32-bit Int
s, respectively. For examples, see the Array
struct and tests in lib.rs, and the _BNG_FFIArray
class in convertbng
convert_bng
is available from PyPI for OSX and *nix:
pip install convertbng
More information is available in its repository
MIT