7

Using Python2.7 and shapely, let:

import shapely
coords = [(0, 0), (0, 2), (2, 0), (2, 2), (0, 0)]
bowtie = shapely.geometry.Polygon(coords)
bowtie.is_valid

which gives this :

Self-intersection at or near point 1 1  
Out[2]: False

So let try the buffer(0) method as describer in the doc (http://toblerity.org/shapely/manual.html):

clean = bowtie.buffer(0)
type(clean)

which gives that:

Out[4]: shapely.geometry.polygon.Polygon

The difference between the example in the doc is that in the present case, the crossing point is not defined in the original coordinates, so it's not resulting in a multipolygon and it's not really consistent with these initial coordinates, as this command:

clean.wkt

shows when it returns:

Out[16]: 'POLYGON ((0 0, 0 2, 1 1, 0 0))'

And the resulting image for a more visual understanding:

bowtie cleaned polygon vs original self-intersecting bowtie polygon

With:
Red: original self-intersecting polygon
Teal: cleaned bowtie polygon with buffer(0) method (only one half of the original polygon. Take care of the different scaling effect on iPython...)

Question:
How to easily get the original shape back with a valid geometry so that we can perform further operations like intersections, etc?

  • It seems that using slightly bigger buffer than zero has solved same kind of problems. – user30184 Jun 7 '17 at 19:32
  • I've also tried in this example with buffer(0.1) to buffer(0.5) by increment 0.1; result is the same: clean is a simple polygon, not a multipolygon. – s.k Jun 7 '17 at 19:36
  • You can use GeometryCollection((bowtie, clean)) to plot both at once. – bugmenot123 Jun 10 '17 at 14:26
4

A different hack would be using only the exterior of the bowtie, intersecting it with itself (generating a MultiLineString), polygonizing that (generating Polygons) and finally aggregating into a MultiPolygon:

be = bowtie.exterior
mls = be.intersection(be)
polygons = polygonize(mls)
valid_bowtie = MultiPolygon(polygons)
print(valid_bowtie)

MULTIPOLYGON (((0 0, 0 2, 1 1, 0 0)), ((2 0, 1 1, 2 2, 2 0)))
0

In my case, exterior was returning LinearRing, and anyway, intersection with itself didn't work because the original polygon isn't valid. I ended up finding this answer which was more helpful.

This is the code I came up with:

coords = [[0,0],[1,1],[0,1],[1,0],[0,0]]
line_non_simple = shapely.geometry.LineString(coords)
mls = shapely.ops.unary_union(line_non_simple)
polygons = list(shapely.ops.polygonize(mls))
shapely.geometry.MultiPolygon(polygons)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.