This is an automated email from the ASF dual-hosted git repository.
petern pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sedona.git
The following commit(s) were added to refs/heads/master by this push:
new 762d6f8500 [GH-2476] Implement convex_hull (#2484)
762d6f8500 is described below
commit 762d6f85004c17b3bafef73dc3bb65a3a058e38d
Author: Krishna C Vemulakonda <[email protected]>
AuthorDate: Mon Nov 10 09:41:36 2025 -0700
[GH-2476] Implement convex_hull (#2484)
Co-authored-by: Peter Nguyen <[email protected]>
---
python/sedona/spark/geopandas/base.py | 39 ++++++++++++++++++++--
python/sedona/spark/geopandas/geoseries.py | 11 +++---
python/tests/geopandas/test_geoseries.py | 25 +++++++++++++-
.../tests/geopandas/test_match_geopandas_series.py | 10 +++++-
4 files changed, 74 insertions(+), 11 deletions(-)
diff --git a/python/sedona/spark/geopandas/base.py
b/python/sedona/spark/geopandas/base.py
index 3bdf70b39e..6e9eb39ee0 100644
--- a/python/sedona/spark/geopandas/base.py
+++ b/python/sedona/spark/geopandas/base.py
@@ -611,9 +611,42 @@ class GeoFrame(metaclass=ABCMeta):
# def concave_hull(self, ratio=0.0, allow_holes=False):
# raise NotImplementedError("This method is not implemented yet.")
- # @property
- # def convex_hull(self):
- # raise NotImplementedError("This method is not implemented yet.")
+ @property
+ def convex_hull(self):
+ """
+ Return the convex hull of each geometry.
+
+ The convex hull is the smallest convex Polygon that contains
+ all the points of the geometry.
+
+ Examples
+ --------
+ >>> from shapely.geometry import Point, Polygon, LineString
+ >>> from sedona.spark.geopandas import GeoSeries
+ >>> s = GeoSeries(
+ ... [
+ ... Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
+ ... LineString([(0, 0), (2, 1)]),
+ ... Point(0, 0),
+ ... ]
+ ... )
+ >>> s
+ 0 POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))
+ 1 LINESTRING (0 0, 2 1)
+ 2 POINT (0 0)
+ dtype: geometry
+
+ >>> s.convex_hull
+ 0 POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))
+ 1 POLYGON ((0 0, 2 1, 0 0))
+ 2 POINT (0 0)
+ dtype: geometry
+
+ See also
+ --------
+ GeoSeries.envelope : axis-aligned bounding rectangle
+ """
+ return _delegate_to_geometry_column("convex_hull", self)
# def delaunay_triangles(self, tolerance=0.0, only_edges=False):
# raise NotImplementedError("This method is not implemented yet.")
diff --git a/python/sedona/spark/geopandas/geoseries.py
b/python/sedona/spark/geopandas/geoseries.py
index ec2cebb075..222419afd0 100644
--- a/python/sedona/spark/geopandas/geoseries.py
+++ b/python/sedona/spark/geopandas/geoseries.py
@@ -973,12 +973,11 @@ class GeoSeries(GeoFrame, pspd.Series):
raise NotImplementedError("This method is not implemented yet.")
@property
- def convex_hull(self):
- # Implementation of the abstract method.
- raise NotImplementedError(
- _not_implemented_error(
- "convex_hull", "Computes the convex hull of each geometry."
- )
+ def convex_hull(self) -> "GeoSeries":
+ spark_expr = stf.ST_ConvexHull(self.spark.column)
+ return self._query_geometry_column(
+ spark_expr,
+ returns_geom=True,
)
def delaunay_triangles(self, tolerance=0.0, only_edges=False):
diff --git a/python/tests/geopandas/test_geoseries.py
b/python/tests/geopandas/test_geoseries.py
index 157b46bb5d..30de7fd356 100644
--- a/python/tests/geopandas/test_geoseries.py
+++ b/python/tests/geopandas/test_geoseries.py
@@ -1203,7 +1203,30 @@ e": "Feature", "properties": {}, "geometry": {"type":
"Point", "coordinates": [3
pass
def test_convex_hull(self):
- pass
+ s = GeoSeries(
+ [
+ Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
+ LineString([(0, 0), (2, 1)]),
+ Point(0, 0),
+ None,
+ ]
+ )
+
+ result = s.convex_hull
+
+ expected = gpd.GeoSeries(
+ [
+ Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), # polygon hull ==
itself
+ LineString([(0, 0), (2, 1)]), # NOT a polygon
+ Point(0, 0), # point stays point
+ None, # None stays None
+ ]
+ )
+ self.check_sgpd_equals_gpd(result, expected)
+
+ # Check if GeoDataFrame works as well
+ df_result = s.to_geoframe().convex_hull
+ self.check_sgpd_equals_gpd(df_result, expected)
def test_delaunay_triangles(self):
pass
diff --git a/python/tests/geopandas/test_match_geopandas_series.py
b/python/tests/geopandas/test_match_geopandas_series.py
index 2d7e8848bf..20718baf0c 100644
--- a/python/tests/geopandas/test_match_geopandas_series.py
+++ b/python/tests/geopandas/test_match_geopandas_series.py
@@ -728,7 +728,15 @@ class TestMatchGeopandasSeries(TestGeopandasBase):
pass
def test_convex_hull(self):
- pass
+ for geom in self.geoms:
+ sgpd_result = GeoSeries(geom).convex_hull
+ gpd_result = gpd.GeoSeries(geom).convex_hull
+ self.check_sgpd_equals_gpd(sgpd_result, gpd_result)
+
+ mixed = [self.points[1], self.linestrings[1], self.polygons[1], None]
+ sgpd_result = GeoSeries(mixed).convex_hull
+ gpd_result = gpd.GeoSeries(mixed).convex_hull
+ self.check_sgpd_equals_gpd(sgpd_result, gpd_result)
def test_delaunay_triangles(self):
pass