fix various issues
- pmtile coordinates - pixel calculation - swapped lat / long - allow tileSize to be configured - allow any zoom for coordinates
This commit is contained in:
parent
678d8833d1
commit
13c024f6f8
1 changed files with 55 additions and 34 deletions
|
@ -208,30 +208,29 @@ export const serve_data = {
|
||||||
return res.status(404).send(JSON.stringify(tileJSON));
|
return res.status(404).send(JSON.stringify(tileJSON));
|
||||||
}
|
}
|
||||||
|
|
||||||
const TILE_SIZE = 256;
|
const TILE_SIZE = tileJSON.tileSize || 512;
|
||||||
let tileCenter;
|
let bbox;
|
||||||
let xy;
|
let xy;
|
||||||
|
var zoom = z;
|
||||||
|
|
||||||
if (Number.isInteger(x) && Number.isInteger(y)) {
|
if (Number.isInteger(x) && Number.isInteger(y)) {
|
||||||
const intX = parseInt(req.params.x, 10);
|
const intX = parseInt(req.params.x, 10);
|
||||||
const intY = parseInt(req.params.y, 10);
|
const intY = parseInt(req.params.y, 10);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
z < tileJSON.minzoom ||
|
zoom < tileJSON.minzoom ||
|
||||||
z > tileJSON.maxzoom ||
|
zoom > tileJSON.maxzoom ||
|
||||||
intX < 0 ||
|
intX < 0 ||
|
||||||
intY < 0 ||
|
intY < 0 ||
|
||||||
intX >= Math.pow(2, z) ||
|
intX >= Math.pow(2, zoom) ||
|
||||||
intY >= Math.pow(2, z)
|
intY >= Math.pow(2, zoom)
|
||||||
) {
|
) {
|
||||||
return res.status(404).send('Out of bounds');
|
return res.status(404).send('Out of bounds');
|
||||||
}
|
}
|
||||||
xy = [intX, intY];
|
xy = [intX, intY];
|
||||||
tileCenter = new SphericalMercator().bbox(intX, intY, z);
|
bbox = new SphericalMercator().bbox(intX, intY, zoom);
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
z < tileJSON.minzoom ||
|
|
||||||
z > tileJSON.maxzoom ||
|
|
||||||
x < -180 ||
|
x < -180 ||
|
||||||
y < -90 ||
|
y < -90 ||
|
||||||
x > 180 ||
|
x > 180 ||
|
||||||
|
@ -240,19 +239,27 @@ export const serve_data = {
|
||||||
return res.status(404).send('Out of bounds');
|
return res.status(404).send('Out of bounds');
|
||||||
}
|
}
|
||||||
|
|
||||||
tileCenter = [y, x, y + 0.1, x + 0.1];
|
//no zoom limit with coordinates
|
||||||
const { minX, minY } = new SphericalMercator().xyz(tileCenter, z);
|
if (zoom < tileJSON.minzoom) {
|
||||||
xy = [minX, minY];
|
zoom = tileJSON.minzoom;
|
||||||
|
}
|
||||||
|
if (zoom > tileJSON.maxzoom) {
|
||||||
|
zoom = tileJSON.maxzoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
bbox = [x, y, x + 0.1, y + 0.1];
|
||||||
|
const { minX, minY } = new SphericalMercator().xyz(bbox, zoom);
|
||||||
|
xy = [minX, minY, zoom];
|
||||||
}
|
}
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
if (sourceType === 'pmtiles') {
|
if (sourceType === 'pmtiles') {
|
||||||
const tileinfo = await getPMtilesTile(source, z, x, y);
|
const tileinfo = await getPMtilesTile(source, zoom, xy[0], xy[1]);
|
||||||
if (!tileinfo?.data) return res.status(204).send();
|
if (!tileinfo?.data) return res.status(204).send();
|
||||||
data = tileinfo.data;
|
data = tileinfo.data;
|
||||||
} else {
|
} else {
|
||||||
data = await new Promise((resolve, reject) => {
|
data = await new Promise((resolve, reject) => {
|
||||||
source.getTile(z, xy[0], xy[1], (err, tileData) => {
|
source.getTile(zoom, xy[0], xy[1], (err, tileData) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return /does not exist/.test(err.message)
|
return /does not exist/.test(err.message)
|
||||||
? resolve(null)
|
? resolve(null)
|
||||||
|
@ -271,51 +278,63 @@ export const serve_data = {
|
||||||
const canvas = createCanvas(TILE_SIZE, TILE_SIZE);
|
const canvas = createCanvas(TILE_SIZE, TILE_SIZE);
|
||||||
const context = canvas.getContext('2d');
|
const context = canvas.getContext('2d');
|
||||||
context.drawImage(image, 0, 0);
|
context.drawImage(image, 0, 0);
|
||||||
const imgdata = context.getImageData(0, 0, TILE_SIZE, TILE_SIZE);
|
|
||||||
|
|
||||||
const arrayWidth = imgdata.width;
|
const long = bbox[0];
|
||||||
const arrayHeight = imgdata.height;
|
const lat = bbox[1];
|
||||||
const bytesPerPixel = 4;
|
|
||||||
|
|
||||||
const xPixel = Math.floor(xy[0]);
|
// calculate pixel coordinate of tile,
|
||||||
const yPixel = Math.floor(xy[1]);
|
// 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 (
|
if (
|
||||||
xPixel < 0 ||
|
xPixel < 0 ||
|
||||||
yPixel < 0 ||
|
yPixel < 0 ||
|
||||||
xPixel >= arrayWidth ||
|
xPixel >= TILE_SIZE ||
|
||||||
yPixel >= arrayHeight
|
yPixel >= TILE_SIZE
|
||||||
) {
|
) {
|
||||||
return reject('Out of bounds Pixel');
|
return reject('Pixel is out of bounds');
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = (yPixel * arrayWidth + xPixel) * bytesPerPixel;
|
const imgdata = context.getImageData(xPixel, yPixel, 1, 1);
|
||||||
|
const red = imgdata.data[0];
|
||||||
const red = imgdata.data[index];
|
const green = imgdata.data[1];
|
||||||
const green = imgdata.data[index + 1];
|
const blue = imgdata.data[2];
|
||||||
const blue = imgdata.data[index + 2];
|
|
||||||
|
|
||||||
let elevation;
|
let elevation;
|
||||||
if (encoding === 'mapbox') {
|
if (encoding === 'mapbox') {
|
||||||
elevation =
|
elevation =
|
||||||
-10000 + (red * 256 * 256 + green * 256 + blue) * 0.1;
|
-10000 + ((red * 256 * 256 + green * 256 + blue) * 0.1);
|
||||||
} else if (encoding === 'terrarium') {
|
} else if (encoding === 'terrarium') {
|
||||||
elevation = red * 256 + green + blue / 256 - 32768;
|
elevation = (red * 256 + green + blue / 256) - 32768
|
||||||
} else {
|
} else {
|
||||||
elevation = 'invalid encoding';
|
elevation = 'invalid encoding';
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(
|
resolve(
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
z,
|
z: zoom,
|
||||||
x: xy[0],
|
x: xy[0],
|
||||||
y: xy[1],
|
y: xy[1],
|
||||||
red,
|
red,
|
||||||
green,
|
green,
|
||||||
blue,
|
blue,
|
||||||
latitude: tileCenter[0],
|
latitude: lat,
|
||||||
longitude: tileCenter[1],
|
longitude: long,
|
||||||
elevation,
|
elevation
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -406,6 +425,7 @@ export const serve_data = {
|
||||||
const metadata = await getPMtilesInfo(source);
|
const metadata = await getPMtilesInfo(source);
|
||||||
|
|
||||||
tileJSON['encoding'] = params['encoding'];
|
tileJSON['encoding'] = params['encoding'];
|
||||||
|
tileJSON['tileSize'] = params['tileSize'];
|
||||||
tileJSON['name'] = id;
|
tileJSON['name'] = id;
|
||||||
tileJSON['format'] = 'pbf';
|
tileJSON['format'] = 'pbf';
|
||||||
Object.assign(tileJSON, metadata);
|
Object.assign(tileJSON, metadata);
|
||||||
|
@ -427,6 +447,7 @@ export const serve_data = {
|
||||||
const info = await mbw.getInfo();
|
const info = await mbw.getInfo();
|
||||||
source = mbw.getMbTiles();
|
source = mbw.getMbTiles();
|
||||||
tileJSON['encoding'] = params['encoding'];
|
tileJSON['encoding'] = params['encoding'];
|
||||||
|
tileJSON['tileSize'] = params['tileSize'];
|
||||||
tileJSON['name'] = id;
|
tileJSON['name'] = id;
|
||||||
tileJSON['format'] = 'pbf';
|
tileJSON['format'] = 'pbf';
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue