Closed peterstace closed 3 years ago
The first multipolygon in the attached file contains 6 child polygons. The 4th child polygon's exterior ring is not simple, which violates the validation rules for polygons. In particular, the offending control points in the exterior ring are:
Index Point
297 {151.1567491196036 -33.578014746144}
298 {151.15686002573 -33.57427243628813}
299 {151.15686002573 -33.57427243628814}
300 {151.15686002573 -33.57427243628813}
301 {151.1568730920001 -33.57428004599996}
302 {151.1569620060001 -33.57433404699998}
The 298th and 300th control point are identical, so this ring doubles back on itself (thus making it non-simple and thus the Polgyon invalid).
This confirms that GEOS has emitted an invalid geometry it this case, and simplefeatures' MultiPolygon validation algorithm is correctly identifying it as such.
This agrees with what PostGIS is saying as well:
SELECT ST_IsValid('01060000000600000... omitted for brevity ...417eb119bc40c0'::geometry);
NOTICE: Self-intersection at or near point 151.15686002573 -33.57427243628814
st_isvalid
------------
f
(1 row)
Interestingly the 299th control point is only a single ULP away from the 298th and 300th control point, so we're dealing with a very marginal case here (so it's understandable that GEOS doesn't get this 100% correct).
What I'm thinking right now is that we probably have to just deal with GEOS sometimes giving invalid geometries. There are a few possible ways to work around this:
Require that the user of simplefeatures provide the DisableAllValidations
when using GEOS operations such as geos.Intersection
, geos.Union
etc. This has the disadvantage that the user now has an invalid geometry, and thus has to be very careful what they actually do with it.
Before giving back the geometry to the user, run the geometry through extern GEOSGeometry GEOS_DLL *GEOSMakeValid_r(GEOSContextHandle_t handle, const GEOSGeometry* g);
. This has the advantage that the user should end up with a valid geometry, but it has the disadvantage that everything will be a tiny bit slower due to the extra processing.
I'm thinking that option 2 is probably the best.
Something that I haven't considered yet is that GEOS emitted invalid geometries because the inputs to its operation (intersection in this case) were invalid. If this is the case, it would mean that there is a bug in simplefeatures geometry validation logic (i.e. it didn't detect an invalid geometry as being invalid). I'll take a look into that. EDIT: this turned out not to be the case, see the comment below).
The input geometries to the GEOS operation seems to be valid. However, they contain control points that are extremely close together.
This is an extract from the input geometry to GEOS around 151.15686002573, -33.57427243628814 (which is where the GEOS result had self-intersection in its outer ring):
[
151.1567888500001,
-33.57423098399994
],
[
151.15686002573,
-33.57427243628814
],
[
151.15686002573,
-33.57427243628813
],
[
151.1568730920001,
-33.57428004599996
],
With adjacent control points only a single ULP appart from each other, I'm not surprised at all that GEOS has trouble with these.
Nothing more to do here, closing.
GEOS has emitted the attached WKBs, and simplefeatures as reporting them as invalid. There are two possibilities:
The task here is to investigate to see which of the two cases we are looking at. possible_validation_bug.txt