schema_name: Shortbread
schema_description: A basic, lean, general-purpose vector tile schema for OpenStreetMap data. See https://shortbread.geofabrik.de/
attribution: <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>
examples: shortbread.spec.yml
args:
  area:
    description: Geofabrik area to download
    default: massachusetts
  osm_url:
    description: OSM URL to download
    default: '${ args.area == "planet" ? "aws:latest" : ("geofabrik:" + args.area) }'
sources:
  ocean:
    type: shapefile
    url: https://osmdata.openstreetmap.de/download/water-polygons-split-3857.zip
  admin_points:
    type: shapefile
    url: https://shortbread.geofabrik.de/shapefiles/admin-points-4326.zip
  osm:
    type: osm
    url: '${ args.osm_url }'
definitions:
  # TODO let attribute definitions set multiple keys so you can just use `- *names`
  attributes:
  - &name
    key: name
  - &name_en
    key: name_en
    tag_value: name:en
  - &name_de
    key: name_de
    tag_value: name:de

layers:

#  Water

- id: ocean
  features:
  - source: ocean
    geometry: polygon

- id: water_polygons
  features:
  - source: osm
    geometry: polygon
    min_zoom:
      default_value: 4
      overrides: &water_zoom_overrides
        10:
          waterway: [ dock, canal ]
    include_when: &water_filter
      natural:
      - glacier
      - water
      waterway:
      - riverbank
      - dock
      - canal
      landuse:
      - reservoir
      - basin
    attributes:
    - key: kind
      type: match_value

- id: water_polygons_labels
  features:
  - source: osm
    geometry: polygon_centroid
    min_zoom:
      default_value: 14
      overrides: *water_zoom_overrides
    include_when: *water_filter
    exclude_when:
      name: ''
    attributes:
    - key: kind
      type: match_value
    - *name
    - *name_en
    - *name_de

- id: water_lines
  features:
  - source: osm
    geometry: line
    min_zoom:
      default_value: 9
      overrides:
        14:
          waterway: [ stream, ditch ]
    # TODO rivers and canals min length=0.25px
    include_when:
      waterway:
      - canal
      - river
      - stream
      - ditch
    attributes:
    - key: kind
      type: match_value

- id: water_line_labels
  features:
  - source: osm
    geometry: line
    min_zoom:
      default_value: 12
      overrides:
        14:
          waterway: [ stream, ditch ]
    # TODO rivers and canals min length=0.25px
    include_when:
      waterway:
      - canal
      - river
      - stream
      - ditch
    exclude_when:
      name: ''
    attributes:
    - key: kind
      type: match_value
    - *name
    - *name_en
    - *name_de

##  Countries, States, Cities
- id: boundaries
  features:
  - source: osm
    geometry: line
    # TODO get min admin level from relations
    min_size: 0
    min_zoom:
      default_value: 7
      overrides:
        0:
          admin_level: 2
    include_when:
      __all__:
      - boundary: administrative
      - admin_level: [ 2, 4 ]
    attributes:
    - key: maritime
      type: boolean
    - key: admin_level
      type: integer

- id: boundary_labels
  features:
  - source: admin_points
    geometry: point
    min_zoom:
      default_value: 5
      overrides:
        2: '${ feature.tags.has("ADMIN_LEVEL", "2") && double(feature.tags.WAY_AREA) >= 2e8 }'
        3: '${ double(feature.tags.WAY_AREA) >= 7e7 }'
        4: '${ double(feature.tags.WAY_AREA) >= 1e7 }'
    # TODO sort by WAY_AREA descending
    attributes:
    - key: way_area
      tag_value: WAY_AREA
      type: double
    - key: admin_level
      tag_value: ADMIN_LEVEL
      type: integer
    - key: name
      tag_value: NAME
    - key: name_en
      tag_value: NAME_EN
    - key: name_de
      tag_value: NAME_DE

