Make fill tiles respect buffer size (#1100)

pull/1106/head
Michael Barry 2024-11-13 07:04:03 -05:00 zatwierdzone przez GitHub
rodzic 6d6cd37d1c
commit e6f1c41006
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
5 zmienionych plików z 39 dodań i 18 usunięć

Wyświetl plik

@ -463,6 +463,24 @@ public class VectorTile {
return result;
}
/**
* Returns the encoded geometry for a polygon that fills an entire tile plus {@code buffer} pixels as a shortcut to
* avoid needing to create an extra JTS geometry for encoding.
*/
public static VectorGeometry encodeFill(double buffer) {
int min = (int) Math.round(EXTENT * buffer / 256d);
int width = EXTENT + min + min;
return new VectorGeometry(new int[]{
CommandEncoder.commandAndLength(Command.MOVE_TO, 1),
zigZagEncode(-min), zigZagEncode(-min),
CommandEncoder.commandAndLength(Command.LINE_TO, 3),
zigZagEncode(width), 0,
0, zigZagEncode(width),
zigZagEncode(-width), 0,
CommandEncoder.commandAndLength(Command.CLOSE_PATH, 1)
}, GeometryType.POLYGON, 0);
}
/**
* Adds features in a layer to this tile.
*

Wyświetl plik

@ -28,7 +28,6 @@ import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.Polygonal;
import org.locationtech.jts.geom.impl.PackedCoordinateSequence;
import org.locationtech.jts.geom.util.AffineTransformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -39,14 +38,6 @@ import org.slf4j.LoggerFactory;
*/
public class FeatureRenderer implements Consumer<FeatureCollector.Feature>, Closeable {
private static final Logger LOGGER = LoggerFactory.getLogger(FeatureRenderer.class);
private static final VectorTile.VectorGeometry FILL = VectorTile.encodeGeometry(GeoUtils.JTS_FACTORY
.createPolygon(GeoUtils.JTS_FACTORY.createLinearRing(new PackedCoordinateSequence.Double(new double[]{
-5, -5,
261, -5,
261, 261,
-5, 261,
-5, -5
}, 2, 0))));
private final PlanetilerConfig config;
private final Consumer<RenderedFeature> consumer;
private final Stats stats;
@ -282,13 +273,13 @@ public class FeatureRenderer implements Consumer<FeatureCollector.Feature>, Clos
// polygons that span multiple tiles contain detail about the outer edges separate from the filled tiles, so emit
// filled tiles now
if (feature.isPolygon()) {
emitted += emitFilledTiles(id, feature, sliced);
emitted += emitFilledTiles(zoom, id, feature, sliced);
}
stats.emittedFeatures(zoom, feature.getLayer(), emitted);
}
private int emitFilledTiles(long id, FeatureCollector.Feature feature, TiledGeometry sliced) {
private int emitFilledTiles(int zoom, long id, FeatureCollector.Feature feature, TiledGeometry sliced) {
Optional<RenderedFeature.Group> groupInfo = Optional.empty();
/*
* Optimization: large input polygons that generate many filled interior tiles (i.e. the ocean), the encoder avoids
@ -298,7 +289,7 @@ public class FeatureRenderer implements Consumer<FeatureCollector.Feature>, Clos
VectorTile.Feature vectorTileFeature = new VectorTile.Feature(
feature.getLayer(),
id,
FILL,
VectorTile.encodeFill(feature.getBufferPixelsAtZoom(zoom)),
feature.getAttrsAtZoom(sliced.zoomLevel())
);

Wyświetl plik

@ -770,7 +770,7 @@ class PlanetilerTests {
), Map.of())
)),
newTileEntry(Z14_TILES / 2 + 2, Z14_TILES / 2 + 1, 14, List.of(
feature(newPolygon(tileFill(5), List.of()), Map.of())
feature(newPolygon(tileFill(4), List.of()), Map.of())
)),
newTileEntry(Z14_TILES / 2 + 3, Z14_TILES / 2 + 1, 14, List.of(
feature(tileLeft(4), Map.of())
@ -814,7 +814,7 @@ class PlanetilerTests {
);
assertEquals(List.of(
feature(newPolygon(tileFill(5)), Map.of())
feature(newPolygon(tileFill(4)), Map.of())
), results.tiles.get(TileCoord.ofXYZ(Z15_TILES / 2, Z15_TILES / 2, 15)));
}
@ -832,7 +832,7 @@ class PlanetilerTests {
assertEquals(5461, results.tiles.size());
// spot-check one filled tile
assertEquals(List.of(rectangle(-5, 256 + 5).norm()), results.tiles.get(TileCoord.ofXYZ(
assertEquals(List.of(rectangle(-4, 256 + 4).norm()), results.tiles.get(TileCoord.ofXYZ(
Z4_TILES / 2, Z4_TILES / 2, 4
)).stream().map(d -> d.geometry().geom().norm()).toList());
}
@ -2449,7 +2449,7 @@ class PlanetilerTests {
),
(in, features) -> features.polygon("layer")
.setZoomRange(0, 2)
.setBufferPixels(0)
.setBufferPixels(1)
);
}

Wyświetl plik

@ -692,6 +692,18 @@ class VectorTileTest {
}
}
@ParameterizedTest
@CsvSource({
"0, 0, 256",
"1, -1, 257",
"10, -10, 266",
})
void testFill(double buffer, double min, double max) throws GeometryException {
var geom = VectorTile.encodeFill(buffer);
assertSameGeometry(rectangle(min, max), geom.decode());
assertArrayEquals(VectorTile.encodeGeometry(rectangle(min, max)).commands(), geom.commands());
}
private static void assertArrayEquals(int[] a, int[] b) {
assertEquals(
IntStream.of(a).boxed().toList(),

Wyświetl plik

@ -814,7 +814,7 @@ class FeatureRendererTest {
tileRight(1)
),
TileCoord.ofXYZ(Z14_TILES / 2, Z14_TILES / 2, 14), List.of(
newPolygon(tileFill(5), List.of()) // <<<<---- the filled tile!
newPolygon(tileFill(1), List.of()) // <<<<---- the filled tile!
),
TileCoord.ofXYZ(Z14_TILES / 2 + 1, Z14_TILES / 2, 14), List.of(
tileLeft(1)
@ -1173,7 +1173,7 @@ class FeatureRendererTest {
var rendered = renderGeometry(feature);
var innerTile = rendered.get(TileCoord.ofXYZ(Z14_TILES / 2, Z14_TILES / 2, 14));
assertEquals(1, innerTile.size());
assertEquals(new TestUtils.NormGeometry(rectangle(-5, 256 + 5)),
assertEquals(new TestUtils.NormGeometry(rectangle(-1, 256 + 1)),
new TestUtils.NormGeometry(innerTile.iterator().next()));
}