DTM Geländemodell
Das DTM ist ein Höhenkachelsatz für ganz Österreich: Geländehöhe ohne Gebäude und Bewuchs, kodiert als Farbe (Terrain-RGB) und
damit direkt für raster-dem, Schummerung und 3D-Gelände in MapLibre, Mapbox GL und kompatiblen Clients verwendbar.
1. Kennwerte
Abschnitt betitelt „1. Kennwerte“| Tileset-ID | relief-terrainrgb |
|---|---|
| Datei | relief-terrainrgb-20250915-ed2e4341.pmtiles |
| Stichtag | 15.09.2025 |
| Größe | 39,1 GB (39 067 398 974 Bytes) |
| SHA-256 | ed2e4341e6e10d0fa62880e2f1c91d9828fc3de84b7ddd541417110221c8121a |
| Format | webp, Kodierung mapbox, 512 px |
| Zoomstufen | z5–z16 |
| Gebiet (WGS84) | 9,5306 / 46,3697 / 17,1661 / 49,0235 (W/S/O/N) |
| Kacheln | 664 979 adressiert, 663 931 verschiedene Inhalte |
| Lizenz | CC BY 4.0 |
Die Tabelle wird beim Build aus viewer/tiles-manifest.json und dem PMTiles-Header der Datei erzeugt (Stand der Erzeugung: 2026-11-07).
2. Live-Karte
Abschnitt betitelt „2. Live-Karte“Der Klick liest die Kachel der aktuellen Zoomstufe (maximal z16) per Range-Request, dekodiert das Pixel am Klickpunkt mit der
Formel aus Abschnitt 4 und zeigt Höhe und RGB-Wert. Bei eingeschaltetem 3D steht zusätzlich der Wert von queryTerrainElevation dabei.
3. Einbinden
Abschnitt betitelt „3. Einbinden“import * as maplibregl from "maplibre-gl";import { Protocol } from "pmtiles";
maplibregl.addProtocol("pmtiles", new Protocol().tile);const map = new maplibregl.Map({container: "map",center: [12.694, 47.074], zoom: 11, pitch: 60,style: { version: 8, sources: { dem: { type: "raster-dem", url: "pmtiles://https://tiles.mapx.at/relief-terrainrgb-20250915-ed2e4341.pmtiles", tileSize: 512, encoding: "mapbox", maxzoom: 16 } }, terrain: { source: "dem", exaggeration: 1.2 }, layers: [{ id: "hill", type: "hillshade", source: "dem" }]}});map.on("click", (e) => console.log(map.queryTerrainElevation(e.lngLat)));Leaflet kennt kein raster-dem. Über den XYZ-Endpunkt (API) kommen die Rohkacheln; sie zeigen die kodierte Farbe, nicht
eine Karte. Für Höhenwerte die Pixel selbst dekodieren (Abschnitt 4).
L.tileLayer("https://tiles.mapx.at/v1/dtm/{z}/{x}/{y}.webp", {tileSize: 512, zoomOffset: -1, minZoom: 5, maxNativeZoom: 16, maxZoom: 20,crossOrigin: true,attribution: 'BEV – ALS-DTM 1 m, CC BY 4.0'}).addTo(map);import TileLayer from "ol/layer/WebGLTile.js";import XYZ from "ol/source/XYZ.js";
// Bänder sind in OpenLayers auf 0..1 normiert, daher * 255const hoehe = ["+", -10000, ["*", 0.1, ["+",["*", 65536 * 255, ["band", 1]], ["*", 256 * 255, ["band", 2]], ["*", 255, ["band", 3]]]]];
new TileLayer({source: new XYZ({ url: "https://tiles.mapx.at/v1/dtm/{z}/{x}/{y}.webp", tileSize: 512, minZoom: 5, maxZoom: 16, crossOrigin: "anonymous", attributions: "BEV – ALS-DTM 1 m, CC BY 4.0"}),style: { color: ["interpolate", ["linear"], hoehe, 200, [60, 120, 60], 1500, [200, 190, 120], 3000, [255, 255, 255]] }});- Browser, Rechtsklick auf XYZ Tiles, Neue Verbindung.
- URL
https://tiles.mapx.at/v1/dtm/{z}/{x}/{y}.webp, Min. Zoom 5, Max. Zoom 16, Kachelauflösung 512. - Der Layer zeigt die Rohkacheln (kodierte Farbe). Höhen ergeben sich aus der Formel in Abschnitt 4 (
(R*65536 + G*256 + B)*0,1 - 10000), etwa im Raster-Rechner auf den drei Bändern.
Die Anleitung ist nicht in QGIS nachvollzogen; sie folgt dem Ablauf für XYZ-Kacheln.
# pip install pmtiles pillow numpy requestsimport io, requests, numpy as npfrom PIL import Imagefrom pmtiles.reader import Reader
URL = "https://tiles.mapx.at/relief-terrainrgb-20250915-ed2e4341.pmtiles"
def get_bytes(offset, length): r = requests.get(URL, headers={"Range": f"bytes={offset}-{offset + length - 1}"}, timeout=30) r.raise_for_status() return r.content
reader = Reader(get_bytes)tile = reader.get(12, 2192, 1439) # z, x, y (Großglockner)rgb = np.asarray(Image.open(io.BytesIO(tile)).convert("RGB")).astype(np.uint32)hoehe = -10000 + (rgb[..., 0] * 65536 + rgb[..., 1] * 256 + rgb[..., 2]) * 0.1print(hoehe.shape, hoehe.min(), hoehe.max())# PMTiles-Header (127 Bytes) per Range-Requestcurl -s -r 0-126 https://tiles.mapx.at/relief-terrainrgb-20250915-ed2e4341.pmtiles | xxd | head -4
# eine Kachel über den XYZ-Endpunktcurl -s -o kachel.webp https://tiles.mapx.at/v1/dtm/12/2192/1439.webp
# ganze Datei (39.1 GB), fortsetzbarcurl -C - -O https://tiles.mapx.at/relief-terrainrgb-20250915-ed2e4341.pmtilesconst hoehe = (r, g, b) => -10000 + (r * 65536 + g * 256 + b) * 0.1;fn hoehe(r: u8, g: u8, b: u8) -> f64 { -10000.0 + (u32::from(r) * 65536 + u32::from(g) * 256 + u32::from(b)) as f64 * 0.1}// Gegenrichtung (wie die Pipeline in crates/mapx-rgb): auf 0,1 m runden, auf 0..=16777215 begrenzenfn rgb(h: f64) -> [u8; 3] { let q = ((h + 10000.0) * 10.0).round_ties_even().clamp(0.0, 16777215.0) as u32; [(q >> 16) as u8, (q >> 8) as u8, q as u8]}4. Kodierung
Abschnitt betitelt „4. Kodierung“höhe_m = -10000 + (R · 65536 + G · 256 + B) · 0,1- Wertebereich theoretisch −10000 m bis +1 667 721,5 m in Schritten von 0,1 m; in Österreich liegen die Werte zwischen rund 115 m (Neusiedler See) und rund 3 798 m (Großglockner).
- Gerundet wird beim Schreiben auf 0,1 m (Rundung zur geraden Zahl bei genau .5, siehe Rust-Code oben), Werte außerhalb des Bereichs werden begrenzt.
- WebP verlustfrei: verlustbehaftete Kompression würde die kodierten Höhen direkt verfälschen. Keine Alpha-Information nutzen, RGB-Bänder unverändert lesen (kein Farbmanagement, kein Premultiplied Alpha).
- 512 × 512 Pixel, ohne Rand (kein 1-px-Skirt). In MapLibre
tileSize: 512undencoding: "mapbox"angeben.
Ausführlich: Terrain-RGB.
5. Auflösung je Zoom
Abschnitt betitelt „5. Auflösung je Zoom“Bei 47,5° N, 512-px-Kacheln, Web-Mercator:
| Zoom | m pro Pixel | Kantenlänge Kachel (km) | Anmerkung |
|---|---|---|---|
| z5 | 1 652 | 846 | |
| z6 | 826 | 423 | |
| z7 | 413 | 212 | |
| z8 | 207 | 106 | |
| z9 | 103 | 53 | |
| z10 | 52 | 26 | |
| z11 | 26 | 13 | |
| z12 | 13 | 6,61 | |
| z13 | 6,46 | 3,30 | |
| z14 | 3,23 | 1,65 | |
| z15 | 1,61 | 0,83 | |
| z16 | 0,81 | 0,41 | höchste gespeicherte Stufe (≈ 1-m-Ursprung) |
| z17 | 0,40 | 0,21 | Overzoom (Client) |
Die Daten stammen aus einem 1-m-Raster. z16 (≈ 0,8 m pro Pixel) ist die erste Stufe, die die Quelle nicht vergröbert; z15 würde etwa 60 % der Pixel verwerfen.
Über z16 gibt es keine Kacheln: MapLibre zoomt ab z17 die z16-Kachel auf (maxzoom: 16 setzen), es entsteht keine zusätzliche Information.
Die Stufen z15 bis z5 sind 2×2-Mittel im Höhenraum (Dekodieren, mitteln, neu kodieren), kein Bild-Resize.
6. Datenherkunft
Abschnitt betitelt „6. Datenherkunft“- Quelle: BEV (Bundesamt für Eich- und Vermessungswesen), ALS-DTM 1 m, Geonetwork-Serie
5ce253fc-b7c5-4362-97af-6556c18a45d9, Airborne Laserscanning, nur Gelände. - 55 Quellkacheln à 50 × 50 km als COG in EPSG:3035 (ETRS89-LAEA), Stichtag 15.09.2025.
- Reprojektion nach EPSG:3857 bilinear (nicht Lanczos: Überschwinger an steilen Klippen würden die Höhen selbst verfälschen).
- Erzeugt mit der Rust-Pipeline
crates/mapx-rgb(ohne GDAL).
7. Genauigkeit und Grenzen
Abschnitt betitelt „7. Genauigkeit und Grenzen“Belegt (Quelle: relief/README.md, relief/test/hoehen_check.py, Vault mapx/Terrain-RGB-Rust-Test):
- Quantisierung 0,1 m.
- z16 gegen das bilinear interpolierte Quell-DTM an drei Prüfpunkten: Jauerling 960,10 m (Δ −0,03 m), Donau bei Melk 203,90 m (Δ −0,04 m), Stift Melk 248,30 m (Δ +0,02 m).
- Rust-Render gegen die Quelle auf zehn Kacheln (Alpen und Melk): höchstens 0,05 m Abweichung, das ist der Rundungsfehler.
- Kantenzusammenführung: Pixel am Rand der Quellkacheln werden aus den gültigen Nachbarn renormiert.
Grenzen:
- DTM zeigt das Gelände ohne Gebäude, Bäume und Brücken. Für die Oberfläche gibt es das DSM.
- Kein Messwert außerhalb der Daten. Das Gebiet des Kachelsatzes ist das Rechteck 9,53–17,17° O, 46,37–49,02° N. Pixel ohne Quelldaten (außerhalb Österreichs, Lücken) sind eine glatte Fortsetzung des Geländes, keine Messung. Im Test (Durchstich Melk gegen das DTM außerhalb des Gebiets) lag der Fehler dieser Fortsetzung im Mittel bei 11 m, am Übergang springt die Höhe im Median um bis zu 17 m (steiles Gelände, Maximum 46 m).
- Abweichung der Übersichtsstufen z15 bis z5 gegenüber der Quelle: nicht gemessen (nur Mittelbildung im Höhenraum, verglichen wurde Python gegen Rust, nicht gegen die Quelle).
- Gesamtgenauigkeit über ganz Österreich (RMSE gegen unabhängige Referenzpunkte): nicht gemessen. Die Lagegenauigkeit und vertikale Genauigkeit des BEV-Modells selbst gibt der Datenanbieter an, hier nicht wiederholt.
- Der Anteil von z15 und z16 an der Dateigröße ist nicht gemessen.
8. Varianten und Verwandte
Abschnitt betitelt „8. Varianten und Verwandte“| Produkt | Inhalt | Datei | Größe |
|---|---|---|---|
| DTM (diese Seite) | Gelände | relief-terrainrgb-20250915-ed2e4341.pmtiles |
39.1 GB |
| DSM | Oberfläche (inkl. Gebäude, Bewuchs), gleiche Kodierung, BEV ALS-DOM 1 m | relief-dsm-terrainrgb-20250915-d19cb434.pmtiles |
82.1 GB |
| Höhenlinien | Vektor, z10–z16 | siehe Manifest |
Ein nDSM (DSM minus DTM, Bewuchs- und Gebäudehöhe) ist angedacht, aber nicht verfügbar.
9. Versionen und Changelog
Abschnitt betitelt „9. Versionen und Changelog“Jede Datei trägt Stichtag und Hash im Namen und ändert sich nie; ein neuer Stand ist eine neue Datei.
| Stichtag | Datei | SHA-256 |
|---|---|---|
| 15.09.2025 | relief-terrainrgb-20250915-ed2e4341.pmtiles |
ed2e4341e6e10d0fa62880e2f1c91d9828fc3de84b7ddd541417110221c8121a |
Prüfen: curl -s {url} | sha256sum (lädt die ganze Datei). Alle Änderungen: Changelog.
10. Attribution
Abschnitt betitelt „10. Attribution“Pflicht nach CC BY 4.0. Text:
Relief: BEV – ALS-DTM 1 m (Stichtag 15.09.2025), CC BY 4.0HTML (wie in den PMTiles-Metadaten, MapLibre übernimmt es automatisch aus dem Tileset):
Relief: <a href="https://data.bev.gv.at/geonetwork/srv/ger/catalog.search#/metadata/5ce253fc-b7c5-4362-97af-6556c18a45d9">BEV – ALS-DTM 1 m</a> (Stichtag 15.09.2025), CC BY 4.0Mehr: Lizenz.
11. FAQ
Abschnitt betitelt „11. FAQ“Warum WebP verlustfrei? Weil jede Veränderung der Farbe eine andere Höhe bedeutet. Verlustfrei ist die einzige Wahl, die die 0,1-m-Kodierung erhält.
Warum kein Nodata? Ein Nodata-Wert (zum Beispiel Höhe 0) würde in Hillshade und 3D als Loch oder Graben erscheinen. Fehlende Pixel werden deshalb vor dem Kodieren aus dem Füllraster (flächentreues Mittel, Push-Pull-Fortsetzung) glatt ergänzt. Kacheln ganz ohne Quelldaten gibt es nicht (Lücke im PMTiles). Wo ein Wert vorliegt, ist er daher nicht automatisch ein Messwert, siehe Abschnitt 7.
Unterschied zu Mapbox und MapTiler? Gleiche Kodierung wie mapbox-terrain-dem-v1 (Mapbox-Formel, 512 px, aber ohne 1-px-Rand). Mapbox liefert Daten bis z14 (PNG, nur über SDKs, Abrechnung je Request), MapTiler nach unserem Kenntnisstand bis etwa z12 (nicht nachgeprüft). mapx geht bis z16, ist nur auf Österreich begrenzt, verlustfrei, schlüsselfrei und als ganze Datei herunterladbar.
Warum sehe ich Nähte in der Schummerung? Kacheln mit 1-px-Rand (514 px) erzeugen mit tileSize: 512 Nähte. Diese Kacheln sind randlos 512 × 512, tileSize: 512 ist richtig.