1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-feeds.git synced 2025-03-09 15:40:03 +00:00
openmptcprouter-feeds/luci-app-gpoint-main/root/usr/share/gpoint/lib/geohash.lua
2022-11-22 03:23:41 +08:00

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