-- Data processing based on openmaptiles.org schema -- https://openmaptiles.org/schema/ -- Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors. -- Used under CC-BY 4.0 -------- -- Alter these lines to control which languages are written for place/streetnames -- -- Preferred language can be (for example) "en" for English, "de" for German, or nil to use OSM's name tag: preferred_language = en -- This is written into the following vector tile attribute (usually "name:latin"): preferred_language_attribute = "name:latin" -- If OSM's name tag differs, then write it into this attribute (usually "name_int"): default_language_attribute = "name_int" -- Also write these languages if they differ - for example, { "de", "fr" } additional_languages = {} -------- -- Enter/exit Tilemaker function init_function() end function exit_function() end -- Implement Sets in tables function Set(list) local set = {} for _, l in ipairs(list) do set[l] = true end return set end -- Meters per pixel if tile is 256x256 ZRES5 = 4891.97 ZRES6 = 2445.98 ZRES7 = 1222.99 ZRES8 = 611.5 ZRES9 = 305.7 ZRES10 = 152.9 ZRES11 = 76.4 ZRES12 = 38.2 ZRES13 = 19.1 -- The height of one floor, in meters BUILDING_FLOOR_HEIGHT = 3.66 -- Process node/way tags aerodromeValues = Set { "international", "public", "regional", "military", "private" } -- Process node tags node_keys = { "addr:housenumber", "aerialway", "aeroway", "amenity", "barrier", "highway", "historic", "leisure", "natural", "office", "place", "railway", "shop", "sport", "tourism", "waterway" } function node_function(node) -- Write 'aerodrome_label' local aeroway = node:Find("aeroway") if aeroway == "aerodrome" then node:Layer("aerodrome_label", false) SetNameAttributes(node) node:Attribute("iata", node:Find("iata")) SetEleAttributes(node) node:Attribute("icao", node:Find("icao")) local aerodrome_value = node:Find("aerodrome") local class if aerodromeValues[aerodrome_value] then class = aerodrome_value else class = "other" end node:Attribute("class", class) end -- Write 'housenumber' local housenumber = node:Find("addr:housenumber") if housenumber ~= "" then node:Layer("housenumber", false) node:Attribute("housenumber", housenumber) end -- Write 'place' -- note that OpenMapTiles has a rank for countries (1-3), states (1-6) and cities (1-10+); -- we could potentially approximate it for cities based on the population tag local place = node:Find("place") if place ~= "" then local rank = nil local mz = 13 local pop = tonumber(node:Find("population")) or 0 if place == "continent" then mz = 0 elseif place == "country" then if pop > 50000000 then rank = 1; mz = 1 elseif pop > 20000000 then rank = 2; mz = 2 else rank = 3; mz = 3 end elseif place == "state" then mz = 4 elseif place == "city" then mz = 5 elseif place == "town" and pop > 8000 then mz = 7 elseif place == "town" then mz = 8 elseif place == "village" and pop > 2000 then mz = 9 elseif place == "village" then mz = 10 elseif place == "suburb" then mz = 11 elseif place == "hamlet" then mz = 12 elseif place == "neighbourhood" then mz = 13 elseif place == "locality" then mz = 13 end node:Layer("place", false) node:Attribute("class", place) node:MinZoom(mz) if rank then node:AttributeNumeric("rank", rank) end if place == "country" then node:Attribute("iso_a2", node:Find("ISO3166-1:alpha2")) end SetNameAttributes(node) return end -- Write 'poi' local rank, class, subclass = GetPOIRank(node) if rank then WritePOI(node, class, subclass, rank) end -- Write 'mountain_peak' and 'water_name' local natural = node:Find("natural") if natural == "peak" or natural == "volcano" then node:Layer("mountain_peak", false) SetEleAttributes(node) node:AttributeNumeric("rank", 1) node:Attribute("class", natural) SetNameAttributes(node) return end if natural == "bay" then node:Layer("water_name", false) SetNameAttributes(node) return end end -- Process way tags majorRoadValues = Set { "motorway", "trunk", "primary" } mainRoadValues = Set { "secondary", "motorway_link", "trunk_link", "primary_link", "secondary_link" } midRoadValues = Set { "tertiary", "tertiary_link" } minorRoadValues = Set { "unclassified", "residential", "road", "living_street" } trackValues = Set { "track" } pathValues = Set { "footway", "cycleway", "bridleway", "path", "steps", "pedestrian" } linkValues = Set { "motorway_link", "trunk_link", "primary_link", "secondary_link", "tertiary_link" } constructionValues = Set { "primary", "secondary", "tertiary", "motorway", "service", "trunk", "track" } pavedValues = Set { "paved", "asphalt", "cobblestone", "concrete", "concrete:lanes", "concrete:plates", "metal", "paving_stones", "sett", "unhewn_cobblestone", "wood" } unpavedValues = Set { "unpaved", "compacted", "dirt", "earth", "fine_gravel", "grass", "grass_paver", "gravel", "gravel_turf", "ground", "ice", "mud", "pebblestone", "salt", "sand", "snow", "woodchips" } aerowayBuildings = Set { "terminal", "gate", "tower" } landuseKeys = Set { "school", "university", "kindergarten", "college", "library", "hospital", "railway", "cemetery", "military", "residential", "commercial", "industrial", "retail", "stadium", "pitch", "playground", "theme_park", "bus_station", "zoo" } landcoverKeys = { wood = "wood", forest = "wood", wetland = "wetland", beach = "sand", sand = "sand", farmland = "farmland", farm = "farmland", orchard = "farmland", vineyard = "farmland", plant_nursery = "farmland", glacier = "ice", ice_shelf = "ice", grassland = "grass", grass = "grass", meadow = "grass", allotments = "grass", park = "grass", village_green = "grass", recreation_ground = "grass", garden = "grass", golf_course = "grass" } -- POI key/value pairs: based on https://github.com/openmaptiles/openmaptiles/blob/master/layers/poi/mapping.yaml poiTags = { aerialway = Set { "station" }, amenity = Set { "arts_centre", "bank", "bar", "bbq", "bicycle_parking", "bicycle_rental", "biergarten", "bus_station", "cafe", "cinema", "clinic", "college", "community_centre", "courthouse", "dentist", "doctors", "embassy", "fast_food", "ferry_terminal", "fire_station", "food_court", "fuel", "grave_yard", "hospital", "ice_cream", "kindergarten", "library", "marketplace", "motorcycle_parking", "nightclub", "nursing_home", "parking", "pharmacy", "place_of_worship", "police", "post_box", "post_office", "prison", "pub", "public_building", "recycling", "restaurant", "school", "shelter", "swimming_pool", "taxi", "telephone", "theatre", "toilets", "townhall", "university", "veterinary", "waste_basket" }, barrier = Set { "bollard", "border_control", "cycle_barrier", "gate", "lift_gate", "sally_port", "stile", "toll_booth" }, building = Set { "dormitory" }, highway = Set { "bus_stop" }, historic = Set { "monument", "castle", "ruins" }, landuse = Set { "basin", "brownfield", "cemetery", "reservoir", "winter_sports" }, leisure = Set { "dog_park", "escape_game", "garden", "golf_course", "ice_rink", "hackerspace", "marina", "miniature_golf", "park", "pitch", "playground", "sports_centre", "stadium", "swimming_area", "swimming_pool", "water_park" }, railway = Set { "halt", "station", "subway_entrance", "train_station_entrance", "tram_stop" }, shop = Set { "accessories", "alcohol", "antiques", "art", "bag", "bakery", "beauty", "bed", "beverages", "bicycle", "books", "boutique", "butcher", "camera", "car", "car_repair", "carpet", "charity", "chemist", "chocolate", "clothes", "coffee", "computer", "confectionery", "convenience", "copyshop", "cosmetics", "deli", "delicatessen", "department_store", "doityourself", "dry_cleaning", "electronics", "erotic", "fabric", "florist", "frozen_food", "furniture", "garden_centre", "general", "gift", "greengrocer", "hairdresser", "hardware", "hearing_aids", "hifi", "ice_cream", "interior_decoration", "jewelry", "kiosk", "lamps", "laundry", "mall", "massage", "mobile_phone", "motorcycle", "music", "musical_instrument", "newsagent", "optician", "outdoor", "perfume", "perfumery", "pet", "photo", "second_hand", "shoes", "sports", "stationery", "supermarket", "tailor", "tattoo", "ticket", "tobacco", "toys", "travel_agency", "video", "video_games", "watches", "weapons", "wholesale", "wine" }, sport = Set { "american_football", "archery", "athletics", "australian_football", "badminton", "baseball", "basketball", "beachvolleyball", "billiards", "bmx", "boules", "bowls", "boxing", "canadian_football", "canoe", "chess", "climbing", "climbing_adventure", "cricket", "cricket_nets", "croquet", "curling", "cycling", "disc_golf", "diving", "dog_racing", "equestrian", "fatsal", "field_hockey", "free_flying", "gaelic_games", "golf", "gymnastics", "handball", "hockey", "horse_racing", "horseshoes", "ice_hockey", "ice_stock", "judo", "karting", "korfball", "long_jump", "model_aerodrome", "motocross", "motor", "multi", "netball", "orienteering", "paddle_tennis", "paintball", "paragliding", "pelota", "racquet", "rc_car", "rowing", "rugby", "rugby_league", "rugby_union", "running", "sailing", "scuba_diving", "shooting", "shooting_range", "skateboard", "skating", "skiing", "soccer", "surfing", "swimming", "table_soccer", "table_tennis", "team_handball", "tennis", "toboggan", "volleyball", "water_ski", "yoga" }, tourism = Set { "alpine_hut", "aquarium", "artwork", "attraction", "bed_and_breakfast", "camp_site", "caravan_site", "chalet", "gallery", "guest_house", "hostel", "hotel", "information", "motel", "museum", "picnic_site", "theme_park", "viewpoint", "zoo" }, waterway = Set { "dock" } } -- POI "class" values: based on https://github.com/openmaptiles/openmaptiles/blob/master/layers/poi/poi.yaml poiClasses = { townhall = "town_hall", public_building = "town_hall", courthouse = "town_hall", community_centre = "town_hall", golf = "golf", golf_course = "golf", miniature_golf = "golf", fast_food = "fast_food", food_court = "fast_food", park = "park", bbq = "park", bus_stop = "bus", bus_station = "bus", subway_entrance = "entrance", train_station_entrance = "entrance", camp_site = "campsite", caravan_site = "campsite", laundry = "laundry", dry_cleaning = "laundry", supermarket = "grocery", deli = "grocery", delicatessen = "grocery", department_store = "grocery", greengrocer = "grocery", marketplace = "grocery", books = "library", library = "library", university = "college", college = "college", hotel = "lodging", motel = "lodging", bed_and_breakfast = "lodging", guest_house = "lodging", hostel = "lodging", chalet = "lodging", alpine_hut = "lodging", dormitory = "lodging", chocolate = "ice_cream", confectionery = "ice_cream", post_box = "post", post_office = "post", cafe = "cafe", school = "school", kindergarten = "school", alcohol = "alcohol_shop", beverages = "alcohol_shop", wine = "alcohol_shop", bar = "bar", nightclub = "bar", marina = "harbor", dock = "harbor", car = "car", car_repair = "car", taxi = "car", hospital = "hospital", nursing_home = "hospital", clinic = "hospital", grave_yard = "cemetery", cemetery = "cemetery", attraction = "attraction", viewpoint = "attraction", biergarten = "beer", pub = "beer", music = "music", musical_instrument = "music", american_football = "stadium", stadium = "stadium", soccer = "stadium", art = "art_gallery", artwork = "art_gallery", gallery = "art_gallery", arts_centre = "art_gallery", bag = "clothing_store", clothes = "clothing_store", swimming_area = "swimming", swimming = "swimming", castle = "castle", ruins = "castle" } poiClassRanks = { hospital = 1, railway = 2, bus = 3, attraction = 4, harbor = 5, college = 6, school = 7, stadium = 8, zoo = 9, town_hall = 10, campsite = 11, cemetery = 12, park = 13, library = 14, police = 15, post = 16, golf = 17, shop = 18, grocery = 19, fast_food = 20, clothing_store = 21, bar = 22 } waterClasses = Set { "river", "riverbank", "stream", "canal", "drain", "ditch", "dock" } waterwayClasses = Set { "stream", "river", "canal", "drain", "ditch" } -- Scan relations for use in ways function relation_scan_function(relation) if relation:Find("type") == "boundary" and relation:Find("boundary") == "administrative" then relation:Accept() end end -- Process way tags function way_function(way) local route = way:Find("route") local highway = way:Find("highway") local waterway = way:Find("waterway") local water = way:Find("water") local building = way:Find("building") local natural = way:Find("natural") local historic = way:Find("historic") local landuse = way:Find("landuse") local leisure = way:Find("leisure") local amenity = way:Find("amenity") local aeroway = way:Find("aeroway") local railway = way:Find("railway") local service = way:Find("service") local sport = way:Find("sport") local shop = way:Find("shop") local tourism = way:Find("tourism") local man_made = way:Find("man_made") local boundary = way:Find("boundary") local isClosed = way:IsClosed() local housenumber = way:Find("addr:housenumber") local write_name = false local construction = way:Find("construction") -- Miscellaneous preprocessing if way:Find("disused") == "yes" then return end if boundary ~= "" and way:Find("protection_title") == "National Forest" and way:Find("operator") == "United States Forest Service" then return end if highway == "proposed" then return end if aerowayBuildings[aeroway] then building = "yes"; aeroway = "" end if landuse == "field" then landuse = "farmland" end if landuse == "meadow" and way:Find("meadow") == "agricultural" then landuse = "farmland" end -- Boundaries within relations local admin_level = 11 local isBoundary = false while true do local rel = way:NextRelation() if not rel then break end isBoundary = true admin_level = math.min(admin_level, tonumber(way:FindInRelation("admin_level")) or 11) end -- Boundaries in ways if boundary == "administrative" then admin_level = math.min(admin_level, tonumber(way:Find("admin_level")) or 11) isBoundary = true end -- Administrative boundaries -- https://openmaptiles.org/schema/#boundary if isBoundary and not (way:Find("maritime") == "yes") then local mz = 0 if admin_level >= 3 and admin_level < 5 then mz = 4 elseif admin_level >= 5 and admin_level < 7 then mz = 8 elseif admin_level == 7 then mz = 10 elseif admin_level >= 8 then mz = 12 end way:Layer("boundary", false) way:AttributeNumeric("admin_level", admin_level) way:MinZoom(mz) -- disputed status (0 or 1). some styles need to have the 0 to show it. local disputed = way:Find("disputed") if disputed == "yes" then way:AttributeNumeric("disputed", 1) else way:AttributeNumeric("disputed", 0) end end -- Roads ('transportation' and 'transportation_name', plus 'transportation_name_detail') if highway ~= "" then local access = way:Find("access") local surface = way:Find("surface") local h = highway local minzoom = 99 local layer = "transportation" if majorRoadValues[highway] then minzoom = 4 end if highway == "trunk" then minzoom = 5 elseif highway == "primary" then minzoom = 7 end if mainRoadValues[highway] then minzoom = 9 end if midRoadValues[highway] then minzoom = 11 end if minorRoadValues[highway] then h = "minor"; minzoom = 12 end if trackValues[highway] then h = "track"; minzoom = 14 end if pathValues[highway] then h = "path"; minzoom = 14 end if h == "service" then minzoom = 12 end -- Links (ramp) local ramp = false if linkValues[highway] then splitHighway = split(highway, "_") highway = splitHighway[1]; h = highway ramp = true minzoom = 11 end -- Construction if highway == "construction" then if constructionValues[construction] then h = construction .. "_construction" if construction ~= "service" and construction ~= "track" then minzoom = 11 else minzoom = 12 end else h = "minor_construction" minzoom = 14 end end -- Write to layer if minzoom <= 14 then way:Layer(layer, false) way:MinZoom(minzoom) SetZOrder(way) way:Attribute("class", h) SetBrunnelAttributes(way) if ramp then way:AttributeNumeric("ramp", 1) end if access == "private" or access == "no" then way:Attribute("access", "no") end if pavedValues[surface] then way:Attribute("surface", "paved") end if unpavedValues[surface] then way:Attribute("surface", "unpaved") end -- Service if highway == "service" and service ~= "" then way:Attribute("service", service) end local oneway = way:Find("oneway") if oneway == "yes" or oneway == "1" then way:AttributeNumeric("oneway", 1) end if oneway == "-1" then -- **** TODO end -- Write names if minzoom < 8 then minzoom = 8 end if highway == "motorway" or highway == "trunk" then way:Layer("transportation_name", false) way:MinZoom(minzoom) elseif h == "minor" or h == "track" or h == "path" or h == "service" then way:Layer("transportation_name_detail", false) way:MinZoom(minzoom) else way:Layer("transportation_name_mid", false) way:MinZoom(minzoom) end SetNameAttributes(way) way:Attribute("class", h) way:Attribute("network", "road") -- **** could also be us-interstate, us-highway, us-state if h ~= highway then way:Attribute("subclass", highway) end local ref = way:Find("ref") if ref ~= "" then way:Attribute("ref", ref) way:AttributeNumeric("ref_length", ref:len()) end end end -- Railways ('transportation' and 'transportation_name', plus 'transportation_name_detail') if railway ~= "" then way:Layer("transportation", false) way:Attribute("class", railway) SetZOrder(way) SetBrunnelAttributes(way) if service ~= "" then way:Attribute("service", service) way:MinZoom(12) else way:MinZoom(9) end way:Layer("transportation_name", false) SetNameAttributes(way) way:MinZoom(14) way:Attribute("class", "rail") end -- Pier if man_made == "pier" then way:Layer("transportation", isClosed) SetZOrder(way) way:Attribute("class", "pier") SetMinZoomByArea(way) end -- 'Ferry' if route == "ferry" then way:Layer("transportation", false) way:Attribute("class", "ferry") SetZOrder(way) way:MinZoom(9) SetBrunnelAttributes(way) way:Layer("transportation_name", false) SetNameAttributes(way) way:MinZoom(12) way:Attribute("class", "ferry") end -- 'Aeroway' if aeroway ~= "" then way:Layer("aeroway", isClosed) way:Attribute("class", aeroway) way:Attribute("ref", way:Find("ref")) write_name = true end -- 'aerodrome_label' if aeroway == "aerodrome" then way:LayerAsCentroid("aerodrome_label") SetNameAttributes(way) way:Attribute("iata", way:Find("iata")) SetEleAttributes(way) way:Attribute("icao", way:Find("icao")) local aerodrome = way:Find(aeroway) local class if aerodromeValues[aerodrome] then class = aerodrome else class = "other" end way:Attribute("class", class) end -- Set 'waterway' and associated if waterwayClasses[waterway] and not isClosed then if waterway == "river" and way:Holds("name") then way:Layer("waterway", false) else way:Layer("waterway_detail", false) end if way:Find("intermittent") == "yes" then way:AttributeNumeric("intermittent", 1) else way:AttributeNumeric( "intermittent", 0) end way:Attribute("class", waterway) SetNameAttributes(way) SetBrunnelAttributes(way) elseif waterway == "boatyard" then way:Layer("landuse", isClosed); way:Attribute("class", "industrial"); way:MinZoom(12) elseif waterway == "dam" then way:Layer("building", isClosed) elseif waterway == "fuel" then way:Layer("landuse", isClosed); way:Attribute("class", "industrial"); way:MinZoom(14) end -- Set names on rivers if waterwayClasses[waterway] and not isClosed then if waterway == "river" and way:Holds("name") then way:Layer("water_name", false) else way:Layer("water_name_detail", false) way:MinZoom(14) end way:Attribute("class", waterway) SetNameAttributes(way) end -- Set 'building' and associated if building ~= "" then way:Layer("building", true) SetBuildingHeightAttributes(way) SetMinZoomByArea(way) end -- Set 'housenumber' if housenumber ~= "" then way:LayerAsCentroid("housenumber", false) way:Attribute("housenumber", housenumber) end -- Set 'water' if natural == "water" or natural == "bay" or leisure == "swimming_pool" or landuse == "reservoir" or landuse == "basin" or waterClasses[waterway] then if way:Find("covered") == "yes" or not isClosed then return end local class = "lake"; if natural == "bay" then class = "ocean" elseif waterway ~= "" then class = "river" end if class == "lake" and way:Find("wikidata") == "Q192770" then return end if class == "ocean" and isClosed and (way:AreaIntersecting("ocean") / way:Area() > 0.98) then return end way:Layer("water", true) SetMinZoomByArea(way) way:Attribute("class", class) if way:Find("intermittent") == "yes" then way:Attribute("intermittent", 1) end -- we only want to show the names of actual lakes not every man-made basin that probably doesn't even have a name other than "basin" -- examples for which we don't want to show a name: -- https://www.openstreetmap.org/way/25958687 -- https://www.openstreetmap.org/way/27201902 -- https://www.openstreetmap.org/way/25309134 -- https://www.openstreetmap.org/way/24579306 if way:Holds("name") and natural == "water" and water ~= "basin" and water ~= "wastewater" then way:LayerAsCentroid("water_name_detail") SetNameAttributes(way) SetMinZoomByArea(way) way:Attribute("class", class) end return -- in case we get any landuse processing end -- Set 'landcover' (from landuse, natural, leisure) local l = landuse if l == "" then l = natural end if l == "" then l = leisure end if landcoverKeys[l] then way:Layer("landcover", true) SetMinZoomByArea(way) way:Attribute("class", landcoverKeys[l]) if l == "wetland" then way:Attribute("subclass", way:Find("wetland")) else way:Attribute("subclass", l) end write_name = true -- Set 'landuse' else if l == "" then l = amenity end if l == "" then l = tourism end if landuseKeys[l] then way:Layer("landuse", true) way:Attribute("class", l) if l == "residential" then if way:Area() < ZRES8 ^ 2 then way:MinZoom(8) else SetMinZoomByArea(way) end else way:MinZoom(11) end write_name = true end end -- Parks -- **** name? if boundary == "national_park" then way:Layer("park", true); way:Attribute("class", boundary); SetNameAttributes(way) elseif leisure == "nature_reserve" then way:Layer("park", true); way:Attribute("class", leisure); SetNameAttributes(way) end -- POIs ('poi' and 'poi_detail') local rank, class, subclass = GetPOIRank(way) if rank then WritePOI(way, class, subclass, rank); return end -- Catch-all if (building ~= "" or write_name) and way:Holds("name") then way:LayerAsCentroid("poi_detail") SetNameAttributes(way) if write_name then rank = 6 else rank = 25 end way:AttributeNumeric("rank", rank) end end -- Remap coastlines function attribute_function(attr, layer) if attr["featurecla"] == "Glaciated areas" then return { subclass = "glacier" } elseif attr["featurecla"] == "Antarctic Ice Shelf" then return { subclass = "ice_shelf" } elseif attr["featurecla"] == "Urban area" then return { class = "residential" } else return { class = "ocean" } end end -- ========================================================== -- Common functions -- Write a way centroid to POI layer function WritePOI(obj, class, subclass, rank) local layer = "poi" if rank > 4 then layer = "poi_detail" end obj:LayerAsCentroid(layer) SetNameAttributes(obj) obj:AttributeNumeric("rank", rank) obj:Attribute("class", class) obj:Attribute("subclass", subclass) end -- Set name attributes on any object function SetNameAttributes(obj) local name = obj:Find("name"), iname local main_written = name -- if we have a preferred language, then write that (if available), and additionally write the base name tag if preferred_language and obj:Holds("name:" .. preferred_language) then iname = obj:Find("name:" .. preferred_language) obj:Attribute(preferred_language_attribute, iname) if iname ~= name and default_language_attribute then obj:Attribute(default_language_attribute, name) else main_written = iname end else obj:Attribute(preferred_language_attribute, name) end -- then set any additional languages for i, lang in ipairs(additional_languages) do iname = obj:Find("name:" .. lang) if iname == "" then iname = name end if iname ~= main_written then obj:Attribute("name:" .. lang, iname) end end end -- Set ele and ele_ft on any object function SetEleAttributes(obj) local ele = obj:Find("ele") if ele ~= "" then local meter = math.floor(tonumber(ele) or 0) local feet = math.floor(meter * 3.2808399) obj:AttributeNumeric("ele", meter) obj:AttributeNumeric("ele_ft", feet) end end function SetBrunnelAttributes(obj) if obj:Find("bridge") == "yes" then obj:Attribute("brunnel", "bridge") elseif obj:Find("tunnel") == "yes" then obj:Attribute("brunnel", "tunnel") elseif obj:Find("ford") == "yes" then obj:Attribute("brunnel", "ford") end end -- Set minimum zoom level by area function SetMinZoomByArea(way) local area = way:Area() if area > ZRES5 ^ 2 then way:MinZoom(6) elseif area > ZRES6 ^ 2 then way:MinZoom(7) elseif area > ZRES7 ^ 2 then way:MinZoom(8) elseif area > ZRES8 ^ 2 then way:MinZoom(9) elseif area > ZRES9 ^ 2 then way:MinZoom(10) elseif area > ZRES10 ^ 2 then way:MinZoom(11) elseif area > ZRES11 ^ 2 then way:MinZoom(12) elseif area > ZRES12 ^ 2 then way:MinZoom(13) else way:MinZoom(14) end end -- Calculate POIs (typically rank 1-4 go to 'poi' z12-14, rank 5+ to 'poi_detail' z14) -- returns rank, class, subclass function GetPOIRank(obj) local k, list, v, class, rank -- Can we find the tag? for k, list in pairs(poiTags) do if list[obj:Find(k)] then v = obj:Find(k) -- k/v are the OSM tag pair class = poiClasses[v] or k rank = poiClassRanks[class] or 25 return rank, class, v end end -- Catch-all for shops local shop = obj:Find("shop") if shop ~= "" then return poiClassRanks['shop'], "shop", shop end -- Nothing found return nil, nil, nil end function SetBuildingHeightAttributes(way) local height = tonumber(way:Find("height"), 10) local minHeight = tonumber(way:Find("min_height"), 10) local levels = tonumber(way:Find("building:levels"), 10) local minLevel = tonumber(way:Find("building:min_level"), 10) local renderHeight = BUILDING_FLOOR_HEIGHT if height or levels then renderHeight = height or (levels * BUILDING_FLOOR_HEIGHT) end local renderMinHeight = 0 if minHeight or minLevel then renderMinHeight = minHeight or (minLevel * BUILDING_FLOOR_HEIGHT) end -- Fix upside-down buildings if renderHeight < renderMinHeight then renderHeight = renderHeight + renderMinHeight end way:AttributeNumeric("render_height", renderHeight) way:AttributeNumeric("render_min_height", renderMinHeight) end -- Implement z_order as calculated by Imposm -- See https://imposm.org/docs/imposm3/latest/mapping.html#wayzorder for details. function SetZOrder(way) local highway = way:Find("highway") local layer = tonumber(way:Find("layer")) local bridge = way:Find("bridge") local tunnel = way:Find("tunnel") local zOrder = 0 if bridge ~= "" and bridge ~= "no" then zOrder = zOrder + 10 elseif tunnel ~= "" and tunnel ~= "no" then zOrder = zOrder - 10 end if not (layer == nil) then if layer > 7 then layer = 7 elseif layer < -7 then layer = -7 end zOrder = zOrder + layer * 10 end local hwClass = 0 -- See https://github.com/omniscale/imposm3/blob/53bb80726ca9456e4a0857b38803f9ccfe8e33fd/mapping/columns.go#L251 if highway == "motorway" then hwClass = 9 elseif highway == "trunk" then hwClass = 8 elseif highway == "primary" then hwClass = 6 elseif highway == "secondary" then hwClass = 5 elseif highway == "tertiary" then hwClass = 4 else hwClass = 3 end zOrder = zOrder + hwClass way:ZOrder(zOrder) end -- ========================================================== -- Lua utility functions function split(inputstr, sep) -- https://stackoverflow.com/a/7615129/4288232 if sep == nil then sep = "%s" end local t = {}; i = 1 for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do t[i] = str i = i + 1 end return t end -- vim: tabstop=2 shiftwidth=2 noexpandtab