mirror of
https://github.com/Ysurac/openmptcprouter-feeds.git
synced 2025-03-09 15:40:03 +00:00
147 lines
No EOL
4.4 KiB
Lua
147 lines
No EOL
4.4 KiB
Lua
-- Geohash
|
|
-- (c) 2015 Ivan Ribeiro Rocha (ivan.ribeiro@gmail.com)
|
|
-- (c) 2022 modified by Vladislav Kadulin (spanky@yandex.ru)
|
|
|
|
local bit = require("bit32")
|
|
|
|
geohash = {}
|
|
|
|
local BITS = { 16, 8, 4, 2, 1 }
|
|
local BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz"
|
|
|
|
local NEIGHBORS = { right = { even = "bc01fg45238967deuvhjyznpkmstqrwx" },
|
|
left = { even = "238967debc01fg45kmstqrwxuvhjyznp" },
|
|
top = { even = "p0r21436x8zb9dcf5h7kjnmqesgutwvy" },
|
|
bottom = { even = "14365h7k9dcfesgujnmqp0r2twvyx8zb" } }
|
|
|
|
local BORDERS = { right = { even = "bcfguvyz" },
|
|
left = { even = "0145hjnp" },
|
|
top = { even = "prxz" },
|
|
bottom = { even = "028b" } }
|
|
|
|
NEIGHBORS.bottom.odd = NEIGHBORS.left.even
|
|
NEIGHBORS.top.odd = NEIGHBORS.right.even
|
|
NEIGHBORS.left.odd = NEIGHBORS.bottom.even
|
|
NEIGHBORS.right.odd = NEIGHBORS.top.even
|
|
|
|
BORDERS.bottom.odd = BORDERS.left.even
|
|
BORDERS.top.odd = BORDERS.right.even
|
|
BORDERS.left.odd = BORDERS.bottom.even
|
|
BORDERS.right.odd = BORDERS.top.even
|
|
|
|
function geohash.decode(hash)
|
|
local flip = true;
|
|
local coords = { latitude = { -90.0, 90.0 },
|
|
longitude = { -180.0, 180.0 } }
|
|
|
|
for i = 1, #hash do
|
|
local c = hash:sub(i, i)
|
|
local cd = BASE32:find(c) - 1
|
|
for j = 1, 5 do
|
|
mask = BITS[j]
|
|
local tab = (flip and coords.longitude) or coords.latitude
|
|
local idx = (bit.band(cd, mask) > 0) and 1 or 2
|
|
tab[idx] = (tab[1] + tab[2]) / 2
|
|
flip = not flip
|
|
end
|
|
end
|
|
|
|
for k, _ in pairs(coords) do
|
|
coords[k][3] = (coords[k][1] + coords[k][2]) / 2
|
|
end
|
|
|
|
return { lat = coords.latitude, lon = coords.longitude }
|
|
|
|
end
|
|
|
|
function geohash.encode(latitude, longitude, precision)
|
|
local lat = { -90.0, 90.0 }
|
|
local lon = { -180.0, 180.0 }
|
|
local b, ch, flip = 0, 0, true
|
|
local res = "";
|
|
|
|
latitude = tonumber(latitude)
|
|
longitude = tonumber(longitude)
|
|
precision = tonumber(precision)
|
|
local precision = precision or 12
|
|
|
|
while #res < precision do
|
|
local tab = flip and lon or lat
|
|
local grd = flip and longitude or latitude
|
|
|
|
mid = (tab[1] + tab[2]) / 2
|
|
|
|
if grd > mid then
|
|
ch = bit.bor(ch, BITS[b + 1])
|
|
tab[1] = mid
|
|
else
|
|
tab[2] = mid
|
|
end
|
|
|
|
flip = not flip;
|
|
|
|
if b < 4 then
|
|
b = b + 1
|
|
else
|
|
res = res..BASE32:sub(ch + 1, ch + 1);
|
|
b, ch = 0, 0
|
|
end
|
|
end
|
|
return res
|
|
end
|
|
|
|
function geohash.calculate_distance(lat1, lon1, lat2, lon2)
|
|
local R = 6371000
|
|
local r1, r2 = math.rad(lat1), math.rad(lat2)
|
|
local dlat, dlon = math.rad((lat2-lat1)), math.rad((lon2-lon1))
|
|
local a = math.sin(dlat/2) * math.sin(dlat/2) +
|
|
math.cos(r1) * math.cos(r2) *
|
|
math.sin(dlon/2) * math.sin(dlon/2)
|
|
local c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
|
|
return R * c
|
|
end
|
|
|
|
function geohash.distance(hash1, hash2)
|
|
local t1, t2 = decode(hash1), decode(hash2)
|
|
return calculate_distance(coord(t1).lat, coord(t1).lon,
|
|
coord(t2).lat, coord(t2).lon)
|
|
end
|
|
|
|
function geohash.neighbor(hash, dir)
|
|
hash = hash:lower()
|
|
local len = #hash
|
|
local last = hash:sub(len, len);
|
|
local flip = ((math.mod(len,2) == 0) and 'even') or 'odd'
|
|
local base = hash:sub(1, len - 1)
|
|
if BORDERS[dir][flip]:find(last) then
|
|
base = neighbor(base, dir)
|
|
end
|
|
local n = NEIGHBORS[dir][flip]:find(last)
|
|
return base..BASE32:sub(n, n)
|
|
end
|
|
|
|
function geohash.neighbors(hash)
|
|
local neighbors = { top = neighbor(hash, 'top'),
|
|
bottom = neighbor(hash, 'bottom'),
|
|
right = neighbor(hash, 'right'),
|
|
left = neighbor(hash, 'left') }
|
|
neighbors.topleft = neighbor(neighbors.left, 'top');
|
|
neighbors.topright = neighbor(neighbors.right, 'top');
|
|
neighbors.bottomleft = neighbor(neighbors.left, 'bottom');
|
|
neighbors.bottomright = neighbor(neighbors.right, 'bottom');
|
|
return neighbors
|
|
end
|
|
|
|
function geohash.coord(t)
|
|
if type(t) == 'table' then
|
|
return { lat = t.lat[3], lon = t.lon[3] }
|
|
end
|
|
return coord(decode(t))
|
|
end
|
|
|
|
function geohash.coord_str(t)
|
|
local t = coord(t)
|
|
return string.format("lat: %s and lon: %s", tostring(t.lat), tostring(t.lon))
|
|
end
|
|
|
|
return geohash |