Upgrade planetiler-basemap to be compatible with OpenMapTiles 3.13 (#49)

Applying changes to layers from [OpenMapTiles 3.13 release](https://github.com/openmaptiles/openmaptiles/releases/tag/v3.13) (https://github.com/openmaptiles/openmaptiles/compare/v3.12.2...v3.13), minus transportation network connectivity improvements - those will be a separate change.
This commit is contained in:
Michael Barry
2022-01-19 05:36:44 -05:00
committed by GitHub
parent 8e49c0831c
commit 0baaf8d886
37 changed files with 1690 additions and 464 deletions

View File

@@ -7,10 +7,10 @@ See [README.md](../README.md) in the parent directory for instructions on how to
- Road name abbreviations are not implemented yet in the `transportation_name` layer - Road name abbreviations are not implemented yet in the `transportation_name` layer
- `agg_stop` tag not implemented yet in the `poi` layer - `agg_stop` tag not implemented yet in the `poi` layer
- Paths are visible at z13 and z14 in `transportation` and `transportation_name` layers instead of just z14 in
OpenMapTiles, to revert this behavior set `--transportation-z13-paths=false`
- `brunnel` tag is excluded from `transportation_name` layer to avoid breaking apart long `transportation_name` - `brunnel` tag is excluded from `transportation_name` layer to avoid breaking apart long `transportation_name`
lines, to revert this behavior set `--transportation-name-brunnel=true` lines, to revert this behavior set `--transportation-name-brunnel=true`
- `rank` field on `mountain_peak` linestrings only has 3 levels (1: has wikipedia page and name, 2: has name, 3: no name
or wikipedia page or name)
## Code Layout ## Code Layout

View File

@@ -10,6 +10,8 @@ import com.onthegomap.planetiler.Planetiler;
import com.onthegomap.planetiler.Profile; import com.onthegomap.planetiler.Profile;
import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema; import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema;
import com.onthegomap.planetiler.basemap.generated.Tables; import com.onthegomap.planetiler.basemap.generated.Tables;
import com.onthegomap.planetiler.basemap.layers.Transportation;
import com.onthegomap.planetiler.basemap.layers.TransportationName;
import com.onthegomap.planetiler.config.PlanetilerConfig; import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.expression.MultiExpression; import com.onthegomap.planetiler.expression.MultiExpression;
import com.onthegomap.planetiler.reader.SimpleFeature; import com.onthegomap.planetiler.reader.SimpleFeature;
@@ -61,10 +63,27 @@ public class BasemapProfile extends ForwardingProfile {
// register release/finish/feature postprocessor/osm relationship handler methods... // register release/finish/feature postprocessor/osm relationship handler methods...
List<Handler> layers = new ArrayList<>(); List<Handler> layers = new ArrayList<>();
Transportation transportationLayer = null;
TransportationName transportationNameLayer = null;
for (Layer layer : OpenMapTilesSchema.createInstances(translations, config, stats)) { for (Layer layer : OpenMapTilesSchema.createInstances(translations, config, stats)) {
if ((onlyLayers.isEmpty() || onlyLayers.contains(layer.name())) && !excludeLayers.contains(layer.name())) { if ((onlyLayers.isEmpty() || onlyLayers.contains(layer.name())) && !excludeLayers.contains(layer.name())) {
layers.add(layer); layers.add(layer);
registerHandler(layer); registerHandler(layer);
if (layer instanceof TransportationName transportationName) {
transportationNameLayer = transportationName;
}
}
if (layer instanceof Transportation transportation) {
transportationLayer = transportation;
}
}
// special-case: transportation_name layer depends on transportation layer
if (transportationNameLayer != null) {
transportationNameLayer.needsTransportationLayer(transportationLayer);
if (!layers.contains(transportationLayer)) {
layers.add(transportationLayer);
registerHandler(transportationLayer);
} }
} }

View File

@@ -58,7 +58,7 @@ public class Generate {
private static final String LINE_SEPARATOR = System.lineSeparator(); private static final String LINE_SEPARATOR = System.lineSeparator();
private static final String GENERATED_FILE_HEADER = """ private static final String GENERATED_FILE_HEADER = """
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -690,12 +690,12 @@ public class Generate {
* Models for deserializing yaml into: * Models for deserializing yaml into:
*/ */
private static record OpenmaptilesConfig( private record OpenmaptilesConfig(
OpenmaptilesTileSet tileset OpenmaptilesTileSet tileset
) {} ) {}
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
private static record OpenmaptilesTileSet( private record OpenmaptilesTileSet(
List<String> layers, List<String> layers,
String version, String version,
String attribution, String attribution,
@@ -705,51 +705,52 @@ public class Generate {
) {} ) {}
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
private static record LayerDetails( private record LayerDetails(
String id, String id,
String description, String description,
Map<String, JsonNode> fields, Map<String, JsonNode> fields,
double buffer_size double buffer_size
) {} ) {}
private static record Datasource( private record Datasource(
String type, String type,
String mapping_file String mapping_file
) {} ) {}
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
private static record LayerConfig( private record LayerConfig(
LayerDetails layer, LayerDetails layer,
List<Datasource> datasources List<Datasource> datasources
) {} ) {}
private static record Imposm3Column( private record Imposm3Column(
String type, String type,
String name, String name,
String key, String key,
boolean from_member boolean from_member
) {} ) {}
static record Imposm3Filters( record Imposm3Filters(
JsonNode reject, JsonNode reject,
JsonNode require JsonNode require
) {} ) {}
static record Imposm3Table( record Imposm3Table(
String type, String type,
@JsonProperty("_resolve_wikidata") boolean resolveWikidata, @JsonProperty("_resolve_wikidata") boolean resolveWikidata,
List<Imposm3Column> columns, List<Imposm3Column> columns,
Imposm3Filters filters, Imposm3Filters filters,
JsonNode mapping, JsonNode mapping,
Map<String, JsonNode> type_mappings Map<String, JsonNode> type_mappings,
@JsonProperty("relation_types") List<String> relationTypes
) {} ) {}
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
private static record Imposm3Mapping( private record Imposm3Mapping(
Map<String, Imposm3Table> tables Map<String, Imposm3Table> tables
) {} ) {}
private static record OsmTableField( private record OsmTableField(
String clazz, String clazz,
String name, String name,
String extractCode String extractCode

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -52,16 +52,15 @@ import java.util.Set;
/** /**
* All vector tile layer definitions, attributes, and allowed values generated from the * All vector tile layer definitions, attributes, and allowed values generated from the
* <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/openmaptiles.yaml">OpenMapTiles vector tile * <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/openmaptiles.yaml">OpenMapTiles vector tile schema
* schema * v3.13</a>.
* v3.12.2</a>.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class OpenMapTilesSchema { public class OpenMapTilesSchema {
public static final String NAME = "OpenMapTiles"; public static final String NAME = "OpenMapTiles";
public static final String DESCRIPTION = "A tileset showcasing all layers in OpenMapTiles. https://openmaptiles.org"; public static final String DESCRIPTION = "A tileset showcasing all layers in OpenMapTiles. https://openmaptiles.org";
public static final String VERSION = "3.12.1"; public static final String VERSION = "3.13.0";
public static final String ATTRIBUTION = "<a href=\"https://www.openmaptiles.org/\" target=\"_blank\">&copy; OpenMapTiles</a> <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">&copy; OpenStreetMap contributors</a>"; public static final String ATTRIBUTION = "<a href=\"https://www.openmaptiles.org/\" target=\"_blank\">&copy; OpenMapTiles</a> <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">&copy; OpenStreetMap contributors</a>";
public static final List<String> LANGUAGES = List.of("am", "ar", "az", "be", "bg", "br", "bs", "ca", "co", "cs", "cy", public static final List<String> LANGUAGES = List.of("am", "ar", "az", "be", "bg", "br", "bs", "ca", "co", "cs", "cy",
"da", "de", "el", "en", "eo", "es", "et", "eu", "fi", "fr", "fy", "ga", "gd", "he", "hi", "hr", "hu", "hy", "id", "da", "de", "el", "en", "eo", "es", "et", "eu", "fi", "fr", "fy", "ga", "gd", "he", "hi", "hr", "hu", "hy", "id",
@@ -99,7 +98,7 @@ public class OpenMapTilesSchema {
* polygons to improve rendering performance. This however can lead to less rendering options in clients since these * polygons to improve rendering performance. This however can lead to less rendering options in clients since these
* boundaries show up. So you might not be able to use border styling for ocean water features. * boundaries show up. So you might not be able to use border styling for ocean water features.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/water/water.yaml">water.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/water/water.yaml">water.yaml</a>
*/ */
public interface Water extends Layer { public interface Water extends Layer {
@@ -116,14 +115,16 @@ public class OpenMapTilesSchema {
/** /**
* All water polygons from <a href="http://osmdata.openstreetmap.de/">OpenStreetMapData</a> have the class * All water polygons from <a href="http://osmdata.openstreetmap.de/">OpenStreetMapData</a> have the class
* <code>ocean</code>. Water bodies are classified as <code>lake</code> or <code>river</code> for water bodies * <code>ocean</code>. Water bodies with the <a href="http://wiki.openstreetmap.org/wiki/Tag:waterway=riverbank"><code>waterway=riverbank</code></a>
* with the <a href="http://wiki.openstreetmap.org/wiki/Key:waterway"><code>waterway</code></a> tag. * or <a href="http://wiki.openstreetmap.org/wiki/Tag:water=river"><code>water=river</code></a> tag are classified
* as river. Wet and dry docks tagged <a href="http://wiki.openstreetmap.org/wiki/Tag:waterway=dock"><code>waterway=dock</code></a>
* are classified as a <code>dock</code>. All other water bodies are classified as <code>lake</code>.
* <p> * <p>
* allowed values: * allowed values:
* <ul> * <ul>
* <li>lake
* <li>dock * <li>dock
* <li>river * <li>river
* <li>lake
* <li>ocean * <li>ocean
* </ul> * </ul>
*/ */
@@ -156,11 +157,11 @@ public class OpenMapTilesSchema {
/** Attribute values for map elements in the water layer. */ /** Attribute values for map elements in the water layer. */
final class FieldValues { final class FieldValues {
public static final String CLASS_LAKE = "lake";
public static final String CLASS_DOCK = "dock"; public static final String CLASS_DOCK = "dock";
public static final String CLASS_RIVER = "river"; public static final String CLASS_RIVER = "river";
public static final String CLASS_LAKE = "lake";
public static final String CLASS_OCEAN = "ocean"; public static final String CLASS_OCEAN = "ocean";
public static final Set<String> CLASS_VALUES = Set.of("lake", "dock", "river", "ocean"); public static final Set<String> CLASS_VALUES = Set.of("dock", "river", "lake", "ocean");
public static final String BRUNNEL_BRIDGE = "bridge"; public static final String BRUNNEL_BRIDGE = "bridge";
public static final String BRUNNEL_TUNNEL = "tunnel"; public static final String BRUNNEL_TUNNEL = "tunnel";
public static final Set<String> BRUNNEL_VALUES = Set.of("bridge", "tunnel"); public static final Set<String> BRUNNEL_VALUES = Set.of("bridge", "tunnel");
@@ -170,9 +171,9 @@ public class OpenMapTilesSchema {
final class FieldMappings { final class FieldMappings {
public static final MultiExpression<String> Class = MultiExpression.of( public static final MultiExpression<String> Class = MultiExpression.of(
List.of(MultiExpression.entry("lake", matchAny("waterway", "", "lake")), List.of(MultiExpression.entry("dock", matchAny("waterway", "dock")),
MultiExpression.entry("dock", matchAny("waterway", "dock")), MultiExpression.entry("river", FALSE), MultiExpression.entry("river", or(matchAny("water", "river"), matchAny("waterway", "riverbank"))),
MultiExpression.entry("ocean", FALSE))); MultiExpression.entry("lake", matchAny("waterway", "")), MultiExpression.entry("ocean", FALSE)));
} }
} }
@@ -183,7 +184,7 @@ public class OpenMapTilesSchema {
* there is also <code>canal</code> generated, starting z13 there is no generalization according to <code>class</code> * there is also <code>canal</code> generated, starting z13 there is no generalization according to <code>class</code>
* field applied. Waterways do not have a <code>subclass</code> field. * field applied. Waterways do not have a <code>subclass</code> field.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/waterway/waterway.yaml">waterway.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/waterway/waterway.yaml">waterway.yaml</a>
*/ */
public interface Waterway extends Layer { public interface Waterway extends Layer {
@@ -273,7 +274,7 @@ public class OpenMapTilesSchema {
* href="http://wiki.openstreetmap.org/wiki/Landcover">implied by OSM tags</a>. The most common use case for this * href="http://wiki.openstreetmap.org/wiki/Landcover">implied by OSM tags</a>. The most common use case for this
* layer is to style wood (<code>class=wood</code>) and grass (<code>class=grass</code>) areas. * layer is to style wood (<code>class=wood</code>) and grass (<code>class=grass</code>) areas.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/landcover/landcover.yaml">landcover.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/landcover/landcover.yaml">landcover.yaml</a>
*/ */
public interface Landcover extends Layer { public interface Landcover extends Layer {
@@ -428,7 +429,7 @@ public class OpenMapTilesSchema {
* Landuse is used to describe use of land by humans. At lower zoom levels this is from Natural Earth data for * Landuse is used to describe use of land by humans. At lower zoom levels this is from Natural Earth data for
* residential (urban) areas and at higher zoom levels mostly OSM <code>landuse</code> tags. * residential (urban) areas and at higher zoom levels mostly OSM <code>landuse</code> tags.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/landuse/landuse.yaml">landuse.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/landuse/landuse.yaml">landuse.yaml</a>
*/ */
public interface Landuse extends Layer { public interface Landuse extends Layer {
@@ -527,7 +528,7 @@ public class OpenMapTilesSchema {
/** /**
* <a href="http://wiki.openstreetmap.org/wiki/Tag:natural%3Dpeak">Natural peaks</a> * <a href="http://wiki.openstreetmap.org/wiki/Tag:natural%3Dpeak">Natural peaks</a>
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/mountain_peak/mountain_peak.yaml">mountain_peak.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/mountain_peak/mountain_peak.yaml">mountain_peak.yaml</a>
*/ */
public interface MountainPeak extends Layer { public interface MountainPeak extends Layer {
@@ -556,13 +557,27 @@ public class OpenMapTilesSchema {
* <ul> * <ul>
* <li>"peak" * <li>"peak"
* <li>"volcano" * <li>"volcano"
* <li>"ridge"
* <li>"cliff"
* <li>"arete"
* </ul> * </ul>
*/ */
public static final String CLASS = "class"; public static final String CLASS = "class";
/** Elevation (<code>ele</code>) in meters. */ /** Elevation (<code>ele</code>) in meters. */
public static final String ELE = "ele"; public static final String ELE = "ele";
/** Elevation (<code>ele</code>) in feets. */ /** Elevation (<code>ele</code>) in feet. */
public static final String ELE_FT = "ele_ft"; public static final String ELE_FT = "ele_ft";
/**
* Value 1 for peaks in location where feet is used as customary unit (USA).
* <p>
* allowed values:
* <ul>
* <li>1
* <li>null
* </ul>
*/
public static final String CUSTOMARY_FT = "customary_ft";
/** Rank of the peak within one tile (starting at 1 that is the most important peak). */ /** Rank of the peak within one tile (starting at 1 that is the most important peak). */
public static final String RANK = "rank"; public static final String RANK = "rank";
} }
@@ -572,7 +587,10 @@ public class OpenMapTilesSchema {
public static final String CLASS_PEAK = "peak"; public static final String CLASS_PEAK = "peak";
public static final String CLASS_VOLCANO = "volcano"; public static final String CLASS_VOLCANO = "volcano";
public static final Set<String> CLASS_VALUES = Set.of("peak", "volcano"); public static final String CLASS_RIDGE = "ridge";
public static final String CLASS_CLIFF = "cliff";
public static final String CLASS_ARETE = "arete";
public static final Set<String> CLASS_VALUES = Set.of("peak", "volcano", "ridge", "cliff", "arete");
} }
/** Complex mappings to generate attribute values from OSM element tags in the mountain_peak layer. */ /** Complex mappings to generate attribute values from OSM element tags in the mountain_peak layer. */
@@ -586,7 +604,7 @@ public class OpenMapTilesSchema {
* <a href="http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dprotected_area"><code>boundary=protected_area</code></a>, * <a href="http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dprotected_area"><code>boundary=protected_area</code></a>,
* or <a href="http://wiki.openstreetmap.org/wiki/Tag:leisure%3Dnature_reserve"><code>leisure=nature_reserve</code></a>. * or <a href="http://wiki.openstreetmap.org/wiki/Tag:leisure%3Dnature_reserve"><code>leisure=nature_reserve</code></a>.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/park/park.yaml">park.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/park/park.yaml">park.yaml</a>
*/ */
public interface Park extends Layer { public interface Park extends Layer {
@@ -645,7 +663,7 @@ public class OpenMapTilesSchema {
* contains several <a href="http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative#admin_level"><code>admin_level</code></a> * contains several <a href="http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative#admin_level"><code>admin_level</code></a>
* but for most styles it makes sense to just style <code>admin_level=2</code> and <code>admin_level=4</code>. * but for most styles it makes sense to just style <code>admin_level=2</code> and <code>admin_level=4</code>.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/boundary/boundary.yaml">boundary.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/boundary/boundary.yaml">boundary.yaml</a>
*/ */
public interface Boundary extends Layer { public interface Boundary extends Layer {
@@ -751,7 +769,7 @@ public class OpenMapTilesSchema {
* buildings are contained in the <strong>building</strong> layer but all other airport related polygons can be found * buildings are contained in the <strong>building</strong> layer but all other airport related polygons can be found
* in the <strong>aeroway</strong> layer. * in the <strong>aeroway</strong> layer.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/aeroway/aeroway.yaml">aeroway.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/aeroway/aeroway.yaml">aeroway.yaml</a>
*/ */
public interface Aeroway extends Layer { public interface Aeroway extends Layer {
@@ -814,7 +832,7 @@ public class OpenMapTilesSchema {
* roads is the most essential part of the map. The <code>transportation</code> layer also contains polygons for * roads is the most essential part of the map. The <code>transportation</code> layer also contains polygons for
* features like plazas. * features like plazas.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/transportation/transportation.yaml">transportation.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/transportation/transportation.yaml">transportation.yaml</a>
*/ */
public interface Transportation extends Layer { public interface Transportation extends Layer {
@@ -836,7 +854,7 @@ public class OpenMapTilesSchema {
* href="http://wiki.openstreetmap.org/wiki/Key:railway"><code>railway</code></a>, <a * href="http://wiki.openstreetmap.org/wiki/Key:railway"><code>railway</code></a>, <a
* href="http://wiki.openstreetmap.org/wiki/Key:aerialway"><code>aerialway</code></a>, <a * href="http://wiki.openstreetmap.org/wiki/Key:aerialway"><code>aerialway</code></a>, <a
* href="http://wiki.openstreetmap.org/wiki/Key:route"><code>route</code></a> tag (for shipping ways), or <a * href="http://wiki.openstreetmap.org/wiki/Key:route"><code>route</code></a> tag (for shipping ways), or <a
* href="http://wiki.openstreetmap.org/wiki/Key:route"><code>man_made</code></a>. * href="http://wiki.openstreetmap.org/wiki/Key:man_made"><code>man_made</code></a>.
* <p> * <p>
* allowed values: * allowed values:
* <ul> * <ul>
@@ -850,6 +868,7 @@ public class OpenMapTilesSchema {
* <li>service * <li>service
* <li>track * <li>track
* <li>raceway * <li>raceway
* <li>busway
* <li>motorway_construction * <li>motorway_construction
* <li>trunk_construction * <li>trunk_construction
* <li>primary_construction * <li>primary_construction
@@ -892,6 +911,13 @@ public class OpenMapTilesSchema {
* </ul> * </ul>
*/ */
public static final String SUBCLASS = "subclass"; public static final String SUBCLASS = "subclass";
/**
* The network type derived mainly from <a href="http://wiki.openstreetmap.org/wiki/Key:network"><code>network</code></a>
* tag of the road. See more info about <a href="http://wiki.openstreetmap.org/wiki/Road_signs_in_the_United_States"><code>us-
* </code></a>, <a href="https://en.wikipedia.org/wiki/Trans-Canada_Highway"><code>ca-transcanada</code></a>, or
* <a href="http://wiki.openstreetmap.org/wiki/United_Kingdom_Tagging_Guidelines#UK_roads"><code>gb- </code></a>.
*/
public static final String NETWORK = "network";
/** /**
* Mark whether way is a tunnel or bridge. * Mark whether way is a tunnel or bridge.
@@ -944,6 +970,40 @@ public class OpenMapTilesSchema {
* </ul> * </ul>
*/ */
public static final String SERVICE = "service"; public static final String SERVICE = "service";
/**
* Access restrictions on this road. Supported values of the <a href="http://wiki.openstreetmap.org/wiki/Key:access"><code>access</code></a>
* tag are <code>no</code> and <code>private</code>, which resolve to <code>no</code>.
* <p>
* allowed values:
* <ul>
* <li>false
* </ul>
*/
public static final String ACCESS = "access";
/**
* Whether this is a toll road, based on the <a href="http://wiki.openstreetmap.org/wiki/Key:toll"><code>toll</code></a>
* tag.
* <p>
* allowed values:
* <ul>
* <li>0
* <li>1
* </ul>
*/
public static final String TOLL = "toll";
/**
* Whether this is an expressway, based on the <a href="http://wiki.openstreetmap.org/wiki/Key:expressway"><code>expressway</code></a>
* tag.
* <p>
* allowed values:
* <ul>
* <li>1
* </ul>
*/
public static final String EXPRESSWAY = "expressway";
/** Original value of the <a href="http://wiki.openstreetmap.org/wiki/Key:layer"><code>layer</code></a> tag. */ /** Original value of the <a href="http://wiki.openstreetmap.org/wiki/Key:layer"><code>layer</code></a> tag. */
public static final String LAYER = "layer"; public static final String LAYER = "layer";
/** /**
@@ -1012,6 +1072,7 @@ public class OpenMapTilesSchema {
public static final String CLASS_SERVICE = "service"; public static final String CLASS_SERVICE = "service";
public static final String CLASS_TRACK = "track"; public static final String CLASS_TRACK = "track";
public static final String CLASS_RACEWAY = "raceway"; public static final String CLASS_RACEWAY = "raceway";
public static final String CLASS_BUSWAY = "busway";
public static final String CLASS_MOTORWAY_CONSTRUCTION = "motorway_construction"; public static final String CLASS_MOTORWAY_CONSTRUCTION = "motorway_construction";
public static final String CLASS_TRUNK_CONSTRUCTION = "trunk_construction"; public static final String CLASS_TRUNK_CONSTRUCTION = "trunk_construction";
public static final String CLASS_PRIMARY_CONSTRUCTION = "primary_construction"; public static final String CLASS_PRIMARY_CONSTRUCTION = "primary_construction";
@@ -1023,7 +1084,7 @@ public class OpenMapTilesSchema {
public static final String CLASS_TRACK_CONSTRUCTION = "track_construction"; public static final String CLASS_TRACK_CONSTRUCTION = "track_construction";
public static final String CLASS_RACEWAY_CONSTRUCTION = "raceway_construction"; public static final String CLASS_RACEWAY_CONSTRUCTION = "raceway_construction";
public static final Set<String> CLASS_VALUES = Set.of("motorway", "trunk", "primary", "secondary", "tertiary", public static final Set<String> CLASS_VALUES = Set.of("motorway", "trunk", "primary", "secondary", "tertiary",
"minor", "path", "service", "track", "raceway", "motorway_construction", "trunk_construction", "minor", "path", "service", "track", "raceway", "busway", "motorway_construction", "trunk_construction",
"primary_construction", "secondary_construction", "tertiary_construction", "minor_construction", "primary_construction", "secondary_construction", "tertiary_construction", "minor_construction",
"path_construction", "service_construction", "track_construction", "raceway_construction"); "path_construction", "service_construction", "track_construction", "raceway_construction");
public static final String SUBCLASS_RAIL = "rail"; public static final String SUBCLASS_RAIL = "rail";
@@ -1079,7 +1140,7 @@ public class OpenMapTilesSchema {
MultiExpression.entry("service", matchAny("highway", "service")), MultiExpression.entry("service", matchAny("highway", "service")),
MultiExpression.entry("track", matchAny("highway", "track")), MultiExpression.entry("track", matchAny("highway", "track")),
MultiExpression.entry("raceway", matchAny("highway", "raceway")), MultiExpression.entry("raceway", matchAny("highway", "raceway")),
MultiExpression.entry("motorway_construction", MultiExpression.entry("busway", matchAny("highway", "busway")), MultiExpression.entry("motorway_construction",
and(matchAny("highway", "construction"), matchAny("construction", "motorway", "motorway_link"))), and(matchAny("highway", "construction"), matchAny("construction", "motorway", "motorway_link"))),
MultiExpression.entry("trunk_construction", MultiExpression.entry("trunk_construction",
and(matchAny("highway", "construction"), matchAny("construction", "trunk", "trunk_link"))), and(matchAny("highway", "construction"), matchAny("construction", "trunk", "trunk_link"))),
@@ -1107,7 +1168,7 @@ public class OpenMapTilesSchema {
* href="http://wiki.openstreetmap.org/wiki/Key:building"><code>building= </code></a>). The buildings are not yet * href="http://wiki.openstreetmap.org/wiki/Key:building"><code>building= </code></a>). The buildings are not yet
* ready for 3D rendering support and any help to improve this is welcomed. * ready for 3D rendering support and any help to improve this is welcomed.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/building/building.yaml">building.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/building/building.yaml">building.yaml</a>
*/ */
public interface Building extends Layer { public interface Building extends Layer {
@@ -1157,7 +1218,7 @@ public class OpenMapTilesSchema {
* Lake center lines for labelling lake bodies. This is based of the <a href="https://github.com/lukasmartinelli/osm-lakelines">osm-lakelines</a> * Lake center lines for labelling lake bodies. This is based of the <a href="https://github.com/lukasmartinelli/osm-lakelines">osm-lakelines</a>
* project which derives nice centerlines from OSM water bodies. Only the most important lakes contain labels. * project which derives nice centerlines from OSM water bodies. Only the most important lakes contain labels.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/water_name/water_name.yaml">water_name.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/water_name/water_name.yaml">water_name.yaml</a>
*/ */
public interface WaterName extends Layer { public interface WaterName extends Layer {
@@ -1221,7 +1282,7 @@ public class OpenMapTilesSchema {
* placement than having many small linestrings. For motorways you should use the <code>ref</code> field to label them * placement than having many small linestrings. For motorways you should use the <code>ref</code> field to label them
* while for other roads you should use <code>name</code>. * while for other roads you should use <code>name</code>.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/transportation_name/transportation_name.yaml">transportation_name.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/transportation_name/transportation_name.yaml">transportation_name.yaml</a>
*/ */
public interface TransportationName extends Layer { public interface TransportationName extends Layer {
@@ -1299,13 +1360,15 @@ public class OpenMapTilesSchema {
* <li>"raceway_construction" * <li>"raceway_construction"
* <li>"rail" * <li>"rail"
* <li>"transit" * <li>"transit"
* <li>"motorway_junction"
* </ul> * </ul>
*/ */
public static final String CLASS = "class"; public static final String CLASS = "class";
/** /**
* Distinguish more specific classes of path: Subclass is value of the <a href="http://wiki.openstreetmap.org/wiki/Key:highway"><code>highway</code></a> * Distinguish more specific classes of path: Subclass is value of the <a href="http://wiki.openstreetmap.org/wiki/Key:highway"><code>highway</code></a>
* (for paths). * (for paths), and &quot;junction&quot; for <a href="http://wiki.openstreetmap.org/wiki/Tag:highway=motorway_junction"><code>motorway
* junctions</code></a>.
* <p> * <p>
* allowed values: * allowed values:
* <ul> * <ul>
@@ -1317,6 +1380,7 @@ public class OpenMapTilesSchema {
* <li>"bridleway" * <li>"bridleway"
* <li>"corridor" * <li>"corridor"
* <li>"platform" * <li>"platform"
* <li>"junction"
* </ul> * </ul>
*/ */
public static final String SUBCLASS = "subclass"; public static final String SUBCLASS = "subclass";
@@ -1353,6 +1417,18 @@ public class OpenMapTilesSchema {
* </ul> * </ul>
*/ */
public static final String INDOOR = "indoor"; public static final String INDOOR = "indoor";
/** 1st route concurrency. */
public static final String ROUTE_1 = "route_1";
/** 2nd route concurrency. */
public static final String ROUTE_2 = "route_2";
/** 3rd route concurrency. */
public static final String ROUTE_3 = "route_3";
/** 4th route concurrency. */
public static final String ROUTE_4 = "route_4";
/** 5th route concurrency. */
public static final String ROUTE_5 = "route_5";
/** 6th route concurrency. */
public static final String ROUTE_6 = "route_6";
} }
/** Attribute values for map elements in the transportation_name layer. */ /** Attribute values for map elements in the transportation_name layer. */
@@ -1389,10 +1465,12 @@ public class OpenMapTilesSchema {
public static final String CLASS_RACEWAY_CONSTRUCTION = "raceway_construction"; public static final String CLASS_RACEWAY_CONSTRUCTION = "raceway_construction";
public static final String CLASS_RAIL = "rail"; public static final String CLASS_RAIL = "rail";
public static final String CLASS_TRANSIT = "transit"; public static final String CLASS_TRANSIT = "transit";
public static final String CLASS_MOTORWAY_JUNCTION = "motorway_junction";
public static final Set<String> CLASS_VALUES = Set.of("motorway", "trunk", "primary", "secondary", "tertiary", public static final Set<String> CLASS_VALUES = Set.of("motorway", "trunk", "primary", "secondary", "tertiary",
"minor", "service", "track", "path", "raceway", "motorway_construction", "trunk_construction", "minor", "service", "track", "path", "raceway", "motorway_construction", "trunk_construction",
"primary_construction", "secondary_construction", "tertiary_construction", "minor_construction", "primary_construction", "secondary_construction", "tertiary_construction", "minor_construction",
"service_construction", "track_construction", "path_construction", "raceway_construction", "rail", "transit"); "service_construction", "track_construction", "path_construction", "raceway_construction", "rail", "transit",
"motorway_junction");
public static final String SUBCLASS_PEDESTRIAN = "pedestrian"; public static final String SUBCLASS_PEDESTRIAN = "pedestrian";
public static final String SUBCLASS_PATH = "path"; public static final String SUBCLASS_PATH = "path";
public static final String SUBCLASS_FOOTWAY = "footway"; public static final String SUBCLASS_FOOTWAY = "footway";
@@ -1401,8 +1479,9 @@ public class OpenMapTilesSchema {
public static final String SUBCLASS_BRIDLEWAY = "bridleway"; public static final String SUBCLASS_BRIDLEWAY = "bridleway";
public static final String SUBCLASS_CORRIDOR = "corridor"; public static final String SUBCLASS_CORRIDOR = "corridor";
public static final String SUBCLASS_PLATFORM = "platform"; public static final String SUBCLASS_PLATFORM = "platform";
public static final String SUBCLASS_JUNCTION = "junction";
public static final Set<String> SUBCLASS_VALUES = Set.of("pedestrian", "path", "footway", "cycleway", "steps", public static final Set<String> SUBCLASS_VALUES = Set.of("pedestrian", "path", "footway", "cycleway", "steps",
"bridleway", "corridor", "platform"); "bridleway", "corridor", "platform", "junction");
public static final String BRUNNEL_BRIDGE = "bridge"; public static final String BRUNNEL_BRIDGE = "bridge";
public static final String BRUNNEL_TUNNEL = "tunnel"; public static final String BRUNNEL_TUNNEL = "tunnel";
public static final String BRUNNEL_FORD = "ford"; public static final String BRUNNEL_FORD = "ford";
@@ -1422,7 +1501,7 @@ public class OpenMapTilesSchema {
* important layers to create a beautiful map. We suggest you use different font styles and sizes to create a text * important layers to create a beautiful map. We suggest you use different font styles and sizes to create a text
* hierarchy. * hierarchy.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/place/place.yaml">place.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/place/place.yaml">place.yaml</a>
*/ */
public interface Place extends Layer { public interface Place extends Layer {
@@ -1467,6 +1546,7 @@ public class OpenMapTilesSchema {
* <li>"continent" * <li>"continent"
* <li>"country" * <li>"country"
* <li>"state" * <li>"state"
* <li>"province"
* <li>"city" * <li>"city"
* <li>"town" * <li>"town"
* <li>"village" * <li>"village"
@@ -1505,6 +1585,7 @@ public class OpenMapTilesSchema {
public static final String CLASS_CONTINENT = "continent"; public static final String CLASS_CONTINENT = "continent";
public static final String CLASS_COUNTRY = "country"; public static final String CLASS_COUNTRY = "country";
public static final String CLASS_STATE = "state"; public static final String CLASS_STATE = "state";
public static final String CLASS_PROVINCE = "province";
public static final String CLASS_CITY = "city"; public static final String CLASS_CITY = "city";
public static final String CLASS_TOWN = "town"; public static final String CLASS_TOWN = "town";
public static final String CLASS_VILLAGE = "village"; public static final String CLASS_VILLAGE = "village";
@@ -1513,8 +1594,8 @@ public class OpenMapTilesSchema {
public static final String CLASS_QUARTER = "quarter"; public static final String CLASS_QUARTER = "quarter";
public static final String CLASS_NEIGHBOURHOOD = "neighbourhood"; public static final String CLASS_NEIGHBOURHOOD = "neighbourhood";
public static final String CLASS_ISOLATED_DWELLING = "isolated_dwelling"; public static final String CLASS_ISOLATED_DWELLING = "isolated_dwelling";
public static final Set<String> CLASS_VALUES = Set.of("continent", "country", "state", "city", "town", "village", public static final Set<String> CLASS_VALUES = Set.of("continent", "country", "state", "province", "city", "town",
"hamlet", "suburb", "quarter", "neighbourhood", "isolated_dwelling"); "village", "hamlet", "suburb", "quarter", "neighbourhood", "isolated_dwelling");
} }
/** Complex mappings to generate attribute values from OSM element tags in the place layer. */ /** Complex mappings to generate attribute values from OSM element tags in the place layer. */
@@ -1528,7 +1609,7 @@ public class OpenMapTilesSchema {
* a map. This adds significant size to <em>z14</em>. For buildings the centroid of the building is used as * a map. This adds significant size to <em>z14</em>. For buildings the centroid of the building is used as
* housenumber. * housenumber.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/housenumber/housenumber.yaml">housenumber.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/housenumber/housenumber.yaml">housenumber.yaml</a>
*/ */
public interface Housenumber extends Layer { public interface Housenumber extends Layer {
@@ -1562,7 +1643,7 @@ public class OpenMapTilesSchema {
* <a href="http://wiki.openstreetmap.org/wiki/Points_of_interest">Points of interests</a> containing a of a variety * <a href="http://wiki.openstreetmap.org/wiki/Points_of_interest">Points of interests</a> containing a of a variety
* of OpenStreetMap tags. Mostly contains amenities, sport, shop and tourist POIs. * of OpenStreetMap tags. Mostly contains amenities, sport, shop and tourist POIs.
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/poi/poi.yaml">poi.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/poi/poi.yaml">poi.yaml</a>
*/ */
public interface Poi extends Layer { public interface Poi extends Layer {
@@ -1732,10 +1813,11 @@ public class OpenMapTilesSchema {
matchAny("subclass", "accessories", "antiques", "beauty", "bed", "boutique", "camera", "carpet", "charity", matchAny("subclass", "accessories", "antiques", "beauty", "bed", "boutique", "camera", "carpet", "charity",
"chemist", "coffee", "computer", "convenience", "copyshop", "cosmetics", "garden_centre", "doityourself", "chemist", "coffee", "computer", "convenience", "copyshop", "cosmetics", "garden_centre", "doityourself",
"erotic", "electronics", "fabric", "florist", "frozen_food", "furniture", "video_games", "video", "general", "erotic", "electronics", "fabric", "florist", "frozen_food", "furniture", "video_games", "video", "general",
"gift", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk", "lamps", "gift", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk",
"mall", "massage", "motorcycle", "mobile_phone", "newsagent", "optician", "outdoor", "perfumery", "perfume", "locksmith", "lamps", "mall", "massage", "motorcycle", "mobile_phone", "newsagent", "optician", "outdoor",
"pet", "photo", "second_hand", "shoes", "sports", "stationery", "tailor", "tattoo", "ticket", "tobacco", "perfumery", "perfume", "pet", "photo", "second_hand", "shoes", "sports", "stationery", "tailor", "tattoo",
"toys", "travel_agency", "watches", "weapons", "wholesale")), MultiExpression.entry("town_hall", "ticket", "tobacco", "toys", "travel_agency", "watches", "weapons", "wholesale")),
MultiExpression.entry("town_hall",
matchAny("subclass", "townhall", "public_building", "courthouse", "community_centre")), matchAny("subclass", "townhall", "public_building", "courthouse", "community_centre")),
MultiExpression.entry("golf", matchAny("subclass", "golf", "golf_course", "miniature_golf")), MultiExpression.entry("golf", matchAny("subclass", "golf", "golf_course", "miniature_golf")),
MultiExpression.entry("fast_food", matchAny("subclass", "fast_food", "food_court")), MultiExpression.entry("fast_food", matchAny("subclass", "fast_food", "food_court")),
@@ -1777,7 +1859,7 @@ public class OpenMapTilesSchema {
/** /**
* <a href="http://wiki.openstreetmap.org/wiki/Tag:aeroway%3Daerodrome">Aerodrome labels</a> * <a href="http://wiki.openstreetmap.org/wiki/Tag:aeroway%3Daerodrome">Aerodrome labels</a>
* <p> * <p>
* Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/layers/aerodrome_label/aerodrome_label.yaml">aerodrome_label.yaml</a> * Generated from <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/layers/aerodrome_label/aerodrome_label.yaml">aerodrome_label.yaml</a>
*/ */
public interface AerodromeLabel extends Layer { public interface AerodromeLabel extends Layer {

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -50,7 +50,7 @@ import java.util.Map;
/** /**
* OSM element parsers generated from the <a href="https://github.com/omniscale/imposm3">imposm3</a> table definitions * OSM element parsers generated from the <a href="https://github.com/omniscale/imposm3">imposm3</a> table definitions
* in the <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.12.2/openmaptiles.yaml">OpenMapTiles vector tile * in the <a href="https://github.com/openmaptiles/openmaptiles/blob/v3.13/openmaptiles.yaml">OpenMapTiles vector tile
* schema</a>. * schema</a>.
* <p> * <p>
* These filter and parse the raw OSM key/value attribute pairs on tags into records with fields that match the columns * These filter and parse the raw OSM key/value attribute pairs on tags into records with fields that match the columns
@@ -75,7 +75,7 @@ public class Tables {
} }
/** The {@code rowClass} of an imposm3 table row and its constructor coerced to a {@link Constructor}. */ /** The {@code rowClass} of an imposm3 table row and its constructor coerced to a {@link Constructor}. */
public static record RowClassAndConstructor( public record RowClassAndConstructor(
Class<? extends Row> rowClass, Class<? extends Row> rowClass,
Constructor create Constructor create
) {} ) {}
@@ -89,31 +89,31 @@ public class Tables {
} }
/** The {@code handlerClass} of a layer handler and it's {@code process} method coerced to a {@link RowHandler}. */ /** The {@code handlerClass} of a layer handler and it's {@code process} method coerced to a {@link RowHandler}. */
public static record RowHandlerAndClass<T extends Row>( public record RowHandlerAndClass<T extends Row>(
Class<?> handlerClass, Class<?> handlerClass,
RowHandler<T> handler RowHandler<T> handler
) {} ) {}
/** An OSM element that would appear in the {@code osm_water_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_water_polygon} table generated by imposm3. */
public static record OsmWaterPolygon( public record OsmWaterPolygon(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String natural, @Override String name, @Override String nameEn, @Override String nameDe, @Override String natural,
@Override String landuse, @Override String waterway, @Override boolean isIntermittent, @Override boolean isTunnel, @Override String landuse, @Override String waterway, @Override String water, @Override boolean isIntermittent,
@Override boolean isBridge, @Override SourceFeature source @Override boolean isTunnel, @Override boolean isBridge, @Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithNatural, WithLanduse, WithWaterway, WithIsIntermittent, ) implements Row, WithName, WithNameEn, WithNameDe, WithNatural, WithLanduse, WithWaterway, WithWater,
WithIsTunnel, WithIsBridge, WithSource { WithIsIntermittent, WithIsTunnel, WithIsBridge, WithSource {
public OsmWaterPolygon(SourceFeature source, String mappingKey) { public OsmWaterPolygon(SourceFeature source, String mappingKey) {
this(source.getString("name"), source.getString("name:en"), source.getString("name:de"), this(source.getString("name"), source.getString("name:en"), source.getString("name:de"),
source.getString("natural"), source.getString("landuse"), source.getString("waterway"), source.getString("natural"), source.getString("landuse"), source.getString("waterway"),
source.getBoolean("intermittent"), source.getBoolean("tunnel"), source.getBoolean("bridge"), source); source.getString("water"), source.getBoolean("intermittent"), source.getBoolean("tunnel"),
source.getBoolean("bridge"), source);
} }
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */ /** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and( public static final Expression MAPPING = and(
or(matchAny("landuse", "reservoir", "basin", "salt_pond"), matchAny("leisure", "swimming_pool"), or(matchAny("landuse", "reservoir", "basin", "salt_pond"), matchAny("leisure", "swimming_pool"),
matchAny("natural", "water", "bay"), matchAny("natural", "water", "bay", "spring"), matchAny("waterway", "riverbank", "dock"),
matchAny("waterway", "river", "riverbank", "stream", "canal", "drain", "ditch", "dock")), matchAny("water", "river")), not(matchAny("covered", "yes")), matchType("polygon"));
not(matchAny("covered", "yes")), matchType("polygon"));
/** /**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link * Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
@@ -126,7 +126,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_waterway_linestring} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_waterway_linestring} table generated by imposm3. */
public static record OsmWaterwayLinestring( public record OsmWaterwayLinestring(
@Override String waterway, @Override String name, @Override String nameEn, @Override String nameDe, @Override String waterway, @Override String name, @Override String nameEn, @Override String nameDe,
@Override boolean isTunnel, @Override boolean isBridge, @Override boolean isIntermittent, @Override boolean isTunnel, @Override boolean isBridge, @Override boolean isIntermittent,
@Override SourceFeature source @Override SourceFeature source
@@ -154,7 +154,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_landcover_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_landcover_polygon} table generated by imposm3. */
public static record OsmLandcoverPolygon( public record OsmLandcoverPolygon(
@Override String subclass, @Override String mappingKey, @Override SourceFeature source @Override String subclass, @Override String mappingKey, @Override SourceFeature source
) implements Row, WithSubclass, WithMappingKey, WithSource { ) implements Row, WithSubclass, WithMappingKey, WithSource {
@@ -165,7 +165,7 @@ public class Tables {
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */ /** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and(or( public static final Expression MAPPING = and(or(
matchAny("landuse", "allotments", "farm", "farmland", "orchard", "plant_nursery", "vineyard", "grass", matchAny("landuse", "allotments", "farm", "farmland", "orchard", "plant_nursery", "vineyard", "grass",
"grassland", "meadow", "forest", "village_green", "recreation_ground", "park"), "grassland", "meadow", "forest", "village_green", "recreation_ground"),
matchAny("natural", "wood", "wetland", "fell", "grassland", "heath", "scrub", "tundra", "glacier", "bare_rock", matchAny("natural", "wood", "wetland", "fell", "grassland", "heath", "scrub", "tundra", "glacier", "bare_rock",
"scree", "beach", "sand", "dune"), matchAny("leisure", "park", "garden", "golf_course"), "scree", "beach", "sand", "dune"), matchAny("leisure", "park", "garden", "golf_course"),
matchAny("wetland", "bog", "swamp", "wet_meadow", "marsh", "reedbed", "saltern", "tidalflat", "saltmarsh", matchAny("wetland", "bog", "swamp", "wet_meadow", "marsh", "reedbed", "saltern", "tidalflat", "saltmarsh",
@@ -182,7 +182,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_landuse_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_landuse_polygon} table generated by imposm3. */
public static record OsmLandusePolygon( public record OsmLandusePolygon(
@Override String landuse, @Override String amenity, @Override String leisure, @Override String tourism, @Override String landuse, @Override String amenity, @Override String leisure, @Override String tourism,
@Override String place, @Override String waterway, @Override SourceFeature source @Override String place, @Override String waterway, @Override SourceFeature source
) implements Row, WithLanduse, WithAmenity, WithLeisure, WithTourism, WithPlace, WithWaterway, WithSource { ) implements Row, WithLanduse, WithAmenity, WithLeisure, WithTourism, WithPlace, WithWaterway, WithSource {
@@ -196,9 +196,10 @@ public class Tables {
public static final Expression MAPPING = and(or( public static final Expression MAPPING = and(or(
matchAny("landuse", "railway", "cemetery", "military", "residential", "commercial", "industrial", "garages", matchAny("landuse", "railway", "cemetery", "military", "residential", "commercial", "industrial", "garages",
"retail"), "retail"),
matchAny("amenity", "bus_station", "school", "university", "kindergarten", "college", "library", "hospital"), matchAny("amenity", "bus_station", "school", "university", "kindergarten", "college", "library", "hospital",
matchAny("leisure", "stadium", "pitch", "playground", "track"), matchAny("tourism", "theme_park", "zoo"), "grave_yard"), matchAny("leisure", "stadium", "pitch", "playground", "track"),
matchAny("place", "suburb", "quarter", "neighbourhood"), matchAny("waterway", "dam")), matchType("polygon")); matchAny("tourism", "theme_park", "zoo"), matchAny("place", "suburb", "quarter", "neighbourhood"),
matchAny("waterway", "dam")), matchType("polygon"));
/** /**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link * Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
@@ -211,7 +212,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_peak_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_peak_point} table generated by imposm3. */
public static record OsmPeakPoint( public record OsmPeakPoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String ele, @Override String name, @Override String nameEn, @Override String nameDe, @Override String ele,
@Override String wikipedia, @Override SourceFeature source @Override String wikipedia, @Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithEle, WithWikipedia, WithSource { ) implements Row, WithName, WithNameEn, WithNameDe, WithEle, WithWikipedia, WithSource {
@@ -222,7 +223,7 @@ public class Tables {
} }
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */ /** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and(matchAny("natural", "peak", "volcano"), matchType("point")); public static final Expression MAPPING = and(matchAny("natural", "peak", "volcano", "saddle"), matchType("point"));
/** /**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link * Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
@@ -234,8 +235,33 @@ public class Tables {
} }
} }
/** An OSM element that would appear in the {@code osm_mountain_linestring} table generated by imposm3. */
public record OsmMountainLinestring(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String wikipedia,
@Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithWikipedia, WithSource {
public OsmMountainLinestring(SourceFeature source, String mappingKey) {
this(source.getString("name"), source.getString("name:en"), source.getString("name:de"),
source.getString("wikipedia"), source);
}
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and(matchAny("natural", "ridge", "cliff", "arete"),
matchType("linestring"));
/**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
* OsmMountainLinestring}.
*/
public interface Handler {
void process(OsmMountainLinestring element, FeatureCollector features);
}
}
/** An OSM element that would appear in the {@code osm_park_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_park_polygon} table generated by imposm3. */
public static record OsmParkPolygon( public record OsmParkPolygon(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String landuse, @Override String name, @Override String nameEn, @Override String nameDe, @Override String landuse,
@Override String leisure, @Override String boundary, @Override String protectionTitle, @Override String leisure, @Override String boundary, @Override String protectionTitle,
@Override SourceFeature source @Override SourceFeature source
@@ -264,7 +290,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_aeroway_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_aeroway_polygon} table generated by imposm3. */
public static record OsmAerowayPolygon( public record OsmAerowayPolygon(
@Override String ref, @Override String aeroway, @Override SourceFeature source @Override String ref, @Override String aeroway, @Override SourceFeature source
) implements Row, WithRef, WithAeroway, WithSource { ) implements Row, WithRef, WithAeroway, WithSource {
@@ -289,7 +315,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_aeroway_linestring} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_aeroway_linestring} table generated by imposm3. */
public static record OsmAerowayLinestring( public record OsmAerowayLinestring(
@Override String ref, @Override String aeroway, @Override SourceFeature source @Override String ref, @Override String aeroway, @Override SourceFeature source
) implements Row, WithRef, WithAeroway, WithSource { ) implements Row, WithRef, WithAeroway, WithSource {
@@ -311,7 +337,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_aeroway_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_aeroway_point} table generated by imposm3. */
public static record OsmAerowayPoint( public record OsmAerowayPoint(
@Override String ref, @Override String aeroway, @Override SourceFeature source @Override String ref, @Override String aeroway, @Override SourceFeature source
) implements Row, WithRef, WithAeroway, WithSource { ) implements Row, WithRef, WithAeroway, WithSource {
@@ -333,18 +359,19 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_highway_linestring} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_highway_linestring} table generated by imposm3. */
public static record OsmHighwayLinestring( public record OsmHighwayLinestring(
@Override String highway, @Override String construction, @Override String ref, @Override String network, @Override String highway, @Override String construction, @Override String ref, @Override String network,
@Override int zOrder, @Override long layer, @Override long level, @Override boolean indoor, @Override String name, @Override int zOrder, @Override long layer, @Override long level, @Override boolean indoor, @Override String name,
@Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel, @Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel,
@Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway, @Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway,
@Override boolean isArea, @Override String service, @Override String usage, @Override String publicTransport, @Override boolean isArea, @Override String service, @Override String access, @Override boolean toll,
@Override String manMade, @Override String bicycle, @Override String foot, @Override String horse, @Override String usage, @Override String publicTransport, @Override String manMade, @Override String bicycle,
@Override String mtbScale, @Override String surface, @Override SourceFeature source @Override String foot, @Override String horse, @Override String mtbScale, @Override String sacScale,
@Override String surface, @Override boolean expressway, @Override SourceFeature source
) implements Row, WithHighway, WithConstruction, WithRef, WithNetwork, WithZOrder, WithLayer, WithLevel, WithIndoor, ) implements Row, WithHighway, WithConstruction, WithRef, WithNetwork, WithZOrder, WithLayer, WithLevel, WithIndoor,
WithName, WithNameEn, WithNameDe, WithShortName, WithIsTunnel, WithIsBridge, WithIsRamp, WithIsFord, WithIsOneway, WithName, WithNameEn, WithNameDe, WithShortName, WithIsTunnel, WithIsBridge, WithIsRamp, WithIsFord, WithIsOneway,
WithIsArea, WithService, WithUsage, WithPublicTransport, WithManMade, WithBicycle, WithFoot, WithHorse, WithIsArea, WithService, WithAccess, WithToll, WithUsage, WithPublicTransport, WithManMade, WithBicycle, WithFoot,
WithMtbScale, WithSurface, WithSource { WithHorse, WithMtbScale, WithSacScale, WithSurface, WithExpressway, WithSource {
public OsmHighwayLinestring(SourceFeature source, String mappingKey) { public OsmHighwayLinestring(SourceFeature source, String mappingKey) {
this(source.getString("highway"), source.getString("construction"), source.getString("ref"), this(source.getString("highway"), source.getString("construction"), source.getString("ref"),
@@ -352,18 +379,19 @@ public class Tables {
source.getBoolean("indoor"), source.getString("name"), source.getString("name:en"), source.getString("name:de"), source.getBoolean("indoor"), source.getString("name"), source.getString("name:en"), source.getString("name:de"),
source.getString("short_name"), source.getBoolean("tunnel"), source.getBoolean("bridge"), source.getString("short_name"), source.getBoolean("tunnel"), source.getBoolean("bridge"),
source.getBoolean("ramp"), source.getBoolean("ford"), source.getDirection("oneway"), source.getBoolean("area"), source.getBoolean("ramp"), source.getBoolean("ford"), source.getDirection("oneway"), source.getBoolean("area"),
source.getString("service"), source.getString("usage"), source.getString("public_transport"), source.getString("service"), source.getString("access"), source.getBoolean("toll"), source.getString("usage"),
source.getString("man_made"), source.getString("bicycle"), source.getString("foot"), source.getString("horse"), source.getString("public_transport"), source.getString("man_made"), source.getString("bicycle"),
source.getString("mtb:scale"), source.getString("surface"), source); source.getString("foot"), source.getString("horse"), source.getString("mtb:scale"),
source.getString("sac_scale"), source.getString("surface"), source.getBoolean("expressway"), source);
} }
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */ /** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and(or( public static final Expression MAPPING = and(or(
matchAny("highway", "motorway", "motorway_link", "trunk", "trunk_link", "primary", "primary_link", "secondary", matchAny("highway", "motorway", "motorway_link", "trunk", "trunk_link", "primary", "primary_link", "secondary",
"secondary_link", "tertiary", "tertiary_link", "unclassified", "residential", "living_street", "road", "secondary_link", "tertiary", "tertiary_link", "unclassified", "residential", "living_street", "road",
"pedestrian", "path", "footway", "cycleway", "steps", "bridleway", "corridor", "service", "track", "raceway", "pedestrian", "path", "footway", "cycleway", "steps", "bridleway", "corridor", "service", "track", "raceway",
"construction"), matchAny("public_transport", "platform"), matchAny("man_made", "pier")), "busway", "construction"), matchAny("public_transport", "platform"), matchAny("man_made", "pier"),
matchType("linestring")); matchAny("service", "driveway", "parking_aisle")), matchType("linestring"));
/** /**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link * Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
@@ -376,7 +404,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_railway_linestring} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_railway_linestring} table generated by imposm3. */
public static record OsmRailwayLinestring( public record OsmRailwayLinestring(
@Override String railway, @Override String ref, @Override String network, @Override int zOrder, @Override String railway, @Override String ref, @Override String network, @Override int zOrder,
@Override long layer, @Override long level, @Override boolean indoor, @Override String name, @Override long layer, @Override long level, @Override boolean indoor, @Override String name,
@Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel, @Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel,
@@ -411,7 +439,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_aerialway_linestring} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_aerialway_linestring} table generated by imposm3. */
public static record OsmAerialwayLinestring( public record OsmAerialwayLinestring(
@Override String aerialway, @Override int zOrder, @Override long layer, @Override String name, @Override String aerialway, @Override int zOrder, @Override long layer, @Override String name,
@Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel, @Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel,
@Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway, @Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway,
@@ -442,7 +470,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_shipway_linestring} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_shipway_linestring} table generated by imposm3. */
public static record OsmShipwayLinestring( public record OsmShipwayLinestring(
@Override String shipway, @Override int zOrder, @Override long layer, @Override String name, @Override String shipway, @Override int zOrder, @Override long layer, @Override String name,
@Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel, @Override String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel,
@Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway, @Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway,
@@ -472,17 +500,17 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_highway_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_highway_polygon} table generated by imposm3. */
public static record OsmHighwayPolygon( public record OsmHighwayPolygon(
@Override String highway, @Override int zOrder, @Override long layer, @Override long level, @Override String highway, @Override int zOrder, @Override long layer, @Override long level,
@Override boolean indoor, @Override boolean isArea, @Override String publicTransport, @Override String manMade, @Override boolean indoor, @Override boolean isArea, @Override String publicTransport, @Override String manMade,
@Override SourceFeature source @Override String service, @Override SourceFeature source
) implements Row, WithHighway, WithZOrder, WithLayer, WithLevel, WithIndoor, WithIsArea, WithPublicTransport, ) implements Row, WithHighway, WithZOrder, WithLayer, WithLevel, WithIndoor, WithIsArea, WithPublicTransport,
WithManMade, WithSource { WithManMade, WithService, WithSource {
public OsmHighwayPolygon(SourceFeature source, String mappingKey) { public OsmHighwayPolygon(SourceFeature source, String mappingKey) {
this(source.getString("highway"), source.getWayZorder(), source.getLong("layer"), source.getLong("level"), this(source.getString("highway"), source.getWayZorder(), source.getLong("layer"), source.getLong("level"),
source.getBoolean("indoor"), source.getBoolean("area"), source.getString("public_transport"), source.getBoolean("indoor"), source.getBoolean("area"), source.getString("public_transport"),
source.getString("man_made"), source); source.getString("man_made"), source.getString("service"), source);
} }
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */ /** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
@@ -500,8 +528,34 @@ public class Tables {
} }
} }
/** An OSM element that would appear in the {@code osm_highway_point} table generated by imposm3. */
public record OsmHighwayPoint(
@Override String highway, @Override int zOrder, @Override long layer, @Override long level, @Override String name,
@Override String nameEn, @Override String nameDe, @Override String ref, @Override SourceFeature source
) implements Row, WithHighway, WithZOrder, WithLayer, WithLevel, WithName, WithNameEn, WithNameDe, WithRef,
WithSource {
public OsmHighwayPoint(SourceFeature source, String mappingKey) {
this(source.getString("highway"), source.getWayZorder(), source.getLong("layer"), source.getLong("level"),
source.getString("name"), source.getString("name:en"), source.getString("name:de"), source.getString("ref"),
source);
}
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and(matchAny("highway", "motorway_junction"), matchType("point"));
/**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
* OsmHighwayPoint}.
*/
public interface Handler {
void process(OsmHighwayPoint element, FeatureCollector features);
}
}
/** An OSM element that would appear in the {@code osm_building_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_building_polygon} table generated by imposm3. */
public static record OsmBuildingPolygon( public record OsmBuildingPolygon(
@Override String material, @Override String colour, @Override String building, @Override String buildingpart, @Override String material, @Override String colour, @Override String building, @Override String buildingpart,
@Override String buildingheight, @Override String buildingminHeight, @Override String buildinglevels, @Override String buildingheight, @Override String buildingminHeight, @Override String buildinglevels,
@Override String buildingminLevel, @Override String height, @Override String minHeight, @Override String levels, @Override String buildingminLevel, @Override String height, @Override String minHeight, @Override String levels,
@@ -518,9 +572,10 @@ public class Tables {
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */ /** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and( public static final Expression MAPPING = and(
or(matchField("building:part"), matchField("building"), matchAny("aeroway", "terminal", "hangar")), or(matchField("building:part"), matchField("building"), matchAny("aeroway", "terminal", "hangar"),
not(matchAny("building", "no", "none", "No")), not(matchAny("building:part", "no", "none", "No")), matchAny("location", "underground")), not(matchAny("building", "no", "none", "No")),
not(matchAny("man_made", "bridge")), matchType("polygon")); not(matchAny("building:part", "no", "none", "No")), not(matchAny("man_made", "bridge")),
not(matchAny("location", "underground")), matchType("polygon"));
/** /**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link * Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
@@ -533,7 +588,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_marine_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_marine_point} table generated by imposm3. */
public static record OsmMarinePoint( public record OsmMarinePoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String place, @Override String name, @Override String nameEn, @Override String nameDe, @Override String place,
@Override long rank, @Override boolean isIntermittent, @Override SourceFeature source @Override long rank, @Override boolean isIntermittent, @Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithPlace, WithRank, WithIsIntermittent, WithSource { ) implements Row, WithName, WithNameEn, WithNameDe, WithPlace, WithRank, WithIsIntermittent, WithSource {
@@ -558,7 +613,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_continent_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_continent_point} table generated by imposm3. */
public static record OsmContinentPoint( public record OsmContinentPoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override SourceFeature source @Override String name, @Override String nameEn, @Override String nameDe, @Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithSource { ) implements Row, WithName, WithNameEn, WithNameDe, WithSource {
@@ -581,7 +636,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_country_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_country_point} table generated by imposm3. */
public static record OsmCountryPoint( public record OsmCountryPoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override long rank, @Override String name, @Override String nameEn, @Override String nameDe, @Override long rank,
@Override String countryCodeIso31661Alpha2, @Override String iso31661Alpha2, @Override String iso31661, @Override String countryCodeIso31661Alpha2, @Override String iso31661Alpha2, @Override String iso31661,
@Override SourceFeature source @Override SourceFeature source
@@ -608,7 +663,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_island_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_island_polygon} table generated by imposm3. */
public static record OsmIslandPolygon( public record OsmIslandPolygon(
@Override String name, @Override String nameEn, @Override String nameDe, @Override long rank, @Override String name, @Override String nameEn, @Override String nameDe, @Override long rank,
@Override SourceFeature source @Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithRank, WithSource { ) implements Row, WithName, WithNameEn, WithNameDe, WithRank, WithSource {
@@ -632,7 +687,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_island_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_island_point} table generated by imposm3. */
public static record OsmIslandPoint( public record OsmIslandPoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override long rank, @Override String name, @Override String nameEn, @Override String nameDe, @Override long rank,
@Override SourceFeature source @Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithRank, WithSource { ) implements Row, WithName, WithNameEn, WithNameDe, WithRank, WithSource {
@@ -656,20 +711,22 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_state_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_state_point} table generated by imposm3. */
public static record OsmStatePoint( public record OsmStatePoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String isInCountry, @Override String name, @Override String nameEn, @Override String nameDe, @Override String place,
@Override String isInCountryCode, @Override String ref, @Override long rank, @Override SourceFeature source @Override String isInCountry, @Override String isInCountryCode, @Override String ref, @Override long rank,
) implements Row, WithName, WithNameEn, WithNameDe, WithIsInCountry, WithIsInCountryCode, WithRef, WithRank, @Override SourceFeature source
WithSource { ) implements Row, WithName, WithNameEn, WithNameDe, WithPlace, WithIsInCountry, WithIsInCountryCode, WithRef,
WithRank, WithSource {
public OsmStatePoint(SourceFeature source, String mappingKey) { public OsmStatePoint(SourceFeature source, String mappingKey) {
this(source.getString("name"), source.getString("name:en"), source.getString("name:de"), this(source.getString("name"), source.getString("name:en"), source.getString("name:de"),
source.getString("is_in:country"), source.getString("is_in:country_code"), source.getString("ref"), source.getString("place"), source.getString("is_in:country"), source.getString("is_in:country_code"),
source.getLong("rank"), source); source.getString("ref"), source.getLong("rank"), source);
} }
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */ /** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and(matchAny("place", "state"), matchField("name"), matchType("point")); public static final Expression MAPPING = and(matchAny("place", "state", "province"), matchField("name"),
matchType("point"));
/** /**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link * Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as {@link
@@ -682,7 +739,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_city_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_city_point} table generated by imposm3. */
public static record OsmCityPoint( public record OsmCityPoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String place, @Override String name, @Override String nameEn, @Override String nameDe, @Override String place,
@Override long population, @Override String capital, @Override long rank, @Override SourceFeature source @Override long population, @Override String capital, @Override long rank, @Override SourceFeature source
) implements Row, WithName, WithNameEn, WithNameDe, WithPlace, WithPopulation, WithCapital, WithRank, WithSource { ) implements Row, WithName, WithNameEn, WithNameDe, WithPlace, WithPopulation, WithCapital, WithRank, WithSource {
@@ -709,7 +766,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_housenumber_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_housenumber_point} table generated by imposm3. */
public static record OsmHousenumberPoint(@Override String housenumber, @Override SourceFeature source) implements Row, public record OsmHousenumberPoint(@Override String housenumber, @Override SourceFeature source) implements Row,
WithHousenumber, WithSource { WithHousenumber, WithSource {
public OsmHousenumberPoint(SourceFeature source, String mappingKey) { public OsmHousenumberPoint(SourceFeature source, String mappingKey) {
@@ -731,7 +788,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_poi_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_poi_point} table generated by imposm3. */
public static record OsmPoiPoint( public record OsmPoiPoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String subclass, @Override String name, @Override String nameEn, @Override String nameDe, @Override String subclass,
@Override String mappingKey, @Override String station, @Override String funicular, @Override String information, @Override String mappingKey, @Override String station, @Override String funicular, @Override String information,
@Override String uicRef, @Override String religion, @Override long level, @Override boolean indoor, @Override String uicRef, @Override String religion, @Override long level, @Override boolean indoor,
@@ -751,9 +808,9 @@ public class Tables {
public static final Expression MAPPING = and(or(matchAny("aerialway", "station"), public static final Expression MAPPING = and(or(matchAny("aerialway", "station"),
matchAny("amenity", "arts_centre", "bank", "bar", "bbq", "bicycle_parking", "bicycle_rental", "biergarten", matchAny("amenity", "arts_centre", "bank", "bar", "bbq", "bicycle_parking", "bicycle_rental", "biergarten",
"bus_station", "cafe", "cinema", "clinic", "college", "community_centre", "courthouse", "dentist", "doctors", "bus_station", "cafe", "cinema", "clinic", "college", "community_centre", "courthouse", "dentist", "doctors",
"drinking_water", "embassy", "fast_food", "ferry_terminal", "fire_station", "food_court", "fuel", "grave_yard", "drinking_water", "fast_food", "ferry_terminal", "fire_station", "food_court", "fuel", "grave_yard", "hospital",
"hospital", "ice_cream", "kindergarten", "library", "marketplace", "motorcycle_parking", "nightclub", "ice_cream", "kindergarten", "library", "marketplace", "motorcycle_parking", "nightclub", "nursing_home",
"nursing_home", "parking", "pharmacy", "place_of_worship", "police", "post_box", "post_office", "prison", "pub", "parking", "pharmacy", "place_of_worship", "police", "post_box", "post_office", "prison", "pub",
"public_building", "recycling", "restaurant", "school", "shelter", "swimming_pool", "taxi", "telephone", "public_building", "recycling", "restaurant", "school", "shelter", "swimming_pool", "taxi", "telephone",
"theatre", "toilets", "townhall", "university", "veterinary", "waste_basket"), "theatre", "toilets", "townhall", "university", "veterinary", "waste_basket"),
matchAny("barrier", "bollard", "border_control", "cycle_barrier", "gate", "lift_gate", "sally_port", "stile", matchAny("barrier", "bollard", "border_control", "cycle_barrier", "gate", "lift_gate", "sally_port", "stile",
@@ -762,17 +819,18 @@ public class Tables {
matchAny("landuse", "basin", "brownfield", "cemetery", "reservoir", "winter_sports"), matchAny("landuse", "basin", "brownfield", "cemetery", "reservoir", "winter_sports"),
matchAny("leisure", "dog_park", "escape_game", "garden", "golf_course", "ice_rink", "hackerspace", "marina", matchAny("leisure", "dog_park", "escape_game", "garden", "golf_course", "ice_rink", "hackerspace", "marina",
"miniature_golf", "park", "pitch", "playground", "sports_centre", "stadium", "swimming_area", "swimming_pool", "miniature_golf", "park", "pitch", "playground", "sports_centre", "stadium", "swimming_area", "swimming_pool",
"water_park"), matchAny("railway", "halt", "station", "subway_entrance", "train_station_entrance", "tram_stop"), "water_park"), matchAny("office", "diplomatic"),
matchAny("railway", "halt", "station", "subway_entrance", "train_station_entrance", "tram_stop"),
matchAny("shop", "accessories", "alcohol", "antiques", "art", "bag", "bakery", "beauty", "bed", "beverages", matchAny("shop", "accessories", "alcohol", "antiques", "art", "bag", "bakery", "beauty", "bed", "beverages",
"bicycle", "books", "boutique", "butcher", "camera", "car", "car_repair", "car_parts", "carpet", "charity", "bicycle", "books", "boutique", "butcher", "camera", "car", "car_repair", "car_parts", "carpet", "charity",
"chemist", "chocolate", "clothes", "coffee", "computer", "confectionery", "convenience", "copyshop", "chemist", "chocolate", "clothes", "coffee", "computer", "confectionery", "convenience", "copyshop",
"cosmetics", "deli", "delicatessen", "department_store", "doityourself", "dry_cleaning", "electronics", "cosmetics", "deli", "delicatessen", "department_store", "doityourself", "dry_cleaning", "electronics",
"erotic", "fabric", "florist", "frozen_food", "furniture", "garden_centre", "general", "gift", "greengrocer", "erotic", "fabric", "florist", "frozen_food", "furniture", "garden_centre", "general", "gift", "greengrocer",
"hairdresser", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk", "hairdresser", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk",
"lamps", "laundry", "mall", "massage", "mobile_phone", "motorcycle", "music", "musical_instrument", "newsagent", "lamps", "laundry", "locksmith", "mall", "massage", "mobile_phone", "motorcycle", "music", "musical_instrument",
"optician", "outdoor", "perfume", "perfumery", "pet", "photo", "second_hand", "shoes", "sports", "stationery", "newsagent", "optician", "outdoor", "perfume", "perfumery", "pet", "photo", "second_hand", "shoes", "sports",
"supermarket", "tailor", "tattoo", "ticket", "tobacco", "toys", "travel_agency", "video", "video_games", "stationery", "supermarket", "tailor", "tattoo", "ticket", "tobacco", "toys", "travel_agency", "video",
"watches", "weapons", "wholesale", "wine"), "video_games", "watches", "weapons", "wholesale", "wine"),
matchAny("sport", "american_football", "archery", "athletics", "australian_football", "badminton", "baseball", matchAny("sport", "american_football", "archery", "athletics", "australian_football", "badminton", "baseball",
"basketball", "beachvolleyball", "billiards", "bmx", "boules", "bowls", "boxing", "canadian_football", "canoe", "basketball", "beachvolleyball", "billiards", "bmx", "boules", "bowls", "boxing", "canadian_football", "canoe",
"chess", "climbing", "climbing_adventure", "cricket", "cricket_nets", "croquet", "curling", "cycling", "chess", "climbing", "climbing_adventure", "cricket", "cricket_nets", "croquet", "curling", "cycling",
@@ -798,7 +856,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_poi_polygon} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_poi_polygon} table generated by imposm3. */
public static record OsmPoiPolygon( public record OsmPoiPolygon(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String subclass, @Override String name, @Override String nameEn, @Override String nameDe, @Override String subclass,
@Override String mappingKey, @Override String station, @Override String funicular, @Override String information, @Override String mappingKey, @Override String station, @Override String funicular, @Override String information,
@Override String uicRef, @Override String religion, @Override long level, @Override boolean indoor, @Override String uicRef, @Override String religion, @Override long level, @Override boolean indoor,
@@ -818,9 +876,9 @@ public class Tables {
public static final Expression MAPPING = and(or(matchAny("aerialway", "station"), public static final Expression MAPPING = and(or(matchAny("aerialway", "station"),
matchAny("amenity", "arts_centre", "bank", "bar", "bbq", "bicycle_parking", "bicycle_rental", "biergarten", matchAny("amenity", "arts_centre", "bank", "bar", "bbq", "bicycle_parking", "bicycle_rental", "biergarten",
"bus_station", "cafe", "cinema", "clinic", "college", "community_centre", "courthouse", "dentist", "doctors", "bus_station", "cafe", "cinema", "clinic", "college", "community_centre", "courthouse", "dentist", "doctors",
"drinking_water", "embassy", "fast_food", "ferry_terminal", "fire_station", "food_court", "fuel", "grave_yard", "drinking_water", "fast_food", "ferry_terminal", "fire_station", "food_court", "fuel", "grave_yard", "hospital",
"hospital", "ice_cream", "kindergarten", "library", "marketplace", "motorcycle_parking", "nightclub", "ice_cream", "kindergarten", "library", "marketplace", "motorcycle_parking", "nightclub", "nursing_home",
"nursing_home", "parking", "pharmacy", "place_of_worship", "police", "post_box", "post_office", "prison", "pub", "parking", "pharmacy", "place_of_worship", "police", "post_box", "post_office", "prison", "pub",
"public_building", "recycling", "restaurant", "school", "shelter", "swimming_pool", "taxi", "telephone", "public_building", "recycling", "restaurant", "school", "shelter", "swimming_pool", "taxi", "telephone",
"theatre", "toilets", "townhall", "university", "veterinary", "waste_basket"), "theatre", "toilets", "townhall", "university", "veterinary", "waste_basket"),
matchAny("barrier", "bollard", "border_control", "cycle_barrier", "gate", "lift_gate", "sally_port", "stile", matchAny("barrier", "bollard", "border_control", "cycle_barrier", "gate", "lift_gate", "sally_port", "stile",
@@ -829,17 +887,18 @@ public class Tables {
matchAny("landuse", "basin", "brownfield", "cemetery", "reservoir", "winter_sports"), matchAny("landuse", "basin", "brownfield", "cemetery", "reservoir", "winter_sports"),
matchAny("leisure", "dog_park", "escape_game", "garden", "golf_course", "ice_rink", "hackerspace", "marina", matchAny("leisure", "dog_park", "escape_game", "garden", "golf_course", "ice_rink", "hackerspace", "marina",
"miniature_golf", "park", "pitch", "playground", "sports_centre", "stadium", "swimming_area", "swimming_pool", "miniature_golf", "park", "pitch", "playground", "sports_centre", "stadium", "swimming_area", "swimming_pool",
"water_park"), matchAny("railway", "halt", "station", "subway_entrance", "train_station_entrance", "tram_stop"), "water_park"), matchAny("office", "diplomatic"),
matchAny("railway", "halt", "station", "subway_entrance", "train_station_entrance", "tram_stop"),
matchAny("shop", "accessories", "alcohol", "antiques", "art", "bag", "bakery", "beauty", "bed", "beverages", matchAny("shop", "accessories", "alcohol", "antiques", "art", "bag", "bakery", "beauty", "bed", "beverages",
"bicycle", "books", "boutique", "butcher", "camera", "car", "car_repair", "car_parts", "carpet", "charity", "bicycle", "books", "boutique", "butcher", "camera", "car", "car_repair", "car_parts", "carpet", "charity",
"chemist", "chocolate", "clothes", "coffee", "computer", "confectionery", "convenience", "copyshop", "chemist", "chocolate", "clothes", "coffee", "computer", "confectionery", "convenience", "copyshop",
"cosmetics", "deli", "delicatessen", "department_store", "doityourself", "dry_cleaning", "electronics", "cosmetics", "deli", "delicatessen", "department_store", "doityourself", "dry_cleaning", "electronics",
"erotic", "fabric", "florist", "frozen_food", "furniture", "garden_centre", "general", "gift", "greengrocer", "erotic", "fabric", "florist", "frozen_food", "furniture", "garden_centre", "general", "gift", "greengrocer",
"hairdresser", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk", "hairdresser", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk",
"lamps", "laundry", "mall", "massage", "mobile_phone", "motorcycle", "music", "musical_instrument", "newsagent", "lamps", "laundry", "locksmith", "mall", "massage", "mobile_phone", "motorcycle", "music", "musical_instrument",
"optician", "outdoor", "perfume", "perfumery", "pet", "photo", "second_hand", "shoes", "sports", "stationery", "newsagent", "optician", "outdoor", "perfume", "perfumery", "pet", "photo", "second_hand", "shoes", "sports",
"supermarket", "tailor", "tattoo", "ticket", "tobacco", "toys", "travel_agency", "video", "video_games", "stationery", "supermarket", "tailor", "tattoo", "ticket", "tobacco", "toys", "travel_agency", "video",
"watches", "weapons", "wholesale", "wine"), "video_games", "watches", "weapons", "wholesale", "wine"),
matchAny("sport", "american_football", "archery", "athletics", "australian_football", "badminton", "baseball", matchAny("sport", "american_football", "archery", "athletics", "australian_football", "badminton", "baseball",
"basketball", "beachvolleyball", "billiards", "bmx", "boules", "bowls", "boxing", "canadian_football", "canoe", "basketball", "beachvolleyball", "billiards", "bmx", "boules", "bowls", "boxing", "canadian_football", "canoe",
"chess", "climbing", "climbing_adventure", "cricket", "cricket_nets", "croquet", "curling", "cycling", "chess", "climbing", "climbing_adventure", "cricket", "cricket_nets", "croquet", "curling", "cycling",
@@ -865,7 +924,7 @@ public class Tables {
} }
/** An OSM element that would appear in the {@code osm_aerodrome_label_point} table generated by imposm3. */ /** An OSM element that would appear in the {@code osm_aerodrome_label_point} table generated by imposm3. */
public static record OsmAerodromeLabelPoint( public record OsmAerodromeLabelPoint(
@Override String name, @Override String nameEn, @Override String nameDe, @Override String aerodromeType, @Override String name, @Override String nameEn, @Override String nameDe, @Override String aerodromeType,
@Override String aerodrome, @Override String military, @Override String iata, @Override String icao, @Override String aerodrome, @Override String military, @Override String iata, @Override String icao,
@Override String ele, @Override SourceFeature source @Override String ele, @Override SourceFeature source
@@ -892,6 +951,12 @@ public class Tables {
} }
} }
/** Rows with a String access attribute. */
public interface WithAccess {
String access();
}
/** Rows with a long adminLevel attribute. */ /** Rows with a long adminLevel attribute. */
public interface WithAdminLevel { public interface WithAdminLevel {
@@ -1006,18 +1071,18 @@ public class Tables {
String countryCodeIso31661Alpha2(); String countryCodeIso31661Alpha2();
} }
/** Rows with a String disputedBy attribute. */
public interface WithDisputedBy {
String disputedBy();
}
/** Rows with a String ele attribute. */ /** Rows with a String ele attribute. */
public interface WithEle { public interface WithEle {
String ele(); String ele();
} }
/** Rows with a boolean expressway attribute. */
public interface WithExpressway {
boolean expressway();
}
/** Rows with a String foot attribute. */ /** Rows with a String foot attribute. */
public interface WithFoot { public interface WithFoot {
@@ -1246,6 +1311,12 @@ public class Tables {
String network(); String network();
} }
/** Rows with a String osmcSymbol attribute. */
public interface WithOsmcSymbol {
String osmcSymbol();
}
/** Rows with a String place attribute. */ /** Rows with a String place attribute. */
public interface WithPlace { public interface WithPlace {
@@ -1342,6 +1413,12 @@ public class Tables {
String relminLevel(); String relminLevel();
} }
/** Rows with a String sacScale attribute. */
public interface WithSacScale {
String sacScale();
}
/** Rows with a String service attribute. */ /** Rows with a String service attribute. */
public interface WithService { public interface WithService {
@@ -1390,6 +1467,12 @@ public class Tables {
String surface(); String surface();
} }
/** Rows with a boolean toll attribute. */
public interface WithToll {
boolean toll();
}
/** Rows with a String tourism attribute. */ /** Rows with a String tourism attribute. */
public interface WithTourism { public interface WithTourism {
@@ -1408,6 +1491,12 @@ public class Tables {
String usage(); String usage();
} }
/** Rows with a String water attribute. */
public interface WithWater {
String water();
}
/** Rows with a String waterway attribute. */ /** Rows with a String waterway attribute. */
public interface WithWaterway { public interface WithWaterway {
@@ -1437,6 +1526,8 @@ public class Tables {
MultiExpression.entry(new RowClassAndConstructor(OsmLandusePolygon.class, OsmLandusePolygon::new), MultiExpression.entry(new RowClassAndConstructor(OsmLandusePolygon.class, OsmLandusePolygon::new),
OsmLandusePolygon.MAPPING), OsmLandusePolygon.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmPeakPoint.class, OsmPeakPoint::new), OsmPeakPoint.MAPPING), MultiExpression.entry(new RowClassAndConstructor(OsmPeakPoint.class, OsmPeakPoint::new), OsmPeakPoint.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmMountainLinestring.class, OsmMountainLinestring::new),
OsmMountainLinestring.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmParkPolygon.class, OsmParkPolygon::new), MultiExpression.entry(new RowClassAndConstructor(OsmParkPolygon.class, OsmParkPolygon::new),
OsmParkPolygon.MAPPING), OsmParkPolygon.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmAerowayPolygon.class, OsmAerowayPolygon::new), MultiExpression.entry(new RowClassAndConstructor(OsmAerowayPolygon.class, OsmAerowayPolygon::new),
@@ -1455,6 +1546,8 @@ public class Tables {
OsmShipwayLinestring.MAPPING), OsmShipwayLinestring.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmHighwayPolygon.class, OsmHighwayPolygon::new), MultiExpression.entry(new RowClassAndConstructor(OsmHighwayPolygon.class, OsmHighwayPolygon::new),
OsmHighwayPolygon.MAPPING), OsmHighwayPolygon.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmHighwayPoint.class, OsmHighwayPoint::new),
OsmHighwayPoint.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmBuildingPolygon.class, OsmBuildingPolygon::new), MultiExpression.entry(new RowClassAndConstructor(OsmBuildingPolygon.class, OsmBuildingPolygon::new),
OsmBuildingPolygon.MAPPING), OsmBuildingPolygon.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmMarinePoint.class, OsmMarinePoint::new), MultiExpression.entry(new RowClassAndConstructor(OsmMarinePoint.class, OsmMarinePoint::new),
@@ -1504,6 +1597,10 @@ public class Tables {
result.computeIfAbsent(OsmPeakPoint.class, cls -> new ArrayList<>()) result.computeIfAbsent(OsmPeakPoint.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process)); .add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
} }
if (handler instanceof OsmMountainLinestring.Handler typedHandler) {
result.computeIfAbsent(OsmMountainLinestring.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
}
if (handler instanceof OsmParkPolygon.Handler typedHandler) { if (handler instanceof OsmParkPolygon.Handler typedHandler) {
result.computeIfAbsent(OsmParkPolygon.class, cls -> new ArrayList<>()) result.computeIfAbsent(OsmParkPolygon.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process)); .add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
@@ -1540,6 +1637,10 @@ public class Tables {
result.computeIfAbsent(OsmHighwayPolygon.class, cls -> new ArrayList<>()) result.computeIfAbsent(OsmHighwayPolygon.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process)); .add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
} }
if (handler instanceof OsmHighwayPoint.Handler typedHandler) {
result.computeIfAbsent(OsmHighwayPoint.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
}
if (handler instanceof OsmBuildingPolygon.Handler typedHandler) { if (handler instanceof OsmBuildingPolygon.Handler typedHandler) {
result.computeIfAbsent(OsmBuildingPolygon.class, cls -> new ArrayList<>()) result.computeIfAbsent(OsmBuildingPolygon.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process)); .add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -36,6 +36,7 @@ See https://github.com/openmaptiles/openmaptiles/blob/master/LICENSE.md for deta
package com.onthegomap.planetiler.basemap.layers; package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty; import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty;
import static com.onthegomap.planetiler.basemap.util.Utils.nullOrEmpty;
import com.onthegomap.planetiler.FeatureCollector; import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema; import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema;
@@ -67,13 +68,15 @@ public class AerodromeLabel implements
@Override @Override
public void process(Tables.OsmAerodromeLabelPoint element, FeatureCollector features) { public void process(Tables.OsmAerodromeLabelPoint element, FeatureCollector features) {
String clazz = classLookup.getOrElse(element.source(), FieldValues.CLASS_OTHER);
boolean important = !nullOrEmpty(element.iata()) && FieldValues.CLASS_INTERNATIONAL.equals(clazz);
features.centroid(LAYER_NAME) features.centroid(LAYER_NAME)
.setBufferPixels(BUFFER_SIZE) .setBufferPixels(BUFFER_SIZE)
.setMinZoom(10) .setMinZoom(important ? 8 : 10)
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations)) .putAttrs(LanguageUtils.getNames(element.source().tags(), translations))
.putAttrs(Utils.elevationTags(element.ele())) .putAttrs(Utils.elevationTags(element.ele()))
.setAttr(Fields.IATA, nullIfEmpty(element.iata())) .setAttr(Fields.IATA, nullIfEmpty(element.iata()))
.setAttr(Fields.ICAO, nullIfEmpty(element.icao())) .setAttr(Fields.ICAO, nullIfEmpty(element.icao()))
.setAttr(Fields.CLASS, classLookup.getOrElse(element.source(), FieldValues.CLASS_OTHER)); .setAttr(Fields.CLASS, clazz);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -168,7 +168,9 @@ public class Boundary implements
: new BoundaryInfo(2, 4, 4); : new BoundaryInfo(2, 4, 4);
case "ne_10m_admin_1_states_provinces_lines" -> { case "ne_10m_admin_1_states_provinces_lines" -> {
Double minZoom = Parse.parseDoubleOrNull(feature.getTag("min_zoom")); Double minZoom = Parse.parseDoubleOrNull(feature.getTag("min_zoom"));
yield minZoom != null && minZoom <= 7 ? new BoundaryInfo(4, 1, 4) : null; yield minZoom != null && minZoom <= 7 ? new BoundaryInfo(4, 1, 4) :
minZoom != null && minZoom <= 7.7 ? new BoundaryInfo(4, 4, 4) :
null;
} }
default -> null; default -> null;
}; };

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -152,14 +152,14 @@ public class Landcover implements
long numPoints = num.longValue(); long numPoints = num.longValue();
if (zoom >= 10) { if (zoom >= 10) {
if (WOOD_OR_FOREST.contains(subclass) && numPoints < 300) { if (WOOD_OR_FOREST.contains(subclass) && numPoints < 300) {
attrs.put(tempGroupKey, numPoints < 50 ? "<50" : "<300"); attrs.put(tempGroupKey, "<300");
toMerge.add(item); toMerge.add(item);
} else { // don't merge } else { // don't merge
result.add(item); result.add(item);
} }
} else if (zoom == 9) { } else if (zoom == 9) {
if (WOOD_OR_FOREST.contains(subclass)) { if (WOOD_OR_FOREST.contains(subclass)) {
attrs.put(tempGroupKey, numPoints < 50 ? "<50" : numPoints < 300 ? "<300" : ">300"); attrs.put(tempGroupKey, numPoints < 300 ? "<300" : ">300");
toMerge.add(item); toMerge.add(item);
} else { // don't merge } else { // don't merge
result.add(item); result.add(item);

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -101,6 +101,9 @@ public class Landuse implements
nullIfEmpty(element.waterway()) nullIfEmpty(element.waterway())
); );
if (clazz != null) { if (clazz != null) {
if ("grave_yard".equals(clazz)) {
clazz = FieldValues.CLASS_CEMETERY;
}
features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
.setAttr(Fields.CLASS, clazz) .setAttr(Fields.CLASS, clazz)
.setMinPixelSizeOverrides(MIN_PIXEL_SIZE_THRESHOLDS) .setMinPixelSizeOverrides(MIN_PIXEL_SIZE_THRESHOLDS)

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -48,12 +48,18 @@ import com.onthegomap.planetiler.basemap.generated.Tables;
import com.onthegomap.planetiler.basemap.util.LanguageUtils; import com.onthegomap.planetiler.basemap.util.LanguageUtils;
import com.onthegomap.planetiler.config.PlanetilerConfig; import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.reader.SourceFeature;
import com.onthegomap.planetiler.stats.Stats; import com.onthegomap.planetiler.stats.Stats;
import com.onthegomap.planetiler.util.Parse; import com.onthegomap.planetiler.util.Parse;
import com.onthegomap.planetiler.util.Translations; import com.onthegomap.planetiler.util.Translations;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.prep.PreparedGeometry;
import org.locationtech.jts.geom.prep.PreparedGeometryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Defines the logic for generating map elements for mountain peak label points in the {@code mountain_peak} layer from * Defines the logic for generating map elements for mountain peak label points in the {@code mountain_peak} layer from
@@ -63,8 +69,10 @@ import org.locationtech.jts.geom.Point;
* mountain_peak sql files</a>. * mountain_peak sql files</a>.
*/ */
public class MountainPeak implements public class MountainPeak implements
BasemapProfile.NaturalEarthProcessor,
OpenMapTilesSchema.MountainPeak, OpenMapTilesSchema.MountainPeak,
Tables.OsmPeakPoint.Handler, Tables.OsmPeakPoint.Handler,
Tables.OsmMountainLinestring.Handler,
BasemapProfile.FeaturePostProcessor { BasemapProfile.FeaturePostProcessor {
/* /*
@@ -73,20 +81,40 @@ public class MountainPeak implements
* label density by only taking the top 5 most important mountain peaks within each 100x100px * label density by only taking the top 5 most important mountain peaks within each 100x100px
* square. * square.
*/ */
private static final Logger LOGGER = LoggerFactory.getLogger(TransportationName.class);
private final Translations translations; private final Translations translations;
private final Stats stats; private final Stats stats;
// keep track of areas that prefer feet to meters to set customary_ft=1 (just U.S.)
private PreparedGeometry unitedStates = null;
private final AtomicBoolean loggedNoUS = new AtomicBoolean(false);
public MountainPeak(Translations translations, PlanetilerConfig config, Stats stats) { public MountainPeak(Translations translations, PlanetilerConfig config, Stats stats) {
this.translations = translations; this.translations = translations;
this.stats = stats; this.stats = stats;
} }
@Override
public void processNaturalEarth(String table, SourceFeature feature, FeatureCollector features) {
if ("ne_10m_admin_0_countries".equals(table) && feature.hasTag("iso_a2", "US")) {
// multiple threads call this method concurrently, US polygon *should* only be found
// once, but just to be safe synchronize updates to that field
synchronized (this) {
try {
Geometry boundary = feature.polygon();
unitedStates = PreparedGeometryFactory.prepare(boundary);
} catch (GeometryException e) {
LOGGER.error("Failed to get United States Polygon for mountain_peak layer: " + e);
}
}
}
}
@Override @Override
public void process(Tables.OsmPeakPoint element, FeatureCollector features) { public void process(Tables.OsmPeakPoint element, FeatureCollector features) {
Integer meters = Parse.parseIntSubstring(element.ele()); Integer meters = Parse.parseIntSubstring(element.ele());
if (meters != null && Math.abs(meters) < 10_000) { if (meters != null && Math.abs(meters) < 10_000) {
features.point(LAYER_NAME) var feature = features.point(LAYER_NAME)
.setAttr(Fields.CLASS, element.source().getTag("natural")) .setAttr(Fields.CLASS, element.source().getTag("natural"))
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations)) .putAttrs(LanguageUtils.getNames(element.source().tags(), translations))
.putAttrs(elevationTags(meters)) .putAttrs(elevationTags(meters))
@@ -101,9 +129,46 @@ public class MountainPeak implements
// in adjacent tiles. postProcess() will remove anything outside the desired buffer. // in adjacent tiles. postProcess() will remove anything outside the desired buffer.
.setBufferPixels(100) .setBufferPixels(100)
.setPointLabelGridSizeAndLimit(13, 100, 5); .setPointLabelGridSizeAndLimit(13, 100, 5);
if (peakInAreaUsingFeet(element)) {
feature.setAttr(Fields.CUSTOMARY_FT, 1);
}
} }
} }
@Override
public void process(Tables.OsmMountainLinestring element, FeatureCollector features) {
// TODO rank is approximate to sort important/named ridges before others, should switch to labelgrid for linestrings later
int rank = 3 -
(nullIfEmpty(element.wikipedia()) != null ? 1 : 0) -
(nullIfEmpty(element.name()) != null ? 1 : 0);
features.line(LAYER_NAME)
.setAttr(Fields.CLASS, element.source().getTag("natural"))
.setAttr(Fields.RANK, rank)
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations))
.setSortKey(rank)
.setMinZoom(13)
.setBufferPixels(100);
}
/** Returns true if {@code element} is a point in an area where feet are used insead of meters (the US). */
private boolean peakInAreaUsingFeet(Tables.OsmPeakPoint element) {
if (unitedStates == null) {
if (!loggedNoUS.get() && loggedNoUS.compareAndSet(false, true)) {
LOGGER.warn("No US polygon for inferring mountain_peak customary_ft tag");
}
} else {
try {
Geometry wayGeometry = element.source().worldGeometry();
return unitedStates.intersects(wayGeometry);
} catch (GeometryException e) {
e.log(stats, "omt_mountain_peak_us_test",
"Unable to test mountain_peak against US polygon: " + element.source().id());
}
}
return false;
}
@Override @Override
public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) { public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) {
LongIntMap groupCounts = new LongIntHashMap(); LongIntMap groupCounts = new LongIntHashMap();

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -42,6 +42,7 @@ import static com.onthegomap.planetiler.collection.FeatureGroup.SORT_KEY_BITS;
import com.carrotsearch.hppc.LongIntHashMap; import com.carrotsearch.hppc.LongIntHashMap;
import com.carrotsearch.hppc.LongIntMap; import com.carrotsearch.hppc.LongIntMap;
import com.onthegomap.planetiler.FeatureCollector; import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.FeatureMerge;
import com.onthegomap.planetiler.VectorTile; import com.onthegomap.planetiler.VectorTile;
import com.onthegomap.planetiler.basemap.BasemapProfile; import com.onthegomap.planetiler.basemap.BasemapProfile;
import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema; import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema;
@@ -101,10 +102,10 @@ public class Park implements
); );
// park shape // park shape
features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) var outline = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
.setAttr(Fields.CLASS, clazz) .setAttrWithMinzoom(Fields.CLASS, clazz, 5)
.setMinPixelSize(2) .setMinPixelSize(2)
.setMinZoom(6); .setMinZoom(4);
// park name label point (if it has one) // park name label point (if it has one)
if (element.name() != null) { if (element.name() != null) {
@@ -112,8 +113,13 @@ public class Park implements
double area = element.source().area(); double area = element.source().area();
int minzoom = getMinZoomForArea(area); int minzoom = getMinZoomForArea(area);
features.centroid(LAYER_NAME).setBufferPixels(256) var names = LanguageUtils.getNamesWithoutTranslations(element.source().tags());
outline.putAttrsWithMinzoom(names, 5);
features.pointOnSurface(LAYER_NAME).setBufferPixels(256)
.setAttr(Fields.CLASS, clazz) .setAttr(Fields.CLASS, clazz)
.putAttrs(names)
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations)) .putAttrs(LanguageUtils.getNames(element.source().tags(), translations))
.setPointLabelGridPixelSize(14, 100) .setPointLabelGridPixelSize(14, 100)
.setSortKey(SortKey .setSortKey(SortKey
@@ -132,12 +138,12 @@ public class Park implements
// sql filter: area > 70000*2^(20-zoom_level) // sql filter: area > 70000*2^(20-zoom_level)
// simplifies to: zoom_level > 20 - log(area / 70000) / log(2) // simplifies to: zoom_level > 20 - log(area / 70000) / log(2)
int minzoom = (int) Math.floor(20 - Math.log(area / WORLD_AREA_FOR_70K_SQUARE_METERS) / LOG2); int minzoom = (int) Math.floor(20 - Math.log(area / WORLD_AREA_FOR_70K_SQUARE_METERS) / LOG2);
minzoom = Math.min(14, Math.max(6, minzoom)); minzoom = Math.min(14, Math.max(5, minzoom));
return minzoom; return minzoom;
} }
@Override @Override
public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) { public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) throws GeometryException {
// infer the "rank" attribute from point ordering within each label grid square // infer the "rank" attribute from point ordering within each label grid square
LongIntMap counts = new LongIntHashMap(); LongIntMap counts = new LongIntHashMap();
for (VectorTile.Feature feature : items) { for (VectorTile.Feature feature : items) {
@@ -147,6 +153,9 @@ public class Park implements
counts.put(feature.group(), count); counts.put(feature.group(), count);
} }
} }
if (zoom <= 4) {
items = FeatureMerge.mergeOverlappingPolygons(items, 0);
}
return items; return items;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -171,7 +171,7 @@ public class Place implements
case "ne_10m_admin_1_states_provinces" -> { case "ne_10m_admin_1_states_provinces" -> {
Double scalerank = Parse.parseDoubleOrNull(feature.getTag("scalerank")); Double scalerank = Parse.parseDoubleOrNull(feature.getTag("scalerank"));
Double labelrank = Parse.parseDoubleOrNull(feature.getTag("labelrank")); Double labelrank = Parse.parseDoubleOrNull(feature.getTag("labelrank"));
if (scalerank != null && scalerank <= 3 && labelrank != null && labelrank <= 2) { if (scalerank != null && scalerank <= 6 && labelrank != null && labelrank <= 7) {
states.put(feature.worldGeometry(), new NaturalEarthRegion( states.put(feature.worldGeometry(), new NaturalEarthRegion(
feature.getString("name"), 6, feature.getString("name"), 6,
scalerank, scalerank,
@@ -265,7 +265,7 @@ public class Place implements
features.point(LAYER_NAME).setBufferPixels(BUFFER_SIZE) features.point(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
.putAttrs(names) .putAttrs(names)
.setAttr(Fields.CLASS, FieldValues.CLASS_STATE) .setAttr(Fields.CLASS, element.place())
.setAttr(Fields.RANK, rank) .setAttr(Fields.RANK, rank)
.setMinZoom(2) .setMinZoom(2)
.setSortKey(rank); .setSortKey(rank);

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -36,8 +36,8 @@ See https://github.com/openmaptiles/openmaptiles/blob/master/LICENSE.md for deta
package com.onthegomap.planetiler.basemap.layers; package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.basemap.util.Utils.coalesce; import static com.onthegomap.planetiler.basemap.util.Utils.coalesce;
import static com.onthegomap.planetiler.basemap.util.Utils.nullIf;
import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty; import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty;
import static com.onthegomap.planetiler.basemap.util.Utils.nullIfLong;
import static com.onthegomap.planetiler.basemap.util.Utils.nullOrEmpty; import static com.onthegomap.planetiler.basemap.util.Utils.nullOrEmpty;
import static java.util.Map.entry; import static java.util.Map.entry;
@@ -170,7 +170,7 @@ public class Poi implements
output.setBufferPixels(BUFFER_SIZE) output.setBufferPixels(BUFFER_SIZE)
.setAttr(Fields.CLASS, poiClass) .setAttr(Fields.CLASS, poiClass)
.setAttr(Fields.SUBCLASS, subclass) .setAttr(Fields.SUBCLASS, subclass)
.setAttr(Fields.LAYER, nullIf(element.layer(), 0)) .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0))
.setAttr(Fields.LEVEL, Parse.parseLongOrNull(element.source().getTag("level"))) .setAttr(Fields.LEVEL, Parse.parseLongOrNull(element.source().getTag("level")))
.setAttr(Fields.INDOOR, element.indoor() ? 1 : null) .setAttr(Fields.INDOOR, element.indoor() ? 1 : null)
.putAttrs(LanguageUtils.getNames(element.source().tags(), translations)) .putAttrs(LanguageUtils.getNames(element.source().tags(), translations))

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -36,6 +36,10 @@ See https://github.com/openmaptiles/openmaptiles/blob/master/LICENSE.md for deta
package com.onthegomap.planetiler.basemap.layers; package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.basemap.util.Utils.*; import static com.onthegomap.planetiler.basemap.util.Utils.*;
import static com.onthegomap.planetiler.util.MemoryEstimator.CLASS_HEADER_BYTES;
import static com.onthegomap.planetiler.util.MemoryEstimator.POINTER_BYTES;
import static com.onthegomap.planetiler.util.MemoryEstimator.estimateSize;
import static java.util.Map.entry;
import com.onthegomap.planetiler.FeatureCollector; import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.FeatureMerge; import com.onthegomap.planetiler.FeatureMerge;
@@ -45,15 +49,32 @@ import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema;
import com.onthegomap.planetiler.basemap.generated.Tables; import com.onthegomap.planetiler.basemap.generated.Tables;
import com.onthegomap.planetiler.config.PlanetilerConfig; import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.expression.MultiExpression; import com.onthegomap.planetiler.expression.MultiExpression;
import com.onthegomap.planetiler.geo.GeoUtils;
import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.reader.SourceFeature;
import com.onthegomap.planetiler.reader.osm.OsmElement;
import com.onthegomap.planetiler.reader.osm.OsmReader;
import com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
import com.onthegomap.planetiler.stats.Stats; import com.onthegomap.planetiler.stats.Stats;
import com.onthegomap.planetiler.util.MemoryEstimator;
import com.onthegomap.planetiler.util.Parse; import com.onthegomap.planetiler.util.Parse;
import com.onthegomap.planetiler.util.Translations; import com.onthegomap.planetiler.util.Translations;
import com.onthegomap.planetiler.util.ZoomFunction; import com.onthegomap.planetiler.util.ZoomFunction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.prep.PreparedGeometry;
import org.locationtech.jts.geom.prep.PreparedGeometryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Defines the logic for generating map elements for roads, shipways, railroads, and paths in the {@code transportation} * Defines the logic for generating map elements for roads, shipways, railroads, and paths in the {@code transportation}
@@ -69,7 +90,9 @@ public class Transportation implements
Tables.OsmRailwayLinestring.Handler, Tables.OsmRailwayLinestring.Handler,
Tables.OsmShipwayLinestring.Handler, Tables.OsmShipwayLinestring.Handler,
Tables.OsmHighwayPolygon.Handler, Tables.OsmHighwayPolygon.Handler,
BasemapProfile.NaturalEarthProcessor,
BasemapProfile.FeaturePostProcessor, BasemapProfile.FeaturePostProcessor,
BasemapProfile.OsmRelationPreprocessor,
BasemapProfile.IgnoreWikidata { BasemapProfile.IgnoreWikidata {
/* /*
@@ -78,6 +101,8 @@ public class Transportation implements
* layer includes names, but less detailed attributes. * layer includes names, but less detailed attributes.
*/ */
private static final Logger LOGGER = LoggerFactory.getLogger(Transportation.class);
private static final Pattern GREAT_BRITAIN_REF_NETWORK_PATTERN = Pattern.compile("^[AM][0-9AM()]+");
private static final MultiExpression.Index<String> classMapping = FieldMappings.Class.index(); private static final MultiExpression.Index<String> classMapping = FieldMappings.Class.index();
private static final Set<String> RAILWAY_RAIL_VALUES = Set.of( private static final Set<String> RAILWAY_RAIL_VALUES = Set.of(
FieldValues.SUBCLASS_RAIL, FieldValues.SUBCLASS_RAIL,
@@ -108,11 +133,24 @@ public class Transportation implements
"paved", "asphalt", "cobblestone", "concrete", "concrete:lanes", "concrete:plates", "metal", "paved", "asphalt", "cobblestone", "concrete", "concrete:lanes", "concrete:plates", "metal",
"paving_stones", "sett", "unhewn_cobblestone", "wood" "paving_stones", "sett", "unhewn_cobblestone", "wood"
); );
private static final Set<String> ACCESS_NO_VALUES = Set.of(
"private", "no"
);
private static final ZoomFunction.MeterToPixelThresholds MIN_LENGTH = ZoomFunction.meterThresholds() private static final ZoomFunction.MeterToPixelThresholds MIN_LENGTH = ZoomFunction.meterThresholds()
.put(7, 50) .put(7, 50)
.put(6, 100) .put(6, 100)
.put(5, 500) .put(5, 500)
.put(4, 1_000); .put(4, 1_000);
// ORDER BY network_type, network, LENGTH(ref), ref)
private static final Comparator<RouteRelation> RELATION_ORDERING = Comparator
.<RouteRelation>comparingInt(
r -> r.networkType() != null ? r.networkType.ordinal() : Integer.MAX_VALUE)
.thenComparing(routeRelation -> coalesce(routeRelation.network(), ""))
.thenComparingInt(r -> r.ref().length())
.thenComparing(RouteRelation::ref);
private final AtomicBoolean loggedNoGb = new AtomicBoolean(false);
private final boolean z13Paths;
private PreparedGeometry greatBritain = null;
private final Map<String, Integer> MINZOOMS; private final Map<String, Integer> MINZOOMS;
private final Stats stats; private final Stats stats;
private final PlanetilerConfig config; private final PlanetilerConfig config;
@@ -120,30 +158,54 @@ public class Transportation implements
public Transportation(Translations translations, PlanetilerConfig config, Stats stats) { public Transportation(Translations translations, PlanetilerConfig config, Stats stats) {
this.config = config; this.config = config;
this.stats = stats; this.stats = stats;
boolean z13Paths = config.arguments().getBoolean( z13Paths = config.arguments().getBoolean(
"transportation_z13_paths", "transportation_z13_paths",
"transportation(_name) layer: show paths on z13", "transportation(_name) layer: show all paths on z13",
true false
); );
MINZOOMS = Map.of( MINZOOMS = Map.ofEntries(
FieldValues.CLASS_TRACK, 14, entry(FieldValues.CLASS_PATH, z13Paths ? 13 : 14),
FieldValues.CLASS_PATH, z13Paths ? 13 : 14, entry(FieldValues.CLASS_TRACK, 14),
FieldValues.CLASS_MINOR, 13, entry(FieldValues.CLASS_SERVICE, 13),
FieldValues.CLASS_RACEWAY, 12, entry(FieldValues.CLASS_MINOR, 13),
FieldValues.CLASS_TERTIARY, 11, entry(FieldValues.CLASS_RACEWAY, 12),
FieldValues.CLASS_SECONDARY, 9, entry(FieldValues.CLASS_TERTIARY, 11),
FieldValues.CLASS_PRIMARY, 7, entry(FieldValues.CLASS_BUSWAY, 11),
FieldValues.CLASS_TRUNK, 5, entry(FieldValues.CLASS_SECONDARY, 9),
FieldValues.CLASS_MOTORWAY, 4 entry(FieldValues.CLASS_PRIMARY, 7),
entry(FieldValues.CLASS_TRUNK, 5),
entry(FieldValues.CLASS_MOTORWAY, 4)
); );
} }
@Override
public void processNaturalEarth(String table, SourceFeature feature,
FeatureCollector features) {
if ("ne_10m_admin_0_countries".equals(table) && feature.hasTag("iso_a2", "GB")) {
// multiple threads call this method concurrently, GB polygon *should* only be found
// once, but just to be safe synchronize updates to that field
synchronized (this) {
try {
Geometry boundary = feature.polygon().buffer(GeoUtils.metersToPixelAtEquator(0, 10_000) / 256d);
greatBritain = PreparedGeometryFactory.prepare(boundary);
} catch (GeometryException e) {
LOGGER.error("Failed to get Great Britain Polygon: " + e);
}
}
}
}
/** Returns a value for {@code surface} tag constrained to a small set of known values from raw OSM data. */ /** Returns a value for {@code surface} tag constrained to a small set of known values from raw OSM data. */
private static String surface(String value) { private static String surface(String value) {
return value == null ? null : SURFACE_PAVED_VALUES.contains(value) ? FieldValues.SURFACE_PAVED : return value == null ? null : SURFACE_PAVED_VALUES.contains(value) ? FieldValues.SURFACE_PAVED :
SURFACE_UNPAVED_VALUES.contains(value) ? FieldValues.SURFACE_UNPAVED : null; SURFACE_UNPAVED_VALUES.contains(value) ? FieldValues.SURFACE_UNPAVED : null;
} }
/** Returns a value for {@code access} tag constrained to a small set of known values from raw OSM data. */
private static String access(String value) {
return value == null ? null : ACCESS_NO_VALUES.contains(value) ? "no" : null;
}
/** Returns a value for {@code service} tag constrained to a small set of known values from raw OSM data. */ /** Returns a value for {@code service} tag constrained to a small set of known values from raw OSM data. */
private static String service(String value) { private static String service(String value) {
return (value == null || !SERVICE_VALUES.contains(value)) ? null : value; return (value == null || !SERVICE_VALUES.contains(value)) ? null : value;
@@ -171,68 +233,160 @@ public class Transportation implements
return "footway".equals(highway) || "steps".equals(highway); return "footway".equals(highway) || "steps".equals(highway);
} }
static boolean isLink(String highway) {
return highway != null && highway.endsWith("_link");
}
private static boolean isResidentialOrUnclassified(String highway) { private static boolean isResidentialOrUnclassified(String highway) {
return "residential".equals(highway) || "unclassified".equals(highway); return "residential".equals(highway) || "unclassified".equals(highway);
} }
private static boolean isDrivewayOrParkingAisle(String service) {
return FieldValues.SERVICE_PARKING_AISLE.equals(service) || FieldValues.SERVICE_DRIVEWAY.equals(service);
}
private static boolean isBridgeOrPier(String manMade) { private static boolean isBridgeOrPier(String manMade) {
return "bridge".equals(manMade) || "pier".equals(manMade); return "bridge".equals(manMade) || "pier".equals(manMade);
} }
enum RouteNetwork {
US_INTERSTATE("us-interstate"),
US_HIGHWAY("us-highway"),
US_STATE("us-state"),
CA_TRANSCANADA("ca-transcanada"),
GB_MOTORWAY("gb-motorway"),
GB_TRUNK("gb-trunk");
final String name;
RouteNetwork(String name) {
this.name = name;
}
}
@Override
public List<OsmRelationInfo> preprocessOsmRelation(OsmElement.Relation relation) {
if (relation.hasTag("route", "road", "hiking")) {
RouteNetwork networkType = null;
String network = relation.getString("network");
String ref = relation.getString("ref");
if ("US:I".equals(network)) {
networkType = RouteNetwork.US_INTERSTATE;
} else if ("US:US".equals(network)) {
networkType = RouteNetwork.US_HIGHWAY;
} else if (network != null && network.length() == 5 && network.startsWith("US:")) {
networkType = RouteNetwork.US_STATE;
} else if (network != null && network.startsWith("CA:transcanada")) {
networkType = RouteNetwork.CA_TRANSCANADA;
}
int rank = switch (coalesce(network, "")) {
case "iwn", "nwn", "rwn" -> 1;
case "lwn" -> 2;
default -> (relation.hasTag("osmc:symbol") || relation.hasTag("colour")) ? 2 : 3;
};
if (networkType != null || rank < 3) {
return List.of(new RouteRelation(coalesce(ref, ""), network, networkType, (byte) rank, relation.id()));
}
}
return null;
}
List<RouteRelation> getRouteRelations(Tables.OsmHighwayLinestring element) {
String ref = element.ref();
List<OsmReader.RelationMember<RouteRelation>> relations = element.source().relationInfo(RouteRelation.class);
List<RouteRelation> result = new ArrayList<>(relations.size() + 1);
for (var relationMember : relations) {
var relation = relationMember.relation();
// avoid duplicates - list should be very small and usually only one
if (!result.contains(relation)) {
result.add(relation);
}
}
if (ref != null) {
// GB doesn't use regular relations like everywhere else, so if we are
// in GB then use a naming convention instead.
Matcher refMatcher = GREAT_BRITAIN_REF_NETWORK_PATTERN.matcher(ref);
if (refMatcher.find()) {
if (greatBritain == null) {
if (!loggedNoGb.get() && loggedNoGb.compareAndSet(false, true)) {
LOGGER.warn("No GB polygon for inferring route network types");
}
} else {
try {
Geometry wayGeometry = element.source().worldGeometry();
if (greatBritain.intersects(wayGeometry)) {
Transportation.RouteNetwork networkType =
"motorway".equals(element.highway()) ? Transportation.RouteNetwork.GB_MOTORWAY
: Transportation.RouteNetwork.GB_TRUNK;
String network = "motorway".equals(element.highway()) ? "omt-gb-motorway" : "omt-gb-trunk";
result.add(new RouteRelation(refMatcher.group(), network, networkType, (byte) -1,
0));
}
} catch (GeometryException e) {
e.log(stats, "omt_transportation_name_gb_test",
"Unable to test highway against GB route network: " + element.source().id());
}
}
}
}
Collections.sort(result);
return result;
}
RouteRelation getRouteRelation(Tables.OsmHighwayLinestring element) {
List<RouteRelation> all = getRouteRelations(element);
return all.isEmpty() ? null : all.get(0);
}
@Override @Override
public void process(Tables.OsmHighwayLinestring element, FeatureCollector features) { public void process(Tables.OsmHighwayLinestring element, FeatureCollector features) {
if (element.isArea()) { if (element.isArea()) {
return; return;
} }
RouteRelation routeRelation = getRouteRelation(element);
RouteNetwork networkType = routeRelation != null ? routeRelation.networkType : null;
String highway = element.highway(); String highway = element.highway();
String highwayClass = highwayClass(element.highway(), element.publicTransport(), element.construction(), String highwayClass = highwayClass(element.highway(), element.publicTransport(), element.construction(),
element.manMade()); element.manMade());
String service = service(element.service());
if (highwayClass != null) { if (highwayClass != null) {
int minzoom; if (isPierPolygon(element)) {
if ("pier".equals(element.manMade())) { return;
try {
if (element.source().worldGeometry() instanceof LineString lineString && lineString.isClosed()) {
// ignore this because it's a polygon
return;
}
} catch (GeometryException e) {
e.log(stats, "omt_transportation_pier",
"Unable to decode pier geometry for " + element.source().id());
return;
}
minzoom = 13;
} else if (isResidentialOrUnclassified(highway)) {
minzoom = 12;
} else {
String baseClass = highwayClass.replace("_construction", "");
minzoom = MINZOOMS.getOrDefault(baseClass, 12);
} }
boolean highwayIsLink = coalesce(highway, "").endsWith("_link"); int minzoom = getMinzoom(element, highwayClass);
if (highwayIsLink) { boolean highwayRamp = isLink(highway);
minzoom = Math.max(minzoom, 9); Integer rampAboveZ12 = (highwayRamp || element.isRamp()) ? 1 : null;
} Integer rampBelowZ12 = highwayRamp ? 1 : null;
boolean highwayRamp = highwayIsLink || "steps".equals(highway);
int rampAboveZ12 = (highwayRamp || element.isRamp()) ? 1 : 0;
int rampBelowZ12 = highwayRamp ? 1 : 0;
FeatureCollector.Feature feature = features.line(LAYER_NAME).setBufferPixels(BUFFER_SIZE) FeatureCollector.Feature feature = features.line(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
// main attributes at all zoom levels (used for grouping <= z8) // main attributes at all zoom levels (used for grouping <= z8)
.setAttr(Fields.CLASS, highwayClass) .setAttr(Fields.CLASS, highwayClass)
.setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, element.publicTransport(), highway)) .setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, element.publicTransport(), highway))
.setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord())) .setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord()))
// rest at z9+ .setAttr(Fields.NETWORK, networkType != null ? networkType.name : null)
.setAttrWithMinzoom(Fields.SERVICE, service(element.service()), 12) // z8+
.setAttrWithMinzoom(Fields.ONEWAY, element.isOneway(), 12) .setAttrWithMinzoom(Fields.EXPRESSWAY, element.expressway() && !"motorway".equals(highway) ? 1 : null, 8)
.setAttr(Fields.RAMP, minzoom >= 12 ? rampAboveZ12 : // z9+
((ZoomFunction<Integer>) z -> z < 9 ? null : z >= 12 ? rampAboveZ12 : rampBelowZ12)) .setAttrWithMinzoom(Fields.LAYER, nullIfLong(element.layer(), 0), 9)
.setAttrWithMinzoom(Fields.LAYER, nullIf(element.layer(), 0), 9)
.setAttrWithMinzoom(Fields.BICYCLE, nullIfEmpty(element.bicycle()), 9) .setAttrWithMinzoom(Fields.BICYCLE, nullIfEmpty(element.bicycle()), 9)
.setAttrWithMinzoom(Fields.FOOT, nullIfEmpty(element.foot()), 9) .setAttrWithMinzoom(Fields.FOOT, nullIfEmpty(element.foot()), 9)
.setAttrWithMinzoom(Fields.HORSE, nullIfEmpty(element.horse()), 9) .setAttrWithMinzoom(Fields.HORSE, nullIfEmpty(element.horse()), 9)
.setAttrWithMinzoom(Fields.MTB_SCALE, nullIfEmpty(element.mtbScale()), 9) .setAttrWithMinzoom(Fields.MTB_SCALE, nullIfEmpty(element.mtbScale()), 9)
.setAttrWithMinzoom(Fields.ACCESS, access(element.access()), 9)
.setAttrWithMinzoom(Fields.TOLL, element.toll() ? 1 : null, 9)
// sometimes z9+, sometimes z12+
.setAttr(Fields.RAMP, minzoom >= 12 ? rampAboveZ12 :
((ZoomFunction<Integer>) z -> z < 9 ? null : z >= 12 ? rampAboveZ12 : rampBelowZ12))
// z12+
.setAttrWithMinzoom(Fields.SERVICE, service, 12)
.setAttrWithMinzoom(Fields.ONEWAY, nullIfInt(element.isOneway(), 0), 12)
.setAttrWithMinzoom(Fields.SURFACE, surface(element.surface()), 12) .setAttrWithMinzoom(Fields.SURFACE, surface(element.surface()), 12)
.setMinPixelSize(0) // merge during post-processing, then limit by size .setMinPixelSize(0) // merge during post-processing, then limit by size
.setSortKey(element.zOrder()) .setSortKey(element.zOrder())
@@ -246,6 +400,53 @@ public class Transportation implements
} }
} }
int getMinzoom(Tables.OsmHighwayLinestring element, String highwayClass) {
List<RouteRelation> routeRelations = getRouteRelations(element);
int routeRank = 3;
for (var rel : routeRelations) {
if (rel.intRank() < routeRank) {
routeRank = rel.intRank();
}
}
String highway = element.highway();
int minzoom;
if ("pier".equals(element.manMade())) {
minzoom = 13;
} else if (isResidentialOrUnclassified(highway)) {
minzoom = 12;
} else {
String baseClass = highwayClass.replace("_construction", "");
minzoom = switch (baseClass) {
case FieldValues.CLASS_SERVICE -> isDrivewayOrParkingAisle(service(element.service())) ? 14 : 13;
case FieldValues.CLASS_TRACK, FieldValues.CLASS_PATH -> routeRank == 1 ? 12 :
(z13Paths || !nullOrEmpty(element.name()) || routeRank <= 2 || !nullOrEmpty(element.sacScale())) ? 13 : 14;
default -> MINZOOMS.get(baseClass);
};
}
if (isLink(highway)) {
minzoom = Math.max(minzoom, 9);
}
return minzoom;
}
private boolean isPierPolygon(Tables.OsmHighwayLinestring element) {
if ("pier".equals(element.manMade())) {
try {
if (element.source().worldGeometry() instanceof LineString lineString && lineString.isClosed()) {
// ignore this because it's a polygon
return true;
}
} catch (GeometryException e) {
e.log(stats, "omt_transportation_pier",
"Unable to decode pier geometry for " + element.source().id());
return true;
}
}
return false;
}
@Override @Override
public void process(Tables.OsmRailwayLinestring element, FeatureCollector features) { public void process(Tables.OsmRailwayLinestring element, FeatureCollector features) {
String railway = element.railway(); String railway = element.railway();
@@ -268,10 +469,10 @@ public class Transportation implements
.setAttr(Fields.CLASS, clazz) .setAttr(Fields.CLASS, clazz)
.setAttr(Fields.SUBCLASS, railway) .setAttr(Fields.SUBCLASS, railway)
.setAttr(Fields.SERVICE, service(service)) .setAttr(Fields.SERVICE, service(service))
.setAttr(Fields.ONEWAY, element.isOneway()) .setAttr(Fields.ONEWAY, nullIfInt(element.isOneway(), 0))
.setAttr(Fields.RAMP, element.isRamp() ? 1 : 0) .setAttr(Fields.RAMP, element.isRamp() ? 1L : null)
.setAttrWithMinzoom(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord()), 10) .setAttrWithMinzoom(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord()), 10)
.setAttrWithMinzoom(Fields.LAYER, nullIf(element.layer(), 0), 9) .setAttrWithMinzoom(Fields.LAYER, nullIfLong(element.layer(), 0), 9)
.setSortKey(element.zOrder()) .setSortKey(element.zOrder())
.setMinPixelSize(0) // merge during post-processing, then limit by size .setMinPixelSize(0) // merge during post-processing, then limit by size
.setMinZoom(minzoom); .setMinZoom(minzoom);
@@ -284,10 +485,10 @@ public class Transportation implements
.setAttr(Fields.CLASS, "aerialway") .setAttr(Fields.CLASS, "aerialway")
.setAttr(Fields.SUBCLASS, element.aerialway()) .setAttr(Fields.SUBCLASS, element.aerialway())
.setAttr(Fields.SERVICE, service(element.service())) .setAttr(Fields.SERVICE, service(element.service()))
.setAttr(Fields.ONEWAY, element.isOneway()) .setAttr(Fields.ONEWAY, nullIfInt(element.isOneway(), 0))
.setAttr(Fields.RAMP, element.isRamp() ? 1 : 0) .setAttr(Fields.RAMP, element.isRamp() ? 1L : null)
.setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord())) .setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord()))
.setAttr(Fields.LAYER, nullIf(element.layer(), 0)) .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0))
.setSortKey(element.zOrder()) .setSortKey(element.zOrder())
.setMinPixelSize(0) // merge during post-processing, then limit by size .setMinPixelSize(0) // merge during post-processing, then limit by size
.setMinZoom(12); .setMinZoom(12);
@@ -299,10 +500,10 @@ public class Transportation implements
.setAttr(Fields.CLASS, element.shipway()) // "ferry" .setAttr(Fields.CLASS, element.shipway()) // "ferry"
// no subclass // no subclass
.setAttr(Fields.SERVICE, service(element.service())) .setAttr(Fields.SERVICE, service(element.service()))
.setAttr(Fields.ONEWAY, element.isOneway()) .setAttr(Fields.ONEWAY, nullIfInt(element.isOneway(), 0))
.setAttr(Fields.RAMP, element.isRamp() ? 1 : 0) .setAttr(Fields.RAMP, element.isRamp() ? 1L : null)
.setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord())) .setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord()))
.setAttr(Fields.LAYER, nullIf(element.layer(), 0)) .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0))
.setSortKey(element.zOrder()) .setSortKey(element.zOrder())
.setMinPixelSize(0) // merge during post-processing, then limit by size .setMinPixelSize(0) // merge during post-processing, then limit by size
.setMinZoom(11); .setMinZoom(11);
@@ -320,7 +521,7 @@ public class Transportation implements
.setAttr(Fields.CLASS, highwayClass) .setAttr(Fields.CLASS, highwayClass)
.setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, element.publicTransport(), element.highway())) .setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, element.publicTransport(), element.highway()))
.setAttr(Fields.BRUNNEL, brunnel("bridge".equals(manMade), false, false)) .setAttr(Fields.BRUNNEL, brunnel("bridge".equals(manMade), false, false))
.setAttr(Fields.LAYER, nullIf(element.layer(), 0)) .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0))
.setSortKey(element.zOrder()) .setSortKey(element.zOrder())
.setMinZoom(13); .setMinZoom(13);
} }
@@ -330,7 +531,37 @@ public class Transportation implements
@Override @Override
public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) { public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) {
double tolerance = config.tolerance(zoom); double tolerance = config.tolerance(zoom);
double minLength = coalesce(MIN_LENGTH.apply(zoom), config.minFeatureSize(zoom)).doubleValue(); double minLength = coalesce(MIN_LENGTH.apply(zoom), 0).doubleValue();
// TODO preserve direction for one-way?
return FeatureMerge.mergeLineStrings(items, minLength, tolerance, BUFFER_SIZE); return FeatureMerge.mergeLineStrings(items, minLength, tolerance, BUFFER_SIZE);
} }
/** Information extracted from route relations to use when processing ways in that relation. */
record RouteRelation(
String ref,
String network,
RouteNetwork networkType,
byte rank,
@Override long id
) implements OsmRelationInfo, Comparable<RouteRelation> {
@Override
public long estimateMemoryUsageBytes() {
return CLASS_HEADER_BYTES +
MemoryEstimator.estimateSize(rank) +
POINTER_BYTES + estimateSize(ref) +
POINTER_BYTES + estimateSize(network) +
POINTER_BYTES + // networkType
MemoryEstimator.estimateSizeLong(id);
}
public int intRank() {
return rank;
}
@Override
public int compareTo(RouteRelation o) {
return RELATION_ORDERING.compare(this, o);
}
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -38,45 +38,30 @@ package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.basemap.layers.Transportation.highwayClass; import static com.onthegomap.planetiler.basemap.layers.Transportation.highwayClass;
import static com.onthegomap.planetiler.basemap.layers.Transportation.highwaySubclass; import static com.onthegomap.planetiler.basemap.layers.Transportation.highwaySubclass;
import static com.onthegomap.planetiler.basemap.layers.Transportation.isFootwayOrSteps; import static com.onthegomap.planetiler.basemap.layers.Transportation.isFootwayOrSteps;
import static com.onthegomap.planetiler.basemap.util.Utils.brunnel; import static com.onthegomap.planetiler.basemap.util.Utils.*;
import static com.onthegomap.planetiler.basemap.util.Utils.coalesce;
import static com.onthegomap.planetiler.basemap.util.Utils.nullIf;
import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty;
import static com.onthegomap.planetiler.util.MemoryEstimator.CLASS_HEADER_BYTES;
import static com.onthegomap.planetiler.util.MemoryEstimator.POINTER_BYTES;
import static com.onthegomap.planetiler.util.MemoryEstimator.estimateSize;
import com.carrotsearch.hppc.LongArrayList;
import com.carrotsearch.hppc.LongByteHashMap;
import com.carrotsearch.hppc.LongByteMap;
import com.onthegomap.planetiler.FeatureCollector; import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.FeatureMerge; import com.onthegomap.planetiler.FeatureMerge;
import com.onthegomap.planetiler.ForwardingProfile;
import com.onthegomap.planetiler.VectorTile; import com.onthegomap.planetiler.VectorTile;
import com.onthegomap.planetiler.basemap.BasemapProfile; import com.onthegomap.planetiler.basemap.BasemapProfile;
import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema; import com.onthegomap.planetiler.basemap.generated.OpenMapTilesSchema;
import com.onthegomap.planetiler.basemap.generated.Tables; import com.onthegomap.planetiler.basemap.generated.Tables;
import com.onthegomap.planetiler.basemap.util.LanguageUtils; import com.onthegomap.planetiler.basemap.util.LanguageUtils;
import com.onthegomap.planetiler.config.PlanetilerConfig; import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.geo.GeoUtils;
import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.reader.SourceFeature;
import com.onthegomap.planetiler.reader.osm.OsmElement; import com.onthegomap.planetiler.reader.osm.OsmElement;
import com.onthegomap.planetiler.reader.osm.OsmReader;
import com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
import com.onthegomap.planetiler.stats.Stats; import com.onthegomap.planetiler.stats.Stats;
import com.onthegomap.planetiler.util.MemoryEstimator;
import com.onthegomap.planetiler.util.Parse; import com.onthegomap.planetiler.util.Parse;
import com.onthegomap.planetiler.util.Translations; import com.onthegomap.planetiler.util.Translations;
import com.onthegomap.planetiler.util.ZoomFunction; import com.onthegomap.planetiler.util.ZoomFunction;
import java.util.Comparator; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.prep.PreparedGeometry;
import org.locationtech.jts.geom.prep.PreparedGeometryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Defines the logic for generating map elements for road, shipway, rail, and path names in the {@code * Defines the logic for generating map elements for road, shipway, rail, and path names in the {@code
@@ -87,14 +72,17 @@ import org.slf4j.LoggerFactory;
*/ */
public class TransportationName implements public class TransportationName implements
OpenMapTilesSchema.TransportationName, OpenMapTilesSchema.TransportationName,
Tables.OsmHighwayPoint.Handler,
Tables.OsmHighwayLinestring.Handler, Tables.OsmHighwayLinestring.Handler,
BasemapProfile.NaturalEarthProcessor, Tables.OsmAerialwayLinestring.Handler,
Tables.OsmShipwayLinestring.Handler,
BasemapProfile.FeaturePostProcessor, BasemapProfile.FeaturePostProcessor,
BasemapProfile.OsmRelationPreprocessor, BasemapProfile.IgnoreWikidata,
BasemapProfile.IgnoreWikidata { ForwardingProfile.OsmNodePreprocessor,
ForwardingProfile.OsmWayPreprocessor {
/* /*
* Generate road names from OSM data. Route network and ref are copied * Generate road names from OSM data. Route networkType and ref are copied
* from relations that roads are a part of - except in Great Britain which * from relations that roads are a part of - except in Great Britain which
* uses a naming convention instead of relations. * uses a naming convention instead of relations.
* *
@@ -113,8 +101,6 @@ public class TransportationName implements
private static final String LINK_TEMP_KEY = "__islink"; private static final String LINK_TEMP_KEY = "__islink";
private static final String RELATION_ID_TEMP_KEY = "__relid"; private static final String RELATION_ID_TEMP_KEY = "__relid";
private static final Logger LOGGER = LoggerFactory.getLogger(TransportationName.class);
private static final Pattern GREAT_BRITAIN_REF_NETWORK_PATTERN = Pattern.compile("^[AM][0-9AM()]+");
private static final ZoomFunction.MeterToPixelThresholds MIN_LENGTH = ZoomFunction.meterThresholds() private static final ZoomFunction.MeterToPixelThresholds MIN_LENGTH = ZoomFunction.meterThresholds()
.put(6, 20_000) .put(6, 20_000)
.put(7, 20_000) .put(7, 20_000)
@@ -122,23 +108,23 @@ public class TransportationName implements
.put(9, 8_000) .put(9, 8_000)
.put(10, 8_000) .put(10, 8_000)
.put(11, 8_000); .put(11, 8_000);
private static final Comparator<RouteRelation> RELATION_ORDERING = Comparator private static final List<String> CONCURRENT_ROUTE_KEYS = List.of(
.<RouteRelation>comparingInt(r -> r.network.ordinal()) Fields.ROUTE_1,
// TODO also compare network string? Fields.ROUTE_2,
.thenComparingInt(r -> r.ref.length()) Fields.ROUTE_3,
.thenComparing(RouteRelation::ref); Fields.ROUTE_4,
private final Map<String, Integer> MINZOOMS; Fields.ROUTE_5,
Fields.ROUTE_6
);
private final boolean brunnel; private final boolean brunnel;
private final boolean sizeForShield; private final boolean sizeForShield;
private final boolean limitMerge; private final boolean limitMerge;
private final Stats stats;
private final PlanetilerConfig config; private final PlanetilerConfig config;
private final AtomicBoolean loggedNoGb = new AtomicBoolean(false); private Transportation transportation;
private PreparedGeometry greatBritain = null; private final LongByteMap motorwayJunctionHighwayClasses = new LongByteHashMap();
public TransportationName(Translations translations, PlanetilerConfig config, Stats stats) { public TransportationName(Translations translations, PlanetilerConfig config, Stats stats) {
this.config = config; this.config = config;
this.stats = stats;
this.brunnel = config.arguments().getBoolean( this.brunnel = config.arguments().getBoolean(
"transportation_name_brunnel", "transportation_name_brunnel",
"transportation_name layer: set to false to omit brunnel and help merge long highways", "transportation_name layer: set to false to omit brunnel and help merge long highways",
@@ -154,71 +140,72 @@ public class TransportationName implements
"transportation_name layer: limit merge so we don't combine different relations to help merge long highways", "transportation_name layer: limit merge so we don't combine different relations to help merge long highways",
false false
); );
boolean z13Paths = config.arguments().getBoolean( }
"transportation_z13_paths",
"transportation(_name) layer: show paths on z13", public void needsTransportationLayer(Transportation transportation) {
true this.transportation = transportation;
); }
MINZOOMS = Map.of(
FieldValues.CLASS_TRACK, 14,
FieldValues.CLASS_PATH, z13Paths ? 13 : 14, @Override
FieldValues.CLASS_MINOR, 13, public void preprocessOsmNode(OsmElement.Node node) {
FieldValues.CLASS_TRUNK, 8, if (node.hasTag("highway", "motorway_junction")) {
FieldValues.CLASS_MOTORWAY, 6 motorwayJunctionHighwayClasses.put(node.id(), HighwayClass.UNKNOWN.value);
// default: 12 }
);
} }
@Override @Override
public void processNaturalEarth(String table, SourceFeature feature, public void preprocessOsmWay(OsmElement.Way way) {
FeatureCollector features) { String highway = way.getString("highway");
if ("ne_10m_admin_0_countries".equals(table) && feature.hasTag("iso_a2", "GB")) { if (highway != null) {
// multiple threads call this method concurrently, GB polygon *should* only be found HighwayClass cls = HighwayClass.from(highway);
// once, but just to be safe synchronize updates to that field if (cls != HighwayClass.UNKNOWN) {
synchronized (this) { LongArrayList nodes = way.nodes();
try { for (int i = 0; i < nodes.size(); i++) {
Geometry boundary = feature.polygon().buffer(GeoUtils.metersToPixelAtEquator(0, 10_000) / 256d); long node = nodes.get(i);
greatBritain = PreparedGeometryFactory.prepare(boundary); if (motorwayJunctionHighwayClasses.containsKey(node)) {
} catch (GeometryException e) { byte oldValue = motorwayJunctionHighwayClasses.get(node);
LOGGER.error("Failed to get Great Britain Polygon: " + e); byte newValue = cls.value;
if (newValue > oldValue) {
motorwayJunctionHighwayClasses.put(node, newValue);
}
}
} }
} }
} }
} }
@Override @Override
public List<OsmRelationInfo> preprocessOsmRelation(OsmElement.Relation relation) { public void process(Tables.OsmHighwayPoint element, FeatureCollector features) {
if (relation.hasTag("route", "road")) { long id = element.source().id();
RouteNetwork networkType = null; byte value = motorwayJunctionHighwayClasses.getOrDefault(id, (byte) -1);
String network = relation.getString("network"); if (value > 0) {
String ref = relation.getString("ref"); HighwayClass cls = HighwayClass.from(value);
if (cls != HighwayClass.UNKNOWN) {
String subclass = FieldValues.SUBCLASS_JUNCTION;
String ref = element.ref();
if ("US:I".equals(network)) { features.point(LAYER_NAME)
networkType = RouteNetwork.US_INTERSTATE; .setBufferPixels(BUFFER_SIZE)
} else if ("US:US".equals(network)) { .putAttrs(LanguageUtils.getNamesWithoutTranslations(element.source().tags()))
networkType = RouteNetwork.US_HIGHWAY; .setAttr(Fields.REF, ref)
} else if (network != null && network.length() == 5 && network.startsWith("US:")) { .setAttr(Fields.REF_LENGTH, ref != null ? ref.length() : null)
networkType = RouteNetwork.US_STATE; .setAttr(Fields.CLASS, highwayClass(cls.highwayValue, null, null, null))
} else if (network != null && network.startsWith("CA:transcanada")) { .setAttr(Fields.SUBCLASS, subclass)
networkType = RouteNetwork.CA_TRANSCANADA; .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0))
} .setSortKeyDescending(element.zOrder())
.setMinZoom(10);
if (networkType != null) {
return List.of(new RouteRelation(coalesce(ref, ""), networkType, relation.id()));
} }
} }
return null;
} }
@Override @Override
public void process(Tables.OsmHighwayLinestring element, FeatureCollector features) { public void process(Tables.OsmHighwayLinestring element, FeatureCollector features) {
List<OsmReader.RelationMember<RouteRelation>> relations = element.source()
.relationInfo(RouteRelation.class);
String ref = element.ref(); String ref = element.ref();
RouteRelation relation = getRouteRelation(element, relations, ref); List<Transportation.RouteRelation> relations = transportation.getRouteRelations(element);
if (relation != null && nullIfEmpty(relation.ref) != null) { Transportation.RouteRelation relation = relations.isEmpty() ? null : relations.get(0);
ref = relation.ref; if (relation != null && nullIfEmpty(relation.ref()) != null) {
ref = relation.ref();
} }
String name = nullIfEmpty(element.name()); String name = nullIfEmpty(element.name());
@@ -230,13 +217,15 @@ public class TransportationName implements
return; return;
} }
boolean isLink = Transportation.isLink(highway);
String baseClass = highwayClass.replace("_construction", ""); String baseClass = highwayClass.replace("_construction", "");
int minzoom = MINZOOMS.getOrDefault(baseClass, 12); int minzoom = FieldValues.CLASS_TRUNK.equals(baseClass) ? 8 :
boolean isLink = highway.endsWith("_link"); FieldValues.CLASS_MOTORWAY.equals(baseClass) ? 6 :
if (isLink) { isLink ? 13 : 12; // fallback - get from line minzoom, but floor at 12
minzoom = Math.max(13, minzoom);
} // inherit min zoom threshold from visible road, and ensure we never show a label on a road that's not visible yet.
minzoom = Math.max(minzoom, transportation.getMinzoom(element, highwayClass));
FeatureCollector.Feature feature = features.line(LAYER_NAME) FeatureCollector.Feature feature = features.line(LAYER_NAME)
.setBufferPixels(BUFFER_SIZE) .setBufferPixels(BUFFER_SIZE)
@@ -246,13 +235,21 @@ public class TransportationName implements
.setAttr(Fields.REF, ref) .setAttr(Fields.REF, ref)
.setAttr(Fields.REF_LENGTH, ref != null ? ref.length() : null) .setAttr(Fields.REF_LENGTH, ref != null ? ref.length() : null)
.setAttr(Fields.NETWORK, .setAttr(Fields.NETWORK,
(relation != null && relation.network != null) ? relation.network.name : ref != null ? "road" : null) (relation != null && relation.networkType() != null) ? relation.networkType().name
: !nullOrEmpty(ref) ? "road" : null)
.setAttr(Fields.CLASS, highwayClass) .setAttr(Fields.CLASS, highwayClass)
.setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, null, highway)) .setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, null, highway))
.setMinPixelSize(0) .setMinPixelSize(0)
.setSortKey(element.zOrder()) .setSortKey(element.zOrder())
.setMinZoom(minzoom); .setMinZoom(minzoom);
// populate route_1, route_2, ... tags
for (int i = 0; i < Math.min(CONCURRENT_ROUTE_KEYS.size(), relations.size()); i++) {
Transportation.RouteRelation routeRelation = relations.get(i);
feature.setAttr(CONCURRENT_ROUTE_KEYS.get(i), routeRelation.network() == null ? null :
routeRelation.network() + "=" + coalesce(routeRelation.ref(), ""));
}
if (brunnel) { if (brunnel) {
feature.setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord())); feature.setAttr(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord()));
} }
@@ -265,48 +262,44 @@ public class TransportationName implements
if (limitMerge) { if (limitMerge) {
feature feature
.setAttr(LINK_TEMP_KEY, isLink ? 1 : 0) .setAttr(LINK_TEMP_KEY, isLink ? 1 : 0)
.setAttr(RELATION_ID_TEMP_KEY, relation == null ? null : relation.id); .setAttr(RELATION_ID_TEMP_KEY, relation == null ? null : relation.id());
} }
if (isFootwayOrSteps(highway)) { if (isFootwayOrSteps(highway)) {
feature feature
.setAttrWithMinzoom(Fields.LAYER, nullIf(element.layer(), 0), 12) .setAttrWithMinzoom(Fields.LAYER, nullIfLong(element.layer(), 0), 12)
.setAttrWithMinzoom(Fields.LEVEL, Parse.parseLongOrNull(element.source().getTag("level")), 12) .setAttrWithMinzoom(Fields.LEVEL, Parse.parseLongOrNull(element.source().getTag("level")), 12)
.setAttrWithMinzoom(Fields.INDOOR, element.indoor() ? 1 : null, 12); .setAttrWithMinzoom(Fields.INDOOR, element.indoor() ? 1 : null, 12);
} }
} }
private RouteRelation getRouteRelation(Tables.OsmHighwayLinestring element, @Override
List<OsmReader.RelationMember<RouteRelation>> relations, String ref) { public void process(Tables.OsmAerialwayLinestring element, FeatureCollector features) {
RouteRelation relation = relations.stream() if (!nullOrEmpty(element.name())) {
.map(OsmReader.RelationMember::relation) features.line(LAYER_NAME)
.min(RELATION_ORDERING) .setBufferPixels(BUFFER_SIZE)
.orElse(null); .setBufferPixelOverrides(MIN_LENGTH)
if (relation == null && ref != null) { .putAttrs(LanguageUtils.getNamesWithoutTranslations(element.source().tags()))
// GB doesn't use regular relations like everywhere else, so if we are .setAttr(Fields.CLASS, "aerialway")
// in GB then use a naming convention instead. .setAttr(Fields.SUBCLASS, element.aerialway())
Matcher refMatcher = GREAT_BRITAIN_REF_NETWORK_PATTERN.matcher(ref); .setMinPixelSize(0)
if (refMatcher.find()) { .setSortKey(element.zOrder())
if (greatBritain == null) { .setMinZoom(12);
if (!loggedNoGb.get() && loggedNoGb.compareAndSet(false, true)) { }
LOGGER.warn("No GB polygon for inferring route network types"); }
}
} else { @Override
try { public void process(Tables.OsmShipwayLinestring element, FeatureCollector features) {
Geometry wayGeometry = element.source().worldGeometry(); if (!nullOrEmpty(element.name())) {
if (greatBritain.intersects(wayGeometry)) { features.line(LAYER_NAME)
RouteNetwork networkType = .setBufferPixels(BUFFER_SIZE)
"motorway".equals(element.highway()) ? RouteNetwork.GB_MOTORWAY : RouteNetwork.GB_TRUNK; .setBufferPixelOverrides(MIN_LENGTH)
relation = new RouteRelation(refMatcher.group(), networkType, 0); .putAttrs(LanguageUtils.getNamesWithoutTranslations(element.source().tags()))
} .setAttr(Fields.CLASS, element.shipway())
} catch (GeometryException e) { .setMinPixelSize(0)
e.log(stats, "omt_transportation_name_gb_test", .setSortKey(element.zOrder())
"Unable to test highway against GB route network: " + element.source().id()); .setMinZoom(12);
}
}
}
} }
return relation;
} }
@Override @Override
@@ -341,35 +334,38 @@ public class TransportationName implements
name instanceof String str ? str.length() * 6 : Double.MAX_VALUE; name instanceof String str ? str.length() * 6 : Double.MAX_VALUE;
} }
private enum RouteNetwork { private enum HighwayClass {
MOTORWAY("motorway", 6),
TRUNK("trunk", 5),
PRIMARY("primary", 4),
SECONDARY("secondary", 3),
TERTIARY("tertiary", 2),
UNCLASSIFIED("unclassified", 1),
UNKNOWN("", 0);
US_INTERSTATE("us-interstate"), private static final Map<String, HighwayClass> indexByString = new HashMap<>();
US_HIGHWAY("us-highway"), private static final Map<Byte, HighwayClass> indexByByte = new HashMap<>();
US_STATE("us-state"), final byte value;
CA_TRANSCANADA("ca-transcanada"), final String highwayValue;
GB_MOTORWAY("gb-motorway"),
GB_TRUNK("gb-trunk");
final String name; HighwayClass(String highwayValue, int id) {
this.highwayValue = highwayValue;
RouteNetwork(String name) { this.value = (byte) id;
this.name = name;
} }
}
/** Information extracted from route relations to use when processing ways in that relation. */ static {
private static record RouteRelation( Arrays.stream(values()).forEach(cls -> {
String ref, indexByString.put(cls.highwayValue, cls);
RouteNetwork network, indexByByte.put(cls.value, cls);
@Override long id });
) implements OsmRelationInfo { }
@Override static HighwayClass from(String highway) {
public long estimateMemoryUsageBytes() { return indexByString.getOrDefault(highway, UNKNOWN);
return CLASS_HEADER_BYTES + }
POINTER_BYTES + estimateSize(ref) +
POINTER_BYTES + // network static HighwayClass from(byte value) {
MemoryEstimator.estimateSizeLong(id); return indexByByte.getOrDefault(value, UNKNOWN);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -103,13 +103,15 @@ public class Water implements
@Override @Override
public void process(Tables.OsmWaterPolygon element, FeatureCollector features) { public void process(Tables.OsmWaterPolygon element, FeatureCollector features) {
if (!"bay".equals(element.natural())) { if (!"bay".equals(element.natural())) {
String clazz = "riverbank".equals(element.waterway()) ? FieldValues.CLASS_RIVER :
classMapping.getOrElse(element.source(), FieldValues.CLASS_LAKE);
features.polygon(LAYER_NAME) features.polygon(LAYER_NAME)
.setBufferPixels(BUFFER_SIZE) .setBufferPixels(BUFFER_SIZE)
.setMinPixelSizeBelowZoom(11, 2) .setMinPixelSizeBelowZoom(11, 2)
.setMinZoom(6) .setMinZoom(6)
.setAttr(Fields.INTERMITTENT, element.isIntermittent() ? 1 : 0) .setAttr(Fields.INTERMITTENT, element.isIntermittent() ? 1 : 0)
.setAttrWithMinzoom(Fields.BRUNNEL, Utils.brunnel(element.isBridge(), element.isTunnel()), 12) .setAttrWithMinzoom(Fields.BRUNNEL, Utils.brunnel(element.isBridge(), element.isTunnel()), 12)
.setAttr(Fields.CLASS, classMapping.getOrElse(element.source(), FieldValues.CLASS_RIVER)); .setAttr(Fields.CLASS, clazz);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License
@@ -37,6 +37,9 @@ package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty; import static com.onthegomap.planetiler.basemap.util.Utils.nullIfEmpty;
import com.carrotsearch.hppc.LongObjectHashMap;
import com.google.common.util.concurrent.AtomicDouble;
import com.graphhopper.coll.GHLongObjectHashMap;
import com.onthegomap.planetiler.FeatureCollector; import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.FeatureMerge; import com.onthegomap.planetiler.FeatureMerge;
import com.onthegomap.planetiler.VectorTile; import com.onthegomap.planetiler.VectorTile;
@@ -46,7 +49,11 @@ import com.onthegomap.planetiler.basemap.generated.Tables;
import com.onthegomap.planetiler.basemap.util.LanguageUtils; import com.onthegomap.planetiler.basemap.util.LanguageUtils;
import com.onthegomap.planetiler.basemap.util.Utils; import com.onthegomap.planetiler.basemap.util.Utils;
import com.onthegomap.planetiler.config.PlanetilerConfig; import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.reader.SourceFeature; import com.onthegomap.planetiler.reader.SourceFeature;
import com.onthegomap.planetiler.reader.osm.OsmElement;
import com.onthegomap.planetiler.reader.osm.OsmReader;
import com.onthegomap.planetiler.reader.osm.OsmRelationInfo;
import com.onthegomap.planetiler.stats.Stats; import com.onthegomap.planetiler.stats.Stats;
import com.onthegomap.planetiler.util.Translations; import com.onthegomap.planetiler.util.Translations;
import com.onthegomap.planetiler.util.ZoomFunction; import com.onthegomap.planetiler.util.ZoomFunction;
@@ -63,7 +70,9 @@ public class Waterway implements
OpenMapTilesSchema.Waterway, OpenMapTilesSchema.Waterway,
Tables.OsmWaterwayLinestring.Handler, Tables.OsmWaterwayLinestring.Handler,
BasemapProfile.FeaturePostProcessor, BasemapProfile.FeaturePostProcessor,
BasemapProfile.NaturalEarthProcessor { BasemapProfile.NaturalEarthProcessor,
BasemapProfile.OsmRelationPreprocessor,
BasemapProfile.OsmAllProcessor {
/* /*
* Uses Natural Earth at lower zoom-levels and OpenStreetMap at higher zoom levels. * Uses Natural Earth at lower zoom-levels and OpenStreetMap at higher zoom levels.
@@ -76,14 +85,6 @@ public class Waterway implements
* short segment of it goes through this tile. * short segment of it goes through this tile.
*/ */
private final Translations translations;
private final PlanetilerConfig config;
public Waterway(Translations translations, PlanetilerConfig config, Stats stats) {
this.config = config;
this.translations = translations;
}
private static final Map<String, Integer> CLASS_MINZOOM = Map.of( private static final Map<String, Integer> CLASS_MINZOOM = Map.of(
"river", 12, "river", 12,
"canal", 12, "canal", 12,
@@ -92,12 +93,29 @@ public class Waterway implements
"drain", 13, "drain", 13,
"ditch", 13 "ditch", 13
); );
private static final String TEMP_REL_ID_ADDR = "_relid";
private final Translations translations;
private final PlanetilerConfig config;
private final Stats stats;
private final LongObjectHashMap<AtomicDouble> riverRelationLengths = new GHLongObjectHashMap<>();
public Waterway(Translations translations, PlanetilerConfig config, Stats stats) {
this.config = config;
this.translations = translations;
this.stats = stats;
}
private static final ZoomFunction.MeterToPixelThresholds MIN_PIXEL_LENGTHS = ZoomFunction.meterThresholds() private static final ZoomFunction.MeterToPixelThresholds MIN_PIXEL_LENGTHS = ZoomFunction.meterThresholds()
.put(6, 500_000)
.put(7, 400_000)
.put(8, 300_000)
.put(9, 8_000) .put(9, 8_000)
.put(10, 4_000) .put(10, 4_000)
.put(11, 1_000); .put(11, 1_000);
// zoom-level 3-5 come from natural earth
@Override @Override
public void processNaturalEarth(String table, SourceFeature feature, FeatureCollector features) { public void processNaturalEarth(String table, SourceFeature feature, FeatureCollector features) {
if (feature.hasTag("featurecla", "River")) { if (feature.hasTag("featurecla", "River")) {
@@ -105,7 +123,6 @@ public class Waterway implements
ZoomRange zoom = switch (table) { ZoomRange zoom = switch (table) {
case "ne_110m_rivers_lake_centerlines" -> new ZoomRange(3, 3); case "ne_110m_rivers_lake_centerlines" -> new ZoomRange(3, 3);
case "ne_50m_rivers_lake_centerlines" -> new ZoomRange(4, 5); case "ne_50m_rivers_lake_centerlines" -> new ZoomRange(4, 5);
case "ne_10m_rivers_lake_centerlines" -> new ZoomRange(6, 8);
default -> null; default -> null;
}; };
if (zoom != null) { if (zoom != null) {
@@ -117,6 +134,52 @@ public class Waterway implements
} }
} }
// zoom-level 6-8 come from OSM river relations
private record WaterwayRelation(
long id,
Map<String, Object> names
) implements OsmRelationInfo {}
@Override
public List<OsmRelationInfo> preprocessOsmRelation(OsmElement.Relation relation) {
if (relation.hasTag("waterway", "river") && !Utils.nullOrEmpty(relation.getString("name"))) {
riverRelationLengths.put(relation.id(), new AtomicDouble());
return List.of(new WaterwayRelation(relation.id(), LanguageUtils.getNames(relation.tags(), translations)));
}
return null;
}
@Override
public void processAllOsm(SourceFeature feature, FeatureCollector features) {
List<OsmReader.RelationMember<WaterwayRelation>> waterways = feature.relationInfo(WaterwayRelation.class);
if (waterways != null && !waterways.isEmpty() && feature.canBeLine()) {
for (var waterway : waterways) {
String role = waterway.role();
if (Utils.nullOrEmpty(role) || "main_stream".equals(role)) {
long relId = waterway.relation().id();
try {
AtomicDouble counter = riverRelationLengths.get(relId);
if (counter != null) {
counter.addAndGet(feature.length());
}
} catch (GeometryException e) {
e.log(stats, "waterway_decode", "Unable to get waterway length for " + feature.id());
}
features.line(LAYER_NAME)
.setAttr(TEMP_REL_ID_ADDR, relId)
.setBufferPixels(BUFFER_SIZE)
.setAttr(Fields.CLASS, FieldValues.CLASS_RIVER)
.putAttrs(waterway.relation().names())
.setZoomRange(6, 8)
.setMinPixelSize(0);
}
}
}
}
// zoom-level 9+ come from OSM river ways
@Override @Override
public void process(Tables.OsmWaterwayLinestring element, FeatureCollector features) { public void process(Tables.OsmWaterwayLinestring element, FeatureCollector features) {
String waterway = element.waterway(); String waterway = element.waterway();
@@ -137,7 +200,22 @@ public class Waterway implements
@Override @Override
public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) { public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) {
if (zoom >= 9 && zoom <= 11) { if (zoom >= 6 && zoom <= 8) {
// remove ways for river relations if relation is not long enough
double minSizeAtZoom = MIN_PIXEL_LENGTHS.apply(zoom).doubleValue() / Math.pow(2, zoom) / 256d;
for (int i = 0; i < items.size(); i++) {
Object relIdObj = items.get(i).attrs().remove(TEMP_REL_ID_ADDR);
if (relIdObj instanceof Long relId && riverRelationLengths.get(relId).get() < minSizeAtZoom) {
items.set(i, null);
}
}
return FeatureMerge.mergeLineStrings(
items,
config.minFeatureSize(zoom),
config.tolerance(zoom),
BUFFER_SIZE
);
} else if (zoom >= 9 && zoom <= 11) {
return FeatureMerge.mergeLineStrings( return FeatureMerge.mergeLineStrings(
items, items,
MIN_PIXEL_LENGTHS.apply(zoom).doubleValue(), MIN_PIXEL_LENGTHS.apply(zoom).doubleValue(),

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. Copyright (c) 2021, MapTiler.com & OpenMapTiles contributors.
All rights reserved. All rights reserved.
Code license: BSD 3-Clause License Code license: BSD 3-Clause License

View File

@@ -28,9 +28,14 @@ public class Utils {
return a != null ? a : b != null ? b : c != null ? c : d != null ? d : e != null ? e : f; return a != null ? a : b != null ? b : c != null ? c : d != null ? d : e != null ? e : f;
} }
/** Returns {@code a} or {@code nullValue} if {@code a} is null. */ /** Boxes {@code a} into an {@link Integer}, or {@code null} if {@code a} is {@code nullValue}. */
public static <T> T nullIf(T a, T nullValue) { public static Long nullIfLong(long a, long nullValue) {
return nullValue.equals(a) ? null : a; return a == nullValue ? null : a;
}
/** Boxes {@code a} into a {@link Long}, or {@code null} if {@code a} is {@code nullValue}. */
public static Integer nullIfInt(int a, int nullValue) {
return a == nullValue ? null : a;
} }
/** Returns {@code a}, or null if {@code a} is "". */ /** Returns {@code a}, or null if {@code a} is "". */

View File

@@ -211,7 +211,8 @@ public class GenerateTest {
List.of(), List.of(),
null, null,
null, null,
props props,
List.of()
)); ));
assertEquals(or( assertEquals(or(
and( and(

View File

@@ -211,4 +211,15 @@ public abstract class AbstractLayerTest {
profile.postProcessLayerFeatures(layer, zoom, 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

@@ -13,7 +13,7 @@ public class AerodromeLabelTest extends AbstractLayerTest {
} }
@Test @Test
public void testHappyPathPoint() { public void testIntlWithIata() {
assertFeatures(14, List.of(Map.of( assertFeatures(14, List.of(Map.of(
"class", "international", "class", "international",
"ele", 100, "ele", 100,
@@ -23,7 +23,7 @@ public class AerodromeLabelTest extends AbstractLayerTest {
"_layer", "aerodrome_label", "_layer", "aerodrome_label",
"_type", "point", "_type", "point",
"_minzoom", 10, "_minzoom", 8,
"_maxzoom", 14, "_maxzoom", 14,
"_buffer", 64d "_buffer", 64d
)), process(pointFeature(Map.of( )), process(pointFeature(Map.of(
@@ -41,7 +41,8 @@ public class AerodromeLabelTest extends AbstractLayerTest {
public void testInternational() { public void testInternational() {
assertFeatures(14, List.of(Map.of( assertFeatures(14, List.of(Map.of(
"class", "international", "class", "international",
"_layer", "aerodrome_label" "_layer", "aerodrome_label",
"_minzoom", 10 // no IATA
)), process(pointFeature(Map.of( )), process(pointFeature(Map.of(
"aeroway", "aerodrome", "aeroway", "aerodrome",
"aerodrome_type", "international" "aerodrome_type", "international"
@@ -52,7 +53,8 @@ public class AerodromeLabelTest extends AbstractLayerTest {
public void testPublic() { public void testPublic() {
assertFeatures(14, List.of(Map.of( assertFeatures(14, List.of(Map.of(
"class", "public", "class", "public",
"_layer", "aerodrome_label" "_layer", "aerodrome_label",
"_minzoom", 10
)), process(pointFeature(Map.of( )), process(pointFeature(Map.of(
"aeroway", "aerodrome", "aeroway", "aerodrome",
"aerodrome_type", "public airport" "aerodrome_type", "public airport"
@@ -70,7 +72,8 @@ public class AerodromeLabelTest extends AbstractLayerTest {
public void testMilitary() { public void testMilitary() {
assertFeatures(14, List.of(Map.of( assertFeatures(14, List.of(Map.of(
"class", "military", "class", "military",
"_layer", "aerodrome_label" "_layer", "aerodrome_label",
"_minzoom", 10
)), process(pointFeature(Map.of( )), process(pointFeature(Map.of(
"aeroway", "aerodrome", "aeroway", "aerodrome",
"aerodrome_type", "military airport" "aerodrome_type", "military airport"
@@ -88,7 +91,8 @@ public class AerodromeLabelTest extends AbstractLayerTest {
public void testPrivate() { public void testPrivate() {
assertFeatures(14, List.of(Map.of( assertFeatures(14, List.of(Map.of(
"class", "private", "class", "private",
"_layer", "aerodrome_label" "_layer", "aerodrome_label",
"_minzoom", 10
)), process(pointFeature(Map.of( )), process(pointFeature(Map.of(
"aeroway", "aerodrome", "aeroway", "aerodrome",
"aerodrome_type", "private" "aerodrome_type", "private"
@@ -106,7 +110,8 @@ public class AerodromeLabelTest extends AbstractLayerTest {
public void testOther() { public void testOther() {
assertFeatures(14, List.of(Map.of( assertFeatures(14, List.of(Map.of(
"class", "other", "class", "other",
"_layer", "aerodrome_label" "_layer", "aerodrome_label",
"_minzoom", 10
)), process(pointFeature(Map.of( )), process(pointFeature(Map.of(
"aeroway", "aerodrome" "aeroway", "aerodrome"
)))); ))));

View File

@@ -144,11 +144,30 @@ public class BoundaryTest extends AbstractLayerTest {
"ne_10m_admin_1_states_provinces_lines", "ne_10m_admin_1_states_provinces_lines",
0 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
),
NATURAL_EARTH_SOURCE,
"ne_10m_admin_1_states_provinces_lines",
0
)));
assertFeatures(0, List.of(), process(SimpleFeature.create( assertFeatures(0, List.of(), process(SimpleFeature.create(
newLineString(0, 0, 1, 1), newLineString(0, 0, 1, 1),
Map.of( Map.of(
"min_zoom", 7.1d "min_zoom", 7.9d
), ),
NATURAL_EARTH_SOURCE, NATURAL_EARTH_SOURCE,
"ne_10m_admin_1_states_provinces_lines", "ne_10m_admin_1_states_provinces_lines",

View File

@@ -41,6 +41,14 @@ public class BuildingTest extends AbstractLayerTest {
)))); ))));
} }
@Test
public void testIgnoreUndergroundBuilding() {
assertFeatures(14, List.of(), process(polygonFeature(Map.of(
"building", "yes",
"location", "underground"
))));
}
@Test @Test
public void testAirportBuildings() { public void testAirportBuildings() {
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(

View File

@@ -130,6 +130,9 @@ public class LandcoverTest extends AbstractLayerTest {
)), process(polygonFeature(Map.of( )), process(polygonFeature(Map.of(
"natural", "dune" "natural", "dune"
)))); ))));
assertFeatures(10, List.of(), process(polygonFeature(Map.of(
"landuse", "park"
))));
} }
@Test @Test
@@ -137,6 +140,7 @@ public class LandcoverTest extends AbstractLayerTest {
Map<String, Object> map = Map.of("subclass", "wood"); Map<String, Object> map = Map.of("subclass", "wood");
assertMerges(List.of(map, map, map, map, map, map), List.of( 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", 48, "subclass", "wood")),
feature(rectangle(10, 20), Map.of("_numpoints", 49, "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", 50, "subclass", "wood")),
@@ -144,19 +148,23 @@ public class LandcoverTest extends AbstractLayerTest {
feature(rectangle(12, 18), Map.of("_numpoints", 300, "subclass", "wood")), feature(rectangle(12, 18), Map.of("_numpoints", 300, "subclass", "wood")),
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood")) feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood"))
), 14); ), 14);
assertMerges(List.of(map, map, map, map), List.of( 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", 48, "subclass", "wood")),
feature(rectangle(10, 20), Map.of("_numpoints", 49, "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", 50, "subclass", "wood")),
feature(rectangle(12, 18), Map.of("_numpoints", 299, "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", 300, "subclass", "wood")),
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood")) feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood"))
), 13); ), 13);
assertMerges(List.of(map, map, map), List.of( 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", 48, "subclass", "wood")),
feature(rectangle(10, 20), Map.of("_numpoints", 49, "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", 50, "subclass", "wood")),
feature(rectangle(12, 18), Map.of("_numpoints", 299, "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", 300, "subclass", "wood")),
feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood")) feature(rectangle(12, 18), Map.of("_numpoints", 301, "subclass", "wood"))
), 9); ), 9);

View File

@@ -58,6 +58,18 @@ public class LanduseTest extends AbstractLayerTest {
)))); ))));
} }
@Test
public void testGraveYardBecomesCemetery() {
assertFeatures(14, List.of(
Map.of("_layer", "poi"),
Map.of(
"_layer", "landuse",
"class", "cemetery"
)), process(polygonFeature(Map.of(
"amenity", "grave_yard"
))));
}
@Test @Test
public void testOsmLanduseLowerZoom() { public void testOsmLanduseLowerZoom() {
assertFeatures(6, List.of(Map.of( assertFeatures(6, List.of(Map.of(

View File

@@ -1,11 +1,15 @@
package com.onthegomap.planetiler.basemap.layers; package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.TestUtils.newPoint; 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 org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.onthegomap.planetiler.VectorTile; import com.onthegomap.planetiler.VectorTile;
import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.reader.SimpleFeature;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -31,6 +35,7 @@ public class MountainPeakTest extends AbstractLayerTest {
"class", "peak", "class", "peak",
"ele", 100, "ele", 100,
"ele_ft", 328, "ele_ft", 328,
"customary_ft", "<null>",
"_layer", "mountain_peak", "_layer", "mountain_peak",
"_type", "point", "_type", "point",
@@ -70,6 +75,17 @@ public class MountainPeakTest extends AbstractLayerTest {
)))); ))));
} }
@Test
public void testSaddle() {
assertFeatures(14, List.of(Map.of(
"class", "saddle"
)), process(pointFeature(Map.of(
"natural", "saddle",
"ele", "100"
))));
}
@Test @Test
public void testNoElevation() { public void testNoElevation() {
assertFeatures(14, List.of(), process(pointFeature(Map.of( assertFeatures(14, List.of(), process(pointFeature(Map.of(
@@ -86,7 +102,7 @@ public class MountainPeakTest extends AbstractLayerTest {
} }
@Test @Test
public void testIgnoreLines() { public void testIgnorePeakLines() {
assertFeatures(14, List.of(), process(lineFeature(Map.of( assertFeatures(14, List.of(), process(lineFeature(Map.of(
"natural", "peak", "natural", "peak",
"name", "name", "name", "name",
@@ -94,6 +110,68 @@ public class MountainPeakTest extends AbstractLayerTest {
)))); ))));
} }
@Test
public 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
public void testCustomaryFt() {
process(SimpleFeature.create(
rectangle(0, 0.1),
Map.of("iso_a2", "US"),
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"
)),
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"
)),
OSM_SOURCE,
null,
0
)));
}
private int getSortKey(Map<String, Object> tags) { private int getSortKey(Map<String, Object> tags) {
return process(pointFeature(Map.of( return process(pointFeature(Map.of(
"natural", "peak", "natural", "peak",

View File

@@ -13,9 +13,9 @@ public class ParkTest extends AbstractLayerTest {
"_layer", "park", "_layer", "park",
"_type", "polygon", "_type", "polygon",
"class", "national_park", "class", "national_park",
"name", "<null>", "name", "Grand Canyon National Park",
"_minpixelsize", 2d, "_minpixelsize", 2d,
"_minzoom", 6, "_minzoom", 4,
"_maxzoom", 14 "_maxzoom", 14
), Map.of( ), Map.of(
"_layer", "park", "_layer", "park",
@@ -24,8 +24,8 @@ public class ParkTest extends AbstractLayerTest {
"name", "Grand Canyon National Park", "name", "Grand Canyon National Park",
"name_int", "Grand Canyon National Park", "name_int", "Grand Canyon National Park",
"name:latin", "Grand Canyon National Park", "name:latin", "Grand Canyon National Park",
"name:es", "es name", // "name:es", "es name", // don't include all translations
"_minzoom", 6, "_minzoom", 5,
"_maxzoom", 14 "_maxzoom", 14
)), process(polygonFeature(Map.of( )), process(polygonFeature(Map.of(
"boundary", "national_park", "boundary", "national_park",
@@ -52,9 +52,9 @@ public class ParkTest extends AbstractLayerTest {
"_layer", "park", "_layer", "park",
"_type", "polygon", "_type", "polygon",
"class", "protected_area", "class", "protected_area",
"name", "<null>", "name", "Small park",
"_minpixelsize", 2d, "_minpixelsize", 2d,
"_minzoom", 6, "_minzoom", 4,
"_maxzoom", 14 "_maxzoom", 14
), Map.of( ), Map.of(
"_layer", "park", "_layer", "park",
@@ -75,7 +75,7 @@ public class ParkTest extends AbstractLayerTest {
), Map.of( ), Map.of(
"_layer", "park", "_layer", "park",
"_type", "point", "_type", "point",
"_minzoom", 6, "_minzoom", 5,
"_maxzoom", 14 "_maxzoom", 14
)), process(polygonFeatureWithArea(1, Map.of( )), process(polygonFeatureWithArea(1, Map.of(
"boundary", "protected_area", "boundary", "protected_area",

View File

@@ -131,8 +131,8 @@ public class PlaceTest extends AbstractLayerTest {
rectangle(0.4, 0.6), rectangle(0.4, 0.6),
Map.of( Map.of(
"name", "Massachusetts - not important", "name", "Massachusetts - not important",
"scalerank", 4, "scalerank", 8,
"labelrank", 4, "labelrank", 8,
"datarank", 1 "datarank", 1
), ),
NATURAL_EARTH_SOURCE, NATURAL_EARTH_SOURCE,
@@ -194,6 +194,44 @@ public class PlaceTest extends AbstractLayerTest {
))); )));
} }
@Test
public 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
),
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"
),
OSM_SOURCE,
null,
0
)));
}
@Test @Test
public void testIslandPoint() { public void testIslandPoint() {
assertFeatures(0, List.of(Map.of( assertFeatures(0, List.of(Map.of(

View File

@@ -181,4 +181,30 @@ public class PoiTest extends AbstractLayerTest {
) )
))); )));
} }
@Test
public 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
public 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"
))));
}
} }

View File

@@ -1,14 +1,20 @@
package com.onthegomap.planetiler.basemap.layers; package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.TestUtils.newLineString; 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.TestUtils.rectangle;
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE; 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.OSM_SOURCE;
import com.onthegomap.planetiler.FeatureCollector; import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.basemap.BasemapProfile;
import com.onthegomap.planetiler.config.Arguments;
import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.reader.SimpleFeature; import com.onthegomap.planetiler.reader.SimpleFeature;
import com.onthegomap.planetiler.reader.SourceFeature;
import com.onthegomap.planetiler.reader.osm.OsmElement; import com.onthegomap.planetiler.reader.osm.OsmElement;
import com.onthegomap.planetiler.stats.Stats;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -33,12 +39,12 @@ public class TransportationTest extends AbstractLayerTest {
"_type", "line", "_type", "line",
"class", "path", "class", "path",
"subclass", "footway", "subclass", "footway",
"oneway", 0, "oneway", "<null>",
"name", "<null>", "name", "<null>",
"layer", "<null>",
"_buffer", 4d, "_buffer", 4d,
"_minpixelsize", 0d, "_minpixelsize", 0d,
"_minzoom", 13, "_minzoom", 13
"_maxzoom", 14
), Map.of( ), Map.of(
"_layer", "transportation_name", "_layer", "transportation_name",
"_type", "line", "_type", "line",
@@ -54,9 +60,10 @@ public class TransportationTest extends AbstractLayerTest {
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(
"_layer", "transportation", "_layer", "transportation",
"surface", "paved", "surface", "paved",
"oneway", 0, "oneway", "<null>",
"layer", "<null>",
"level", 0L, "level", 0L,
"ramp", 0, "ramp", "<null>",
"bicycle", "dismount", "bicycle", "dismount",
"foot", "designated" "foot", "designated"
), Map.of( ), Map.of(
@@ -70,20 +77,154 @@ public class TransportationTest extends AbstractLayerTest {
)), result); )), result);
} }
@Test
public void testImportantPath() {
var rel = new OsmElement.Relation(1);
rel.setTag("colour", "white");
rel.setTag("name", "Appalachian Trail - 11 MA");
rel.setTag("network", "nwn");
rel.setTag("osmc", "symbol white::white_stripe");
rel.setTag("ref", "AT");
rel.setTag("route", "hiking");
rel.setTag("short_name", "AT 11 MA");
rel.setTag("symbol", "white-paint blazes");
rel.setTag("type", "route");
rel.setTag("wikidata", "Q620648");
rel.setTag("wikipedia", "en:Appalachian Trail");
FeatureCollector features = process(lineFeatureWithRelation(
profile.preprocessOsmRelation(rel),
Map.of(
"bicycle", "no",
"highway", "path",
"horse", "no",
"name", "Appalachian Trail",
"ref", "AT",
"surface", "ground"
)));
assertFeatures(12, List.of(Map.of(
"_layer", "transportation",
"_type", "line",
"class", "path",
"subclass", "path",
"oneway", "<null>",
"name", "<null>",
"layer", "<null>",
"_buffer", 4d,
"_minpixelsize", 0d,
"_minzoom", 12
), Map.of(
"_layer", "transportation_name",
"_type", "line",
"class", "path",
"subclass", "path",
"name", "Appalachian Trail",
"name_int", "Appalachian Trail",
"name:latin", "Appalachian Trail",
"_minpixelsize", 0d,
"_minzoom", 12
)), features);
}
@Test @Test
public void testUnnamedPath() { public void testUnnamedPath() {
assertFeatures(13, List.of(Map.of( assertFeatures(14, List.of(Map.of(
"_layer", "transportation", "_layer", "transportation",
"class", "path", "class", "path",
"subclass", "path", "subclass", "path",
"surface", "unpaved", "surface", "unpaved",
"oneway", 0 "oneway", "<null>",
"_minzoom", 14
)), process(lineFeature(Map.of( )), process(lineFeature(Map.of(
"surface", "dirt", "surface", "dirt",
"highway", "path" "highway", "path"
)))); ))));
} }
@Test
public void testPrivatePath() {
assertFeatures(9, List.of(Map.of(
"_layer", "transportation",
"class", "path",
"access", "no"
)), process(lineFeature(Map.of(
"access", "private",
"highway", "path"
))));
assertFeatures(9, List.of(Map.of(
"_layer", "transportation",
"class", "path",
"access", "no"
)), process(lineFeature(Map.of(
"access", "no",
"highway", "path"
))));
assertFeatures(8, List.of(Map.of(
"_layer", "transportation",
"class", "path",
"access", "<null>"
)), process(lineFeature(Map.of(
"access", "no",
"highway", "path"
))));
}
@Test
public void testExpressway() {
assertFeatures(8, List.of(Map.of(
"_layer", "transportation",
"class", "motorway",
"expressway", "<null>"
)), process(lineFeature(Map.of(
"highway", "motorway",
"expressway", "yes"
))));
assertFeatures(8, List.of(Map.of(
"_layer", "transportation",
"class", "primary",
"expressway", 1
)), process(lineFeature(Map.of(
"highway", "primary",
"expressway", "yes"
))));
assertFeatures(7, List.of(Map.of(
"_layer", "transportation",
"class", "primary",
"expressway", "<null>"
)), process(lineFeature(Map.of(
"highway", "primary",
"expressway", "yes"
))));
}
@Test
public void testToll() {
assertFeatures(9, List.of(Map.of(
"_layer", "transportation",
"class", "motorway",
"toll", "<null>"
)), process(lineFeature(Map.of(
"highway", "motorway"
))));
assertFeatures(9, List.of(Map.of(
"_layer", "transportation",
"class", "motorway",
"toll", 1
)), process(lineFeature(Map.of(
"highway", "motorway",
"toll", "yes"
))));
assertFeatures(8, List.of(Map.of(
"_layer", "transportation",
"class", "motorway",
"toll", "<null>"
)), process(lineFeature(Map.of(
"highway", "motorway",
"toll", "yes"
))));
}
@Test @Test
public void testIndoorTunnelSteps() { public void testIndoorTunnelSteps() {
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(
@@ -93,7 +234,7 @@ public class TransportationTest extends AbstractLayerTest {
"brunnel", "tunnel", "brunnel", "tunnel",
"indoor", 1, "indoor", 1,
"oneway", 1, "oneway", 1,
"ramp", 1 "ramp", "<null>"
)), process(lineFeature(Map.of( )), process(lineFeature(Map.of(
"highway", "steps", "highway", "steps",
"tunnel", "building_passage", "tunnel", "building_passage",
@@ -124,12 +265,37 @@ public class TransportationTest extends AbstractLayerTest {
"bridge", "yes" "bridge", "yes"
))); )));
assertFeatures(13, List.of(mapOf(
"_layer", "transportation",
"class", "motorway",
"surface", "paved",
"oneway", 1,
"ramp", "<null>",
"bicycle", "no",
"foot", "no",
"horse", "no",
"brunnel", "bridge",
"network", "us-interstate",
"_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>",
"route_1", "US:I=90",
"_minzoom", 6
)), features);
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(
"_layer", "transportation", "_layer", "transportation",
"class", "motorway", "class", "motorway",
"surface", "paved", "surface", "paved",
"oneway", 1, "oneway", 1,
"ramp", 0, "ramp", "<null>",
"bicycle", "no", "bicycle", "no",
"foot", "no", "foot", "no",
"horse", "no", "horse", "no",
@@ -143,6 +309,7 @@ public class TransportationTest extends AbstractLayerTest {
"ref", "90", "ref", "90",
"ref_length", 2, "ref_length", 2,
"network", "us-interstate", "network", "us-interstate",
"route_1", "US:I=90",
"brunnel", "<null>", "brunnel", "<null>",
"_minzoom", 6 "_minzoom", 6
)), features); )), features);
@@ -166,11 +333,92 @@ public class TransportationTest extends AbstractLayerTest {
"ref", "90", "ref", "90",
"ref_length", 2, "ref_length", 2,
"network", "us-interstate", "network", "us-interstate",
"route_1", "US:I=90",
"brunnel", "<null>", "brunnel", "<null>",
"_minzoom", 6 "_minzoom", 6
)), features); )), features);
} }
@Test
public void testMotorwayJunction() {
var otherNode1 = new OsmElement.Node(1, 1, 1);
var junctionNode = new OsmElement.Node(2, 1, 2);
var otherNode2 = new OsmElement.Node(3, 1, 3);
var otherNode3 = new OsmElement.Node(4, 2, 3);
junctionNode.setTag("highway", "motorway_junction");
junctionNode.setTag("name", "exit 1");
junctionNode.setTag("layer", "1");
junctionNode.setTag("ref", "12");
// 2 ways meet at junctionNode (id=2) - use most important class of a highway intersecting it (motorway)
var way1 = new OsmElement.Way(5);
way1.setTag("highway", "motorway");
way1.nodes().add(otherNode1.id(), junctionNode.id(), otherNode2.id());
var way2 = new OsmElement.Way(6);
way2.setTag("highway", "primary");
way2.nodes().add(junctionNode.id(), otherNode3.id());
profile.preprocessOsmNode(otherNode1);
profile.preprocessOsmNode(junctionNode);
profile.preprocessOsmNode(otherNode2);
profile.preprocessOsmNode(otherNode3);
profile.preprocessOsmWay(way1);
profile.preprocessOsmWay(way2);
FeatureCollector features = process(SimpleFeature.create(
newPoint(1, 2),
junctionNode.tags(),
OSM_SOURCE,
null,
junctionNode.id()
));
assertFeatures(13, List.of(mapOf(
"_layer", "transportation_name",
"class", "motorway",
"subclass", "junction",
"name", "exit 1",
"ref", "12",
"ref_length", 2,
"layer", 1L,
"_type", "point",
"_minzoom", 10
)), features);
}
@Test
public void testInterstateMotorwayWithoutWayInfo() {
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"
)));
assertFeatures(13, List.of(mapOf(
"_layer", "transportation",
"class", "motorway",
"network", "us-interstate",
"_minzoom", 4
), Map.of(
"_layer", "transportation_name",
"class", "motorway",
"ref", "90",
"ref_length", 2,
"network", "us-interstate",
"brunnel", "<null>",
"route_1", "US:I=90",
"_minzoom", 6
)), features);
}
@Test @Test
public void testPrimaryRoadConstruction() { public void testPrimaryRoadConstruction() {
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(
@@ -223,7 +471,7 @@ public class TransportationTest extends AbstractLayerTest {
"_layer", "transportation", "_layer", "transportation",
"class", "service", "class", "service",
"service", "driveway", "service", "driveway",
"_minzoom", 12 "_minzoom", 14
)), process(lineFeature(Map.of( )), process(lineFeature(Map.of(
"highway", "service", "highway", "service",
"service", "driveway" "service", "driveway"
@@ -256,7 +504,28 @@ public class TransportationTest extends AbstractLayerTest {
} }
@Test @Test
public void testTrack() { public void testNamedTrack() {
assertFeatures(13, List.of(Map.of(
"_layer", "transportation",
"class", "track",
"surface", "unpaved",
"horse", "yes",
"_minzoom", 13
), Map.of(
"_layer", "transportation_name",
"class", "track",
"name", "name",
"_minzoom", 13
)), process(lineFeature(Map.of(
"highway", "track",
"surface", "dirt",
"horse", "yes",
"name", "name"
))));
}
@Test
public void testUnnamedTrack() {
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(
"_layer", "transportation", "_layer", "transportation",
"class", "track", "class", "track",
@@ -270,6 +539,29 @@ public class TransportationTest extends AbstractLayerTest {
)))); ))));
} }
@Test
public void testBusway() {
assertFeatures(13, List.of(Map.of(
"_layer", "transportation",
"class", "busway",
"brunnel", "tunnel",
"_minzoom", 11
), Map.of(
"_layer", "transportation_name",
"class", "busway",
"name", "Silver Line",
"_minzoom", 12
)), process(lineFeature(Map.of(
"access", "no",
"bus", "yes",
"highway", "busway",
"layer", "-1",
"name", "Silver Line",
"trolley_wire", "yes",
"tunnel", "yes"
))));
}
final OsmElement.Relation relUS = new OsmElement.Relation(1); final OsmElement.Relation relUS = new OsmElement.Relation(1);
{ {
@@ -294,8 +586,9 @@ public class TransportationTest extends AbstractLayerTest {
"_layer", "transportation", "_layer", "transportation",
"class", "primary", "class", "primary",
"surface", "paved", "surface", "paved",
"oneway", 0, "oneway", "<null>",
"ramp", 0, "ramp", "<null>",
"network", "us-highway",
"_minzoom", 7 "_minzoom", 7
), Map.of( ), Map.of(
"_layer", "transportation_name", "_layer", "transportation_name",
@@ -305,6 +598,8 @@ public class TransportationTest extends AbstractLayerTest {
"ref", "3", "ref", "3",
"ref_length", 1, "ref_length", 1,
"network", "us-highway", "network", "us-highway",
"route_1", "US:US=3",
"route_2", "US:MA=2",
"_minzoom", 12 "_minzoom", 12
)), process(lineFeatureWithRelation( )), process(lineFeatureWithRelation(
Stream.concat( Stream.concat(
@@ -325,12 +620,17 @@ public class TransportationTest extends AbstractLayerTest {
), Map.of( ), Map.of(
"_layer", "transportation_name", "_layer", "transportation_name",
"class", "primary", "class", "primary",
"route_1", "US:US=3",
"route_2", "US:MA=2",
"ref", "3", "ref", "3",
"network", "us-highway" "network", "us-highway"
)), process(lineFeatureWithRelation( )), process(lineFeatureWithRelation(
Stream.concat( Stream.concat(
profile.preprocessOsmRelation(relMA).stream(), profile.preprocessOsmRelation(relMA).stream(),
profile.preprocessOsmRelation(relUS).stream() Stream.concat( // ignore duplicates
profile.preprocessOsmRelation(relUS).stream(),
profile.preprocessOsmRelation(relUS).stream()
)
).toList(), ).toList(),
Map.of( Map.of(
"highway", "primary", "highway", "primary",
@@ -368,7 +668,8 @@ public class TransportationTest extends AbstractLayerTest {
public void testCompoundRef() { public void testCompoundRef() {
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(
"_layer", "transportation", "_layer", "transportation",
"class", "primary" "class", "primary",
"network", "<null>"
), Map.of( ), Map.of(
"_layer", "transportation_name", "_layer", "transportation_name",
"class", "primary", "class", "primary",
@@ -409,7 +710,7 @@ public class TransportationTest extends AbstractLayerTest {
"class", "motorway", "class", "motorway",
"surface", "paved", "surface", "paved",
"oneway", 1, "oneway", 1,
"ramp", 0, "ramp", "<null>",
"_minzoom", 4 "_minzoom", 4
), Map.of( ), Map.of(
"_layer", "transportation_name", "_layer", "transportation_name",
@@ -438,7 +739,7 @@ public class TransportationTest extends AbstractLayerTest {
"_layer", "transportation", "_layer", "transportation",
"class", "motorway", "class", "motorway",
"oneway", 1, "oneway", 1,
"ramp", 0, "ramp", "<null>",
"_minzoom", 4 "_minzoom", 4
), Map.of( ), Map.of(
"_layer", "transportation_name", "_layer", "transportation_name",
@@ -464,7 +765,7 @@ public class TransportationTest extends AbstractLayerTest {
"_layer", "transportation", "_layer", "transportation",
"class", "motorway", "class", "motorway",
"oneway", 1, "oneway", 1,
"ramp", 0, "ramp", "<null>",
"_minzoom", 4 "_minzoom", 4
), Map.of( ), Map.of(
"_layer", "transportation_name", "_layer", "transportation_name",
@@ -504,8 +805,8 @@ public class TransportationTest extends AbstractLayerTest {
"subclass", "light_rail", "subclass", "light_rail",
"brunnel", "tunnel", "brunnel", "tunnel",
"layer", -1L, "layer", -1L,
"oneway", 0, "oneway", "<null>",
"ramp", 0, "ramp", "<null>",
"_minzoom", 11, "_minzoom", 11,
"_maxzoom", 14, "_maxzoom", 14,
@@ -526,8 +827,8 @@ public class TransportationTest extends AbstractLayerTest {
"subclass", "subway", "subclass", "subway",
"brunnel", "tunnel", "brunnel", "tunnel",
"layer", -2L, "layer", -2L,
"oneway", 0, "oneway", "<null>",
"ramp", 0, "ramp", "<null>",
"_minzoom", 14, "_minzoom", 14,
"_maxzoom", 14, "_maxzoom", 14,
@@ -561,6 +862,7 @@ public class TransportationTest extends AbstractLayerTest {
"layer", "-2" "layer", "-2"
)))); ))));
assertFeatures(13, List.of(Map.of( assertFeatures(13, List.of(Map.of(
"layer", "<null>",
"_minzoom", 10 "_minzoom", 10
)), process(lineFeature(Map.of( )), process(lineFeature(Map.of(
"railway", "rail", "railway", "rail",
@@ -599,11 +901,20 @@ public class TransportationTest extends AbstractLayerTest {
@Test @Test
public void testAerialway() { public void testAerialway() {
assertFeatures(10, List.of(Map.of( assertFeatures(12, List.of(Map.of(
"_layer", "transportation", "_layer", "transportation",
"class", "aerialway", "class", "aerialway",
"subclass", "gondola", "subclass", "gondola",
"_minzoom", 12,
"_maxzoom", 14,
"_type", "line"
), Map.of(
"_layer", "transportation_name",
"class", "aerialway",
"subclass", "gondola",
"name", "Summit Gondola",
"_minzoom", 12, "_minzoom", 12,
"_maxzoom", 14, "_maxzoom", 14,
"_type", "line" "_type", "line"
@@ -627,6 +938,14 @@ public class TransportationTest extends AbstractLayerTest {
"_minzoom", 11, "_minzoom", 11,
"_maxzoom", 14, "_maxzoom", 14,
"_type", "line" "_type", "line"
), Map.of(
"_layer", "transportation_name",
"class", "ferry",
"name", "Boston - Provincetown Ferry",
"_minzoom", 12,
"_maxzoom", 14,
"_type", "line"
)), process(lineFeature(Map.of( )), process(lineFeature(Map.of(
"route", "ferry", "route", "ferry",
"name", "Boston - Provincetown Ferry", "name", "Boston - Provincetown Ferry",
@@ -718,4 +1037,25 @@ public class TransportationTest extends AbstractLayerTest {
getWaySortKey(Map.of("highway", "motorway", "layer", "-2")) getWaySortKey(Map.of("highway", "motorway", "layer", "-2"))
); );
} }
@Test
public void testTransportationNameLayerRequiresTransportationLayer() {
var profile = new BasemapProfile(translations, PlanetilerConfig.from(Arguments.of(
"only_layers", "transportation_name"
)), Stats.inMemory());
SourceFeature feature = lineFeature(Map.of(
"highway", "path",
"name", "test"
));
var collector = featureCollectorFactory.get(feature);
profile.processFeature(feature, collector);
assertFeatures(14, List.of(Map.of(
"_layer", "transportation_name",
"class", "path",
"name", "test"
), Map.of(
"_layer", "transportation",
"class", "path"
)), collector);
}
} }

View File

@@ -132,7 +132,7 @@ public class WaterTest extends AbstractLayerTest {
"_minzoom", 6, "_minzoom", 6,
"_maxzoom", 14 "_maxzoom", 14
)), process(polygonFeature(Map.of( )), process(polygonFeature(Map.of(
"waterway", "stream", "waterway", "riverbank",
"bridge", "1", "bridge", "1",
"intermittent", "1" "intermittent", "1"
)))); ))));
@@ -152,6 +152,39 @@ public class WaterTest extends AbstractLayerTest {
)))); ))));
} }
@Test
public void testRiverbank() {
assertFeatures(11, List.of(Map.of(
"class", "river",
"_layer", "water",
"_type", "polygon"
)), process(polygonFeature(Map.of(
"waterway", "riverbank"
))));
}
@Test
public void testRiverk() {
assertFeatures(11, List.of(Map.of(
"class", "river",
"_layer", "water",
"_type", "polygon"
)), process(polygonFeature(Map.of(
"water", "river"
))));
}
@Test
public void testSpring() {
assertFeatures(11, List.of(Map.of(
"class", "lake",
"_layer", "water",
"_type", "polygon"
)), process(polygonFeature(Map.of(
"natural", "spring"
))));
}
@Test @Test
public void testOceanZoomLevels() { public void testOceanZoomLevels() {
assertCoversZoomRange(0, 14, "water", assertCoversZoomRange(0, 14, "water",

View File

@@ -2,17 +2,86 @@ package com.onthegomap.planetiler.basemap.layers;
import static com.onthegomap.planetiler.TestUtils.newLineString; import static com.onthegomap.planetiler.TestUtils.newLineString;
import static com.onthegomap.planetiler.basemap.BasemapProfile.NATURAL_EARTH_SOURCE; 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.assertEquals;
import com.onthegomap.planetiler.FeatureCollector;
import com.onthegomap.planetiler.VectorTile; import com.onthegomap.planetiler.VectorTile;
import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.geo.GeometryException;
import com.onthegomap.planetiler.reader.SimpleFeature; 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.List;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class WaterwayTest extends AbstractLayerTest { public class WaterwayTest extends AbstractLayerTest {
@ParameterizedTest
@ValueSource(booleans = {false, true})
public 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(),
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 @Test
public void testWaterwayImportantRiverProcess() { public void testWaterwayImportantRiverProcess() {
var charlesRiver = process(lineFeature(Map.of( var charlesRiver = process(lineFeature(Map.of(
@@ -163,24 +232,5 @@ public class WaterwayTest extends AbstractLayerTest {
"ne_50m_rivers_lake_centerlines", "ne_50m_rivers_lake_centerlines",
0 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
)));
} }
} }