COOLJAPAN
← All posts

OxiProj 0.1.1 Released — Python & WASM Bindings, Tissot Distortion, and GPU Reprojection

Two days after its debut, OxiProj 0.1.1 adds Python (PyO3) and WASM bindings, Tissot indicatrix and covariance/autodiff analysis, SIMD + rayon + oxicuda GPU reprojection, and geo-types/geozero/GeoParquet interop. Still a Pure-Rust PROJ replacement — no C, no FFI.

release oxiproj proj gis cartography geospatial pure-rust map-projections python wasm

Two days in, OxiProj already speaks Python, runs in the browser, and reprojects on the GPU.

Today we released OxiProj 0.1.1 — a fast follow-up to the 0.1.0 debut that adds Python and WASM bindings, cartographic-distortion analysis, and SIMD/GPU-accelerated reprojection, on the heels of the Pure-Rust PROJ port we shipped two days ago.

If you missed it: OxiProj is a Pure-Rust reimplementation of PROJ 9.8.0 — not a binding to libproj, no proj-sys, no C toolchain. 0.1.1 doesn’t change that one bit; the optional EPSG proj.db still runs on the Pure-Rust oxisql-sqlite-compat engine, and the crate still compiles to a single static binary or to WASM. This post is about the deltas.

What’s new in 0.1.1

proj-sys remains the last big -sys liability dragging libproj and the C toolchain into every geospatial CI run — and it still hurts OxiGDAL most. 0.1.1 keeps closing the gap, and widens OxiProj’s reach well beyond Rust:

Technical Deep Dive: the 0.1.1 deltas

Bindings: Python and WASM. Two new crates extend OxiProj past Rust. oxiproj-py exposes Crs/Transformer/Coordinate via PyO3, mirroring pyproj, with a pip install / maturin publish workflow — and the epsg feature on by default, so authority strings work out of the box (Transformer('EPSG:4326', 'EPSG:3857')). oxiproj-wasm brings coordinate transformation to the browser and Node.js via wasm-bindgen.

Cartographic-analysis math. 0.1.1 adds a real distortion toolkit. The Tissot indicatrix (TissotParams) computes semi-major/minor axes, angular distortion, areal scale, and a conformality test using Snyder §4-14 formulas. Underpinning it is a forward-mode autodiff path: dual numbers Dual1<N> (first order) and Dual2<N> (second order), a Scalar trait, and a ProjectGeneric<S> surface that evaluates projections over dual numbers — feeding exact Jacobians into covariance propagation (CovMatrix2x2, computing Σ_out = J·Σ_in·Jᵀ) and second-order distortion via HessianFactors (Dual2<2>). DistortionRaster::compute sweeps TissotParams across an extent and exports to GeoTIFF or CSV.

Acceleration: SIMD, rayon, and GPU. Columnar reprojection goes wide: reproject_interleaved() / reproject_interleaved_xyz() batch with f64x4, and SIMD kernels land across the stack (inverse_batch/direct_batch in oxiproj-geodesic, project_fwd_batch_x4 4-lane in oxiproj-projections, Helmert SIMD batch, bilinear batch sampling). Transformer::transform_xy_par() adds rayon parallel batching behind the rayon feature. And there’s optional CUDA support behind the gpu feature: an oxiproj::gpu module powered by the Pure-Rust oxicuda stack — libcuda.so loaded at runtime, with no CUDA Toolkit at build time. Web Mercator (EPSG:4326↔3857) forward/inverse and the distortion field run as hand-written f64 PTX kernels, including a from-scratch f64 transcendental library (ln/exp/tan/atan/asinh/sinh, validated to ~1e-14 on hardware) since PTX only ships f32 approximations. There’s a helmert7_batch_gpu pure-arithmetic 3-D Helmert datum batch, transparent CPU fallback when no device is present, and an oxiproj transform --gpu flag.

Interop and geodesy. OxiProj now meets the Rust geo stack where it lives: geo-types interop (TransformGeoTypes for Point/LineString/Polygon/Multi*), geozero streaming reprojection (ReprojectionProcessor<P> with Arc<Transformer>), GeoArrow/GeoParquet CRS metadata via a hand-rolled JSON parser, and a Cloud-Optimized GeoTIFF reader (CogLayout, CogGridSampler) with a zero-dependency TIFF IFD parser. On the geodesy side: EpochTaggedCrs ([email protected], EPSG:[email protected]), an epoch-aware pipeline (transform_epoch_aware(), PlateMotionModel), a plate-motion frame chain (ITRF2020→ITRF2014→ITRF2008), GeoidGrid vertical-datum conversion, and SH geoid synthesis from ICGEM .gfc files (GeoidCoeffs::from_gfc() for EGM2008/EGM96).

Getting Started

The Rust path is unchanged — cargo add oxiproj (plus --features epsg for authority codes). What’s new in 0.1.1 is Python:

pip install oxiproj
from oxiproj import Transformer

t = Transformer("EPSG:4326", "EPSG:3857")   # epsg feature on by default in oxiproj-py
x, y = t.transform(9.0, 48.0)               # lon, lat -> Web Mercator meters
print(x, y)

Or analyze map distortion straight from the CLI with the new distort subcommand:

oxiproj distort --point 9.0 48.0

What’s New in 0.1.1

Tips

This is the foundation, widened

0.1.1 leans hard on the COOLJAPAN ecosystem, all grounded in real new dependencies: oxih5 backs the GGXF/HDF5 grid format, oxiblas powers the Helmert LSQ GEMM, oxicuda is the Pure-Rust GPU/PTX stack, oxiz does SMT verification, and oxiarc-deflate handles compressed grids — alongside the oxisql-sqlite-compat EPSG engine and oxihttp CDN fetch from 0.1.0.

The north star hasn’t moved: the OxiGDAL cutover — letting OxiGDAL drop proj-sys and build fully C-free — is still the goal we’re driving toward.

Repository: https://github.com/cool-japan/oxiproj

Star the repo if you want geospatial that runs in Rust, Python, the browser, and the GPU — all from one Pure-Rust core. Pure Rust cartography is here — no libproj, no FFI, no C toolchain.

KitaSan at COOLJAPAN OÜ June 21, 2026

↑ Back to all posts