Skip to content

Commit

Permalink
tile_id: more improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ciscorn committed Feb 17, 2025
1 parent f256fa6 commit 0a86ca6
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 50 deletions.
23 changes: 12 additions & 11 deletions cpp/pmtiles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ uint64_t decode_varint(const char **data, const char *end) {

void rotate(int64_t n, int64_t &x, int64_t &y, int64_t rx, int64_t ry) {
if (ry == 0) {
if (rx == 1) {
if (rx != 0) {
x = n - 1 - x;
y = n - 1 - y;
}
Expand Down Expand Up @@ -404,13 +404,13 @@ inline zxy tileid_to_zxy(uint64_t tileid) {
uint64_t pos = tileid - acc;
int64_t x = 0, y = 0;
for (uint8_t a = 0; a < z; a++) {
uint64_t rx = (pos / 2) & 1;
uint64_t ry = (pos ^ rx) & 1;
uint64_t s = 1 << a;
uint64_t rx = s & (pos / 2);
uint64_t ry = s & (pos ^ rx);
rotate(s, x, y, rx, ry);
pos /= 4;
x += s * rx;
y += s * ry;
pos >>= 1;
x += rx;
y += ry;
}
return zxy(z, static_cast<int>(x), static_cast<int>(y));
}
Expand All @@ -424,12 +424,13 @@ inline uint64_t zxy_to_tileid(uint8_t z, uint32_t x, uint32_t y) {
}
uint64_t acc = ((1LL << (z * 2U)) - 1) / 3;
int64_t tx = x, ty = y;
for (int32_t a = z - 1; a >= 0; a--) {
int64_t rx = (tx >> a) & 1;
int64_t ry = (ty >> a) & 1;
int64_t s = 1LL << a;
int a = z - 1;
for (int64_t s = 1LL << a; s > 0; s >>= 1) {
int64_t rx = s & tx;
int64_t ry = s & ty;
rotate(s, tx, ty, rx, ry);
acc += s * s * ((3 * rx) ^ ry);
acc += ((3 * rx) ^ ry) << a;
a--;
}
return acc;
}
Expand Down
63 changes: 36 additions & 27 deletions js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,16 @@ function rotate(
rx: number,
ry: number
): [number, number] {
let [tx, ty] = [x, y];
if (ry === 0) {
if (rx === 1) {
tx = n - 1 - tx;
ty = n - 1 - ty;
if (rx !== 0) {
x = n - 1 - x;
y = n - 1 - y;
}
const t = tx;
tx = ty;
tx = t;
const t = x;
x = y;
y = t;
}
return [tx, ty];
return [x, y];
}

/**
Expand All @@ -82,40 +81,50 @@ 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");
}
let [tx, ty] = [x, y];
let acc = (4 ** z - 1) / 3;
for (let a = z - 1; a >= 0; a--) {
const rx = (tx >> a) & 1;
const ry = (ty >> a) & 1;
const s = 2 ** a;
[tx, ty] = rotate(s, tx, ty, rx, ry);
acc += s * s * ((3 * rx) ^ ry);
let acc = ((1 << z) * (1 << z) - 1) / 3;
let a = z - 1;
for (let s = 1 << a; s > 0; s >>= 1) {
const rx = x & s;
const ry = y & s;
acc += ((3 * rx) ^ ry) * (1 << a);
[x, y] = rotate(s, x, y, rx, ry);
a--;
}
return acc;
}

function tileIdToZ(i: number): number {
let c = 3 * i + 1;
if (c < 0x100000000) {
return 31 - Math.clz32(c);
} else {
return 63 - Math.clz32(c / 0x100000000);
}
}

/**
* Convert a Hilbert TileID to Z,X,Y.
*/
export function tileIdToZxy(i: number): [number, number, number] {
const z = Math.floor(Math.log2(3 * i + 1)) >> 1;
const z = tileIdToZ(i) >> 1;
if (z > 26)
throw new Error("Tile zoom level exceeds max safe number limit (26)");
const acc = (4 ** z - 1) / 3;
let pos = i - acc;
const acc = ((1 << z) * (1 << z) - 1) / 3;

let t = i - acc;
let x = 0;
let y = 0;
for (let a = 0; a < z; a++) {
const rx = (pos >> 1) & 1;
const ry = (pos ^ rx) & 1;
const s = 2 ** a;
let 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);
pos = Math.floor(pos / 4);
x += s * rx;
y += s * ry;
t = t / 2;
x += rx;
y += ry;
}
return [z, x, y];
}
Expand Down
28 changes: 16 additions & 12 deletions python/pmtiles/tile.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __str__(self):

def rotate(n, x, y, rx, ry):
if ry == 0:
if rx == 1:
if rx != 0:
x = n - 1 - x
y = n - 1 - y
x, y = y, x
Expand All @@ -32,12 +32,14 @@ def zxy_to_tileid(z, x, y):
raise ValueError("tile x/y outside zoom level bounds")

acc = ((1 << (z * 2)) - 1) // 3
for a in reversed(range(0, z)):
rx = (x >> a) & 1
ry = (y >> a) & 1
a = z - 1
while a >= 0:
s = 1 << a
rx = s & x
ry = s & y
acc += ((3 * rx) ^ ry) << a
(x, y) = rotate(s, x, y, rx, ry)
acc += s * s * ((3 * rx) ^ ry)
a -= 1
return acc


Expand All @@ -49,14 +51,16 @@ def tileid_to_zxy(tile_id):
pos = tile_id - acc
x = 0
y = 0
for a in range(0, z):
rx = (pos // 2) & 1
ry = (pos ^ rx) & 1
s = 1 << a
s = 1
n = 1 << z
while s < n:
rx = (pos // 2) & s
ry = (pos ^ rx) & s
(x, y) = rotate(s, x, y, rx, ry)
pos //= 4
x += s * rx
y += s * ry
x += rx
y += ry
pos >>= 1
s <<= 1
return (z, x, y)


Expand Down

0 comments on commit 0a86ca6

Please sign in to comment.