Skip to content

Commit 7ac63a7

Browse files
Kontinuationkontinuation
authored andcommitted
feat(raster): add GDAL raster support
refactor(raster): align executor semantics with main fix(submodules): align pointers with main fix(submodules): restore gitmodules config Revert array and builder to main fix(sedona-gdal): restore missing files and methods after rebase Resolve conflict resolving problems
1 parent 38c777f commit 7ac63a7

35 files changed

Lines changed: 9415 additions & 30 deletions

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

c/sedona-gdal/src/dyn_load.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ fn load_all_symbols(lib: &Library, api: &mut SedonaGdalApi) -> Result<(), GdalIn
157157
load_fn!(lib, api, VSIFileFromMemBuffer);
158158
load_fn!(lib, api, VSIFCloseL);
159159
load_fn!(lib, api, VSIUnlink);
160+
load_fn!(lib, api, VSIGetDirectorySeparator);
161+
load_fn!(lib, api, VSIOpenDir);
162+
load_fn!(lib, api, VSIGetNextDirEntry);
163+
load_fn!(lib, api, VSICloseDir);
160164
load_fn!(lib, api, VSIGetMemFileBuffer);
161165
load_fn!(lib, api, VSIFree);
162166
load_fn!(lib, api, VSIMalloc);

c/sedona-gdal/src/gdal.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,23 @@ impl Gdal {
171171
vsi::get_vsi_mem_file_bytes_owned(self.api, file_name)
172172
}
173173

174+
/// Open a VSI directory for iteration.
175+
/// See also [`vsi::open_dir`].
176+
pub fn open_vsi_dir(
177+
&self,
178+
path: &str,
179+
recurse_depth: i32,
180+
options: Option<&crate::cpl::CslStringList>,
181+
) -> Result<crate::vsi::VsiDir> {
182+
crate::vsi::open_dir(self.api, path, recurse_depth, options)
183+
}
184+
185+
/// Return the directory separator used by GDAL for a given VSI path.
186+
/// See also [`vsi::get_directory_separator`].
187+
pub fn vsi_directory_separator(&self, path: &str) -> Result<String> {
188+
crate::vsi::get_directory_separator(self.api, path)
189+
}
190+
174191
// -- Raster operations ---------------------------------------------------
175192

176193
/// Create a bare in-memory MEM dataset with GDAL-owned bands.

c/sedona-gdal/src/gdal_dyn_bindgen.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ pub type GDALRWFlag = c_int;
3131
pub type OGRwkbByteOrder = c_int;
3232
pub type GDALOpenFlags = c_uint;
3333
pub type GDALRIOResampleAlg = c_int;
34+
pub type GUIntBig = u64;
35+
pub type GIntBig = i64;
36+
pub type vsi_l_offset = GUIntBig;
3437

3538
// --- Opaque handle types ---
3639

@@ -44,6 +47,31 @@ pub type OGRFeatureH = *mut c_void;
4447
pub type OGRFieldDefnH = *mut c_void;
4548
pub type VSILFILE = *mut c_void;
4649

50+
// --- VSI mode constants ---
51+
52+
pub const VSI_S_IFMT: i32 = 0o170000;
53+
pub const VSI_S_IFDIR: i32 = 0o040000;
54+
pub const VSI_S_IFREG: i32 = 0o100000;
55+
56+
#[repr(C)]
57+
#[derive(Debug, Copy, Clone)]
58+
pub struct VSIDIR {
59+
_unused: [u8; 0],
60+
}
61+
62+
#[repr(C)]
63+
#[derive(Debug, Copy, Clone)]
64+
pub struct VSIDIREntry {
65+
pub pszName: *mut c_char,
66+
pub nMode: c_int,
67+
pub nSize: vsi_l_offset,
68+
pub nMTime: GIntBig,
69+
pub bModeKnown: c_char,
70+
pub bSizeKnown: c_char,
71+
pub bMTimeKnown: c_char,
72+
pub papszExtra: *mut *mut c_char,
73+
}
74+
4775
// --- Enum types ---
4876

