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 8de70083cc [GH-2485] Implement minimum_bounding_circle (#2488)
8de70083cc is described below

commit 8de70083cc405a22836538e52e24bb116086943f
Author: Krishna C Vemulakonda <[email protected]>
AuthorDate: Tue Nov 11 10:26:01 2025 -0700

    [GH-2485] Implement minimum_bounding_circle (#2488)
    
    Co-authored-by: Peter Nguyen <[email protected]>
---
 python/sedona/spark/geopandas/base.py              | 21 ++++++++++++++++--
 python/sedona/spark/geopandas/geoseries.py         |  9 +++++---
 python/tests/geopandas/test_geopandas_base.py      |  8 ++-----
 python/tests/geopandas/test_geoseries.py           | 25 +++++++++++++++++++++-
 .../tests/geopandas/test_match_geopandas_series.py |  5 ++++-
 5 files changed, 55 insertions(+), 13 deletions(-)

diff --git a/python/sedona/spark/geopandas/base.py 
b/python/sedona/spark/geopandas/base.py
index 6e9eb39ee0..53553f54ad 100644
--- a/python/sedona/spark/geopandas/base.py
+++ b/python/sedona/spark/geopandas/base.py
@@ -722,8 +722,25 @@ class GeoFrame(metaclass=ABCMeta):
     # def representative_point(self):
     #     raise NotImplementedError("This method is not implemented yet.")
 
-    # def minimum_bounding_circle(self):
-    #     raise NotImplementedError("This method is not implemented yet.")
+    def minimum_bounding_circle(self):
+        """
+        Returns a ``GeoSeries`` containing the minimum bounding circle of each 
geometry.
+        The minimum bounding circle is the smallest circle that completely 
encloses
+        the geometry. The result is returned as a circular polygon 
approximation.
+        Returns
+        -------
+        GeoSeries
+            A GeoSeries containing the minimum bounding circle for each 
geometry.
+        Examples
+        --------
+        >>> from shapely.geometry import Polygon
+        >>> from sedona.spark.geopandas import GeoSeries
+        >>> gs = GeoSeries([Polygon([(0, 0), (3, 0), (3, 3), (0, 3)])])
+        >>> gs.minimum_bounding_circle
+        0    POLYGON ((...))
+        dtype: geometry
+        """
+        return _delegate_to_geometry_column("minimum_bounding_circle", self)
 
     # def minimum_bounding_radius(self):
     #     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 222419afd0..0091c8614b 100644
--- a/python/sedona/spark/geopandas/geoseries.py
+++ b/python/sedona/spark/geopandas/geoseries.py
@@ -1030,9 +1030,12 @@ class GeoSeries(GeoFrame, pspd.Series):
         # Implementation of the abstract method.
         raise NotImplementedError("This method is not implemented yet.")
 
-    def minimum_bounding_circle(self):
-        # Implementation of the abstract method.
-        raise NotImplementedError("This method is not implemented yet.")
+    def minimum_bounding_circle(self) -> "GeoSeries":
+        spark_expr = stf.ST_MinimumBoundingCircle(self.spark.column)
+        return self._query_geometry_column(
+            spark_expr,
+            returns_geom=True,
+        )
 
     def minimum_bounding_radius(self):
         # Implementation of the abstract method.
diff --git a/python/tests/geopandas/test_geopandas_base.py 
b/python/tests/geopandas/test_geopandas_base.py
index d2171bc1e1..de6ab14ad0 100644
--- a/python/tests/geopandas/test_geopandas_base.py
+++ b/python/tests/geopandas/test_geopandas_base.py
@@ -53,9 +53,7 @@ class TestGeopandasBase(TestBase):
     # TODO chore: rename to check_sgpd_series_equals_gpd_series and change the 
names in the geoseries tests
     @classmethod
     def check_sgpd_equals_gpd(
-        cls,
-        actual: GeoSeries,
-        expected: gpd.GeoSeries,
+        cls, actual: GeoSeries, expected: gpd.GeoSeries, tolerance: float = 
1e-2
     ):
         assert isinstance(actual, GeoSeries)
         assert isinstance(expected, gpd.GeoSeries)
@@ -69,9 +67,7 @@ class TestGeopandasBase(TestBase):
             # Sometimes sedona and geopandas both return empty geometries but 
of different types (e.g Point and Polygon)
             elif a.is_empty and e.is_empty:
                 continue
-            cls.assert_geometry_almost_equal(
-                a, e, tolerance=1e-2
-            )  # increased tolerance from 1e-6
+            cls.assert_geometry_almost_equal(a, e, tolerance)
 
         assert_index_equal(actual.index.to_pandas(), expected.index)
 
diff --git a/python/tests/geopandas/test_geoseries.py 
b/python/tests/geopandas/test_geoseries.py
index 30de7fd356..28a0b36d6e 100644
--- a/python/tests/geopandas/test_geoseries.py
+++ b/python/tests/geopandas/test_geoseries.py
@@ -1283,7 +1283,30 @@ e": "Feature", "properties": {}, "geometry": {"type": 
"Point", "coordinates": [3
         pass
 
     def test_minimum_bounding_circle(self):
-        pass
+        s = GeoSeries(
+            [
+                Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
+                LineString([(0, 0), (2, 0)]),
+                Point(0, 0),
+                None,
+            ]
+        )
+
+        expected = gpd.GeoSeries(
+            [
+                Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
+                LineString([(0, 0), (2, 0)]),
+                Point(0, 0),
+                None,
+            ]
+        ).minimum_bounding_circle()
+
+        result = s.minimum_bounding_circle()
+        self.check_sgpd_equals_gpd(result, expected)
+
+        gdf = s.to_geoframe()
+        df_result = gdf.minimum_bounding_circle()
+        self.check_sgpd_equals_gpd(df_result, expected)
 
     def test_minimum_bounding_radius(self):
         pass
diff --git a/python/tests/geopandas/test_match_geopandas_series.py 
b/python/tests/geopandas/test_match_geopandas_series.py
index 20718baf0c..7ba09205b7 100644
--- a/python/tests/geopandas/test_match_geopandas_series.py
+++ b/python/tests/geopandas/test_match_geopandas_series.py
@@ -775,7 +775,10 @@ class TestMatchGeopandasSeries(TestGeopandasBase):
         pass
 
     def test_minimum_bounding_circle(self):
-        pass
+        for geom in self.geoms:
+            sgpd_result = GeoSeries(geom).minimum_bounding_circle()
+            gpd_result = gpd.GeoSeries(geom).minimum_bounding_circle()
+            self.check_sgpd_equals_gpd(sgpd_result, gpd_result, tolerance=0.5)
 
     def test_minimum_bounding_radius(self):
         pass

Reply via email to