Skip to content

Commit

Permalink
fix various issues
Browse files Browse the repository at this point in the history
- pmtile coordinates
- pixel calculation
- swapped lat / long
- allow tileSize to be configured
- allow any zoom for coordinates
  • Loading branch information
Miko committed Jan 7, 2025
1 parent 678d883 commit 13c024f
Showing 1 changed file with 55 additions and 34 deletions.
89 changes: 55 additions & 34 deletions src/serve_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,30 +208,29 @@ export const serve_data = {
return res.status(404).send(JSON.stringify(tileJSON));
}

const TILE_SIZE = 256;
let tileCenter;
const TILE_SIZE = tileJSON.tileSize || 512;
let bbox;
let xy;
var zoom = z;

if (Number.isInteger(x) && Number.isInteger(y)) {
const intX = parseInt(req.params.x, 10);
const intY = parseInt(req.params.y, 10);

if (
z < tileJSON.minzoom ||
z > tileJSON.maxzoom ||
zoom < tileJSON.minzoom ||
zoom > tileJSON.maxzoom ||
intX < 0 ||
intY < 0 ||
intX >= Math.pow(2, z) ||
intY >= Math.pow(2, z)
intX >= Math.pow(2, zoom) ||
intY >= Math.pow(2, zoom)
) {
return res.status(404).send('Out of bounds');
}
xy = [intX, intY];
tileCenter = new SphericalMercator().bbox(intX, intY, z);
bbox = new SphericalMercator().bbox(intX, intY, zoom);
} else {
if (
z < tileJSON.minzoom ||
z > tileJSON.maxzoom ||
x < -180 ||
y < -90 ||
x > 180 ||
Expand All @@ -240,19 +239,27 @@ export const serve_data = {
return res.status(404).send('Out of bounds');
}

tileCenter = [y, x, y + 0.1, x + 0.1];
const { minX, minY } = new SphericalMercator().xyz(tileCenter, z);
xy = [minX, minY];
//no zoom limit with coordinates
if (zoom < tileJSON.minzoom) {
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;
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();
data = tileinfo.data;
} else {
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) {
return /does not exist/.test(err.message)
? resolve(null)
Expand All @@ -271,51 +278,63 @@ export const serve_data = {
const canvas = createCanvas(TILE_SIZE, TILE_SIZE);
const context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
const imgdata = context.getImageData(0, 0, TILE_SIZE, TILE_SIZE);

const arrayWidth = imgdata.width;
const arrayHeight = imgdata.height;
const bytesPerPixel = 4;
const long = bbox[0];
const lat = bbox[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 xPixel = Math.floor(xy[0]);
const yPixel = Math.floor(xy[1]);
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 >= arrayWidth ||
yPixel >= arrayHeight
xPixel >= TILE_SIZE ||
yPixel >= TILE_SIZE
) {
return reject('Out of bounds Pixel');
return reject('Pixel is out of bounds');
}

const index = (yPixel * arrayWidth + xPixel) * bytesPerPixel;

const red = imgdata.data[index];
const green = imgdata.data[index + 1];
const blue = imgdata.data[index + 2];
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;
-10000 + ((red * 256 * 256 + green * 256 + blue) * 0.1);
} else if (encoding === 'terrarium') {
elevation = red * 256 + green + blue / 256 - 32768;
elevation = (red * 256 + green + blue / 256) - 32768

Check notice

Code scanning / CodeQL

Semicolon insertion Note

Avoid automated semicolon insertion (95% of all statements in
the enclosing function
have an explicit semicolon).
} else {
elevation = 'invalid encoding';
}

resolve(
res.status(200).send({
z,
z: zoom,
x: xy[0],
y: xy[1],
red,
green,
blue,
latitude: tileCenter[0],
longitude: tileCenter[1],
elevation,
latitude: lat,
longitude: long,
elevation
}),
);
};
Expand Down Expand Up @@ -406,6 +425,7 @@ export const serve_data = {
const metadata = await getPMtilesInfo(source);

tileJSON['encoding'] = params['encoding'];
tileJSON['tileSize'] = params['tileSize'];
tileJSON['name'] = id;
tileJSON['format'] = 'pbf';
Object.assign(tileJSON, metadata);
Expand All @@ -427,6 +447,7 @@ export const serve_data = {
const info = await mbw.getInfo();
source = mbw.getMbTiles();
tileJSON['encoding'] = params['encoding'];
tileJSON['tileSize'] = params['tileSize'];
tileJSON['name'] = id;
tileJSON['format'] = 'pbf';

Expand Down

0 comments on commit 13c024f

Please sign in to comment.