Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for Mapzen terrain #6024

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 100 additions & 4 deletions debug/hillshade.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,52 @@
</head>

<body>

<style>
#menu {
background: #fff;
position: absolute;
z-index: 1;
top: 10px;
right: 10px;
border-radius: 3px;
width: 120px;
border: 1px solid rgba(0,0,0,0.4);
font-family: 'Open Sans', sans-serif;
}

#menu a {
font-size: 13px;
color: #404040;
display: block;
margin: 0;
padding: 0;
padding: 10px;
text-decoration: none;
border-bottom: 1px solid rgba(0,0,0,0.25);
text-align: center;
}

#menu a:last-child {
border: none;
}

#menu a:hover {
background-color: #f8f8f8;
color: #404040;
}

#menu a.active {
background-color: #3887be;
color: #ffffff;
}

#menu a.active:hover {
background: #3074a4;
}
</style>

<nav id="menu"></nav>
<div id='map'></div>

<script src='/dist/mapbox-gl-dev.js'></script>
Expand All @@ -26,19 +72,69 @@
});

map.on('load', function () {
map.addSource('dem', {

map.addSource('mapbox-dem', {
"type": "raster-dem",
"url": "mapbox://mapbox.terrain-rgb"
"url": "mapbox://mapbox.terrain-rgb",
"tileSize": 256
});
map.addLayer({
"id": "hillshading",
"source": "dem",
"id": "Mapbox data",
"source": "mapbox-dem",
"type": "hillshade"
// insert below waterway-river-canal-shadow;
// where hillshading sits in the Mapbox Outdoors style
}, 'waterway-river-canal-shadow');

map.addSource('terrarium-dem', {
"type": "raster-dem",
"encoding": "terrarium",
"tiles": [
"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"
],
"tileSize": 256
});
map.addLayer({
"id": "Terrarium data",
"source": "terrarium-dem",
"type": "hillshade",
"layout": {
"visibility": "none"
}
// insert below waterway-river-canal-shadow;
// where hillshading sits in the Mapbox Outdoors style
}, 'waterway-river-canal-shadow');

});

var toggleableLayerIds = ['Mapbox data', 'Terrarium data'];

for (var i = 0; i < toggleableLayerIds.length; i++) {
var id = toggleableLayerIds[i];

var link = document.createElement('a');
link.href = '#';
link.className = (i === 0) ? 'active' : '';
link.textContent = id;

link.onclick = function (e) {
var clickedLayer = this.textContent;
e.preventDefault();
e.stopPropagation();

if (this.className === '') {
var activeLayer = document.getElementsByClassName('active')[0];
activeLayer.className = '';
map.setLayoutProperty(activeLayer.textContent, 'visibility', 'none');
this.className = 'active';
map.setLayoutProperty(clickedLayer, 'visibility', 'visible');
}
};

var layers = document.getElementById('menu');
layers.appendChild(link);
}

</script>
</body>
</html>
3 changes: 2 additions & 1 deletion flow-typed/style-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ declare type RasterDEMSourceSpecification = {
"minzoom"?: number,
"maxzoom"?: number,
"tileSize"?: number,
"attribution"?: string
"attribution"?: string,
"encoding"?: "terrarium" | "mapbox"
}

declare type GeojsonSourceSpecification = {|
Expand Down
32 changes: 22 additions & 10 deletions src/data/dem_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,14 @@ class DEMData {
this.loaded = !!data;
}

loadFromImage(data: RGBAImage) {
loadFromImage(data: RGBAImage, encoding?: "mapbox" | "terrarium") {
if (data.height !== data.width) throw new RangeError('DEM tiles must be square');

// Build level 0
const level = this.level = new Level(data.width, data.width / 2);
const pixels = data.data;

// unpack
for (let y = 0; y < level.dim; y++) {
for (let x = 0; x < level.dim; x++) {
const i = y * level.dim + x;
const j = i * 4;
// decoding per https://blog.mapbox.com/global-elevation-data-6689f1d0ba65
level.set(x, y, this.scale * ((pixels[j] * 256 * 256 + pixels[j + 1] * 256.0 + pixels[j + 2]) / 10.0 - 10000.0));
}
}
this.unpackData(level, pixels, encoding || "mapbox");

// in order to avoid flashing seams between tiles, here we are initially populating a 1px border of pixels around the image
// with the data of the nearest pixel from the image. this data is eventually replaced when the tile's neighboring
Expand All @@ -95,6 +87,26 @@ class DEMData {
this.loaded = true;
}

_unpackMapbox(r: number, g: number, b: number) {
return ((r * 256 * 256 + g * 256.0 + b) / 10.0 - 10000.0);
}

_unpackTerrarium(r: number, g: number, b: number) {
return ((r * 256 + g + b / 256) - 32768.0);
}

unpackData(level: Level, pixels: Uint8Array | Uint8ClampedArray, encoding: string) {
const unpackFunctions = {"mapbox": this._unpackMapbox, "terrarium": this._unpackTerrarium};
const unpack = unpackFunctions[encoding];
for (let y = 0; y < level.dim; y++) {
for (let x = 0; x < level.dim; x++) {
const i = y * level.dim + x;
const j = i * 4;
level.set(x, y, this.scale * unpack(pixels[j], pixels[j + 1], pixels[j + 2]));
}
}
}

getPixels() {
return new RGBAImage({width: this.level.dim + 2 * this.level.border, height: this.level.dim + 2 * this.level.border}, new Uint8Array(this.level.data.buffer));
}
Expand Down
7 changes: 6 additions & 1 deletion src/source/raster_dem_tile_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ import type {Callback} from '../types/callback';


class RasterDEMTileSource extends RasterTileSource implements Source {
encoding: "mapbox" | "terrarium";

constructor(id: string, options: RasterDEMSourceSpecification, dispatcher: Dispatcher, eventedParent: Evented) {
super(id, options, dispatcher, eventedParent);
this.type = 'raster-dem';
this.maxzoom = 22;
this._options = util.extend({}, options);
this.encoding = options.encoding || "mapbox";
}

serialize() {
Expand All @@ -29,6 +32,7 @@ class RasterDEMTileSource extends RasterTileSource implements Source {
tileSize: this.tileSize,
tiles: this.tiles,
bounds: this.bounds,
encoding: this.encoding
};
}

Expand All @@ -55,7 +59,8 @@ class RasterDEMTileSource extends RasterTileSource implements Source {
uid: tile.uid,
coord: tile.tileID,
source: this.id,
rawImageData: rawImageData
rawImageData: rawImageData,
encoding: this.encoding
};

if (!tile.workerID || tile.state === 'expired') {
Expand Down
5 changes: 3 additions & 2 deletions src/source/raster_dem_tile_worker_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ class RasterDEMTileWorkerSource {

loadTile(params: WorkerDEMTileParameters, callback: WorkerDEMTileCallback) {
const source = params.source,
uid = params.uid;
uid = params.uid,
encoding = params.encoding || "mapbox";

if (!this.loading[source])
this.loading[source] = {};

const dem = new DEMData(uid);
this.loading[source][uid] = dem;
dem.loadFromImage(params.rawImageData);
dem.loadFromImage(params.rawImageData, encoding);
delete this.loading[source][uid];

this.loaded[source] = this.loaded[source] || {};
Expand Down
3 changes: 2 additions & 1 deletion src/source/worker_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export type WorkerTileParameters = TileParameters & {

export type WorkerDEMTileParameters = TileParameters & {
coord: { z: number, x: number, y: number, w: number },
rawImageData: RGBAImage
rawImageData: RGBAImage,
encoding: "mapbox" | "terrarium"
};

export type WorkerTileResult = {
Expand Down
17 changes: 15 additions & 2 deletions src/style-spec/reference/v8.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@
"type": "enum",
"values": {
"raster-dem": {
"doc": "A raster DEM source using Mapbox Terrain RGB"
"doc": "A RGB-encoded raster DEM source"
}
},
"doc": "The type of the source."
Expand Down Expand Up @@ -272,6 +272,19 @@
"type": "string",
"doc": "Contains an attribution to be displayed when the map is shown to a user."
},
"encoding": {
"type": "enum",
"values": {
"terrarium": {
"doc": "Terrarium format PNG tiles. See https://aws.amazon.com/es/public-datasets/terrain/ for more info."
},
"mapbox": {
"doc": "Mapbox Terrain RGB tiles. See https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb for more info."
}
},
"default": "mapbox",
"doc": "The encoding used by this source. Mapbox Terrain RGB is used by default"
},
"*": {
"type": "*",
"doc": "Other keys to configure the data source."
Expand Down Expand Up @@ -502,7 +515,7 @@
}
},
"hillshade": {
"doc": "Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB tiles",
"doc": "Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles.",
"sdk-support": {
"basic functionality": {
"js": "0.43.0"
Expand Down