Skip to content

Commit

Permalink
Merge #291
Browse files Browse the repository at this point in the history
291: allow reading dimensions from md groups r=jdroenner,lnicola a=ChristianBeilschmidt

- [X] I agree to follow the project's [code of conduct](https://github.com/georust/gdal/blob/master/CODE_OF_CONDUCT.md).
- [X] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users.
---

Added the wrapper for the dimension call for md groups.

Co-authored-by: Christian Beilschmidt <christian.beilschmidt@geoengine.de>
  • Loading branch information
bors[bot] and ChristianBeilschmidt authored Sep 2, 2022
2 parents f22bde0 + b830df0 commit 2a29d92
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 40 deletions.
6 changes: 5 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,15 @@
- Added program wrapper for `GDALMultiDimTranslate`

- <https://github.com/georust/gdal/pull/289>

- Test that `GdalError` is `Send`

- <https://github.com/georust/gdal/pull/293>

- Allow reading `Dimension`s from `Group`s in multimensional `Dataset`s.

- <https://github.com/georust/gdal/pull/291>

## 0.12

- Bump Rust edition to 2021
Expand Down
136 changes: 98 additions & 38 deletions src/raster/mdarray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ use gdal_sys::{
GDALDimensionGetSize, GDALDimensionHS, GDALDimensionRelease, GDALExtendedDataTypeClass,
GDALExtendedDataTypeGetClass, GDALExtendedDataTypeGetName,
GDALExtendedDataTypeGetNumericDataType, GDALExtendedDataTypeH, GDALExtendedDataTypeRelease,
GDALGroupGetAttribute, GDALGroupGetGroupNames, GDALGroupGetMDArrayNames, GDALGroupGetName,
GDALGroupH, GDALGroupOpenGroup, GDALGroupOpenMDArray, GDALGroupRelease,
GDALMDArrayGetAttribute, GDALMDArrayGetDataType, GDALMDArrayGetDimensionCount,
GDALMDArrayGetDimensions, GDALMDArrayGetNoDataValueAsDouble, GDALMDArrayGetSpatialRef,
GDALMDArrayGetTotalElementsCount, GDALMDArrayGetUnit, GDALMDArrayH, GDALMDArrayRelease,
OSRDestroySpatialReference, VSIFree,
GDALGroupGetAttribute, GDALGroupGetDimensions, GDALGroupGetGroupNames,
GDALGroupGetMDArrayNames, GDALGroupGetName, GDALGroupH, GDALGroupOpenGroup,
GDALGroupOpenMDArray, GDALGroupRelease, GDALMDArrayGetAttribute, GDALMDArrayGetDataType,
GDALMDArrayGetDimensionCount, GDALMDArrayGetDimensions, GDALMDArrayGetNoDataValueAsDouble,
GDALMDArrayGetSpatialRef, GDALMDArrayGetTotalElementsCount, GDALMDArrayGetUnit, GDALMDArrayH,
GDALMDArrayRelease, OSRDestroySpatialReference, VSIFree,
};
use libc::c_void;
use std::ffi::CString;
Expand All @@ -38,11 +38,17 @@ pub struct MDArray<'a> {
}

#[derive(Debug)]
enum GroupOrDimension<'a> {
pub enum GroupOrDimension<'a> {
Group { _group: &'a Group<'a> },
Dimension { _dimension: &'a Dimension<'a> },
}

#[derive(Debug)]
pub enum GroupOrArray<'a> {
Group { _group: &'a Group<'a> },
MDArray { _md_array: &'a MDArray<'a> },
}

