This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sedona-db.git
The following commit(s) were added to refs/heads/main by this push:
new 1f4506b2 fix(c/sedona-geos): Support export of geometries with M
values from GEOS (#640)
1f4506b2 is described below
commit 1f4506b258d4eefc331f8c1c0198ed1694c9dbe3
Author: Dewey Dunnington <[email protected]>
AuthorDate: Thu Feb 19 08:50:48 2026 -0600
fix(c/sedona-geos): Support export of geometries with M values from GEOS
(#640)
---
Cargo.lock | 61 +++++------------------
Cargo.toml | 47 +++++++----------
c/sedona-geos/src/geos_to_wkb.rs | 20 +++++++-
c/sedona-geos/src/wkb_to_geos.rs | 18 +++----
python/sedonadb/tests/functions/test_functions.py | 4 +-
5 files changed, 61 insertions(+), 89 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index a13a037a..74239ac0 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]]
@@ -6068,7 +6033,7 @@ dependencies = [
"getrandom 0.4.1",
"once_cell",
"rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -6704,7 +6669,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 ce62c751..32099667 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 f60fd897..c8d26038 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<f64> 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 9bd83507..91d75b71 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<f64>,
) -> GResult<geos::CoordSeq> {
- 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::<f64>(),
);
- 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::<LittleEndian>(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 904a3875..fbbda82c 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)"),