diff --git a/c/sedona-proj/src/proj.rs b/c/sedona-proj/src/proj.rs index c597ec011..053260f3d 100644 --- a/c/sedona-proj/src/proj.rs +++ b/c/sedona-proj/src/proj.rs @@ -371,6 +371,17 @@ impl Proj { Ok((xyzt_out.0, xyzt_out.1)) } + /// Transform XYZ coordinates + pub(crate) fn transform_xyz( + &mut self, + point: (f64, f64, f64), + ) -> Result<(f64, f64, f64), SedonaProjError> { + // Filling extra dimensions with zeroes is what PostGIS does + let xyzt = (point.0, point.1, point.2, 0.0); + let xyzt_out = self.transform(xyzt)?; + Ok((xyzt_out.0, xyzt_out.1, xyzt_out.2)) + } + /// Transform XYZT coordinates pub(crate) fn transform( &mut self, diff --git a/c/sedona-proj/src/transform.rs b/c/sedona-proj/src/transform.rs index 3ed71cbc8..1801b6539 100644 --- a/c/sedona-proj/src/transform.rs +++ b/c/sedona-proj/src/transform.rs @@ -228,6 +228,18 @@ impl CrsTransform for ProjTransform { coord.1 = res.1; Ok(()) } + + fn transform_coord_3d(&self, coord: &mut (f64, f64, f64)) -> Result<(), SedonaGeometryError> { + let res = self.proj.borrow_mut().transform_xyz(*coord).map_err(|e| { + SedonaGeometryError::Invalid(format!( + "PROJ coordinate transformation failed with error: {e}" + )) + })?; + coord.0 = res.0; + coord.1 = res.1; + coord.2 = res.2; + Ok(()) + } } #[cfg(test)] diff --git a/python/sedonadb/tests/functions/test_transforms.py b/python/sedonadb/tests/functions/test_transforms.py index 4f82c5dd2..22bd0fd96 100644 --- a/python/sedonadb/tests/functions/test_transforms.py +++ b/python/sedonadb/tests/functions/test_transforms.py @@ -31,6 +31,16 @@ def test_st_transform(eng): ) +@pytest.mark.parametrize("eng", [SedonaDB, PostGIS]) +def test_st_transform_3d(eng): + eng = eng.create_or_skip() + eng.assert_query_result( + "SELECT ST_Transform(ST_GeomFromText('POINT Z (1 1 1)'), 'EPSG:4979', 'EPSG:4978')", + "POINT Z (6376201.805927448 111297.016517882 110568.792276973)", + wkt_precision=9, + ) + + @pytest.mark.parametrize("eng", [SedonaDB, PostGIS]) @pytest.mark.parametrize( ("geom", "srid", "expected_srid"),