Skip to content

Instantly share code, notes, and snippets.

@Taosif7
Last active February 10, 2022 09:42
Show Gist options
  • Save Taosif7/e643ecf75cd593ca0cf676a4851d47e2 to your computer and use it in GitHub Desktop.
Save Taosif7/e643ecf75cd593ca0cf676a4851d47e2 to your computer and use it in GitHub Desktop.
Dart Geohash Implementation
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