upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/main/geohash.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/geohash.c')
-rw-r--r--main/geohash.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/main/geohash.c b/main/geohash.c
new file mode 100644
index 0000000..f649824
--- /dev/null
+++ b/main/geohash.c
@@ -0,0 +1,48 @@
1#include "geohash.h"
2#include <string.h>
3
4static const char BASE32[] = "0123456789bcdefghjkmnpqrstuvwxyz";
5
6void geohash_encode(double lat, double lon, int precision, char *out)
7{
8 double lat_range[2] = { -90.0, 90.0 };
9 double lon_range[2] = { -180.0, 180.0 };
10 uint8_t hash_bytes[16];
11 int bit_count = precision * 5;
12 int byte_count = (bit_count + 7) / 8;
13 memset(hash_bytes, 0, sizeof(hash_bytes));
14
15 for (int i = 0; i < bit_count; i++) {
16 int byte_idx = i / 8;
17 int bit_idx = 7 - (i % 8);
18
19 if (i % 2 == 0) {
20 double mid = (lon_range[0] + lon_range[1]) / 2.0;
21 if (lon >= mid) {
22 hash_bytes[byte_idx] |= (1 << bit_idx);
23 lon_range[0] = mid;
24 } else {
25 lon_range[1] = mid;
26 }
27 } else {
28 double mid = (lat_range[0] + lat_range[1]) / 2.0;
29 if (lat >= mid) {
30 hash_bytes[byte_idx] |= (1 << bit_idx);
31 lat_range[0] = mid;
32 } else {
33 lat_range[1] = mid;
34 }
35 }
36 }
37
38 for (int i = 0; i < precision; i++) {
39 int byte_idx = (i * 5) / 8;
40 int bit_offset = (i * 5) % 8;
41 uint16_t val = (hash_bytes[byte_idx] << 8);
42 if (byte_idx + 1 < (int)sizeof(hash_bytes))
43 val |= hash_bytes[byte_idx + 1];
44 val = (val >> (16 - 5 - bit_offset)) & 0x1F;
45 out[i] = BASE32[val];
46 }
47 out[precision] = '\0';
48}