diff --git a/Cargo.lock b/Cargo.lock index f518de7fa..ccbffd95a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,7 +181,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -192,7 +192,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2419,7 +2419,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2525,7 +2525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2885,20 +2885,21 @@ dependencies = [ [[package]] name = "geos" -version = "10.0.0" -source = "git+https://github.com/georust/geos.git?rev=47afbad2483e489911ddb456417808340e9342c3#47afbad2483e489911ddb456417808340e9342c3" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fab6ae800ae29f31e473433e0fd61a07dacdab29644b5e6fd69c835921b9" dependencies = [ "geo-types", "geos-sys", "libc", - "num", "wkt 0.10.3", ] [[package]] name = "geos-sys" -version = "2.0.6" -source = "git+https://github.com/georust/geos.git?rev=47afbad2483e489911ddb456417808340e9342c3#47afbad2483e489911ddb456417808340e9342c3" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "582778505a1ec6d017d0382e947eb592b5f623479b6f1b1f2adf506934e84f89" dependencies = [ "libc", "pkg-config", @@ -3914,20 +3915,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -3963,28 +3950,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -4913,7 +4878,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -6058,7 +6023,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -6694,7 +6659,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ce62c751e..320996677 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,22 +60,21 @@ keywords = ["geospatial", "gis", "spatial", "datafusion", "arrow"] categories = ["science::geo", "database"] [workspace.dependencies] -approx = "0.5" adbc_core = ">=0.22.0" adbc_ffi = ">=0.22.0" -lru = "0.16" +approx = "0.5" arrow = { version = "57.0.0", features = ["prettyprint", "ffi", "chrono-tz"] } arrow-array = { version = "57.0.0" } +arrow-buffer = { version = "57.0.0" } arrow-cast = { version = "57.0.0" } arrow-data = { version = "57.0.0" } arrow-ipc = { version = "57.0.0" } arrow-json = { version = "57.0.0" } arrow-schema = { version = "57.0.0" } -arrow-buffer = { version = "57.0.0" } async-trait = { version = "0.1.87" } bytemuck = "1.25" -bytes = "1.11" byteorder = "1" +bytes = "1.11" chrono = { version = "0.4.41", default-features = false } comfy-table = { version = "7.2" } criterion = { version = "0.8", features = ["html_reports"] } @@ -94,36 +93,26 @@ datafusion-physical-plan = { version = "51.0.0" } datafusion-pruning = { version = "51.0.0" } dirs = "6.0.0" env_logger = "0.11" -log = "^0.4" fastrand = "2.0" +float_next_after = "2" futures = "0.3" -pin-project-lite = "0.2" +geo = "0.31.0" +geo-index = { version = "0.3.3", features = ["use-geo_0_31"] } +geo-traits = "0.3.0" +geo-types = "0.7.17" +geojson = "0.24.2" +geos = { version = "11.0.0", features = ["geo", "v3_12_0"] } glam = "0.32.0" -object_store = { version = "0.12.4", default-features = false } -float_next_after = "2" -num-traits = { version = "0.2", default-features = false, features = ["libm"] } -mimalloc = { version = "0.1", default-features = false } libmimalloc-sys = { version = "0.1", default-features = false } +log = "^0.4" +lru = "0.16" +mimalloc = { version = "0.1", default-features = false } +num-traits = { version = "0.2", default-features = false, features = ["libm"] } +object_store = { version = "0.12.4", default-features = false } once_cell = "1.20" - -geos = { git="https://github.com/georust/geos.git", rev="47afbad2483e489911ddb456417808340e9342c3", features = ["geo", "v3_12_0"] } - -geo-types = "0.7.17" -geo-traits = "0.3.0" -geo = "0.31.0" -geojson = "0.24.2" - -geo-index = { version = "0.3.3", features = ["use-geo_0_31"] } - -wkb = "0.9.2" -wkt = "0.14.0" - parking_lot = "0.12" -parquet = { version = "57.0.0", default-features = false, features = [ - "arrow", - "async", - "object_store", -] } +parquet = { version = "57.0.0", default-features = false, features = ["arrow", "async", "object_store"] } +pin-project-lite = "0.2" rand = "0.10" regex = "1.12" rstest = "0.26.1" @@ -134,6 +123,8 @@ tempfile = { version = "3"} thiserror = { version = "2" } tokio = { version = "1.48", features = ["macros", "rt", "sync"] } url = "2.5.7" +wkb = "0.9.2" +wkt = "0.14.0" # Workspace path dependencies for internal crates sedona = { version = "0.3.0", path = "rust/sedona" } diff --git a/c/sedona-geos/src/geos_to_wkb.rs b/c/sedona-geos/src/geos_to_wkb.rs index f60fd8974..c8d260381 100644 --- a/c/sedona-geos/src/geos_to_wkb.rs +++ b/c/sedona-geos/src/geos_to_wkb.rs @@ -19,7 +19,8 @@ use std::io::Write; use byteorder::{LittleEndian, WriteBytesExt}; use datafusion_common::{error::Result, DataFusionError}; use geo_traits::Dimensions; -use geos::{Geom, Geometry, GeometryTypes}; +use geos::{CoordType, Geom, Geometry, GeometryTypes}; +use sedona_common::sedona_internal_err; use sedona_geometry::wkb_factory::{ write_wkb_geometrycollection_header, write_wkb_linestring_header, write_wkb_multilinestring_header, write_wkb_multipoint_header, write_wkb_multipolygon_header, @@ -265,8 +266,16 @@ fn write_coord_seq( dim: Dimensions, writer: &mut impl Write, ) -> Result<()> { + let coord_type = match dim { + Dimensions::Xy => CoordType::XY, + Dimensions::Xyz => CoordType::XYZ, + Dimensions::Xym => CoordType::XYM, + Dimensions::Xyzm => CoordType::XYZM, + _ => return sedona_internal_err!("Unexpected dimensions {dim:?}"), + }; + let coords = coord_seq - .as_buffer(Some(dim.size())) + .as_buffer(Some(coord_type)) .map_err(|e| DataFusionError::Execution(format!("Failed to get coord seq buffer: {e}")))?; // Cast Vec to &[u8] so we can write the bytes directly to the writer buffer @@ -339,6 +348,13 @@ mod tests { test_wkb_round_trip("LINESTRING Z (0 0 10, 1 1 11, 2 2 12)"); } + #[test] + fn test_write_linestring_xym() { + test_wkb_round_trip("LINESTRING M (0 0 0, 1 1 1)"); + test_wkb_round_trip("LINESTRING M (0 0 0, 1 1 1, 2 2 2)"); + test_wkb_round_trip("LINESTRING M (0 0 10, 1 1 11, 2 2 12)"); + } + #[test] fn test_write_linestring_xyzm() { test_wkb_round_trip("LINESTRING ZM (0 0 1 2, 1 1 3 4)"); diff --git a/c/sedona-geos/src/wkb_to_geos.rs b/c/sedona-geos/src/wkb_to_geos.rs index 9bd835075..91d75b716 100644 --- a/c/sedona-geos/src/wkb_to_geos.rs +++ b/c/sedona-geos/src/wkb_to_geos.rs @@ -18,7 +18,7 @@ use std::cell::RefCell; use byteorder::{BigEndian, ByteOrder, LittleEndian}; use geo_traits::*; -use geos::GResult; +use geos::{CoordType, GResult}; use wkb::{reader::*, Endianness}; /// A factory for converting WKB to GEOS geometries. @@ -215,11 +215,11 @@ fn create_coord_sequence_from_raw_parts( num_coords: usize, scratch: &mut Vec, ) -> GResult { - let (has_z, has_m, dim_size) = match dim { - Dimension::Xy => (false, false, 2), - Dimension::Xyz => (true, false, 3), - Dimension::Xym => (false, true, 3), - Dimension::Xyzm => (true, true, 4), + let (coord_type, dim_size) = match dim { + Dimension::Xy => (CoordType::XY, 2), + Dimension::Xyz => (CoordType::XYZ, 3), + Dimension::Xym => (CoordType::XYM, 3), + Dimension::Xyzm => (CoordType::XYZM, 4), }; let num_ordinates = dim_size * num_coords; @@ -233,7 +233,7 @@ fn create_coord_sequence_from_raw_parts( { let coords_f64 = unsafe { &*core::ptr::slice_from_raw_parts(ptr as *const f64, num_ordinates) }; - geos::CoordSeq::new_from_buffer(coords_f64, num_coords, has_z, has_m) + geos::CoordSeq::new_from_buffer(coords_f64, num_coords, coord_type) } // On platforms without unaligned memory access support, we need to copy the data to the @@ -249,7 +249,7 @@ fn create_coord_sequence_from_raw_parts( scratch.as_mut_ptr() as *mut u8, num_ordinates * std::mem::size_of::(), ); - geos::CoordSeq::new_from_buffer(scratch.as_slice(), num_coords, has_z, has_m) + geos::CoordSeq::new_from_buffer(scratch.as_slice(), num_coords, coord_type) } } } else { @@ -262,7 +262,7 @@ fn create_coord_sequence_from_raw_parts( save_f64_to_scratch::(scratch, buf, num_ordinates); } } - geos::CoordSeq::new_from_buffer(scratch.as_slice(), num_coords, has_z, has_m) + geos::CoordSeq::new_from_buffer(scratch.as_slice(), num_coords, coord_type) } } diff --git a/python/sedonadb/tests/functions/test_functions.py b/python/sedonadb/tests/functions/test_functions.py index 904a38753..fbbda82cd 100644 --- a/python/sedonadb/tests/functions/test_functions.py +++ b/python/sedonadb/tests/functions/test_functions.py @@ -1174,10 +1174,10 @@ def test_st_unaryunion(eng, geom, expected): @pytest.mark.parametrize( ("geom", "expected"), [ - # Skip M tests because geos rust isn't capable of writing XYM geometries yet - # https://github.com/apache/sedona-db/issues/481 + ("POINT M EMPTY", "POINT M EMPTY"), ("POINT Z EMPTY", "POINT Z EMPTY"), ("POINT ZM EMPTY", "POINT ZM EMPTY"), + ("POINT M (0 1 2)", "POINT M(0 1 2)"), ("POINT Z (0 0 0)", "POINT Z(0 0 0)"), ("POINT ZM (1 2 3 4)", "POINT ZM(1 2 3 4)"), ("LINESTRING Z (0 0 0, 1 1 1)", "LINESTRING Z(0 0 0,1 1 1)"),