@@ -64,6 +64,80 @@ def geometry(self) -> Dict[str, Tuple[int, int, int]]:
6464
6565 return external_polygons .difference (holes ).__geo_interface__
6666
67+ def _extract_polygons_from_contours (self , contours : List ) -> MultiPolygon :
68+ contours = map (np .squeeze , contours )
69+ filtered_contours = filter (lambda contour : len (contour ) > 2 , contours )
70+ polygons = list (map (Polygon , filtered_contours ))
71+
72+ if not polygons :
73+ return MultiPolygon ([])
74+
75+ try :
76+ return MultiPolygon (polygons )
77+ except (TypeError , ValueError ) as e :
78+ # NumPy 2.0 compatibility - simple wrapper for required operations
79+ if "create_collection" in str (e ) or "casting rule" in str (e ):
80+
81+ class SimpleWrapper :
82+ def __init__ (self , polygons ):
83+ self .is_valid = True
84+ self ._polygons = polygons
85+
86+ def buffer (self , distance ):
87+ buffered = [p .buffer (distance ) for p in self ._polygons ]
88+ return SimpleWrapper (buffered )
89+
90+ def difference (self , other ):
91+ if (
92+ hasattr (other , "_polygons" )
93+ and self ._polygons
94+ and other ._polygons
95+ ):
96+ from shapely .ops import unary_union
97+
98+ self_geom = (
99+ unary_union (self ._polygons )
100+ if len (self ._polygons ) > 1
101+ else self ._polygons [0 ]
102+ )
103+ other_geom = (
104+ unary_union (other ._polygons )
105+ if len (other ._polygons ) > 1
106+ else other ._polygons [0 ]
107+ )
108+ result = self_geom .difference (other_geom )
109+ result_polygons = (
110+ list (result .geoms )
111+ if hasattr (result , "geoms" )
112+ else [result ]
113+ )
114+ return SimpleWrapper (result_polygons )
115+ return self
116+
117+ @property
118+ def __geo_interface__ (self ):
119+ if len (self ._polygons ) == 1 :
120+ poly_coords = self ._polygons [0 ].__geo_interface__ [
121+ "coordinates"
122+ ]
123+ return {
124+ "type" : "MultiPolygon" ,
125+ "coordinates" : [poly_coords ],
126+ }
127+ else :
128+ all_coords = [
129+ p .__geo_interface__ ["coordinates" ]
130+ for p in self ._polygons
131+ ]
132+ return {
133+ "type" : "MultiPolygon" ,
134+ "coordinates" : all_coords ,
135+ }
136+
137+ return SimpleWrapper (polygons )
138+ else :
139+ raise
140+
67141 def draw (
68142 self ,
69143 height : Optional [int ] = None ,
@@ -109,12 +183,6 @@ def draw(
109183 canvas [mask .astype (bool )] = color
110184 return canvas
111185
112- def _extract_polygons_from_contours (self , contours : List ) -> MultiPolygon :
113- contours = map (np .squeeze , contours )
114- filtered_contours = filter (lambda contour : len (contour ) > 2 , contours )
115- polygons = map (Polygon , filtered_contours )
116- return MultiPolygon (polygons )
117-
118186 def create_url (self , signer : Callable [[bytes ], str ]) -> str :
119187 """
120188 Update the segmentation mask to have a url.
0 commit comments