-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add wrappers for GDALBuildVRT, GDALApplyGeoTransform, GDALInvGeoTransform #239
Conversation
src/raster_programs.rs
Outdated
) -> Result<Dataset> { | ||
// Convert dest to raw string | ||
let dest = match dest { | ||
Some(s) => CString::new(s)?.into_raw(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as below, dest.map(|p| p.as_mut_ptr())
.
Thanks for the feedback. I've summarized my updates below:
I didn't take the suggestions re: raw strings verbatim, as I didn't see how they added terminating null bytes. I did look at |
src/raster_programs.rs
Outdated
|
||
fn _build_vrt(dest: Option<&Path>, datasets: &[&Dataset], args: Vec<String>) -> Result<Dataset> { | ||
// Convert dest to CString | ||
let dest = match dest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not great, but let's use utils::_path_to_c_string
here.
(untested)
let dest = dest.map(crate::_path_to_c_string).transpose()?;
let c_dest = dest.map(CString::as_ptr).unwrap_or(ptr::null());
src/raster_programs.rs
Outdated
/// [GDALBuildVRTOptionsNew]: https://gdal.org/api/gdal_utils.html#_CPPv422GDALBuildVRTOptionsNewPPcP28GDALBuildVRTOptionsForBinary | ||
fn new(args: Vec<String>) -> Result<Self> { | ||
// Convert args to CStrings to add terminating null bytes | ||
let mut cstr_args = Vec::<CString>::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Untested, but:
let cstr_args = args.into_iter()
.map(|arg| CString::new(arg))
.collect::<Result<Vec<_>>>()?;
This looks nicer and (as a minor point) pre-allocates the destination Vec
.
Incorporated latest feedback. |
src/raster_programs.rs
Outdated
/// [GDALBuildVRT]: https://gdal.org/api/gdal_utils.html#gdal__utils_8h_1a057aaea8b0ed0476809a781ffa377ea4 | ||
/// [program docs]: https://gdal.org/programs/gdalbuildvrt.html | ||
pub fn build_vrt<D: Borrow<Dataset>>( | ||
dest: Option<&Path>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for missing this. I guess dest: Option<P> ... where P: AsRef<Path>
would be nicer, so you can call it with strings.
r? @jdroenner |
@lnicola Taking
A default type cannot be specified because that is not allowed for functions:
Is there a cleaner way to do this? |
Ah, good point. You can still specify the type, but it's an ugly API. Let's revert this change . |
This reverts commit 41f8359.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@amartin96 Nice PR! The overall code looks great; my suggestions are mostly cosmetic.
src/lib.rs
Outdated
@@ -42,6 +43,43 @@ pub use dataset::{ | |||
pub use driver::Driver; | |||
pub use metadata::Metadata; | |||
|
|||
/// Apply GeoTransform to x/y coordinate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GeoTransform
relevant methods might be better placed inside the dataset
or the rasters
module. It is anyway only relevant to rasters IIUC.
src/lib.rs
Outdated
/// Wraps [GDALApplyGeoTransform]. | ||
/// | ||
/// [GDALApplyGeoTransform]: https://gdal.org/api/raster_c_api.html#_CPPv421GDALApplyGeoTransformPdddPdPd | ||
pub fn apply_geo_transform(geo_transform: &GeoTransform, pixel: f64, line: f64) -> (f64, f64) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be more ergonomic to throw these inside a trait that is impl by GeoTransform
so we get the nicer:
let (wx, wy) = geo_t.apply(pix, line);
let inv_t = geo_t.invert()?;
Optional suggestion.
src/raster_programs.rs
Outdated
@@ -0,0 +1,107 @@ | |||
use crate::{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to move these into a sub-module raster_programs::vrt
or similar. Not a major concern, but this mod. might get cluttered if we bring in more of the programs like Warp, etc.
src/raster_programs.rs
Outdated
/// | ||
/// [GDALBuildVRT]: https://gdal.org/api/gdal_utils.html#gdal__utils_8h_1a057aaea8b0ed0476809a781ffa377ea4 | ||
/// [program docs]: https://gdal.org/programs/gdalbuildvrt.html | ||
pub fn build_vrt<D: Borrow<Dataset>>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we expose the BuildVRTOptions
struct, and let this method take an Option<BuildVrtOptions>
instead of a Vec<String>
? Seems more similar to the C api, and also a bit more natural.
src/raster_programs.rs
Outdated
/// See [GDALBuildVRTOptionsNew]. | ||
/// | ||
/// [GDALBuildVRTOptionsNew]: https://gdal.org/api/gdal_utils.html#_CPPv422GDALBuildVRTOptionsNewPPcP28GDALBuildVRTOptionsForBinary | ||
fn new(args: Vec<String>) -> Result<Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does args
have to be a Vec<String>
? Wouldn't any IntoIterator<Item = ...>
work? This would avoid allocations if it's a fixed sized array.
Going one more step, does the inner type have to be String
or anything that impls TryInto<CString>
(like Vec<U8>
or Vec<NonZeroU8>
, etc.)?
We can leave it as-is if this makes the API too complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I attempted to implement this as follows:
pub fn new<S: TryInto<CString>, I: IntoIterator<Item = S>>(args: I) -> Result<Self> {
let cstr_args = args.into_iter().map(|x| x.try_into()).collect::<std::result::Result<Vec<CString>, _>>()?;
However, I do not know how to convert TryInto<CString>::Error
to GdalError::FfiNulError
.
Can you show me how its done? Is the rest of it as you intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, good pt.; we can't give a good error for arbitrary conversion failures, and the user could anyway map
as req. before passing it. How about:
fn new<S: Into<Vec<u8>>, I: IntoIterator<Item = S>>(args: I) -> Result<Self> {
let c_args = args
.into_iter()
.map(|x| CString::new(x))
.collect::<std::result::Result<Vec<CString>, _>>()?;
....
}
This is inline with the rest of the lib, where we expect &str
to pass CString
to the FFI. The above seems to accept both &str
, and String
, so that should be good.
I will look into applying the latest feedback this weekend. |
Changes look good to me; thanks again @amartin96 . Pinging @lnicola @jdroenner : could you pls. allow running CI and merge if all looks good? |
I took a hard page fault on this one 😄. |
@amartin96 One final nitpick: it would be good to rename |
src/dataset.rs
Outdated
/// | ||
/// [GDALInvGeoTransform]: https://gdal.org/api/raster_c_api.html#_CPPv419GDALInvGeoTransformPdPd | ||
fn invert(&self) -> Result<GeoTransform> { | ||
let mut gt_out: GeoTransform = Default::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could use MaybeUninit
here, but it's fine to leave it like this.
Minor nit: I prefer keeping as much code as possible outside unsafe
blocks, as in let rv = unsafe { ... }; if rv == 0 { ... }
.
src/programs/raster/vrt.rs
Outdated
.map(|x| x.c_options as *const GDALBuildVRTOptions) | ||
.unwrap_or(null()); | ||
|
||
let result = unsafe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same nit about large unsafe
blocks.
CHANGES.md
Outdated
@@ -2,6 +2,13 @@ | |||
|
|||
## Unreleased | |||
|
|||
- Add `programs::raster::build_vrt` | |||
- Add `GeoTransformTrait` extension trait with `apply` and `invert` | |||
- Add `apply_geo_transform` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two lines need to be removed
bors d+ |
✌️ amartin96 can now approve this pull request. To approve and merge a pull request, simply reply with |
bors r+ |
Build succeeded: |
321: Convert `byte_no_cf` and `cf_nasa_4326` to Zarr r=metasim,jdroenner a=lnicola - [x] I agree to follow the project's [code of conduct](https://github.com/georust/gdal/blob/master/CODE_OF_CONDUCT.md). - [ ] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users. --- Closes #239 I left `alldatatypes.nc` untouched because it's string arrays are not supported. Unfortunately, I had to disable these tests on pre-3.4 GDAL, where Zarr is not supported. Co-authored-by: Laurențiu Nicola <[email protected]>
CHANGES.md
if knowledge of this change could be valuable to users.I did not know where to put
apply_geo_transform
andinv_geo_transform
, so I left them inlib.rs
. Please let me know where they should go.I also did not know what manner of tests should be included. Please let me know what I should contribute in that regard.