1
1
package pmtiles
2
2
3
+ import (
4
+ "math/bits"
5
+ )
6
+
3
7
func rotate (n uint64 , x * uint64 , y * uint64 , rx uint64 , ry uint64 ) {
4
8
if ry == 0 {
5
9
if rx == 1 {
@@ -10,82 +14,42 @@ func rotate(n uint64, x *uint64, y *uint64, rx uint64, ry uint64) {
10
14
}
11
15
}
12
16
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
-
30
17
// ZxyToID converts (Z,X,Y) tile coordinates to a Hilbert TileID.
31
18
func 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 )
55
25
rotate (s , & tx , & ty , rx , ry )
26
+ acc += s * s * ((3 * rx ) ^ ry )
56
27
}
57
- return acc + d
28
+ return acc
58
29
}
59
30
60
31
// IDToZxy converts a Hilbert TileID to (Z,X,Y) tile coordinates.
61
32
func 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
72
45
}
46
+ return z , uint32 (tx ), uint32 (ty )
73
47
}
74
48
75
49
// ParentID efficiently finds a parent Hilbert TileID without converting to (Z,X,Y).
76
50
func 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
91
55
}
0 commit comments