Make planetiler-openmaptiles runnable as a standalone project (#19)

This commit is contained in:
Michael Barry
2022-08-02 07:07:41 -04:00
committed by GitHub
parent 62d420811b
commit 0d7cd887ce
75 changed files with 2560 additions and 454 deletions

View File

@@ -0,0 +1,242 @@
package org.openmaptiles.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 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.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.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.StreamSupport;
import org.openmaptiles.OpenMapTilesProfile;
import org.openmaptiles.util.Utils;
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 OpenMapTilesProfile profile = new OpenMapTilesProfile(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) {
// ensure both are sorted by layer
var expectedList =
expected.stream().sorted(Comparator.comparing(d -> Utils.coalesce(d.get("_layer"), "").toString())).toList();
var actualList = StreamSupport.stream(actual.spliterator(), false)
.sorted(Comparator.comparing(FeatureCollector.Feature::getLayer))
.toList();
assertEquals(expectedList.size(), actualList.size(), () -> "size: " + actualList);
for (int i = 0; i < expectedList.size(); i++) {
assertSubmap(expectedList.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),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
);
}
SourceFeature lineFeature(Map<String, Object> props) {
return SimpleFeature.create(
newLineString(0, 0, 1, 1),
new HashMap<>(props),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
);
}
SourceFeature closedWayFeature(Map<String, Object> props) {
return SimpleFeature.createFakeOsmFeature(
newLineString(0, 0, 1, 0, 1, 1, 0, 1, 0, 0),
new HashMap<>(props),
OpenMapTilesProfile.OSM_SOURCE,
null,
0,
null
);
}
SourceFeature polygonFeatureWithArea(double area, Map<String, Object> props) {
return SimpleFeature.create(
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(area))),
new HashMap<>(props),
OpenMapTilesProfile.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,
OpenMapTilesProfile.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))
);
}
public static Map<String, Object> mapOf(Object... args) {
assert args.length % 2 == 0;
Map<String, Object> result = new HashMap<>();
for (int i = 0; i < args.length; i += 2) {
String key = args[i].toString();
Object value = args[i + 1];
result.put(key, value == null ? "<null>" : value);
}
return result;
}
}

View File

@@ -0,0 +1,156 @@
package org.openmaptiles.layers;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class AerodromeLabelTest extends AbstractLayerTest {
@BeforeEach
public void setupWikidataTranslation() {
wikidataTranslations.put(123, "es", "es wd name");
}
@Test
void testIntlWithIata() {
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", 8,
"_maxzoom", 14,
"_buffer", 64d
)), process(pointFeature(Map.of(
"aeroway", "aerodrome",
"name", "osm name",
"wikidata", "Q123",
"ele", "100",
"aerodrome", "international",
"iata", "123",
"icao", "1234"
))));
}
@Test
void testElevationFeet() {
assertFeatures(14, List.of(Map.of(
"ele", 100,
"ele_ft", 328
)), process(pointFeature(Map.of(
"aeroway", "aerodrome",
"name", "osm name",
"ele", "328'",
"aerodrome", "international",
"iata", "123",
"icao", "1234"
))));
}
@Test
void testElevationFeetInches() {
assertFeatures(14, List.of(Map.of(
"ele", 100,
"ele_ft", 328
)), process(pointFeature(Map.of(
"aeroway", "aerodrome",
"name", "osm name",
"ele", "328' 1\"",
"aerodrome", "international",
"iata", "123",
"icao", "1234"
))));
}
@Test
void testInternational() {
assertFeatures(14, List.of(Map.of(
"class", "international",
"_layer", "aerodrome_label",
"_minzoom", 10 // no IATA
)), process(pointFeature(Map.of(
"aeroway", "aerodrome",
"aerodrome_type", "international"
))));
}
@Test
void testPublic() {
assertFeatures(14, List.of(Map.of(
"class", "public",
"_layer", "aerodrome_label",
"_minzoom", 10
)), 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
void testMilitary() {
assertFeatures(14, List.of(Map.of(
"class", "military",
"_layer", "aerodrome_label",
"_minzoom", 10
)), 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
void testPrivate() {
assertFeatures(14, List.of(Map.of(
"class", "private",
"_layer", "aerodrome_label",
"_minzoom", 10
)), 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
void testOther() {
assertFeatures(14, List.of(Map.of(
"class", "other",
"_layer", "aerodrome_label",
"_minzoom", 10
)), process(pointFeature(Map.of(
"aeroway", "aerodrome"
))));
}
@Test
void testIgnoreNonPoints() {
assertFeatures(14, List.of(), process(lineFeature(Map.of(
"aeroway", "aerodrome"
))));
}
}

View File

@@ -0,0 +1,92 @@
package org.openmaptiles.layers;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
class AerowayTest extends AbstractLayerTest {
@Test
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
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
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"
))));
}
}

