-
Notifications
You must be signed in to change notification settings - Fork 442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Polygonizer.getGeometry() results are non-deterministic when extractOnlyPolygonal=true #1063
Comments
I also encountered problems with non-deterministic behavior in I think the issue is at least partly due to Replacing this with a This is the rather ugly code I used to test for stability with a difficult (random) example. public static void main(String[] args) {
Random rng = new Random(100);
PrecisionModel pm = new PrecisionModel(100.0);
GeometryFactory factory = new GeometryFactory(pm);
// Create an array of n random coordinates
// Note that increasing this to 1000 will result in a TopologyValidationError
int n = 100;
Coordinate[] coords = new Coordinate[n];
for (int i = 0; i < n-1; i++) {
Coordinate c = new Coordinate(rng.nextDouble() * 1000, rng.nextDouble() * 1000);
pm.makePrecise(c);
coords[i] = c;
}
coords[coords.length-1] = coords[0];
// Loop 100 times to check for stability
Geometry lineString = factory.createLineString(coords).union();
Geometry lastGeometry = null;
for (int k = 0; k < 100; k++) {
Polygonizer polygonizer = new Polygonizer(true);
polygonizer.add(lineString);
Geometry polygons = polygonizer.getGeometry();
TopologyValidationError err = new IsValidOp(polygons).getValidationError();
if (err != null) {
System.err.println("Error detection! " + err);
}
if (lastGeometry != null) {
if (!lastGeometry.equalsExact(polygons)) {
throw new TopologyException("Polygonization is not stable");
}
}
assert polygons.isValid();
lastGeometry = polygons;
}
} |
Sometimes requiring stable output from an algorithm can reduce performance. This may or may not be one of those cases - it will require some testing to find out. Is it important to have stable results from the |
Normalising the result does not remove the non-deterministic behaviour. Please check the method testJTSBugs1() in the unit test attached to the initial post. The variation includes the complete inclusion/exclusion of polygons with joined edges, resulting in an invalid geometry. Also a noteworthy and bizarre fact is that calling .isValid() on a completely unrelated geometry affects the subsequent behaviour of Polygonizer. I even recall once that a call to a logging library completely unrelated to JTS affected the subsequent behaviour of Polygonizer. Polygonizer is seriously broken and unusable with the extractOnlyPolygonal option enabled. |
I second @MartinJericho's observation that the behavior changes unpredictably, and this is the case even when provided the exact same normalized input (i.e. the same I do think there is a relationship with hashing, which may explain the observation that even seemingly unrelated calls have an impact. Specifically, Investigating this, I could get deterministic behavior in my case by doing either of the following:
Certainly the first seems preferable to relying on |
I now see that the test case in |
Polygonizer implementation seems to hold some internal state that affects the output of the getGeometry() method when extractOnlyPolygonal=true.
The attached unit test class demonstrates the issue. Because of the nature of this bug, the assertions may fail depending on the initial internal state of the library on the testing machine. But the assertions pass in my test environment.
JTSBugsTest.txt
Doing the following multiple times yields different results:
If the input linework intersects along joint edges, and Polygonizer produces an invalid geometry, the result is different every time, even after normalizing the result.
If the input linework intersects only at points, in which case Polygonizer always produces a valid geometry, the result may be different every time, but seems to be deterministic after normalising.
If the input linework does not intersect, Polygonizer seems to produce the same result every time, even without normalising.
Note that something as simple as calling
new GeometryFactory().createPolygon().isValid()
affects the internal state and changes the result of the next call to Polygonizer.getGeometry(). This probably also indicates the presence of a bug in the Geometry.isValid() method, as you would never expect it to modify the state of anything at all.JTS version 1.19.0
The text was updated successfully, but these errors were encountered: