简体   繁体   中英

Fix invalid polygon in Shapely

Shapely defines a Polygon as invalid if any of its segments intersect, including segments that are colinear. Many software packages will create a region or area with a "cutout" as shown here which has colinear segments:

在此处输入图像描述

>>> pp = Polygon([(0,0), (0,3), (3,3), (3,0), (2,0), 
                  (2,2), (1,2), (1,1), (2,1), (2,0), (0,0)])
>>> pp.is_valid
WARNING:shapely.geos:Self-intersection at or near point 2 0
False

Naturally, the cutout can be implemented natively in Shapely, or this same geometry can be implemented as two valid polygons, but if I only have the list of points shown above, is there an easy to "fix" this (create valid geometry from this list of points)?

I found a solution that works for the specific case given:

>>> pp2 = pp.buffer(0)
>>> pp2.is_valid
True
>>> pp2.exterior.coords[:]
[(0.0, 0.0), (0.0, 3.0), (3.0, 3.0), (3.0, 0.0), (2.0, 0.0), (0.0, 0.0)]
>>> pp2.interiors[0].coords[:]
[(2.0, 1.0), (2.0, 2.0), (1.0, 2.0), (1.0, 1.0), (2.0, 1.0)]

Shapely defines a Polygon as invalid if any of its segments intersect, including segments that are colinear. Many software packages will create a region or area with a "cutout" as shown here which has colinear segments:

在此处输入图片说明

>>> pp = Polygon([(0,0), (0,3), (3,3), (3,0), (2,0), 
                  (2,2), (1,2), (1,1), (2,1), (2,0), (0,0)])
>>> pp.is_valid
WARNING:shapely.geos:Self-intersection at or near point 2 0
False

Naturally, the cutout can be implemented natively in Shapely, or this same geometry can be implemented as two valid polygons, but if I only have the list of points shown above, is there an easy to "fix" this (create valid geometry from this list of points)?

Untested, but it appears that Shapely have added a function to support this now.

https://shapely.readthedocs.io/en/latest/manual.html#validation.make_valid

Shapely implemented a solution for this matter. Through pip you can use shapely 1.8a3 version and import this way:

from shapely.validation import make_valid

Unfortunately, if you have had to install other libraries via conda such as geopandas you will probably face a dependency problem because at this point conda only offers shapely 1.7.1 version. So you can use the shapely solution at your program as shown below:

def make_valid(ob):

from shapely.geometry.base import geom_factory
from shapely.geos import lgeos

if ob.is_valid:
    return ob
return geom_factory(lgeos.GEOSMakeValid(ob._geom))

I have used the .buffer(0) method a lot, but it gave different results on Windows and on Linux. Therefore if you encounter such a problem, remember that:

Warning : The .buffer(0) function of shapely may behave different on different operating systems, ie Windows and Linux. I had examples, where on Linux an empty Polygon is returned while on Windows the correct non-empty Polygon is returned!

This problem took me days to solve, that's why I want to add that as an answer (my suggested edit to the accepted answer was sadly rejected).

simplest solution

new_polygon = pp.buffer(0)
new_polygon.is_valid

maybe it would be work.

This is my first attempt at a fix geometry function. I had to handle the special case where a polygons are converted to multipolygons, where make_valid doesn't work b/c len(make_valid(feature)) !=1 .

from shapely.validation import make_valid

def fix_geom(in_feature):

    # avoid changing original geodf
    in_feature = in_feature.copy(deep=True)    
        
    # drop any missing geometries
    in_feature = in_feature[~(in_feature.is_empty)]
    
    # Repair broken geometries
    for index, row in in_feature.iterrows(): # Looping over all polygons
        if row['geometry'].is_valid:
            next
        else:
            fix = make_valid(row['geometry'])

            try:
                in_feature.loc[[index],'geometry'] =  fix # issue with Poly > Multipolygon
            except ValueError:
                in_feature.loc[[index],'geometry'] =  in_feature.loc[[index], 'geometry'].buffer(0)
    return in_feature

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM