It's been a while since I've used or written about Clojure, but I seized an
opportunity to do so today. A Shapely user has been wondering what is up with
simple, yet invalid polygons. The following WKT polygon:
"POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0), (0 0, 0 1, 1 1, 1 0, 0 0))"
has a 2x2 square exterior ring and a square 1x1 interior ring that snaps
precisely into its lower left quadrant.

The interior ring is not a true "hole" because the rings overlap. In the simple
features sense this is an invalid polygon, and Shapely (with GEOS 3.3.0)
confirms it.
>>> ring1 = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)]
>>> ring2 = [(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]
>>> from shapely.geometry import Polygon
>>> q = Polygon(ring1, [ring2])
>>> q.area
3.0
>>> q.is_valid
False
But what's this?
>>> q.is_simple
True
GEOS is a port of JTS – what would JTS do? I'm not a Java programmer, but
there's Clojure: its REPL is a handy means of answering that question. I've
got JTS and JTSIO 1.8.0 in my classpath here.
user=> (def wkt
"POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0), (0 0, 0 1, 1 1, 1 0, 0 0))")
#'user/wkt
user=> wkt
"POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0), (0 0, 0 1, 1 1, 1 0, 0 0))"
user=> (def p (.read (com.vividsolutions.jts.io.WKTReader.) wkt))
#'user/p
user=> p
#<Polygon POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0), (0 0, 0 1, 1 1, 1 0, 0 0))>
user=> (.getArea p)
3.0
user=> (.isValid p)
false
user=> (.isSimple p)
true
JTS, too, says it's simple. Maybe simple features simplicity isn't meaningful for polygons... and a check of the JTS source confirms this.
[isSimple()] Returns true, since by definition LinearRings are always simple.
I can see the rationale, but I think we'll consider breaking with JTS and GEOS
on this one. It would be a first.
Update (2012-09-02)
In hindsight, the case above isn't such a good example. The rings themselves are simple. The polygon is only invalid because they overlap. Instead, here's the case of a bowtie polygon with a self-crossing exterior ring and no interior rings.
wkt = ("POLYGON (("
"39.1451330299999967 23.7510081600000014, "
"97.0537220899999937 40.5455008799999987, "
"105.2652701399999984 48.1330221300000005, "
"100.9175268500000016 58.4333681499999997, "
"71.5608144800000048 83.5511480100000057, "
"60.7118916800000008 86.2531609899999978, "
"62.0046980799999972 75.1478175999999962, "
"83.1631000699999987 42.8207167300000009, "
"92.8230586199999976 37.1917558199999974, "
"95.9940112900000031 26.4705124599999984, "
"106.2205448200000006 15.5197519199999991, "
"39.1451330299999967 23.7510081600000014"
"))" )
bowtie = loads(wkt)
reduce(draw, [bowtie], gca())
Note that I'm exploiting Python's implicit line joining and string literal concatenation to give a little bit of structure to this geometry's WKT representation.

The test of simplicity is performed by GEOS, in which the exterior ring and polygon are simple by defintion.
print bowtie.is_valid
print bowtie.is_simple
print bowtie.exterior.is_simple
False
True
True
If we test the ring as though it were a line we get the opposite result.
from shapely.geometry import LineString
print LineString(bowtie.exterior).is_simple
# False
Whether rings should be simple by definition is, I feel, more a matter of taste than correctness. Letting rings report that they are in fact not simple is more to my taste. The simplicity of a polygon would then be the product of the simplicity of its rings.
from itertools import chain
print all(r.is_simple for r in chain([bowtie.exterior], bowtie.interiors))
# True
By the way, Python's all()
short circuits in a good way: as soon as is_simple
evaluates to False
in the chain, it returns False
.