fix broken light (invalid use of heavy dependencies)
- move elevation calculation to serve_rendered and stub in serve_light due to use of canvas and sharp - elevation api is not available for light
This commit is contained in:
parent
b0a2cefb0e
commit
f55a4791c2
5 changed files with 95 additions and 79 deletions
|
@ -8,19 +8,22 @@ import express from 'express';
|
|||
import Pbf from 'pbf';
|
||||
import { VectorTile } from '@mapbox/vector-tile';
|
||||
import SphericalMercator from '@mapbox/sphericalmercator';
|
||||
import { Image, createCanvas } from 'canvas';
|
||||
import sharp from 'sharp';
|
||||
|
||||
import {
|
||||
fixTileJSONCenter,
|
||||
getTileUrls,
|
||||
isValidHttpUrl,
|
||||
fetchTileData,
|
||||
isLight,
|
||||
} from './utils.js';
|
||||
import { getPMtilesInfo, openPMtiles } from './pmtiles_adapter.js';
|
||||
import { gunzipP, gzipP } from './promises.js';
|
||||
import { openMbTilesWrapper } from './mbtiles_wrapper.js';
|
||||
|
||||
const serve_rendered = (
|
||||
await import(`${!isLight() ? `./serve_rendered.js` : `./serve_light.js`}`)
|
||||
).serve_rendered;
|
||||
|
||||
export const serve_data = {
|
||||
/**
|
||||
* Initializes the serve_data module.
|
||||
|
@ -246,79 +249,9 @@ export const serve_data = {
|
|||
if (fetchTile == null) return res.status(204).send();
|
||||
|
||||
let data = fetchTile.data;
|
||||
const image = new Image();
|
||||
await new Promise(async (resolve, reject) => {
|
||||
image.onload = async () => {
|
||||
const canvas = createCanvas(TILE_SIZE, TILE_SIZE);
|
||||
const context = canvas.getContext('2d');
|
||||
context.drawImage(image, 0, 0);
|
||||
const long = bbox[0];
|
||||
const lat = bbox[1];
|
||||
var param = { long: bbox[0], lat: bbox[1], encoding, format, tile_size: TILE_SIZE, z: zoom, x: xy[0], y: xy[1] };
|
||||
|
||||
// calculate pixel coordinate of tile,
|
||||
// see https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
|
||||
let siny = Math.sin((lat * Math.PI) / 180);
|
||||
// Truncating to 0.9999 effectively limits latitude to 89.189. This is
|
||||
// about a third of a tile past the edge of the world tile.
|
||||
siny = Math.min(Math.max(siny, -0.9999), 0.9999);
|
||||
const xWorld = TILE_SIZE * (0.5 + long / 360);
|
||||
const yWorld =
|
||||
TILE_SIZE *
|
||||
(0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI));
|
||||
|
||||
const scale = 1 << zoom;
|
||||
|
||||
const xTile = Math.floor((xWorld * scale) / TILE_SIZE);
|
||||
const yTile = Math.floor((yWorld * scale) / TILE_SIZE);
|
||||
|
||||
const xPixel = Math.floor(xWorld * scale) - xTile * TILE_SIZE;
|
||||
const yPixel = Math.floor(yWorld * scale) - yTile * TILE_SIZE;
|
||||
if (
|
||||
xPixel < 0 ||
|
||||
yPixel < 0 ||
|
||||
xPixel >= TILE_SIZE ||
|
||||
yPixel >= TILE_SIZE
|
||||
) {
|
||||
return reject('Out of bounds Pixel');
|
||||
}
|
||||
const imgdata = context.getImageData(xPixel, yPixel, 1, 1);
|
||||
const red = imgdata.data[0];
|
||||
const green = imgdata.data[1];
|
||||
const blue = imgdata.data[2];
|
||||
let elevation;
|
||||
if (encoding === 'mapbox') {
|
||||
elevation = -10000 + (red * 256 * 256 + green * 256 + blue) * 0.1;
|
||||
} else if (encoding === 'terrarium') {
|
||||
elevation = red * 256 + green + blue / 256 - 32768;
|
||||
} else {
|
||||
elevation = 'invalid encoding';
|
||||
}
|
||||
resolve(
|
||||
res.status(200).send({
|
||||
z: zoom,
|
||||
x: xy[0],
|
||||
y: xy[1],
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
latitude: lat,
|
||||
longitude: long,
|
||||
elevation,
|
||||
}),
|
||||
);
|
||||
};
|
||||
image.onerror = (err) => reject(err);
|
||||
if (format === 'webp') {
|
||||
try {
|
||||
const img = await sharp(data).toFormat('png').toBuffer();
|
||||
image.src = img;
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
image.src = data;
|
||||
}
|
||||
});
|
||||
res.status(200).send(await serve_rendered.getTerrainElevation(data, param));
|
||||
} catch (err) {
|
||||
return res
|
||||
.status(500)
|
||||
|
|
|
@ -6,4 +6,5 @@ export const serve_rendered = {
|
|||
init: (options, repo, programOpts) => {},
|
||||
add: (options, repo, params, id, programOpts, dataResolver) => {},
|
||||
remove: (repo, id) => {},
|
||||
getTerrainElevation: (data, param) => { param["elevation"] = "not supported in light"; return param; },
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// This happens on ARM:
|
||||
// > terminate called after throwing an instance of 'std::runtime_error'
|
||||
// > what(): Cannot read GLX extensions.
|
||||
import 'canvas';
|
||||
import { Image, createCanvas } from 'canvas';
|
||||
import '@maplibre/maplibre-gl-native';
|
||||
//
|
||||
// SECTION END
|
||||
|
@ -1458,4 +1458,76 @@ export const serve_rendered = {
|
|||
}
|
||||
delete repo[id];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the elevation of terrain tile data by rendering it to a canvas image
|
||||
* @param {object} data `The background color (or empty string for transparent).
|
||||
* @param {object} format A sharp format.
|
||||
* @returns {object}
|
||||
*/
|
||||
getTerrainElevation: async function(data, param) {
|
||||
return await new Promise(async (resolve, reject) => {
|
||||
const image = new Image();
|
||||
image.onload = async () => {
|
||||
const canvas = createCanvas(param["tile_size"], param["tile_size"]);
|
||||
const context = canvas.getContext('2d');
|
||||
context.drawImage(image, 0, 0);
|
||||
|
||||
// calculate pixel coordinate of tile,
|
||||
// see https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
|
||||
let siny = Math.sin((param["lat"] * Math.PI) / 180);
|
||||
// Truncating to 0.9999 effectively limits latitude to 89.189. This is
|
||||
// about a third of a tile past the edge of the world tile.
|
||||
siny = Math.min(Math.max(siny, -0.9999), 0.9999);
|
||||
const xWorld = param["tile_size"] * (0.5 + param["long"] / 360);
|
||||
const yWorld =
|
||||
param["tile_size"] *
|
||||
(0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI));
|
||||
|
||||
const scale = 1 << param["z"];
|
||||
|
||||
const xTile = Math.floor((xWorld * scale) / param["tile_size"]);
|
||||
const yTile = Math.floor((yWorld * scale) / param["tile_size"]);
|
||||
|
||||
const xPixel = Math.floor(xWorld * scale) - xTile * param["tile_size"];
|
||||
const yPixel = Math.floor(yWorld * scale) - yTile * param["tile_size"];
|
||||
if (
|
||||
xPixel < 0 ||
|
||||
yPixel < 0 ||
|
||||
xPixel >= param["tile_size"] ||
|
||||
yPixel >= param["tile_size"]
|
||||
) {
|
||||
return reject('Out of bounds Pixel');
|
||||
}
|
||||
const imgdata = context.getImageData(xPixel, yPixel, 1, 1);
|
||||
const red = imgdata.data[0];
|
||||
const green = imgdata.data[1];
|
||||
const blue = imgdata.data[2];
|
||||
let elevation;
|
||||
if (param["encoding"] === 'mapbox') {
|
||||
elevation = -10000 + (red * 256 * 256 + green * 256 + blue) * 0.1;
|
||||
} else if (param["encoding"] === 'terrarium') {
|
||||
elevation = red * 256 + green + blue / 256 - 32768;
|
||||
} else {
|
||||
elevation = 'invalid encoding';
|
||||
}
|
||||
param["elevation"] = elevation;
|
||||
param["red"] = red;
|
||||
param["green"] = green;
|
||||
param["blue"] = blue;
|
||||
resolve(param);
|
||||
};
|
||||
image.onerror = (err) => reject(err);
|
||||
if (param["format"] === 'webp') {
|
||||
try {
|
||||
const img = await sharp(data).toFormat('png').toBuffer();
|
||||
image.src = img;
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
image.src = data;
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -21,18 +21,17 @@ import {
|
|||
getTileUrls,
|
||||
getPublicUrl,
|
||||
isValidHttpUrl,
|
||||
isLight,
|
||||
} from './utils.js';
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const packageJson = JSON.parse(
|
||||
fs.readFileSync(__dirname + '/../package.json', 'utf8'),
|
||||
);
|
||||
|
||||
const isLight = packageJson.name.slice(-6) === '-light';
|
||||
const serve_rendered = (
|
||||
await import(`${!isLight ? `./serve_rendered.js` : `./serve_light.js`}`)
|
||||
await import(`${!isLight() ? `./serve_rendered.js` : `./serve_light.js`}`)
|
||||
).serve_rendered;
|
||||
|
||||
/**
|
||||
|
|
11
src/utils.js
11
src/utils.js
|
@ -12,6 +12,17 @@ export const allowedSpriteFormats = allowedOptions(['png', 'json']);
|
|||
|
||||
export const allowedTileSizes = allowedOptions(['256', '512']);
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
export function isLight() {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const packageJson = JSON.parse(
|
||||
fs.readFileSync(__dirname + '/../package.json', 'utf8'),
|
||||
);
|
||||
return packageJson.name.slice(-6) === '-light';
|
||||
}
|
||||
|
||||
/**
|
||||
* Restrict user input to an allowed set of options.
|
||||
* @param {string[]} opts - An array of allowed option strings.
|
||||
|
|
Loading…
Reference in a new issue