Module: Geohash

Defined in:
lib/geohash_ruby.rb

Constant Summary collapse

VERSION =
'1.0.2'
BASE32 =
'0123456789bcdefghjkmnpqrstuvwxyz'
NEIGHBORS =
{
  right: [
    'bc01fg45238967deuvhjyznpkmstqrwx',
    'p0r21436x8zb9dcf5h7kjnmqesgutwvy',
  ],
  left: [
    '238967debc01fg45kmstqrwxuvhjyznp',
    '14365h7k9dcfesgujnmqp0r2twvyx8zb',
  ],
  top: [
    'p0r21436x8zb9dcf5h7kjnmqesgutwvy',
    'bc01fg45238967deuvhjyznpkmstqrwx',
  ],
  bottom: [
    '14365h7k9dcfesgujnmqp0r2twvyx8zb',
    '238967debc01fg45kmstqrwxuvhjyznp',
  ]
}
BORDERS =
{
  right:  ['bcfguvyz', 'prxz'],
  left:   ['0145hjnp', '028b'],
  top:    ['prxz', 'bcfguvyz'],
  bottom: ['028b', '0145hjnp'],
}
@@neighbors_cache =
{}
@@adjacent_cache =
{
  right: {}, left: {}, top: {}, bottom: {}
}

Class Method Summary collapse

Class Method Details

.adjacent(geohash, dir) ⇒ String

Calculate adjacent geohashes

Returns:

  • (String)

    adjacent geohash



136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/geohash_ruby.rb', line 136

def adjacent(geohash, dir)
  return @@adjacent_cache[dir][geohash] if @@adjacent_cache[dir][geohash]

  head, last = geohash[0..-2], geohash[-1]
  parity = geohash.length & 1

  head = adjacent(head, dir) if BORDERS[dir][parity].include?(last)

  # NOTICE: do not use append `<<` instead of `+=`
  head += BASE32[NEIGHBORS[dir][parity].index(last)]

  @@adjacent_cache[dir][geohash] = head
end

.decode(geohash) ⇒ [[Float]]

Decode geohash into bounding box of latitudes and longitudes

Returns:

  • ([[Float]])

    decoded bounding box [

    [north_latitude, west_longitude],
    [south_latitude, east_longitude]
    

    ]



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/geohash_ruby.rb', line 53

def decode(geohash)
  bounds = [[-90.0, +90.0], [-180.0, +180.0]]

  geohash.downcase.each_char.with_index do |c, i|
    d = BASE32.index c

    5.times do |j|
      bit = (d & (1 << (4 - j))) >> (4 - j)
      k = (~i & 1) ^ (j & 1)
      bounds[k][bit ^ 1] = (bounds[k][0] + bounds[k][1]) / 2
    end
  end

  bounds.transpose
end

.encode(latitude, longitude, precision = 12) ⇒ String

Encode latitude and longitude into geohash

Returns:

  • (String)

    geohash string



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/geohash_ruby.rb', line 78

def encode(latitude, longitude, precision = 12)
  mids = [latitude, longitude]
  bounds = [[-90.0, +90.0], [-180.0, +180.0]]

  geohash = ''

  precision.times do |i|
    d = 0

    5.times do |j|
      k = (~i & 1) ^ (j & 1)
      mid = (bounds[k][0] + bounds[k][1]) / 2
      bit = mids[k] > mid ? 1 : 0
      bounds[k][bit ^ 1] = mid
      d |= bit << (4 - j)
    end

    geohash << BASE32[d]
  end

  geohash
end

.neighbors(geohash) ⇒ [String]

Calculate neighbors geohash

Returns:

  • ([String])

    neighbors array



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/geohash_ruby.rb', line 108

def neighbors(geohash)
  return @@neighbors_cache[geohash] if @@neighbors_cache[geohash]

  # walk path:
  #
  # 8   1 - 2
  # |   |   |
  # 7   B   3
  # |       |
  # 6 - 5 - 4
  #
  @@neighbors_cache[geohash] = walk geohash, [
    :top,
    :right,
    :bottom, :bottom,
    :left, :left,
    :top, :top
  ]
end

.walk(base, path) ⇒ [String]

Walk down

Returns:

  • ([String])

    result geohashes of the walk



158
159
160
# File 'lib/geohash_ruby.rb', line 158

def walk(base, path)
  path.map { |dir| base = adjacent(base, dir) }
end