Skip to content

Commit

Permalink
Misc documentation and formatting tweaks.
Browse files Browse the repository at this point in the history
  • Loading branch information
metasim committed May 9, 2023
1 parent 3af5834 commit 0cb95fa
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 53 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@

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

- Split `spatial_ref` module into more feature-specific submodules.
**Breaking** `SpatialRef::to_c_hsrs` is now `unsafe` since it returns a raw C pointer, as is the convention with
`Dataset::c_dataset`, `Geometry::c_geometry`, etc.

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

## 0.14

- Added new content to `README.md` and the root docs.
Expand Down
3 changes: 1 addition & 2 deletions examples/spatial_reference.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use gdal::errors::Result;
use gdal::spatial_ref::SpatialRef;
use gdal::spatial_ref::CoordTransform;
use gdal::spatial_ref::{CoordTransform, SpatialRef};
use gdal::vector::Geometry;

fn run() -> Result<()> {
Expand Down
4 changes: 2 additions & 2 deletions src/dataset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ impl Dataset {
#[cfg(major_ge_3)]
/// Set the spatial reference system for this dataset.
pub fn set_spatial_ref(&mut self, spatial_ref: &SpatialRef) -> Result<()> {
let rv = unsafe { gdal_sys::GDALSetSpatialRef(self.c_dataset, spatial_ref.c_handle()) };
let rv = unsafe { gdal_sys::GDALSetSpatialRef(self.c_dataset, spatial_ref.to_c_hsrs()) };
if rv != CPLErr::CE_None {
return Err(_last_cpl_err(rv));
}
Expand Down Expand Up @@ -683,7 +683,7 @@ impl Dataset {

let c_layer = unsafe {
let c_srs = match options.srs {
Some(srs) => srs.c_handle(),
Some(srs) => srs.to_c_hsrs(),
None => null_mut(),
};
// The C function takes `char **papszOptions` without mention of `const`, and this is
Expand Down
13 changes: 10 additions & 3 deletions src/spatial_ref/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
//! GDAL Spatial Reference System Functions
//! GDAL Spatial Reference System
//!
//! <https://gdal.org/api/ogr_srs_api.html>
//! See: [Spatial Reference System C API](https://gdal.org/api/ogr_srs_api.html).
//!
//! See also: [OGR Coordinate Reference Systems and Coordinate Transformation Tutorial](https://gdal.org/tutorials/osr_api_tut.html)

mod srs;
mod transform;
mod transform_opts;

pub use srs::{AxisOrientationType, SpatialRef};
/// Axis orientation options
///
/// See [`OGRAxisOrientation`](https://gdal.org/api/ogr_srs_api.html#_CPPv418OGRAxisOrientation).
pub type AxisOrientationType = gdal_sys::OGRAxisOrientation::Type;

pub use srs::SpatialRef;
pub use transform::CoordTransform;
pub use transform_opts::CoordTransformOptions;
66 changes: 46 additions & 20 deletions src/spatial_ref/srs.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
use crate::utils::{_last_null_pointer_err, _string};
use gdal_sys::{self, OGRErr};
use libc::{c_char, c_int};
use std::ffi::{CStr, CString};
use std::ptr::{self};
use std::str::FromStr;

use crate::errors::*;

#[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;

/// A OpenGIS Spatial Reference System definition.
///
/// Used in geo-referencing raster and vector data, and in coordinate transformations.
///
/// # Notes
/// * See also: [OGR Coordinate Reference Systems and Coordinate Transformation Tutorial](https://gdal.org/tutorials/osr_api_tut.html)
/// * Consult the [OGC WKT Coordinate System Issues](https://gdal.org/tutorials/wktproblems.html)
/// page for implementation details of WKT in OGR.
#[derive(Debug)]
pub struct SpatialRef(gdal_sys::OGRSpatialReferenceH);

Expand Down Expand Up @@ -63,11 +59,21 @@ impl SpatialRef {
}
}

/// Get the handle to underlying C API data
pub(crate) unsafe fn c_handle(&self) -> gdal_sys::OGRSpatialReferenceH {
/// Returns a C pointer to the allocated [`gdal_sys::OGRSpatialReferenceH`] memory.
///
/// # Safety
/// This method returns a raw C pointer
pub unsafe fn to_c_hsrs(&self) -> gdal_sys::OGRSpatialReferenceH {
self.0
}

/// Set spatial reference from various text formats.
///
/// This method will examine the provided input, and try to deduce the format,
/// and then use it to initialize the spatial reference system. See the [C++ API docs][CPP]
/// for details on these forms.
///
/// [CPP]: https://gdal.org/api/ogrspatialref.html#_CPPv4N19OGRSpatialReference16SetFromUserInputEPKc
pub fn from_definition(definition: &str) -> Result<SpatialRef> {
let c_obj = unsafe { gdal_sys::OSRNewSpatialReference(ptr::null()) };
if c_obj.is_null() {
Expand Down Expand Up @@ -96,7 +102,7 @@ impl SpatialRef {
pub fn from_epsg(epsg_code: u32) -> Result<SpatialRef> {
let null_ptr = ptr::null_mut();
let c_obj = unsafe { gdal_sys::OSRNewSpatialReference(null_ptr) };
let rv = unsafe { gdal_sys::OSRImportFromEPSG(c_obj, epsg_code as c_int) };
let rv = unsafe { gdal_sys::OSRImportFromEPSG(c_obj, epsg_code as libc::c_int) };
if rv != OGRErr::OGRERR_NONE {
Err(GdalError::OgrError {
err: rv,
Expand Down Expand Up @@ -124,7 +130,7 @@ impl SpatialRef {

pub fn from_esri(esri_wkt: &str) -> Result<SpatialRef> {
let c_str = CString::new(esri_wkt)?;
let mut ptrs = vec![c_str.as_ptr() as *mut c_char, ptr::null_mut()];
let mut ptrs = vec![c_str.as_ptr() as *mut libc::c_char, ptr::null_mut()];
let null_ptr = ptr::null_mut();
let c_obj = unsafe { gdal_sys::OSRNewSpatialReference(null_ptr) };
let rv = unsafe { gdal_sys::OSRImportFromESRI(c_obj, ptrs.as_mut_ptr()) };
Expand Down Expand Up @@ -166,7 +172,8 @@ impl SpatialRef {

pub fn to_pretty_wkt(&self) -> Result<String> {
let mut c_wkt = ptr::null_mut();
let rv = unsafe { gdal_sys::OSRExportToPrettyWkt(self.0, &mut c_wkt, false as c_int) };
let rv =
unsafe { gdal_sys::OSRExportToPrettyWkt(self.0, &mut c_wkt, false as libc::c_int) };
let res = if rv != OGRErr::OGRERR_NONE {
Err(GdalError::OgrError {
err: rv,
Expand Down Expand Up @@ -348,13 +355,17 @@ impl SpatialRef {
unsafe { gdal_sys::OSRIsVertical(self.0) == 1 }
}

pub fn axis_orientation(&self, target_key: &str, axis: i32) -> Result<AxisOrientationType> {
pub fn axis_orientation(
&self,
target_key: &str,
axis: i32,
) -> Result<super::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,
axis as libc::c_int,
&mut orientation,
)
};
Expand All @@ -375,7 +386,7 @@ impl SpatialRef {
gdal_sys::OSRGetAxis(
self.0,
CString::new(target_key)?.as_ptr(),
axis as c_int,
axis as libc::c_int,
ptr::null_mut(),
)
};
Expand Down Expand Up @@ -413,6 +424,9 @@ impl SpatialRef {
}

#[cfg(major_ge_3)]
/// Get the valid use bounding area for this `SpatialRef`.
///
/// See: [`OSRGetAreaOfUse`](https://gdal.org/api/ogr_srs_api.html#_CPPv415OSRGetAreaOfUse20OGRSpatialReferenceHPdPdPdPdPPKc)
pub fn 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) =
Expand Down Expand Up @@ -442,6 +456,18 @@ impl SpatialRef {
}
}

#[derive(Debug, Clone)]
/// Defines the bounding area of valid use for a [`SpatialRef`].
///
/// See [`area_of_use`][SpatialRef::area_of_use].
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,
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
56 changes: 43 additions & 13 deletions src/spatial_ref/transform.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use gdal_sys::{CPLErr, OGRCoordinateTransformationH};
use libc::c_int;
use std::ptr::null_mut;
use crate::errors;
use crate::errors::GdalError;
use crate::spatial_ref::{CoordTransformOptions, SpatialRef};
use crate::utils::{_last_cpl_err, _last_null_pointer_err};
use gdal_sys::{CPLErr, OGRCoordinateTransformationH};
use libc::c_int;
use std::ptr::null_mut;

#[derive(Debug)]
/// Defines a coordinate transformation from one SRS to another.
/// Defines a coordinate transformation from one [`SpatialRef`] to another.
pub struct CoordTransform {
inner: OGRCoordinateTransformationH,
from: String,
Expand All @@ -21,8 +21,13 @@ impl Drop for CoordTransform {
}

impl CoordTransform {
/// Constructs a new transformation from `source` to `target`.
///
/// See: [OCTNewCoordinateTransformation](https://gdal.org/api/ogr_srs_api.html#_CPPv430OCTNewCoordinateTransformation20OGRSpatialReferenceH20OGRSpatialReferenceH)
pub fn new(source: &SpatialRef, target: &SpatialRef) -> errors::Result<CoordTransform> {
let c_obj = unsafe { gdal_sys::OCTNewCoordinateTransformation(source.c_handle(), target.c_handle()) };
let c_obj = unsafe {
gdal_sys::OCTNewCoordinateTransformation(source.to_c_hsrs(), target.to_c_hsrs())
};
if c_obj.is_null() {
return Err(_last_null_pointer_err("OCTNewCoordinateTransformation"));
}
Expand All @@ -33,13 +38,21 @@ impl CoordTransform {
})
}

/// Constructs a new transformation from `source` to `target` with additional extended options
/// defined by `options`: [`CoordTransformOptions`].
///
/// See: [OCTNewCoordinateTransformation](https://gdal.org/api/ogr_srs_api.html#_CPPv432OCTNewCoordinateTransformationEx20OGRSpatialReferenceH20OGRSpatialReferenceH35OGRCoordinateTransformationOptionsH)
pub fn new_with_options(
source: &SpatialRef,
target: &SpatialRef,
options: &CoordTransformOptions,
) -> errors::Result<CoordTransform> {
let c_obj = unsafe {
gdal_sys::OCTNewCoordinateTransformationEx(source.c_handle(), target.c_handle(), options.c_options())
gdal_sys::OCTNewCoordinateTransformationEx(
source.to_c_hsrs(),
target.to_c_hsrs(),
options.c_options(),
)
};
if c_obj.is_null() {
return Err(_last_null_pointer_err("OCTNewCoordinateTransformation"));
Expand All @@ -56,15 +69,21 @@ impl CoordTransform {
///
/// # Arguments
/// * `bounds` - array of [axis0_min, axis1_min, axis0_max, axis1_max],
/// interpreted in the axis order of the source SpatialRef,
/// typically [xmin, ymin, xmax, ymax]
/// interpreted in the axis order of the source SpatialRef,
/// typically [xmin, ymin, xmax, ymax]
/// * `densify_pts` - number of points per edge (recommended: 21)
///
/// # Returns
/// `Ok([f64; 4])` with bounds in axis order of target SpatialRef
/// `Err` if there is an error.
///
/// See: [OCTTransformBounds](https://gdal.org/api/ogr_srs_api.html#_CPPv418OCTTransformBounds28OGRCoordinateTransformationHKdKdKdKdPdPdPdPdKi)
#[cfg(all(major_ge_3, minor_ge_4))]
pub fn transform_bounds(&self, bounds: &[f64; 4], densify_pts: i32) -> errors::Result<[f64; 4]> {
pub fn transform_bounds(
&self,
bounds: &[f64; 4],
densify_pts: i32,
) -> errors::Result<[f64; 4]> {
let mut out_xmin: f64 = 0.;
let mut out_ymin: f64 = 0.;
let mut out_xmax: f64 = 0.;
Expand Down Expand Up @@ -109,7 +128,14 @@ impl CoordTransform {
/// * `x` - slice of x coordinates
/// * `y` - slice of y coordinates (must match x in length)
/// * `z` - slice of z coordinates, or an empty slice to ignore
pub fn transform_coords(&self, x: &mut [f64], y: &mut [f64], z: &mut [f64]) -> errors::Result<()> {
///
/// See: [OCTTransform](https://gdal.org/api/ogr_srs_api.html#_CPPv412OCTTransform28OGRCoordinateTransformationHiPdPdPd)
pub fn transform_coords(
&self,
x: &mut [f64],
y: &mut [f64],
z: &mut [f64],
) -> errors::Result<()> {
let nb_coords = x.len();
assert_eq!(
nb_coords,
Expand Down Expand Up @@ -166,16 +192,20 @@ impl CoordTransform {
.expect("Coordinate transform failed")
}

pub fn to_c_hct(&self) -> OGRCoordinateTransformationH {
/// Returns a C pointer to the allocated [`gdal_sys::OGRCoordinateTransformationH`] memory.
///
/// # Safety
/// This method returns a raw C pointer
pub unsafe fn to_c_hct(&self) -> OGRCoordinateTransformationH {
self.inner
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::assert_almost_eq;
use crate::vector::Geometry;
use super::*;

#[cfg(all(major_ge_3, minor_ge_4))]
#[test]
Expand Down Expand Up @@ -346,4 +376,4 @@ mod tests {
panic!("Wrong error type");
}
}
}
}
17 changes: 9 additions & 8 deletions src/spatial_ref/transform_opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ impl CoordTransformOptions {
/// The west longitude is generally lower than the east longitude, except for areas of interest
/// that go across the anti-meridian.
///
/// For more information, see:
/// <https://gdal.org/tutorials/osr_api_tut.html#advanced-coordinate-transformation>
/// For more information, see
/// [Advanced Coordinate Transformation Tutorial](https://gdal.org/tutorials/osr_api_tut.html#advanced-coordinate-transformation).
///
/// # Arguments
///
Expand Down Expand Up @@ -101,8 +101,9 @@ impl CoordTransformOptions {

/// Sets whether ballpark transformations are allowed.
///
/// By default, PROJ may generate "ballpark transformations" (see
/// <https://proj.org/glossary.html>) when precise datum transformations are missing. For high
/// By default, PROJ may generate "ballpark transformations"
/// (see [Glossary](https://proj.org/glossary.html))
/// when precise datum transformations are missing. For high
/// accuracy use cases, such transformations might not be allowed.
///
/// If this option is specified with PROJ < 8, the `OGR_CT_OP_SELECTION` configuration option
Expand Down Expand Up @@ -131,8 +132,8 @@ impl CoordTransformOptions {
/// string starting with `+proj=pipeline`), a WKT2 string describing a `CoordinateOperation`,
/// or a `"urn:ogc:def:coordinateOperation:EPSG::XXXX"` URN.
///
/// For more information, see:
/// <https://gdal.org/tutorials/osr_api_tut.html#advanced-coordinate-transformation>
/// For more information, see
/// [Advanced Coordinate Transformation Tutorial](https://gdal.org/tutorials/osr_api_tut.html#advanced-coordinate-transformation).
///
/// # Arguments
///
Expand Down Expand Up @@ -173,7 +174,7 @@ mod tests {
options.set_ballpark_allowed(false).unwrap();
let trafo = CoordTransform::new_with_options(&ma, &nl, &options);
let err = trafo.unwrap_err();
assert!(matches!(err, GdalError::NullPointer { .. }), "{:?}", err);
assert!(matches!(err, GdalError::NullPointer { .. }), "{err:?}");
}

#[test]
Expand All @@ -189,4 +190,4 @@ mod tests {
let trafo = CoordTransform::new_with_options(&nad27, &wgs84, &options);
assert!(trafo.is_ok());
}
}
}
2 changes: 1 addition & 1 deletion src/vector/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ impl Geometry {

pub fn set_spatial_ref(&mut self, spatial_ref: SpatialRef) {
unsafe {
gdal_sys::OGR_G_AssignSpatialReference(self.c_geometry(), spatial_ref.c_handle())
gdal_sys::OGR_G_AssignSpatialReference(self.c_geometry(), spatial_ref.to_c_hsrs())
};
}

Expand Down
4 changes: 3 additions & 1 deletion src/vector/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,9 @@ pub trait LayerAccess: Sized {

/// Read batches of columnar [Arrow](https://arrow.apache.org/) data from OGR.
///
/// Extended options are available via [`CslStringList`]. As defined in the OGR documentation for [`GetArrowStream`](https://gdal.org/api/ogrlayer_cpp.html#_CPPv4N8OGRLayer14GetArrowStreamEP16ArrowArrayStream12CSLConstList), the current options are:
/// Extended options are available via [`crate::cpl::CslStringList`].
/// As defined in the OGR documentation for [`GetArrowStream`](https://gdal.org/api/ogrlayer_cpp.html#_CPPv4N8OGRLayer14GetArrowStreamEP16ArrowArrayStream12CSLConstList),
/// the current options are:
///
/// * `INCLUDE_FID=YES/NO`. Whether to include the FID column. Defaults to YES.
/// * `MAX_FEATURES_IN_BATCH=integer`. Maximum number of features to retrieve in a ArrowArray batch. Defaults to 65 536.
Expand Down
Loading

0 comments on commit 0cb95fa

Please sign in to comment.