Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RasterBand to Ndarray, with failure. #68

Merged
merged 4 commits into from
Mar 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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