Fix buffer union unbuffer exceptions (#713)

pull/717/head
Michael Barry 2023-11-07 07:28:00 -05:00 zatwierdzone przez GitHub
rodzic 65935461e3
commit 517851435d
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 36 dodań i 6 usunięć

Wyświetl plik

@ -29,6 +29,7 @@ import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.Polygonal;
import org.locationtech.jts.geom.TopologyException;
import org.locationtech.jts.geom.util.GeometryFixer;
import org.locationtech.jts.index.strtree.STRtree;
import org.locationtech.jts.operation.buffer.BufferOp;
import org.locationtech.jts.operation.buffer.BufferParameters;
@ -323,7 +324,7 @@ public class FeatureMerge {
// spinning for a very long time on very dense tiles.
// TODO use some heuristic to choose bufferUnbuffer vs. bufferUnionUnbuffer based on the number small
// polygons in the group?
merged = bufferUnionUnbuffer(buffer, polygonGroup);
merged = bufferUnionUnbuffer(buffer, polygonGroup, stats);
} else {
merged = buffer(buffer, GeoUtils.createGeometryCollection(polygonGroup));
}
@ -411,7 +412,7 @@ public class FeatureMerge {
* Merges nearby polygons by expanding each individual polygon by {@code buffer}, unioning them, and contracting the
* result.
*/
private static Geometry bufferUnionUnbuffer(double buffer, List<Geometry> polygonGroup) throws GeometryException {
static Geometry bufferUnionUnbuffer(double buffer, List<Geometry> polygonGroup, Stats stats) {
/*
* A simpler alternative that might initially appear faster would be:
*
@ -433,10 +434,11 @@ public class FeatureMerge {
try {
merged = union(merged);
} catch (TopologyException e) {
throw new GeometryException("buffer_union_failure", "Error unioning buffered polygons", e)
.addGeometryDetails("original", GeoUtils.createGeometryCollection(polygonGroup))
.addDetails(() -> "buffer: " + buffer)
.addGeometryDetails("buffered", GeoUtils.createGeometryCollection(buffered));
// buffer result is sometimes invalid, which makes union throw so fix
// it and try again (see #700)
stats.dataError("buffer_union_unbuffer_union_failed");
merged = GeometryFixer.fix(merged);
merged = union(merged);
}
merged = unbuffer(buffer, merged);
return merged;

Wyświetl plik

@ -10,7 +10,9 @@ import com.onthegomap.planetiler.collection.Hppc;
import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.geo.GeometryType;
import com.onthegomap.planetiler.mbtiles.Mbtiles;
import com.onthegomap.planetiler.stats.Stats;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -20,11 +22,14 @@ import java.util.function.UnaryOperator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -853,4 +858,27 @@ class FeatureMergeTest {
)
);
}
@ParameterizedTest
@ValueSource(strings = {
"/issue_700/exception_1.wkb",
"/issue_700/exception_2.wkb",
"/issue_700/exception_3.wkb",
"/issue_700/exception_4.wkb",
"/issue_700/exception_5.wkb",
"/issue_700/exception_6.wkb",
"/issue_700/exception_7.wkb",
"/issue_700/exception_8.wkb",
"/issue_700/exception_9.wkb",
})
void testIssue700BufferUnionUnbufferFailure(String path) throws IOException, ParseException {
try (var is = getClass().getResource(path).openStream()) {
GeometryCollection collection = (GeometryCollection) new WKBReader().read(is.readAllBytes());
List<Geometry> geometries = new ArrayList<>();
for (int i = 0; i < collection.getNumGeometries(); i++) {
geometries.add(collection.getGeometryN(i));
}
FeatureMerge.bufferUnionUnbuffer(0.5, geometries, Stats.inMemory());
}
}
}

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.