petern48 commented on code in PR #2512:
URL: https://github.com/apache/sedona/pull/2512#discussion_r2579773778
##########
python/tests/geopandas/test_geoseries.py:
##########
@@ -1520,7 +1520,79 @@ def test_force_2d(self):
self.check_sgpd_equals_gpd(df_result, expected)
def test_force_3d(self):
- pass
+ # 1. 2D geometries promoted to 3D with default z=0.0
+ s = sgpd.GeoSeries(
+ [
+ Point(1, 2),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, np.nan),
+ LineString([(1, 1), (0, 1), (1, 0)]),
+ Polygon([(0, 0), (0, 10), (10, 10)]),
+ GeometryCollection(
+ [
+ Point(1, 1),
+ LineString([(1, 1), (0, 1), (1, 0)]),
+ ]
+ ),
+ ]
+ )
+ # Promote 2D to 3D with z=0, keep 3D as is
+ expected = gpd.GeoSeries(
+ [
+ Point(1, 2, 0),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, 0),
+ LineString([(1, 1, 0), (0, 1, 0), (1, 0, 0)]),
+ Polygon([(0, 0, 0), (0, 10, 0), (10, 10, 0), (0, 0, 0)]),
+ GeometryCollection(
+ [
+ Point(1, 1, 0),
+ LineString([(1, 1, 0), (0, 1, 0), (1, 0, 0)]),
+ ]
+ ),
+ ]
+ )
+ result = s.force_3d()
+ self.check_sgpd_equals_gpd(result, expected)
+
+ # 2. 2D geometries promoted to 3D with scalar z
+ expected = gpd.GeoSeries(
+ [
+ Point(1, 2, 4),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, 4),
+ LineString([(1, 1, 4), (0, 1, 4), (1, 0, 4)]),
+ Polygon([(0, 0, 4), (0, 10, 4), (10, 10, 4), (0, 0, 4)]),
+ GeometryCollection(
+ [
+ Point(1, 1, 4),
+ LineString([(1, 1, 4), (0, 1, 4), (1, 0, 4)]),
+ ]
+ ),
+ ]
+ )
+ result = s.force_3d(4)
+ self.check_sgpd_equals_gpd(result, expected)
+
+ # 3. Array-like z: use ps.Series
+ z = [0, 2, 2, 3, 4, 5]
+ expected = gpd.GeoSeries(
+ [
+ Point(1, 2, 0),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, 2),
+ LineString([(1, 1, 3), (0, 1, 3), (1, 0, 3)]),
+ Polygon([(0, 0, 4), (0, 10, 4), (10, 10, 4), (0, 0, 4)]),
+ GeometryCollection(
+ [
+ Point(1, 1, 5),
+ LineString([(1, 1, 5), (0, 1, 5), (1, 0, 5)]),
+ ]
+ ),
+ ]
+ )
+ result = s.force_3d(z)
+ self.check_sgpd_equals_gpd(result, expected)
Review Comment:
Could you add these cases below?
```
ST_Force3D(st_geomfromtext('POINT M (1 2 3)'), 7.5)
-- Result: POINT Z(1 2 7.5)
ST_Force3D(st_geomfromtext('POINT ZM (1 2 3 4)'), 7.5)
-- Result: POINT Z(1 2 3)
```
##########
python/tests/geopandas/test_match_geopandas_series.py:
##########
@@ -878,7 +878,48 @@ def test_force_2d(self):
self.check_sgpd_equals_gpd(sgpd_3d, gpd_3d)
def test_force_3d(self):
- pass
+ # force_3d was added from geopandas 1.0.0
+ if parse_version(gpd.__version__) < parse_version("1.0.0"):
+ pytest.skip("geopandas force_3d requires version 1.0.0 or higher")
+ # 1) Promote 2D to 3D with z = 4
+ for geom in self.geoms:
+ if isinstance(geom[0], (LinearRing, GeometryCollection,
MultiPolygon)):
Review Comment:
```suggestion
if isinstance(geom[0], (LinearRing)):
```
This should theoretically pass now.
##########
python/tests/geopandas/test_geoseries.py:
##########
@@ -1520,7 +1520,79 @@ def test_force_2d(self):
self.check_sgpd_equals_gpd(df_result, expected)
def test_force_3d(self):
- pass
+ # 1. 2D geometries promoted to 3D with default z=0.0
+ s = sgpd.GeoSeries(
+ [
+ Point(1, 2),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, np.nan),
+ LineString([(1, 1), (0, 1), (1, 0)]),
+ Polygon([(0, 0), (0, 10), (10, 10)]),
+ GeometryCollection(
+ [
+ Point(1, 1),
+ LineString([(1, 1), (0, 1), (1, 0)]),
+ ]
+ ),
+ ]
+ )
+ # Promote 2D to 3D with z=0, keep 3D as is
+ expected = gpd.GeoSeries(
+ [
+ Point(1, 2, 0),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, 0),
+ LineString([(1, 1, 0), (0, 1, 0), (1, 0, 0)]),
+ Polygon([(0, 0, 0), (0, 10, 0), (10, 10, 0), (0, 0, 0)]),
+ GeometryCollection(
+ [
+ Point(1, 1, 0),
+ LineString([(1, 1, 0), (0, 1, 0), (1, 0, 0)]),
+ ]
+ ),
+ ]
+ )
+ result = s.force_3d()
+ self.check_sgpd_equals_gpd(result, expected)
+
+ # 2. 2D geometries promoted to 3D with scalar z
+ expected = gpd.GeoSeries(
+ [
+ Point(1, 2, 4),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, 4),
+ LineString([(1, 1, 4), (0, 1, 4), (1, 0, 4)]),
+ Polygon([(0, 0, 4), (0, 10, 4), (10, 10, 4), (0, 0, 4)]),
+ GeometryCollection(
+ [
+ Point(1, 1, 4),
+ LineString([(1, 1, 4), (0, 1, 4), (1, 0, 4)]),
+ ]
+ ),
+ ]
+ )
+ result = s.force_3d(4)
+ self.check_sgpd_equals_gpd(result, expected)
+
+ # 3. Array-like z: use ps.Series
+ z = [0, 2, 2, 3, 4, 5]
+ expected = gpd.GeoSeries(
+ [
+ Point(1, 2, 0),
+ Point(0.5, 2.5, 2),
+ Point(1, 1, 2),
+ LineString([(1, 1, 3), (0, 1, 3), (1, 0, 3)]),
+ Polygon([(0, 0, 4), (0, 10, 4), (10, 10, 4), (0, 0, 4)]),
+ GeometryCollection(
+ [
+ Point(1, 1, 5),
+ LineString([(1, 1, 5), (0, 1, 5), (1, 0, 5)]),
+ ]
+ ),
+ ]
+ )
+ result = s.force_3d(z)
+ self.check_sgpd_equals_gpd(result, expected)
Review Comment:
For those curious about the difference in behavior, Geopandas returns the
following instead. It's strange and inconsistent imo... I would guess it's
unintentional and just a result of adding M support later on.
```python
gpd.GeoSeries([shapely.wkt.loads("POINT M (1 2 3)")]).force_3d(7.5)
0 POINT M (1 2 3)
gpd.GeoSeries([shapely.wkt.loads("POINT ZM (1 2 3 4)")]).force_3d(7.5)
0 POINT Z (1 2 7.5)
```
##########
python/sedona/spark/geopandas/base.py:
##########
@@ -949,8 +949,66 @@ def force_2d(self):
"""
return _delegate_to_geometry_column("force_2d", self)
- # def force_3d(self, z=0):
- # raise NotImplementedError("This method is not implemented yet.")
+ def force_3d(self, z=0.0):
+ """Force the dimensionality of a geometry to 3D.
+
+ 2D geometries will get the provided Z coordinate; 3D geometries
+ are unchanged (unless their Z coordinate is ``np.nan``).
Review Comment:
```suggestion
are unchanged (unless their Z coordinate is ``np.nan``).
Note: Sedona's behavior may differ from Geopandas' for M and ZM
geometries.
For M geometries, Sedona will replace the M coordinate and add the Z
coordinate.
For ZM geometries, Sedona will drop the M coordinate and retain the
Z coordinate.
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]