impl Drop for MDArray<'_> {
fn drop(&mut self) {
unsafe {
Expand Down Expand Up @@ -86,29 +92,34 @@ impl<'a> MDArray<'a> {
}

pub fn dimensions(&self) -> Result<Vec<Dimension>> {
unsafe {
let mut num_dimensions: usize = 0;
let c_dimensions =
GDALMDArrayGetDimensions(self.c_mdarray, std::ptr::addr_of_mut!(num_dimensions));
let mut num_dimensions: usize = 0;

if c_dimensions.is_null() {
return Err(_last_null_pointer_err("GDALMDArrayGetDimensions"));
}
let c_dimensions = unsafe { GDALMDArrayGetDimensions(self.c_mdarray, &mut num_dimensions) };

let dimensions_ref = std::slice::from_raw_parts_mut(c_dimensions, num_dimensions);
// `num_dimensions` is `0`, we can safely return an empty vector
// `GDALMDArrayGetDimensions` does not state that errors can occur
if num_dimensions > 0 && c_dimensions.is_null() {
return Err(_last_null_pointer_err("GDALMDArrayGetDimensions"));
}

let mut dimensions: Vec<Dimension> = Vec::with_capacity(num_dimensions);
let dimensions_ref =
unsafe { std::slice::from_raw_parts_mut(c_dimensions, num_dimensions) };

for c_dimension in dimensions_ref {
let dimension = Dimension::from_c_dimension(self, *c_dimension);
dimensions.push(dimension);
}
let mut dimensions: Vec<Dimension> = Vec::with_capacity(num_dimensions);

// only free the array, not the dimensions themselves
VSIFree(c_dimensions as *mut c_void);
for c_dimension in dimensions_ref {
let dimension = unsafe {
Dimension::from_c_dimension(GroupOrArray::MDArray { _md_array: self }, *c_dimension)
};
dimensions.push(dimension);
}

Ok(dimensions)
// only free the array, not the dimensions themselves
unsafe {
VSIFree(c_dimensions as *mut c_void);
}

Ok(dimensions)
}

pub fn datatype(&self) -> ExtendedDataType {
Expand Down Expand Up @@ -309,9 +320,8 @@ impl<'a> MDArray<'a> {
pub fn no_data_value_as_double(&self) -> Option<f64> {
let mut has_nodata = 0;

let no_data_value = unsafe {
GDALMDArrayGetNoDataValueAsDouble(self.c_mdarray, std::ptr::addr_of_mut!(has_nodata))
};
let no_data_value =
unsafe { GDALMDArrayGetNoDataValueAsDouble(self.c_mdarray, &mut has_nodata) };

if has_nodata == 0 {
None
Expand Down Expand Up @@ -414,7 +424,7 @@ impl<'a> Group<'a> {
}
}

pub fn open_group(&self, name: &str, options: CslStringList) -> Result<Group> {
pub fn open_group(&'_ self, name: &str, options: CslStringList) -> Result<Group<'a>> {
let name = CString::new(name)?;

unsafe {
Expand All @@ -441,13 +451,42 @@ impl<'a> Group<'a> {
Ok(Attribute::from_c_attribute(c_attribute))
}
}

pub fn dimensions(&self, options: CslStringList) -> Result<Vec<Dimension>> {
unsafe {
let mut num_dimensions: usize = 0;
let c_dimensions =
GDALGroupGetDimensions(self.c_group, &mut num_dimensions, options.as_ptr());

// `num_dimensions` is `0`, we can safely return an empty vector
// `GDALGroupGetDimensions` does not state that errors can occur
if num_dimensions > 0 && c_dimensions.is_null() {
return Err(_last_null_pointer_err("GDALGroupGetDimensions"));
}

let dimensions_ref = std::slice::from_raw_parts_mut(c_dimensions, num_dimensions);

let mut dimensions: Vec<Dimension> = Vec::with_capacity(num_dimensions);

for c_dimension in dimensions_ref {
let dimension =
Dimension::from_c_dimension(GroupOrArray::Group { _group: self }, *c_dimension);
dimensions.push(dimension);
}

// only free the array, not the dimensions themselves
VSIFree(c_dimensions as *mut c_void);

Ok(dimensions)
}
}
}

/// A `GDALDimension` with name and size
#[derive(Debug)]
pub struct Dimension<'a> {
c_dimension: *mut GDALDimensionHS,
_md_array: &'a MDArray<'a>,
_parent: GroupOrArray<'a>,
}

impl Drop for Dimension<'_> {
Expand All @@ -463,10 +502,13 @@ impl<'a> Dimension<'a> {
///
/// # Safety
/// This method operates on a raw C pointer
pub fn from_c_dimension(_md_array: &'a MDArray<'a>, c_dimension: *mut GDALDimensionHS) -> Self {
pub unsafe fn from_c_dimension(
_parent: GroupOrArray<'a>,
c_dimension: *mut GDALDimensionHS,
) -> Self {
Self {
c_dimension,
_md_array,
_parent,
}
}
pub fn size(&self) -> usize {
Expand Down Expand Up @@ -595,10 +637,8 @@ impl Attribute {
unsafe {
let mut num_dimensions = 0;

let c_dimension_sizes = GDALAttributeGetDimensionsSize(
self.c_attribute,
std::ptr::addr_of_mut!(num_dimensions),
);
let c_dimension_sizes =
GDALAttributeGetDimensionsSize(self.c_attribute, &mut num_dimensions);

let dimension_sizes = std::slice::from_raw_parts(c_dimension_sizes, num_dimensions)
.iter()
Expand Down Expand Up @@ -646,8 +686,7 @@ impl Attribute {
pub fn read_as_i64_array(&self) -> Vec<i32> {
unsafe {
let mut array_len = 0;
let c_int_array =
GDALAttributeReadAsIntArray(self.c_attribute, std::ptr::addr_of_mut!(array_len));
let c_int_array = GDALAttributeReadAsIntArray(self.c_attribute, &mut array_len);

let int_array = std::slice::from_raw_parts(c_int_array, array_len).to_vec();

Expand All @@ -664,8 +703,7 @@ impl Attribute {
pub fn read_as_f64_array(&self) -> Vec<f64> {
unsafe {
let mut array_len = 0;
let c_int_array =
GDALAttributeReadAsDoubleArray(self.c_attribute, std::ptr::addr_of_mut!(array_len));
let c_int_array = GDALAttributeReadAsDoubleArray(self.c_attribute, &mut array_len);

let float_array = std::slice::from_raw_parts(c_int_array, array_len).to_vec();

Expand Down Expand Up @@ -755,6 +793,17 @@ mod tests {
};
let dataset = Dataset::open_ex("fixtures/byte_no_cf.nc", dataset_options).unwrap();
let root_group = dataset.root_group().unwrap();

// group dimensions
let group_dimensions = root_group.dimensions(CslStringList::new()).unwrap();
let group_dimensions_names: Vec<String> = group_dimensions
.into_iter()
.map(|dimensions| dimensions.name())
.collect();
assert_eq!(group_dimensions_names, vec!["x", "y"]);

// array dimensions

let array_name = "Band1".to_string();
let options = CslStringList::new(); //Driver specific options determining how the array should be opened. Pass nullptr for default behavior.
let md_array = root_group.open_md_array(&array_name, options).unwrap();
Expand All @@ -765,6 +814,7 @@ mod tests {
}
assert_eq!(dimension_names, vec!["y".to_string(), "x".to_string()])
}

#[test]
fn test_dimension_size() {
let dataset_options = DatasetOptions {
Expand Down Expand Up @@ -843,6 +893,7 @@ mod tests {
let dataset = Dataset::open_ex("fixtures/byte_no_cf.nc", dataset_options).unwrap();

let root_group = dataset.root_group().unwrap();

let md_array = root_group
.open_md_array("Band1", CslStringList::new())
.unwrap();
Expand Down Expand Up @@ -914,6 +965,12 @@ mod tests {
let group_science = root_group
.open_group("science", CslStringList::new())
.unwrap();

assert!(group_science
.dimensions(Default::default())
.unwrap()
.is_empty());

let group_grids = group_science
.open_group("grids", CslStringList::new())
.unwrap();
Expand Down Expand Up @@ -962,6 +1019,9 @@ mod tests {
let group_grids = group_science
.open_group("grids", CslStringList::new())
.unwrap();

drop(group_science); // check that `Group`s do not borrow each other

let group_data = group_grids
.open_group("data", CslStringList::new())
.unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/raster/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod types;
mod warp;

#[cfg(all(major_ge_3, minor_ge_1))]
pub use mdarray::{ExtendedDataType, ExtendedDataTypeClass, Group, MDArray};
pub use mdarray::{Attribute, Dimension, ExtendedDataType, ExtendedDataTypeClass, Group, MDArray};
pub use rasterband::{
Buffer, ByteBuffer, CmykEntry, ColorEntry, ColorInterpretation, ColorTable, GrayEntry,
HlsEntry, PaletteInterpretation, RasterBand, ResampleAlg, RgbaEntry,
Expand Down

0 comments on commit 2a29d92

Please sign in to comment.