View File

@@ -0,0 +1,640 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.newLineString;
import static com.onthegomap.planetiler.TestUtils.rectangle;
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;
import org.openmaptiles.OpenMapTilesProfile;
class BoundaryTest extends AbstractLayerTest {
@Test
void testNaturalEarthCountryBoundaries() {
assertCoversZoomRange(
0, 4, "boundary",
process(SimpleFeature.create(
newLineString(0, 0, 1, 1),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_110m_admin_0_boundary_lines_land",
0
)),
process(SimpleFeature.create(
newLineString(0, 0, 1, 1),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_50m_admin_0_boundary_lines_land",
1
)),
process(SimpleFeature.create(
newLineString(0, 0, 1, 1),
Map.of(),
OpenMapTilesProfile.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)"
),
OpenMapTilesProfile.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)"
),
OpenMapTilesProfile.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)"
),
OpenMapTilesProfile.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)"
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_admin_0_boundary_lines_land",
0
)));
}
@Test
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
),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_admin_1_states_provinces_lines",
0
)));
assertFeatures(0, List.of(Map.of(
"_layer", "boundary",
"_type", "line",
"disputed", 0,
"maritime", 0,
"admin_level", 4,
"_minzoom", 4,
"_maxzoom", 4,
"_buffer", 4d
)), process(SimpleFeature.create(
newLineString(0, 0, 1, 1),
Map.of(
"min_zoom", 7.6d
),
OpenMapTilesProfile.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.9d
),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_admin_1_states_provinces_lines",
0
)));
}
@Test
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
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
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
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
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
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
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
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
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
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
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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.OSM_SOURCE,
null,
4,
profile.preprocessOsmRelation(country2).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList()
)
));
List<FeatureCollector.Feature> features = new ArrayList<>();
profile.finish(OpenMapTilesProfile.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
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(),
OpenMapTilesProfile.OSM_SOURCE,
null,
3,
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList()
)));
List<FeatureCollector.Feature> features = new ArrayList<>();
profile.finish(OpenMapTilesProfile.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
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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.OSM_SOURCE,
null,
3,
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList()
)));
List<FeatureCollector.Feature> features = new ArrayList<>();
profile.finish(OpenMapTilesProfile.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
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(),
OpenMapTilesProfile.OSM_SOURCE,
null,
3,
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList()
)));
List<FeatureCollector.Feature> features = new ArrayList<>();
profile.finish(OpenMapTilesProfile.OSM_SOURCE, new FeatureCollector.Factory(params, stats), features::add);
assertFeatures(0, List.of(Map.of(
"adm0_l", "<null>",
"adm0_r", "<null>"
)), features);
}
@Test
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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.OSM_SOURCE,
null,
3,
profile.preprocessOsmRelation(country1).stream().map(r -> new OsmReader.RelationMember<>("", r))
.toList()
)));
List<FeatureCollector.Feature> features = new ArrayList<>();
profile.finish(OpenMapTilesProfile.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);
}
}

View File

@@ -0,0 +1,179 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.rectangle;
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.Assertions;
import org.junit.jupiter.api.Test;
import org.openmaptiles.OpenMapTilesProfile;
class BuildingTest extends AbstractLayerTest {
@Test
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
void testIgnoreUndergroundBuilding() {
assertFeatures(14, List.of(), process(polygonFeature(Map.of(
"building", "yes",
"location", "underground"
))));
}
@Test
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
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
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"
),
OpenMapTilesProfile.OSM_SOURCE,
null,
0,
relationInfos
)));
}
@Test
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
);
Assertions.assertEquals(
2,
profile.postProcessLayerFeatures(Building.LAYER_NAME, 14, List.of(poly1, poly2)).size()
);
Assertions.assertEquals(
1,
profile.postProcessLayerFeatures(Building.LAYER_NAME, 13, List.of(poly1, poly2)).size()
);
}
@Test
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"
))));
}
}

