Not sure if this is what is going on, but there are 2 rules identified in the check/repair geometry
1 remove sequential duplicate points
2 close open polygons
If I take two of your polygon shapes, one CW and one CCW ring, you end up with the sequence of potential steps
Line 23, the array points ends up being a multipart shape, 2 shapes with the same number of points.
a1 = np.array([[10., 5.], [15., 10.], [20., 5.], [15., 0.], [10., 5.]])
ccw = np.array([[10., 5.], [7.5, 7.5], [5., 5.], [7.5, 2.5], [10., 5.]])
tmp = np.asarray([a1, ccw])
z_3 = np.vstack(tmp)
dif = np.diff(z_3, axis=0)
z_3b = z_3[np.nonzero(dif)].reshape(-1, 2)
z_3b = np.concatenate((z_3b, [z_3[-1]]))
a1
array([[10., 5.],
[15., 10.],
[20., 5.],
[15., 0.],
[10., 5.]])
ccw
array([[10. , 5. ],
[ 7.5, 7.5],
[ 5. , 5. ],
[ 7.5, 2.5],
[10. , 5. ]])
tmp
array([[[10. , 5. ],
[15. , 10. ],
[20. , 5. ],
[15. , 0. ],
[10. , 5. ]],
[[10. , 5. ],
[ 7.5, 7.5],
[ 5. , 5. ],
[ 7.5, 2.5],
[10. , 5. ]]])
z_3
array([[10. , 5. ],
[15. , 10. ],
[20. , 5. ],
[15. , 0. ],
[10. , 5. ],
[10. , 5. ],
[ 7.5, 7.5],
[ 5. , 5. ],
[ 7.5, 2.5],
[10. , 5. ]])
z_3b
array([[10. , 5. ],
[15. , 10. ],
[20. , 5. ],
[15. , 0. ],
[10. , 5. ],
[ 7.5, 7.5],
[ 5. , 5. ],
[ 7.5, 2.5],
[10. , 5. ]])
Now the interesting thing is that that sequence yields a 'mobius loop' kind of shape (z_3b) since the common point (10, 5) is duplicated, for both parts, but removed by the second rule. This might account for the seemingly hole outside, just being a continuation of the outer ring, closing back in on itself on line 57
I created 2 versions of the above sequence of points. One a singlepart featureclass and the other a multipart featureclass by using Dissolve. I then converted both versions out to arrays, using FeatureClassToNumPyArray.
Both contain the same points but the order of the ring inclusion is altered. Note that the duplicate [10, 5] in the middle two points of the shape are NOT removed. They shouldn't be sinceone is needed to close the first ring and the other to start the second ring.
This raises two questions
- Shouldn't the "ar1" version fail because its points are completely outside the clockwise ring. It seems that the mere fact that the CCW ring's start and end points are coincident with those of the outer ring. (Clementini vs within)
- Shouldn't the "ar2" version fail because it starts with a CCW ring.
ar1
array([[10. , 5. ],
[15. , 10. ],
[20. , 5. ],
[15. , 0. ],
[10. , 5. ],
[10. , 5. ],
[ 7.5, 2.5],
[ 5. , 5. ],
[ 7.5, 7.5],
[10. , 5. ]])
ar2
array([[10. , 5. ],
[ 7.5, 2.5],
[ 5. , 5. ],
[ 7.5, 7.5],
[10. , 5. ],
[10. , 5. ],
[15. , 10. ],
[20. , 5. ],
[15. , 0. ],
[10. , 5. ]])
Interesting to say the least.