Derived Terrain Layer
The Mapbox Terrain-RGB layer stores elevation in its pixel values. This decodes it into average air pressure, rendered in grayscale over OpenStreetMap.
Using the Terrain-RGB layer requires a Mapbox access token, supplied through the MAPBOX_KEY environment variable.
|
Configuration
-
YAML
-
JSON
cache:
name: disk
path: ./terrain_cache
layers:
- id: osm
provider:
name: proxy
url: https://tile.openstreetmap.org/{z}/{x}/{y}.png
- id: air_pressure
provider:
name: transform
threads: 8 (1)
formula: | (2)
import "math"
func transform(r, g, b, a uint8) (uint8, uint8, uint8, uint8) {
elevation := -10000 + ((float64(r)*256*256 + float64(g)*256 + float64(b)) * 0.1)
pressure := 101325 * math.Pow(1-.0000225577*elevation, 5.25588)
c := uint8(pressure / 1000)
return c, c, c, 255
}
provider:
name: fallback
primary:
name: proxy
url: https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token={env.MAPBOX_KEY} (3)
secondary:
name: static
color: "0186a0" (4)
- id: air_pressure_over_osm
provider:
name: blend
mode: opacity (5)
opacity: 0.5
providers:
- name: ref (6)
layer: air_pressure
- name: ref
layer: osm
| 1 | A tile has 65,536 pixels. Splitting them across 8 goroutines makes each tile faster to produce at the cost of more CPU per request. |
| 2 | The function is called once per pixel. Darker pixels are lower pressure, meaning higher ground. See Transform. |
| 3 | {env.MAPBOX_KEY} keeps the token out of the configuration file. The pngraw format matters, as other formats can alter the pixel values and so the decoded elevation. |
| 4 | Mapbox returns an error for tiles entirely over the sea. This color decodes to an elevation of 0, so sea level pressure is shown instead of an error. |
| 5 | Mixes the two images half and half rather than drawing one over the other, since both layers are fully opaque. |
| 6 | Each referenced layer is cached on its own, so osm and air_pressure can also be requested directly without generating them again. |
{
"cache": {
"name": "disk",
"path": "./terrain_cache"
},
"layers": [
{
"id": "osm",
"provider": {
"name": "proxy",
"url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
}
},
{
"id": "air_pressure",
"provider": {
"name": "transform",
"threads": 8, (1)
"formula": "import \"math\"\nfunc transform(r, g, b, a uint8) (uint8, uint8, uint8, uint8) {\n elevation := -10000 + ((float64(r)*256*256 + float64(g)*256 + float64(b)) * 0.1)\n pressure := 101325 * math.Pow(1-.0000225577*elevation, 5.25588)\n c := uint8(pressure / 1000)\n return c, c, c, 255\n}\n", (2)
"provider": {
"name": "fallback",
"primary": {
"name": "proxy",
"url": "https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token={env.MAPBOX_KEY}" (3)
},
"secondary": {
"name": "static",
"color": "0186a0" (4)
}
}
}
},
{
"id": "air_pressure_over_osm",
"provider": {
"name": "blend",
"mode": "opacity", (5)
"opacity": 0.5,
"providers": [
{
"name": "ref", (6)
"layer": "air_pressure"
},
{
"name": "ref",
"layer": "osm"
}
]
}
}
]
}
| 1 | A tile has 65,536 pixels. Splitting them across 8 goroutines makes each tile faster to produce at the cost of more CPU per request. |
| 2 | The function is called once per pixel. Darker pixels are lower pressure, meaning higher ground. See Transform. |
| 3 | {env.MAPBOX_KEY} keeps the token out of the configuration file. The pngraw format matters, as other formats can alter the pixel values and so the decoded elevation. |
| 4 | Mapbox returns an error for tiles entirely over the sea. This color decodes to an elevation of 0, so sea level pressure is shown instead of an error. |
| 5 | Mixes the two images half and half rather than drawing one over the other, since both layers are fully opaque. |
| 6 | Each referenced layer is cached on its own, so osm and air_pressure can also be requested directly without generating them again. |
Try it
export MAPBOX_KEY=your-token
tilegroxy test -c terrain.yml
tilegroxy serve -c terrain.yml
The test command confirms all three layers generate before you start the server. Be mindful of the OpenStreetMap tile usage policy.