View File

@@ -0,0 +1,30 @@
package org.openmaptiles.layers;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
class HousenumberTest extends AbstractLayerTest {
@Test
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"
))));
}
}

View File

@@ -0,0 +1,209 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.rectangle;
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.Assertions;
import org.junit.jupiter.api.Test;
import org.openmaptiles.OpenMapTilesProfile;
class LandcoverTest extends AbstractLayerTest {
@Test
void testNaturalEarthGlaciers() {
var glacier1 = process(SimpleFeature.create(
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_110m_glaciated_areas",
0
));
var glacier2 = process(SimpleFeature.create(
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_50m_glaciated_areas",
0
));
var glacier3 = process(SimpleFeature.create(
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
Map.of(),
OpenMapTilesProfile.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
void testNaturalEarthAntarcticIceShelves() {
var ice1 = process(SimpleFeature.create(
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_50m_antarctic_ice_shelves_polys",
0
));
var ice2 = process(SimpleFeature.create(
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
Map.of(),
OpenMapTilesProfile.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
void testOsmLandcover() {
assertFeatures(13, List.of(Map.of(
"_layer", "landcover",
"subclass", "wood",
"class", "wood",
"_minpixelsize", 8d,
"_numpointsattr", "_numpoints",
"_minzoom", 7,
"_maxzoom", 14
)), process(polygonFeature(Map.of(
"natural", "wood"
))));
assertFeatures(12, List.of(Map.of(
"_layer", "landcover",
"subclass", "forest",
"class", "wood",
"_minpixelsize", 8d,
"_minzoom", 7,
"_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"
))));
assertFeatures(10, List.of(), process(polygonFeature(Map.of(
"landuse", "park"
))));
}
@Test
void testMergeForestsBuNumPointsZ9to13() throws GeometryException {
Map<String, Object> map = Map.of("subclass", "wood");
assertMerges(List.of(map, map, map, map, map, map), List.of(
// don't merge any
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), List.of(
// < 300 - merge
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")),
// >= 300 - don't merge
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), List.of(
// < 300 - merge
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")),
// >= 300 - merge
feature(rectangle(12, 18), Map.of("_numpoints", 300, "subclass", "wood")),
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood"))
), 9);
}
@Test
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 {
Assertions.assertEquals(expected,
profile.postProcessLayerFeatures("landcover", zoom, in).stream().map(
VectorTile.Feature::attrs)
.toList());
}
}

View File

@@ -0,0 +1,94 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.rectangle;
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;
import org.openmaptiles.OpenMapTilesProfile;
class LanduseTest extends AbstractLayerTest {
@Test
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),
OpenMapTilesProfile.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),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_50m_urban_areas",
0
)));
}
@Test
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
void testGraveYardBecomesCemetery() {
assertFeatures(14, List.of(
Map.of("_layer", "poi"),
Map.of(
"_layer", "landuse",
"class", "cemetery"
)), process(polygonFeature(Map.of(
"amenity", "grave_yard"
))));
}
@Test
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"
))));
}
}

View File

