diff --git a/src/main/java/org/openmaptiles/generated/OpenMapTilesSchema.java b/src/main/java/org/openmaptiles/generated/OpenMapTilesSchema.java index 03014fce..676b5a46 100644 --- a/src/main/java/org/openmaptiles/generated/OpenMapTilesSchema.java +++ b/src/main/java/org/openmaptiles/generated/OpenMapTilesSchema.java @@ -209,13 +209,20 @@ default String name() { /** Attribute names for map elements in the waterway layer. */ final class Fields { /** - * The OSM name value of the waterway. The - * name field may be empty for NaturalEarth data or at lower zoom levels. + * The OSM name value of the waterway. + * Language-specific values are in name:xx. The name field may be empty for NaturalEarth + * data or at lower zoom levels. */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name. */ + /** + * English name name:en if available, otherwise name. This is deprecated and will be + * removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; - /** German name name:de if available, otherwise name or name:en. */ + /** + * German name name:de if available, otherwise name or name:en. This is + * deprecated and will be removed in a future release in favor of name:de. + */ public static final String NAME_DE = "name_de"; /** @@ -546,9 +553,15 @@ default String name() { /** Attribute names for map elements in the mountain_peak layer. */ final class Fields { - /** The OSM name value of the peak. */ + /** + * The OSM name value of the peak. + * Language-specific values are in name:xx. + */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name. */ + /** + * English name name:en if available, otherwise name. This is deprecated and will be + * removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; /** German name name:de if available, otherwise name or name:en. */ public static final String NAME_DE = "name_de"; @@ -606,10 +619,6 @@ final class FieldMappings { * boundary=protected_area, or * leisure=nature_reserve. - * This layer also includes boundaries for indigenous lands tagged with boundary=aboriginal_lands. - * 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 * park.yaml @@ -627,27 +636,29 @@ default String name() { final class Fields { /** * Use the class to differentiate between different kinds of features in the parks - * layer, for example between parks and non-parks. The class for boundary=protected_area parks is the - * lower-case of the + * layer. The class for boundary=protected_area parks is the lower-case of the * protection_title value with * blanks replaced by _. national_park is the class of * protection_title=National Park and boundary=national_park. * nature_reserve is the class of protection_title=Nature Reserve and * leisure=nature_reserve. The class for other * protection_title values is - * similarly assigned. The class for boundary=aboriginal_lands is aboriginal_lands. + * similarly assigned. */ public static final String CLASS = "class"; /** * The OSM name value of the park (point - * features only). + * features only). Language-specific values are in name:xx. */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name (point features only). */ + /** + * English name name:en if available, otherwise name (point features only). This is + * deprecated and will be removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; /** * German name name:de if available, otherwise name or name:en (point - * features only). + * features only). This is deprecated and will be removed in a future release in favor of name:de. */ 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 @@ final class FieldMappings { } } /** - * Contains administrative boundaries as linestrings. Until z4 + * Contains administrative boundaries as linestrings and aboriginal lands as polygons. Until z4 * Natural Earth data is used after which OSM boundaries * (boundary=administrative) are @@ -686,6 +697,15 @@ default String name() { /** Attribute names for map elements in the boundary layer. */ final class Fields { + /** + * Use the class to differentiate between different kinds of boundaries. The class for + * boundary=aboriginal_lands is aboriginal_lands. + */ + public static final String CLASS = "class"; + /** + * The OSM name value (area features only). + */ + public static final String NAME = "name"; /** * OSM admin_level * indicating the level of importance of this boundary. The admin_level corresponds to the lowest @@ -1236,11 +1256,18 @@ default String name() { final class Fields { /** * The OSM name value of the water body. + * Language-specific values are in name:xx. */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name. */ + /** + * English name name:en if available, otherwise name. This is deprecated and will be + * removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; - /** German name name:de if available, otherwise name or name:en. */ + /** + * German name name:de if available, otherwise name or name:en. This is + * deprecated and will be removed in a future release in favor of name:de. + */ public static final String NAME_DE = "name_de"; /** @@ -1309,9 +1336,15 @@ final class Fields { * of the highway. */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name. */ + /** + * English name name:en if available, otherwise name. This is deprecated and will be + * removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; - /** German name name:de if available, otherwise name or name:en. */ + /** + * German name name:de if available, otherwise name or name:en. This is + * deprecated and will be removed in a future release in favor of name:de. + */ public static final String NAME_DE = "name_de"; /** * The OSM ref tag of the motorway or its @@ -1432,18 +1465,54 @@ final class Fields { * */ 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 @@ default String name() { /** Attribute names for map elements in the place layer. */ final class Fields { - /** The OSM name value of the POI. */ + /** + * The OSM name value of the place. + * Language-specific values are in name:xx. + */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name. */ + /** + * English name name:en if available, otherwise name. This is deprecated and will be + * removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; - /** German name name:de if available, otherwise name or name:en. */ + /** + * German name name:de if available, otherwise name or name:en. This is + * deprecated and will be removed in a future release in favor of name:de. + */ public static final String NAME_DE = "name_de"; /** @@ -1561,7 +1639,8 @@ final class Fields { * Original value of the place tag. * Distinguish between continents, countries, states, islands and places like settlements or smaller entities. Use * class 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 + * boundary tag. *

* allowed values: *

*/ public static final String CLASS = "class"; @@ -1617,8 +1697,10 @@ final class FieldValues { 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 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 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 @@ default String name() { /** Attribute names for map elements in the poi layer. */ final class Fields { - /** The OSM name value of the POI. */ + /** + * The OSM name value of the POI. + * Language-specific values are in name:xx. + */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name. */ + /** + * English name name:en if available, otherwise name. This is deprecated and will be + * removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; - /** German name name:de if available, otherwise name or name:en. */ + /** + * German name name:de if available, otherwise name or name:en. This is + * deprecated and will be removed in a future release in favor of name:de. + */ public static final String NAME_DE = "name_de"; /** @@ -1835,12 +1926,13 @@ final class FieldMappings { public static final MultiExpression 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 @@ final class FieldMappings { 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 @@ default String name() { /** Attribute names for map elements in the aerodrome_label layer. */ final class Fields { - /** The OSM name value of the aerodrome. */ + /** + * The OSM name value of the aerodrome. + * Language-specific values are in name:xx. + */ public static final String NAME = "name"; - /** English name name:en if available, otherwise name. */ + /** + * English name name:en if available, otherwise name. This is deprecated and will be + * removed in a future release in favor of name:en. + */ public static final String NAME_EN = "name_en"; - /** German name name:de if available, otherwise name or name:en. */ + /** + * German name name:de if available, otherwise name or name:en. This is + * deprecated and will be removed in a future release in favor of name:de. + */ public static final String NAME_DE = "name_de"; /** diff --git a/src/main/java/org/openmaptiles/generated/Tables.java b/src/main/java/org/openmaptiles/generated/Tables.java index 1d2458ed..88fa4ec2 100644 --- a/src/main/java/org/openmaptiles/generated/Tables.java +++ b/src/main/java/org/openmaptiles/generated/Tables.java @@ -248,8 +248,9 @@ public OsmParkPolygon(SourceFeature source, String mappingKey) { } /** 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 interface Handler { 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 interface Handler { 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 interface Handler { /** 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 interface Handler { } /** 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 interface Handler { } /** 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 interface WithShipway { 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 interface WithZOrder { 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 static Map, List>> generateDis 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)); diff --git a/src/main/java/org/openmaptiles/layers/Boundary.java b/src/main/java/org/openmaptiles/layers/Boundary.java index 83f7f62e..99a29977 100644 --- a/src/main/java/org/openmaptiles/layers/Boundary.java +++ b/src/main/java/org/openmaptiles/layers/Boundary.java @@ -79,6 +79,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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> regionGeometries = new HashMap<>(); private final Map> 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 Boundary(Translations translations, PlanetilerConfig config, Stats stats) false ); this.stats = stats; + this.translations = translations; } private static boolean isDisputed(Map tags) { @@ -306,6 +311,15 @@ public void processAllOsm(SourceFeature feature, FeatureCollector features) { } } + @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 emit) { diff --git a/src/main/java/org/openmaptiles/layers/Park.java b/src/main/java/org/openmaptiles/layers/Park.java index 026f1f62..648df0f3 100644 --- a/src/main/java/org/openmaptiles/layers/Park.java +++ b/src/main/java/org/openmaptiles/layers/Park.java @@ -91,20 +91,15 @@ public Park(Translations translations, PlanetilerConfig config, Stats stats) { @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( - nullIfEmpty(protectionTitle), - nullIfEmpty(element.boundary()), - nullIfEmpty(element.leisure()) - ); + String protectionTitle = element.protectionTitle(); + if (protectionTitle != null) { + protectionTitle = protectionTitle.replace(' ', '_').toLowerCase(Locale.ROOT); } + String clazz = coalesce( + nullIfEmpty(protectionTitle), + nullIfEmpty(element.boundary()), + nullIfEmpty(element.leisure()) + ); // park shape var outline = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) diff --git a/src/main/java/org/openmaptiles/layers/Place.java b/src/main/java/org/openmaptiles/layers/Place.java index ed1e5221..f764d15f 100644 --- a/src/main/java/org/openmaptiles/layers/Place.java +++ b/src/main/java/org/openmaptiles/layers/Place.java @@ -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 ISLAND_AREA_RANKS = new TreeMap<>(Map.of( - Double.MAX_VALUE, 3, + private static final TreeMap 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 void process(Tables.OsmStatePoint element, FeatureCollector features) { 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 void process(Tables.OsmCityPoint element, FeatureCollector features) { } } + @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 postProcess(int zoom, List items) { // infer the rank field from ordering of the place labels with each label grid square diff --git a/src/main/java/org/openmaptiles/layers/Poi.java b/src/main/java/org/openmaptiles/layers/Poi.java index b2b9aba1..e511cc50 100644 --- a/src/main/java/org/openmaptiles/layers/Poi.java +++ b/src/main/java/org/openmaptiles/layers/Poi.java @@ -139,6 +139,11 @@ static int poiClassRank(String clazz) { } 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, diff --git a/src/main/java/org/openmaptiles/layers/Transportation.java b/src/main/java/org/openmaptiles/layers/Transportation.java index 4aa898ef..ba828a44 100644 --- a/src/main/java/org/openmaptiles/layers/Transportation.java +++ b/src/main/java/org/openmaptiles/layers/Transportation.java @@ -142,7 +142,9 @@ public class Transportation implements private static final Set 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 CA_AB_PRIMARY_AS_ARTERIAL_BY_REF = Set.of( "2", "3", "4" @@ -290,8 +292,15 @@ public List preprocessOsmRelation(OsmElement.Relation relation) RouteNetwork networkType = null; String network = relation.getString("network"); String ref = relation.getString("ref"); - - if ("US:I".equals(network)) { + String name = nullIfEmpty(relation.getString("name")); + String colour = coalesce( + nullIfEmpty(relation.getString("colour")), nullIfEmpty(relation.getString("ref:colour"))); + + 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 List preprocessOsmRelation(OsmElement.Relation relation) }; 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 @@ List getRouteRelations(Tables.OsmHighwayLinestring element) { }; result.add(new RouteRelation(refMatcher.group(), networkType == null ? null : networkType.network, + null, null, networkType, (byte) -1, 0)); } } catch (GeometryException e) { @@ -391,7 +402,9 @@ List getRouteRelations(Tables.OsmHighwayLinestring element) { 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 @@ List getRouteRelations(Tables.OsmHighwayLinestring element) { RouteRelation getRouteRelation(Tables.OsmHighwayLinestring element) { List all = getRouteRelations(element); - return all.isEmpty() ? null : all.get(0); + return all.isEmpty() ? null : all.getFirst(); } @Override @@ -436,6 +449,8 @@ public void process(Tables.OsmHighwayLinestring element, FeatureCollector featur 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 void process(Tables.OsmHighwayLinestring element, FeatureCollector featur .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 @@ enum RouteNetwork { 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 @@ enum RouteNetwork { record RouteRelation( String ref, String network, + String name, + String colour, RouteNetwork networkType, byte rank, @Override long id @@ -669,6 +688,8 @@ public long estimateMemoryUsageBytes() { 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); } diff --git a/src/main/java/org/openmaptiles/layers/TransportationName.java b/src/main/java/org/openmaptiles/layers/TransportationName.java index 4e8fefd8..2ac9f400 100644 --- a/src/main/java/org/openmaptiles/layers/TransportationName.java +++ b/src/main/java/org/openmaptiles/layers/TransportationName.java @@ -113,6 +113,11 @@ public class TransportationName implements .put(9, 8_000) .put(10, 4_000) .put(11, 2_000); + private static final ZoomFunction 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 void process(Tables.OsmHighwayLinestring element, FeatureCollector featur 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 void process(Tables.OsmHighwayLinestring element, FeatureCollector featur .setSortKey(element.zOrder()) .setMinZoom(minzoom); - // populate route_1, route_2, ... route_n tags and remove duplicates + // populate route_1_, route_2_, ... route_n_ tags and remove duplicates Set 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 void process(Tables.OsmAerialwayLinestring element, FeatureCollector feat 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 void process(Tables.OsmShipwayLinestring element, FeatureCollector featur 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) diff --git a/src/main/java/org/openmaptiles/layers/WaterName.java b/src/main/java/org/openmaptiles/layers/WaterName.java index cebaeffe..cd3a1a8b 100644 --- a/src/main/java/org/openmaptiles/layers/WaterName.java +++ b/src/main/java/org/openmaptiles/layers/WaterName.java @@ -83,11 +83,13 @@ public class WaterName implements private static final Logger LOGGER = LoggerFactory.getLogger(WaterName.class); private static final Set 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 lakeCenterlines = Hppc.newLongObjectHashMap(); // may be updated concurrently by multiple threads - private final ConcurrentSkipListMap importantMarinePoints = new ConcurrentSkipListMap<>(); + private final ConcurrentSkipListMap importantMarinePoints = new ConcurrentSkipListMap<>(); private final Stats stats; public WaterName(Translations translations, PlanetilerConfig config, Stats stats) { @@ -133,11 +135,49 @@ public void processNaturalEarth(String table, SourceFeature feature, FeatureColl 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 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) { if (!element.name().isBlank()) { @@ -148,29 +188,14 @@ public void process(Tables.OsmMarinePoint element, FeatureCollector features) { 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 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 void process(Tables.OsmWaterPolygon element, FeatureCollector features) { .setMinZoom(minzoom); } } + + private record NaturalEarthRegion( + Geometry geometry, + int scalerank + ) {} } diff --git a/src/test/java/org/openmaptiles/layers/BoundaryTest.java b/src/test/java/org/openmaptiles/layers/BoundaryTest.java index 931371b8..95e56d09 100644 --- a/src/test/java/org/openmaptiles/layers/BoundaryTest.java +++ b/src/test/java/org/openmaptiles/layers/BoundaryTest.java @@ -714,4 +714,26 @@ void testOsmBoundariesOnly() { 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" + )))); + } } diff --git a/src/test/java/org/openmaptiles/layers/ParkTest.java b/src/test/java/org/openmaptiles/layers/ParkTest.java index 2383a136..a393b211 100644 --- a/src/test/java/org/openmaptiles/layers/ParkTest.java +++ b/src/test/java/org/openmaptiles/layers/ParkTest.java @@ -45,30 +45,6 @@ void testNationalPark() { )))); } - @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); diff --git a/src/test/java/org/openmaptiles/layers/PlaceTest.java b/src/test/java/org/openmaptiles/layers/PlaceTest.java index d12a6e46..02873f69 100644 --- a/src/test/java/org/openmaptiles/layers/PlaceTest.java +++ b/src/test/java/org/openmaptiles/layers/PlaceTest.java @@ -258,7 +258,7 @@ void testIslandPolygon() { "name", "Nantucket", "name_en", "Nantucket", "name:latin", "Nantucket", - "rank", 3, + "rank", 1, "_type", "point", "_minzoom", 8 @@ -287,6 +287,49 @@ void testIslandPolygon() { )))); } + @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[]{ diff --git a/src/test/java/org/openmaptiles/layers/TransportationTest.java b/src/test/java/org/openmaptiles/layers/TransportationTest.java index fe32a98f..2210aa65 100644 --- a/src/test/java/org/openmaptiles/layers/TransportationTest.java +++ b/src/test/java/org/openmaptiles/layers/TransportationTest.java @@ -3,6 +3,7 @@ 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 @@ void testInterstateMotorway() { "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", "", - "_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", ""), + entry("_minzoom", 6) )), features); assertFeatures(8, List.of(Map.of( @@ -304,17 +306,18 @@ void testInterstateMotorway() { "horse", "", "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", "", - "_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", ""), + entry("_minzoom", 6) )), features); } @@ -326,7 +329,7 @@ void testDuplicateRoute() { 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 @@ void testDuplicateRoute() { "ref", "104", "ref_length", 3, "network", "us-state", - "route_1", "US:OK=104", - "route_2", "", + "route_1_network", "US:OK", + "route_1_ref", "104", + "route_2_network", "", + "route_2_ref", "", "_minzoom", 8 )), features); } @@ -372,7 +377,7 @@ void testRouteWithoutNetworkType() { 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 @@ void testRouteWithoutNetworkType() { "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 @@ void testSegmentWithManyRoutes() { List 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 @@ void testSegmentWithManyRoutes() { "_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", "" + "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", "", + "route_9_ref", "" )), rendered); } @@ -519,10 +580,12 @@ void testPolishHighwayIssue165() { "_layer", "transportation_name", "class", "trunk", "name", "", - "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 @@ void testInterstateMotorwayWithoutWayInfo() { "ref_length", 2, "network", "us-interstate", "brunnel", "", - "route_1", "US:I=90", + "route_1_network", "US:I", + "route_1_ref", "90", "_minzoom", 6 )), features); } @@ -839,17 +903,19 @@ void testUSAndStateHighway() { "ramp", "", "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 @@ void testUSAndStateHighway() { ), 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 @@ void testIssue58() { "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); + } }