Skip to content

Commit b43596c

Browse files
authored
Merge pull request #145 from dmarteau/update_spatial_ref
Add more SpatialRef methods
2 parents c1c2720 + c7733fe commit b43596c

File tree

5 files changed

+247
-2
lines changed

5 files changed

+247
-2
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changes
22

33
## Unreleased
4+
* Add more functions to SpatialRef implementation
5+
* <https://github.com/georust/gdal/pull/145>
46
* **Breaking**: Change `Feature::field` return type from
57
`Result<FieldValue>` to `Result<Option<FieldValue>>`. Fields
68
can be null. Before this change, if a field was null, the value

src/errors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,9 @@ pub enum GdalError {
5757
to: String,
5858
msg: Option<String>,
5959
},
60+
#[error("Axis not found for key '{key}' in method '{method_name}'")]
61+
AxisNotFoundError {
62+
key: String,
63+
method_name: &'static str,
64+
},
6065
}

src/spatial_ref/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod srs;
22

3-
pub use srs::CoordTransform;
4-
pub use srs::SpatialRef;
3+
pub use gdal_sys::OGRAxisOrientation;
4+
pub use srs::{AxisOrientationType, CoordTransform, SpatialRef};
55

66
#[cfg(test)]
77
mod tests;

src/spatial_ref/srs.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ impl CoordTransform {
7878
}
7979
}
8080

81+
#[derive(Debug, Clone)]
82+
pub struct AreaOfUse {
83+
pub west_lon_degree: f64,
84+
pub south_lat_degree: f64,
85+
pub east_lon_degree: f64,
86+
pub north_lat_degree: f64,
87+
pub name: String,
88+
}
89+
90+
pub type AxisOrientationType = gdal_sys::OGRAxisOrientation::Type;
91+
8192
#[derive(Debug)]
8293
pub struct SpatialRef(OGRSpatialReferenceH);
8394

@@ -303,6 +314,123 @@ impl SpatialRef {
303314
}
304315
}
305316