@@ -0,0 +1,323 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.newPoint;
import static com.onthegomap.planetiler.TestUtils.rectangle;
import com.google.common.collect.Lists;
import com.onthegomap.planetiler.VectorTile;
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.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openmaptiles.OpenMapTilesProfile;
class MountainPeakTest extends AbstractLayerTest {
@BeforeEach
public void setupWikidataTranslation() {
wikidataTranslations.put(123, "es", "es wd name");
}
@Test
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,
"customary_ft", "<null>",
"_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
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
void testVolcano() {
assertFeatures(14, List.of(Map.of(
"class", "volcano"
)), process(pointFeature(Map.of(
"natural", "volcano",
"ele", "100"
))));
}
@Test
void testElevationFeet() {
assertFeatures(14, List.of(Map.of(
"class", "volcano",
"ele", 30,
"ele_ft", 100
)), process(pointFeature(Map.of(
"natural", "volcano",
"ele", "100'"
))));
}
@Test
void testElevationFeetInches() {
assertFeatures(14, List.of(Map.of(
"class", "volcano",
"ele", 31,
"ele_ft", 101
)), process(pointFeature(Map.of(
"natural", "volcano",
"ele", "100' 11\""
))));
}
@Test
void testSaddle() {
assertFeatures(14, List.of(Map.of(
"class", "saddle"
)), process(pointFeature(Map.of(
"natural", "saddle",
"ele", "100"
))));
}
@Test
void testNoElevation() {
assertFeatures(14, List.of(), process(pointFeature(Map.of(
"natural", "volcano"
))));
}
@Test
void testBogusElevation() {
assertFeatures(14, List.of(), process(pointFeature(Map.of(
"natural", "volcano",
"ele", "11000"
))));
}
@Test
void testIgnorePeakLines() {
assertFeatures(14, List.of(), process(lineFeature(Map.of(
"natural", "peak",
"name", "name",
"ele", "100"
))));
}
@Test
void testMountainLinestring() {
assertFeatures(14, List.of(Map.of(
"class", "ridge",
"name", "Ridge",
"_layer", "mountain_peak",
"_type", "line",
"_minzoom", 13,
"_maxzoom", 14,
"_buffer", 100d
)), process(lineFeature(Map.of(
"natural", "ridge",
"name", "Ridge"
))));
}
@Test
void testCustomaryFt() {
process(SimpleFeature.create(
rectangle(0, 0.1),
Map.of("iso_a2", "US"),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_admin_0_countries",
0
));
// inside US - customary_ft=1
assertFeatures(14, List.of(Map.of(
"class", "volcano",
"customary_ft", 1,
"ele", 100,
"ele_ft", 328
)), process(SimpleFeature.create(
newPoint(0, 0),
new HashMap<>(Map.<String, Object>of(
"natural", "volcano",
"ele", "100"
)),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
)));
// outside US - customary_ft omitted
assertFeatures(14, List.of(Map.of(
"class", "volcano",
"customary_ft", "<null>",
"ele", 100,
"ele_ft", 328
)), process(SimpleFeature.create(
newPoint(1, 1),
new HashMap<>(Map.<String, Object>of(
"natural", "volcano",
"ele", "100"
)),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
)));
}
private int getSortKey(Map<String, Object> tags) {
return process(pointFeature(Map.of(
"natural", "peak",
"ele", "100"
))).iterator().next().getSortKey();
}
@Test
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
void testMountainPeakPostProcessing() throws GeometryException {
Assertions.assertEquals(List.of(), profile.postProcessLayerFeatures(MountainPeak.LAYER_NAME, 13, List.of()));
Assertions.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
))));
Assertions.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
void testMountainPeakPostProcessingLimitsFeaturesOutsideZoom() throws GeometryException {
Assertions.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
)
)));
}
}

View File

@@ -0,0 +1,135 @@
package org.openmaptiles.layers;
import com.onthegomap.planetiler.geo.GeoUtils;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
class ParkTest extends AbstractLayerTest {
@Test
void testNationalPark() {
assertFeatures(13, List.of(Map.of(
"_layer", "park",
"_type", "polygon",
"class", "national_park",
"name", "Grand Canyon National Park",
"_minpixelsize", 2d,
"_minzoom", 4,
"_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", // don't include all translations
"_minzoom", 5,
"_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
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", "Small park",
"_minpixelsize", 2d,
"_minzoom", 4,
"_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", 5,
"_maxzoom", 14
)), process(polygonFeatureWithArea(1, Map.of(
"boundary", "protected_area",
"name", "Small park",
"wikidata", "Q123"
))));
}
@Test
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();
}
}

View File

