Skip to content

Commit

Permalink
Merge pull request #145 from dmarteau/update_spatial_ref
Browse files Browse the repository at this point in the history
Add more SpatialRef methods
  • Loading branch information
jdroenner authored Jan 27, 2021
2 parents c1c2720 + c7733fe commit b43596c
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changes

## Unreleased
* Add more functions to SpatialRef implementation
* <https://github.com/georust/gdal/pull/145>
* **Breaking**: Change `Feature::field` return type from
`Result<FieldValue>` to `Result<Option<FieldValue>>`. Fields
can be null. Before this change, if a field was null, the value
Expand Down
5 changes: 5 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ pub enum GdalError {
to: String,
msg: Option<String>,
},
#[error("Axis not found for key '{key}' in method '{method_name}'")]
AxisNotFoundError {
key: String,
method_name: &'static str,
},
}
4 changes: 2 additions & 2 deletions src/spatial_ref/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod srs;

pub use srs::CoordTransform;
pub use srs::SpatialRef;
pub use gdal_sys::OGRAxisOrientation;
pub use srs::{AxisOrientationType, CoordTransform, SpatialRef};

#[cfg(test)]
mod tests;
157 changes: 157 additions & 0 deletions src/spatial_ref/srs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ impl CoordTransform {
}
}

#[derive(Debug, Clone)]
pub struct AreaOfUse {
pub west_lon_degree: f64,
pub south_lat_degree: f64,
pub east_lon_degree: f64,
pub north_lat_degree: f64,
pub name: String,
}

pub type AxisOrientationType = gdal_sys::OGRAxisOrientation::Type;

#[derive(Debug)]
pub struct SpatialRef(OGRSpatialReferenceH);

Expand Down Expand Up @@ -303,6 +314,123 @@ impl SpatialRef {
}
}

#[cfg(major_ge_3)]
pub fn get_name(&self) -> Result<String> {
let c_ptr = unsafe { gdal_sys::OSRGetName(self.0) };
if c_ptr.is_null() {
return Err(_last_null_pointer_err("OSRGetName"));
}
Ok(_string(c_ptr))
}

pub fn get_angular_units_name(&self) -> Result<String> {
let mut c_ptr = ptr::null_mut();
unsafe { gdal_sys::OSRGetAngularUnits(self.0, &mut c_ptr) };
if c_ptr.is_null() {
return Err(_last_null_pointer_err("OSRGetAngularUnits"));
}
Ok(_string(c_ptr))
}

pub fn get_angular_units(&self) -> f64 {
unsafe { gdal_sys::OSRGetAngularUnits(self.0, ptr::null_mut()) }
}

pub fn get_linear_units_name(&self) -> Result<String> {
let mut c_ptr = ptr::null_mut();
unsafe { gdal_sys::OSRGetLinearUnits(self.0, &mut c_ptr) };
if c_ptr.is_null() {
return Err(_last_null_pointer_err("OSRGetLinearUnits"));
}
Ok(_string(c_ptr))
}

pub fn get_linear_units(&self) -> f64 {
unsafe { gdal_sys::OSRGetLinearUnits(self.0, ptr::null_mut()) }
}

#[inline]
pub fn is_geographic(&self) -> bool {
unsafe { gdal_sys::OSRIsGeographic(self.0) == 1 }
}

#[inline]
#[cfg(all(major_ge_3, minor_ge_1))]
pub fn is_derived_geographic(&self) -> bool {
unsafe { gdal_sys::OSRIsDerivedGeographic(self.0) == 1 }
}

#[inline]
pub fn is_local(&self) -> bool {
unsafe { gdal_sys::OSRIsLocal(self.0) == 1 }
}

#[inline]
pub fn is_projected(&self) -> bool {
unsafe { gdal_sys::OSRIsProjected(self.0) == 1 }
}

#[inline]
pub fn is_compound(&self) -> bool {
unsafe { gdal_sys::OSRIsCompound(self.0) == 1 }
}

#[inline]
pub fn is_geocentric(&self) -> bool {
unsafe { gdal_sys::OSRIsGeocentric(self.0) == 1 }
}

#[inline]
pub fn is_vertical(&self) -> bool {
unsafe { gdal_sys::OSRIsVertical(self.0) == 1 }
}

pub fn get_axis_orientation(&self, target_key: &str, axis: i32) -> Result<AxisOrientationType> {
let mut orientation = gdal_sys::OGRAxisOrientation::OAO_Other;
let c_ptr = unsafe {
gdal_sys::OSRGetAxis(
self.0,
CString::new(target_key)?.as_ptr(),
axis as c_int,
&mut orientation,
)
};
// null ptr indicate a failure (but no CPLError) see Gdal documentation.
if c_ptr.is_null() {
Err(GdalError::AxisNotFoundError {
key: target_key.into(),
method_name: "OSRGetAxis",
})
} else {
Ok(orientation)
}
}

pub fn get_axis_name(&self, target_key: &str, axis: i32) -> Result<String> {
// See get_axis_orientation
let c_ptr = unsafe {
gdal_sys::OSRGetAxis(
self.0,
CString::new(target_key)?.as_ptr(),
axis as c_int,
ptr::null_mut(),
)
};
if c_ptr.is_null() {
Err(GdalError::AxisNotFoundError {
key: target_key.into(),
method_name: "OSRGetAxis",
})
} else {
Ok(_string(c_ptr))
}
}

