Repository: geopandas/geopandas
Pull request #3543 (2025-04-08 19:47:56)

ENH: add minimum_clearance_line
xref #2010


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c45a702..a797e06d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ New features and improvements:
   to allow better control of conversion of non-geometric Arrow data to DataFrames (#3466).
 - Added `is_valid_coverage` and `invalid_coverage_edges` to GeoSeries/GeoDataFrame to allow validation of polygonal coverage (#3545).
 - Added `maximum_inscribed_circle` method from shapely to GeoSeries/GeoDataframe (#3544).
+- Added `minimum_clearance_line` method from shapely to GeoSeries/GeoDataframe (#3543).
 - Added ``method`` and ``keep_collapsed`` argument to ``make_valid`` (#3548).
 
 Bug fixes:
diff --git a/doc/source/docs/reference/geoseries.rst b/doc/source/docs/reference/geoseries.rst
index 9f8c7ad9..48ebea22 100644
--- a/doc/source/docs/reference/geoseries.rst
+++ b/doc/source/docs/reference/geoseries.rst
@@ -30,6 +30,7 @@ General methods and attributes
    GeoSeries.exterior
    GeoSeries.interiors
    GeoSeries.minimum_bounding_radius
+   GeoSeries.minimum_clearance
    GeoSeries.x
    GeoSeries.y
    GeoSeries.z
@@ -113,6 +114,7 @@ Constructive methods and attributes
    GeoSeries.minimum_bounding_circle
    GeoSeries.maximum_inscribed_circle
    GeoSeries.minimum_clearance
+   GeoSeries.minimum_clearance_line
    GeoSeries.minimum_rotated_rectangle
    GeoSeries.normalize
    GeoSeries.remove_repeated_points
diff --git a/geopandas/array.py b/geopandas/array.py
index e3bf9bfa..44011c88 100644
--- a/geopandas/array.py
+++ b/geopandas/array.py
@@ -679,6 +679,11 @@ class GeometryArray(ExtensionArray):
     def minimum_clearance(self):
         return shapely.minimum_clearance(self._data)
 
+    def minimum_clearance_line(self):
+        if not SHAPELY_GE_21:
+            raise ImportError("'minimum_clearance_line' requires shapely>=2.1.")
+        return GeometryArray(shapely.minimum_clearance_line(self._data), crs=self.crs)
+
     def normalize(self):
         return GeometryArray(shapely.normalize(self._data), crs=self.crs)
 
diff --git a/geopandas/base.py b/geopandas/base.py
index bfe2be3a..554e0027 100644
--- a/geopandas/base.py
+++ b/geopandas/base.py
@@ -1928,9 +1928,51 @@ GeometryCollection
         1    1.414214
         2         inf
         dtype: float64
+
+        See also
+        --------
+        minimum_clearance_line
         """
         return Series(self.geometry.values.minimum_clearance(), index=self.index)
 
+    def minimum_clearance_line(self):
+        """Returns a ``GeoSeries`` of linestrings whose endpoints define the
+        minimum clearance.
+
+        A geometry's “minimum clearance” is the smallest distance by which a vertex
+        of the geometry could be moved to produce an invalid geometry.
+
+        If the geometry has no minimum clearance, an empty LineString will be returned.
+
+        Examples
+        --------
+
+        >>> from shapely.geometry import Polygon, LineString, Point
+        >>> s = geopandas.GeoSeries(
+        ...     [
+        ...         Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
+        ...         LineString([(0, 0), (1, 1), (3, 2)]),
+        ...         Point(0, 0),
+        ...     ]
+        ... )
+        >>> s
+        0    POLYGON ((0 0, 1 1, 0 1, 0 0))
+        1        LINESTRING (0 0, 1 1, 3 2)
+        2                       POINT (0 0)
+        dtype: geometry
+
+        >>> s.minimum_clearance_line()
+        0    LINESTRING (0 1, 0.5 0.5)
+        1        LINESTRING (0 0, 1 1)
+        2             LINESTRING EMPTY
+        dtype: geometry
+
+        See also
+        --------
+        minimum_clearance
+        """
+        return _delegate_geo_method("minimum_clearance_line", self)
+
     def normalize(self):
         """Returns a ``GeoSeries`` of normalized
         geometries to normal form (or canonical form).


Test patch:
diff --git a/geopandas/tests/test_geom_methods.py b/geopandas/tests/test_geom_methods.py
index 71d44780..772ad6ab 100644
--- a/geopandas/tests/test_geom_methods.py
+++ b/geopandas/tests/test_geom_methods.py
@@ -1978,6 +1978,15 @@ class TestGeomMethods:
             Series([1.0, 1.0]),
         )
 
+    @pytest.mark.skipif(not SHAPELY_GE_21, reason="requires shapely 2.1")
+    def test_minimum_clearance_line(self):
+        mcl_geoms = self.g1.minimum_clearance_line()
+
+        expected = GeoSeries(
+            [LineString([(1, 0), (0.5, 0.5)]), LineString([(0, 0), (1, 0)])]
+        )
+        assert_geoseries_equal(mcl_geoms, expected)
+
     @pytest.mark.parametrize("size", [10, 20, 50])
     def test_sample_points(self, size):
         for gs in (