@@ -0,0 +1,521 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.newPoint;
import static com.onthegomap.planetiler.TestUtils.rectangle;
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.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.Assertions;
import org.junit.jupiter.api.Test;
import org.openmaptiles.OpenMapTilesProfile;
class PlaceTest extends AbstractLayerTest {
@Test
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
void testCountry() {
wikidataTranslations.put(30, "es", "Estados Unidos");
process(SimpleFeature.create(
rectangle(0, 0.25),
Map.of(
"name", "United States",
"scalerank", 0,
"labelrank", 2
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
)));
}
@Test
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
),
OpenMapTilesProfile.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", 8,
"labelrank", 8,
"datarank", 1
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
)));
}
@Test
void testProvince() {
wikidataTranslations.put(95027, "es", "provincia de Lugo");
process(SimpleFeature.create(
rectangle(0, 0.25),
Map.of(
"name", "Nova Scotia",
"scalerank", 3,
"labelrank", 3,
"datarank", 3
),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_admin_1_states_provinces",
0
));
assertFeatures(4, List.of(Map.of(
"_layer", "place",
"class", "province",
"name", "Lugo",
"name:es", "provincia de Lugo",
"rank", 3,
"_type", "point",
"_minzoom", 2
)), process(SimpleFeature.create(
newPoint(0.1, 0.1),
Map.of(
"place", "province",
"wikidata", "Q95027",
"name", "Lugo"
),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
)));
}
@Test
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
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
void testPlaceSortKeyRanking() {
int[] sortKeys = new int[]{
// max
Place.getSortKey(0, Place.PlaceType.CITY, 1_000_000_000, "name"),
Place.getSortKey(0, Place.PlaceType.CITY, 1_000_000_000, "name longer"),
Place.getSortKey(0, Place.PlaceType.CITY, 1_000_000_000, "x".repeat(32)),
Place.getSortKey(0, Place.PlaceType.CITY, 10_000_000, "name"),
Place.getSortKey(0, Place.PlaceType.CITY, 0, "name"),
Place.getSortKey(0, Place.PlaceType.TOWN, 1_000_000_000, "name"),
Place.getSortKey(0, Place.PlaceType.ISOLATED_DWELLING, 1_000_000_000, "name"),
Place.getSortKey(0, null, 1_000_000_000, "name"),
Place.getSortKey(1, Place.PlaceType.CITY, 1_000_000_000, "name"),
Place.getSortKey(10, Place.PlaceType.CITY, 1_000_000_000, "name"),
Place.getSortKey(null, Place.PlaceType.CITY, 1_000_000_000, "name"),
// min
Place.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
void testCountryCapital() {
process(SimpleFeature.create(
newPoint(0, 0),
Map.of(
"name", "Washington, D.C.",
"scalerank", 0,
"wikidataid", "Q61"
),
OpenMapTilesProfile.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
void testStateCapital() {
process(SimpleFeature.create(
newPoint(0, 0),
Map.of(
"name", "Boston",
"scalerank", 2,
"wikidataid", "Q100"
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.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
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
void testCitySetRankFromGridrank() throws GeometryException {
var layerName = Place.LAYER_NAME;
Assertions.assertEquals(List.of(), profile.postProcessLayerFeatures(layerName, 13, List.of()));
Assertions.assertEquals(List.of(pointFeature(
layerName,
Map.of("rank", 11),
1
)), profile.postProcessLayerFeatures(layerName, 13, List.of(pointFeature(
layerName,
Map.of(),
1
))));
Assertions.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
)
)));
}
}

View File

@@ -0,0 +1,239 @@
package org.openmaptiles.layers;
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.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
class PoiTest extends AbstractLayerTest {
private SourceFeature feature(boolean area, Map<String, Object> tags) {
return area ? polygonFeature(tags) : pointFeature(tags);
}
@Test
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})
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})
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})
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
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})
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})
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
void testGridRank() throws GeometryException {
var layerName = Poi.LAYER_NAME;
Assertions.assertEquals(List.of(), profile.postProcessLayerFeatures(layerName, 13, List.of()));
Assertions.assertEquals(List.of(pointFeature(
layerName,
Map.of("rank", 1),
1
)), profile.postProcessLayerFeatures(layerName, 14, List.of(pointFeature(
layerName,
Map.of(),
1
))));
Assertions.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
)
)));
}
@Test
void testEmbassy() {
assertFeatures(7, List.of(Map.of(
"_layer", "poi",
"class", "diplomatic",
"subclass", "diplomatic",
"name", "The Embassy"
)), process(pointFeature(Map.of(
"office", "diplomatic",
"name", "The Embassy"
))));
}
@Test
void testLocksmith() {
assertFeatures(7, List.of(Map.of(
"_layer", "poi",
"class", "shop",
"subclass", "locksmith",
"name", "The Locksmith"
)), process(pointFeature(Map.of(
"shop", "locksmith",
"name", "The Locksmith"
))));
}
@Test
void testAtm() {
List<Map<String, Object>> expected = List.of(Map.of(
"_layer", "poi",
"class", "atm",
"subclass", "atm",
"name", "ATM name"
));
// prefer name, otherwise fall back to operator, or else network
assertFeatures(14, expected, process(pointFeature(Map.of(
"amenity", "atm",
"name", "ATM name"
))));
assertFeatures(14, expected, process(pointFeature(Map.of(
"amenity", "atm",
"name", "ATM name",
"operator", "ATM operator",
"network", "ATM network"
))));
assertFeatures(14, expected, process(pointFeature(Map.of(
"amenity", "atm",
"operator", "ATM name",
"network", "ATM network"
))));
assertFeatures(14, expected, process(pointFeature(Map.of(
"amenity", "atm",
"network", "ATM name"
))));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.newLineString;
import static com.onthegomap.planetiler.TestUtils.rectangle;
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;
import org.locationtech.jts.geom.Geometry;
import org.openmaptiles.OpenMapTilesProfile;
class WaterNameTest extends AbstractLayerTest {
@Test
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
void testWaterNameLakeline() {
assertFeatures(11, List.of(), process(SimpleFeature.create(
newLineString(0, 0, 1, 1),
new HashMap<>(Map.<String, Object>of(
"OSM_ID", -10
)),
OpenMapTilesProfile.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"
)),
OpenMapTilesProfile.OSM_SOURCE,
null,
10
)));
}
@Test
void testWaterNameMultipleLakelines() {
assertFeatures(11, List.of(), process(SimpleFeature.create(
newLineString(0, 0, 1, 1),
new HashMap<>(Map.<String, Object>of(
"OSM_ID", -10
)),
OpenMapTilesProfile.LAKE_CENTERLINE_SOURCE,
null,
0
)));
assertFeatures(11, List.of(), process(SimpleFeature.create(
newLineString(2, 2, 3, 3),
new HashMap<>(Map.<String, Object>of(
"OSM_ID", -10
)),
OpenMapTilesProfile.LAKE_CENTERLINE_SOURCE,
null,
0
)));
assertFeatures(10, List.of(Map.of(
"_layer", "water"
), Map.of(
"name", "waterway",
"name:es", "waterway es",
"_layer", "water_name",
"_geom",
new TestUtils.NormGeometry(
GeoUtils.latLonToWorldCoords(GeoUtils.JTS_FACTORY.createGeometryCollection(new Geometry[]{
newLineString(0, 0, 1, 1),
newLineString(2, 2, 3, 3)
}))),
"_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"
)),
OpenMapTilesProfile.OSM_SOURCE,
null,
10
)));
}
@Test
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"
)),
OpenMapTilesProfile.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"
))));
}
}

