mirror of
https://github.com/protomaps/PMTiles.git
synced 2026-02-04 10:51:07 +00:00
Simplify and optimize Hilbert tile ID <-> XYZ conversion (#527)
* Optimize Hilbert tile ID <-> XYZ conversion * biome * tile_id: more improvements * tile_id(cpp): uint32
This commit is contained in:
105
js/src/index.ts
105
js/src/index.ts
@@ -55,44 +55,22 @@ export function readVarint(p: BufferPosition): number {
|
||||
return readVarintRemainder(val, p);
|
||||
}
|
||||
|
||||
function rotate(n: number, xy: number[], rx: number, ry: number): void {
|
||||
function rotate(
|
||||
n: number,
|
||||
x: number,
|
||||
y: number,
|
||||
rx: number,
|
||||
ry: number
|
||||
): [number, number] {
|
||||
if (ry === 0) {
|
||||
if (rx === 1) {
|
||||
xy[0] = n - 1 - xy[0];
|
||||
xy[1] = n - 1 - xy[1];
|
||||
if (rx !== 0) {
|
||||
return [n - 1 - y, n - 1 - x];
|
||||
}
|
||||
const t = xy[0];
|
||||
xy[0] = xy[1];
|
||||
xy[1] = t;
|
||||
return [y, x];
|
||||
}
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
function idOnLevel(z: number, pos: number): [number, number, number] {
|
||||
const n = 2 ** z;
|
||||
let rx = pos;
|
||||
let ry = pos;
|
||||
let t = pos;
|
||||
const xy = [0, 0];
|
||||
let s = 1;
|
||||
while (s < n) {
|
||||
rx = 1 & (t / 2);
|
||||
ry = 1 & (t ^ rx);
|
||||
rotate(s, xy, rx, ry);
|
||||
xy[0] += s * rx;
|
||||
xy[1] += s * ry;
|
||||
t = t / 4;
|
||||
s *= 2;
|
||||
}
|
||||
return [z, xy[0], xy[1]];
|
||||
}
|
||||
|
||||
const tzValues: number[] = [
|
||||
0, 1, 5, 21, 85, 341, 1365, 5461, 21845, 87381, 349525, 1398101, 5592405,
|
||||
22369621, 89478485, 357913941, 1431655765, 5726623061, 22906492245,
|
||||
91625968981, 366503875925, 1466015503701, 5864062014805, 23456248059221,
|
||||
93824992236885, 375299968947541, 1501199875790165,
|
||||
];
|
||||
|
||||
/**
|
||||
* Convert Z,X,Y to a Hilbert TileID.
|
||||
*/
|
||||
@@ -100,43 +78,52 @@ export function zxyToTileId(z: number, x: number, y: number): number {
|
||||
if (z > 26) {
|
||||
throw new Error("Tile zoom level exceeds max safe number limit (26)");
|
||||
}
|
||||
if (x > 2 ** z - 1 || y > 2 ** z - 1) {
|
||||
if (x >= 1 << z || y >= 1 << z) {
|
||||
throw new Error("tile x/y outside zoom level bounds");
|
||||
}
|
||||
|
||||
const acc = tzValues[z];
|
||||
const n = 2 ** z;
|
||||
let rx = 0;
|
||||
let ry = 0;
|
||||
let d = 0;
|
||||
const xy = [x, y];
|
||||
let s = n / 2;
|
||||
while (s > 0) {
|
||||
rx = (xy[0] & s) > 0 ? 1 : 0;
|
||||
ry = (xy[1] & s) > 0 ? 1 : 0;
|
||||
d += s * s * ((3 * rx) ^ ry);
|
||||
rotate(s, xy, rx, ry);
|
||||
s = s / 2;
|
||||
let acc = ((1 << z) * (1 << z) - 1) / 3;
|
||||
let a = z - 1;
|
||||
let [tx, ty] = [x, y];
|
||||
for (let s = 1 << a; s > 0; s >>= 1) {
|
||||
const rx = tx & s;
|
||||
const ry = ty & s;
|
||||
acc += ((3 * rx) ^ ry) * (1 << a);
|
||||
[tx, ty] = rotate(s, tx, ty, rx, ry);
|
||||
a--;
|
||||
}
|
||||
return acc + d;
|
||||
return acc;
|
||||
}
|
||||
|
||||
function tileIdToZ(i: number): number {
|
||||
const c = 3 * i + 1;
|
||||
if (c < 0x100000000) {
|
||||
return 31 - Math.clz32(c);
|
||||
}
|
||||
return 63 - Math.clz32(c / 0x100000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Hilbert TileID to Z,X,Y.
|
||||
*/
|
||||
export function tileIdToZxy(i: number): [number, number, number] {
|
||||
let acc = 0;
|
||||
const z = 0;
|
||||
const z = tileIdToZ(i) >> 1;
|
||||
if (z > 26)
|
||||
throw new Error("Tile zoom level exceeds max safe number limit (26)");
|
||||
const acc = ((1 << z) * (1 << z) - 1) / 3;
|
||||
|
||||
for (let z = 0; z < 27; z++) {
|
||||
const numTiles = (0x1 << z) * (0x1 << z);
|
||||
if (acc + numTiles > i) {
|
||||
return idOnLevel(z, i - acc);
|
||||
}
|
||||
acc += numTiles;
|
||||
let t = i - acc;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
const n = 1 << z;
|
||||
for (let s = 1; s < n; s <<= 1) {
|
||||
const rx = s & (t / 2);
|
||||
const ry = s & (t ^ rx);
|
||||
[x, y] = rotate(s, x, y, rx, ry);
|
||||
t = t / 2;
|
||||
x += rx;
|
||||
y += ry;
|
||||
}
|
||||
|
||||
throw new Error("Tile zoom level exceeds max safe number limit (26)");
|
||||
return [z, x, y];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user