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 fc61ed2f03 [GH-2482] Geopandas: Implement intersection_all (#2486)
fc61ed2f03 is described below

commit fc61ed2f038f541e6740817a131e294eaf012fba
Author: Subham <[email protected]>
AuthorDate: Wed Nov 12 12:03:05 2025 +0530

    [GH-2482] Geopandas: Implement intersection_all (#2486)
    
    Co-authored-by: Peter Nguyen <[email protected]>
    Co-authored-by: Gourav <[email protected]>
---
 python/sedona/spark/geopandas/base.py              | 25 +++++++++++++++++++---
 python/sedona/spark/geopandas/geoseries.py         | 16 ++++++++++----
 python/tests/geopandas/test_geoseries.py           | 15 ++++++++++++-
 .../tests/geopandas/test_match_geopandas_series.py | 14 ++++++++++++
 4 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/python/sedona/spark/geopandas/base.py 
b/python/sedona/spark/geopandas/base.py
index 53553f54ad..82dd7dd53b 100644
--- a/python/sedona/spark/geopandas/base.py
+++ b/python/sedona/spark/geopandas/base.py
@@ -905,6 +905,28 @@ class GeoFrame(metaclass=ABCMeta):
         """
         return _delegate_to_geometry_column("union_all", self, method, 
grid_size)
 
+    def intersection_all(self) -> BaseGeometry:
+        """Returns a geometry containing the intersection of all geometries in
+        the ``GeoSeries``.
+
+        Returns
+        -------
+        shapely.geometry.base.BaseGeometry
+
+        Examples
+        --------
+        >>> from sedona.spark.geopandas import GeoSeries
+        >>> from shapely.geometry import box
+        >>> s = GeoSeries([box(0, 0, 2, 2), box(1, 1, 3, 3)])
+        >>> s
+        0    POLYGON ((2 0, 2 2, 0 2, 0 0, 2 0))
+        1    POLYGON ((3 1, 3 3, 1 3, 1 1, 3 1))
+        dtype: geometry
+        >>> s.intersection_all()
+        <POLYGON ((1 1, 1 2, 2 2, 2 1, 1 1))>
+        """
+        return _delegate_to_geometry_column("intersection_all", self)
+
     def crosses(self, other, align=None) -> ps.Series:
         """Returns a ``Series`` of ``dtype('bool')`` with value ``True`` for
         each aligned geometry that cross `other`.
@@ -2393,9 +2415,6 @@ class GeoFrame(metaclass=ABCMeta):
         """
         return _delegate_to_geometry_column("union", self, other, align)
 
-    def intersection_all(self):
-        raise NotImplementedError("This method is not implemented yet.")
-
     def contains(self, other, align=None):
         """Returns a ``Series`` of ``dtype('bool')`` with value ``True`` for
         each aligned geometry that contains `other`.
diff --git a/python/sedona/spark/geopandas/geoseries.py 
b/python/sedona/spark/geopandas/geoseries.py
index 0091c8614b..0530b62e3d 100644
--- a/python/sedona/spark/geopandas/geoseries.py
+++ b/python/sedona/spark/geopandas/geoseries.py
@@ -1126,6 +1126,18 @@ class GeoSeries(GeoFrame, pspd.Series):
         geom = ps_series.iloc[0]
         return geom
 
+    def intersection_all(self) -> BaseGeometry:
+        if len(self) == 0:
+            from shapely.geometry import GeometryCollection
+
+            return GeometryCollection()
+        spark_expr = sta.ST_Intersection_Aggr(self.spark.column)
+        tmp = self._query_geometry_column(spark_expr, returns_geom=False, 
is_aggr=True)
+
+        ps_series = tmp.take([0])
+        geom = ps_series.iloc[0]
+        return geom
+
     def crosses(self, other, align=None) -> pspd.Series:
         # Sedona does not support GeometryCollection (errors), so we return 
NULL for now to avoid error.
         other_series, extended = self._make_series_of_val(other)
@@ -1363,10 +1375,6 @@ class GeoSeries(GeoFrame, pspd.Series):
             keep_name=keep_name,
         )
 
-    def intersection_all(self):
-        # Implementation of the abstract method.
-        raise NotImplementedError("This method is not implemented yet.")
-
     # 
============================================================================
     # Binary Predicates
     # 
============================================================================
diff --git a/python/tests/geopandas/test_geoseries.py 
b/python/tests/geopandas/test_geoseries.py
index 28a0b36d6e..c1c373a2ff 100644
--- a/python/tests/geopandas/test_geoseries.py
+++ b/python/tests/geopandas/test_geoseries.py
@@ -1955,7 +1955,20 @@ e": "Feature", "properties": {}, "geometry": {"type": 
"Point", "coordinates": [3
         self.check_sgpd_equals_gpd(df_result, expected)
 
     def test_intersection_all(self):
-        pass
+        s = GeoSeries([box(0, 0, 2, 2), box(1, 1, 3, 3)])
+        result = s.intersection_all()
+        expected = Polygon([(1, 1), (1, 2), (2, 2), (2, 1), (1, 1)])
+        self.check_geom_equals(result, expected)
+
+        # Check that GeoDataFrame works too
+        df_result = s.to_geoframe().intersection_all()
+        self.check_geom_equals(df_result, expected)
+
+        # Empty GeoSeries
+        s = sgpd.GeoSeries([])
+        result = s.intersection_all()
+        expected = GeometryCollection()
+        self.check_geom_equals(result, expected)
 
     def test_contains(self):
         s = GeoSeries(
diff --git a/python/tests/geopandas/test_match_geopandas_series.py 
b/python/tests/geopandas/test_match_geopandas_series.py
index 7ba09205b7..1a9f7ad4ef 100644
--- a/python/tests/geopandas/test_match_geopandas_series.py
+++ b/python/tests/geopandas/test_match_geopandas_series.py
@@ -860,6 +860,20 @@ class TestMatchGeopandasSeries(TestGeopandasBase):
         gpd_result = gpd.GeoSeries([]).union_all()
         self.check_geom_equals(sgpd_result, gpd_result)
 
+    def test_intersection_all(self):
+        if parse_version(gpd.__version__) < parse_version("1.0.0"):
+            pytest.skip("geopandas intersection_all requires version 1.0.0 or 
higher")
+
+        lst = self.geoms
+        sgpd_result = GeoSeries(lst).intersection_all()
+        gpd_result = gpd.GeoSeries(lst).intersection_all()
+        self.check_geom_equals(sgpd_result, gpd_result)
+
+        # Ensure we have the same result for empty GeoSeries
+        sgpd_result = GeoSeries([]).intersection_all()
+        gpd_result = gpd.GeoSeries([]).intersection_all()
+        self.check_geom_equals(sgpd_result, gpd_result)
+
     def test_crosses(self):
         for geom, geom2 in self.pairs:
             if self.contains_any_geom_collection(geom, geom2):

Reply via email to