View File

@@ -0,0 +1,280 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.rectangle;
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;
import org.openmaptiles.OpenMapTilesProfile;
class WaterTest extends AbstractLayerTest {
@Test
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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.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(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_ocean",
0
)));
}
@Test
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(),
OpenMapTilesProfile.WATER_POLYGON_SOURCE,
null,
0
)));
}
@Test
void testWaterOsmId() {
long id = 123;
assertFeatures(14, List.of(Map.of(
"class", "lake",
"id", id,
"_layer", "water",
"_type", "polygon",
"_minzoom", 6,
"_maxzoom", 14
)), process(SimpleFeature.create(
GeoUtils.worldToLatLonCoords(rectangle(0, Math.sqrt(1))),
new HashMap<>(Map.<String, Object>of(
"natural", "water",
"water", "reservoir"
)),
OpenMapTilesProfile.OSM_SOURCE,
null,
id
)));
}
@Test
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", "swimming_pool",
"_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", "riverbank",
"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
void testRiverbank() {
assertFeatures(11, List.of(Map.of(
"class", "river",
"_layer", "water",
"_type", "polygon"
)), process(polygonFeature(Map.of(
"waterway", "riverbank"
))));
}
@Test
void testRiver() {
assertFeatures(11, List.of(Map.of(
"class", "river",
"_layer", "water",
"_type", "polygon"
)), process(polygonFeature(Map.of(
"water", "river"
))));
}
@Test
void testSpring() {
assertFeatures(11, List.of(Map.of(
"class", "lake",
"_layer", "water",
"_type", "polygon"
)), process(polygonFeature(Map.of(
"natural", "spring"
))));
}
@Test
void testOceanZoomLevels() {
assertCoversZoomRange(0, 14, "water",
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_110m_ocean",
0
)),
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_50m_ocean",
0
)),
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_ocean",
0
)),
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(),
OpenMapTilesProfile.WATER_POLYGON_SOURCE,
null,
0
))
);
}
@Test
void testLakeZoomLevels() {
assertCoversZoomRange(0, 14, "water",
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_110m_lakes",
0
)),
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_50m_lakes",
0
)),
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_10m_lakes",
0
)),
process(SimpleFeature.create(
rectangle(0, 10),
Map.of(
"natural", "water",
"water", "reservoir"
),
OpenMapTilesProfile.OSM_SOURCE,
null,
0
))
);
}
}

