/src/geos/src/shape/fractal/HilbertCode.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2020 Paul Ramsey <pramsey@cleverelephant.ca> |
7 | | * |
8 | | * This is free software; you can redistribute and/or modify it under |
9 | | * the terms of the GNU Lesser General Public Licence as published |
10 | | * by the Free Software Foundation. |
11 | | * See the COPYING file for more information. |
12 | | * |
13 | | **********************************************************************/ |
14 | | |
15 | | #include <geos/shape/fractal/HilbertCode.h> |
16 | | #include <geos/geom/Coordinate.h> |
17 | | #include <geos/util/IllegalArgumentException.h> |
18 | | |
19 | | #include <cstdint> |
20 | | |
21 | | namespace geos { |
22 | | namespace shape { // geos.shape |
23 | | namespace fractal { // geos.shape.fractal |
24 | | |
25 | | // Fast Hilbert curve algorithm by http://threadlocalmutex.com/ |
26 | | // From C++ https://github.com/rawrunprotected/hilbert_curves |
27 | | //(public domain) |
28 | | |
29 | | /*public static*/ |
30 | | uint32_t HilbertCode::levelSize(uint32_t level) |
31 | 0 | { |
32 | 0 | return (uint32_t)std::pow(2, 2*level); |
33 | 0 | } |
34 | | |
35 | | /*public static*/ |
36 | | uint32_t HilbertCode::maxOrdinate(uint32_t level) |
37 | 0 | { |
38 | 0 | return (uint32_t)std::pow(2, level) - 1; |
39 | 0 | } |
40 | | |
41 | | /*public static*/ |
42 | | uint32_t HilbertCode::level(uint32_t numPoints) |
43 | 0 | { |
44 | 0 | uint32_t pow2 = (uint32_t) ((std::log(numPoints)/std::log(2))); |
45 | 0 | uint32_t level = pow2 / 2; |
46 | 0 | uint32_t size = levelSize(level); |
47 | 0 | if (size < numPoints) |
48 | 0 | level += 1; |
49 | 0 | return level; |
50 | 0 | } |
51 | | |
52 | | |
53 | | uint32_t |
54 | | HilbertCode::deinterleave(uint32_t x) |
55 | 0 | { |
56 | 0 | x = x & 0x55555555; |
57 | 0 | x = (x | (x >> 1)) & 0x33333333; |
58 | 0 | x = (x | (x >> 2)) & 0x0F0F0F0F; |
59 | 0 | x = (x | (x >> 4)) & 0x00FF00FF; |
60 | 0 | x = (x | (x >> 8)) & 0x0000FFFF; |
61 | 0 | return x; |
62 | 0 | } |
63 | | |
64 | | uint32_t |
65 | | HilbertCode::interleave(uint32_t x) |
66 | 0 | { |
67 | 0 | x = (x | (x << 8)) & 0x00FF00FF; |
68 | 0 | x = (x | (x << 4)) & 0x0F0F0F0F; |
69 | 0 | x = (x | (x << 2)) & 0x33333333; |
70 | 0 | x = (x | (x << 1)) & 0x55555555; |
71 | 0 | return x; |
72 | 0 | } |
73 | | |
74 | | uint32_t |
75 | | HilbertCode::prefixScan(uint32_t x) |
76 | 0 | { |
77 | 0 | x = (x >> 8) ^ x; |
78 | 0 | x = (x >> 4) ^ x; |
79 | 0 | x = (x >> 2) ^ x; |
80 | 0 | x = (x >> 1) ^ x; |
81 | 0 | return x; |
82 | 0 | } |
83 | | |
84 | | uint32_t |
85 | | HilbertCode::descan(uint32_t x) |
86 | 0 | { |
87 | 0 | return x ^ (x >> 1); |
88 | 0 | } |
89 | | |
90 | | /*private static*/ |
91 | | void |
92 | | HilbertCode::checkLevel(uint32_t level) |
93 | 0 | { |
94 | 0 | if (level > MAX_LEVEL) { |
95 | 0 | throw util::IllegalArgumentException("Level out of range"); |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | /* public static */ |
100 | | geom::Coordinate |
101 | | HilbertCode::decode(uint32_t level, uint32_t i) |
102 | 0 | { |
103 | 0 | checkLevel(level); |
104 | 0 | i = i << (32 - 2 * level); |
105 | |
|
106 | 0 | uint32_t i0 = deinterleave(i); |
107 | 0 | uint32_t i1 = deinterleave(i >> 1); |
108 | |
|
109 | 0 | uint32_t t0 = (i0 | i1) ^ 0xFFFF; |
110 | 0 | uint32_t t1 = i0 & i1; |
111 | |
|
112 | 0 | uint32_t prefixT0 = prefixScan(t0); |
113 | 0 | uint32_t prefixT1 = prefixScan(t1); |
114 | |
|
115 | 0 | uint32_t a = (((i0 ^ 0xFFFF) & prefixT1) | (i0 & prefixT0)); |
116 | |
|
117 | 0 | geom::Coordinate c; |
118 | 0 | c.x = (a ^ i1) >> (16 - level); |
119 | 0 | c.y = (a ^ i0 ^ i1) >> (16 - level); |
120 | 0 | return c; |
121 | 0 | } |
122 | | |
123 | | /* public static */ |
124 | | uint32_t |
125 | | HilbertCode::encode(uint32_t level, uint32_t x, uint32_t y) |
126 | 0 | { |
127 | 0 | checkLevel(level); |
128 | 0 | x = x << (16 - level); |
129 | 0 | y = y << (16 - level); |
130 | |
|
131 | 0 | uint32_t A, B, C, D; |
132 | | |
133 | | // Initial prefix scan round, prime with x and y |
134 | 0 | { |
135 | 0 | uint32_t a = x ^ y; |
136 | 0 | uint32_t b = 0xFFFF ^ a; |
137 | 0 | uint32_t c = 0xFFFF ^ (x | y); |
138 | 0 | uint32_t d = x & (y ^ 0xFFFF); |
139 | |
|
140 | 0 | A = a | (b >> 1); |
141 | 0 | B = (a >> 1) ^ a; |
142 | |
|
143 | 0 | C = ((c >> 1) ^ (b & (d >> 1))) ^ c; |
144 | 0 | D = ((a & (c >> 1)) ^ (d >> 1)) ^ d; |
145 | 0 | } |
146 | |
|
147 | 0 | { |
148 | 0 | uint32_t a = A; |
149 | 0 | uint32_t b = B; |
150 | 0 | uint32_t c = C; |
151 | 0 | uint32_t d = D; |
152 | |
|
153 | 0 | A = ((a & (a >> 2)) ^ (b & (b >> 2))); |
154 | 0 | B = ((a & (b >> 2)) ^ (b & ((a ^ b) >> 2))); |
155 | |
|
156 | 0 | C ^= ((a & (c >> 2)) ^ (b & (d >> 2))); |
157 | 0 | D ^= ((b & (c >> 2)) ^ ((a ^ b) & (d >> 2))); |
158 | 0 | } |
159 | |
|
160 | 0 | { |
161 | 0 | uint32_t a = A; |
162 | 0 | uint32_t b = B; |
163 | 0 | uint32_t c = C; |
164 | 0 | uint32_t d = D; |
165 | |
|
166 | 0 | A = ((a & (a >> 4)) ^ (b & (b >> 4))); |
167 | 0 | B = ((a & (b >> 4)) ^ (b & ((a ^ b) >> 4))); |
168 | |
|
169 | 0 | C ^= ((a & (c >> 4)) ^ (b & (d >> 4))); |
170 | 0 | D ^= ((b & (c >> 4)) ^ ((a ^ b) & (d >> 4))); |
171 | 0 | } |
172 | | |
173 | | // Final round and projection |
174 | 0 | { |
175 | 0 | uint32_t a = A; |
176 | 0 | uint32_t b = B; |
177 | 0 | uint32_t c = C; |
178 | 0 | uint32_t d = D; |
179 | |
|
180 | 0 | C ^= ((a & (c >> 8)) ^ (b & (d >> 8))); |
181 | 0 | D ^= ((b & (c >> 8)) ^ ((a ^ b) & (d >> 8))); |
182 | 0 | } |
183 | | |
184 | | // Undo transformation prefix scan |
185 | 0 | uint32_t a = C ^ (C >> 1); |
186 | 0 | uint32_t b = D ^ (D >> 1); |
187 | | |
188 | | // Recover index bits |
189 | 0 | uint32_t i0 = x ^ y; |
190 | 0 | uint32_t i1 = b | (0xFFFF ^ (i0 | a)); |
191 | |
|
192 | 0 | return ((interleave(i1) << 1) | interleave(i0)) >> (32 - 2 * level); |
193 | 0 | } |
194 | | |
195 | | |
196 | | |
197 | | } // namespace geos.shape.fractal |
198 | | } // namespace geos.shape |
199 | | } // namespace geos |