Imgoodisher

Reverse GPS

Nov 9th, 2013
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.53 KB | None | 0 0
  1. local ids = {[922]=true, [923]=true, [924]=true, [925]=true}
  2.  
  3. function lookup(id, time)
  4.     for i,v in pairs(ids) do
  5.         rednet.send(i, "RGPS LOOKUP "..id)
  6.     end
  7.     local timeout = os.startTimer(time or 0.1)
  8.     local dists = {}
  9.     while true do
  10.         local evt, id, msg = os.pullEvent()
  11.         if evt == "rednet_message" and ids[id] then
  12.             table.insert(dists, textutils.unserialize(msg))
  13.         elseif evt == "timer" and id == timeout then
  14.             break
  15.         end
  16.     end
  17.     return dists
  18. end
  19.  
  20. local function trilaterate( A, B, C )
  21.     local a2b = B.position - A.position
  22.     local a2c = C.position - A.position
  23.        
  24.     if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then
  25.         return nil
  26.     end
  27.    
  28.     local d = a2b:length()
  29.     local ex = a2b:normalize( )
  30.     local i = ex:dot( a2c )
  31.     local ey = (a2c - (ex * i)):normalize()
  32.     local j = ey:dot( a2c )
  33.     local ez = ex:cross( ey )
  34.  
  35.     local r1 = A.distance
  36.     local r2 = B.distance
  37.     local r3 = C.distance
  38.        
  39.     local x = (r1*r1 - r2*r2 + d*d) / (2*d)
  40.     local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j)
  41.        
  42.     local result = A.position + (ex * x) + (ey * y)
  43.  
  44.     local zSquared = r1*r1 - x*x - y*y
  45.     if zSquared > 0 then
  46.         local z = math.sqrt( zSquared )
  47.         local result1 = result + (ez * z)
  48.         local result2 = result - (ez * z)
  49.        
  50.         local rounded1, rounded2 = result1:round(), result2:round()
  51.         if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then
  52.             return rounded1, rounded2
  53.         else
  54.             return rounded1
  55.         end
  56.     end
  57.     return result:round()
  58.    
  59. end
  60.  
  61. local function narrow( p1, p2, fix )
  62.     local dist1 = math.abs( (p1 - fix.position):length() - fix.distance )
  63.     local dist2 = math.abs( (p2 - fix.position):length() - fix.distance )
  64.    
  65.     if math.abs(dist1 - dist2) < 0.05 then
  66.         return p1, p2
  67.     elseif dist1 < dist2 then
  68.         return p1:round()
  69.     else
  70.         return p2:round()
  71.     end
  72. end
  73.  
  74. function locate( id, timeout, _bDebug )
  75.     if _bDebug then
  76.         print( "Finding position..." )
  77.     end
  78.  
  79.     -- Find a modem
  80.     local sModemSide = nil
  81.     for n,sSide in ipairs( rs.getSides() ) do
  82.         if peripheral.getType( sSide ) == "modem" then 
  83.             sModemSide = sSide
  84.             break
  85.         end
  86.     end
  87.  
  88.     if sModemSide == nil then
  89.         return nil
  90.     end
  91.    
  92.     -- Open a channel
  93.     local modem = peripheral.wrap( sModemSide )
  94.     local bCloseChannel = false
  95.     if not modem.isOpen( os.getComputerID() ) then
  96.         modem.open( os.getComputerID() )
  97.         bCloseChannel = true
  98.     end
  99.        
  100.     -- Wait for the responses
  101.     local tFixes = {}
  102.     local pos1, pos2 = nil
  103.    
  104.     local dists = lookup(id, timeout)
  105.     for i, v in pairs(dists) do
  106.         local tFix = { position = vector.new( v[1], v[2], v[3] ), distance = v[4] }
  107.         if _bDebug then
  108.             print( tFix.distance.." metres from "..tostring( tFix.position ) )
  109.         end
  110.         table.insert( tFixes, tFix )
  111.                    
  112.         if #tFixes >= 3 then
  113.             if not pos1 then
  114.                 pos1, pos2 = trilaterate( tFixes[1], tFixes[2], tFixes[#tFixes] )
  115.             else
  116.                 pos1, pos2 = narrow( pos1, pos2, tFixes[#tFixes] )
  117.             end
  118.         end
  119.                    
  120.         if pos1 and not pos2 then
  121.             break
  122.         end
  123.     end
  124.    
  125.     -- Close the channel, if we opened one
  126.     if bCloseChannel then
  127.         modem.close( os.getComputerID() )
  128.     end
  129.    
  130.     -- Return the response
  131.     if pos1 and pos2 then
  132.         if _bDebug then
  133.             print( "Ambiguous position" )
  134.             print( "Could be "..pos1.x..","..pos1.y..","..pos1.z.." or "..pos2.x..","..pos2.y..","..pos2.z )
  135.         end
  136.         return nil
  137.     elseif pos1 then
  138.         if _bDebug then
  139.             print( "Position is "..pos1.x..","..pos1.y..","..pos1.z )
  140.         end
  141.         return pos1.x, pos1.y, pos1.z
  142.     else
  143.         if _bDebug then
  144.             print( "Could not determine position" )
  145.         end
  146.         return nil
  147.     end
  148. end
Advertisement
Add Comment
Please, Sign In to add comment