Skip to content

Commit

Permalink
Merge pull request #68 from rochamatcomp/master
Browse files Browse the repository at this point in the history
RasterBand to Ndarray, with failure.
  • Loading branch information
jdroenner authored Mar 18, 2019
2 parents a36aee4 + 5246812 commit 1f74666
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 10 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ documentation = "https://georust.github.io/gdal/"

[features]
bindgen = ["gdal-sys/bindgen"]
array = ["ndarray"]

[dependencies]
failure = "0.1"
Expand All @@ -21,6 +22,7 @@ geo-types = "0.3"
# gdal-sys = { path = "gdal-sys", version = "0.2"}
gdal-sys = "0.2"
num-traits = "0.2"
ndarray = {version = "0.12.1", optional = true }

[workspace]
members = ["gdal-sys"]
12 changes: 11 additions & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ pub struct Error {
inner: Context<ErrorKind>,
}

#[derive(Clone, Eq, PartialEq, Debug, Fail)]
#[derive(Clone, PartialEq, Debug, Fail)]
pub enum ErrorKind {

#[fail(display = "FfiNulError")]
FfiNulError(#[cause] std::ffi::NulError),
#[fail(display = "StrUtf8Error")]
StrUtf8Error(#[cause] std::str::Utf8Error),
#[cfg(feature = "ndarray")]
#[fail(display = "NdarrayShapeError")]
NdarrayShapeError(#[cause] ndarray::ShapeError),
#[fail(display = "CPL error class: '{:?}', error number: '{}', error msg: '{}'", class, number, msg)]
CplError {
class: CPLErr::Type,
Expand Down Expand Up @@ -109,3 +112,10 @@ impl From<std::str::Utf8Error> for Error {
Error { inner: Context::new(ErrorKind::StrUtf8Error(err)) }
}
}

#[cfg(feature = "ndarray")]
impl From<ndarray::ShapeError> for Error {
fn from(err: ndarray::ShapeError) -> Error {
Error { inner: Context::new(ErrorKind::NdarrayShapeError(err)) }
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ extern crate geo_types;
extern crate libc;
extern crate num_traits;

#[cfg(feature = "ndarray")]
extern crate ndarray;

pub use version::version_info;

pub mod config;
Expand Down
65 changes: 58 additions & 7 deletions src/raster/dataset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use gdal_major_object::MajorObject;
use metadata::Metadata;
use gdal_sys::{self, CPLErr, GDALAccess, GDALDatasetH, GDALDataType, GDALMajorObjectH};

#[cfg(feature = "ndarray")]
use ndarray::Array2;

use errors::*;

pub type GeoTransform = [c_double; 6];
Expand All @@ -32,7 +35,6 @@ impl Drop for Dataset {
}
}


impl Dataset {
pub fn open(path: &Path) -> Result<Dataset> {
_register_drivers();
Expand Down Expand Up @@ -69,6 +71,16 @@ impl Dataset {
(size_x, size_y)
}

/// Get block size from a 'Dataset'.
/// # Arguments
/// * band_index - the band_index
/*
pub fn size_block(&self, band_index: isize) -> (usize, usize) {
let band = self.rasterband(band_index)?;
band.size_block()
}
*/

pub fn driver(&self) -> Driver {
unsafe {
let c_driver = gdal_sys::GDALGetDatasetDriver(self.c_dataset);
Expand All @@ -91,31 +103,52 @@ impl Dataset {
Ok(())
}

pub fn set_geo_transform(&self, tr: &GeoTransform) -> Result<()> {
assert_eq!(tr.len(), 6);
/// Affine transformation called geotransformation.
///
/// This is like a linear transformation preserves points, straight lines and planes.
/// Also, sets of parallel lines remain parallel after an affine transformation.
/// # Arguments
/// * transformation - coeficients of transformations
///
/// x-coordinate of the top-left corner pixel (x-offset)
/// width of a pixel (x-resolution)
/// row rotation (typically zero)
/// y-coordinate of the top-left corner pixel
/// column rotation (typically zero)
/// height of a pixel (y-resolution, typically negative)
pub fn set_geo_transform(&self, transformation: &GeoTransform) -> Result<()> {
assert_eq!(transformation.len(), 6);
let rv = unsafe {
gdal_sys::GDALSetGeoTransform(self.c_dataset, tr.as_ptr() as *mut f64)
gdal_sys::GDALSetGeoTransform(self.c_dataset, transformation.as_ptr() as *mut f64)
};
if rv != CPLErr::CE_None {
Err(_last_cpl_err(rv))?;
}
Ok(())
}

/// Get affine transformation coefficients.
///
/// x-coordinate of the top-left corner pixel (x-offset)
/// width of a pixel (x-resolution)
/// row rotation (typically zero)
/// y-coordinate of the top-left corner pixel
/// column rotation (typically zero)
/// height of a pixel (y-resolution, typically negative)
pub fn geo_transform(&self) -> Result<GeoTransform> {
let mut tr = GeoTransform::default();
let mut transformation = GeoTransform::default();
let rv = unsafe {
gdal_sys::GDALGetGeoTransform(
self.c_dataset,
tr.as_mut_ptr()
transformation.as_mut_ptr()
)
};

// check if the dataset has a GeoTransform
if rv != CPLErr::CE_None {
Err(_last_cpl_err(rv))?;
}
Ok(tr)
Ok(transformation)
}

pub fn create_copy(
Expand Down Expand Up @@ -192,6 +225,24 @@ impl Dataset {
self.rasterband(band_index)?.read_as(window, window_size, size)
}

#[cfg(feature = "ndarray")]
/// Read a 'Array2<T>' from a 'Dataset'. T implements 'GdalType'.
/// # Arguments
/// * band_index - the band_index
/// * window - the window position from top left
/// * window_size - the window size (GDAL will interpolate data if window_size != array_size)
/// * array_size - the desired size of the 'Array'
pub fn read_as_array<T: Copy + GdalType>(
&self,
band_index: isize,
window: (isize, isize),
window_size: (usize, usize),
array_size: (usize, usize),
) -> Result<Array2<T>>
{
self.rasterband(band_index)?.read_as_array(window, window_size, array_size)
}

/// Write a 'Buffer<T>' into a 'Dataset'.
/// # Arguments
/// * band_index - the band_index
Expand Down
101 changes: 101 additions & 0 deletions src/raster/rasterband.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use metadata::Metadata;
use gdal_sys::{self, CPLErr, GDALDataType, GDALMajorObjectH, GDALRasterBandH, GDALRWFlag};
use utils::_last_cpl_err;

#[cfg(feature = "ndarray")]
use ndarray::{Array2};

use errors::*;

pub struct RasterBand<'a> {
Expand All @@ -22,6 +25,23 @@ impl <'a> RasterBand<'a> {
RasterBand { c_rasterband, owning_dataset }
}

/// Get block size from a 'Dataset'.
/// # Arguments
/// * band_index - the band_index
pub fn block_size(&self) -> (usize, usize) {
let mut size_x = 0;
let mut size_y = 0;

unsafe {
gdal_sys::GDALGetBlockSize(
self.c_rasterband,
&mut size_x,
&mut size_y
)
};
(size_x as usize, size_y as usize)
}

/// Read a 'Buffer<T>' from a 'Dataset'. T implements 'GdalType'
/// # Arguments
/// * band_index - the band_index
Expand Down Expand Up @@ -65,6 +85,52 @@ impl <'a> RasterBand<'a> {
Ok(Buffer{size, data})
}

#[cfg(feature = "ndarray")]
/// Read a 'Array2<T>' from a 'Dataset'. T implements 'GdalType'.
/// # Arguments
/// * window - the window position from top left
/// * window_size - the window size (GDAL will interpolate data if window_size != array_size)
/// * array_size - the desired size of the 'Array'
/// # Docs
/// The Matrix shape is (rows, cols) and raster shape is (cols in x-axis, rows in y-axis).
pub fn read_as_array<T: Copy + GdalType>(
&self,
window: (isize, isize),
window_size: (usize, usize),
array_size: (usize, usize),
) -> Result<Array2<T>>
{
let pixels = (array_size.0 * array_size.1) as usize;
let mut data: Vec<T> = Vec::with_capacity(pixels);

let values = unsafe {
gdal_sys::GDALRasterIO(
self.c_rasterband,
GDALRWFlag::GF_Read,
window.0 as c_int,
window.1 as c_int,
window_size.0 as c_int,
window_size.1 as c_int,
data.as_mut_ptr() as GDALRasterBandH,
array_size.0 as c_int,
array_size.1 as c_int,
T::gdal_type(),
0,
0
)
};
if values != CPLErr::CE_None {
Err(_last_cpl_err(values))?;
}

unsafe {
data.set_len(pixels);
};

// Matrix shape is (rows, cols) and raster shape is (cols in x-axis, rows in y-axis)
Array2::from_shape_vec((array_size.1, array_size.0) , data).map_err(Into::into)
}

/// Read a full 'Dataset' as 'Buffer<T>'.
/// # Arguments
/// * band_index - the band_index
Expand All @@ -80,6 +146,41 @@ impl <'a> RasterBand<'a> {
)
}

#[cfg(feature = "ndarray")]
/// Read a 'Array2<T>' from a 'Dataset' block. T implements 'GdalType'
/// # Arguments
/// * block_index - the block index
/// # Docs
/// The Matrix shape is (rows, cols) and raster shape is (cols in x-axis, rows in y-axis).
pub fn read_block<T: Copy + GdalType>(
&self,
block_index: (usize, usize)
) -> Result<Array2<T>>
{
let size = self.block_size();
let pixels = (size.0 * size.1) as usize;
let mut data: Vec<T> = Vec::with_capacity(pixels);

//let no_data:
let rv = unsafe {
gdal_sys::GDALReadBlock(
self.c_rasterband,
block_index.0 as c_int,
block_index.1 as c_int,
data.as_mut_ptr() as GDALRasterBandH
)
};
if rv != CPLErr::CE_None {
Err(_last_cpl_err(rv))?;
}

unsafe {
data.set_len(pixels);
};

Array2::from_shape_vec((size.1, size.0), data).map_err(Into::into)
}

// Write a 'Buffer<T>' into a 'Dataset'.
/// # Arguments
/// * band_index - the band_index
Expand Down
Loading

0 comments on commit 1f74666

Please sign in to comment.