- id: place_labels
  features:
  - source: osm
    geometry: point
    include_when:
      place:
      - city
      - town
      - village
      - hamlet
      - suburb
      - neighbourhood
      - isolated_dwelling
      - farm
      - island
      - locality
    exclude_when:
      name: ''
    min_zoom:
      default_value: 10
      overrides:
        4:
          __all__:
            place: [ city, town, village, hamlet ]
            capital: [ yes, '4' ]
        6:
          __all__:
            place: city
            __not__:
              capital: [ yes, '4' ]
        7:
          __all__:
            place: town
            __not__:
              capital: [ yes, '4' ]
    # TODO z-order
    attributes:
    - key: kind
      value:
        default_value: '${ match_value }'
        overrides:
          capital:
            __all__:
              place: [ city, town, village, hamlet ]
              capital: yes
          state_capital:
            __all__:
              place: [ city, town, village, hamlet ]
              capital: '4'
    - *name
    - *name_en
    - *name_de
    - key: population
      type: integer
      value:
        match:
        - value: '${ feature.tags.get("population") }'
          if: { population: __any__ }
        - value: 100000
          if: { place: city }
        - value: 5000
          if: { place: town }
        - value: 1000
          if: { place: suburb }
        - value: 100
          if: { place: [ village, neighborhood ] }
        - value: 50
          if: { place: hamlet }
        - value: 5
          if: { place: [ isolated_dwelling, farm ] }
        - else: 0

#  Land Use, Land Cover, Buildings
- id: land
  features:
  - source: osm
    geometry: polygon
    include_when:
      amenity:
      - grave_yard
      landuse:
      - allotments
      - brownfield
      - cemetery
      - commercial
      - farmland
      - farmyard
      - forest
      - grass
      - greenfield
      - greenhouse_horticulture
      - industrial
      - landfill
      - meadow
      - orchard
      - plant_nursery
      - quarry
      - railway
      - recreation_ground
      - residential
      - retail
      - village_green
      - vineyard
      leisure:
      - garden
      - golf_course
      - miniature_golf
      - park
      - playground
      natural:
      - bare_rock
      - beach
      - grassland
      - heath
      - sand
      - scree
      - scrub
      - shingle
      - wood
      wetland:
      - bog
      - marsh
      - string_bog
      - swamp
      - wet_meadow
    min_zoom:
      default_value: 11
      overrides:
        7:
          natural: wood
          landuse: forest
        10:
          landuse:
          - brownfield
          - commercial
          - farmland
          - farmyard
          - greenfield
          - industrial
          - landfill
          - railway
          - residential
          - retail
          natural:
          - beach
          - sand
        13:
          amenity: grave_yard
          natural: wood
          landuse: cemetery
    attributes:
    - key: kind
      value: '${match_value == "forest" ? "wood": match_value}'

- id: sites
  features:
  - source: osm
    geometry: polygon
    min_zoom: 14
    include_when:
      military: danger_area
      leisure: sports_center
      landuse: construction
      amenity:
      - university
      - hospital
      - prison
      - parking
      - bicycle_parking
    attributes:
    - key: kind
      type: match_value

- id: buildings
  features:
  - source: osm
    geometry: polygon
    min_zoom: 14
    include_when:
      building: __any__
    exclude_when:
      building: no

- id: addresses
  features:
  - source: osm
    geometry: polygon_centroid_if_convex
    min_zoom: 14
    include_when: &address_filter
      addr:housenumber: __any__
      addr:housename: __any__
    attributes: &address_attributes
    - key: name
      tag_value: addr:housename
    - key: number
      tag_value: addr:housenumber
  - source: osm
    geometry: point
    min_zoom: 14
    include_when: *address_filter
    attributes: *address_attributes