#[cfg(all(major_ge_3, minor_ge_1))]
pub fn get_axes_count(&self) -> i32 {
unsafe { gdal_sys::OSRGetAxesCount(self.0) }
}

#[cfg(major_ge_3)]
pub fn set_axis_mapping_strategy(&self, strategy: gdal_sys::OSRAxisMappingStrategy::Type) {
unsafe {
Expand All @@ -315,6 +443,35 @@ impl SpatialRef {
unsafe { gdal_sys::OSRGetAxisMappingStrategy(self.0) }
}

#[cfg(major_ge_3)]
pub fn get_area_of_use(&self) -> Option<AreaOfUse> {
let mut c_area_name: *const libc::c_char = ptr::null_mut();
let (mut w_long, mut s_lat, mut e_long, mut n_lat): (f64, f64, f64, f64) =
(0.0, 0.0, 0.0, 0.0);
let ret_val = unsafe {
gdal_sys::OSRGetAreaOfUse(
self.0,
&mut w_long,
&mut s_lat,
&mut e_long,
&mut n_lat,
&mut c_area_name,
) == 1
};

if ret_val {
Some(AreaOfUse {
west_lon_degree: w_long,
south_lat_degree: s_lat,
east_lon_degree: e_long,
north_lat_degree: n_lat,
name: _string(c_area_name),
})
} else {
None
}
}

// TODO: should this take self instead of &self?
pub fn to_c_hsrs(&self) -> OGRSpatialReferenceH {
self.0
Expand Down
81 changes: 81 additions & 0 deletions src/spatial_ref/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,84 @@ fn axis_mapping_strategy() {
gdal_sys::OSRAxisMappingStrategy::OAMS_TRADITIONAL_GIS_ORDER
);
}

#[cfg(major_ge_3)]
#[test]
fn get_area_of_use() {
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();
let area_of_use = spatial_ref.get_area_of_use().unwrap();
assert_almost_eq(area_of_use.west_lon_degree, -180.0);
assert_almost_eq(area_of_use.south_lat_degree, -90.0);
assert_almost_eq(area_of_use.east_lon_degree, 180.0);
assert_almost_eq(area_of_use.north_lat_degree, 90.0);
}

#[cfg(major_ge_3)]
#[test]
fn get_name() {
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();
let name = spatial_ref.get_name().unwrap();
assert_eq!(name, "WGS 84");
}

#[test]
fn get_units_epsg4326() {
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();

let angular_units_name = spatial_ref.get_angular_units_name().unwrap();
assert_eq!(angular_units_name.to_lowercase(), "degree");
let to_radians = spatial_ref.get_angular_units();
assert_almost_eq(to_radians, 0.01745329);
}

#[test]
fn get_units_epsg2154() {
let spatial_ref = SpatialRef::from_epsg(2154).unwrap();
let linear_units_name = spatial_ref.get_linear_units_name().unwrap();
assert_eq!(linear_units_name.to_lowercase(), "metre");
let to_meters = spatial_ref.get_linear_units();
assert_almost_eq(to_meters, 1.0);
}

#[test]
fn predicats_epsg4326() {
let spatial_ref_4326 = SpatialRef::from_epsg(4326).unwrap();
assert!(spatial_ref_4326.is_geographic());
assert!(!spatial_ref_4326.is_local());
assert!(!spatial_ref_4326.is_projected());
assert!(!spatial_ref_4326.is_compound());
assert!(!spatial_ref_4326.is_geocentric());
assert!(!spatial_ref_4326.is_vertical());

#[cfg(all(major_ge_3, minor_ge_1))]
assert!(!spatial_ref_4326.is_derived_geographic());
}

#[test]
fn predicats_epsg2154() {
let spatial_ref_2154 = SpatialRef::from_epsg(2154).unwrap();
assert!(!spatial_ref_2154.is_geographic());
assert!(!spatial_ref_2154.is_local());
assert!(spatial_ref_2154.is_projected());
assert!(!spatial_ref_2154.is_compound());
assert!(!spatial_ref_2154.is_geocentric());

#[cfg(all(major_ge_3, minor_ge_1))]
assert!(!spatial_ref_2154.is_derived_geographic());
}

//XXX Gdal 2 implementation is partial
#[cfg(major_ge_3)]
#[test]
fn crs_axis() {
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();

#[cfg(all(major_ge_3, minor_ge_1))]
assert_eq!(spatial_ref.get_axes_count(), 2);

let orientation = spatial_ref.get_axis_orientation("GEOGCS", 0).unwrap();
assert_eq!(orientation, gdal_sys::OGRAxisOrientation::OAO_North);
assert!(spatial_ref.get_axis_name("GEOGCS", 0).is_ok());
assert!(spatial_ref.get_axis_name("DO_NO_EXISTS", 0).is_err());
assert!(spatial_ref.get_axis_orientation("DO_NO_EXISTS", 0).is_err());
}

0 comments on commit b43596c

Please sign in to comment.