Last active
February 10, 2022 09:42
-
-
Save Taosif7/e643ecf75cd593ca0cf676a4851d47e2 to your computer and use it in GitHub Desktop.
Dart Geohash Implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
String chars = "0123456789bcdefghjkmnpqrstuvwxyz"; | |
const BITS_PER_BASE32_CHAR = 5; | |
main() { | |
LatLng location = LatLng(22.5678, 72.1234); | |
String geohash = encode(location, 8); | |
print("Original: " + location.toString()); | |
print("GeoHash: " + geohash); | |
print("Decoded: " + decodeGeoCode(geohash).toString()); | |
} | |
String encode(LatLng position, int precision) { | |
String geocode = ""; | |
List<double> longitude_range = [-180, 180]; | |
List<double> latitude_range = [-90, 90]; | |
// go through each character for precision | |
for (int i = 0; i < precision; i++) { | |
int hash = 0; | |
// generate a base32 char | |
for (int j = 0; j < BITS_PER_BASE32_CHAR; j++) { | |
bool isEvenBit = ((i * BITS_PER_BASE32_CHAR) + j) % 2 == 0; | |
double val = isEvenBit ? position.longitude : position.latitude; | |
List<double> range = isEvenBit ? longitude_range : latitude_range; | |
double mid = (range[0] + range[1]) / 2; | |
if (val > mid) { | |
hash = (hash << 1) + 1; | |
range[0] = mid; | |
} else { | |
hash = hash << 1; | |
range[1] = mid; | |
} | |
} | |
geocode += base32Char(hash); | |
} | |
return geocode; | |
} | |
LatLng decodeGeoCode(String geocode) { | |
String binaryCode = ""; | |
// Convert geocode into string of binary | |
for (int i = 0; i < geocode.length; i++) { | |
// get decimal of character | |
int decimal = chars.indexOf(geocode[i]); | |
// convert decimal to binary | |
String binary = dec2bin(decimal).padLeft(5, '0'); | |
binaryCode += binary; | |
} | |
// parse longitude for geocode | |
double longitude = parseLongitudeFromBinary(binaryCode); | |
// parse latitude for geocode | |
double latitude = parseLatitudeFromBinary(binaryCode); | |
// Construct LatLng object & return it | |
return LatLng(latitude, longitude); | |
} | |
double parseLongitudeFromBinary(String binaryString) { | |
double max = 180; | |
double min = -180; | |
double mid = 0; | |
for (int i = 0; i < binaryString.length; i += 2) { | |
max = binaryString[i] == "0" ? mid : max; | |
min = binaryString[i] == "0" ? min : mid; | |
mid = (max + min) / 2; | |
} | |
return mid; | |
} | |
double parseLatitudeFromBinary(String binaryString) { | |
double max = 90; | |
double min = -90; | |
double mid = 0; | |
for (int i = 1; i < binaryString.length; i += 2) { | |
max = binaryString[i] == "0" ? mid : max; | |
min = binaryString[i] == "0" ? min : mid; | |
mid = (max + min) / 2; | |
} | |
return mid; | |
} | |
String base32Char(int value) { | |
return chars.substring(value, value + 1); | |
} | |
String dec2bin(int dec) { | |
var bin = ''; | |
int positions = 0; | |
while (dec > 0) { | |
bin = (dec % 2 == 0 ? '0' : '1') + bin; | |
dec ~/= 2; | |
positions++; | |
} | |
return bin; | |
} | |
class LatLng { | |
double latitude, longitude; | |
LatLng(this.latitude, this.longitude){ | |
if(this.latitude > 90 || this.latitude < -90){ | |
throw Exception("Latitude out of range"); | |
}else if(this.longitude > 180 || this.longitude < -180){ | |
throw Exception("Longitude out of range"); | |
} | |
} | |
String toString() { | |
return "${this.latitude}, ${this.longitude}"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment