encode method

  1. @override
String encode(
  1. double lat,
  2. double lon,
  3. int precision
)

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();
}