encode method
Encode a latitude and longitude to a geohash string of given
precision (i.e. character length). To get a rough estimation
on the required precision, the Movable Type blog offers this table
("note that the cell width reduces moving away from the equator"):
- Geohash length Cell width Cell height
- 1 ≤ 5,000km × 5,000km
- 2 ≤ 1,250km × 625km
- 3 ≤ 156km × 156km
- 4 ≤ 39.1km × 19.5km
- 5 ≤ 4.89km × 4.89km
- 6 ≤ 1.22km × 0.61km
- 7 ≤ 153m × 153m
- 8 ≤ 38.2m × 19.1m
- 9 ≤ 4.77m × 4.77m
- 10 ≤ 1.19m × 0.596m
- 11 ≤ 149mm × 149mm
- 12 ≤ 37.2mm × 18.6mm
Implementation
@override
String encode(double lat, double lon, int precision) {
if (precision > maxPrecision || precision < 1) {
throw ArgumentError('Precision should be between 1 and $maxPrecision');
}
if (lat < -90 || lat > 90) {
throw ArgumentError('Latitude is out of bounds: $lat');
}
while (lon < -180) lon += 360;
while (lon > 180) lon -= 360;
int idx = 0;
int bit = 0;
bool evenBit = true;
final geohash = StringBuffer();
double minLat = -90;
double maxLat = 90;
double minLon = -180;
double maxLon = 180;
while (geohash.length < precision) {
idx <<= 1;
if (evenBit) {
final midLon = (minLon + maxLon) / 2;
if (lon >= midLon) {
idx |= 1;
minLon = midLon;
} else {
maxLon = midLon;
}
} else {
final midLat = (minLat + maxLat) / 2;
if (lat >= midLat) {
idx |= 1;
minLat = midLat;
} else {
maxLat = midLat;
}
}
evenBit = !evenBit;
bit += 1;
if (bit == 5) {
geohash.write(_kBase32[idx]);
bit = 0;
idx = 0;
}
}
return geohash.toString();
}