From 082e1bc86bb3d15cfa9423a62ea1c47cd33fce09 Mon Sep 17 00:00:00 2001 From: tombieli Date: Mon, 22 May 2023 20:53:43 +0200 Subject: [PATCH 01/14] Mapping of additional methods for SpatialRef. --- src/spatial_ref/srs.rs | 180 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index a61e4cda..bb977407 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -451,6 +451,96 @@ impl SpatialRef { None } } + + + pub fn semi_major(&self) -> Result { + let mut rv = OGRErr::OGRERR_NONE; + let a = unsafe { gdal_sys::OSRGetSemiMajor(self.0, &mut rv as *mut u32) }; + if rv != OGRErr::OGRERR_NONE { + return Err(GdalError::OgrError { + err: rv, + method_name: "OSRGetSemiMajor", + }); + } + Ok(a) + } + + pub fn semi_minor(&self) -> Result { + let mut rv = OGRErr::OGRERR_NONE; + let b = unsafe { gdal_sys::OSRGetSemiMinor(self.0, &mut rv as *mut u32) }; + if rv != OGRErr::OGRERR_NONE { + return Err(GdalError::OgrError { + err: rv, + method_name: "OSRGetSemiMinor", + }); + } + Ok(b) + } + + pub fn set_proj_param(&mut self, name: &str, value: f64) -> Result<()> { + let c_name = CString::new(name)?; + let rv = unsafe { gdal_sys::OSRSetProjParm(self.0, c_name.as_ptr(), value) }; + if rv != OGRErr::OGRERR_NONE { + return Err(GdalError::OgrError { + err: rv, + method_name: "OSRSetProjParm", + }); + } + Ok(()) + } + + pub fn get_proj_param(&self, name: &str) -> Result { + let c_name = CString::new(name)?; + let mut rv = OGRErr::OGRERR_NONE; + let p = unsafe { gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), 0.0, &mut rv as *mut u32) }; + if rv != OGRErr::OGRERR_NONE { + return Err(GdalError::OgrError { + err: rv, + method_name: "OSRGetProjParm", + }); + } + Ok(p) + } + + pub fn get_proj_param_or_default(&self, name: &str, default: f64) -> f64 { + match CString::new(name) { + Ok(c_name) => unsafe { gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), default, ptr::null_mut()) }, + Err(_) => default + } + } + + pub fn set_attr_value(&self, node_path: &str, new_value: &str) -> Result<()> { + let c_node_path = CString::new(node_path)?; + let c_new_value = CString::new(new_value)?; + let rv = unsafe { gdal_sys::OSRSetAttrValue(self.0, c_node_path.as_ptr(), c_new_value.as_ptr()) }; + if rv != OGRErr::OGRERR_NONE { + return Err(GdalError::OgrError { + err: rv, + method_name: "OSRSetAttrValue", + }); + } + Ok(()) + } + + pub fn get_attr_value(&self, node_path: &str, child: u32) -> Result { + let c_node_path = CString::new(node_path)?; + let c_ptr_value = unsafe { gdal_sys::OSRGetAttrValue(self.0, c_node_path.as_ptr(), child as libc::c_int) }; + if c_ptr_value.is_null() { + return Err(_last_null_pointer_err("OSRGetAttrValue")); + } + Ok(_string(c_ptr_value)) + } + + + pub fn geog_cs(&self) -> Result { + let raw_ret = unsafe {gdal_sys::OSRCloneGeogCS(self.0)}; + if raw_ret.is_null() { + return Err(_last_null_pointer_err("OSRCloneGeogCS")); + } + + Ok(SpatialRef(raw_ret)) + } + } #[derive(Debug, Clone)] @@ -700,4 +790,94 @@ mod tests { assert!(spatial_ref.axis_name("DO_NO_EXISTS", 0).is_err()); assert!(spatial_ref.axis_orientation("DO_NO_EXISTS", 0).is_err()); } + + #[test] + fn semi_major_and_semi_minor() { + let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); + + let semi_major = spatial_ref.semi_major().unwrap(); + assert_almost_eq(semi_major, 6_378_137.0); + + let semi_minor = spatial_ref.semi_minor().unwrap(); + assert_almost_eq(semi_minor, 6_356_752.31); + } + + + #[test] + fn proj_params() { + let spatial_ref = SpatialRef::from_proj4("+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs").unwrap(); + + let central_meridian = spatial_ref.get_proj_param("central_meridian").unwrap(); + assert_almost_eq(central_meridian, 42.0); + + let satellite_height = spatial_ref.get_proj_param("satellite_height").unwrap(); + assert_almost_eq(satellite_height, 35_785_831.0); + + let satellite_height = spatial_ref.get_proj_param_or_default("satellite_height", 0.0); + assert_almost_eq(satellite_height, 35_785_831.0); + } + + #[test] + fn setting_proj_param() { + let mut spatial_ref = SpatialRef::from_proj4("+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs").unwrap(); + + spatial_ref.set_proj_param("central_meridian", -15.0).unwrap(); + + let central_meridian = spatial_ref.get_proj_param("central_meridian").unwrap(); + + assert_almost_eq(central_meridian, -15.0); + + } + + #[test] + #[should_panic = "OgrError { err: 6, method_name: \"OSRGetProjParm\" }"] + fn non_existing_proj_param() { + let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); + + spatial_ref.get_proj_param("spam").unwrap(); + } + + #[test] + fn non_existing_proj_param_using_default() { + let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); + + let spam = spatial_ref.get_proj_param_or_default("spam", 15.0); + + assert_almost_eq(spam, 15.0); + } + + #[test] + fn attr_values() { + let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); + + let geog_cs = spatial_ref.get_attr_value("GEOGCS", 0).unwrap(); + + assert_eq!(geog_cs, "WGS 84"); + } + + #[test] + fn geog_cs() { + let spatial_ref = SpatialRef::from_proj4("+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs").unwrap(); + let expected_geog_cs = SpatialRef::from_wkt( + r#" + GEOGCS["unknown", + DATUM["WGS_1984", + SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]], + AUTHORITY["EPSG","6326"]], + PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]], + UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]], + AXIS["Longitude",EAST], + AXIS["Latitude",NORTH] + ] + "# + ).unwrap(); + + let geog_cs = spatial_ref.geog_cs().unwrap(); + + assert_eq!( + geog_cs, expected_geog_cs, + "GEOGCS of geos spatial reference: \"{:?}\"\n does not equal to expected one: {:?}", geog_cs.to_wkt(), expected_geog_cs.to_wkt() + ); + } + } From 9810fb061912aa5db155854c702467fd375b0c57 Mon Sep 17 00:00:00 2001 From: tombieli Date: Mon, 22 May 2023 21:13:18 +0200 Subject: [PATCH 02/14] Added information to CHANGES.md --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f2a6667f..7fce3bd8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,11 @@ # Changes ## Unreleased + +- Added `SpatialRef::semi_major`, `semi_minor`, `set_proj_param`, `get_proj_param`, `get_proj_param_or_default`, `set_attr_value`, `get_attr_value` and `geog_cs`. + + - + - Added pre-built bindings for GDAL 3.7 - From f0b728818d7f8171c1ba7a708a2f106d7be043c7 Mon Sep 17 00:00:00 2001 From: tombieli Date: Mon, 22 May 2023 23:52:01 +0200 Subject: [PATCH 03/14] Added documentation to newly added functions/methods. --- src/spatial_ref/srs.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index bb977407..9eb8d03d 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -452,7 +452,9 @@ impl SpatialRef { } } - + /// Get spheroid semi major axis. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from orginal method. + /// + /// See: [`OSRGetSemiMajor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMajor20OGRSpatialReferenceHP6OGRErr) pub fn semi_major(&self) -> Result { let mut rv = OGRErr::OGRERR_NONE; let a = unsafe { gdal_sys::OSRGetSemiMajor(self.0, &mut rv as *mut u32) }; @@ -465,6 +467,9 @@ impl SpatialRef { Ok(a) } + /// Get spheroid semi minor axis. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from orginal method. + /// + /// See: [`OSRGetSemiMinor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMinor20OGRSpatialReferenceHP6OGRErr) pub fn semi_minor(&self) -> Result { let mut rv = OGRErr::OGRERR_NONE; let b = unsafe { gdal_sys::OSRGetSemiMinor(self.0, &mut rv as *mut u32) }; @@ -477,6 +482,9 @@ impl SpatialRef { Ok(b) } + /// Set a projection parameter value. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from orginal method. + /// + /// See: [`OSRSetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRSetProjParm20OGRSpatialReferenceHPKcd) pub fn set_proj_param(&mut self, name: &str, value: f64) -> Result<()> { let c_name = CString::new(name)?; let rv = unsafe { gdal_sys::OSRSetProjParm(self.0, c_name.as_ptr(), value) }; @@ -489,6 +497,9 @@ impl SpatialRef { Ok(()) } + /// Fetch a projection parameter value. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from orginal method. + /// + /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) pub fn get_proj_param(&self, name: &str) -> Result { let c_name = CString::new(name)?; let mut rv = OGRErr::OGRERR_NONE; @@ -502,6 +513,10 @@ impl SpatialRef { Ok(p) } + /// Fetch a projection parameter value. In case of any error returns defualt value. + /// This associated function is variant of [`SpatialRef::get_proj_param`] which incorporates default fallback mechanism from orginal library. + /// + /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) pub fn get_proj_param_or_default(&self, name: &str, default: f64) -> f64 { match CString::new(name) { Ok(c_name) => unsafe { gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), default, ptr::null_mut()) }, @@ -509,6 +524,9 @@ impl SpatialRef { } } + /// Set attribute value in spatial reference. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from orginal method. + /// + /// See: [`OSRSetAttrValue`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRSetAttrValue20OGRSpatialReferenceHPKcPKc) pub fn set_attr_value(&self, node_path: &str, new_value: &str) -> Result<()> { let c_node_path = CString::new(node_path)?; let c_new_value = CString::new(new_value)?; @@ -522,6 +540,9 @@ impl SpatialRef { Ok(()) } + /// Fetch indicated attribute of named node. It returns [`Err`] variant if orginal method returns `nullptr`. + /// + /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) pub fn get_attr_value(&self, node_path: &str, child: u32) -> Result { let c_node_path = CString::new(node_path)?; let c_ptr_value = unsafe { gdal_sys::OSRGetAttrValue(self.0, c_node_path.as_ptr(), child as libc::c_int) }; @@ -532,6 +553,9 @@ impl SpatialRef { } + /// Make a duplicate of the GEOGCS node of this [`SpatialRef`]. It returns [`Err`] variant if orginal method returns `nullptr`. + /// + /// Seff: [OSRCloneGeogCS](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRCloneGeogCS20OGRSpatialReferenceH) pub fn geog_cs(&self) -> Result { let raw_ret = unsafe {gdal_sys::OSRCloneGeogCS(self.0)}; if raw_ret.is_null() { From 05075fc17b5d5760efc23372f41222894c83b30e Mon Sep 17 00:00:00 2001 From: tombieli <105295213+tombieli@users.noreply.github.com> Date: Tue, 23 May 2023 22:24:07 +0200 Subject: [PATCH 04/14] Apply documentation reformating suggested by @metasim. Co-authored-by: Simeon H.K. Fitch --- src/spatial_ref/srs.rs | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 9eb8d03d..db17ec38 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -452,7 +452,9 @@ impl SpatialRef { } } - /// Get spheroid semi major axis. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from orginal method. + /// Get spheroid semi major axis. + /// + /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. /// /// See: [`OSRGetSemiMajor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMajor20OGRSpatialReferenceHP6OGRErr) pub fn semi_major(&self) -> Result { @@ -467,7 +469,9 @@ impl SpatialRef { Ok(a) } - /// Get spheroid semi minor axis. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from orginal method. + /// Get spheroid semi minor axis. + /// + /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. /// /// See: [`OSRGetSemiMinor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMinor20OGRSpatialReferenceHP6OGRErr) pub fn semi_minor(&self) -> Result { @@ -482,7 +486,9 @@ impl SpatialRef { Ok(b) } - /// Set a projection parameter value. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from orginal method. + /// Set a projection parameter value. + /// + /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from the C library. /// /// See: [`OSRSetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRSetProjParm20OGRSpatialReferenceHPKcd) pub fn set_proj_param(&mut self, name: &str, value: f64) -> Result<()> { @@ -497,7 +503,9 @@ impl SpatialRef { Ok(()) } - /// Fetch a projection parameter value. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from orginal method. + /// Fetch a projection parameter value. + /// + /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) pub fn get_proj_param(&self, name: &str) -> Result { @@ -513,8 +521,10 @@ impl SpatialRef { Ok(p) } - /// Fetch a projection parameter value. In case of any error returns defualt value. - /// This associated function is variant of [`SpatialRef::get_proj_param`] which incorporates default fallback mechanism from orginal library. + /// Fetch a projection parameter value. + /// + /// In case of any error returns default value. + /// This associated function is variant of [`SpatialRef::get_proj_param`] which incorporates default fallback mechanism from the C library. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) pub fn get_proj_param_or_default(&self, name: &str, default: f64) -> f64 { @@ -524,7 +534,9 @@ impl SpatialRef { } } - /// Set attribute value in spatial reference. It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from orginal method. + /// Set attribute value in spatial reference. + /// + /// It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from the C library. /// /// See: [`OSRSetAttrValue`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRSetAttrValue20OGRSpatialReferenceHPKcPKc) pub fn set_attr_value(&self, node_path: &str, new_value: &str) -> Result<()> { @@ -540,7 +552,9 @@ impl SpatialRef { Ok(()) } - /// Fetch indicated attribute of named node. It returns [`Err`] variant if orginal method returns `nullptr`. + /// Fetch indicated attribute of named node. + /// + /// Returns [`Err`] variant if the C library return `nullptr`. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) pub fn get_attr_value(&self, node_path: &str, child: u32) -> Result { @@ -553,7 +567,9 @@ impl SpatialRef { } - /// Make a duplicate of the GEOGCS node of this [`SpatialRef`]. It returns [`Err`] variant if orginal method returns `nullptr`. + /// Make a duplicate of the GEOGCS node of this [`SpatialRef`]. + /// + /// Returns [`Err`] variant if the C library returns `nullptr`. /// /// Seff: [OSRCloneGeogCS](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRCloneGeogCS20OGRSpatialReferenceH) pub fn geog_cs(&self) -> Result { From 78a95c29b50fdb4332b9f30771b1f2075b55f258 Mon Sep 17 00:00:00 2001 From: tombieli Date: Tue, 23 May 2023 22:47:22 +0200 Subject: [PATCH 05/14] Applying changes from "cargo fmt". --- src/spatial_ref/srs.rs | 95 +++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index db17ec38..51868029 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -452,14 +452,14 @@ impl SpatialRef { } } - /// Get spheroid semi major axis. + /// Get spheroid semi major axis. /// /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. - /// + /// /// See: [`OSRGetSemiMajor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMajor20OGRSpatialReferenceHP6OGRErr) pub fn semi_major(&self) -> Result { let mut rv = OGRErr::OGRERR_NONE; - let a = unsafe { gdal_sys::OSRGetSemiMajor(self.0, &mut rv as *mut u32) }; + let a = unsafe { gdal_sys::OSRGetSemiMajor(self.0, &mut rv as *mut u32) }; if rv != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { err: rv, @@ -469,14 +469,14 @@ impl SpatialRef { Ok(a) } - /// Get spheroid semi minor axis. + /// Get spheroid semi minor axis. /// /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. - /// + /// /// See: [`OSRGetSemiMinor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMinor20OGRSpatialReferenceHP6OGRErr) pub fn semi_minor(&self) -> Result { let mut rv = OGRErr::OGRERR_NONE; - let b = unsafe { gdal_sys::OSRGetSemiMinor(self.0, &mut rv as *mut u32) }; + let b = unsafe { gdal_sys::OSRGetSemiMinor(self.0, &mut rv as *mut u32) }; if rv != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { err: rv, @@ -486,14 +486,14 @@ impl SpatialRef { Ok(b) } - /// Set a projection parameter value. + /// Set a projection parameter value. /// /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from the C library. - /// + /// /// See: [`OSRSetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRSetProjParm20OGRSpatialReferenceHPKcd) pub fn set_proj_param(&mut self, name: &str, value: f64) -> Result<()> { let c_name = CString::new(name)?; - let rv = unsafe { gdal_sys::OSRSetProjParm(self.0, c_name.as_ptr(), value) }; + let rv = unsafe { gdal_sys::OSRSetProjParm(self.0, c_name.as_ptr(), value) }; if rv != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { err: rv, @@ -503,15 +503,16 @@ impl SpatialRef { Ok(()) } - /// Fetch a projection parameter value. + /// Fetch a projection parameter value. /// /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. - /// + /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) pub fn get_proj_param(&self, name: &str) -> Result { let c_name = CString::new(name)?; let mut rv = OGRErr::OGRERR_NONE; - let p = unsafe { gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), 0.0, &mut rv as *mut u32) }; + let p = + unsafe { gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), 0.0, &mut rv as *mut u32) }; if rv != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { err: rv, @@ -521,28 +522,32 @@ impl SpatialRef { Ok(p) } - /// Fetch a projection parameter value. + /// Fetch a projection parameter value. /// /// In case of any error returns default value. /// This associated function is variant of [`SpatialRef::get_proj_param`] which incorporates default fallback mechanism from the C library. - /// + /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) pub fn get_proj_param_or_default(&self, name: &str, default: f64) -> f64 { match CString::new(name) { - Ok(c_name) => unsafe { gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), default, ptr::null_mut()) }, - Err(_) => default + Ok(c_name) => unsafe { + gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), default, ptr::null_mut()) + }, + Err(_) => default, } } - /// Set attribute value in spatial reference. + /// Set attribute value in spatial reference. /// /// It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from the C library. - /// + /// /// See: [`OSRSetAttrValue`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRSetAttrValue20OGRSpatialReferenceHPKcPKc) pub fn set_attr_value(&self, node_path: &str, new_value: &str) -> Result<()> { let c_node_path = CString::new(node_path)?; let c_new_value = CString::new(new_value)?; - let rv = unsafe { gdal_sys::OSRSetAttrValue(self.0, c_node_path.as_ptr(), c_new_value.as_ptr()) }; + let rv = unsafe { + gdal_sys::OSRSetAttrValue(self.0, c_node_path.as_ptr(), c_new_value.as_ptr()) + }; if rv != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { err: rv, @@ -552,35 +557,35 @@ impl SpatialRef { Ok(()) } - /// Fetch indicated attribute of named node. + /// Fetch indicated attribute of named node. /// /// Returns [`Err`] variant if the C library return `nullptr`. - /// + /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) pub fn get_attr_value(&self, node_path: &str, child: u32) -> Result { let c_node_path = CString::new(node_path)?; - let c_ptr_value = unsafe { gdal_sys::OSRGetAttrValue(self.0, c_node_path.as_ptr(), child as libc::c_int) }; + let c_ptr_value = unsafe { + gdal_sys::OSRGetAttrValue(self.0, c_node_path.as_ptr(), child as libc::c_int) + }; if c_ptr_value.is_null() { return Err(_last_null_pointer_err("OSRGetAttrValue")); } Ok(_string(c_ptr_value)) } - - /// Make a duplicate of the GEOGCS node of this [`SpatialRef`]. + /// Make a duplicate of the GEOGCS node of this [`SpatialRef`]. /// /// Returns [`Err`] variant if the C library returns `nullptr`. - /// + /// /// Seff: [OSRCloneGeogCS](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRCloneGeogCS20OGRSpatialReferenceH) pub fn geog_cs(&self) -> Result { - let raw_ret = unsafe {gdal_sys::OSRCloneGeogCS(self.0)}; + let raw_ret = unsafe { gdal_sys::OSRCloneGeogCS(self.0) }; if raw_ret.is_null() { return Err(_last_null_pointer_err("OSRCloneGeogCS")); } Ok(SpatialRef(raw_ret)) } - } #[derive(Debug, Clone)] @@ -842,10 +847,12 @@ mod tests { assert_almost_eq(semi_minor, 6_356_752.31); } - #[test] fn proj_params() { - let spatial_ref = SpatialRef::from_proj4("+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs").unwrap(); + let spatial_ref = SpatialRef::from_proj4( + "+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs", + ) + .unwrap(); let central_meridian = spatial_ref.get_proj_param("central_meridian").unwrap(); assert_almost_eq(central_meridian, 42.0); @@ -859,14 +866,18 @@ mod tests { #[test] fn setting_proj_param() { - let mut spatial_ref = SpatialRef::from_proj4("+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs").unwrap(); + let mut spatial_ref = SpatialRef::from_proj4( + "+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs", + ) + .unwrap(); - spatial_ref.set_proj_param("central_meridian", -15.0).unwrap(); + spatial_ref + .set_proj_param("central_meridian", -15.0) + .unwrap(); let central_meridian = spatial_ref.get_proj_param("central_meridian").unwrap(); assert_almost_eq(central_meridian, -15.0); - } #[test] @@ -897,7 +908,10 @@ mod tests { #[test] fn geog_cs() { - let spatial_ref = SpatialRef::from_proj4("+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs").unwrap(); + let spatial_ref = SpatialRef::from_proj4( + "+proj=geos +lon_0=42 +h=35785831 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs", + ) + .unwrap(); let expected_geog_cs = SpatialRef::from_wkt( r#" GEOGCS["unknown", @@ -909,15 +923,18 @@ mod tests { AXIS["Longitude",EAST], AXIS["Latitude",NORTH] ] - "# - ).unwrap(); - + "#, + ) + .unwrap(); + let geog_cs = spatial_ref.geog_cs().unwrap(); assert_eq!( - geog_cs, expected_geog_cs, - "GEOGCS of geos spatial reference: \"{:?}\"\n does not equal to expected one: {:?}", geog_cs.to_wkt(), expected_geog_cs.to_wkt() + geog_cs, + expected_geog_cs, + "GEOGCS of geos spatial reference: \"{:?}\"\n does not equal to expected one: {:?}", + geog_cs.to_wkt(), + expected_geog_cs.to_wkt() ); } - } From a407af2c43d68c2f6fb83cc6b260891d9cecdf57 Mon Sep 17 00:00:00 2001 From: tombieli <105295213+tombieli@users.noreply.github.com> Date: Thu, 25 May 2023 08:35:41 +0000 Subject: [PATCH 06/14] Comments correction based on suggestions made by @lnicola. --- src/spatial_ref/srs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 51868029..08742f2b 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -452,9 +452,9 @@ impl SpatialRef { } } - /// Get spheroid semi major axis. + /// Get spheroid semi-major axis. /// - /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. + /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). /// /// See: [`OSRGetSemiMajor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMajor20OGRSpatialReferenceHP6OGRErr) pub fn semi_major(&self) -> Result { @@ -469,9 +469,9 @@ impl SpatialRef { Ok(a) } - /// Get spheroid semi minor axis. + /// Get spheroid semi-minor axis. /// - /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. + /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). /// /// See: [`OSRGetSemiMinor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMinor20OGRSpatialReferenceHP6OGRErr) pub fn semi_minor(&self) -> Result { @@ -488,7 +488,7 @@ impl SpatialRef { /// Set a projection parameter value. /// - /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from the C library. + /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). /// /// See: [`OSRSetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRSetProjParm20OGRSpatialReferenceHPKcd) pub fn set_proj_param(&mut self, name: &str, value: f64) -> Result<()> { @@ -505,7 +505,7 @@ impl SpatialRef { /// Fetch a projection parameter value. /// - /// Returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) error result from the C library. + /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) pub fn get_proj_param(&self, name: &str) -> Result { @@ -539,7 +539,7 @@ impl SpatialRef { /// Set attribute value in spatial reference. /// - /// It returns [`Err`] variant in case of non [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE) result from the C library. + /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). /// /// See: [`OSRSetAttrValue`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRSetAttrValue20OGRSpatialReferenceHPKcPKc) pub fn set_attr_value(&self, node_path: &str, new_value: &str) -> Result<()> { From 64e1667e96c699f11f4d6ce30ba040dc1a34d0ca Mon Sep 17 00:00:00 2001 From: tombieli Date: Sat, 27 May 2023 20:55:39 +0200 Subject: [PATCH 07/14] Changing type of parameter "child" from function "get_attr_value" to usize. Following suggestion from @lnicola. --- src/spatial_ref/srs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 08742f2b..627d43fb 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -562,7 +562,7 @@ impl SpatialRef { /// Returns [`Err`] variant if the C library return `nullptr`. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) - pub fn get_attr_value(&self, node_path: &str, child: u32) -> Result { + pub fn get_attr_value(&self, node_path: &str, child: usize) -> Result { let c_node_path = CString::new(node_path)?; let c_ptr_value = unsafe { gdal_sys::OSRGetAttrValue(self.0, c_node_path.as_ptr(), child as libc::c_int) From e3c111a26dc3829562a6327eefaa4523632c0e98 Mon Sep 17 00:00:00 2001 From: tombieli Date: Tue, 30 May 2023 11:25:59 +0200 Subject: [PATCH 08/14] Comments correction according to suggestions by @lnicola. --- src/spatial_ref/srs.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 627d43fb..cd6e4646 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -454,7 +454,7 @@ impl SpatialRef { /// Get spheroid semi-major axis. /// - /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). + /// Returns an error if the semi-major axis can't be found /// /// See: [`OSRGetSemiMajor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMajor20OGRSpatialReferenceHP6OGRErr) pub fn semi_major(&self) -> Result { @@ -471,7 +471,7 @@ impl SpatialRef { /// Get spheroid semi-minor axis. /// - /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). + /// Returns an error if the semi-minor axis can't be found /// /// See: [`OSRGetSemiMinor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMinor20OGRSpatialReferenceHP6OGRErr) pub fn semi_minor(&self) -> Result { @@ -488,7 +488,7 @@ impl SpatialRef { /// Set a projection parameter value. /// - /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). + /// Returns an error if there the `PROJCS` node is missing. /// /// See: [`OSRSetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRSetProjParm20OGRSpatialReferenceHPKcd) pub fn set_proj_param(&mut self, name: &str, value: f64) -> Result<()> { @@ -559,7 +559,7 @@ impl SpatialRef { /// Fetch indicated attribute of named node. /// - /// Returns [`Err`] variant if the C library return `nullptr`. + /// Returns an error if a specified node is missing. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) pub fn get_attr_value(&self, node_path: &str, child: usize) -> Result { @@ -573,11 +573,11 @@ impl SpatialRef { Ok(_string(c_ptr_value)) } - /// Make a duplicate of the GEOGCS node of this [`SpatialRef`]. + /// Make a duplicate of the `GEOGCS` node of this [`SpatialRef`]. /// - /// Returns [`Err`] variant if the C library returns `nullptr`. + /// Returns an error if the `GEOGCS` node is missing. /// - /// Seff: [OSRCloneGeogCS](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRCloneGeogCS20OGRSpatialReferenceH) + /// See: [OSRCloneGeogCS](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRCloneGeogCS20OGRSpatialReferenceH) pub fn geog_cs(&self) -> Result { let raw_ret = unsafe { gdal_sys::OSRCloneGeogCS(self.0) }; if raw_ret.is_null() { From e0de31f153cdd1245169c895d07236170b6b1967 Mon Sep 17 00:00:00 2001 From: tombieli Date: Tue, 30 May 2023 13:04:40 +0200 Subject: [PATCH 09/14] Refactoring of get_proj_param, set_proj_param, get_attr_value, set_attr_value and releveant tests. Based on suggestions by @lnicola. --- src/spatial_ref/srs.rs | 122 ++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index cd6e4646..82869842 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -458,11 +458,11 @@ impl SpatialRef { /// /// See: [`OSRGetSemiMajor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMajor20OGRSpatialReferenceHP6OGRErr) pub fn semi_major(&self) -> Result { - let mut rv = OGRErr::OGRERR_NONE; - let a = unsafe { gdal_sys::OSRGetSemiMajor(self.0, &mut rv as *mut u32) }; - if rv != OGRErr::OGRERR_NONE { + let mut err_code = OGRErr::OGRERR_NONE; + let a = unsafe { gdal_sys::OSRGetSemiMajor(self.0, &mut err_code as *mut u32) }; + if err_code != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { - err: rv, + err: err_code, method_name: "OSRGetSemiMajor", }); } @@ -475,11 +475,11 @@ impl SpatialRef { /// /// See: [`OSRGetSemiMinor`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetSemiMinor20OGRSpatialReferenceHP6OGRErr) pub fn semi_minor(&self) -> Result { - let mut rv = OGRErr::OGRERR_NONE; - let b = unsafe { gdal_sys::OSRGetSemiMinor(self.0, &mut rv as *mut u32) }; - if rv != OGRErr::OGRERR_NONE { + let mut err_code = OGRErr::OGRERR_NONE; + let b = unsafe { gdal_sys::OSRGetSemiMinor(self.0, &mut err_code as *mut u32) }; + if err_code != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { - err: rv, + err: err_code, method_name: "OSRGetSemiMinor", }); } @@ -505,49 +505,44 @@ impl SpatialRef { /// Fetch a projection parameter value. /// - /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). + /// Returns: + /// * `Ok(Some(value))` - if parameter is sucessfully found, + /// * `Ok(None)` - if parameter is not found (C library will return [OGRERR_FAILURE](https://gdal.org/api/vector_c_api.html#c.OGRERR_FAILURE)), + /// * `Err(_)` - if there is a string conversion error or on other GDAL OGR error. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) - pub fn get_proj_param(&self, name: &str) -> Result { + pub fn get_proj_param(&self, name: &str) -> Result> { let c_name = CString::new(name)?; - let mut rv = OGRErr::OGRERR_NONE; - let p = - unsafe { gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), 0.0, &mut rv as *mut u32) }; - if rv != OGRErr::OGRERR_NONE { - return Err(GdalError::OgrError { - err: rv, - method_name: "OSRGetProjParm", - }); - } - Ok(p) - } - - /// Fetch a projection parameter value. - /// - /// In case of any error returns default value. - /// This associated function is variant of [`SpatialRef::get_proj_param`] which incorporates default fallback mechanism from the C library. - /// - /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) - pub fn get_proj_param_or_default(&self, name: &str, default: f64) -> f64 { - match CString::new(name) { - Ok(c_name) => unsafe { - gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), default, ptr::null_mut()) - }, - Err(_) => default, + let mut err_code = OGRErr::OGRERR_NONE; + let p = unsafe { + gdal_sys::OSRGetProjParm(self.0, c_name.as_ptr(), 0.0, &mut err_code as *mut u32) + }; + if err_code != OGRErr::OGRERR_NONE { + match err_code { + OGRErr::OGRERR_FAILURE => Ok(None), + other_err => Err(GdalError::OgrError { + err: other_err, + method_name: "OSRGetProjParm", + }), + } + } else { + Ok(Some(p)) } } /// Set attribute value in spatial reference. /// - /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). + /// Returns error in case if path was invalid or on GDAL OGR error. /// /// See: [`OSRSetAttrValue`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRSetAttrValue20OGRSpatialReferenceHPKcPKc) - pub fn set_attr_value(&self, node_path: &str, new_value: &str) -> Result<()> { + pub fn set_attr_value(&mut self, node_path: &str, new_value: Option<&str>) -> Result<()> { let c_node_path = CString::new(node_path)?; - let c_new_value = CString::new(new_value)?; - let rv = unsafe { - gdal_sys::OSRSetAttrValue(self.0, c_node_path.as_ptr(), c_new_value.as_ptr()) + let c_new_value = match new_value { + Some(value) => Some(CString::new(value)?), + None => None, }; + let value_ptr = c_new_value.map(|s| s.as_ptr()).unwrap_or(ptr::null()); + let rv = unsafe { gdal_sys::OSRSetAttrValue(self.0, c_node_path.as_ptr(), value_ptr) }; if rv != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { err: rv, @@ -559,18 +554,22 @@ impl SpatialRef { /// Fetch indicated attribute of named node. /// - /// Returns an error if a specified node is missing. + // Returns: + /// * `Ok(Some(value))` - if node and attribute are sucessfully found, + /// * `Ok(None)` - if node or attribute are not found (C library will return `nullptr`) or attribute contains no value, + /// * `Err(_)` - if there is a string conversion error. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) - pub fn get_attr_value(&self, node_path: &str, child: usize) -> Result { + pub fn get_attr_value(&self, node_path: &str, child: usize) -> Result> { let c_node_path = CString::new(node_path)?; let c_ptr_value = unsafe { gdal_sys::OSRGetAttrValue(self.0, c_node_path.as_ptr(), child as libc::c_int) }; if c_ptr_value.is_null() { - return Err(_last_null_pointer_err("OSRGetAttrValue")); + Ok(None) + } else { + Ok(Some(_string(c_ptr_value))) } - Ok(_string(c_ptr_value)) } /// Make a duplicate of the `GEOGCS` node of this [`SpatialRef`]. @@ -854,13 +853,16 @@ mod tests { ) .unwrap(); - let central_meridian = spatial_ref.get_proj_param("central_meridian").unwrap(); + let central_meridian = spatial_ref + .get_proj_param("central_meridian") + .unwrap() + .unwrap(); assert_almost_eq(central_meridian, 42.0); - let satellite_height = spatial_ref.get_proj_param("satellite_height").unwrap(); - assert_almost_eq(satellite_height, 35_785_831.0); - - let satellite_height = spatial_ref.get_proj_param_or_default("satellite_height", 0.0); + let satellite_height = spatial_ref + .get_proj_param("satellite_height") + .unwrap() + .unwrap(); assert_almost_eq(satellite_height, 35_785_831.0); } @@ -875,35 +877,31 @@ mod tests { .set_proj_param("central_meridian", -15.0) .unwrap(); - let central_meridian = spatial_ref.get_proj_param("central_meridian").unwrap(); + let central_meridian = spatial_ref + .get_proj_param("central_meridian") + .unwrap() + .unwrap(); assert_almost_eq(central_meridian, -15.0); } #[test] - #[should_panic = "OgrError { err: 6, method_name: \"OSRGetProjParm\" }"] fn non_existing_proj_param() { let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); - spatial_ref.get_proj_param("spam").unwrap(); - } + let spam = spatial_ref.get_proj_param("spam").unwrap(); - #[test] - fn non_existing_proj_param_using_default() { - let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); - - let spam = spatial_ref.get_proj_param_or_default("spam", 15.0); - - assert_almost_eq(spam, 15.0); + assert_eq!(spam, None); } #[test] fn attr_values() { let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); - - let geog_cs = spatial_ref.get_attr_value("GEOGCS", 0).unwrap(); - + println!("{}", spatial_ref.to_wkt().unwrap()); + let geog_cs = spatial_ref.get_attr_value("GEOGCS", 0).unwrap().unwrap(); assert_eq!(geog_cs, "WGS 84"); + + //TODO: write some meaningful test for "set_attr_value". } #[test] From db004e9f142b14dd69e7533606ec34753dd45639 Mon Sep 17 00:00:00 2001 From: tombieli Date: Tue, 30 May 2023 13:16:13 +0200 Subject: [PATCH 10/14] Remove rendundant println. --- src/spatial_ref/srs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 82869842..f95acbb6 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -897,7 +897,6 @@ mod tests { #[test] fn attr_values() { let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); - println!("{}", spatial_ref.to_wkt().unwrap()); let geog_cs = spatial_ref.get_attr_value("GEOGCS", 0).unwrap().unwrap(); assert_eq!(geog_cs, "WGS 84"); From db7724840146bb377e055743d21f4575a66eb090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 30 May 2023 17:34:17 +0300 Subject: [PATCH 11/14] Fix use-after-free in SpatialRef::set_attr_value --- src/spatial_ref/srs.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index f95acbb6..65d86c39 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -541,7 +541,10 @@ impl SpatialRef { Some(value) => Some(CString::new(value)?), None => None, }; - let value_ptr = c_new_value.map(|s| s.as_ptr()).unwrap_or(ptr::null()); + let value_ptr = c_new_value + .as_ref() + .map(|s| s.as_ptr()) + .unwrap_or(ptr::null()); let rv = unsafe { gdal_sys::OSRSetAttrValue(self.0, c_node_path.as_ptr(), value_ptr) }; if rv != OGRErr::OGRERR_NONE { return Err(GdalError::OgrError { @@ -896,11 +899,28 @@ mod tests { #[test] fn attr_values() { - let spatial_ref = SpatialRef::from_epsg(4326).unwrap(); - let geog_cs = spatial_ref.get_attr_value("GEOGCS", 0).unwrap().unwrap(); - assert_eq!(geog_cs, "WGS 84"); - - //TODO: write some meaningful test for "set_attr_value". + let mut spatial_ref = SpatialRef::from_epsg(4326).unwrap(); + assert_eq!( + spatial_ref.get_attr_value("GEOGCS", 0).unwrap().unwrap(), + "WGS 84" + ); + assert_eq!( + spatial_ref + .get_attr_value("GEOGCS|UNIT", 0) + .unwrap() + .unwrap(), + "degree" + ); + spatial_ref + .set_attr_value("GEOGCS|UNIT", Some("meter")) + .unwrap(); + assert_eq!( + spatial_ref + .get_attr_value("GEOGCS|UNIT", 0) + .unwrap() + .unwrap(), + "meter" + ); } #[test] From adf98cc662400f6d86b7dadf34203012771b6d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 30 May 2023 19:40:38 +0300 Subject: [PATCH 12/14] Add assert for child --- src/spatial_ref/srs.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 65d86c39..1ca324ea 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -564,6 +564,11 @@ impl SpatialRef { /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) pub fn get_attr_value(&self, node_path: &str, child: usize) -> Result> { + assert!( + child <= libc::c_int::MAX as usize, + "`child` must fit in `int`" + ); + let c_node_path = CString::new(node_path)?; let c_ptr_value = unsafe { gdal_sys::OSRGetAttrValue(self.0, c_node_path.as_ptr(), child as libc::c_int) From e42080aa51e8104c4b408d2799974f8615b8a52f Mon Sep 17 00:00:00 2001 From: tombieli Date: Wed, 31 May 2023 12:09:00 +0200 Subject: [PATCH 13/14] Adding information to docs about potential panic in "get_attr_value". --- src/spatial_ref/srs.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 1ca324ea..24403e12 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -562,6 +562,8 @@ impl SpatialRef { /// * `Ok(None)` - if node or attribute are not found (C library will return `nullptr`) or attribute contains no value, /// * `Err(_)` - if there is a string conversion error. /// + /// **Note:** this fuction panics when child > [libc::c_int::MAX]. + /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) pub fn get_attr_value(&self, node_path: &str, child: usize) -> Result> { assert!( From 96ae16814cfab82244b10c1953d4d036177ca61f Mon Sep 17 00:00:00 2001 From: tombieli Date: Wed, 31 May 2023 20:46:47 +0200 Subject: [PATCH 14/14] Comments refactoring according to suggesions by @lnicola. --- src/spatial_ref/srs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/spatial_ref/srs.rs b/src/spatial_ref/srs.rs index 24403e12..1e5e5807 100644 --- a/src/spatial_ref/srs.rs +++ b/src/spatial_ref/srs.rs @@ -557,12 +557,14 @@ impl SpatialRef { /// Fetch indicated attribute of named node. /// - // Returns: + /// Returns: /// * `Ok(Some(value))` - if node and attribute are sucessfully found, /// * `Ok(None)` - if node or attribute are not found (C library will return `nullptr`) or attribute contains no value, /// * `Err(_)` - if there is a string conversion error. /// - /// **Note:** this fuction panics when child > [libc::c_int::MAX]. + /// # Panics + /// + /// If `child` is greater than [`libc::c_int::MAX`]. /// /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAttrValue20OGRSpatialReferenceHPKci) pub fn get_attr_value(&self, node_path: &str, child: usize) -> Result> {