Advertisement
Doob

[OpenComputers] GPS_lib

May 14th, 2017
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.92 KB | None | 0 0
  1. local component = require('component')
  2. local modem = nil
  3. if component.isAvailable('modem') then
  4.   modem = component.modem
  5. end
  6. local computer = require('computer')
  7. local floor, sqrt, abs = math.floor, math.sqrt, math.abs
  8.  
  9. local CHANNEL_GPS, gps = 65534, {}
  10.  
  11. local function round(v, m)
  12.   m = m or 1.0
  13.   return {
  14.     x = floor((v.x+(m*0.5))/m)*m,
  15.     y = floor((v.y+(m*0.5))/m)*m,
  16.     z = floor((v.z+(m*0.5))/m)*m
  17.   }
  18. end
  19.  
  20. local function len(v)
  21.   return sqrt(v.x^2 + v.y^2 + v.z^2)
  22. end
  23.  
  24. local function cross(v, b)
  25.   return {x = v.y*b.z-v.z*b.y, y = v.z*b.x-v.x*b.z, z = v.x*b.y-v.y*b.x}
  26. end
  27.  
  28. local function dot(v, b)
  29.   return v.x*b.x + v.y*b.y + v.z*b.z
  30. end
  31.  
  32. local function add(v, b)
  33.   return {x = v.x+b.x, y = v.y+b.y, z = v.z+b.z}
  34. end
  35.  
  36. local function sub(v, b)
  37.   return {x = v.x-b.x, y = v.y-b.y, z = v.z-b.z}
  38. end
  39.  
  40. local function mul(v, m)
  41.   return {x = v.x*m, y = v.y*m, z = v.z*m}
  42. end
  43.  
  44. local function norm(v)
  45.   return mul(v, 1/len(v))
  46. end
  47.  
  48. local function trilaterate(A, B, C)
  49.   local a2b = {x = B.x-A.x, y = B.y-A.y, z = B.z-A.z}
  50.   local a2c = {x = C.x-A.x, y = C.y-A.y, z = C.z-A.z}
  51.   if abs(dot(norm(a2b), norm(a2c))) > 0.999 then
  52.     return nil
  53.   end
  54.   local d = len(a2b)
  55.   local ex = norm(a2b)
  56.   local i = dot(ex, a2c)
  57.   local ey = norm(sub(mul(ex, i), a2c))
  58.   local j = dot(ey, a2c)
  59.   local ez = cross(ex, ey)
  60.   local r1 = A.d
  61.   local r2 = B.d
  62.   local r3 = C.d
  63.   local x = (r1^2 - r2^2 + d^2) / (2*d)
  64.   local y = (r1^2 - r3^2 - x^2 + (x-i)^2 + j^2) / (2*j)
  65.   local result = add(A, add(mul(ex, x), mul(ey, y)))
  66.   local zSquared = r1^2 - x^2 - y^2
  67.   if zSquared > 0 then
  68.     local z = sqrt( zSquared )
  69.     local result1 = add(result, mul(ez, z))
  70.     local result2 = add(result, mul(ez, z))
  71.     local rounded1, rounded2 = round(result1, 0.01), round(result2, 0.01)
  72.     if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then
  73.       return rounded1, rounded2
  74.     else
  75.       return rounded1
  76.     end
  77.   end
  78.   return round(result, 0.01)
  79. end
  80.  
  81. local function narrow(p1, p2, fix)
  82.   local dist1 = abs(len(sub(p1, fix)) - fix.d)
  83.   local dist2 = abs(len(sub(p2, fix)) - fix.d)
  84.   if abs(dist1 - dist2) < 0.01 then
  85.     return p1, p2
  86.   elseif dist1 < dist2 then
  87.     return round(p1, 0.01)
  88.   else
  89.     return round(p2, 0.01)
  90.   end
  91. end
  92.  
  93. function gps.locate(DEBUG)
  94.   if not modem then
  95.     if DEBUG then
  96.       print('No wireless modem attached')
  97.     end
  98.     return nil
  99.   end
  100.   if DEBUG then
  101.     print('Finding position...')
  102.   end
  103.   modem.open(CHANNEL_GPS)
  104.   modem.broadcast(CHANNEL_GPS, 'PING')
  105.   local tFixes = {}
  106.   local pos1, pos2 = nil, nil
  107.   local timeout = computer.uptime()+2
  108.   while true do
  109.     local e = {computer.pullSignal(1)}
  110.     if e[1] == 'modem_message' and e[6] == 'GPS' then
  111.       local tFix = {x = e[7], y = e[8], z = e[9], d = e[5]}
  112.       if DEBUG then
  113.         print(tFix.d .. ' metres from ' .. tFix.x..', '..tFix.y..', '..tFix.z)
  114.       end
  115.       if tFix.d == 0 then
  116.         pos1, pos2 = {tFix.x, tFix.y, tFix.z}, nil
  117.       else
  118.         table.insert(tFixes, tFix)
  119.         if #tFixes >= 3 then
  120.           if not pos1 then
  121.             pos1, pos2 = trilaterate(tFixes[1], tFixes[2], tFixes[#tFixes])
  122.           else
  123.             pos1, pos2 = narrow(pos1, pos2, tFixes[#tFixes])
  124.           end
  125.         end
  126.       end
  127.       if pos1 and not pos2 then
  128.         break
  129.       end
  130.     end
  131.     if computer.uptime() >= timeout then
  132.       break
  133.     end
  134.   end
  135.   modem.close(CHANNEL_GPS)
  136.   if pos1 and pos2 then
  137.     if DEBUG then
  138.       print('Ambiguous position')
  139.       print('Could be '..pos1.x..', '..pos1.y..', '..pos1.z..' or '..pos2.x..', '..pos2.y..', '..pos2.z)
  140.     end
  141.     return nil
  142.   elseif pos1 then
  143.     if DEBUG then
  144.       print('Position is '..pos1.x..', '..pos1.y..', '..pos1.z)
  145.     end
  146.     return pos1.x, pos1.y, pos1.z
  147.   else
  148.     if DEBUG then
  149.       print('Could not determine position')
  150.     end
  151.     return nil
  152.   end
  153. end
  154.  
  155. return gps
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement