diff options
Diffstat (limited to 'main/geohash.c')
| -rw-r--r-- | main/geohash.c | 48 |
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 | |||
| 4 | static const char BASE32[] = "0123456789bcdefghjkmnpqrstuvwxyz"; | ||
| 5 | |||
| 6 | void 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 | } | ||