##  Streets and Transport
- id: streets
  features:
  - source: osm
    geometry: line
    min_size: 0
    min_zoom:
      default_value: 13
      overrides:
        5:
          highway: motorway%
        6:
          highway: trunk%
        8:
          highway: primary%
          __all__:
            railway: [ rail, narrow_gauge ]
            service: __any__
        9:
          highway: secondary%
        10:
          __all__:
            railway: [ rail, narrow_gauge ]
            service: ''
          railway:
          - funicular
          - light_rail
          - monorail
          - subway
          - tram
          highway: tertiary
        11:
          aeroway: runway
        12:
          highway: [ residential, unclassified ]
    #  TODO   min_tile_cover_size: 0
    # TODO z-order
    include_when:
      highway:
      - motorway
      - motorway_link
      - trunk
      - trunk_link
      - primary
      - primary_link
      - secondary
      - secondary_link
      - tertiary
      - tertiary_link
      - unclassified
      - residential
      - living_street
      - service
      - pedestrian
      - track
      - footway
      - steps
      - path
      - cycleway
      aeroway: # TODO update shortbread spec
      - runway
      - taxiway
      railway:
      - rail
      - narrow_gauge
      - tram
      - light_rail
      - funicular
      - subway
      - monorail
    attributes:
    - key: kind
      value: '${ match_value.replace("_link", "") }'
    - key: link
      min_zoom: 11
      value: true
      include_when:
        highway: '%_link'
      else: false
    - key: rail
      min_zoom: 11
      value: true
      include_when:
        railway: __any__
      else: false
    - &tunnel_attr
      key: tunnel
      min_zoom: 11
      value: true
      include_when:
        tunnel: [ yes, building_passage ]
        covered: yes
      else: false
    - &bridge_attr
      key: bridge
      min_zoom: 11
      value: true
      include_when:
        bridge: yes
      else: false
    - key: tracktype
      min_zoom: 11
    - key: surface # TODO canonicalize?
      min_zoom: 11
    - key: service
      min_zoom: 11
    - key: bicycle
      min_zoom: 14
    - key: horse
      min_zoom: 14

- id: street_labels
  features:
  - source: osm
    geometry: line
    min_zoom:
      default_value: 14
      overrides:
        10:
          highway: motorway
        12:
          highway: [ trunk, primary ]
        13:
          highway:
          - motorway_link
          - trunk_link
          - primary_link
          - secondary
          - secondary_link
          - tertiary
    include_when:
      highway:
      - motorway
      - motorway_link
      - trunk
      - trunk_link
      - primary
      - primary_link
      - secondary
      - secondary_link
      - tertiary
      - tertiary_link
      - unclassified
      - residential
      - living_street
      - service
      - pedestrian
      - track
      - footway
      - steps
      - path
      - cycleway
    exclude_when:
      __all__:
        name: ''
        ref: ''
    attributes:
    - key: kind
      value: '${ match_value.replace("_link", "") }'
    - *name
    - *name_en
    - *name_de
    # TODO use ref var to avoid duplicating logic
    - key: ref
      exclude_when: &missing_ref
        ref: ''
      value: '${ feature.tags["ref"].replace(";", "\n") }'
    - key: ref_cols
      value: '${ max(feature.tags["ref"].split(";").map(r, size(r))) }'
      exclude_when: *missing_ref
    - key: ref_rows
      value: '${ size(feature.tags["ref"].split(";")) }'
      exclude_when: *missing_ref

- id: street_polygons
  features:
  - source: osm
    geometry: polygon
    min_zoom: 14
    include_when:
      __all__:
      - highway: [ pedestrian, service ]
      - area: yes
    attributes:
    - key: kind
      type: match_value
    - *bridge_attr
    - *tunnel_attr
    - key: surface
    - key: rail
      value: false # TODO omit?

- id: street_polygons_labels
  features:
  - source: osm
    geometry: polygon_point_on_surface
    min_zoom: 14
    include_when:
      __all__:
        highway: [ pedestrian, service ]
        area: yes
        name: __any__
    attributes:
    - key: kind
      type: match_value
    - *name
    - *name_en
    - *name_de

- id: street_labels_points # TODO update documentation (streetS_labels_points)
  features:
  - source: osm
    geometry: point
    min_zoom: 12
    include_when:
      highway: motorway_junction
    attributes:
    - key: kind
      type: match_value
    - key: ref
    - *name
    - *name_en
    - *name_de

- id: aerialways
  features:
  - source: osm
    geometry: line
    min_zoom: 12
    include_when:
      aerialway: __any__
    attributes:
    - key: kind
      type: match_value

- id: public_transport
  features:
  - source: osm
    geometry: point
    min_zoom: &public_transport_zoom
      default_value: 14
      overrides:
        11:
          aeroway: aerodrome
        13:
          railway: [ station, halt ]
          aerialway: station
    include_when: &public_transport_filter
      railway: [ station, halt, tram_stop ]
      aeroway: aerodrome
      aerialway: station
    attributes: &public_transport_attrs
    - key: kind
      type: match_value
    - *name
    - *name_en
    - *name_de
    - key: iata
  - source: osm
    geometry: polygon_point_on_surface
    min_zoom: *public_transport_zoom
    include_when: *public_transport_filter
    attributes: *public_transport_attrs