View File

@@ -0,0 +1,235 @@
package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.newLineString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.VectorTile;
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 com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
import java.util.ArrayList;
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;
import org.openmaptiles.OpenMapTilesProfile;
class WaterwayTest extends AbstractLayerTest {
@ParameterizedTest
@ValueSource(booleans = {false, true})
void testOsmWaterwayRelation(boolean isLongEnough) throws GeometryException {
var rel = new OsmElement.Relation(1);
rel.setTag("name", "River Relation");
rel.setTag("name:es", "ES name");
rel.setTag("waterway", "river");
List<OsmRelationInfo> relationInfos = profile.preprocessOsmRelation(rel);
FeatureCollector features = process(SimpleFeature.createFakeOsmFeature(
newLineString(0, 0, 0, isLongEnough ? 3 : 1),
Map.of(),
OpenMapTilesProfile.OSM_SOURCE,
null,
0,
(relationInfos == null ? List.<OsmRelationInfo>of() : relationInfos).stream()
.map(r -> new OsmReader.RelationMember<>("", r)).toList()
));
assertFeatures(14, List.of(Map.of(
"class", "river",
"name", "River Relation",
"name:es", "ES name",
"_relid", 1L,
"_layer", "waterway",
"_type", "line",
"_minzoom", 6,
"_maxzoom", 8,
"_buffer", 4d
)), features);
// ensure that post-processing combines waterways, and filters out ones that
// belong to rivers that are not long enough to be shown
var line1 = new VectorTile.Feature(
Waterway.LAYER_NAME,
1,
VectorTile.encodeGeometry(newLineString(0, 0, 10, 0)),
mapOf("name", "river", "_relid", 1L),
0
);
var line2 = new VectorTile.Feature(
Waterway.LAYER_NAME,
1,
VectorTile.encodeGeometry(newLineString(10, 0, 20, 0)),
mapOf("name", "river", "_relid", 1L),
0
);
var connected = new VectorTile.Feature(
Waterway.LAYER_NAME,
1,
VectorTile.encodeGeometry(newLineString(0, 0, 20, 0)),
mapOf("name", "river"),
0
);
assertEquals(
isLongEnough ? List.of(connected) : List.of(),
profile.postProcessLayerFeatures(Waterway.LAYER_NAME, 8, new ArrayList<>(List.of(line1, line2)))
);
}
@Test
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
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
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
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"
),
OpenMapTilesProfile.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"
),
OpenMapTilesProfile.NATURAL_EARTH_SOURCE,
"ne_50m_rivers_lake_centerlines",
0
)));
}
}