11package pmtiles
22
3+ import (
4+ "math/bits"
5+ )
6+
37func rotate (n uint64 , x * uint64 , y * uint64 , rx uint64 , ry uint64 ) {
48 if ry == 0 {
59 if rx == 1 {
@@ -10,82 +14,42 @@ func rotate(n uint64, x *uint64, y *uint64, rx uint64, ry uint64) {
1014 }
1115}
1216
13- func tOnLevel (z uint8 , pos uint64 ) (uint8 , uint32 , uint32 ) {
14- var n uint64 = 1 << z
15- rx , ry , t := pos , pos , pos
16- var tx uint64
17- var ty uint64
18- var s uint64
19- for s = 1 ; s < n ; s *= 2 {
20- rx = 1 & (t / 2 )
21- ry = 1 & (t ^ rx )
22- rotate (s , & tx , & ty , rx , ry )
23- tx += s * rx
24- ty += s * ry
25- t /= 4
26- }
27- return uint8 (z ), uint32 (tx ), uint32 (ty )
28- }
29-
3017// ZxyToID converts (Z,X,Y) tile coordinates to a Hilbert TileID.
3118func ZxyToID (z uint8 , x uint32 , y uint32 ) uint64 {
32- var acc uint64
33- var tz uint8
34- for ; tz < z ; tz ++ {
35- acc += (0x1 << tz ) * (0x1 << tz )
36- }
37- var n uint64 = 1 << z
38- var rx uint64
39- var ry uint64
40- var d uint64
41- tx := uint64 (x )
42- ty := uint64 (y )
43- for s := n / 2 ; s > 0 ; s /= 2 {
44- if tx & s > 0 {
45- rx = 1
46- } else {
47- rx = 0
48- }
49- if ty & s > 0 {
50- ry = 1
51- } else {
52- ry = 0
53- }
54- d += s * s * ((3 * rx ) ^ ry )
19+ var acc uint64 = ((1 << (z * 2 )) - 1 ) / 3
20+ var tx , ty uint64 = uint64 (x ), uint64 (y )
21+ for a := int32 (z - 1 ); a >= 0 ; a -- {
22+ var rx uint64 = (tx >> a ) & 1
23+ var ry uint64 = (ty >> a ) & 1
24+ var s uint64 = (1 << a )
5525 rotate (s , & tx , & ty , rx , ry )
26+ acc += s * s * ((3 * rx ) ^ ry )
5627 }
57- return acc + d
28+ return acc
5829}
5930
6031// IDToZxy converts a Hilbert TileID to (Z,X,Y) tile coordinates.
6132func IDToZxy (i uint64 ) (uint8 , uint32 , uint32 ) {
62- var acc uint64
63- var z uint8
64- for {
65- var numTiles uint64
66- numTiles = (1 << z ) * (1 << z )
67- if acc + numTiles > i {
68- return tOnLevel (z , i - acc )
69- }
70- acc += numTiles
71- z ++
33+ var z uint8 = uint8 ((64 - bits .LeadingZeros64 (3 * i + 1 ) - 1 ) / 2 )
34+ var acc uint64 = (1 << (z * 2 ) - 1 ) / 3
35+ var pos uint64 = i - acc
36+ var tx , ty uint64 = 0 , 0
37+ for a := uint8 (0 ); a < z ; a ++ {
38+ var rx uint64 = (pos / 2 ) & 1
39+ var ry uint64 = (pos ^ rx ) & 1
40+ var s uint64 = 1 << a
41+ rotate (s , & tx , & ty , rx , ry )
42+ tx += s * rx
43+ ty += s * ry
44+ pos /= 4
7245 }
46+ return z , uint32 (tx ), uint32 (ty )
7347}
7448
7549// ParentID efficiently finds a parent Hilbert TileID without converting to (Z,X,Y).
7650func ParentID (i uint64 ) uint64 {
77- var acc uint64
78- var lastAcc uint64
79- var z uint8
80- for {
81- var numTiles uint64
82- numTiles = (1 << z ) * (1 << z )
83- if acc + numTiles > i {
84- return lastAcc + (i - acc )/ 4
85- }
86- lastAcc = acc
87- acc += numTiles
88- z ++
89- }
90-
51+ var z uint8 = uint8 ((64 - bits .LeadingZeros64 (3 * i + 1 ) - 1 ) / 2 )
52+ var acc uint64 = (1 << (z * 2 ) - 1 ) / 3
53+ var parentAcc uint64 = (1 << ((z - 1 )* 2 ) - 1 ) / 3
54+ return parentAcc + (i - acc )/ 4
9155}
0 commit comments