The Rust GDAL Cookbook
This book is a Rust adaptation of the excellent Python GDAL/OGR Cookbook.
First steps
The Rust GDAL bindings consist of two crates, gdal
and gdal-sys
.
The former contains high-level, idiomatic APIs, while the latter exposes the C API almost unchanged.
Since the high-level bindings are incomplete, at times you will need to drop down to gdal-sys
.
When that happens, a familiarity with the GDAL C API will be very useful.
And if you want to expand the gdal
API, pull requests are always appreciated!
Linking with GDAL
gdal-sys
does not compile GDAL from source, so it has to be available on your system.
On Linux, that usually means installing a GDAL development package (gdal-devel
, libgdal-dev
or gdal
).
If you are an advanced user, you can use the GDAL_INCLUDE_DIR
, GDAL_LIB_DIR
and GDAL_STATIC
environment variables to control the linking.
On Windows and MacOS, you will need to acquire or build GDAL.
The environment variables mentioned above work, but setting GDAL_HOME
, or even using WSL, might be easier for Windows users.
Generating the bindings
The gdal
crate bundles bindings for some versions of GDAL, but if you have a newer one, you can enable the bindgen
feature.
Checking the GDAL version
Once you've got everything set up, run cargo add gdal
and try the following code:
use gdal::version::VersionInfo; fn main() { println!("{}", gdal::version_info("VERSION_NUM")); // 3060200 println!("{}", VersionInfo::release_name()); // 3.6.2 }
Setting an error handler
The following example installs an error handle and emits an error.
You can notice that there is no API available in gdal
, so it uses the gdal-sys
crate, at the cost of a lot of ceremony.
use std::ffi::CString; use gdal::{config, errors::CplErrType}; use gdal_sys::CPLErr; fn error_handler(class: CplErrType, number: i32, message: &str) { let class = match class { CplErrType::None => "[NONE]", CplErrType::Debug => "[DEBUG]", CplErrType::Warning => "[WARN]", CplErrType::Failure => "[ERROR]", CplErrType::Fatal => "[FATAL]", }; eprintln!("{class} [{number}] {message}"); } fn main() { config::set_error_handler(error_handler); unsafe { let message = CString::new("test error").unwrap(); gdal_sys::CPLError(CPLErr::CE_Debug, 2, message.as_ptr()); // [DEBUG] [2] test error } config::remove_error_handler(); }
Geometry
Create a Point
use gdal::{errors, vector::Geometry}; use gdal_sys::OGRwkbGeometryType; fn main() -> errors::Result<()> { let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?; point.add_point_2d((1198054.34, 648493.09)); println!("{}", point.wkt()?); // POINT (1198054.34 648493.09) Ok(()) }
Create a Linestring
use gdal::{errors, vector::Geometry}; use gdal_sys::OGRwkbGeometryType; fn main() -> errors::Result<()> { let mut line_string = Geometry::empty(OGRwkbGeometryType::wkbLineString)?; line_string.add_point_2d((1116651.439379124, 637392.6969887456)); line_string.add_point_2d((1188804.0108498496, 652655.7409537067)); line_string.add_point_2d((1226730.3625203592, 634155.0816022386)); line_string.add_point_2d((1281307.30760719, 636467.6640211721)); println!("{}", line_string.wkt()?); Ok(()) }
Create a Polygon
use gdal::{errors, vector::Geometry}; use gdal_sys::OGRwkbGeometryType; fn main() -> errors::Result<()> { let mut ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?; ring.add_point_2d((1179091.1646903288, 712782.8838459781)); ring.add_point_2d((1161053.0218226474, 667456.2684348812)); ring.add_point_2d((1214704.933941905, 641092.8288590391)); ring.add_point_2d((1228580.428455506, 682719.3123998424)); ring.add_point_2d((1218405.0658121984, 721108.1805541387)); ring.add_point_2d((1179091.1646903288, 712782.8838459781)); let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?; poly.add_geometry(ring)?; println!("{}", poly.wkt()?); Ok(()) }
Create a Polygon with holes
use gdal::{errors, vector::Geometry}; use gdal_sys::OGRwkbGeometryType; fn main() -> errors::Result<()> { let mut outer_ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?; outer_ring.add_point_2d((1154115.274565847, 686419.4442701361)); outer_ring.add_point_2d((1154115.274565847, 653118.2574374934)); outer_ring.add_point_2d((1165678.1866605144, 653118.2574374934)); outer_ring.add_point_2d((1165678.1866605144, 686419.4442701361)); outer_ring.add_point_2d((1154115.274565847, 686419.4442701361)); let mut inner_ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?; inner_ring.add_point_2d((1149490.1097279799, 691044.6091080031)); inner_ring.add_point_2d((1149490.1097279799, 648030.5761158396)); inner_ring.add_point_2d((1191579.1097525698, 648030.5761158396)); inner_ring.add_point_2d((1191579.1097525698, 691044.6091080031)); inner_ring.add_point_2d((1149490.1097279799, 691044.6091080031)); let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?; poly.add_geometry(outer_ring)?; poly.add_geometry(inner_ring)?; println!("{}", poly.wkt()?); Ok(()) }
Create a MultiPoint
use gdal::{errors, vector::Geometry}; use gdal_sys::OGRwkbGeometryType; fn main() -> errors::Result<()> { let mut multi_point = Geometry::empty(OGRwkbGeometryType::wkbMultiPoint)?; let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?; point.add_point_2d((1251243.7361610543, 598078.7958668759)); multi_point.add_geometry(point)?; let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?; point.add_point_2d((1240605.8570339603, 601778.9277371694)); multi_point.add_geometry(point)?; let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?; point.add_point_2d((1250318.7031934808, 606404.0925750365)); multi_point.add_geometry(point)?; println!("{}", multi_point.wkt()?); Ok(()) }
Create a MultiPolygon
use gdal::{errors, vector::Geometry}; use gdal_sys::OGRwkbGeometryType; fn main() -> errors::Result<()> { let mut multi_polygon = Geometry::empty(OGRwkbGeometryType::wkbMultiPolygon)?; let mut ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?; ring.add_point_2d((1204067.0548148106, 634617.5980860253)); ring.add_point_2d((1204067.0548148106, 620742.1035724243)); ring.add_point_2d((1215167.4504256917, 620742.1035724243)); ring.add_point_2d((1215167.4504256917, 634617.5980860253)); ring.add_point_2d((1204067.0548148106, 634617.5980860253)); let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?; poly.add_geometry(ring)?; multi_polygon.add_geometry(poly)?; let mut ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?; ring.add_point_2d((1179553.6811741155, 647105.5431482664)); ring.add_point_2d((1179553.6811741155, 626292.3013778647)); ring.add_point_2d((1194354.20865529, 626292.3013778647)); ring.add_point_2d((1194354.20865529, 647105.5431482664)); ring.add_point_2d((1179553.6811741155, 647105.5431482664)); let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?; poly.add_geometry(ring)?; multi_polygon.add_geometry(poly)?; println!("{}", multi_polygon.wkt()?); Ok(()) }
Create a GeometryCollection
use gdal::{errors, vector::Geometry}; use gdal_sys::OGRwkbGeometryType; fn main() -> errors::Result<()> { let mut geometry_collection = Geometry::empty(OGRwkbGeometryType::wkbGeometryCollection)?; let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?; point.add_point_2d((-122.23, 47.09)); geometry_collection.add_geometry(point)?; let mut line_string = Geometry::empty(OGRwkbGeometryType::wkbLineString)?; line_string.add_point_2d((-122.60, 47.14)); line_string.add_point_2d((-122.48, 47.23)); geometry_collection.add_geometry(line_string)?; println!("{}", geometry_collection.wkt()?); Ok(()) }
Create a Geometry from WKT
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = "POINT (1120351.5712494177 741921.4223245403)"; let point = Geometry::from_wkt(&wkt)?; let (x, y, _) = point.get_point(0); println!("{x} {y}"); // 1120351.5712494177 741921.4223245403 Ok(()) }
Create a Geometry from GeoJSON
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = r#"{"type":"Point","coordinates":[108420.33,753808.59]}"#; let point = Geometry::from_geojson(&wkt)?; let (x, y, _) = point.get_point(0); println!("{x} {y}"); // 108420.33 753808.59 Ok(()) }
Create a Geometry from GML
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = r#"<gml:Point xmlns:gml="http://www.opengis.net/gml"><gml:coordinates>108420.33,753808.59</gml:coordinates></gml:Point>""#; let point = Geometry::from_gml(&wkt)?; let (x, y, _) = point.get_point(0); println!("{x} {y}"); // 108420.33 753808.59 Ok(()) }
Create a Geometry from WKB
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkb = [ 0x00, 0x80, 0x00, 0x00, 0x01, 0x41, 0x32, 0x47, 0xe6, 0x57, 0x0a, 0x3d, 0x71, 0x41, 0x23, 0xca, 0x5a, 0x2e, 0x14, 0x7a, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let point = Geometry::from_wkb(&wkb)?; let (x, y, _) = point.get_point(0); println!("{x} {y}"); // 1198054.34 648493.09 Ok(()) }
Count points in a Geometry
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = "LINESTRING (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)"; let line_string = Geometry::from_wkt(&wkt)?; let count = line_string.point_count(); println!("Geometry has {count} points"); // Geometry has 4 points Ok(()) }
Count geometries in a Geometry
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = "MULTIPOINT (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)"; let points = Geometry::from_wkt(&wkt)?; let count = points.geometry_count(); println!("Geometry has {count} geometries"); // Geometry has 4 geometries Ok(()) }
Buffer a Geometry
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = "POINT (1198054.34 648493.09)"; let point = Geometry::from_wkt(&wkt)?; let distance = 500.0; let poly = point.buffer(distance, 2)?; let poly_wkt = poly.wkt()?; println!("{wkt} buffered by {distance} is {poly_wkt}"); // POINT (1198054.34 648493.09) buffered by 500 is POLYGON ((1198554.34 648493.09,1198407.89339059 648139.536609407,1198054.34 647993.09,1197700.78660941 648139.536609407,1197554.34 648493.09,1197700.78660941 648846.643390593,1198054.34 648993.09,1198407.89339059 648846.643390593,1198554.34 648493.09)) Ok(()) }
Compute the area of a Geometry
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = "POLYGON ((1162440.5712740074 672081.4332727483, 1162440.5712740074 647105.5431482664, 1195279.2416228633 647105.5431482664, 1195279.2416228633 672081.4332727483, 1162440.5712740074 672081.4332727483))"; let poly = Geometry::from_wkt(&wkt)?; let area = poly.area(); println!("Area: {area:.2}"); // 820175022.47 Ok(()) }
Compute the length of a Geometry
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt = "LINESTRING (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)"; let line_string = Geometry::from_wkt(&wkt)?; let length = line_string.length(); println!("Length: {length:.2}"); // Length: 76121.94 Ok(()) }
Get the type of a Geometry as a string
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkts = [ "POINT (1198054.34 648493.09)", "LINESTRING (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)", "POLYGON ((1162440.5712740074 672081.4332727483, 1162440.5712740074 647105.5431482664, 1195279.2416228633 647105.5431482664, 1195279.2416228633 672081.4332727483, 1162440.5712740074 672081.4332727483))" ]; for wkt in wkts { let geom = Geometry::from_wkt(wkt)?; println!("{}", geom.geometry_name()); } // POINT // LINESTRING // POLYGON Ok(()) }
Compute the intersection of two Geometries
use gdal::{errors, vector::Geometry}; fn main() -> errors::Result<()> { let wkt_1 = "POLYGON ((1208064.271243039 624154.6783778917, 1208064.271243039 601260.9785661874, 1231345.9998651114 601260.9785661874, 1231345.9998651114 624154.6783778917, 1208064.271243039 624154.6783778917))"; let wkt_2 = "POLYGON ((1199915.6662253144 633079.3410163528, 1199915.6662253144 614453.958118695, 1219317.1067437078 614453.958118695, 1219317.1067437078 633079.3410163528, 1199915.6662253144 633079.3410163528)))"; let poly_1 = Geometry::from_wkt(wkt_1)?; let poly_2 = Geometry::from_wkt(wkt_2)?; if let Some(intersection) = poly_1.intersection(&poly_2) { let wkt = intersection.wkt()?; println!("{}", wkt); } // POLYGON ((1208064.27124304 624154.678377892,1219317.10674371 624154.678377892,1219317.10674371 614453.958118695,1208064.27124304 614453.958118695,1208064.27124304 624154.678377892)) Ok(()) }