OpenMapTiles 3.15.0 SNAPSHOT (2) (#144)

* version bumped from 3.14.0 to 3.15.0-SNAPSHOT

* regenerate-openmaptiles.sh 07f243c5d9efa558fa539d7a31b2ae50507aaa9d (to match content of OMT PR 1457)

* SQL -> Java re-implementation of OMT PR 1457

* version bumped from 3.14.0 to 3.15.0-SNAPSHOT

* WaterName.areaToMinZoom(): improved handling of rounding and precission + added unit tests

* mvn spotless:apply

* water label min. zoom calculation simplified

* comment adjusted to be hopefully more useful

* mvn spotless:apply

* minzoom for CA_TRANSCANADA and US_INTERSTATE trunk now 4 (to match OMT PR 1440)

* minzoom for some other Canada trunks now 4 (to match OMT PR 1446)

* equals() simplified + clean-up of comments

* regenerate-openmaptiles.sh 5f7b2c11b3224759a21133381ca7d959a1f3cf51 (to match content of OMT PR 1465)

* GB road relations processing adjusted to match OMT PR 1465, e.g. handle also primary and secondary roads

* regenerate-openmaptiles.sh edb42f2db3c2b0ec37045367720eed84d7bbd71f (to match content of OMT PR 1466)

* IE road relations processing adjusted to match OMT PR 1466, e.g. handle IE roates in similar way as GB routes

* fixed handling of networkType for secondary GB routes

* clean-up: case statements simplified

* mvn spotless:apply

* clazz calculation moved up so that minzoom can be set to 3 for only lakes (to match OMT PR 1475)

* unit tests adjusted + extended to cover 'minzoom=3 fore lakes' change

* fixed minor typo from previous PR

* render POIs for large universities at low zoom (to match OMT PR 1479)

* clean-up, to make the diff/PR smaller

* regenerate-openmaptiles.sh 5e9b7c475d53a5bd5ea394da361594d3f4ce2d66 (to match content of OMT PR 1485)

* handle 'grade1' and 'tracktype' as per OMT PR 1485

* added implementation of agg_stop

It is based on OMT PR 1480 (which contains latest the fix) and the rest of older code
(which was not worling properly until the fix).

* clean-up: mvn spotless:apply

* Long ferries (as per OMT PR 1486)

* regenerate-openmaptiles.sh b3d67ed5b327c9059aeea0b3304772c6b4c8c7e9  (to match content of OMT PR 1489)

* Add aboriginal lands (as per OMT PR 1489)

* handle duplicate route relations (to match OMT PR 1501)

* regenerate-openmaptiles.sh master, to match several OMT PRs which adjusted only YML

* URLs in comments adjusted to match OMT PR 1560

* Convert separated addresses to dashed addresses

* add brunnel (and layer) attributes only for certain zoomlevels, depending on feature size (matching OMT PR 1579)

* unit test testInterstateMotorway(): brunnel tag for test line no longer available at Z8

* unit test testInterstateMotorway() clean-up: Z13 was tested twice

* minor clean-up: fixed unit test naming

* partial fix for differences in transportation_name layer

The difference is between OpenMapTiles/master (OMT) and
planetiler-openmaptiles/omt_3_15_0 (PT-OMT) (e.g. development versions).

The point is, that while PT-OMT was using limit of "8km" for Z9-Z11, OMT
is using limit "ST_Length(geometry) > 8000 / POWER(2, zoom_level - 9)
AND zoom_level BETWEEN 9 AND 11".

Some further differences still visible, hence further commits expected.

* further adjustments to better match what is done with ferries in OMT

... (as per OMT PR 1486)

But FERRY_MIN_PIXEL_SIZE is "too much" in the contexct of Planetiler,
since it is applied within tiles, hence causes gaps in lines if a line
"strikes a little" certain tile. Hence we will need to divert a little.

* ferry minLength tweak + clean-up

* mvn spotless:apply

* fixed minor typo

* minor reformatting

* ferry line length filter replaced with min. zoom calculation

hence the results are much closer to what OMT is doing for Z4-Z9

* testFerry() adjusted to match previous commit

ferry test polygon with area 1 now qualifies for min. zoom 5

* clea-up of unused stuff + mvn spotless:apply

* mvn spotless:apply

* added TODO node for follow-up pull-request/simplification

* clean-up: common getMinZoom() code moved to Utils

* minzoom clipping for brunnel was adjusted do Z9-Z12 -> test adjusted too

* clean-up

* use same tolerance for all transportation items, like OSM does

* clean-up, since ferry and non-ferry procesing is now same

* we need regenerate to work with master branch for now

* first sub-class search for agg_stop simplified a little

* contains() used instead of indexOf() for better readability

* numbers as list, not array, so that getFirst() and getLast() can be used

* better trimming and filtring of housenumbers

* adjusted handling of large house numbers

* several unit tests collapsed to one with @ParameterizedTest + @CsvSource

* AGG_STOP_SUBCLASS_ORDER simplified from Map to List

* fixed major omission from previous commit

* clamp() used to replace min()&max() combo

* agg_stop now implemented

* fixed typo in the error message

* prepare IE and GB boundary geometry outside of synchronized{}

* fixed typo in the error message

* mvn spotless:apply

* switch statements for IE and GB route networks simplified

* avoid RouteNetwork->String mapping, not needed for anyMatch()

* fix: attr. brunnel optional based on size on Z4-Z11, attr. layer optional between Z9-Z11

* tolerance change in transportation reverted, added note to README as per why

* fix: monzoom for sea&co. is Z0-Z14 based on area, for the rest it is Z3-Z14 again based on area

* clean-up: avoid doing area->side->area, do just area

* regenerate-openmaptiles.sh 6c31841f4674f15e15afde346a060cf7c22e6cdd (to match content of OMT PR 1591)

* relevant process() functions adjusted to match changes in transportation/mapping.yaml

* regenerate-openmaptiles.sh master, instead of 6c31841f4674f15e15afde346a060cf7c22e6cdd (to match content of OMT PR 1591, in a cleaner way)

* introduce duplicate housenumber filtering (matching OMT PR 1391)

* (less related) clean-up: use isEmpty() instead if size check

* testContainsHousenumber UT adjusted, since duplicate housenumber filtering is reducing amount of house numbers

* use combination of uic_ref, name, network and operator as key for agg_stop sets

If we rely on only on `uic_ref` we group together also stations which are
too far apart (even different cities). With this combo results seem OK,
e.g. all grouped stations are within around 950m (1000 pixels at Z14) of
each other (1000 being used in `PARTITION BY LabelGrid(...` in
`layers/poi/poi.sql` in OpenMapTiles).

* agg_stop comparison made more explicit, since we want to match same exact one

* mvn spotless:apply

* name now important for agg_stop processing, hence name:es (ab)used for unit tests

* agg_stop: simplified processing of nearest station

Results still same, only ordering is different:
- previously: agg_stop=1 first
- now: FIFO

* agg_stop: forther code simplification

* fixed major typo introduced in previous merge

* setMinPixelSize() + setMinZoom() used instead of areaToMinZoom()

* clean-up: unused stuff removed

* mvn spotless:apply

* setAttrWithMinSize() used instead of getBrunnelMinzoom()

getFerryMinzoom() kept since we'd like to replicate `sql_filter: ST_Length(...` from OMT

* getMinZoomForLength() no longer used, hence removed

* MIN_LENGTH value halved, to partially counter the effect of Planetiler applying the limit before merging

* clean-up: LOG2 not used, hence removed

* Revert "MIN_LENGTH value halved, to partially counter the effect of Planetiler applying the limit before merging"

This reverts commit 8fb67075289f3028d31761dcc9564fc597adab36.

* use 256px as buffer pixel override instead of MIN_LENGTH

Make sure we have enough room (=whole next tile) when checking MIN_LENGTH,
to avoid pieces of otherwise "long enough" lines to be excluded (thus
creating "holes" or missing ends) in some tiles just because length in that
particular tile is bellow limit. Given that MIN_LENGTH values translated to
pixels are quite big (compared to {@code BUFFER_SIZE}), such missing pieces
would be quite noticeable.

This improves items mainly in Z12-Z13.

* added BY_TEMP_HAS_NAME comparator to avoid its repeated construction during run-time

* duplicate houcenumber processing simplified further

* clean-up: get(0) replaced with getFirst()

* clean-up: CPU-intensive prepare() moved out of synchronized block

* regenerate-openmaptiles.sh 3cf77e2a542d8a369bb08bf2538cdde0b3effb2b (to match content of OMT PR 1423)

* unit test adjusted for POI office class changes

* regenerate-openmaptiles.sh master (to match content of OMT PR 1544)

* added charging_station implementation matching OMT PR 1544

* use setMinPixelSizeBelowZoom() instead of uniAreaToMinZoom()

* use setMinPixelSizeBelowZoom() instead of getFerryMinzoom()

* fixed unit test, to match recent tweaks

* regenerate-openmaptiles.sh master (to match content of OMT PR 1605)

* Fix university office/amenity collision (to match OSM PR 1607)

* Remove expressway from ramps

* OsmMarinePoint+ne_10m_geography_marine_polys join via name limited to 50km distance

* regenerate-openmaptiles.sh master (to match content of OMT PR 1604)

* Revert "Add aboriginal lands (as per OMT PR 1489)"

This reverts commit 899a0c5718734d5a746cdd84df2e1308614954c0.

* added handling of aboriginal_lands/OsmBoundaryPolygon into Boundary and Place layers

* big islands can now get rank lower than 3

* Add e-road and a-road for transportation z4

* testPolishHighwayIssue165() adjusted: e-road now takes precendence

* regenerate-openmaptiles.sh master (to match content of OMT PR 1627)

* regenerate-openmaptiles.sh fff7110aeb61882abfafe22d1618fbe6181d96cb (to match content of OMT PR 1620)

* Expanded road route attributes (to match OMT PR 1620)

* unrelated clean-up: use getFirst()

* adjusted handling or null and empty ref

* regenerate-openmaptiles.sh master (to match content of OMT PR 1620)

* pointOnSurface() used instead of centroid() to make sure the point is within the boundary

* adjusted deduplication of route_<n>_<something> attributes

* clean-up of some previous adjustments of importantMarinePoints

* clean-up: removed unused imports

* mvn spotless:apply
This commit is contained in:
Peter Hanecak
2024-03-07 09:37:35 +01:00
committed by GitHub
parent 075d90e565
commit b66c89d441
13 changed files with 607 additions and 226 deletions

View File

@@ -209,13 +209,20 @@ public class OpenMapTilesSchema {
/** Attribute names for map elements in the waterway layer. */
final class Fields {
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the waterway. The
* <code>name</code> field may be empty for NaturalEarth data or at lower zoom levels.
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the waterway.
* Language-specific values are in <code>name:xx</code>. The <code>name</code> field may be empty for NaturalEarth
* data or at lower zoom levels.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code>. */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code>. This is deprecated and will be
* removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/** German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. */
/**
* German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. This is
* deprecated and will be removed in a future release in favor of <code>name:de</code>.
*/
public static final String NAME_DE = "name_de";
/**
@@ -546,9 +553,15 @@ public class OpenMapTilesSchema {
/** Attribute names for map elements in the mountain_peak layer. */
final class Fields {
/** The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the peak. */
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the peak.
* Language-specific values are in <code>name:xx</code>.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code>. */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code>. This is deprecated and will be
* removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/** German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. */
public static final String NAME_DE = "name_de";
@@ -606,10 +619,6 @@ public class OpenMapTilesSchema {
* <a href=
* "https://wiki.openstreetmap.org/wiki/Tag:boundary%3Dprotected_area"><code>boundary=protected_area</code></a>, or
* <a href="https://wiki.openstreetmap.org/wiki/Tag:leisure%3Dnature_reserve"><code>leisure=nature_reserve</code></a>.
* This layer also includes boundaries for indigenous lands tagged with <a href=
* "https://wiki.openstreetmap.org/wiki/Tag:boundary%3Daboriginal_lands"><code>boundary=aboriginal_lands</code></a>.
* Indigenous boundaries are not parks, but they are included in this layer for technical reasons related to data
* processing. These boundaries represent areas with special legal and administrative status for indigenous peoples.
*
* Generated from
* <a href="https://github.com/openmaptiles/openmaptiles/blob/master/layers/park/park.yaml">park.yaml</a>
@@ -627,27 +636,29 @@ public class OpenMapTilesSchema {
final class Fields {
/**
* Use the <strong>class</strong> to differentiate between different kinds of features in the <code>parks</code>
* layer, for example between parks and non-parks. The class for <code>boundary=protected_area</code> parks is the
* lower-case of the
* layer. The class for <code>boundary=protected_area</code> parks is the lower-case of the
* <a href="http://wiki.openstreetmap.org/wiki/key:protection_title"><code>protection_title</code></a> value with
* blanks replaced by <code>_</code>. <code>national_park</code> is the class of
* <code>protection_title=National Park</code> and <code>boundary=national_park</code>.
* <code>nature_reserve</code> is the class of <code>protection_title=Nature Reserve</code> and
* <code>leisure=nature_reserve</code>. The class for other
* <a href="http://wiki.openstreetmap.org/wiki/key:protection_title"><code>protection_title</code></a> values is
* similarly assigned. The class for <code>boundary=aboriginal_lands</code> is <code>aboriginal_lands</code>.
* similarly assigned.
*/
public static final String CLASS = "class";
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the park (point
* features only).
* features only). Language-specific values are in <code>name:xx</code>.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code> (point features only). */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code> (point features only). This is
* deprecated and will be removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/**
* German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code> (point
* features only).
* features only). This is deprecated and will be removed in a future release in favor of <code>name:de</code>.
*/
public static final String NAME_DE = "name_de";
/** Rank of the park within one tile, starting at 1 that is the most important park (point features only). */
@@ -663,7 +674,7 @@ public class OpenMapTilesSchema {
}
}
/**
* Contains administrative boundaries as linestrings. Until z4
* Contains administrative boundaries as linestrings and aboriginal lands as polygons. Until z4
* <a href="http://www.naturalearthdata.com/downloads/">Natural Earth data</a> is used after which OSM boundaries
* (<a href=
* "http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative"><code>boundary=administrative</code></a>) are
@@ -686,6 +697,15 @@ public class OpenMapTilesSchema {
/** Attribute names for map elements in the boundary layer. */
final class Fields {
/**
* Use the <strong>class</strong> to differentiate between different kinds of boundaries. The class for
* <code>boundary=aboriginal_lands</code> is <code>aboriginal_lands</code>.
*/
public static final String CLASS = "class";
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value (area features only).
*/
public static final String NAME = "name";
/**
* OSM <a href="http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative#admin_level">admin_level</a>
* indicating the level of importance of this boundary. The <code>admin_level</code> corresponds to the lowest
@@ -1236,11 +1256,18 @@ public class OpenMapTilesSchema {
final class Fields {
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the water body.
* Language-specific values are in <code>name:xx</code>.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code>. */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code>. This is deprecated and will be
* removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/** German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. */
/**
* German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. This is
* deprecated and will be removed in a future release in favor of <code>name:de</code>.
*/
public static final String NAME_DE = "name_de";
/**
@@ -1309,9 +1336,15 @@ public class OpenMapTilesSchema {
* of the highway.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code>. */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code>. This is deprecated and will be
* removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/** German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. */
/**
* German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. This is
* deprecated and will be removed in a future release in favor of <code>name:de</code>.
*/
public static final String NAME_DE = "name_de";
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:ref"><code>ref</code></a> tag of the motorway or its
@@ -1432,18 +1465,54 @@ public class OpenMapTilesSchema {
* </ul>
*/
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";
/** 1st route concurrency network. */
public static final String ROUTE_1_NETWORK = "route_1_network";
/** 1st route concurrency ref. */
public static final String ROUTE_1_REF = "route_1_ref";
/** 1st route concurrency name. */
public static final String ROUTE_1_NAME = "route_1_name";
/** 1st route concurrency colour. */
public static final String ROUTE_1_COLOUR = "route_1_colour";
/** 2nd route concurrency network. */
public static final String ROUTE_2_NETWORK = "route_2_network";
/** 2nd route concurrency ref. */
public static final String ROUTE_2_REF = "route_2_ref";
/** 2nd route concurrency name. */
public static final String ROUTE_2_NAME = "route_2_name";
/** 2nd route concurrency colour. */
public static final String ROUTE_2_COLOUR = "route_2_colour";
/** 3rd route concurrency network. */
public static final String ROUTE_3_NETWORK = "route_3_network";
/** 3rd route concurrency ref. */
public static final String ROUTE_3_REF = "route_3_ref";
/** 3rd route concurrency name. */
public static final String ROUTE_3_NAME = "route_3_name";
/** 3rd route concurrency colour. */
public static final String ROUTE_3_COLOUR = "route_3_colour";
/** 4th route concurrency network. */
public static final String ROUTE_4_NETWORK = "route_4_network";
/** 4th route concurrency ref. */
public static final String ROUTE_4_REF = "route_4_ref";
/** 4th route concurrency name. */
public static final String ROUTE_4_NAME = "route_4_name";
/** 4th route concurrency colour. */
public static final String ROUTE_4_COLOUR = "route_4_colour";
/** 5th route concurrency network. */
public static final String ROUTE_5_NETWORK = "route_5_network";
/** 5th route concurrency ref. */
public static final String ROUTE_5_REF = "route_5_ref";
/** 5th route concurrency name. */
public static final String ROUTE_5_NAME = "route_5_name";
/** 5th route concurrency colour. */
public static final String ROUTE_5_COLOUR = "route_5_colour";
/** 6th route concurrency network. */
public static final String ROUTE_6_NETWORK = "route_6_network";
/** 6th route concurrency ref. */
public static final String ROUTE_6_REF = "route_6_ref";
/** 6th route concurrency name. */
public static final String ROUTE_6_NAME = "route_6_name";
/** 6th route concurrency colour. */
public static final String ROUTE_6_COLOUR = "route_6_colour";
}
/** Attribute values for map elements in the transportation_name layer. */
final class FieldValues {
@@ -1534,11 +1603,20 @@ public class OpenMapTilesSchema {
/** Attribute names for map elements in the place layer. */
final class Fields {
/** The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the POI. */
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the place.
* Language-specific values are in <code>name:xx</code>.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code>. */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code>. This is deprecated and will be
* removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/** German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. */
/**
* German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. This is
* deprecated and will be removed in a future release in favor of <code>name:de</code>.
*/
public static final String NAME_DE = "name_de";
/**
@@ -1561,7 +1639,8 @@ public class OpenMapTilesSchema {
* Original value of the <a href="http://wiki.openstreetmap.org/wiki/Key:place"><code>place</code></a> tag.
* Distinguish between continents, countries, states, islands and places like settlements or smaller entities. Use
* <strong>class</strong> to separately style the different places and build a text hierarchy according to their
* importance.
* importance. For places derived from boundaries, the original value of the
* <a href="http://wiki.openstreetmap.org/wiki/Key:boundary"><code>boundary</code></a> tag.
* <p>
* allowed values:
* <ul>
@@ -1579,6 +1658,7 @@ public class OpenMapTilesSchema {
* <li>"neighbourhood"
* <li>"isolated_dwelling"
* <li>"island"
* <li>"aboriginal_lands"
* </ul>
*/
public static final String CLASS = "class";
@@ -1617,8 +1697,10 @@ public class OpenMapTilesSchema {
public static final String CLASS_NEIGHBOURHOOD = "neighbourhood";
public static final String CLASS_ISOLATED_DWELLING = "isolated_dwelling";
public static final String CLASS_ISLAND = "island";
public static final Set<String> CLASS_VALUES = Set.of("continent", "country", "state", "province", "city", "town",
"village", "hamlet", "borough", "suburb", "quarter", "neighbourhood", "isolated_dwelling", "island");
public static final String CLASS_ABORIGINAL_LANDS = "aboriginal_lands";
public static final Set<String> CLASS_VALUES =
Set.of("continent", "country", "state", "province", "city", "town", "village", "hamlet", "borough", "suburb",
"quarter", "neighbourhood", "isolated_dwelling", "island", "aboriginal_lands");
}
/** Complex mappings to generate attribute values from OSM element tags in the place layer. */
final class FieldMappings {
@@ -1677,11 +1759,20 @@ public class OpenMapTilesSchema {
/** Attribute names for map elements in the poi layer. */
final class Fields {
/** The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the POI. */
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the POI.
* Language-specific values are in <code>name:xx</code>.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code>. */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code>. This is deprecated and will be
* removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/** German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. */
/**
* German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. This is
* deprecated and will be removed in a future release in favor of <code>name:de</code>.
*/
public static final String NAME_DE = "name_de";
/**
@@ -1835,12 +1926,13 @@ public class OpenMapTilesSchema {
public static final MultiExpression<String> Class = MultiExpression.of(List.of(
MultiExpression.entry("shop",
matchAny("subclass", "accessories", "antiques", "beauty", "bed", "boutique", "camera", "carpet", "charity",
"chemist", "coffee", "computer", "convenience", "copyshop", "cosmetics", "garden_centre", "doityourself",
"erotic", "electronics", "fabric", "florist", "frozen_food", "furniture", "video_games", "video", "general",
"gift", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk",
"locksmith", "lamps", "mall", "massage", "motorcycle", "mobile_phone", "newsagent", "optician", "outdoor",
"paint", "perfumery", "perfume", "pet", "photo", "second_hand", "shoes", "sports", "stationery", "tailor",
"tattoo", "ticket", "tobacco", "toys", "travel_agency", "watches", "weapons", "wholesale")),
"chemist", "chocolate", "coffee", "computer", "convenience", "confectionery", "copyshop", "cosmetics",
"garden_centre", "doityourself", "erotic", "electronics", "fabric", "florist", "frozen_food", "furniture",
"video_games", "video", "general", "gift", "hardware", "hearing_aids", "hifi", "interior_decoration",
"jewelry", "kiosk", "locksmith", "lamps", "mall", "massage", "motorcycle", "mobile_phone", "newsagent",
"optician", "outdoor", "paint", "perfumery", "perfume", "pet", "photo", "second_hand", "shoes", "sports",
"stationery", "tailor", "tattoo", "ticket", "tobacco", "toys", "travel_agency", "watches", "weapons",
"wholesale")),
MultiExpression.entry("office",
matchAny("subclass", "accountant", "advertising_agency", "architect", "association", "bail_bond_agent",
"charity", "company", "construction_company", "consulting", "cooperative", "courier", "coworking",
@@ -1872,7 +1964,7 @@ public class OpenMapTilesSchema {
MultiExpression.entry("lodging",
matchAny("subclass", "hotel", "motel", "bed_and_breakfast", "guest_house", "hostel", "chalet", "alpine_hut",
"dormitory")),
MultiExpression.entry("ice_cream", matchAny("subclass", "chocolate", "confectionery")),
MultiExpression.entry("ice_cream", matchAny("subclass", "ice_cream")),
MultiExpression.entry("post", matchAny("subclass", "post_box", "post_office", "parcel_locker")),
MultiExpression.entry("cafe", matchAny("subclass", "cafe")),
MultiExpression.entry("school", matchAny("subclass", "school", "kindergarten")),
@@ -1911,11 +2003,20 @@ public class OpenMapTilesSchema {
/** Attribute names for map elements in the aerodrome_label layer. */
final class Fields {
/** The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the aerodrome. */
/**
* The OSM <a href="http://wiki.openstreetmap.org/wiki/Key:name"><code>name</code></a> value of the aerodrome.
* Language-specific values are in <code>name:xx</code>.
*/
public static final String NAME = "name";
/** English name <code>name:en</code> if available, otherwise <code>name</code>. */
/**
* English name <code>name:en</code> if available, otherwise <code>name</code>. This is deprecated and will be
* removed in a future release in favor of <code>name:en</code>.
*/
public static final String NAME_EN = "name_en";
/** German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. */
/**
* German name <code>name:de</code> if available, otherwise <code>name</code> or <code>name:en</code>. This is
* deprecated and will be removed in a future release in favor of <code>name:de</code>.
*/
public static final String NAME_DE = "name_de";
/**

View File

@@ -248,8 +248,9 @@ public class Tables {
}
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING = and(or(matchAny("leisure", "nature_reserve"),
matchAny("boundary", "national_park", "protected_area", "aboriginal_lands")), matchType("polygon"));
public static final Expression MAPPING =
and(or(matchAny("leisure", "nature_reserve"), matchAny("boundary", "national_park", "protected_area")),
matchType("polygon"));
/**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as
@@ -259,6 +260,25 @@ public class Tables {
void process(OsmParkPolygon element, FeatureCollector features);
}
}
/** An OSM element that would appear in the {@code osm_boundary_polygon} table generated by imposm3. */
public record OsmBoundaryPolygon(@Override String name, @Override String boundary, @Override SourceFeature source)
implements Row, WithName, WithBoundary, WithSource {
public OsmBoundaryPolygon(SourceFeature source, String mappingKey) {
this(source.getString("name"), source.getString("boundary"), source);
}
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
public static final Expression MAPPING =
and(matchAny("boundary", "aboriginal_lands"), matchAny("type", "boundary"), matchType("polygon"));
/**
* Interface for layer implementations to extend to subscribe to OSM elements filtered and parsed as
* {@link OsmBoundaryPolygon}.
*/
public interface Handler {
void process(OsmBoundaryPolygon element, FeatureCollector features);
}
}
/** An OSM element that would appear in the {@code osm_aeroway_polygon} table generated by imposm3. */
public record OsmAerowayPolygon(@Override String ref, @Override String aeroway, @Override SourceFeature source)
implements Row, WithRef, WithAeroway, WithSource {
@@ -320,24 +340,23 @@ public class Tables {
public record OsmHighwayLinestring(@Override String highway, @Override String construction,
@Override String tracktype, @Override String ref, @Override String network, @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 boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway,
@Override boolean isArea, @Override String service, @Override String access, @Override boolean toll,
@Override String usage, @Override String publicTransport, @Override String manMade, @Override String bicycle,
@Override String foot, @Override String horse, @Override String mtbScale, @Override String sacScale,
@Override String surface, @Override boolean expressway, @Override SourceFeature source)
@Override String nameEn, @Override String nameDe, @Override boolean isTunnel, @Override boolean isBridge,
@Override boolean isRamp, @Override boolean isFord, @Override int isOneway, @Override boolean isArea,
@Override String service, @Override String access, @Override boolean toll, @Override String usage,
@Override String publicTransport, @Override String manMade, @Override String bicycle, @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, WithTracktype, WithRef, WithNetwork, WithZOrder, WithLayer,
WithLevel, WithIndoor, WithName, WithNameEn, WithNameDe, WithShortName, WithIsTunnel, WithIsBridge, WithIsRamp,
WithIsFord, WithIsOneway, WithIsArea, WithService, WithAccess, WithToll, WithUsage, WithPublicTransport,
WithManMade, WithBicycle, WithFoot, WithHorse, WithMtbScale, WithSacScale, WithSurface, WithExpressway, WithSource {
WithLevel, WithIndoor, WithName, WithNameEn, WithNameDe, WithIsTunnel, WithIsBridge, WithIsRamp, WithIsFord,
WithIsOneway, WithIsArea, WithService, WithAccess, WithToll, WithUsage, WithPublicTransport, WithManMade,
WithBicycle, WithFoot, WithHorse, WithMtbScale, WithSacScale, WithSurface, WithExpressway, WithSource {
public OsmHighwayLinestring(SourceFeature source, String mappingKey) {
this(source.getString("highway"), source.getString("construction"), source.getString("tracktype"),
source.getString("ref"), source.getString("network"), source.getWayZorder(), source.getLong("layer"),
source.getLong("level"), 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.getBoolean("ramp"), source.getBoolean("ford"),
source.getDirection("oneway"), source.getBoolean("area"), source.getString("service"),
source.getString("access"), source.getBoolean("toll"), source.getString("usage"),
source.getString("name:de"), source.getBoolean("tunnel"), source.getBoolean("bridge"),
source.getBoolean("ramp"), source.getBoolean("ford"), source.getDirection("oneway"), source.getBoolean("area"),
source.getString("service"), source.getString("access"), source.getBoolean("toll"), source.getString("usage"),
source.getString("public_transport"), source.getString("man_made"), source.getString("bicycle"),
source.getString("foot"), source.getString("horse"), source.getString("mtb:scale"),
source.getString("sac_scale"), source.getString("surface"), source.getBoolean("expressway"), source);
@@ -363,17 +382,17 @@ public class Tables {
/** An OSM element that would appear in the {@code osm_railway_linestring} table generated by imposm3. */
public record OsmRailwayLinestring(@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 String nameEn, @Override String nameDe, @Override String shortName, @Override boolean isTunnel,
@Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override boolean isArea,
@Override String service, @Override String usage, @Override SourceFeature source) implements Row, WithRailway,
WithRef, WithNetwork, WithZOrder, WithLayer, WithLevel, WithIndoor, WithName, WithNameEn, WithNameDe, WithShortName,
WithIsTunnel, WithIsBridge, WithIsRamp, WithIsFord, WithIsArea, WithService, WithUsage, WithSource {
@Override String nameEn, @Override String nameDe, @Override boolean isTunnel, @Override boolean isBridge,
@Override boolean isRamp, @Override boolean isFord, @Override boolean isArea, @Override String service,
@Override String usage, @Override SourceFeature source) implements Row, WithRailway, WithRef, WithNetwork,
WithZOrder, WithLayer, WithLevel, WithIndoor, WithName, WithNameEn, WithNameDe, WithIsTunnel, WithIsBridge,
WithIsRamp, WithIsFord, WithIsArea, WithService, WithUsage, WithSource {
public OsmRailwayLinestring(SourceFeature source, String mappingKey) {
this(source.getString("railway"), source.getString("ref"), source.getString("network"), source.getWayZorder(),
source.getLong("layer"), source.getLong("level"), 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.getBoolean("ramp"), source.getBoolean("ford"),
source.getBoolean("area"), source.getString("service"), source.getString("usage"), source);
source.getString("name:en"), source.getString("name:de"), source.getBoolean("tunnel"),
source.getBoolean("bridge"), source.getBoolean("ramp"), source.getBoolean("ford"), source.getBoolean("area"),
source.getString("service"), source.getString("usage"), source);
}
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
@@ -391,16 +410,15 @@ public class Tables {
}
/** An OSM element that would appear in the {@code osm_aerialway_linestring} table generated by imposm3. */
public record OsmAerialwayLinestring(@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 boolean isBridge, @Override boolean isRamp, @Override boolean isFord,
@Override int isOneway, @Override boolean isArea, @Override String service, @Override String usage,
@Override SourceFeature source)
implements Row, WithAerialway, WithZOrder, WithLayer, WithName, WithNameEn, WithNameDe, WithShortName, WithIsTunnel,
WithIsBridge, WithIsRamp, WithIsFord, WithIsOneway, WithIsArea, WithService, WithUsage, WithSource {
@Override String name, @Override String nameEn, @Override String nameDe, @Override boolean isTunnel,
@Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override int isOneway,
@Override boolean isArea, @Override String service, @Override String usage, @Override SourceFeature source)
implements Row, WithAerialway, WithZOrder, WithLayer, WithName, WithNameEn, WithNameDe, WithIsTunnel, WithIsBridge,
WithIsRamp, WithIsFord, WithIsOneway, WithIsArea, WithService, WithUsage, WithSource {
public OsmAerialwayLinestring(SourceFeature source, String mappingKey) {
this(source.getString("aerialway"), source.getWayZorder(), source.getLong("layer"), source.getString("name"),
source.getString("name:en"), source.getString("name:de"), source.getString("short_name"),
source.getBoolean("tunnel"), source.getBoolean("bridge"), source.getBoolean("ramp"), source.getBoolean("ford"),
source.getString("name:en"), source.getString("name:de"), source.getBoolean("tunnel"),
source.getBoolean("bridge"), source.getBoolean("ramp"), source.getBoolean("ford"),
source.getDirection("oneway"), source.getBoolean("area"), source.getString("service"),
source.getString("usage"), source);
}
@@ -419,16 +437,16 @@ public class Tables {
}
/** An OSM element that would appear in the {@code osm_shipway_linestring} table generated by imposm3. */
public record OsmShipwayLinestring(@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 boolean isBridge, @Override boolean isRamp, @Override boolean isFord,
@Override boolean isArea, @Override String service, @Override String usage, @Override SourceFeature source)
implements Row, WithShipway, WithZOrder, WithLayer, WithName, WithNameEn, WithNameDe, WithShortName, WithIsTunnel,
WithIsBridge, WithIsRamp, WithIsFord, WithIsArea, WithService, WithUsage, WithSource {
@Override String name, @Override String nameEn, @Override String nameDe, @Override boolean isTunnel,
@Override boolean isBridge, @Override boolean isRamp, @Override boolean isFord, @Override boolean isArea,
@Override String service, @Override String usage, @Override SourceFeature source)
implements Row, WithShipway, WithZOrder, WithLayer, WithName, WithNameEn, WithNameDe, WithIsTunnel, WithIsBridge,
WithIsRamp, WithIsFord, WithIsArea, WithService, WithUsage, WithSource {
public OsmShipwayLinestring(SourceFeature source, String mappingKey) {
this(source.getString("route"), source.getWayZorder(), source.getLong("layer"), source.getString("name"),
source.getString("name:en"), source.getString("name:de"), source.getString("short_name"),
source.getBoolean("tunnel"), source.getBoolean("bridge"), source.getBoolean("ramp"), source.getBoolean("ford"),
source.getBoolean("area"), source.getString("service"), source.getString("usage"), source);
source.getString("name:en"), source.getString("name:de"), source.getBoolean("tunnel"),
source.getBoolean("bridge"), source.getBoolean("ramp"), source.getBoolean("ford"), source.getBoolean("area"),
source.getString("service"), source.getString("usage"), source);
}
/** Imposm3 "mapping" to filter OSM elements that should appear in this "table". */
@@ -1236,11 +1254,6 @@ public class Tables {
String shipway();
}
/** Rows with a String shortName attribute. */
public interface WithShortName {
String shortName();
}
/** Rows with a SourceFeature source attribute. */
public interface WithSource {
SourceFeature source();
@@ -1331,6 +1344,8 @@ public class Tables {
OsmMountainLinestring.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmParkPolygon.class, OsmParkPolygon::new),
OsmParkPolygon.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmBoundaryPolygon.class, OsmBoundaryPolygon::new),
OsmBoundaryPolygon.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmAerowayPolygon.class, OsmAerowayPolygon::new),
OsmAerowayPolygon.MAPPING),
MultiExpression.entry(new RowClassAndConstructor(OsmAerowayLinestring.class, OsmAerowayLinestring::new),
@@ -1406,6 +1421,10 @@ public class Tables {
result.computeIfAbsent(OsmParkPolygon.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
}
if (handler instanceof OsmBoundaryPolygon.Handler typedHandler) {
result.computeIfAbsent(OsmBoundaryPolygon.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));
}
if (handler instanceof OsmAerowayPolygon.Handler typedHandler) {
result.computeIfAbsent(OsmAerowayPolygon.class, cls -> new ArrayList<>())
.add(new RowHandlerAndClass<>(typedHandler.getClass(), typedHandler::process));

View File

@@ -79,6 +79,8 @@ import org.locationtech.jts.operation.linemerge.LineMerger;
import org.locationtech.jts.operation.polygonize.Polygonizer;
import org.openmaptiles.OpenMapTilesProfile;
import org.openmaptiles.generated.OpenMapTilesSchema;
import org.openmaptiles.generated.Tables;
import org.openmaptiles.util.OmtLanguageUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -95,6 +97,7 @@ public class Boundary implements
OpenMapTilesProfile.NaturalEarthProcessor,
OpenMapTilesProfile.OsmRelationPreprocessor,
OpenMapTilesProfile.OsmAllProcessor,
Tables.OsmBoundaryPolygon.Handler,
OpenMapTilesProfile.FeaturePostProcessor,
OpenMapTilesProfile.FinishHandler {
@@ -127,6 +130,7 @@ public class Boundary implements
private final Map<Long, List<Geometry>> regionGeometries = new HashMap<>();
private final Map<CountryBoundaryComponent, List<Geometry>> boundariesToMerge = new HashMap<>();
private final PlanetilerConfig config;
private final Translations translations;
public Boundary(Translations translations, PlanetilerConfig config, Stats stats) {
this.config = config;
@@ -141,6 +145,7 @@ public class Boundary implements
false
);
this.stats = stats;
this.translations = translations;
}
private static boolean isDisputed(Map<String, Object> tags) {
@@ -306,6 +311,15 @@ public class Boundary implements
}
}
@Override
public void process(Tables.OsmBoundaryPolygon element, FeatureCollector features) {
features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
.putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations))
.setAttr(OpenMapTilesSchema.Boundary.Fields.CLASS, element.boundary())
.setMinPixelSizeBelowZoom(13, 4) // for Z4: `sql_filter: area>power(ZRES3,2)`, etc.
.setMinZoom(4);
}
@Override
public void finish(String sourceName, FeatureCollector.Factory featureCollectors,
Consumer<FeatureCollector.Feature> emit) {

View File

@@ -91,20 +91,15 @@ public class Park implements
@Override
public void process(Tables.OsmParkPolygon element, FeatureCollector features) {
String clazz;
if ("aboriginal_lands".equals(element.boundary())) {
clazz = "aboriginal_lands";
} else {
String protectionTitle = element.protectionTitle();
if (protectionTitle != null) {
protectionTitle = protectionTitle.replace(' ', '_').toLowerCase(Locale.ROOT);
}
clazz = coalesce(
String clazz = coalesce(
nullIfEmpty(protectionTitle),
nullIfEmpty(element.boundary()),
nullIfEmpty(element.leisure())
);
}
// park shape
var outline = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE)

View File

@@ -88,6 +88,7 @@ public class Place implements
Tables.OsmIslandPoint.Handler,
Tables.OsmIslandPolygon.Handler,
Tables.OsmCityPoint.Handler,
Tables.OsmBoundaryPolygon.Handler,
OpenMapTilesProfile.FeaturePostProcessor {
/*
@@ -96,8 +97,10 @@ public class Place implements
* and minimum zoom level to use for those points.
*/
private static final TreeMap<Double, Integer> ISLAND_AREA_RANKS = new TreeMap<>(Map.of(
Double.MAX_VALUE, 3,
private static final TreeMap<Double, Integer> AREA_RANKS = new TreeMap<>(Map.of(
Double.MAX_VALUE, 1,
squareMetersToWorldArea(640_000_000), 2,
squareMetersToWorldArea(160_000_000), 3,
squareMetersToWorldArea(40_000_000), 4,
squareMetersToWorldArea(15_000_000), 5,
squareMetersToWorldArea(1_000_000), 6
@@ -282,7 +285,7 @@ public class Place implements
public void process(Tables.OsmIslandPolygon element, FeatureCollector features) {
try {
double area = element.source().area();
int rank = ISLAND_AREA_RANKS.ceilingEntry(area).getValue();
int rank = AREA_RANKS.ceilingEntry(area).getValue();
int minzoom = rank <= 3 ? 8 : rank <= 4 ? 9 : 10;
features.pointOnSurface(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
@@ -369,6 +372,23 @@ public class Place implements
}
}
@Override
public void process(Tables.OsmBoundaryPolygon element, FeatureCollector features) {
try {
int rank = AREA_RANKS.ceilingEntry(element.source().area()).getValue();
int minzoom = rank <= 4 ? rank + 5 : 10;
features.pointOnSurface(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
.putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations))
.setAttr(OpenMapTilesSchema.Boundary.Fields.CLASS, element.boundary())
.setAttr(Fields.RANK, rank)
.setMinZoom(minzoom);
} catch (GeometryException e) {
e.log(stats, "omt_boundary_poly",
"Unable to get point for OSM boundary polygon " + element.source().id());
}
}
@Override
public List<VectorTile.Feature> postProcess(int zoom, List<VectorTile.Feature> items) {
// infer the rank field from ordering of the place labels with each label grid square

View File

@@ -139,6 +139,11 @@ public class Poi implements
}
private String poiClass(String subclass, String mappingKey) {
// Special case subclass collision between office=university and amenity=university
if ("amenity".equals(mappingKey) && "university".equals(subclass)) {
return FieldValues.CLASS_COLLEGE;
}
subclass = coalesce(subclass, "");
return classMapping.getOrElse(Map.of(
"subclass", subclass,

View File

@@ -142,7 +142,9 @@ public class Transportation implements
private static final Set<RouteNetwork> TRUNK_AS_MOTORWAY_BY_NETWORK = Set.of(
RouteNetwork.CA_TRANSCANADA,
RouteNetwork.CA_PROVINCIAL_ARTERIAL,
RouteNetwork.US_INTERSTATE
RouteNetwork.US_INTERSTATE,
RouteNetwork.E_ROAD,
RouteNetwork.A_ROAD
);
private static final Set<String> CA_AB_PRIMARY_AS_ARTERIAL_BY_REF = Set.of(
"2", "3", "4"
@@ -290,8 +292,15 @@ public class Transportation implements
RouteNetwork networkType = null;
String network = relation.getString("network");
String ref = relation.getString("ref");
String name = nullIfEmpty(relation.getString("name"));
String colour = coalesce(
nullIfEmpty(relation.getString("colour")), nullIfEmpty(relation.getString("ref:colour")));
if ("US:I".equals(network)) {
if ("e-road".equals(network)) {
networkType = RouteNetwork.E_ROAD;
} else if ("AsianHighway".equals(network)) {
networkType = RouteNetwork.A_ROAD;
} else if ("US:I".equals(network)) {
networkType = RouteNetwork.US_INTERSTATE;
} else if ("US:US".equals(network)) {
networkType = RouteNetwork.US_HIGHWAY;
@@ -328,7 +337,8 @@ public class Transportation implements
};
if (network != null || rank < 3) {
return List.of(new RouteRelation(coalesce(ref, ""), network, networkType, (byte) rank, relation.id()));
return List
.of(new RouteRelation(coalesce(ref, ""), network, name, colour, networkType, (byte) rank, relation.id()));
}
}
return null;
@@ -366,6 +376,7 @@ public class Transportation implements
};
result.add(new RouteRelation(refMatcher.group(),
networkType == null ? null : networkType.network,
null, null,
networkType, (byte) -1, 0));
}
} catch (GeometryException e) {
@@ -391,7 +402,9 @@ public class Transportation implements
case "trunk", "primary" -> RouteNetwork.IE_NATIONAL;
default -> RouteNetwork.IE_REGIONAL;
};
result.add(new RouteRelation(refMatcher.group(), networkType.network, networkType, (byte) -1, 0));
result.add(new RouteRelation(refMatcher.group(),
networkType.network, null, null,
networkType, (byte) -1, 0));
}
} catch (GeometryException e) {
e.log(stats, "omt_transportation_name_ie_test",
@@ -406,7 +419,7 @@ public class Transportation implements
RouteRelation getRouteRelation(Tables.OsmHighwayLinestring element) {
List<RouteRelation> all = getRouteRelations(element);
return all.isEmpty() ? null : all.get(0);
return all.isEmpty() ? null : all.getFirst();
}
@Override
@@ -436,6 +449,8 @@ public class Transportation implements
Integer rampAboveZ12 = (highwayRamp || element.isRamp()) ? 1 : null;
Integer rampBelowZ12 = highwayRamp ? 1 : null;
boolean expressway = element.expressway() && !"motorway".equals(highway) && !(element.isRamp() || highwayRamp);
FeatureCollector.Feature feature = features.line(LAYER_NAME).setBufferPixels(BUFFER_SIZE)
// main attributes at all zoom levels (used for grouping <= z8)
.setAttr(Fields.CLASS, highwayClass)
@@ -443,7 +458,7 @@ public class Transportation implements
.setAttr(Fields.NETWORK, networkType != null ? networkType.name : null)
.setAttrWithMinSize(Fields.BRUNNEL, brunnel(element.isBridge(), element.isTunnel(), element.isFord()), 4, 4, 12)
// z8+
.setAttrWithMinzoom(Fields.EXPRESSWAY, element.expressway() && !"motorway".equals(highway) ? 1 : null, 8)
.setAttrWithMinzoom(Fields.EXPRESSWAY, expressway ? 1 : null, 8)
// z9+
.setAttrWithMinSize(Fields.LAYER, nullIfLong(element.layer(), 0), 4, 9, 12)
.setAttrWithMinzoom(Fields.BICYCLE, nullIfEmpty(element.bicycle()), 9)
@@ -643,7 +658,9 @@ public class Transportation implements
GB_PRIMARY("gb-primary", "omt-gb-primary"),
IE_MOTORWAY("ie-motorway", "omt-ie-motorway"),
IE_NATIONAL("ie-national", "omt-ie-national"),
IE_REGIONAL("ie-regional", "omt-ie-regional");
IE_REGIONAL("ie-regional", "omt-ie-regional"),
E_ROAD("e-road", null),
A_ROAD("a-road", null);
final String name;
final String network;
@@ -658,6 +675,8 @@ public class Transportation implements
record RouteRelation(
String ref,
String network,
String name,
String colour,
RouteNetwork networkType,
byte rank,
@Override long id
@@ -669,6 +688,8 @@ public class Transportation implements
MemoryEstimator.estimateSize(rank) +
POINTER_BYTES + estimateSize(ref) +
POINTER_BYTES + estimateSize(network) +
POINTER_BYTES + estimateSize(name) +
POINTER_BYTES + estimateSize(colour) +
POINTER_BYTES + // networkType
MemoryEstimator.estimateSizeLong(id);
}

View File

@@ -113,6 +113,11 @@ public class TransportationName implements
.put(9, 8_000)
.put(10, 4_000)
.put(11, 2_000);
private static final ZoomFunction<Number> BUFFER_PIXEL_OVERRIDES =
ZoomFunction.fromMaxZoomThresholds(Map.of(
13, 256,
6, 256
));
private final boolean brunnel;
private final boolean sizeForShield;
private final boolean limitMerge;
@@ -255,7 +260,7 @@ public class TransportationName implements
FeatureCollector.Feature feature = features.line(LAYER_NAME)
.setBufferPixels(BUFFER_SIZE)
.setBufferPixelOverrides(MIN_LENGTH)
.setBufferPixelOverrides(BUFFER_PIXEL_OVERRIDES)
// TODO abbreviate road names - can't port osml10n because it is AGPL
.putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations))
.setAttr(Fields.REF, ref)
@@ -269,12 +274,20 @@ public class TransportationName implements
.setSortKey(element.zOrder())
.setMinZoom(minzoom);
// populate route_1, route_2, ... route_n tags and remove duplicates
// populate route_1_<something>, route_2_<something>, ... route_n_<something> tags and remove duplicates
Set<String> routes = new HashSet<>();
for (var route : relations) {
String routeString = route.network() + "=" + coalesce(route.ref(), "");
String routeString = route.network() + "=" +
coalesce(route.ref(), "") + "=" +
coalesce(route.name(), "") + "=" +
coalesce(route.colour(), "");
if (routes.add(routeString)) {
feature.setAttr("route_" + routes.size(), routeString);
String keyPrefix = "route_" + routes.size() + "_";
feature.setAttr(keyPrefix + "network", route.network());
feature.setAttr(keyPrefix + "ref", nullIfEmpty(route.ref()));
feature.setAttr(keyPrefix + "name", route.name());
feature.setAttr(keyPrefix + "colour", route.colour());
}
}
@@ -308,7 +321,7 @@ public class TransportationName implements
if (!nullOrEmpty(element.name())) {
features.line(LAYER_NAME)
.setBufferPixels(BUFFER_SIZE)
.setBufferPixelOverrides(MIN_LENGTH)
.setBufferPixelOverrides(BUFFER_PIXEL_OVERRIDES)
.putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations))
.setAttr(Fields.CLASS, "aerialway")
.setAttr(Fields.SUBCLASS, element.aerialway())
@@ -323,7 +336,7 @@ public class TransportationName implements
if (!nullOrEmpty(element.name())) {
features.line(LAYER_NAME)
.setBufferPixels(BUFFER_SIZE)
.setBufferPixelOverrides(MIN_LENGTH)
.setBufferPixelOverrides(BUFFER_PIXEL_OVERRIDES)
.putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations))
.setAttr(Fields.CLASS, element.shipway())
.setMinPixelSize(0)

View File

@@ -83,11 +83,13 @@ public class WaterName implements
private static final Logger LOGGER = LoggerFactory.getLogger(WaterName.class);
private static final Set<String> SEA_OR_OCEAN_PLACE = Set.of("sea", "ocean");
private static final double IMPORTANT_MARINE_REGIONS_JOIN_DISTANCE =
GeoUtils.metersToPixelAtEquator(0, 50_000) / 256d;
private final Translations translations;
// need to synchronize updates from multiple threads
private final LongObjectMap<Geometry> lakeCenterlines = Hppc.newLongObjectHashMap();
// may be updated concurrently by multiple threads
private final ConcurrentSkipListMap<String, Integer> importantMarinePoints = new ConcurrentSkipListMap<>();
private final ConcurrentSkipListMap<String, NaturalEarthRegion> importantMarinePoints = new ConcurrentSkipListMap<>();
private final Stats stats;
public WaterName(Translations translations, PlanetilerConfig config, Stats stats) {
@@ -133,10 +135,48 @@ public class WaterName implements
Integer scalerank = Parse.parseIntOrNull(feature.getTag("scalerank"));
if (name != null && scalerank != null) {
name = name.replaceAll("\\s+", " ").trim().toLowerCase();
importantMarinePoints.put(name, scalerank);
try {
importantMarinePoints.put(name, new NaturalEarthRegion(feature.worldGeometry(), scalerank));
} catch (GeometryException e) {
e.log(stats, "ne_marine_polys",
"Error getting geometry for natural earth feature " + table + " " + feature.getTag("ogc_fid"));
}
}
}
}
private NaturalEarthRegion getImportantMarineRegion(Tables.OsmMarinePoint element) {
var source = element.source();
String name = element.name().toLowerCase();
NaturalEarthRegion result = importantMarinePoints.get(name);
if (result == null) {
result = importantMarinePoints.get(source.getString("name:en", "").toLowerCase());
}
if (result == null) {
result = importantMarinePoints.get(source.getString("name:es", "").toLowerCase());
}
if (result == null) {
Map.Entry<String, NaturalEarthRegion> next = importantMarinePoints.ceilingEntry(name);
if (next != null && next.getKey().startsWith(name)) {
result = next.getValue();
}
}
if (result == null) {
return null;
}
try {
double distance = result.geometry.distance(source.worldGeometry());
if (distance <= IMPORTANT_MARINE_REGIONS_JOIN_DISTANCE) {
return result;
}
} catch (GeometryException e) {
e.log(stats, "osm_marine_point",
"Error getting geometry for OSM marine point " + element.source().id());
}
return null;
}
@Override
public void process(Tables.OsmMarinePoint element, FeatureCollector features) {
@@ -148,29 +188,14 @@ public class WaterName implements
var source = element.source();
// use name from OSM, but get min zoom from natural earth based on fuzzy name match...
Integer rank = Parse.parseIntOrNull(source.getTag("rank"));
String name = element.name().toLowerCase();
Integer nerank;
if ((nerank = importantMarinePoints.get(name)) != null) {
rank = nerank;
} else if ((nerank = importantMarinePoints.get(source.getString("name:en", "").toLowerCase())) != null) {
rank = nerank;
} else if ((nerank = importantMarinePoints.get(source.getString("name:es", "").toLowerCase())) != null) {
rank = nerank;
} else {
Map.Entry<String, Integer> next = importantMarinePoints.ceilingEntry(name);
if (next != null && next.getKey().startsWith(name)) {
rank = next.getValue();
}
NaturalEarthRegion neRegion = getImportantMarineRegion(element);
if (neRegion != null) {
rank = neRegion.scalerank;
}
int minZoom;
if ("ocean".equals(element.place())) {
minZoom = 0;
} else if (rank != null) {
// FIXME: While this looks like matching properly stuff in https://github.com/openmaptiles/openmaptiles/pull/1457/files#diff-201daa1c61c99073fe3280d440c9feca5ed2236b251ad454caa14cc203f952d1R74 ,
// it includes not just https://www.openstreetmap.org/relation/13360255 but also https://www.openstreetmap.org/node/1385157299 (and some others).
// Hence check how that OpenMapTiles code works for "James Bay" and:
// a) if same as here then, fix there and then here
// b) if OK (while here NOK), fix only here
minZoom = rank;
} else if ("bay".equals(element.natural())) {
minZoom = 13;
@@ -220,4 +245,9 @@ public class WaterName implements
.setMinZoom(minzoom);
}
}
private record NaturalEarthRegion(
Geometry geometry,
int scalerank
) {}
}

View File

@@ -714,4 +714,26 @@ class BoundaryTest extends AbstractLayerTest {
assertFeatures(14, List.of(Map.of("_minzoom", 1)),
processOsmOnly(lineFeatureWithRelation(profile.preprocessOsmRelation(relation), Map.of())));
}
@Test
void testIndigenousLand() {
assertFeatures(0, List.of(Map.of(
"_layer", "boundary",
"class", "aboriginal_lands",
"name", "Seminole Nation",
"name_en", "Seminole Nation",
"name:latin", "Seminole Nation",
"_type", "polygon",
"_minzoom", 4
), Map.of(
"_layer", "place"
)), process(polygonFeatureWithArea(1,
Map.of(
"type", "boundary",
"boundary", "aboriginal_lands",
"name", "Seminole Nation",
"name:en", "Seminole Nation"
))));
}
}

View File

@@ -45,30 +45,6 @@ class ParkTest extends AbstractLayerTest {
))));
}
@Test
void testAbotiginalLand() {
assertFeatures(13, List.of(Map.of(
"_layer", "park",
"_type", "polygon",
"class", "aboriginal_lands",
"name", "Hualapai Tribe",
"_minpixelsize", 2d,
"_minzoom", 4,
"_maxzoom", 14
), Map.of(
"_layer", "park",
"_type", "point",
"class", "aboriginal_lands",
"name", "Hualapai Tribe",
"_minzoom", 5,
"_maxzoom", 14
)), process(polygonFeature(Map.of(
"boundary", "aboriginal_lands",
"name", "Hualapai Tribe",
"protection_title", "National Park"
))));
}
@Test
void testSmallerPark() {
double z11area = Math.pow((GeoUtils.metersToPixelAtEquator(0, Math.sqrt(70_000)) / 256d), 2) * Math.pow(2, 20 - 11);

View File

@@ -258,7 +258,7 @@ class PlaceTest extends AbstractLayerTest {
"name", "Nantucket",
"name_en", "Nantucket",
"name:latin", "Nantucket",
"rank", 3,
"rank", 1,
"_type", "point",
"_minzoom", 8
@@ -287,6 +287,49 @@ class PlaceTest extends AbstractLayerTest {
))));
}
@Test
void testIndigenousLand() {
assertFeatures(0, List.of(Map.of(
"_layer", "place",
"class", "aboriginal_lands",
"name", "Seminole Nation",
"name_en", "Seminole Nation",
"name:latin", "Seminole Nation",
"rank", 1,
"_type", "point",
"_minzoom", 6
), Map.of(
"_layer", "boundary"
)), process(polygonFeatureWithArea(1,
Map.of(
"type", "boundary",
"boundary", "aboriginal_lands",
"name", "Seminole Nation",
"name:en", "Seminole Nation"
))));
double rank2area = Math.pow(GeoUtils.metersToPixelAtEquator(0, Math.sqrt(640_000_000 - 1)) / 256d, 2);
assertFeatures(0, List.of(Map.of(
"_layer", "place",
"class", "aboriginal_lands",
"name", "Seminole Nation",
"rank", 2,
"_type", "point",
"_minzoom", 7
), Map.of(
"_layer", "boundary"
)), process(polygonFeatureWithArea(rank2area,
Map.of(
"type", "boundary",
"boundary", "aboriginal_lands",
"name", "Seminole Nation",
"name:en", "Seminole Nation"
))));
}
@Test
void testPlaceSortKeyRanking() {
int[] sortKeys = new int[]{

View File

@@ -3,6 +3,7 @@ package org.openmaptiles.layers;
import static com.onthegomap.planetiler.TestUtils.newLineString;
import static com.onthegomap.planetiler.TestUtils.newPoint;
import static com.onthegomap.planetiler.TestUtils.rectangle;
import static java.util.Map.entry;
import static org.junit.jupiter.api.Assertions.assertFalse;
import com.onthegomap.planetiler.FeatureCollector;
@@ -280,17 +281,18 @@ class TransportationTest extends AbstractLayerTest {
"horse", "no",
"brunnel", "bridge",
"_minzoom", 4
), Map.of(
"_layer", "transportation_name",
"class", "motorway",
"name", "Massachusetts Turnpike",
"name_en", "Massachusetts Turnpike",
"ref", "90",
"ref_length", 2,
"network", "us-interstate",
"route_1", "US:I=90",
"brunnel", "<null>",
"_minzoom", 6
), Map.ofEntries(
entry("_layer", "transportation_name"),
entry("class", "motorway"),
entry("name", "Massachusetts Turnpike"),
entry("name_en", "Massachusetts Turnpike"),
entry("ref", "90"),
entry("ref_length", 2),
entry("network", "us-interstate"),
entry("route_1_network", "US:I"),
entry("route_1_ref", "90"),
entry("brunnel", "<null>"),
entry("_minzoom", 6)
)), features);
assertFeatures(8, List.of(Map.of(
@@ -304,17 +306,18 @@ class TransportationTest extends AbstractLayerTest {
"horse", "<null>",
"brunnel", "bridge",
"_minzoom", 4
), Map.of(
"_layer", "transportation_name",
"class", "motorway",
"name", "Massachusetts Turnpike",
"name_en", "Massachusetts Turnpike",
"ref", "90",
"ref_length", 2,
"network", "us-interstate",
"route_1", "US:I=90",
"brunnel", "<null>",
"_minzoom", 6
), Map.ofEntries(
entry("_layer", "transportation_name"),
entry("class", "motorway"),
entry("name", "Massachusetts Turnpike"),
entry("name_en", "Massachusetts Turnpike"),
entry("ref", "90"),
entry("ref_length", 2),
entry("network", "us-interstate"),
entry("route_1_network", "US:I"),
entry("route_1_ref", "90"),
entry("brunnel", "<null>"),
entry("_minzoom", 6)
)), features);
}
@@ -326,7 +329,7 @@ class TransportationTest extends AbstractLayerTest {
rel1.setTag("network", "US:OK");
rel1.setTag("ref", "104");
rel1.setTag("direction", "north");
var rel2 = new OsmElement.Relation(2);
var rel2 = new OsmElement.Relation(1);
rel2.setTag("type", "route");
rel2.setTag("route", "road");
rel2.setTag("network", "US:OK");
@@ -357,8 +360,10 @@ class TransportationTest extends AbstractLayerTest {
"ref", "104",
"ref_length", 3,
"network", "us-state",
"route_1", "US:OK=104",
"route_2", "<null>",
"route_1_network", "US:OK",
"route_1_ref", "104",
"route_2_network", "<null>",
"route_2_ref", "<null>",
"_minzoom", 8
)), features);
}
@@ -372,7 +377,7 @@ class TransportationTest extends AbstractLayerTest {
rel1.setTag("ref", "NJTP");
rel1.setTag("name", "New Jersey Turnpike (mainline)");
var rel2 = new OsmElement.Relation(1);
var rel2 = new OsmElement.Relation(2);
rel2.setTag("type", "route");
rel2.setTag("route", "road");
rel2.setTag("network", "US:I");
@@ -400,8 +405,55 @@ class TransportationTest extends AbstractLayerTest {
"name", "New Jersey Turnpike",
"ref", "95",
"ref_length", 2,
"route_1", "US:I=95",
"route_2", "US:NJ:NJTP=NJTP",
"route_1_network", "US:I",
"route_1_ref", "95",
"route_2_network", "US:NJ:NJTP",
"route_2_ref", "NJTP",
"_minzoom", 6
)), rendered);
}
@Test
void testRouteWithColour() {
var rel1 = new OsmElement.Relation(1);
rel1.setTag("type", "route");
rel1.setTag("route", "road");
rel1.setTag("network", "US:NJ:NJTP");
rel1.setTag("ref", "NJTP");
rel1.setTag("name", "New Jersey Turnpike (mainline)");
rel1.setTag("colour", "#FFFFFF");
rel1.setTag("ref:colour", "#888888");
var rel2 = new OsmElement.Relation(2);
rel2.setTag("type", "route");
rel2.setTag("route", "road");
rel2.setTag("network", "US:I");
rel2.setTag("ref", "95");
rel2.setTag("name", "I 95 (NJ)");
rel2.setTag("ref:colour", "#000000");
FeatureCollector rendered = process(lineFeatureWithRelation(
Stream.concat(
profile.preprocessOsmRelation(rel1).stream(),
profile.preprocessOsmRelation(rel2).stream()
).toList(),
Map.of(
"highway", "motorway",
"name", "New Jersey Turnpike",
"ref", "I 95;NJTP"
)));
assertFeatures(13, List.of(mapOf(
"_layer", "transportation",
"class", "motorway",
"_minzoom", 4
), Map.of(
"_layer", "transportation_name",
"class", "motorway",
"route_1_network", "US:I",
"route_1_colour", "#000000",
"route_2_network", "US:NJ:NJTP",
"route_2_colour", "#FFFFFF",
"_minzoom", 6
)), rendered);
}
@@ -411,7 +463,7 @@ class TransportationTest extends AbstractLayerTest {
List<OsmRelationInfo> relations = new ArrayList<>();
for (int route = 1; route <= 16; route++) {
int num = (route + 1) / 2; // to make dups
var rel = new OsmElement.Relation(route);
var rel = new OsmElement.Relation(num);
rel.setTag("type", "route");
rel.setTag("route", "road");
rel.setTag("network", "US:I");
@@ -434,15 +486,24 @@ class TransportationTest extends AbstractLayerTest {
"_minzoom", 4
), mapOf(
"_layer", "transportation_name",
"route_1", "US:I=1",
"route_2", "US:I=2",
"route_3", "US:I=3",
"route_4", "US:I=4",
"route_5", "US:I=5",
"route_6", "US:I=6",
"route_7", "US:I=7",
"route_8", "US:I=8",
"route_9", "<null>"
"route_1_network", "US:I",
"route_1_ref", "1",
"route_2_network", "US:I",
"route_2_ref", "2",
"route_3_network", "US:I",
"route_3_ref", "3",
"route_4_network", "US:I",
"route_4_ref", "4",
"route_5_network", "US:I",
"route_5_ref", "5",
"route_6_network", "US:I",
"route_6_ref", "6",
"route_7_network", "US:I",
"route_7_ref", "7",
"route_8_network", "US:I",
"route_8_ref", "8",
"route_9_network", "<null>",
"route_9_ref", "<null>"
)), rendered);
}
@@ -519,10 +580,12 @@ class TransportationTest extends AbstractLayerTest {
"_layer", "transportation_name",
"class", "trunk",
"name", "<null>",
"ref", "S7",
"ref_length", 2,
"route_1", "e-road=E 28",
"route_2", "e-road=E 77"
"ref", "E 28",
"ref_length", 4,
"route_1_network", "e-road",
"route_1_ref", "E 28",
"route_2_network", "e-road",
"route_2_ref", "E 77"
)), rendered);
}
@@ -601,7 +664,8 @@ class TransportationTest extends AbstractLayerTest {
"ref_length", 2,
"network", "us-interstate",
"brunnel", "<null>",
"route_1", "US:I=90",
"route_1_network", "US:I",
"route_1_ref", "90",
"_minzoom", 6
)), features);
}
@@ -839,17 +903,19 @@ class TransportationTest extends AbstractLayerTest {
"ramp", "<null>",
"network", "us-highway",
"_minzoom", 7
), Map.of(
"_layer", "transportation_name",
"class", "primary",
"name", "Memorial Drive",
"name_en", "Memorial Drive",
"ref", "3",
"ref_length", 1,
"network", "us-highway",
"route_1", "US:US=3",
"route_2", "US:MA=2",
"_minzoom", 12
), Map.ofEntries(
entry("_layer", "transportation_name"),
entry("class", "primary"),
entry("name", "Memorial Drive"),
entry("name_en", "Memorial Drive"),
entry("ref", "3"),
entry("ref_length", 1),
entry("network", "us-highway"),
entry("route_1_network", "US:US"),
entry("route_1_ref", "3"),
entry("route_2_network", "US:MA"),
entry("route_2_ref", "2"),
entry("_minzoom", 12)
)), process(lineFeatureWithRelation(
Stream.concat(
profile.preprocessOsmRelation(relUS).stream(),
@@ -869,8 +935,10 @@ class TransportationTest extends AbstractLayerTest {
), Map.of(
"_layer", "transportation_name",
"class", "primary",
"route_1", "US:US=3",
"route_2", "US:MA=2",
"route_1_network", "US:US",
"route_1_ref", "3",
"route_2_network", "US:MA",
"route_2_ref", "2",
"ref", "3",
"network", "us-highway"
)), process(lineFeatureWithRelation(
@@ -2041,4 +2109,58 @@ class TransportationTest extends AbstractLayerTest {
"name:en", "Ayalon South"
)), result);
}
@Test
void testARoad() {
var rel = new OsmElement.Relation(1);
rel.setTag("type", "route");
rel.setTag("route", "road");
rel.setTag("network", "AsianHighway");
rel.setTag("ref", "AH11");
FeatureCollector features = process(lineFeatureWithRelation(
profile.preprocessOsmRelation(rel),
Map.of(
"highway", "trunk"
)));
assertFeatures(13, List.of(Map.of(
"_layer", "transportation",
"class", "trunk",
"network", "a-road",
"_minzoom", 4
), Map.of(
"_layer", "transportation_name",
"class", "trunk",
"ref", "AH11",
"network", "a-road"
)), features);
}
@Test
void testERoad() {
var rel = new OsmElement.Relation(1);
rel.setTag("type", "route");
rel.setTag("route", "road");
rel.setTag("network", "e-road");
rel.setTag("ref", "E 50");
FeatureCollector features = process(lineFeatureWithRelation(
profile.preprocessOsmRelation(rel),
Map.of(
"highway", "motorway"
)));
assertFeatures(13, List.of(Map.of(
"_layer", "transportation",
"class", "motorway",
"network", "e-road",
"_minzoom", 4
), Map.of(
"_layer", "transportation_name",
"class", "motorway",
"ref", "E 50",
"network", "e-road"
)), features);
}
}