mirror of
https://github.com/cfpwastaken/planetiler-openmaptiles.git
synced 2026-02-05 04:51:10 +00:00
Change name to Planetiler (#40)
* change name from flatmap to planetiler * bump version to 0.2-SNAPSHOT
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package com.onthegomap.planetiler.basemap;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.onthegomap.planetiler.config.PlanetilerConfig;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import com.onthegomap.planetiler.stats.Stats;
|
||||
import com.onthegomap.planetiler.util.Translations;
|
||||
import com.onthegomap.planetiler.util.Wikidata;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BasemapProfileTest {
|
||||
|
||||
private final Wikidata.WikidataTranslations wikidataTranslations = new Wikidata.WikidataTranslations();
|
||||
private final Translations translations = Translations.defaultProvider(List.of("en", "es", "de"))
|
||||
.addTranslationProvider(wikidataTranslations);
|
||||
private final BasemapProfile profile = new BasemapProfile(translations, PlanetilerConfig.defaults(),
|
||||
Stats.inMemory());
|
||||
|
||||
@Test
|
||||
public void testCaresAboutWikidata() {
|
||||
var node = new OsmElement.Node(1, 1, 1);
|
||||
node.setTag("aeroway", "gate");
|
||||
assertTrue(profile.caresAboutWikidataTranslation(node));
|
||||
|
||||
node.setTag("aeroway", "other");
|
||||
assertFalse(profile.caresAboutWikidataTranslation(node));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesntCareAboutWikidataForRoads() {
|
||||
var way = new OsmElement.Way(1);
|
||||
way.setTag("highway", "footway");
|
||||
assertFalse(profile.caresAboutWikidataTranslation(way));
|
||||
}
|
||||
}
|
||||
225
src/test/java/com/onthegomap/planetiler/basemap/BasemapTest.java
Normal file
225
src/test/java/com/onthegomap/planetiler/basemap/BasemapTest.java
Normal file
@@ -0,0 +1,225 @@
|
||||
package com.onthegomap.planetiler.basemap;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.assertContains;
|
||||
import static com.onthegomap.planetiler.TestUtils.assertFeatureNear;
|
||||
import static com.onthegomap.planetiler.basemap.util.VerifyMonaco.MONACO_BOUNDS;
|
||||
import static com.onthegomap.planetiler.util.Gzip.gunzip;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||
|
||||
import com.onthegomap.planetiler.TestUtils;
|
||||
import com.onthegomap.planetiler.VectorTile;
|
||||
import com.onthegomap.planetiler.basemap.util.VerifyMonaco;
|
||||
import com.onthegomap.planetiler.config.Arguments;
|
||||
import com.onthegomap.planetiler.mbtiles.Mbtiles;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.locationtech.jts.geom.Geometry;
|
||||
import org.locationtech.jts.geom.LineString;
|
||||
import org.locationtech.jts.geom.Point;
|
||||
import org.locationtech.jts.geom.Polygon;
|
||||
|
||||
/**
|
||||
* End-to-end tests for basemap generation.
|
||||
* <p>
|
||||
* Generates an entire map for the smallest openstreetmap extract available (Monaco) and asserts that expected output
|
||||
* features exist
|
||||
*/
|
||||
public class BasemapTest {
|
||||
|
||||
@TempDir
|
||||
static Path tmpDir;
|
||||
private static Mbtiles mbtiles;
|
||||
|
||||
@BeforeAll
|
||||
public static void runPlanetiler() throws Exception {
|
||||
Path dbPath = tmpDir.resolve("output.mbtiles");
|
||||
BasemapMain.run(Arguments.of(
|
||||
// Override input source locations
|
||||
"osm_path", TestUtils.pathToResource("monaco-latest.osm.pbf"),
|
||||
"natural_earth_path", TestUtils.pathToResource("natural_earth_vector.sqlite.zip"),
|
||||
"water_polygons_path", TestUtils.pathToResource("water-polygons-split-3857.zip"),
|
||||
// no centerlines in monaco - so fake it out with an empty source
|
||||
"lake_centerlines_path", TestUtils.pathToResource("water-polygons-split-3857.zip"),
|
||||
|
||||
// Override temp dir location
|
||||
"tmp", tmpDir.toString(),
|
||||
|
||||
// Override output location
|
||||
"mbtiles", dbPath.toString()
|
||||
));
|
||||
mbtiles = Mbtiles.newReadOnlyDatabase(dbPath);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void close() throws IOException {
|
||||
mbtiles.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetadata() {
|
||||
Map<String, String> metadata = mbtiles.metadata().getAll();
|
||||
assertEquals("OpenMapTiles", metadata.get("name"));
|
||||
assertEquals("0", metadata.get("minzoom"));
|
||||
assertEquals("14", metadata.get("maxzoom"));
|
||||
assertEquals("baselayer", metadata.get("type"));
|
||||
assertEquals("pbf", metadata.get("format"));
|
||||
assertEquals("7.40921,43.72335,7.44864,43.75169", metadata.get("bounds"));
|
||||
assertEquals("7.42892,43.73752,14", metadata.get("center"));
|
||||
assertContains("openmaptiles.org", metadata.get("description"));
|
||||
assertContains("openmaptiles.org", metadata.get("attribution"));
|
||||
assertContains("www.openstreetmap.org/copyright", metadata.get("attribution"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureValidGeometries() throws Exception {
|
||||
Set<Mbtiles.TileEntry> parsedTiles = TestUtils.getAllTiles(mbtiles);
|
||||
for (var tileEntry : parsedTiles) {
|
||||
var decoded = VectorTile.decode(gunzip(tileEntry.bytes()));
|
||||
for (VectorTile.Feature feature : decoded) {
|
||||
TestUtils.validateGeometry(feature.geometry().decode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsOceanPolyons() {
|
||||
assertFeatureNear(mbtiles, "water", Map.of(
|
||||
"class", "ocean"
|
||||
), 7.4484, 43.70783, 0, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsCountryName() {
|
||||
assertFeatureNear(mbtiles, "place", Map.of(
|
||||
"class", "country",
|
||||
"iso_a2", "MC",
|
||||
"name", "Monaco"
|
||||
), 7.42769, 43.73235, 2, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsSuburb() {
|
||||
assertFeatureNear(mbtiles, "place", Map.of(
|
||||
"name", "Les Moneghetti",
|
||||
"class", "suburb"
|
||||
), 7.41746, 43.73638, 11, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsBuildings() {
|
||||
assertFeatureNear(mbtiles, "building", Map.of(), 7.41919, 43.73401, 13, 14);
|
||||
assertNumFeatures("building", Map.of(), 14, 1316, Polygon.class);
|
||||
assertNumFeatures("building", Map.of(), 13, 196, Polygon.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsHousenumber() {
|
||||
assertFeatureNear(mbtiles, "housenumber", Map.of(
|
||||
"housenumber", "27"
|
||||
), 7.42117, 43.73652, 14, 14);
|
||||
assertNumFeatures("housenumber", Map.of(), 14, 274, Point.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBoundary() {
|
||||
assertFeatureNear(mbtiles, "boundary", Map.of(
|
||||
"admin_level", 2L,
|
||||
"maritime", 1L,
|
||||
"disputed", 0L
|
||||
), 7.41884, 43.72396, 4, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAeroway() {
|
||||
assertNumFeatures("aeroway", Map.of(
|
||||
"class", "heliport"
|
||||
), 14, 1, Polygon.class);
|
||||
assertNumFeatures("aeroway", Map.of(
|
||||
"class", "helipad"
|
||||
), 14, 11, Polygon.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLandcover() {
|
||||
assertNumFeatures("landcover", Map.of(
|
||||
"class", "grass",
|
||||
"subclass", "park"
|
||||
), 14, 20, Polygon.class);
|
||||
assertNumFeatures("landcover", Map.of(
|
||||
"class", "grass",
|
||||
"subclass", "garden"
|
||||
), 14, 33, Polygon.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPoi() {
|
||||
assertNumFeatures("poi", Map.of(
|
||||
"class", "restaurant",
|
||||
"subclass", "restaurant"
|
||||
), 14, 217, Point.class);
|
||||
assertNumFeatures("poi", Map.of(
|
||||
"class", "art_gallery",
|
||||
"subclass", "artwork"
|
||||
), 14, 132, Point.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLanduse() {
|
||||
assertNumFeatures("landuse", Map.of(
|
||||
"class", "residential"
|
||||
), 14, 8, Polygon.class);
|
||||
assertNumFeatures("landuse", Map.of(
|
||||
"class", "hospital"
|
||||
), 14, 4, Polygon.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransportation() {
|
||||
assertNumFeatures("transportation", Map.of(
|
||||
"class", "path",
|
||||
"subclass", "footway"
|
||||
), 14, 909, LineString.class);
|
||||
assertNumFeatures("transportation", Map.of(
|
||||
"class", "primary"
|
||||
), 14, 170, LineString.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransportationName() {
|
||||
assertNumFeatures("transportation_name", Map.of(
|
||||
"name", "Boulevard du Larvotto",
|
||||
"class", "primary"
|
||||
), 14, 12, LineString.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWaterway() {
|
||||
assertNumFeatures("waterway", Map.of(
|
||||
"class", "stream"
|
||||
), 14, 6, LineString.class);
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
public Stream<DynamicTest> testVerifyChecks() {
|
||||
return VerifyMonaco.verify(mbtiles).results().stream()
|
||||
.map(check -> dynamicTest(check.name(), () -> {
|
||||
check.error().ifPresent(Assertions::fail);
|
||||
}));
|
||||
}
|
||||
|
||||
private static void assertNumFeatures(String layer, Map<String, Object> attrs, int zoom,
|
||||
int expected, Class<? extends Geometry> clazz) {
|
||||
TestUtils.assertNumFeatures(mbtiles, layer, zoom, attrs, MONACO_BOUNDS, expected, clazz);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package com.onthegomap.planetiler.basemap;
|
||||
|
||||
import static com.onthegomap.planetiler.basemap.Generate.parseYaml;
|
||||
import static com.onthegomap.planetiler.expression.Expression.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.onthegomap.planetiler.expression.Expression;
|
||||
import com.onthegomap.planetiler.expression.MultiExpression;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
|
||||
public class GenerateTest {
|
||||
|
||||
@Test
|
||||
public void testParseSimple() {
|
||||
MultiExpression<String> parsed = Generate.generateFieldMapping(parseYaml("""
|
||||
output:
|
||||
key: value
|
||||
key2:
|
||||
- value2
|
||||
- '%value3%'
|
||||
"""));
|
||||
assertEquals(MultiExpression.of(List.of(
|
||||
MultiExpression.entry("output", or(
|
||||
matchAny("key", "value"),
|
||||
matchAny("key2", "value2", "%value3%")
|
||||
))
|
||||
)), parsed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseAnd() {
|
||||
MultiExpression<String> parsed = Generate.generateFieldMapping(parseYaml("""
|
||||
output:
|
||||
__AND__:
|
||||
key1: val1
|
||||
key2: val2
|
||||
"""));
|
||||
assertEquals(MultiExpression.of(List.of(
|
||||
MultiExpression.entry("output", and(
|
||||
matchAny("key1", "val1"),
|
||||
matchAny("key2", "val2")
|
||||
))
|
||||
)), parsed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseAndWithOthers() {
|
||||
MultiExpression<String> parsed = Generate.generateFieldMapping(parseYaml("""
|
||||
output:
|
||||
- key0: val0
|
||||
- __AND__:
|
||||
key1: val1
|
||||
key2: val2
|
||||
"""));
|
||||
assertEquals(MultiExpression.of(List.of(
|
||||
MultiExpression.entry("output", or(
|
||||
matchAny("key0", "val0"),
|
||||
and(
|
||||
matchAny("key1", "val1"),
|
||||
matchAny("key2", "val2")
|
||||
)
|
||||
))
|
||||
)), parsed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseAndContainingOthers() {
|
||||
MultiExpression<String> parsed = Generate.generateFieldMapping(parseYaml("""
|
||||
output:
|
||||
__AND__:
|
||||
- key1: val1
|
||||
- __OR__:
|
||||
key2: val2
|
||||
key3: val3
|
||||
"""));
|
||||
assertEquals(MultiExpression.of(List.of(
|
||||
MultiExpression.entry("output", and(
|
||||
matchAny("key1", "val1"),
|
||||
or(
|
||||
matchAny("key2", "val2"),
|
||||
matchAny("key3", "val3")
|
||||
)
|
||||
))
|
||||
)), parsed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseContainsKey() {
|
||||
MultiExpression<String> parsed = Generate.generateFieldMapping(parseYaml("""
|
||||
output:
|
||||
key1: val1
|
||||
key2:
|
||||
"""));
|
||||
assertEquals(MultiExpression.of(List.of(
|
||||
MultiExpression.entry("output", or(
|
||||
matchAny("key1", "val1"),
|
||||
matchField("key2")
|
||||
))
|
||||
)), parsed);
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
public Stream<DynamicTest> testParseImposm3Mapping() {
|
||||
record TestCase(String name, String mapping, String require, String reject, Expression expected) {
|
||||
|
||||
TestCase(String mapping, Expression expected) {
|
||||
this(mapping, mapping, null, null, expected);
|
||||
}
|
||||
}
|
||||
return Stream.of(
|
||||
new TestCase(
|
||||
"key: val", matchAny("key", "val")
|
||||
),
|
||||
new TestCase(
|
||||
"key: [val1, val2]", matchAny("key", "val1", "val2")
|
||||
),
|
||||
new TestCase(
|
||||
"key: [\"__any__\"]", matchField("key")
|
||||
),
|
||||
new TestCase("reject",
|
||||
"key: val",
|
||||
"mustkey: mustval",
|
||||
null,
|
||||
and(
|
||||
matchAny("key", "val"),
|
||||
matchAny("mustkey", "mustval")
|
||||
)
|
||||
),
|
||||
new TestCase("require",
|
||||
"key: val",
|
||||
null,
|
||||
"badkey: badval",
|
||||
and(
|
||||
matchAny("key", "val"),
|
||||
not(matchAny("badkey", "badval"))
|
||||
)
|
||||
),
|
||||
new TestCase("require and reject complex",
|
||||
"""
|
||||
key: val
|
||||
key2:
|
||||
- val1
|
||||
- val2
|
||||
""",
|
||||
"""
|
||||
mustkey: mustval
|
||||
mustkey2:
|
||||
- mustval1
|
||||
- mustval2
|
||||
""",
|
||||
"""
|
||||
notkey: notval
|
||||
notkey2:
|
||||
- notval1
|
||||
- notval2
|
||||
""",
|
||||
and(
|
||||
or(
|
||||
matchAny("key", "val"),
|
||||
matchAny("key2", "val1", "val2")
|
||||
),
|
||||
matchAny("mustkey", "mustval"),
|
||||
matchAny("mustkey2", "mustval1", "mustval2"),
|
||||
not(matchAny("notkey", "notval")),
|
||||
not(matchAny("notkey2", "notval1", "notval2"))
|
||||
)
|
||||
)
|
||||
).map(test -> dynamicTest(test.name, () -> {
|
||||
Expression parsed = Generate
|
||||
.parseImposm3MappingExpression("point", parseYaml(test.mapping), new Generate.Imposm3Filters(
|
||||
parseYaml(test.reject),
|
||||
parseYaml(test.require)
|
||||
));
|
||||
assertEquals(test.expected, parsed.replace(matchType("point"), TRUE).simplify());
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeMappingTopLevelType() {
|
||||
Expression parsed = Generate
|
||||
.parseImposm3MappingExpression("point", parseYaml("""
|
||||
key: val
|
||||
"""), new Generate.Imposm3Filters(null, null));
|
||||
assertEquals(and(
|
||||
matchAny("key", "val"),
|
||||
matchType("point")
|
||||
), parsed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeMappings() {
|
||||
Map<String, JsonNode> props = new LinkedHashMap<>();
|
||||
props.put("points", parseYaml("""
|
||||
key: val
|
||||
"""));
|
||||
props.put("polygons", parseYaml("""
|
||||
key2: val2
|
||||
"""));
|
||||
Expression parsed = Generate
|
||||
.parseImposm3MappingExpression(new Generate.Imposm3Table(
|
||||
"geometry",
|
||||
false,
|
||||
List.of(),
|
||||
null,
|
||||
null,
|
||||
props
|
||||
));
|
||||
assertEquals(or(
|
||||
and(
|
||||
matchAny("key", "val"),
|
||||
matchType("point")
|
||||
),
|
||||
and(
|
||||
matchAny("key2", "val2"),
|
||||
matchType("polygon")
|
||||
)
|
||||
), parsed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.assertSubmap;
|
||||
import static com.onthegomap.planetiler.TestUtils.newLineString;
|
||||
import static com.onthegomap.planetiler.TestUtils.newPoint;
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.OSM_SOURCE;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.onthegomap.planetiler.FeatureCollector;
|
||||
import com.onthegomap.planetiler.TestUtils;
|
||||
import com.onthegomap.planetiler.VectorTile;
|
||||
import com.onthegomap.planetiler.basemap.BasemapProfile;
|
||||
import com.onthegomap.planetiler.config.PlanetilerConfig;
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import com.onthegomap.planetiler.reader.SourceFeature;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmReader;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
|
||||
import com.onthegomap.planetiler.stats.Stats;
|
||||
import com.onthegomap.planetiler.util.Translations;
|
||||
import com.onthegomap.planetiler.util.Wikidata;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public abstract class AbstractLayerTest {
|
||||
|
||||
final Wikidata.WikidataTranslations wikidataTranslations = new Wikidata.WikidataTranslations();
|
||||
final Translations translations = Translations.defaultProvider(List.of("en", "es", "de"))
|
||||
.addTranslationProvider(wikidataTranslations);
|
||||
|
||||
final PlanetilerConfig params = PlanetilerConfig.defaults();
|
||||
final BasemapProfile profile = new BasemapProfile(translations, PlanetilerConfig.defaults(),
|
||||
Stats.inMemory());
|
||||
final Stats stats = Stats.inMemory();
|
||||
final FeatureCollector.Factory featureCollectorFactory = new FeatureCollector.Factory(params, stats);
|
||||
|
||||
static void assertFeatures(int zoom, List<Map<String, Object>> expected, Iterable<FeatureCollector.Feature> actual) {
|
||||
List<FeatureCollector.Feature> actualList = StreamSupport.stream(actual.spliterator(), false).toList();
|
||||
assertEquals(expected.size(), actualList.size(), () -> "size: " + actualList);
|
||||
for (int i = 0; i < expected.size(); i++) {
|
||||
assertSubmap(expected.get(i), TestUtils.toMap(actualList.get(i), zoom));
|
||||
}
|
||||
}
|
||||
|
||||
static void assertDescending(int... vals) {
|
||||
for (int i = 1; i < vals.length; i++) {
|
||||
if (vals[i - 1] < vals[i]) {
|
||||
fail("element at " + (i - 1) + " is less than element at " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void assertAscending(int... vals) {
|
||||
for (int i = 1; i < vals.length; i++) {
|
||||
if (vals[i - 1] > vals[i]) {
|
||||
fail(
|
||||
Arrays.toString(vals) +
|
||||
System.lineSeparator() + "element at " + (i - 1) + " (" + vals[i - 1] + ") is greater than element at " + i
|
||||
+ " (" + vals[i] + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VectorTile.Feature pointFeature(String layer, Map<String, Object> map, int group) {
|
||||
return new VectorTile.Feature(
|
||||
layer,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newPoint(0, 0)),
|
||||
new HashMap<>(map),
|
||||
group
|
||||
);
|
||||
}
|
||||
|
||||
FeatureCollector process(SourceFeature feature) {
|
||||
var collector = featureCollectorFactory.get(feature);
|
||||
profile.processFeature(feature, collector);
|
||||
return collector;
|
||||
}
|
||||
|
||||
void assertCoversZoomRange(int minzoom, int maxzoom, String layer, FeatureCollector... featureCollectors) {
|
||||
Map<?, ?>[] zooms = new Map[Math.max(15, maxzoom + 1)];
|
||||
for (var features : featureCollectors) {
|
||||
for (var feature : features) {
|
||||
if (feature.getLayer().equals(layer)) {
|
||||
for (int zoom = feature.getMinZoom(); zoom <= feature.getMaxZoom(); zoom++) {
|
||||
Map<String, Object> map = TestUtils.toMap(feature, zoom);
|
||||
if (zooms[zoom] != null) {
|
||||
fail("Multiple features at z" + zoom + ":" + System.lineSeparator() + zooms[zoom] + "\n" + map);
|
||||
}
|
||||
zooms[zoom] = map;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int zoom = 0; zoom <= 14; zoom++) {
|
||||
if (zoom < minzoom || zoom > maxzoom) {
|
||||
if (zooms[zoom] != null) {
|
||||
fail("Expected nothing at z" + zoom + " but found: " + zooms[zoom]);
|
||||
}
|
||||
} else {
|
||||
if (zooms[zoom] == null) {
|
||||
fail("No feature at z" + zoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SourceFeature pointFeature(Map<String, Object> props) {
|
||||
return SimpleFeature.create(
|
||||
newPoint(0, 0),
|
||||
new HashMap<>(props),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
SourceFeature lineFeature(Map<String, Object> props) {
|
||||
return SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
new HashMap<>(props),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
SourceFeature polygonFeatureWithArea(double area, Map<String, Object> props) {
|
||||
return SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(area))),
|
||||
new HashMap<>(props),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
SourceFeature polygonFeature(Map<String, Object> props) {
|
||||
return polygonFeatureWithArea(1, props);
|
||||
}
|
||||
|
||||
|
||||
protected SimpleFeature lineFeatureWithRelation(List<OsmRelationInfo> relationInfos,
|
||||
Map<String, Object> map) {
|
||||
return SimpleFeature.createFakeOsmFeature(
|
||||
newLineString(0, 0, 1, 1),
|
||||
map,
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0,
|
||||
(relationInfos == null ? List.<OsmRelationInfo>of() : relationInfos).stream()
|
||||
.map(r -> new OsmReader.RelationMember<>("", r)).toList()
|
||||
);
|
||||
}
|
||||
|
||||
protected void testMergesLinestrings(Map<String, Object> attrs, String layer,
|
||||
double length, int zoom) throws GeometryException {
|
||||
var line1 = new VectorTile.Feature(
|
||||
layer,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(0, 0, length / 2, 0)),
|
||||
attrs,
|
||||
0
|
||||
);
|
||||
var line2 = new VectorTile.Feature(
|
||||
layer,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(length / 2, 0, length, 0)),
|
||||
attrs,
|
||||
0
|
||||
);
|
||||
var connected = new VectorTile.Feature(
|
||||
layer,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(0, 0, length, 0)),
|
||||
attrs,
|
||||
0
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
List.of(connected),
|
||||
profile.postProcessLayerFeatures(layer, zoom, List.of(line1, line2))
|
||||
);
|
||||
}
|
||||
|
||||
protected void testDoesNotMergeLinestrings(Map<String, Object> attrs, String layer,
|
||||
double length, int zoom) throws GeometryException {
|
||||
var line1 = new VectorTile.Feature(
|
||||
layer,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(0, 0, length / 2, 0)),
|
||||
attrs,
|
||||
0
|
||||
);
|
||||
var line2 = new VectorTile.Feature(
|
||||
layer,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(length / 2, 0, length, 0)),
|
||||
attrs,
|
||||
0
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
List.of(line1, line2),
|
||||
profile.postProcessLayerFeatures(layer, zoom, List.of(line1, line2))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AerodromeLabelTest extends AbstractLayerTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setupWikidataTranslation() {
|
||||
wikidataTranslations.put(123, "es", "es wd name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHappyPathPoint() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "international",
|
||||
"ele", 100,
|
||||
"ele_ft", 328,
|
||||
"name", "osm name",
|
||||
"name:es", "es wd name",
|
||||
|
||||
"_layer", "aerodrome_label",
|
||||
"_type", "point",
|
||||
"_minzoom", 10,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 64d
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"name", "osm name",
|
||||
"wikidata", "Q123",
|
||||
"ele", "100",
|
||||
"aerodrome", "international",
|
||||
"iata", "123",
|
||||
"icao", "1234"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternational() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "international",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"aerodrome_type", "international"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublic() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "public",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"aerodrome_type", "public airport"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "public",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"aerodrome_type", "civil"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMilitary() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "military",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"aerodrome_type", "military airport"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "military",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"military", "airfield"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivate() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "private",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"aerodrome_type", "private"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "private",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome",
|
||||
"aerodrome", "private"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOther() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "other",
|
||||
"_layer", "aerodrome_label"
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "aerodrome"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreNonPoints() {
|
||||
assertFeatures(14, List.of(), process(lineFeature(Map.of(
|
||||
"aeroway", "aerodrome"
|
||||
))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AerowayTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void aerowayGate() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "gate",
|
||||
"ref", "123",
|
||||
|
||||
"_layer", "aeroway",
|
||||
"_type", "point",
|
||||
"_minzoom", 14,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 4d
|
||||
)), process(pointFeature(Map.of(
|
||||
"aeroway", "gate",
|
||||
"ref", "123"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(lineFeature(Map.of(
|
||||
"aeroway", "gate"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(polygonFeature(Map.of(
|
||||
"aeroway", "gate"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aerowayLine() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "runway",
|
||||
"ref", "123",
|
||||
|
||||
"_layer", "aeroway",
|
||||
"_type", "line",
|
||||
"_minzoom", 10,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 4d
|
||||
)), process(lineFeature(Map.of(
|
||||
"aeroway", "runway",
|
||||
"ref", "123"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(pointFeature(Map.of(
|
||||
"aeroway", "runway"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aerowayPolygon() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "runway",
|
||||
"ref", "123",
|
||||
|
||||
"_layer", "aeroway",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 10,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 4d
|
||||
)), process(polygonFeature(Map.of(
|
||||
"aeroway", "runway",
|
||||
"ref", "123"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "runway",
|
||||
"ref", "123",
|
||||
"_layer", "aeroway",
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"area:aeroway", "runway",
|
||||
"ref", "123"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "heliport",
|
||||
"ref", "123",
|
||||
"_layer", "aeroway",
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"aeroway", "heliport",
|
||||
"ref", "123"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(lineFeature(Map.of(
|
||||
"aeroway", "heliport"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(pointFeature(Map.of(
|
||||
"aeroway", "heliport"
|
||||
))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,622 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.newLineString;
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.OSM_SOURCE;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import com.onthegomap.planetiler.FeatureCollector;
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BoundaryTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testNaturalEarthCountryBoundaries() {
|
||||
assertCoversZoomRange(
|
||||
0, 4, "boundary",
|
||||
process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_admin_0_boundary_lines_land",
|
||||
0
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_admin_0_boundary_lines_land",
|
||||
1
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_0_boundary_lines_land",
|
||||
2
|
||||
))
|
||||
);
|
||||
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"disputed", 0,
|
||||
"maritime", 0,
|
||||
"admin_level", 2,
|
||||
|
||||
"_minzoom", 0,
|
||||
"_buffer", 4d
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "International boundary (verify)"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_admin_0_boundary_lines_land",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"disputed", 1,
|
||||
"maritime", 0,
|
||||
"admin_level", 2,
|
||||
"_buffer", 4d
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "Disputed (please verify)"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_admin_0_boundary_lines_land",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"admin_level", 2
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "International boundary (verify)"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_admin_0_boundary_lines_land",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"admin_level", 2
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "International boundary (verify)"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_0_boundary_lines_land",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(0, List.of(), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "Lease Limit"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_0_boundary_lines_land",
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalEarthStateBoundaries() {
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"disputed", 0,
|
||||
"maritime", 0,
|
||||
"admin_level", 4,
|
||||
|
||||
"_minzoom", 1,
|
||||
"_maxzoom", 4,
|
||||
"_buffer", 4d
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"min_zoom", 7d
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_1_states_provinces_lines",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(0, List.of(), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"min_zoom", 7.1d
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_1_states_provinces_lines",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(0, List.of(), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_1_states_provinces_lines",
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergesDisconnectedLineFeatures() throws GeometryException {
|
||||
testMergesLinestrings(Map.of("admin_level", 2), Boundary.LAYER_NAME, 10, 13);
|
||||
testMergesLinestrings(Map.of("admin_level", 2), Boundary.LAYER_NAME, 10, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmTownBoundary() {
|
||||
var relation = new OsmElement.Relation(1);
|
||||
relation.setTag("type", "boundary");
|
||||
relation.setTag("admin_level", "10");
|
||||
relation.setTag("boundary", "administrative");
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"disputed", 0,
|
||||
"maritime", 0,
|
||||
"admin_level", 10,
|
||||
|
||||
"_minzoom", 12,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 4d,
|
||||
"_minpixelsize", 0d
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation),
|
||||
Map.of())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmBoundaryLevelTwoAndAHalf() {
|
||||
var relation = new OsmElement.Relation(1);
|
||||
relation.setTag("type", "boundary");
|
||||
relation.setTag("admin_level", "2.5");
|
||||
relation.setTag("boundary", "administrative");
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"disputed", 0,
|
||||
"maritime", 0,
|
||||
"admin_level", 3,
|
||||
|
||||
"_minzoom", 5,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 4d,
|
||||
"_minpixelsize", 0d
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation),
|
||||
Map.of())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmBoundaryTakesMinAdminLevel() {
|
||||
var relation1 = new OsmElement.Relation(1);
|
||||
relation1.setTag("type", "boundary");
|
||||
relation1.setTag("admin_level", "10");
|
||||
relation1.setTag("name", "Town");
|
||||
relation1.setTag("boundary", "administrative");
|
||||
var relation2 = new OsmElement.Relation(2);
|
||||
relation2.setTag("type", "boundary");
|
||||
relation2.setTag("admin_level", "4");
|
||||
relation2.setTag("name", "State");
|
||||
relation2.setTag("boundary", "administrative");
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"disputed", 0,
|
||||
"maritime", 0,
|
||||
"admin_level", 4
|
||||
)), process(lineFeatureWithRelation(
|
||||
Stream.concat(
|
||||
profile.preprocessOsmRelation(relation2).stream(),
|
||||
profile.preprocessOsmRelation(relation1).stream()
|
||||
).toList(),
|
||||
Map.of())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmBoundarySetsMaritimeFromWay() {
|
||||
var relation1 = new OsmElement.Relation(1);
|
||||
relation1.setTag("type", "boundary");
|
||||
relation1.setTag("admin_level", "10");
|
||||
relation1.setTag("boundary", "administrative");
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"maritime", 1
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation1),
|
||||
Map.of(
|
||||
"maritime", "yes"
|
||||
))
|
||||
));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"maritime", 1
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation1),
|
||||
Map.of(
|
||||
"natural", "coastline"
|
||||
))
|
||||
));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"maritime", 1
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation1),
|
||||
Map.of(
|
||||
"boundary_type", "maritime"
|
||||
))
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoresProtectedAreas() {
|
||||
var relation1 = new OsmElement.Relation(1);
|
||||
relation1.setTag("type", "boundary");
|
||||
relation1.setTag("admin_level", "10");
|
||||
relation1.setTag("boundary", "protected_area");
|
||||
|
||||
assertNull(profile.preprocessOsmRelation(relation1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoresProtectedAdminLevelOver10() {
|
||||
var relation1 = new OsmElement.Relation(1);
|
||||
relation1.setTag("type", "boundary");
|
||||
relation1.setTag("admin_level", "11");
|
||||
relation1.setTag("boundary", "administrative");
|
||||
|
||||
assertNull(profile.preprocessOsmRelation(relation1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmBoundaryDisputed() {
|
||||
var relation = new OsmElement.Relation(1);
|
||||
relation.setTag("type", "boundary");
|
||||
relation.setTag("admin_level", "5");
|
||||
relation.setTag("boundary", "administrative");
|
||||
relation.setTag("disputed", "yes");
|
||||
relation.setTag("name", "Border A - B");
|
||||
relation.setTag("claimed_by", "A");
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
"disputed_name", "BorderA-B",
|
||||
"claimed_by", "A",
|
||||
|
||||
"disputed", 1,
|
||||
"maritime", 0,
|
||||
"admin_level", 5
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation),
|
||||
Map.of())
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmBoundaryDisputedFromWay() {
|
||||
var relation = new OsmElement.Relation(1);
|
||||
relation.setTag("type", "boundary");
|
||||
relation.setTag("admin_level", "5");
|
||||
relation.setTag("boundary", "administrative");
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
|
||||
"disputed", 1,
|
||||
"maritime", 0,
|
||||
"admin_level", 5
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation),
|
||||
Map.of(
|
||||
"disputed", "yes"
|
||||
))
|
||||
));
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
|
||||
"disputed", 1,
|
||||
"maritime", 0,
|
||||
"admin_level", 5,
|
||||
"claimed_by", "A",
|
||||
"disputed_name", "AB"
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation),
|
||||
Map.of(
|
||||
"disputed", "yes",
|
||||
"claimed_by", "A",
|
||||
"name", "AB"
|
||||
))
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountryBoundaryEmittedIfNoName() {
|
||||
var relation = new OsmElement.Relation(1);
|
||||
relation.setTag("type", "boundary");
|
||||
relation.setTag("admin_level", "2");
|
||||
relation.setTag("boundary", "administrative");
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "boundary",
|
||||
"_type", "line",
|
||||
|
||||
"disputed", 0,
|
||||
"maritime", 0,
|
||||
"admin_level", 2
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relation),
|
||||
Map.of())
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountryLeftRightName() {
|
||||
var country1 = new OsmElement.Relation(1);
|
||||
country1.setTag("type", "boundary");
|
||||
country1.setTag("admin_level", "2");
|
||||
country1.setTag("boundary", "administrative");
|
||||
country1.setTag("ISO3166-1:alpha3", "C1");
|
||||
var country2 = new OsmElement.Relation(2);
|
||||
country2.setTag("type", "boundary");
|
||||
country2.setTag("admin_level", "2");
|
||||
country2.setTag("boundary", "administrative");
|
||||
country2.setTag("ISO3166-1:alpha3", "C2");
|
||||
|
||||
// shared edge
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
newLineString(0, 0, 0, 10),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
3,
|
||||
Stream.concat(
|
||||
profile.preprocessOsmRelation(country1).stream(),
|
||||
profile.preprocessOsmRelation(country2).stream()
|
||||
).map(r -> new OsmReader.RelationMember<>("", r)).toList()
|
||||
)
|
||||
));
|
||||
|
||||
// other 2 edges of country 1
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
newLineString(0, 0, 5, 10),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
4,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)
|
||||
));
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
newLineString(0, 10, 5, 10),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
4,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)
|
||||
));
|
||||
|
||||
// other 2 edges of country 2
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
newLineString(0, 0, -5, 10),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
4,
|
||||
profile.preprocessOsmRelation(country2).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)
|
||||
));
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
newLineString(0, 10, -5, 10),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
4,
|
||||
profile.preprocessOsmRelation(country2).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)
|
||||
));
|
||||
|
||||
List<FeatureCollector.Feature> features = new ArrayList<>();
|
||||
profile.finish(OSM_SOURCE, new FeatureCollector.Factory(params, stats), features::add);
|
||||
assertEquals(3, features.size());
|
||||
|
||||
// ensure shared edge has country labels on right sides
|
||||
var sharedEdge = features.stream()
|
||||
.filter(c -> c.getAttrsAtZoom(0).containsKey("adm0_l") && c.getAttrsAtZoom(0).containsKey("adm0_r")).findFirst()
|
||||
.get();
|
||||
if (sharedEdge.getGeometry().getCoordinate().y == 0.5) { // going up
|
||||
assertEquals("C1", sharedEdge.getAttrsAtZoom(0).get("adm0_r"));
|
||||
assertEquals("C2", sharedEdge.getAttrsAtZoom(0).get("adm0_l"));
|
||||
} else { // going down
|
||||
assertEquals("C2", sharedEdge.getAttrsAtZoom(0).get("adm0_r"));
|
||||
assertEquals("C1", sharedEdge.getAttrsAtZoom(0).get("adm0_l"));
|
||||
}
|
||||
var c1 = features.stream()
|
||||
.filter(c -> c.getGeometry().getEnvelopeInternal().getMaxX() > 0.5).findFirst()
|
||||
.get();
|
||||
if (c1.getGeometry().getCoordinate().y == 0.5) { // going up
|
||||
assertEquals("C1", c1.getAttrsAtZoom(0).get("adm0_l"));
|
||||
} else { // going down
|
||||
assertEquals("C1", c1.getAttrsAtZoom(0).get("adm0_r"));
|
||||
}
|
||||
var c2 = features.stream()
|
||||
.filter(c -> c.getGeometry().getEnvelopeInternal().getMinX() < 0.5).findFirst()
|
||||
.get();
|
||||
if (c2.getGeometry().getCoordinate().y == 0.5) { // going up
|
||||
assertEquals("C2", c2.getAttrsAtZoom(0).get("adm0_r"));
|
||||
} else { // going down
|
||||
assertEquals("C2", c2.getAttrsAtZoom(0).get("adm0_l"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountryBoundaryNotClosed() {
|
||||
var country1 = new OsmElement.Relation(1);
|
||||
country1.setTag("type", "boundary");
|
||||
country1.setTag("admin_level", "2");
|
||||
country1.setTag("boundary", "administrative");
|
||||
country1.setTag("ISO3166-1:alpha3", "C1");
|
||||
|
||||
// shared edge
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
newLineString(0, 0, 0, 10, 5, 5),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
3,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)));
|
||||
|
||||
List<FeatureCollector.Feature> features = new ArrayList<>();
|
||||
profile.finish(OSM_SOURCE, new FeatureCollector.Factory(params, stats), features::add);
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"adm0_r", "<null>",
|
||||
"adm0_l", "<null>",
|
||||
"maritime", 0,
|
||||
"disputed", 0,
|
||||
"admin_level", 2,
|
||||
|
||||
"_layer", "boundary"
|
||||
)), features);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedCountry() throws GeometryException {
|
||||
var country1 = new OsmElement.Relation(1);
|
||||
country1.setTag("type", "boundary");
|
||||
country1.setTag("admin_level", "2");
|
||||
country1.setTag("boundary", "administrative");
|
||||
country1.setTag("ISO3166-1:alpha3", "C1");
|
||||
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
GeoUtils.polygonToLineString(rectangle(0, 10)),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
3,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)));
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
GeoUtils.polygonToLineString(rectangle(1, 9)),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
3,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)));
|
||||
|
||||
List<FeatureCollector.Feature> features = new ArrayList<>();
|
||||
profile.finish(OSM_SOURCE, new FeatureCollector.Factory(params, stats), features::add);
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"adm0_l", "C1",
|
||||
"adm0_r", "<null>"
|
||||
), Map.of(
|
||||
"adm0_r", "C1",
|
||||
"adm0_l", "<null>"
|
||||
)), features);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDontLabelBadPolygon() {
|
||||
var country1 = new OsmElement.Relation(1);
|
||||
country1.setTag("type", "boundary");
|
||||
country1.setTag("admin_level", "2");
|
||||
country1.setTag("boundary", "administrative");
|
||||
country1.setTag("ISO3166-1:alpha3", "C1");
|
||||
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
GeoUtils.worldToLatLonCoords(newLineString(0, 0, 0.1, 0, 0.1, 0.1, 0.02, 0.1, 0.02, -0.02)),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
3,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)));
|
||||
|
||||
List<FeatureCollector.Feature> features = new ArrayList<>();
|
||||
profile.finish(OSM_SOURCE, new FeatureCollector.Factory(params, stats), features::add);
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"adm0_l", "<null>",
|
||||
"adm0_r", "<null>"
|
||||
)), features);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreBadPolygonAndLabelGoodPart() throws GeometryException {
|
||||
var country1 = new OsmElement.Relation(1);
|
||||
country1.setTag("type", "boundary");
|
||||
country1.setTag("admin_level", "2");
|
||||
country1.setTag("boundary", "administrative");
|
||||
country1.setTag("ISO3166-1:alpha3", "C1");
|
||||
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
GeoUtils.worldToLatLonCoords(newLineString(0, 0, 0.1, 0, 0.1, 0.1, 0.2, 0.1, 0.2, -0.2)),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
3,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)));
|
||||
|
||||
assertFeatures(14, List.of(), process(SimpleFeature.createFakeOsmFeature(
|
||||
GeoUtils.worldToLatLonCoords(GeoUtils.polygonToLineString(rectangle(0.2, 0.3))),
|
||||
Map.of(),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
3,
|
||||
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
|
||||
.toList()
|
||||
)));
|
||||
|
||||
List<FeatureCollector.Feature> features = new ArrayList<>();
|
||||
profile.finish(OSM_SOURCE, new FeatureCollector.Factory(params, stats), features::add);
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"adm0_l", "<null>",
|
||||
"adm0_r", "<null>"
|
||||
), Map.of(
|
||||
"adm0_l", "<null>",
|
||||
"adm0_r", "C1"
|
||||
)), features);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.OSM_SOURCE;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.onthegomap.planetiler.VectorTile;
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmReader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BuildingTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testBuilding() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"colour", "<null>",
|
||||
"hide_3d", "<null>",
|
||||
"_layer", "building",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 13,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 4d,
|
||||
"_minpixelsize", 0.1d
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "building",
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building:part", "yes"
|
||||
))));
|
||||
assertFeatures(13, List.of(), process(polygonFeature(Map.of(
|
||||
"building", "no"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAirportBuildings() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "building",
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"aeroway", "terminal"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "building",
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"aeroway", "hangar"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenderHeights() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"render_height", "<null>",
|
||||
"render_min_height", "<null>"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"render_height", 5,
|
||||
"render_min_height", 0
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"render_height", 12,
|
||||
"render_min_height", 3
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes",
|
||||
"building:min_height", "3",
|
||||
"building:height", "12"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"render_height", 44,
|
||||
"render_min_height", 10
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes",
|
||||
"building:min_level", "3",
|
||||
"building:levels", "12"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(polygonFeature(Map.of(
|
||||
"building", "yes",
|
||||
"building:min_level", "1500",
|
||||
"building:levels", "1500"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOutlineHides3d() {
|
||||
var relation = new OsmElement.Relation(1);
|
||||
relation.setTag("type", "building");
|
||||
|
||||
var relationInfos = profile.preprocessOsmRelation(relation).stream()
|
||||
.map(i -> new OsmReader.RelationMember<>("outline", i)).toList();
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "building",
|
||||
"hide_3d", true
|
||||
)), process(SimpleFeature.createFakeOsmFeature(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of(
|
||||
"building", "yes"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0,
|
||||
relationInfos
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergePolygonsZ13() throws GeometryException {
|
||||
var poly1 = new VectorTile.Feature(
|
||||
Building.LAYER_NAME,
|
||||
1,
|
||||
VectorTile.encodeGeometry(rectangle(10, 20)),
|
||||
Map.of(),
|
||||
0
|
||||
);
|
||||
var poly2 = new VectorTile.Feature(
|
||||
Building.LAYER_NAME,
|
||||
1,
|
||||
VectorTile.encodeGeometry(rectangle(20, 10, 22, 20)),
|
||||
Map.of(),
|
||||
0
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
2,
|
||||
profile.postProcessLayerFeatures(Building.LAYER_NAME, 14, List.of(poly1, poly2)).size()
|
||||
);
|
||||
assertEquals(
|
||||
1,
|
||||
profile.postProcessLayerFeatures(Building.LAYER_NAME, 13, List.of(poly1, poly2)).size()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"colour", "#ff0000"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes",
|
||||
"building:colour", "#ff0000",
|
||||
"building:material", "brick"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"colour", "#bd8161"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes",
|
||||
"building:building", "yes",
|
||||
"building:material", "brick"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"colour", "<null>"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"building", "yes",
|
||||
"building:building", "yes",
|
||||
"building:colour", "#ff0000"
|
||||
))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class HousenumberTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testHousenumber() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "housenumber",
|
||||
"_type", "point",
|
||||
"_minzoom", 14,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 8d
|
||||
)), process(pointFeature(Map.of(
|
||||
"addr:housenumber", "10"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_layer", "housenumber",
|
||||
"_type", "point",
|
||||
"_minzoom", 14,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 8d
|
||||
)), process(polygonFeature(Map.of(
|
||||
"addr:housenumber", "10"
|
||||
))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.onthegomap.planetiler.VectorTile;
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class LandcoverTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testNaturalEarthGlaciers() {
|
||||
var glacier1 = process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_glaciated_areas",
|
||||
0
|
||||
));
|
||||
var glacier2 = process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_glaciated_areas",
|
||||
0
|
||||
));
|
||||
var glacier3 = process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_glaciated_areas",
|
||||
0
|
||||
));
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "glacier",
|
||||
"class", "ice",
|
||||
"_buffer", 4d
|
||||
)), glacier1);
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "glacier",
|
||||
"class", "ice",
|
||||
"_buffer", 4d
|
||||
)), glacier2);
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "glacier",
|
||||
"class", "ice",
|
||||
"_buffer", 4d
|
||||
)), glacier3);
|
||||
assertCoversZoomRange(0, 6, "landcover",
|
||||
glacier1,
|
||||
glacier2,
|
||||
glacier3
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalEarthAntarcticIceShelves() {
|
||||
var ice1 = process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_antarctic_ice_shelves_polys",
|
||||
0
|
||||
));
|
||||
var ice2 = process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_antarctic_ice_shelves_polys",
|
||||
0
|
||||
));
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "ice_shelf",
|
||||
"class", "ice",
|
||||
"_buffer", 4d
|
||||
)), ice1);
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "ice_shelf",
|
||||
"class", "ice",
|
||||
"_buffer", 4d
|
||||
)), ice2);
|
||||
assertCoversZoomRange(2, 6, "landcover",
|
||||
ice1,
|
||||
ice2
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmLandcover() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "wood",
|
||||
"class", "wood",
|
||||
"_minpixelsize", 8d,
|
||||
"_numpointsattr", "_numpoints",
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"natural", "wood"
|
||||
))));
|
||||
assertFeatures(12, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "forest",
|
||||
"class", "wood",
|
||||
"_minpixelsize", 8d,
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"landuse", "forest"
|
||||
))));
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "landcover",
|
||||
"subclass", "dune",
|
||||
"class", "sand",
|
||||
"_minpixelsize", 4d,
|
||||
"_minzoom", 7,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"natural", "dune"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeForestsBuNumPointsZ9to13() throws GeometryException {
|
||||
Map<String, Object> map = Map.of("subclass", "wood");
|
||||
|
||||
assertMerges(List.of(map, map, map, map, map, map), List.of(
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 48, "subclass", "wood")),
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 49, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 50, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 299, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 300, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood"))
|
||||
), 14);
|
||||
assertMerges(List.of(map, map, map, map), List.of(
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 48, "subclass", "wood")),
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 49, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 50, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 299, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 300, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood"))
|
||||
), 13);
|
||||
assertMerges(List.of(map, map, map), List.of(
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 48, "subclass", "wood")),
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 49, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 50, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 299, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 300, "subclass", "wood")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood"))
|
||||
), 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeNonForestsBelowZ9() throws GeometryException {
|
||||
Map<String, Object> map = Map.of("subclass", "dune");
|
||||
|
||||
assertMerges(List.of(map, map), List.of(
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 48, "subclass", "dune")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "dune"))
|
||||
), 9);
|
||||
assertMerges(List.of(map), List.of(
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 48, "subclass", "dune")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "dune"))
|
||||
), 8);
|
||||
assertMerges(List.of(map, map), List.of(
|
||||
feature(rectangle(10, 20), Map.of("_numpoints", 48, "subclass", "dune")),
|
||||
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "dune"))
|
||||
), 6);
|
||||
}
|
||||
|
||||
|
||||
private VectorTile.Feature feature(org.locationtech.jts.geom.Polygon geom, Map<String, Object> m) {
|
||||
return new VectorTile.Feature(
|
||||
"landcover",
|
||||
1,
|
||||
VectorTile.encodeGeometry(geom),
|
||||
new HashMap<>(m),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
private void assertMerges(List<Map<String, Object>> expected, List<VectorTile.Feature> in, int zoom)
|
||||
throws GeometryException {
|
||||
assertEquals(expected,
|
||||
profile.postProcessLayerFeatures("landcover", zoom, in).stream().map(
|
||||
VectorTile.Feature::attrs)
|
||||
.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class LanduseTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testNaturalEarthUrbanAreas() {
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "landuse",
|
||||
"class", "residential",
|
||||
"_buffer", 4d
|
||||
)), process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of("scalerank", 1.9),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_urban_areas",
|
||||
0
|
||||
)));
|
||||
assertFeatures(0, List.of(), process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
Map.of("scalerank", 2.1),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_urban_areas",
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmLanduse() {
|
||||
assertFeatures(13, List.of(
|
||||
Map.of("_layer", "poi"),
|
||||
Map.of(
|
||||
"_layer", "landuse",
|
||||
"class", "railway",
|
||||
"_minpixelsize", 4d,
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"landuse", "railway",
|
||||
"amenity", "school"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of("_layer", "poi"), Map.of(
|
||||
"_layer", "landuse",
|
||||
"class", "school",
|
||||
"_minpixelsize", 4d,
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"amenity", "school"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOsmLanduseLowerZoom() {
|
||||
assertFeatures(6, List.of(Map.of(
|
||||
"_layer", "landuse",
|
||||
"class", "suburb",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14,
|
||||
"_minpixelsize", 1d
|
||||
)), process(polygonFeature(Map.of(
|
||||
"place", "suburb"
|
||||
))));
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "landuse",
|
||||
"class", "residential",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14,
|
||||
"_minpixelsize", 2d
|
||||
)), process(polygonFeature(Map.of(
|
||||
"landuse", "residential"
|
||||
))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.newPoint;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.onthegomap.planetiler.VectorTile;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MountainPeakTest extends AbstractLayerTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setupWikidataTranslation() {
|
||||
wikidataTranslations.put(123, "es", "es wd name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHappyPath() {
|
||||
var peak = process(pointFeature(Map.of(
|
||||
"natural", "peak",
|
||||
"name", "test",
|
||||
"ele", "100",
|
||||
"wikidata", "Q123"
|
||||
)));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "peak",
|
||||
"ele", 100,
|
||||
"ele_ft", 328,
|
||||
|
||||
"_layer", "mountain_peak",
|
||||
"_type", "point",
|
||||
"_minzoom", 7,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 100d
|
||||
)), peak);
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"name:latin", "test",
|
||||
"name", "test",
|
||||
"name:es", "es wd name"
|
||||
)), peak);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLabelGrid() {
|
||||
var peak = process(pointFeature(Map.of(
|
||||
"natural", "peak",
|
||||
"ele", "100"
|
||||
)));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"_labelgrid_limit", 0
|
||||
)), peak);
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_labelgrid_limit", 5,
|
||||
"_labelgrid_size", 100d
|
||||
)), peak);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolcano() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "volcano"
|
||||
)), process(pointFeature(Map.of(
|
||||
"natural", "volcano",
|
||||
"ele", "100"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoElevation() {
|
||||
assertFeatures(14, List.of(), process(pointFeature(Map.of(
|
||||
"natural", "volcano"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBogusElevation() {
|
||||
assertFeatures(14, List.of(), process(pointFeature(Map.of(
|
||||
"natural", "volcano",
|
||||
"ele", "11000"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreLines() {
|
||||
assertFeatures(14, List.of(), process(lineFeature(Map.of(
|
||||
"natural", "peak",
|
||||
"name", "name",
|
||||
"ele", "100"
|
||||
))));
|
||||
}
|
||||
|
||||
private int getSortKey(Map<String, Object> tags) {
|
||||
return process(pointFeature(Map.of(
|
||||
"natural", "peak",
|
||||
"ele", "100"
|
||||
))).iterator().next().getSortKey();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortKey() {
|
||||
assertAscending(
|
||||
getSortKey(Map.of(
|
||||
"natural", "peak",
|
||||
"name", "name",
|
||||
"wikipedia", "wikilink",
|
||||
"ele", "100"
|
||||
)),
|
||||
getSortKey(Map.of(
|
||||
"natural", "peak",
|
||||
"name", "name",
|
||||
"ele", "100"
|
||||
)),
|
||||
getSortKey(Map.of(
|
||||
"natural", "peak",
|
||||
"ele", "100"
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMountainPeakPostProcessing() throws GeometryException {
|
||||
assertEquals(List.of(), profile.postProcessLayerFeatures(MountainPeak.LAYER_NAME, 13, List.of()));
|
||||
|
||||
assertEquals(List.of(pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of("rank", 1),
|
||||
1
|
||||
)), profile.postProcessLayerFeatures(MountainPeak.LAYER_NAME, 13, List.of(pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of(),
|
||||
1
|
||||
))));
|
||||
|
||||
assertEquals(List.of(
|
||||
pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of("rank", 1, "name", "a"),
|
||||
1
|
||||
), pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of("rank", 2, "name", "b"),
|
||||
1
|
||||
), pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of("rank", 1, "name", "c"),
|
||||
2
|
||||
)
|
||||
), profile.postProcessLayerFeatures(MountainPeak.LAYER_NAME, 13, List.of(
|
||||
pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of("name", "a"),
|
||||
1
|
||||
),
|
||||
pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of("name", "b"),
|
||||
1
|
||||
),
|
||||
pointFeature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
Map.of("name", "c"),
|
||||
2
|
||||
)
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMountainPeakPostProcessingLimitsFeaturesOutsideZoom() throws GeometryException {
|
||||
assertEquals(Lists.newArrayList(
|
||||
new VectorTile.Feature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newPoint(-64, -64)),
|
||||
Map.of("rank", 1),
|
||||
1
|
||||
),
|
||||
null,
|
||||
new VectorTile.Feature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
3,
|
||||
VectorTile.encodeGeometry(newPoint(256 + 64, 256 + 64)),
|
||||
Map.of("rank", 1),
|
||||
2
|
||||
),
|
||||
null
|
||||
), profile.postProcessLayerFeatures(MountainPeak.LAYER_NAME, 13, Lists.newArrayList(
|
||||
new VectorTile.Feature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newPoint(-64, -64)),
|
||||
new HashMap<>(),
|
||||
1
|
||||
),
|
||||
new VectorTile.Feature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
2,
|
||||
VectorTile.encodeGeometry(newPoint(-65, -65)),
|
||||
new HashMap<>(),
|
||||
1
|
||||
),
|
||||
new VectorTile.Feature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
3,
|
||||
VectorTile.encodeGeometry(newPoint(256 + 64, 256 + 64)),
|
||||
new HashMap<>(),
|
||||
2
|
||||
),
|
||||
new VectorTile.Feature(
|
||||
MountainPeak.LAYER_NAME,
|
||||
4,
|
||||
VectorTile.encodeGeometry(newPoint(256 + 65, 256 + 65)),
|
||||
new HashMap<>(),
|
||||
2
|
||||
)
|
||||
)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ParkTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testNationalPark() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "park",
|
||||
"_type", "polygon",
|
||||
"class", "national_park",
|
||||
"name", "<null>",
|
||||
"_minpixelsize", 2d,
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
), Map.of(
|
||||
"_layer", "park",
|
||||
"_type", "point",
|
||||
"class", "national_park",
|
||||
"name", "Grand Canyon National Park",
|
||||
"name_int", "Grand Canyon National Park",
|
||||
"name:latin", "Grand Canyon National Park",
|
||||
"name:es", "es name",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"boundary", "national_park",
|
||||
"name", "Grand Canyon National Park",
|
||||
"name:es", "es name",
|
||||
"protection_title", "National Park",
|
||||
"wikipedia", "en:Grand Canyon National Park"
|
||||
))));
|
||||
|
||||
// needs a name
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "park",
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"boundary", "national_park",
|
||||
"protection_title", "National Park"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmallerPark() {
|
||||
double z11area = Math.pow((GeoUtils.metersToPixelAtEquator(0, Math.sqrt(70_000)) / 256d), 2) * Math.pow(2, 20 - 11);
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "park",
|
||||
"_type", "polygon",
|
||||
"class", "protected_area",
|
||||
"name", "<null>",
|
||||
"_minpixelsize", 2d,
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
), Map.of(
|
||||
"_layer", "park",
|
||||
"_type", "point",
|
||||
"class", "protected_area",
|
||||
"name", "Small park",
|
||||
"name_int", "Small park",
|
||||
"_minzoom", 11,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeatureWithArea(z11area, Map.of(
|
||||
"boundary", "protected_area",
|
||||
"name", "Small park",
|
||||
"wikipedia", "en:Small park"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "park",
|
||||
"_type", "polygon"
|
||||
), Map.of(
|
||||
"_layer", "park",
|
||||
"_type", "point",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeatureWithArea(1, Map.of(
|
||||
"boundary", "protected_area",
|
||||
"name", "Small park",
|
||||
"wikidata", "Q123"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortKeys() {
|
||||
assertAscending(
|
||||
getLabelSortKey(1, Map.of(
|
||||
"boundary", "national_park",
|
||||
"name", "a",
|
||||
"wikipedia", "en:park"
|
||||
)),
|
||||
getLabelSortKey(1e-10, Map.of(
|
||||
"boundary", "national_park",
|
||||
"name", "a",
|
||||
"wikipedia", "en:Park"
|
||||
)),
|
||||
getLabelSortKey(1, Map.of(
|
||||
"boundary", "national_park",
|
||||
"name", "a"
|
||||
)),
|
||||
getLabelSortKey(1e-10, Map.of(
|
||||
"boundary", "national_park",
|
||||
"name", "a"
|
||||
)),
|
||||
|
||||
getLabelSortKey(1, Map.of(
|
||||
"boundary", "protected_area",
|
||||
"name", "a",
|
||||
"wikipedia", "en:park"
|
||||
)),
|
||||
getLabelSortKey(1e-10, Map.of(
|
||||
"boundary", "protected_area",
|
||||
"name", "a",
|
||||
"wikipedia", "en:Park"
|
||||
)),
|
||||
getLabelSortKey(1, Map.of(
|
||||
"boundary", "protected_area",
|
||||
"name", "a"
|
||||
)),
|
||||
getLabelSortKey(1e-10, Map.of(
|
||||
"boundary", "protected_area",
|
||||
"name", "a"
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
private int getLabelSortKey(double area, Map<String, Object> tags) {
|
||||
var iter = process(polygonFeatureWithArea(area, tags)).iterator();
|
||||
iter.next();
|
||||
return iter.next().getSortKey();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.newPoint;
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.OSM_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.layers.Place.getSortKey;
|
||||
import static com.onthegomap.planetiler.collection.FeatureGroup.SORT_KEY_MAX;
|
||||
import static com.onthegomap.planetiler.collection.FeatureGroup.SORT_KEY_MIN;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class PlaceTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testContinent() {
|
||||
wikidataTranslations.put(49, "es", "América del Norte y América Central");
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "continent",
|
||||
"name", "North America",
|
||||
"name:en", "North America",
|
||||
"name:es", "América del Norte y América Central",
|
||||
"name:latin", "North America",
|
||||
"rank", 1,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 0,
|
||||
"_maxzoom", 3
|
||||
)), process(pointFeature(Map.of(
|
||||
"place", "continent",
|
||||
"wikidata", "Q49",
|
||||
"name:es", "América del Norte",
|
||||
"name", "North America",
|
||||
"name:en", "North America"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountry() {
|
||||
wikidataTranslations.put(30, "es", "Estados Unidos");
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 0.25),
|
||||
Map.of(
|
||||
"name", "United States",
|
||||
"scalerank", 0,
|
||||
"labelrank", 2
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_0_countries",
|
||||
0
|
||||
));
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "country",
|
||||
"name", "United States of America",
|
||||
"name_en", "United States of America",
|
||||
"name:es", "Estados Unidos",
|
||||
"name:latin", "United States of America",
|
||||
"iso_a2", "US",
|
||||
"rank", 6,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 5
|
||||
)), process(SimpleFeature.create(
|
||||
newPoint(0.5, 0.5),
|
||||
Map.of(
|
||||
"place", "country",
|
||||
"wikidata", "Q30",
|
||||
"name:es", "Estados Unidos de América",
|
||||
"name", "United States of America",
|
||||
"name:en", "United States of America",
|
||||
"country_code_iso3166_1_alpha_2", "US"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "country",
|
||||
"name", "United States of America",
|
||||
"name_en", "United States of America",
|
||||
"name:es", "Estados Unidos",
|
||||
"name:latin", "United States of America",
|
||||
"iso_a2", "US",
|
||||
"rank", 1,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 0
|
||||
)), process(SimpleFeature.create(
|
||||
newPoint(0.1, 0.1),
|
||||
Map.of(
|
||||
"place", "country",
|
||||
"wikidata", "Q30",
|
||||
"name:es", "Estados Unidos de América",
|
||||
"name", "United States of America",
|
||||
"name:en", "United States of America",
|
||||
"country_code_iso3166_1_alpha_2", "US"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testState() {
|
||||
wikidataTranslations.put(771, "es", "Massachusetts es");
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 0.25),
|
||||
Map.of(
|
||||
"name", "Massachusetts",
|
||||
"scalerank", 0,
|
||||
"labelrank", 2,
|
||||
"datarank", 1
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_1_states_provinces",
|
||||
0
|
||||
));
|
||||
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0.4, 0.6),
|
||||
Map.of(
|
||||
"name", "Massachusetts - not important",
|
||||
"scalerank", 4,
|
||||
"labelrank", 4,
|
||||
"datarank", 1
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_1_states_provinces",
|
||||
0
|
||||
));
|
||||
|
||||
// no match
|
||||
assertFeatures(0, List.of(), process(SimpleFeature.create(
|
||||
newPoint(1, 1),
|
||||
Map.of(
|
||||
"place", "state",
|
||||
"wikidata", "Q771",
|
||||
"name", "Massachusetts",
|
||||
"name:en", "Massachusetts"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
|
||||
// unimportant match
|
||||
assertFeatures(0, List.of(), process(SimpleFeature.create(
|
||||
newPoint(0.5, 0.5),
|
||||
Map.of(
|
||||
"place", "state",
|
||||
"wikidata", "Q771",
|
||||
"name", "Massachusetts",
|
||||
"name:en", "Massachusetts"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
|
||||
// important match
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "state",
|
||||
"name", "Massachusetts",
|
||||
"name_en", "Massachusetts",
|
||||
"name:es", "Massachusetts es",
|
||||
"name:latin", "Massachusetts",
|
||||
"rank", 1,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 2
|
||||
)), process(SimpleFeature.create(
|
||||
newPoint(0.1, 0.1),
|
||||
Map.of(
|
||||
"place", "state",
|
||||
"wikidata", "Q771",
|
||||
"name", "Massachusetts",
|
||||
"name:en", "Massachusetts"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIslandPoint() {
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "island",
|
||||
"name", "Nantucket",
|
||||
"name_en", "Nantucket",
|
||||
"name:latin", "Nantucket",
|
||||
"rank", 7,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 12
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "island",
|
||||
"name", "Nantucket",
|
||||
"name:en", "Nantucket"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIslandPolygon() {
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "island",
|
||||
"name", "Nantucket",
|
||||
"name_en", "Nantucket",
|
||||
"name:latin", "Nantucket",
|
||||
"rank", 3,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 8
|
||||
)), process(polygonFeatureWithArea(1,
|
||||
Map.of(
|
||||
"place", "island",
|
||||
"name", "Nantucket",
|
||||
"name:en", "Nantucket"
|
||||
))));
|
||||
|
||||
double rank4area = Math.pow(GeoUtils.metersToPixelAtEquator(0, Math.sqrt(40_000_000 - 1)) / 256d, 2);
|
||||
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "island",
|
||||
"name", "Nantucket",
|
||||
"rank", 4,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 9
|
||||
)), process(polygonFeatureWithArea(rank4area,
|
||||
Map.of(
|
||||
"place", "island",
|
||||
"name", "Nantucket",
|
||||
"name:en", "Nantucket"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlaceSortKeyRanking() {
|
||||
int[] sortKeys = new int[]{
|
||||
// max
|
||||
getSortKey(0, Place.PlaceType.CITY, 1_000_000_000, "name"),
|
||||
|
||||
getSortKey(0, Place.PlaceType.CITY, 1_000_000_000, "name longer"),
|
||||
getSortKey(0, Place.PlaceType.CITY, 1_000_000_000, "x".repeat(32)),
|
||||
|
||||
getSortKey(0, Place.PlaceType.CITY, 10_000_000, "name"),
|
||||
getSortKey(0, Place.PlaceType.CITY, 0, "name"),
|
||||
|
||||
getSortKey(0, Place.PlaceType.TOWN, 1_000_000_000, "name"),
|
||||
getSortKey(0, Place.PlaceType.ISOLATED_DWELLING, 1_000_000_000, "name"),
|
||||
getSortKey(0, null, 1_000_000_000, "name"),
|
||||
|
||||
getSortKey(1, Place.PlaceType.CITY, 1_000_000_000, "name"),
|
||||
getSortKey(10, Place.PlaceType.CITY, 1_000_000_000, "name"),
|
||||
getSortKey(null, Place.PlaceType.CITY, 1_000_000_000, "name"),
|
||||
|
||||
// min
|
||||
getSortKey(null, null, 0, null),
|
||||
};
|
||||
for (int i = 0; i < sortKeys.length; i++) {
|
||||
if (sortKeys[i] < SORT_KEY_MIN) {
|
||||
fail("Item at index " + i + " is < " + SORT_KEY_MIN + ": " + sortKeys[i]);
|
||||
}
|
||||
if (sortKeys[i] > SORT_KEY_MAX) {
|
||||
fail("Item at index " + i + " is > " + SORT_KEY_MAX + ": " + sortKeys[i]);
|
||||
}
|
||||
}
|
||||
assertAscending(sortKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountryCapital() {
|
||||
process(SimpleFeature.create(
|
||||
newPoint(0, 0),
|
||||
Map.of(
|
||||
"name", "Washington, D.C.",
|
||||
"scalerank", 0,
|
||||
"wikidataid", "Q61"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_populated_places",
|
||||
0
|
||||
));
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "city",
|
||||
"name", "Washington, D.C.",
|
||||
"rank", 1,
|
||||
"capital", 2,
|
||||
"_labelgrid_limit", 0,
|
||||
"_labelgrid_size", 128d,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 2
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "city",
|
||||
"name", "Washington, D.C.",
|
||||
"population", "672228",
|
||||
"wikidata", "Q61",
|
||||
"capital", "yes"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateCapital() {
|
||||
process(SimpleFeature.create(
|
||||
newPoint(0, 0),
|
||||
Map.of(
|
||||
"name", "Boston",
|
||||
"scalerank", 2,
|
||||
"wikidataid", "Q100"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_populated_places",
|
||||
0
|
||||
));
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "city",
|
||||
"name", "Boston",
|
||||
"rank", 3,
|
||||
"capital", 4,
|
||||
|
||||
"_type", "point",
|
||||
"_minzoom", 3
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "city",
|
||||
"name", "Boston",
|
||||
"population", "667137",
|
||||
"capital", "4"
|
||||
))));
|
||||
// no match when far away
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "city",
|
||||
"name", "Boston",
|
||||
"rank", "<null>"
|
||||
)), process(SimpleFeature.create(
|
||||
newPoint(1, 1),
|
||||
Map.of(
|
||||
"place", "city",
|
||||
"name", "Boston",
|
||||
"wikidata", "Q100",
|
||||
"population", "667137",
|
||||
"capital", "4"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
// unaccented name match
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "city",
|
||||
"rank", 3
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "city",
|
||||
"name", "Böston",
|
||||
"population", "667137",
|
||||
"capital", "4"
|
||||
))));
|
||||
// wikidata only match
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "city",
|
||||
"rank", 3
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "city",
|
||||
"name", "Other name",
|
||||
"population", "667137",
|
||||
"wikidata", "Q100",
|
||||
"capital", "4"
|
||||
))));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCityWithoutNaturalEarthMatch() {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "city",
|
||||
"rank", "<null>",
|
||||
"_minzoom", 7,
|
||||
"_labelgrid_limit", 4,
|
||||
"_labelgrid_size", 128d
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "city",
|
||||
"name", "City name"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "isolated_dwelling",
|
||||
"rank", "<null>",
|
||||
"_labelgrid_limit", 0,
|
||||
"_labelgrid_size", 0d,
|
||||
"_minzoom", 14
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "isolated_dwelling",
|
||||
"name", "City name"
|
||||
))));
|
||||
assertFeatures(12, List.of(Map.of(
|
||||
"_layer", "place",
|
||||
"class", "isolated_dwelling",
|
||||
"rank", "<null>",
|
||||
"_labelgrid_limit", 14,
|
||||
"_labelgrid_size", 128d,
|
||||
"_minzoom", 14
|
||||
)), process(pointFeature(
|
||||
Map.of(
|
||||
"place", "isolated_dwelling",
|
||||
"name", "City name"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCitySetRankFromGridrank() throws GeometryException {
|
||||
var layerName = Place.LAYER_NAME;
|
||||
assertEquals(List.of(), profile.postProcessLayerFeatures(layerName, 13, List.of()));
|
||||
|
||||
assertEquals(List.of(pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 11),
|
||||
1
|
||||
)), profile.postProcessLayerFeatures(layerName, 13, List.of(pointFeature(
|
||||
layerName,
|
||||
Map.of(),
|
||||
1
|
||||
))));
|
||||
|
||||
assertEquals(List.of(
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 11, "name", "a"),
|
||||
1
|
||||
), pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 12, "name", "b"),
|
||||
1
|
||||
), pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 11, "name", "c"),
|
||||
2
|
||||
)
|
||||
), profile.postProcessLayerFeatures(layerName, 13, List.of(
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("name", "a"),
|
||||
1
|
||||
),
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("name", "b"),
|
||||
1
|
||||
),
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("name", "c"),
|
||||
2
|
||||
)
|
||||
)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SourceFeature;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
public class PoiTest extends AbstractLayerTest {
|
||||
|
||||
private SourceFeature feature(boolean area, Map<String, Object> tags) {
|
||||
return area ? polygonFeature(tags) : pointFeature(tags);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFenwayPark() {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "poi",
|
||||
"class", "stadium",
|
||||
"subclass", "stadium",
|
||||
"name", "Fenway Park",
|
||||
"rank", "<null>",
|
||||
"_minzoom", 14,
|
||||
"_labelgrid_size", 64d
|
||||
)), process(pointFeature(Map.of(
|
||||
"leisure", "stadium",
|
||||
"name", "Fenway Park"
|
||||
))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true})
|
||||
public void testFunicularHalt(boolean area) {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "poi",
|
||||
"class", "railway",
|
||||
"subclass", "halt",
|
||||
"rank", "<null>",
|
||||
"_minzoom", 12
|
||||
)), process(feature(area, Map.of(
|
||||
"railway", "station",
|
||||
"funicular", "yes",
|
||||
"name", "station"
|
||||
))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true})
|
||||
public void testSubway(boolean area) {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "poi",
|
||||
"class", "railway",
|
||||
"subclass", "subway",
|
||||
"rank", "<null>",
|
||||
"_minzoom", 12
|
||||
)), process(feature(area, Map.of(
|
||||
"railway", "station",
|
||||
"station", "subway",
|
||||
"name", "station"
|
||||
))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true})
|
||||
public void testPlaceOfWorshipFromReligionTag(boolean area) {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "poi",
|
||||
"class", "place_of_worship",
|
||||
"subclass", "religion value",
|
||||
"rank", "<null>",
|
||||
"_minzoom", 14
|
||||
)), process(feature(area, Map.of(
|
||||
"amenity", "place_of_worship",
|
||||
"religion", "religion value",
|
||||
"name", "station"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPitchFromSportTag() {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "poi",
|
||||
"class", "pitch",
|
||||
"subclass", "soccer",
|
||||
"rank", "<null>"
|
||||
)), process(pointFeature(Map.of(
|
||||
"leisure", "pitch",
|
||||
"sport", "soccer",
|
||||
"name", "station"
|
||||
))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true})
|
||||
public void testInformation(boolean area) {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "poi",
|
||||
"class", "information",
|
||||
"subclass", "infotype",
|
||||
"layer", 3L,
|
||||
"level", 2L,
|
||||
"indoor", 1,
|
||||
"rank", "<null>"
|
||||
)), process(feature(area, Map.of(
|
||||
"tourism", "information",
|
||||
"information", "infotype",
|
||||
"name", "station",
|
||||
"layer", "3",
|
||||
"level", "2",
|
||||
"indoor", "yes"
|
||||
))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true})
|
||||
public void testFerryTerminal(boolean area) {
|
||||
assertFeatures(7, List.of(Map.of(
|
||||
"_layer", "poi",
|
||||
"class", "ferry_terminal",
|
||||
"subclass", "ferry_terminal",
|
||||
"name", "Water Taxi",
|
||||
"_minzoom", 12
|
||||
)), process(feature(area, Map.of(
|
||||
"amenity", "ferry_terminal",
|
||||
"information", "infotype",
|
||||
"name", "Water Taxi",
|
||||
"layer", "3",
|
||||
"level", "2",
|
||||
"indoor", "yes"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGridRank() throws GeometryException {
|
||||
var layerName = Poi.LAYER_NAME;
|
||||
assertEquals(List.of(), profile.postProcessLayerFeatures(layerName, 13, List.of()));
|
||||
|
||||
assertEquals(List.of(pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 1),
|
||||
1
|
||||
)), profile.postProcessLayerFeatures(layerName, 14, List.of(pointFeature(
|
||||
layerName,
|
||||
Map.of(),
|
||||
1
|
||||
))));
|
||||
|
||||
assertEquals(List.of(
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 1, "name", "a"),
|
||||
1
|
||||
), pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 2, "name", "b"),
|
||||
1
|
||||
), pointFeature(
|
||||
layerName,
|
||||
Map.of("rank", 1, "name", "c"),
|
||||
2
|
||||
)
|
||||
), profile.postProcessLayerFeatures(layerName, 14, List.of(
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("name", "a"),
|
||||
1
|
||||
),
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("name", "b"),
|
||||
1
|
||||
),
|
||||
pointFeature(
|
||||
layerName,
|
||||
Map.of("name", "c"),
|
||||
2
|
||||
)
|
||||
)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.newLineString;
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.OSM_SOURCE;
|
||||
|
||||
import com.onthegomap.planetiler.FeatureCollector;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import com.onthegomap.planetiler.reader.osm.OsmElement;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TransportationTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testNamedFootway() {
|
||||
FeatureCollector result = process(lineFeature(Map.of(
|
||||
"name", "Lagoon Path",
|
||||
"surface", "asphalt",
|
||||
"level", "0",
|
||||
"highway", "footway",
|
||||
"indoor", "no",
|
||||
"oneway", "no",
|
||||
"foot", "designated",
|
||||
"bicycle", "dismount"
|
||||
)));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"_type", "line",
|
||||
"class", "path",
|
||||
"subclass", "footway",
|
||||
"oneway", 0,
|
||||
"name", "<null>",
|
||||
"_buffer", 4d,
|
||||
"_minpixelsize", 0d,
|
||||
"_minzoom", 13,
|
||||
"_maxzoom", 14
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"_type", "line",
|
||||
"class", "path",
|
||||
"subclass", "footway",
|
||||
"name", "Lagoon Path",
|
||||
"name_int", "Lagoon Path",
|
||||
"name:latin", "Lagoon Path",
|
||||
"_minpixelsize", 0d,
|
||||
"_minzoom", 13,
|
||||
"_maxzoom", 14
|
||||
)), result);
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"surface", "paved",
|
||||
"oneway", 0,
|
||||
"level", 0L,
|
||||
"ramp", 0,
|
||||
"bicycle", "dismount",
|
||||
"foot", "designated"
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"level", 0L,
|
||||
"surface", "<null>",
|
||||
"oneway", "<null>",
|
||||
"ramp", "<null>",
|
||||
"bicycle", "<null>",
|
||||
"foot", "<null>"
|
||||
)), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnnamedPath() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "path",
|
||||
"subclass", "path",
|
||||
"surface", "unpaved",
|
||||
"oneway", 0
|
||||
)), process(lineFeature(Map.of(
|
||||
"surface", "dirt",
|
||||
"highway", "path"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndoorTunnelSteps() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "path",
|
||||
"subclass", "steps",
|
||||
"brunnel", "tunnel",
|
||||
"indoor", 1,
|
||||
"oneway", 1,
|
||||
"ramp", 1
|
||||
)), process(lineFeature(Map.of(
|
||||
"highway", "steps",
|
||||
"tunnel", "building_passage",
|
||||
"oneway", "yes",
|
||||
"indoor", "yes"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterstateMotorway() {
|
||||
var rel = new OsmElement.Relation(1);
|
||||
rel.setTag("type", "route");
|
||||
rel.setTag("route", "road");
|
||||
rel.setTag("network", "US:I");
|
||||
rel.setTag("ref", "90");
|
||||
|
||||
FeatureCollector features = process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(rel),
|
||||
Map.of(
|
||||
"highway", "motorway",
|
||||
"oneway", "yes",
|
||||
"name", "Massachusetts Turnpike",
|
||||
"ref", "I 90",
|
||||
"surface", "asphalt",
|
||||
"foot", "no",
|
||||
"bicycle", "no",
|
||||
"horse", "no",
|
||||
"bridge", "yes"
|
||||
)));
|
||||
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "motorway",
|
||||
"surface", "paved",
|
||||
"oneway", 1,
|
||||
"ramp", 0,
|
||||
"bicycle", "no",
|
||||
"foot", "no",
|
||||
"horse", "no",
|
||||
"brunnel", "bridge",
|
||||
"_minzoom", 4
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "motorway",
|
||||
"name", "Massachusetts Turnpike",
|
||||
"name_en", "Massachusetts Turnpike",
|
||||
"ref", "90",
|
||||
"ref_length", 2,
|
||||
"network", "us-interstate",
|
||||
"brunnel", "<null>",
|
||||
"_minzoom", 6
|
||||
)), features);
|
||||
|
||||
assertFeatures(8, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "motorway",
|
||||
"surface", "<null>",
|
||||
"oneway", "<null>",
|
||||
"ramp", "<null>",
|
||||
"bicycle", "<null>",
|
||||
"foot", "<null>",
|
||||
"horse", "<null>",
|
||||
"brunnel", "bridge",
|
||||
"_minzoom", 4
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "motorway",
|
||||
"name", "Massachusetts Turnpike",
|
||||
"name_en", "Massachusetts Turnpike",
|
||||
"ref", "90",
|
||||
"ref_length", 2,
|
||||
"network", "us-interstate",
|
||||
"brunnel", "<null>",
|
||||
"_minzoom", 6
|
||||
)), features);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimaryRoadConstruction() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "primary_construction",
|
||||
"brunnel", "bridge",
|
||||
"layer", 1L,
|
||||
"oneway", 1,
|
||||
"_minzoom", 7
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"name", "North Washington Street",
|
||||
"class", "primary_construction",
|
||||
"brunnel", "<null>",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeature(Map.of(
|
||||
"highway", "construction",
|
||||
"construction", "primary",
|
||||
"bridge", "yes",
|
||||
"layer", "1",
|
||||
"name", "North Washington Street",
|
||||
"oneway", "yes"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaceway() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "raceway",
|
||||
"oneway", 1,
|
||||
"_minzoom", 12
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "raceway",
|
||||
"name", "Climbing Turn",
|
||||
"ref", "5",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeature(Map.of(
|
||||
"highway", "raceway",
|
||||
"oneway", "yes",
|
||||
"ref", "5",
|
||||
"name", "Climbing Turn"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDriveway() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "service",
|
||||
"service", "driveway",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeature(Map.of(
|
||||
"highway", "service",
|
||||
"service", "driveway"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMountainBikeTrail() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "path",
|
||||
"subclass", "path",
|
||||
"mtb_scale", "4",
|
||||
"surface", "unpaved",
|
||||
"bicycle", "yes",
|
||||
"_minzoom", 13
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "path",
|
||||
"subclass", "path",
|
||||
"name", "Path name",
|
||||
"_minzoom", 13
|
||||
)), process(lineFeature(Map.of(
|
||||
"highway", "path",
|
||||
"mtb:scale", "4",
|
||||
"name", "Path name",
|
||||
"bicycle", "yes",
|
||||
"surface", "ground"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrack() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "track",
|
||||
"surface", "unpaved",
|
||||
"horse", "yes",
|
||||
"_minzoom", 14
|
||||
)), process(lineFeature(Map.of(
|
||||
"highway", "track",
|
||||
"surface", "dirt",
|
||||
"horse", "yes"
|
||||
))));
|
||||
}
|
||||
|
||||
final OsmElement.Relation relUS = new OsmElement.Relation(1);
|
||||
|
||||
{
|
||||
relUS.setTag("type", "route");
|
||||
relUS.setTag("route", "road");
|
||||
relUS.setTag("network", "US:US");
|
||||
relUS.setTag("ref", "3");
|
||||
}
|
||||
|
||||
final OsmElement.Relation relMA = new OsmElement.Relation(2);
|
||||
|
||||
{
|
||||
relMA.setTag("type", "route");
|
||||
relMA.setTag("route", "road");
|
||||
relMA.setTag("network", "US:MA");
|
||||
relMA.setTag("ref", "2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUSAndStateHighway() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "primary",
|
||||
"surface", "paved",
|
||||
"oneway", 0,
|
||||
"ramp", 0,
|
||||
"_minzoom", 7
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "primary",
|
||||
"name", "Memorial Drive",
|
||||
"name_en", "Memorial Drive",
|
||||
"ref", "3",
|
||||
"ref_length", 1,
|
||||
"network", "us-highway",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeatureWithRelation(
|
||||
Stream.concat(
|
||||
profile.preprocessOsmRelation(relUS).stream(),
|
||||
profile.preprocessOsmRelation(relMA).stream()
|
||||
).toList(),
|
||||
Map.of(
|
||||
"highway", "primary",
|
||||
"name", "Memorial Drive",
|
||||
"ref", "US 3;MA 2",
|
||||
"surface", "asphalt"
|
||||
))));
|
||||
|
||||
// swap order
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "primary"
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "primary",
|
||||
"ref", "3",
|
||||
"network", "us-highway"
|
||||
)), process(lineFeatureWithRelation(
|
||||
Stream.concat(
|
||||
profile.preprocessOsmRelation(relMA).stream(),
|
||||
profile.preprocessOsmRelation(relUS).stream()
|
||||
).toList(),
|
||||
Map.of(
|
||||
"highway", "primary",
|
||||
"name", "Memorial Drive",
|
||||
"ref", "US 3;MA 2",
|
||||
"surface", "asphalt"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsStateHighway() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "primary"
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "primary",
|
||||
"name", "Memorial Drive",
|
||||
"name_en", "Memorial Drive",
|
||||
"ref", "2",
|
||||
"ref_length", 1,
|
||||
"network", "us-state",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(relMA),
|
||||
Map.of(
|
||||
"highway", "primary",
|
||||
"name", "Memorial Drive",
|
||||
"ref", "US 3;MA 2",
|
||||
"surface", "asphalt"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompoundRef() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "primary"
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "primary",
|
||||
"name", "Memorial Drive",
|
||||
"name_en", "Memorial Drive",
|
||||
"ref", "US 3;MA 2",
|
||||
"ref_length", 9,
|
||||
"network", "road",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeature(
|
||||
Map.of(
|
||||
"highway", "primary",
|
||||
"name", "Memorial Drive",
|
||||
"ref", "US 3;MA 2",
|
||||
"surface", "asphalt"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransCanadaHighway() {
|
||||
var rel = new OsmElement.Relation(1);
|
||||
rel.setTag("type", "route");
|
||||
rel.setTag("route", "road");
|
||||
rel.setTag("network", "CA:transcanada:namedRoute");
|
||||
|
||||
FeatureCollector features = process(lineFeatureWithRelation(
|
||||
profile.preprocessOsmRelation(rel),
|
||||
Map.of(
|
||||
"highway", "motorway",
|
||||
"oneway", "yes",
|
||||
"name", "Autoroute Claude-Béchard",
|
||||
"ref", "85",
|
||||
"surface", "asphalt"
|
||||
)));
|
||||
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "motorway",
|
||||
"surface", "paved",
|
||||
"oneway", 1,
|
||||
"ramp", 0,
|
||||
"_minzoom", 4
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "motorway",
|
||||
"name", "Autoroute Claude-Béchard",
|
||||
"name_en", "Autoroute Claude-Béchard",
|
||||
"ref", "85",
|
||||
"ref_length", 2,
|
||||
"network", "ca-transcanada",
|
||||
"_minzoom", 6
|
||||
)), features);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreatBritainHighway() {
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 0.1),
|
||||
Map.of("iso_a2", "GB"),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_admin_0_countries",
|
||||
0
|
||||
));
|
||||
|
||||
// in GB
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "motorway",
|
||||
"oneway", 1,
|
||||
"ramp", 0,
|
||||
"_minzoom", 4
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "motorway",
|
||||
"ref", "M1",
|
||||
"ref_length", 2,
|
||||
"network", "gb-motorway",
|
||||
"_minzoom", 6
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"highway", "motorway",
|
||||
"oneway", "yes",
|
||||
"ref", "M1"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
|
||||
// not in GB
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "motorway",
|
||||
"oneway", 1,
|
||||
"ramp", 0,
|
||||
"_minzoom", 4
|
||||
), Map.of(
|
||||
"_layer", "transportation_name",
|
||||
"class", "motorway",
|
||||
"ref", "M1",
|
||||
"ref_length", 2,
|
||||
"network", "road",
|
||||
"_minzoom", 6
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(1, 0, 0, 1),
|
||||
Map.of(
|
||||
"highway", "motorway",
|
||||
"oneway", "yes",
|
||||
"ref", "M1"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergesDisconnectedRoadFeatures() throws GeometryException {
|
||||
testMergesLinestrings(Map.of("class", "motorway"), Transportation.LAYER_NAME, 10, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergesDisconnectedRoadNameFeatures() throws GeometryException {
|
||||
testMergesLinestrings(Map.of("class", "motorway"), TransportationName.LAYER_NAME, 10, 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLightRail() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "transit",
|
||||
"subclass", "light_rail",
|
||||
"brunnel", "tunnel",
|
||||
"layer", -1L,
|
||||
"oneway", 0,
|
||||
"ramp", 0,
|
||||
|
||||
"_minzoom", 11,
|
||||
"_maxzoom", 14,
|
||||
"_type", "line"
|
||||
)), process(lineFeature(Map.of(
|
||||
"railway", "light_rail",
|
||||
"name", "Green Line",
|
||||
"tunnel", "yes",
|
||||
"layer", "-1"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubway() {
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "transit",
|
||||
"subclass", "subway",
|
||||
"brunnel", "tunnel",
|
||||
"layer", -2L,
|
||||
"oneway", 0,
|
||||
"ramp", 0,
|
||||
|
||||
"_minzoom", 14,
|
||||
"_maxzoom", 14,
|
||||
"_type", "line"
|
||||
)), process(lineFeature(Map.of(
|
||||
"railway", "subway",
|
||||
"name", "Red Line",
|
||||
"tunnel", "yes",
|
||||
"layer", "-2",
|
||||
"level", "-2"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRail() {
|
||||
assertFeatures(8, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "rail",
|
||||
"subclass", "rail",
|
||||
"brunnel", "<null>",
|
||||
"layer", "<null>",
|
||||
|
||||
"_minzoom", 8,
|
||||
"_maxzoom", 14,
|
||||
"_type", "line"
|
||||
)), process(lineFeature(Map.of(
|
||||
"railway", "rail",
|
||||
"name", "Boston Subdivision",
|
||||
"usage", "main",
|
||||
"tunnel", "yes",
|
||||
"layer", "-2"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"_minzoom", 10
|
||||
)), process(lineFeature(Map.of(
|
||||
"railway", "rail",
|
||||
"name", "Boston Subdivision"
|
||||
))));
|
||||
assertFeatures(13, List.of(),
|
||||
process(polygonFeature(Map.of(
|
||||
"railway", "rail"
|
||||
))));
|
||||
assertFeatures(13, List.of(Map.of(
|
||||
"class", "rail",
|
||||
"subclass", "rail",
|
||||
"_minzoom", 14,
|
||||
"service", "yard"
|
||||
)), process(lineFeature(Map.of(
|
||||
"railway", "rail",
|
||||
"name", "Boston Subdivision",
|
||||
"service", "yard"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNarrowGauge() {
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "rail",
|
||||
"subclass", "narrow_gauge",
|
||||
|
||||
"_minzoom", 10,
|
||||
"_maxzoom", 14,
|
||||
"_type", "line"
|
||||
)), process(lineFeature(Map.of(
|
||||
"railway", "narrow_gauge"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAerialway() {
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "aerialway",
|
||||
"subclass", "gondola",
|
||||
|
||||
"_minzoom", 12,
|
||||
"_maxzoom", 14,
|
||||
"_type", "line"
|
||||
)), process(lineFeature(Map.of(
|
||||
"aerialway", "gondola",
|
||||
"name", "Summit Gondola"
|
||||
))));
|
||||
assertFeatures(10, List.of(),
|
||||
process(polygonFeature(Map.of(
|
||||
"aerialway", "gondola",
|
||||
"name", "Summit Gondola"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFerry() {
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "ferry",
|
||||
|
||||
"_minzoom", 11,
|
||||
"_maxzoom", 14,
|
||||
"_type", "line"
|
||||
)), process(lineFeature(Map.of(
|
||||
"route", "ferry",
|
||||
"name", "Boston - Provincetown Ferry",
|
||||
"motor_vehicle", "no",
|
||||
"foot", "yes",
|
||||
"bicycle", "yes"
|
||||
))));
|
||||
assertFeatures(10, List.of(),
|
||||
process(polygonFeature(Map.of(
|
||||
"route", "ferry",
|
||||
"name", "Boston - Provincetown Ferry",
|
||||
"motor_vehicle", "no",
|
||||
"foot", "yes",
|
||||
"bicycle", "yes"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPiers() {
|
||||
// area
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "pier",
|
||||
|
||||
"_minzoom", 13,
|
||||
"_maxzoom", 14,
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"man_made", "pier"
|
||||
))));
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "pier",
|
||||
|
||||
"_minzoom", 13,
|
||||
"_maxzoom", 14,
|
||||
"_type", "line"
|
||||
)), process(lineFeature(Map.of(
|
||||
"man_made", "pier"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPedestrianArea() {
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "transportation",
|
||||
"class", "path",
|
||||
"subclass", "pedestrian",
|
||||
|
||||
"_minzoom", 13,
|
||||
"_maxzoom", 14,
|
||||
"_type", "polygon"
|
||||
)), process(polygonFeature(Map.of(
|
||||
"highway", "pedestrian",
|
||||
"area", "yes",
|
||||
"foot", "yes"
|
||||
))));
|
||||
// ignore underground pedestrian areas
|
||||
assertFeatures(10, List.of(),
|
||||
process(polygonFeature(Map.of(
|
||||
"highway", "pedestrian",
|
||||
"area", "yes",
|
||||
"foot", "yes",
|
||||
"layer", "-1"
|
||||
))));
|
||||
}
|
||||
|
||||
private int getWaySortKey(Map<String, Object> tags) {
|
||||
var iter = process(lineFeature(tags)).iterator();
|
||||
return iter.next().getSortKey();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortKeys() {
|
||||
assertDescending(
|
||||
getWaySortKey(Map.of("highway", "footway", "layer", "2")),
|
||||
getWaySortKey(Map.of("highway", "motorway", "bridge", "yes")),
|
||||
getWaySortKey(Map.of("highway", "footway", "bridge", "yes")),
|
||||
getWaySortKey(Map.of("highway", "motorway")),
|
||||
getWaySortKey(Map.of("highway", "trunk")),
|
||||
getWaySortKey(Map.of("railway", "rail")),
|
||||
getWaySortKey(Map.of("highway", "primary")),
|
||||
getWaySortKey(Map.of("highway", "secondary")),
|
||||
getWaySortKey(Map.of("highway", "tertiary")),
|
||||
getWaySortKey(Map.of("highway", "motorway_link")),
|
||||
getWaySortKey(Map.of("highway", "footway")),
|
||||
getWaySortKey(Map.of("highway", "motorway", "tunnel", "yes")),
|
||||
getWaySortKey(Map.of("highway", "footway", "tunnel", "yes")),
|
||||
getWaySortKey(Map.of("highway", "motorway", "layer", "-2"))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.newLineString;
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.LAKE_CENTERLINE_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.OSM_SOURCE;
|
||||
|
||||
import com.onthegomap.planetiler.TestUtils;
|
||||
import com.onthegomap.planetiler.geo.GeoUtils;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WaterNameTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testWaterNamePoint() {
|
||||
assertFeatures(11, List.of(Map.of(
|
||||
"_layer", "water"
|
||||
), Map.of(
|
||||
"class", "lake",
|
||||
"name", "waterway",
|
||||
"name:es", "waterway es",
|
||||
"intermittent", 1,
|
||||
|
||||
"_layer", "water_name",
|
||||
"_type", "point",
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeatureWithArea(1, Map.of(
|
||||
"name", "waterway",
|
||||
"name:es", "waterway es",
|
||||
"natural", "water",
|
||||
"water", "pond",
|
||||
"intermittent", "1"
|
||||
))));
|
||||
double z11area = Math.pow((GeoUtils.metersToPixelAtEquator(0, Math.sqrt(70_000)) / 256d), 2) * Math.pow(2, 20 - 11);
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "water"
|
||||
), Map.of(
|
||||
"_layer", "water_name",
|
||||
"_type", "point",
|
||||
"_minzoom", 11,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeatureWithArea(z11area, Map.of(
|
||||
"name", "waterway",
|
||||
"natural", "water",
|
||||
"water", "pond"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWaterNameLakeline() {
|
||||
assertFeatures(11, List.of(), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
new HashMap<>(Map.<String, Object>of(
|
||||
"OSM_ID", -10
|
||||
)),
|
||||
LAKE_CENTERLINE_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "water"
|
||||
), Map.of(
|
||||
"name", "waterway",
|
||||
"name:es", "waterway es",
|
||||
|
||||
"_layer", "water_name",
|
||||
"_type", "line",
|
||||
"_geom", new TestUtils.NormGeometry(GeoUtils.latLonToWorldCoords(newLineString(0, 0, 1, 1))),
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14,
|
||||
"_minpixelsize", "waterway".length() * 6d
|
||||
)), process(SimpleFeature.create(
|
||||
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
|
||||
new HashMap<>(Map.<String, Object>of(
|
||||
"name", "waterway",
|
||||
"name:es", "waterway es",
|
||||
"natural", "water",
|
||||
"water", "pond"
|
||||
)),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
10
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarinePoint() {
|
||||
assertFeatures(11, List.of(), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
new HashMap<>(Map.<String, Object>of(
|
||||
"scalerank", 1,
|
||||
"name", "Black sea"
|
||||
)),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_geography_marine_polys",
|
||||
0
|
||||
)));
|
||||
|
||||
// name match - use scale rank from NE
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"name", "Black Sea",
|
||||
"name:es", "Mar Negro",
|
||||
"_layer", "water_name",
|
||||
"_type", "point",
|
||||
"_minzoom", 1,
|
||||
"_maxzoom", 14
|
||||
)), process(pointFeature(Map.of(
|
||||
"rank", 9,
|
||||
"name", "Black Sea",
|
||||
"name:es", "Mar Negro",
|
||||
"place", "sea"
|
||||
))));
|
||||
|
||||
// name match but ocean - use min zoom=0
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "water_name",
|
||||
"_type", "point",
|
||||
"_minzoom", 0,
|
||||
"_maxzoom", 14
|
||||
)), process(pointFeature(Map.of(
|
||||
"rank", 9,
|
||||
"name", "Black Sea",
|
||||
"place", "ocean"
|
||||
))));
|
||||
|
||||
// no name match - use OSM rank
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "water_name",
|
||||
"_type", "point",
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14
|
||||
)), process(pointFeature(Map.of(
|
||||
"rank", 9,
|
||||
"name", "Atlantic",
|
||||
"place", "sea"
|
||||
))));
|
||||
|
||||
// no rank at all, default to 8
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"_layer", "water_name",
|
||||
"_type", "point",
|
||||
"_minzoom", 8,
|
||||
"_maxzoom", 14
|
||||
)), process(pointFeature(Map.of(
|
||||
"name", "Atlantic",
|
||||
"place", "sea"
|
||||
))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.rectangle;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.OSM_SOURCE;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.WATER_POLYGON_SOURCE;
|
||||
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WaterTest extends AbstractLayerTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testWaterNaturalEarth() {
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"class", "lake",
|
||||
"intermittent", "<null>",
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 0
|
||||
)), process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_lakes",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"class", "ocean",
|
||||
"intermittent", "<null>",
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 0
|
||||
)), process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_ocean",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(6, List.of(Map.of(
|
||||
"class", "lake",
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_maxzoom", 5
|
||||
)), process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_lakes",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(6, List.of(Map.of(
|
||||
"class", "ocean",
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_maxzoom", 5
|
||||
)), process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_ocean",
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWaterOsmWaterPolygon() {
|
||||
assertFeatures(0, List.of(Map.of(
|
||||
"class", "ocean",
|
||||
"intermittent", "<null>",
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
)), process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
WATER_POLYGON_SOURCE,
|
||||
null,
|
||||
0
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWater() {
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "lake",
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"natural", "water",
|
||||
"water", "reservoir"
|
||||
))));
|
||||
assertFeatures(14, List.of(
|
||||
Map.of("_layer", "poi"),
|
||||
Map.of(
|
||||
"class", "lake",
|
||||
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"leisure", "swimming_pool"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(polygonFeature(Map.of(
|
||||
"natural", "bay"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of()), process(polygonFeature(Map.of(
|
||||
"natural", "water"
|
||||
))));
|
||||
assertFeatures(14, List.of(), process(polygonFeature(Map.of(
|
||||
"natural", "water",
|
||||
"covered", "yes"
|
||||
))));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "river",
|
||||
"brunnel", "bridge",
|
||||
"intermittent", 1,
|
||||
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14
|
||||
)), process(polygonFeature(Map.of(
|
||||
"waterway", "stream",
|
||||
"bridge", "1",
|
||||
"intermittent", "1"
|
||||
))));
|
||||
assertFeatures(11, List.of(Map.of(
|
||||
"class", "lake",
|
||||
"brunnel", "<null>",
|
||||
"intermittent", 0,
|
||||
|
||||
"_layer", "water",
|
||||
"_type", "polygon",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 14,
|
||||
"_minpixelsize", 2d
|
||||
)), process(polygonFeature(Map.of(
|
||||
"landuse", "salt_pond",
|
||||
"bridge", "1"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOceanZoomLevels() {
|
||||
assertCoversZoomRange(0, 14, "water",
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_ocean",
|
||||
0
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_ocean",
|
||||
0
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_ocean",
|
||||
0
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
WATER_POLYGON_SOURCE,
|
||||
null,
|
||||
0
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLakeZoomLevels() {
|
||||
assertCoversZoomRange(0, 14, "water",
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_lakes",
|
||||
0
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_lakes",
|
||||
0
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_lakes",
|
||||
0
|
||||
)),
|
||||
process(SimpleFeature.create(
|
||||
rectangle(0, 10),
|
||||
Map.of(
|
||||
"natural", "water",
|
||||
"water", "reservoir"
|
||||
),
|
||||
OSM_SOURCE,
|
||||
null,
|
||||
0
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package com.onthegomap.planetiler.basemap.layers;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.newLineString;
|
||||
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.onthegomap.planetiler.VectorTile;
|
||||
import com.onthegomap.planetiler.geo.GeometryException;
|
||||
import com.onthegomap.planetiler.reader.SimpleFeature;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WaterwayTest extends AbstractLayerTest {
|
||||
|
||||
@Test
|
||||
public void testWaterwayImportantRiverProcess() {
|
||||
var charlesRiver = process(lineFeature(Map.of(
|
||||
"waterway", "river",
|
||||
"name", "charles river",
|
||||
"name:es", "es name"
|
||||
)));
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "river",
|
||||
"name", "charles river",
|
||||
"name:es", "es name",
|
||||
"intermittent", 0,
|
||||
|
||||
"_layer", "waterway",
|
||||
"_type", "line",
|
||||
"_minzoom", 9,
|
||||
"_maxzoom", 14,
|
||||
"_buffer", 4d
|
||||
)), charlesRiver);
|
||||
assertFeatures(11, List.of(Map.of(
|
||||
"class", "river",
|
||||
"name", "charles river",
|
||||
"name:es", "es name",
|
||||
"intermittent", "<null>",
|
||||
"_buffer", 13.082664546679323
|
||||
)), charlesRiver);
|
||||
assertFeatures(10, List.of(Map.of(
|
||||
"class", "river",
|
||||
"_buffer", 26.165329093358647
|
||||
)), charlesRiver);
|
||||
assertFeatures(9, List.of(Map.of(
|
||||
"class", "river",
|
||||
"_buffer", 26.165329093358647
|
||||
)), charlesRiver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWaterwayImportantRiverPostProcess() throws GeometryException {
|
||||
var line1 = new VectorTile.Feature(
|
||||
Waterway.LAYER_NAME,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(0, 0, 10, 0)),
|
||||
Map.of("name", "river"),
|
||||
0
|
||||
);
|
||||
var line2 = new VectorTile.Feature(
|
||||
Waterway.LAYER_NAME,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(10, 0, 20, 0)),
|
||||
Map.of("name", "river"),
|
||||
0
|
||||
);
|
||||
var connected = new VectorTile.Feature(
|
||||
Waterway.LAYER_NAME,
|
||||
1,
|
||||
VectorTile.encodeGeometry(newLineString(0, 0, 20, 0)),
|
||||
Map.of("name", "river"),
|
||||
0
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
List.of(),
|
||||
profile.postProcessLayerFeatures(Waterway.LAYER_NAME, 11, List.of())
|
||||
);
|
||||
assertEquals(
|
||||
List.of(line1, line2),
|
||||
profile.postProcessLayerFeatures(Waterway.LAYER_NAME, 12, List.of(line1, line2))
|
||||
);
|
||||
assertEquals(
|
||||
List.of(connected),
|
||||
profile.postProcessLayerFeatures(Waterway.LAYER_NAME, 11, List.of(line1, line2))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWaterwaySmaller() {
|
||||
// river with no name is not important
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "river",
|
||||
"brunnel", "bridge",
|
||||
|
||||
"_layer", "waterway",
|
||||
"_type", "line",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeature(Map.of(
|
||||
"waterway", "river",
|
||||
"bridge", "1"
|
||||
))));
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "canal",
|
||||
"_layer", "waterway",
|
||||
"_type", "line",
|
||||
"_minzoom", 12
|
||||
)), process(lineFeature(Map.of(
|
||||
"waterway", "canal",
|
||||
"name", "name"
|
||||
))));
|
||||
|
||||
assertFeatures(14, List.of(Map.of(
|
||||
"class", "stream",
|
||||
"_layer", "waterway",
|
||||
"_type", "line",
|
||||
"_minzoom", 13
|
||||
)), process(lineFeature(Map.of(
|
||||
"waterway", "stream",
|
||||
"name", "name"
|
||||
))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWaterwayNaturalEarth() {
|
||||
assertFeatures(3, List.of(Map.of(
|
||||
"class", "river",
|
||||
"name", "<null>",
|
||||
"intermittent", "<null>",
|
||||
|
||||
"_layer", "waterway",
|
||||
"_type", "line",
|
||||
"_minzoom", 3,
|
||||
"_maxzoom", 3
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "River",
|
||||
"name", "name"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_110m_rivers_lake_centerlines",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(6, List.of(Map.of(
|
||||
"class", "river",
|
||||
"intermittent", "<null>",
|
||||
|
||||
"_layer", "waterway",
|
||||
"_type", "line",
|
||||
"_minzoom", 4,
|
||||
"_maxzoom", 5
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "River",
|
||||
"name", "name"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_50m_rivers_lake_centerlines",
|
||||
0
|
||||
)));
|
||||
|
||||
assertFeatures(6, List.of(Map.of(
|
||||
"class", "river",
|
||||
"intermittent", "<null>",
|
||||
|
||||
"_layer", "waterway",
|
||||
"_type", "line",
|
||||
"_minzoom", 6,
|
||||
"_maxzoom", 8
|
||||
)), process(SimpleFeature.create(
|
||||
newLineString(0, 0, 1, 1),
|
||||
Map.of(
|
||||
"featurecla", "River",
|
||||
"name", "name"
|
||||
),
|
||||
NATURAL_EARTH_SOURCE,
|
||||
"ne_10m_rivers_lake_centerlines",
|
||||
0
|
||||
)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package com.onthegomap.planetiler.basemap.util;
|
||||
|
||||
import static com.onthegomap.planetiler.TestUtils.assertSubmap;
|
||||
import static com.onthegomap.planetiler.basemap.util.LanguageUtils.containsOnlyLatinCharacters;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import com.onthegomap.planetiler.util.Translations;
|
||||
import com.onthegomap.planetiler.util.Wikidata;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
public class LanguageUtilsTest {
|
||||
|
||||
private final Wikidata.WikidataTranslations wikidataTranslations = new Wikidata.WikidataTranslations();
|
||||
private final Translations translations = Translations.defaultProvider(List.of("en", "es", "de"))
|
||||
.addTranslationProvider(wikidataTranslations);
|
||||
|
||||
@Test
|
||||
public void testSimpleExample() {
|
||||
assertSubmap(Map.of(
|
||||
"name", "name",
|
||||
"name_en", "english name",
|
||||
"name_de", "german name"
|
||||
), LanguageUtils.getNames(Map.of(
|
||||
"name", "name",
|
||||
"name:en", "english name",
|
||||
"name:de", "german name"
|
||||
), translations));
|
||||
|
||||
assertSubmap(Map.of(
|
||||
"name", "name",
|
||||
"name_en", "name",
|
||||
"name_de", "german name"
|
||||
), LanguageUtils.getNames(Map.of(
|
||||
"name", "name",
|
||||
"name:de", "german name"
|
||||
), translations));
|
||||
|
||||
assertSubmap(Map.of(
|
||||
"name", "name",
|
||||
"name_en", "english name",
|
||||
"name_de", "name"
|
||||
), LanguageUtils.getNames(Map.of(
|
||||
"name", "name",
|
||||
"name:en", "english name"
|
||||
), translations));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"abc, true",
|
||||
"5!, true",
|
||||
"5~, true",
|
||||
"é, true",
|
||||
"éś, true",
|
||||
"ɏə, true",
|
||||
"ɐ, false",
|
||||
"ᵿἀ, false",
|
||||
"Ḁỿ, true",
|
||||
"\u02ff\u0370, false",
|
||||
"\u0030\u036f, true",
|
||||
"日本, false",
|
||||
"abc本123, false",
|
||||
})
|
||||
public void testIsLatin(String in, boolean isLatin) {
|
||||
if (!isLatin) {
|
||||
assertFalse(containsOnlyLatinCharacters(in));
|
||||
} else {
|
||||
assertEquals(in, LanguageUtils.getNames(Map.of(
|
||||
"name", in
|
||||
), translations).get("name:latin"));
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"abcaāíìś+, null",
|
||||
"abca日āíìś+, 日+",
|
||||
"(abc), null",
|
||||
"日本 (Japan), 日本",
|
||||
"日本 [Japan - Nippon], 日本",
|
||||
" Japan - Nippon (Japan) - Japan - 日本 - Japan - Nippon (Japan), 日本",
|
||||
"Japan - 日本~+ , 日本~+",
|
||||
"Japan / 日本 / Japan , 日本",
|
||||
}, nullValues = "null")
|
||||
public void testRemoveNonLatin(String in, String out) {
|
||||
assertEquals(out, LanguageUtils.getNames(Map.of(
|
||||
"name", in
|
||||
), translations).get("name:nonlatin"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"name, a, true",
|
||||
"name:en, a, true",
|
||||
"int_name, a, true",
|
||||
"name:fr, a, true",
|
||||
"name:es, a, true",
|
||||
"name:pt, a, true",
|
||||
"name:de, a, true",
|
||||
"name:ar, ِغَّ, false",
|
||||
"name:it, a, true",
|
||||
"name:jp, ア, false",
|
||||
"name:jp-Latn, a, true",
|
||||
"name:jp_rm, a, true",
|
||||
})
|
||||
public void testLatinFallbacks(String key, String value, boolean use) {
|
||||
assertEquals(use ? value : null, LanguageUtils.getNames(Map.of(
|
||||
key, value
|
||||
), translations).get("name:latin"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"キャンパス, kyanpasu",
|
||||
"Αλφαβητικός Κατάλογος, Alphabētikós Katálogos",
|
||||
"биологическом, biologičeskom",
|
||||
})
|
||||
public void testTransliterate(String in, String out) {
|
||||
assertEquals(out, LanguageUtils.getNames(Map.of(
|
||||
"name", in
|
||||
), translations).get("name:latin"));
|
||||
translations.setShouldTransliterate(false);
|
||||
assertNull(LanguageUtils.getNames(Map.of(
|
||||
"name", in
|
||||
), translations).get("name:latin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseWikidata() {
|
||||
wikidataTranslations.put(123, "es", "es name");
|
||||
assertSubmap(Map.of(
|
||||
"name:es", "es name"
|
||||
), LanguageUtils.getNames(Map.of(
|
||||
"name", "name",
|
||||
"wikidata", "Q123"
|
||||
), translations));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseOsm() {
|
||||
assertSubmap(Map.of(
|
||||
"name:es", "es name osm"
|
||||
), LanguageUtils.getNames(Map.of(
|
||||
"name", "name",
|
||||
"wikidata", "Q123",
|
||||
"name:es", "es name osm"
|
||||
), translations));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferWikidata() {
|
||||
wikidataTranslations.put(123, "es", "wd es name");
|
||||
assertSubmap(Map.of(
|
||||
"name:es", "wd es name",
|
||||
"name:de", "de name osm"
|
||||
), LanguageUtils.getNames(Map.of(
|
||||
"name", "name",
|
||||
"wikidata", "Q123",
|
||||
"name:es", "es name osm",
|
||||
"name:de", "de name osm"
|
||||
), translations));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDontUseTranslationsWhenNotSpecified() {
|
||||
var result = LanguageUtils.getNamesWithoutTranslations(Map.of(
|
||||
"name", "name",
|
||||
"wikidata", "Q123",
|
||||
"name:es", "es name osm",
|
||||
"name:de", "de name osm"
|
||||
));
|
||||
assertNull(result.get("name:es"));
|
||||
assertNull(result.get("name:de"));
|
||||
assertEquals("name", result.get("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreLanguages() {
|
||||
wikidataTranslations.put(123, "ja", "ja name wd");
|
||||
var result = LanguageUtils.getNamesWithoutTranslations(Map.of(
|
||||
"name", "name",
|
||||
"wikidata", "Q123",
|
||||
"name:ja", "ja name osm"
|
||||
));
|
||||
assertNull(result.get("name:ja"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.onthegomap.planetiler.basemap.util;
|
||||
|
||||
import static com.onthegomap.planetiler.geo.GeoUtils.point;
|
||||
import static com.onthegomap.planetiler.util.Gzip.gzip;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.onthegomap.planetiler.VectorTile;
|
||||
import com.onthegomap.planetiler.geo.TileCoord;
|
||||
import com.onthegomap.planetiler.mbtiles.Mbtiles;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class VerifyMonacoTest {
|
||||
|
||||
private Mbtiles mbtiles;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
mbtiles = Mbtiles.newInMemoryDatabase();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void teardown() throws IOException {
|
||||
mbtiles.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyFileInvalid() {
|
||||
assertInvalid(mbtiles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyTablesInvalid() {
|
||||
mbtiles.createTables().addTileIndex();
|
||||
assertInvalid(mbtiles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStilInvalidWithOneTile() throws IOException {
|
||||
mbtiles.createTables().addTileIndex();
|
||||
mbtiles.metadata().setName("name");
|
||||
try (var writer = mbtiles.newBatchedTileWriter()) {
|
||||
VectorTile tile = new VectorTile();
|
||||
tile.addLayerFeatures("layer", List.of(new VectorTile.Feature(
|
||||
"layer",
|
||||
1,
|
||||
VectorTile.encodeGeometry(point(0, 0)),
|
||||
Map.of()
|
||||
)));
|
||||
writer.write(TileCoord.ofXYZ(0, 0, 0), gzip(tile.encode()));
|
||||
}
|
||||
assertInvalid(mbtiles);
|
||||
}
|
||||
|
||||
private void assertInvalid(Mbtiles mbtiles) {
|
||||
assertTrue(VerifyMonaco.verify(mbtiles).numErrors() > 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user