Skip to content

Commit

Permalink
Scaffolding for GDALWarp binding.
Browse files Browse the repository at this point in the history
  • Loading branch information
metasim committed Jan 31, 2024
1 parent 1f2bc33 commit 576c57a
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 6 deletions.
96 changes: 93 additions & 3 deletions src/raster/warp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ mod reproject_options;
mod resample;
mod warp_options;

use gdal_sys::CPLErr;
use gdal_sys::{CPLErr, GDALDatasetH, GDALWarp};
pub use reproject_options::*;
pub use resample::*;
use std::ffi::CString;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::ptr;
pub use warp_options::*;

Expand All @@ -22,7 +22,7 @@ use crate::DriverManager;

use crate::errors::*;
use crate::spatial_ref::SpatialRef;
use crate::utils::{_last_cpl_err, _path_to_c_string};
use crate::utils::{_last_cpl_err, _last_null_pointer_err, _path_to_c_string};

/// Reproject raster dataset into the given [`SpatialRef`] and save result to `dst_file`.
pub fn create_and_reproject<P: AsRef<Path>>(
Expand Down Expand Up @@ -163,6 +163,79 @@ pub fn reproject_into(
Ok(())
}

pub fn warp<D>(source: &Dataset, dest: D, options: &GdalWarpOptions) -> Result<Dataset>
where
D: Into<WarpDestination>,
{
warp_multiple(&[source], dest, options)
}

pub fn warp_multiple<D>(source: &[&Dataset], dest: D, options: &GdalWarpOptions) -> Result<Dataset>
where
D: Into<WarpDestination>,
{
let app_opts = GdalWarpAppOptions::default();

if true {
todo!("how the hell do you go from {options:?} to GdalWarpAppOptions?");
}

let mut source = source.iter().map(|ds| ds.c_dataset()).collect::<Vec<_>>();

let dest = dest.into();
match dest {
WarpDestination::Dataset(ds) => {
let ds_c = unsafe {
GDALWarp(
ptr::null_mut(),
ds.c_dataset(),
source.len() as libc::c_int,
source.as_mut_ptr(),
app_opts.as_ptr(),
ptr::null_mut(),
)
};
if ds_c.is_null() {
Err(_last_null_pointer_err("GDALWarp"))
} else {
Ok(ds)
}
}
WarpDestination::Path(p) => {
let path = _path_to_c_string(&p)?;
let ds_c = unsafe {
GDALWarp(
path.as_ptr(),
ptr::null_mut(),
source.len() as libc::c_int,
source.as_ptr() as *mut GDALDatasetH,
app_opts.as_ptr(),
ptr::null_mut(),
)
};
Ok(unsafe { Dataset::from_c_dataset(ds_c) })
}
}
}

#[derive(Debug)]
pub enum WarpDestination {
Dataset(Dataset),
Path(PathBuf),
}

impl From<Dataset> for WarpDestination {
fn from(ds: Dataset) -> Self {
WarpDestination::Dataset(ds)
}
}

impl From<PathBuf> for WarpDestination {
fn from(path: PathBuf) -> Self {
WarpDestination::Path(path)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -251,4 +324,21 @@ mod tests {

Ok(())
}

#[test]
#[ignore]
fn test_warp() -> Result<()> {
let source = TempFixture::fixture("labels.tif");
let source_ds = Dataset::open(&source)?;
let dest = Path::new("target").join("labels-warp.tif");

let mut options = GdalWarpOptions::default();
options
.with_band_count(source_ds.raster_count())
.with_initial_value(InitValue::NoData)
.with_resampling_alg(WarpResampleAlg::NearestNeighbour);

warp(&source_ds, dest, &options)?;
Ok(())
}
}
48 changes: 45 additions & 3 deletions src/raster/warp/warp_options.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt::{Debug, Display, Formatter};
use std::ptr;
use std::ptr::NonNull;

use crate::cpl::CslStringList;
Expand All @@ -9,9 +10,9 @@ use crate::utils::_last_null_pointer_err;
use crate::xml::GdalXmlNode;
use gdal_sys::{
GDALCloneWarpOptions, GDALCreateWarpOptions, GDALDeserializeWarpOptions,
GDALDestroyWarpOptions, GDALSerializeWarpOptions, GDALWarpInitDefaultBandMapping,
GDALWarpInitDstNoDataReal, GDALWarpInitSrcNoDataReal, GDALWarpOptions,
GDALWarpResolveWorkingDataType,
GDALDestroyWarpOptions, GDALSerializeWarpOptions, GDALWarpAppOptions, GDALWarpAppOptionsFree,
GDALWarpAppOptionsNew, GDALWarpInitDefaultBandMapping, GDALWarpInitDstNoDataReal,
GDALWarpInitSrcNoDataReal, GDALWarpOptions, GDALWarpResolveWorkingDataType,
};
use libc::c_char;

Expand Down Expand Up @@ -246,6 +247,47 @@ impl Debug for GdalWarpOptions {
}
}

#[derive(Debug)]
pub struct GdalWarpAppOptions(NonNull<GDALWarpAppOptions>);

impl GdalWarpAppOptions {
/// Instatiate and empty set of warp options.
pub fn new() -> Self {
unsafe { Self::from_ptr(GDALWarpAppOptionsNew(ptr::null_mut(), ptr::null_mut())) }
}

/// Create Self from a raw pointer.
///
/// # Safety
/// Caller is responsible for ensuring `ptr` is not null, and
/// ownership of `ptr` is properly transferred
pub unsafe fn from_ptr(ptr: *mut GDALWarpAppOptions) -> Self {
Self(NonNull::new_unchecked(ptr))
}

/// Get a immutable pointer to C API options.
pub fn as_ptr(&self) -> *const GDALWarpAppOptions {
self.0.as_ptr()
}

/// Get a mutable pointer to C API options.
pub fn as_ptr_mut(&mut self) -> *mut GDALWarpAppOptions {
self.0.as_ptr()
}
}

impl Drop for GdalWarpAppOptions {
fn drop(&mut self) {
unsafe { GDALWarpAppOptionsFree(self.as_ptr_mut()) }
}
}

impl Default for GdalWarpAppOptions {
fn default() -> Self {
Self::new()
}
}

/// Specifies the initial value cells in the destination dataset during a warp operation.
///
/// See [`GdalWarpOptions::with_initial_value`].
Expand Down

0 comments on commit 576c57a

Please sign in to comment.