317+
#[cfg(major_ge_3)]
318+
pub fn get_name(&self) -> Result<String> {
319+
let c_ptr = unsafe { gdal_sys::OSRGetName(self.0) };
320+
if c_ptr.is_null() {
321+
return Err(_last_null_pointer_err("OSRGetName"));
322+
}
323+
Ok(_string(c_ptr))
324+
}
325+
326+
pub fn get_angular_units_name(&self) -> Result<String> {
327+
let mut c_ptr = ptr::null_mut();
328+
unsafe { gdal_sys::OSRGetAngularUnits(self.0, &mut c_ptr) };
329+
if c_ptr.is_null() {
330+
return Err(_last_null_pointer_err("OSRGetAngularUnits"));
331+
}
332+
Ok(_string(c_ptr))
333+
}
334+
335+
pub fn get_angular_units(&self) -> f64 {
336+
unsafe { gdal_sys::OSRGetAngularUnits(self.0, ptr::null_mut()) }
337+
}
338+
339+
pub fn get_linear_units_name(&self) -> Result<String> {
340+
let mut c_ptr = ptr::null_mut();
341+
unsafe { gdal_sys::OSRGetLinearUnits(self.0, &mut c_ptr) };
342+
if c_ptr.is_null() {
343+
return Err(_last_null_pointer_err("OSRGetLinearUnits"));
344+
}
345+
Ok(_string(c_ptr))
346+
}
347+
348+
pub fn get_linear_units(&self) -> f64 {
349+
unsafe { gdal_sys::OSRGetLinearUnits(self.0, ptr::null_mut()) }
350+
}
351+
352+
#[inline]
353+
pub fn is_geographic(&self) -> bool {
354+
unsafe { gdal_sys::OSRIsGeographic(self.0) == 1 }
355+
}
356+
357+
#[inline]
358+
#[cfg(all(major_ge_3, minor_ge_1))]
359+
pub fn is_derived_geographic(&self) -> bool {
360+
unsafe { gdal_sys::OSRIsDerivedGeographic(self.0) == 1 }
361+
}
362+
363+
#[inline]
364+
pub fn is_local(&self) -> bool {
365+
unsafe { gdal_sys::OSRIsLocal(self.0) == 1 }
366+
}
367+
368+
#[inline]
369+
pub fn is_projected(&self) -> bool {
370+
unsafe { gdal_sys::OSRIsProjected(self.0) == 1 }
371+
}
372+
373+
#[inline]
374+
pub fn is_compound(&self) -> bool {
375+
unsafe { gdal_sys::OSRIsCompound(self.0) == 1 }
376+
}
377+
378+
#[inline]
379+
pub fn is_geocentric(&self) -> bool {
380+
unsafe { gdal_sys::OSRIsGeocentric(self.0) == 1 }
381+
}
382+
383+
#[inline]
384+
pub fn is_vertical(&self) -> bool {
385+
unsafe { gdal_sys::OSRIsVertical(self.0) == 1 }
386+
}
387+
388+
pub fn get_axis_orientation(&self, target_key: &str, axis: i32) -> Result<AxisOrientationType> {
389+
let mut orientation = gdal_sys::OGRAxisOrientation::OAO_Other;
390+
let c_ptr = unsafe {
391+
gdal_sys::OSRGetAxis(
392+
self.0,
393+
CString::new(target_key)?.as_ptr(),
394+
axis as c_int,
395+
&mut orientation,
396+
)
397+
};
398+
// null ptr indicate a failure (but no CPLError) see Gdal documentation.
399+
if c_ptr.is_null() {
400+
Err(GdalError::AxisNotFoundError {
401+
key: target_key.into(),
402+
method_name: "OSRGetAxis",
403+
})
404+
} else {
405+
Ok(orientation)
406+
}
407+
}
408+
409+
pub fn get_axis_name(&self, target_key: &str, axis: i32) -> Result<String> {
410+
// See get_axis_orientation
411+
let c_ptr = unsafe {
412+
gdal_sys::OSRGetAxis(
413+
self.0,
414+
CString::new(target_key)?.as_ptr(),
415+
axis as c_int,
416+
ptr::null_mut(),
417+
)
418+
};
419+
if c_ptr.is_null() {
420+
Err(GdalError::AxisNotFoundError {
421+
key: target_key.into(),
422+
method_name: "OSRGetAxis",
423+
})
424+
} else {
425+
Ok(_string(c_ptr))
426+
}
427+
}
428+
429+
#[cfg(all(major_ge_3, minor_ge_1))]
430+
pub fn get_axes_count(&self) -> i32 {
431+
unsafe { gdal_sys::OSRGetAxesCount(self.0) }
432+
}
433+
306434
#[cfg(major_ge_3)]
307435
pub fn set_axis_mapping_strategy(&self, strategy: gdal_sys::OSRAxisMappingStrategy::Type) {
308436
unsafe {
@@ -315,6 +443,35 @@ impl SpatialRef {
315443
unsafe { gdal_sys::OSRGetAxisMappingStrategy(self.0) }
316444
}
317445

446+
#[cfg(major_ge_3)]
447+
pub fn get_area_of_use(&self) -> Option<AreaOfUse> {
448+
let mut c_area_name: *const libc::c_char = ptr::null_mut();
449+
let (mut w_long, mut s_lat, mut e_long, mut n_lat): (f64, f64, f64, f64) =
450+
(0.0, 0.0, 0.0, 0.0);
451+
let ret_val = unsafe {
452+
gdal_sys::OSRGetAreaOfUse(
453+
self.0,
454+
&mut w_long,
455+
&mut s_lat,
456+
&mut e_long,
457+
&mut n_lat,
458+
&mut c_area_name,
459+
) == 1
460+
};
461+
462+
if ret_val {
463+
Some(AreaOfUse {
464+
west_lon_degree: w_long,
465+
south_lat_degree: s_lat,
466+
east_lon_degree: e_long,
467+
north_lat_degree: n_lat,
468+
name: _string(c_area_name),
469+
})
470+
} else {
471+
None
472+
}
473+
}
474+
318475
// TODO: should this take self instead of &self?
319476
pub fn to_c_hsrs(&self) -> OGRSpatialReferenceH {
320477
self.0

src/spatial_ref/tests.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,84 @@ fn axis_mapping_strategy() {
222222
gdal_sys::OSRAxisMappingStrategy::OAMS_TRADITIONAL_GIS_ORDER
223223
);
224224
}
225+
226+
#[cfg(major_ge_3)]
227+
#[test]
228+
fn get_area_of_use() {
229+
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();
230+
let area_of_use = spatial_ref.get_area_of_use().unwrap();
231+
assert_almost_eq(area_of_use.west_lon_degree, -180.0);
232+
assert_almost_eq(area_of_use.south_lat_degree, -90.0);
233+
assert_almost_eq(area_of_use.east_lon_degree, 180.0);
234+
assert_almost_eq(area_of_use.north_lat_degree, 90.0);
235+
}
236+
237+
#[cfg(major_ge_3)]
238+
#[test]
239+
fn get_name() {
240+
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();
241+
let name = spatial_ref.get_name().unwrap();
242+
assert_eq!(name, "WGS 84");
243+
}
244+
245+
#[test]
246+
fn get_units_epsg4326() {
247+
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();
248+
249+
let angular_units_name = spatial_ref.get_angular_units_name().unwrap();
250+
assert_eq!(angular_units_name.to_lowercase(), "degree");
251+
let to_radians = spatial_ref.get_angular_units();
252+
assert_almost_eq(to_radians, 0.01745329);
253+
}
254+
255+
#[test]
256+
fn get_units_epsg2154() {
257+
let spatial_ref = SpatialRef::from_epsg(2154).unwrap();
258+
let linear_units_name = spatial_ref.get_linear_units_name().unwrap();
259+
assert_eq!(linear_units_name.to_lowercase(), "metre");
260+
let to_meters = spatial_ref.get_linear_units();
261+
assert_almost_eq(to_meters, 1.0);
262+
}
263+
264+
#[test]
265+
fn predicats_epsg4326() {
266+
let spatial_ref_4326 = SpatialRef::from_epsg(4326).unwrap();
267+
assert!(spatial_ref_4326.is_geographic());
268+
assert!(!spatial_ref_4326.is_local());
269+
assert!(!spatial_ref_4326.is_projected());
270+
assert!(!spatial_ref_4326.is_compound());
271+
assert!(!spatial_ref_4326.is_geocentric());
272+
assert!(!spatial_ref_4326.is_vertical());
273+
274+
#[cfg(all(major_ge_3, minor_ge_1))]
275+
assert!(!spatial_ref_4326.is_derived_geographic());
276+
}
277+
278+
#[test]
279+
fn predicats_epsg2154() {
280+
let spatial_ref_2154 = SpatialRef::from_epsg(2154).unwrap();
281+
assert!(!spatial_ref_2154.is_geographic());
282+
assert!(!spatial_ref_2154.is_local());
283+
assert!(spatial_ref_2154.is_projected());
284+
assert!(!spatial_ref_2154.is_compound());
285+
assert!(!spatial_ref_2154.is_geocentric());
286+
287+
#[cfg(all(major_ge_3, minor_ge_1))]
288+
assert!(!spatial_ref_2154.is_derived_geographic());
289+
}
290+
291+
//XXX Gdal 2 implementation is partial
292+
#[cfg(major_ge_3)]
293+
#[test]
294+
fn crs_axis() {
295+
let spatial_ref = SpatialRef::from_epsg(4326).unwrap();
296+
297+
#[cfg(all(major_ge_3, minor_ge_1))]
298+
assert_eq!(spatial_ref.get_axes_count(), 2);
299+
300+
let orientation = spatial_ref.get_axis_orientation("GEOGCS", 0).unwrap();
301+
assert_eq!(orientation, gdal_sys::OGRAxisOrientation::OAO_North);
302+
assert!(spatial_ref.get_axis_name("GEOGCS", 0).is_ok());
303+
assert!(spatial_ref.get_axis_name("DO_NO_EXISTS", 0).is_err());
304+
assert!(spatial_ref.get_axis_orientation("DO_NO_EXISTS", 0).is_err());
305+
}

0 commit comments

Comments
 (0)