4977
#[repr(C)]
@@ -459,6 +487,17 @@ pub(crate) struct SedonaGdalApi {
459487
>,
460488
pub VSIFCloseL: Option<unsafe extern "C" fn(fp: VSILFILE) -> c_int>,
461489
pub VSIUnlink: Option<unsafe extern "C" fn(pszFilename: *const c_char) -> c_int>,
490+
pub VSIGetDirectorySeparator:
491+
Option<unsafe extern "C" fn(pszPath: *const c_char) -> *const c_char>,
492+
pub VSIOpenDir: Option<
493+
unsafe extern "C" fn(
494+
pszPath: *const c_char,
495+
nRecurseDepth: c_int,
496+
papszOptions: *const *const c_char,
497+
) -> *mut VSIDIR,
498+
>,
499+
pub VSIGetNextDirEntry: Option<unsafe extern "C" fn(dir: *mut VSIDIR) -> *const VSIDIREntry>,
500+
pub VSICloseDir: Option<unsafe extern "C" fn(dir: *mut VSIDIR)>,
462501
pub VSIGetMemFileBuffer: Option<
463502
unsafe extern "C" fn(
464503
pszFilename: *const c_char,

c/sedona-gdal/src/vsi.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,90 @@ mod tests {
290290
.unwrap();
291291
}
292292
}
293+
294+
pub struct VsiDirEntry {
295+
pub name: String,
296+
pub mode: Option<i32>,
297+
pub size: Option<crate::gdal_dyn_bindgen::vsi_l_offset>,
298+
pub mtime: Option<crate::gdal_dyn_bindgen::GIntBig>,
299+
}
300+
301+
pub struct VsiDir {
302+
api: &'static crate::gdal_api::GdalApi,
303+
handle: *mut crate::gdal_dyn_bindgen::VSIDIR,
304+
}
305+
306+
impl VsiDir {
307+
pub fn next_entry(&mut self) -> Option<VsiDirEntry> {
308+
let entry = unsafe { (self.api.inner.VSIGetNextDirEntry?)(self.handle) };
309+
if entry.is_null() {
310+
return None;
311+
}
312+
let entry = unsafe { &*entry };
313+
314+
let name = if entry.pszName.is_null() {
315+
String::new()
316+
} else {
317+
unsafe { std::ffi::CStr::from_ptr(entry.pszName) }
318+
.to_string_lossy()
319+
.into_owned()
320+
};
321+
322+
Some(VsiDirEntry {
323+
name,
324+
mode: (entry.bModeKnown != 0).then_some(entry.nMode),
325+
size: (entry.bSizeKnown != 0).then_some(entry.nSize),
326+
mtime: (entry.bMTimeKnown != 0).then_some(entry.nMTime),
327+
})
328+
}
329+
}
330+
331+
impl Iterator for VsiDir {
332+
type Item = VsiDirEntry;
333+
fn next(&mut self) -> Option<Self::Item> {
334+
self.next_entry()
335+
}
336+
}
337+
338+
impl Drop for VsiDir {
339+
fn drop(&mut self) {
340+
if !self.handle.is_null() {
341+
if let Some(close) = self.api.inner.VSICloseDir {
342+
unsafe { close(self.handle) };
343+
}
344+
self.handle = std::ptr::null_mut();
345+
}
346+
}
347+
}
348+
349+
pub fn open_dir(
350+
api: &'static crate::gdal_api::GdalApi,
351+
path: &str,
352+
recurse_depth: i32,
353+
options: Option<&crate::cpl::CslStringList>,
354+
) -> crate::errors::Result<VsiDir> {
355+
let c_path = std::ffi::CString::new(path)?;
356+
let options_ptr: *const *const std::os::raw::c_char = options
357+
.map(|opts| opts.as_ptr() as *const *const std::os::raw::c_char)
358+
.unwrap_or(std::ptr::null());
359+
let handle =
360+
unsafe { (api.inner.VSIOpenDir.unwrap())(c_path.as_ptr(), recurse_depth, options_ptr) };
361+
if handle.is_null() {
362+
return Err(api.last_null_pointer_err("VSIOpenDir"));
363+
}
364+
Ok(VsiDir { api, handle })
365+
}
366+
367+
pub fn get_directory_separator(
368+
api: &'static crate::gdal_api::GdalApi,
369+
path: &str,
370+
) -> crate::errors::Result<String> {
371+
let c_path = std::ffi::CString::new(path)?;
372+
let separator_ptr = unsafe { (api.inner.VSIGetDirectorySeparator.unwrap())(c_path.as_ptr()) };
373+
if separator_ptr.is_null() {
374+
return Err(api.last_null_pointer_err("VSIGetDirectorySeparator"));
375+
}
376+
Ok(unsafe { std::ffi::CStr::from_ptr(separator_ptr) }
377+
.to_string_lossy()
378+
.into_owned())
379+
}

rust/sedona-raster-functions/src/crs_utils.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,34 @@ pub fn crs_transform_wkb(
6464
Ok(out)
6565
}
6666

67+
/// Transform a single coordinate pair from one CRS to another.
68+
///
69+
/// This is a utility used by raster/spatial functions when only an `(x, y)`
70+
/// coordinate needs reprojection and full geometry decoding would be unnecessary.
71+
///
72+
/// **Behavior**
73+
/// - Builds a PROJ pipeline for `from_crs` -> `to_crs`.
74+
/// - Applies the transformation in place and returns the transformed coordinate.
75+
///
76+
/// **Errors**
77+
/// - Returns an error if PROJ cannot build the CRS-to-CRS transform,
78+
/// or if the coordinate transformation itself fails.
79+
pub fn crs_transform_coord(
80+
engine: &dyn CrsEngine,
81+
coord: (f64, f64),
82+
from_crs: &str,
83+
to_crs: &str,
84+
) -> Result<(f64, f64)> {
85+
let trans = engine
86+
.get_transform_crs_to_crs(from_crs, to_crs, None, "")
87+
.map_err(|e| DataFusionError::External(Box::new(e)))?;
88+
let mut coord = coord;
89+
trans
90+
.transform_coord(&mut coord)
91+
.map_err(|e| DataFusionError::External(Box::new(e)))?;
92+
Ok(coord)
93+
}
94+
6795
#[cfg(test)]
6896
mod tests {
6997
use super::*;

rust/sedona-raster-functions/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub mod register;
2222
pub mod rs_band_accessors;
2323
pub mod rs_bandpath;
2424
pub mod rs_convexhull;
25+
pub mod rs_count;
2526
pub mod rs_envelope;
2627
pub mod rs_example;
2728
pub mod rs_georeference;

rust/sedona-raster-functions/src/register.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub fn default_function_set() -> FunctionSet {
4242
crate::rs_band_accessors::rs_bandnodatavalue_udf,
4343
crate::rs_bandpath::rs_bandpath_udf,
4444
crate::rs_convexhull::rs_convexhull_udf,
45+
crate::rs_count::rs_count_udf,
4546
crate::rs_envelope::rs_envelope_udf,
4647
crate::rs_example::rs_example_udf,
4748
crate::rs_georeference::rs_georeference_udf,

0 commit comments

Comments
 (0)