Inumel

TERMINATE

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