All files / core/systems/geohash geohash.ts

97.43% Statements 38/39
93.33% Branches 14/15
100% Functions 3/3
100% Lines 36/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65      15x     2062x 2062x 2062x 2062x 2062x 2062x 2062x 92800x 92800x 92800x 92800x 92800x 46915x 46915x 45885x 92800x 92800x 18560x 18560x 18560x     2062x       1007x                   1003x 1003x 1003x 1003x 9029x 9029x 9029x 45145x 45145x 45145x 22350x 45145x     1003x                
/** Geohash: base-32 interleaved latitude and longitude bits. */
import type { LatLon } from '../../geo/ellipsoid'
 
const GH32 = '0123456789bcdefghjkmnpqrstuvwxyz'
 
export function toGeohash({ lat, lon }: LatLon, length = 10): string {
  let latR = [-90, 90]
  let lonR = [-180, 180]
  let out = ''
  let bits = 0
  let ch = 0
  let even = true
  while (out.length < length) {
    const r = even ? lonR : latR
    const v = even ? lon : lat
    const mid = (r[0]! + r[1]!) / 2
    ch <<= 1
    if (v >= mid) {
      ch |= 1
      r[0] = mid
    } else r[1] = mid
    even = !even
    if (++bits === 5) {
      out += GH32[ch]
      bits = 0
      ch = 0
    }
  }
  return out
}
 
export function isGeohash(s: string): boolean {
  return /^[0-9b-hjkmnp-z]{1,12}$/.test(s.toLowerCase())
}
 
export function fromGeohash(hash: string): {
  center: LatLon
  west: number
  south: number
  east: number
  north: number
} {
  const latR = [-90, 90]
  const lonR = [-180, 180]
  let even = true
  for (const c of hash.toLowerCase()) {
    const idx = GH32.indexOf(c)
    Iif (idx < 0) throw new Error(`Invalid geohash character "${c}"`)
    for (let bit = 4; bit >= 0; bit--) {
      const r = even ? lonR : latR
      const mid = (r[0]! + r[1]!) / 2
      if ((idx >> bit) & 1) r[0] = mid
      else r[1] = mid
      even = !even
    }
  }
  return {
    center: { lat: (latR[0]! + latR[1]!) / 2, lon: (lonR[0]! + lonR[1]!) / 2 },
    west: lonR[0]!,
    south: latR[0]!,
    east: lonR[1]!,
    north: latR[1]!,
  }
}