planetiler/src/test/java/com/onthegomap/flatmap/render/FeatureRendererTest.java

259 wiersze
8.5 KiB
Java
Czysty Zwykły widok Historia

2021-05-20 09:59:18 +00:00
package com.onthegomap.flatmap.render;
2021-05-16 10:42:57 +00:00
import static com.onthegomap.flatmap.TestUtils.assertSameNormalizedFeatures;
import static com.onthegomap.flatmap.TestUtils.emptyGeometry;
2021-05-18 10:53:12 +00:00
import static com.onthegomap.flatmap.TestUtils.newLineString;
2021-05-16 10:42:57 +00:00
import static com.onthegomap.flatmap.TestUtils.newMultiPoint;
import static com.onthegomap.flatmap.TestUtils.newPoint;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
2021-05-20 09:59:18 +00:00
import com.onthegomap.flatmap.CommonParams;
import com.onthegomap.flatmap.FeatureCollector;
2021-05-16 10:42:57 +00:00
import com.onthegomap.flatmap.geo.GeoUtils;
import com.onthegomap.flatmap.geo.TileCoord;
import com.onthegomap.flatmap.read.ReaderFeature;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.locationtech.jts.geom.Geometry;
public class FeatureRendererTest {
private final CommonParams config = CommonParams.defaults();
private FeatureCollector collector(Geometry worldGeom) {
var latLonGeom = GeoUtils.worldToLatLonCoords(worldGeom);
return new FeatureCollector.Factory(config).get(new ReaderFeature(latLonGeom, 0));
}
2021-05-18 10:53:12 +00:00
private Map<TileCoord, Collection<Geometry>> renderGeometry(FeatureCollector.Feature feature) {
2021-05-16 10:42:57 +00:00
Map<TileCoord, Collection<Geometry>> result = new TreeMap<>();
new FeatureRenderer(config, rendered -> result.computeIfAbsent(rendered.tile(), tile -> new HashSet<>())
.add(rendered.vectorTileFeature().geometry().decode())).renderFeature(feature);
return result;
}
2021-05-18 10:53:12 +00:00
private Map<TileCoord, Collection<RenderedFeature>> renderFeatures(FeatureCollector.Feature feature) {
2021-05-16 10:42:57 +00:00
Map<TileCoord, Collection<RenderedFeature>> result = new TreeMap<>();
new FeatureRenderer(config, rendered -> result.computeIfAbsent(rendered.tile(), tile -> new HashSet<>())
.add(rendered)).renderFeature(feature);
return result;
}
private static final int Z14_TILES = 1 << 14;
private static final double Z14_WIDTH = 1d / Z14_TILES;
@Test
public void testEmptyGeometry() {
var feature = collector(emptyGeometry()).point("layer");
assertSameNormalizedFeatures(Map.of(), renderGeometry(feature));
}
@Test
public void testSinglePoint() {
var feature = pointFeature(newPoint(0.5 + Z14_WIDTH / 2, 0.5 + Z14_WIDTH / 2))
.setZoomRange(14, 14);
assertSameNormalizedFeatures(Map.of(
TileCoord.ofXYZ(Z14_TILES / 2, Z14_TILES / 2, 14), List.of(
newPoint(128, 128)
)
), renderGeometry(feature));
}
@Test
public void testRepeatSinglePointNeighboringTiles() {
var feature = pointFeature(newPoint(0.5 + 1d / 512, 0.5 + 1d / 512))
.setZoomRange(0, 1)
.setBufferPixels(2);
assertSameNormalizedFeatures(Map.of(
TileCoord.ofXYZ(0, 0, 0), List.of(newPoint(128.5, 128.5)),
TileCoord.ofXYZ(0, 0, 1), List.of(newPoint(257, 257)),
TileCoord.ofXYZ(1, 0, 1), List.of(newPoint(1, 257)),
TileCoord.ofXYZ(0, 1, 1), List.of(newPoint(257, 1)),
TileCoord.ofXYZ(1, 1, 1), List.of(newPoint(1, 1))
), renderGeometry(feature));
}
@TestFactory
public List<DynamicTest> testProcessPointsNearInternationalDateLineAndPoles() {
double d = 1d / 512;
record X(double x, double wrapped, double z1x0, double z1x1) {
}
record Y(double y, int z1ty, double tyoff) {
}
var xs = List.of(
new X(-d, 1 - d, -1, 255),
new X(d, 1 + d, 1, 257),
new X(1 - d, -d, -1, 255),
new X(1 + d, d, 1, 257)
);
var ys = List.of(
new Y(0.25, 0, 128),
new Y(-d, 0, -1),
new Y(d, 0, 1),
new Y(1 - d, 1, 255),
new Y(1 + d, 1, 257)
);
List<DynamicTest> tests = new ArrayList<>();
for (X x : xs) {
for (Y y : ys) {
tests.add(dynamicTest((x.x * 256) + ", " + (y.y * 256), () -> {
var feature = pointFeature(newPoint(x.x, y.y))
.setZoomRange(0, 1)
.setBufferPixels(2);
assertSameNormalizedFeatures(Map.of(
TileCoord.ofXYZ(0, 0, 0), List.of(newMultiPoint(
newPoint(x.x * 256, y.y * 256),
newPoint(x.wrapped * 256, y.y * 256)
)),
TileCoord.ofXYZ(0, y.z1ty, 1), List.of(newPoint(x.z1x0, y.tyoff)),
TileCoord.ofXYZ(1, y.z1ty, 1), List.of(newPoint(x.z1x1, y.tyoff))
), renderGeometry(feature));
}));
}
}
return tests;
}
@Test
public void testZ0FullTileBuffer() {
var feature = pointFeature(newPoint(0.25, 0.25))
.setZoomRange(0, 1)
.setBufferPixels(256);
assertSameNormalizedFeatures(Map.of(
TileCoord.ofXYZ(0, 0, 0), List.of(newMultiPoint(
newPoint(-192, 64),
newPoint(64, 64),
newPoint(320, 64)
)),
TileCoord.ofXYZ(0, 0, 1), List.of(newPoint(128, 128)),
TileCoord.ofXYZ(1, 0, 1), List.of(newMultiPoint(
newPoint(-128, 128),
newPoint(256 + 128, 128)
)),
TileCoord.ofXYZ(0, 1, 1), List.of(newPoint(128, -128)),
TileCoord.ofXYZ(1, 1, 1), List.of(newMultiPoint(
newPoint(-128, -128),
newPoint(256 + 128, -128)
))
), renderGeometry(feature));
}
@Test
public void testMultipointNoLabelGrid() {
var feature = pointFeature(newMultiPoint(
newPoint(0.25, 0.25),
newPoint(0.25 + 1d / 256, 0.25 + 1d / 256)
))
.setZoomRange(0, 1)
.setBufferPixels(4);
assertSameNormalizedFeatures(Map.of(
TileCoord.ofXYZ(0, 0, 0), List.of(newMultiPoint(
newPoint(64, 64),
newPoint(65, 65)
)),
TileCoord.ofXYZ(0, 0, 1), List.of(newMultiPoint(
newPoint(128, 128),
newPoint(130, 130)
))
), renderGeometry(feature));
}
@Test
public void testMultipointWithLabelGridSplits() {
var feature = pointFeature(newMultiPoint(
newPoint(0.25, 0.25),
newPoint(0.25 + 1d / 256, 0.25 + 1d / 256)
))
.setLabelGridPixelSize(10, 256)
.setZoomRange(0, 1)
.setBufferPixels(4);
assertSameNormalizedFeatures(Map.of(
TileCoord.ofXYZ(0, 0, 0), List.of(
newPoint(64, 64),
newPoint(65, 65)
),
TileCoord.ofXYZ(0, 0, 1), List.of(
newPoint(128, 128),
newPoint(130, 130)
)
), renderGeometry(feature));
}
@Test
public void testLabelGrid() {
var feature = pointFeature(newPoint(0.75, 0.75))
.setLabelGridSizeAndLimit(10, 256, 2)
.setZoomRange(0, 1)
.setBufferPixels(4);
var rendered = renderFeatures(feature);
var z0Feature = rendered.get(TileCoord.ofXYZ(0, 0, 0)).iterator().next();
var z1Feature = rendered.get(TileCoord.ofXYZ(1, 1, 1)).iterator().next();
assertEquals(Optional.of(new RenderedFeature.Group(0, 2)), z0Feature.group());
assertEquals(Optional.of(new RenderedFeature.Group((1L << 32) + 1, 2)), z1Feature.group());
}
@Test
public void testWrapLabelGrid() {
var feature = pointFeature(newPoint(1.1, -0.1))
.setLabelGridSizeAndLimit(10, 256, 2)
.setZoomRange(0, 1)
.setBufferPixels(64);
var rendered = renderFeatures(feature);
var z0Feature = rendered.get(TileCoord.ofXYZ(0, 0, 0)).iterator().next();
var z1Feature = rendered.get(TileCoord.ofXYZ(0, 0, 1)).iterator().next();
assertEquals(Optional.of(new RenderedFeature.Group((1L << 32) - 1, 2)), z0Feature.group());
assertEquals(Optional.of(new RenderedFeature.Group((1L << 32) - 1, 2)), z1Feature.group());
}
2021-05-18 10:53:12 +00:00
private FeatureCollector.Feature pointFeature(Geometry geom) {
2021-05-16 10:42:57 +00:00
return collector(geom).point("layer");
}
2021-05-18 10:53:12 +00:00
private FeatureCollector.Feature lineFeature(Geometry geom) {
return collector(geom).line("layer");
}
@Test
public void testSplitLineFeatureSingleTile() {
double z14hypot = Math.sqrt(Z14_WIDTH * Z14_WIDTH);
var feature = lineFeature(newLineString(
0.5 + z14hypot / 4, 0.5 + z14hypot / 4,
0.5 + z14hypot * 3 / 4, 0.5 + z14hypot * 3 / 4
))
.setZoomRange(14, 14)
.setBufferPixels(8);
assertSameNormalizedFeatures(Map.of(
TileCoord.ofXYZ(Z14_TILES / 2, Z14_TILES / 2, 14), List.of(
newPoint(64, 64),
newPoint(192, 192)
)
), renderGeometry(feature));
}
2021-05-16 10:42:57 +00:00
2021-05-18 10:53:12 +00:00
// TODO: centroid
2021-05-16 10:42:57 +00:00
// TODO: line
// TODO: multilinestring
// TODO: poly
// TODO: multipolygon
// TODO: geometry collection
// sad tests:
// TODO: invalid line
// TODO: invalid poly
// TODO: coerce poly -> line
// TODO: coerce line -> poly
// TODO: wrong types: point/line/poly -> point/line/poly
}