# # Copyright 2010 Nick Foster # # This file is part of gr-air-modes # # gr-air-modes is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. # # gr-air-modes is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with gr-air-modes; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # import sqlite3 import math, threading, time class output_kml(threading.Thread): def __init__(self, filename, dbname, localpos, lock, timeout=5): threading.Thread.__init__(self) self._dbname = dbname self._filename = filename self.my_coords = localpos self._timeout = timeout self._lock = lock self.shutdown = threading.Event() self.finished = threading.Event() self.setDaemon(1) self.start() def run(self): self._db = sqlite3.connect(self._dbname) #read from the db while self.shutdown.is_set() is False: time.sleep(self._timeout) self.writekml() self._db.close() self._db = None self.finished.set() def close(self): self.shutdown.set() self.finished.wait(0.2) #there's a bug here where self._timeout is long and close() has #to wait for the sleep to expire before closing. we just bail #instead with the 0.2 param above. def writekml(self): kmlstr = self.genkml() if kmlstr is not None: f = open(self._filename, 'w') f.write(kmlstr) f.close() def locked_execute(self, c, query): with self._lock: c.execute(query) def draw_circle(self, center, rng): retstr = "" steps=30 #so we're going to do this by computing a bearing angle based on the steps, and then compute the coordinate of a line extended from the center point to that range. [center_lat, center_lon] = center esquared = (1/298.257223563)*(2-(1/298.257223563)) earth_radius_mi = 3963.19059 #here we figure out the circumference of the latitude ring #which tells us how wide one line of longitude is at our latitude lat_circ = earth_radius_mi * math.cos(center_lat) #the circumference of the longitude ring will be equal to the circumference of the earth lat_rad = math.radians(center_lat) lon_rad = math.radians(center_lon) tmp0 = rng / earth_radius_mi for i in range(0, steps+1): bearing = i*(2*math.pi/steps) #in radians lat_out = math.degrees(math.asin(math.sin(lat_rad)*math.cos(tmp0) + math.cos(lat_rad)*math.sin(tmp0)*math.cos(bearing))) lon_out = center_lon + math.degrees(math.atan2(math.sin(bearing)*math.sin(tmp0)*math.cos(lat_rad), math.cos(tmp0)-math.sin(lat_rad)*math.sin(math.radians(lat_out)))) retstr += " %.8f,%.8f, 0" % (lon_out, lat_out,) retstr = retstr.lstrip() return retstr def genkml(self): #first let's draw the static content retstr="""\n\n\n\t\n\t\n\t""" if self.my_coords is not None: retstr += """\n\t\n\t\tRange rings\n\t\t0""" for rng in [100, 200, 300]: retstr += """\n\t\t\n\t\t\t%inm\n\t\t\t#rangering\n\t\t\t\n\t\t\t\t%s\n\t\t\t\n\t\t""" % (rng, self.draw_circle(self.my_coords, rng),) retstr += """\t\n""" retstr += """\t\n\t\tAircraft locations\n\t\t0""" #read the database and add KML q = "select distinct icao from positions where seen > datetime('now', '-5 minute')" c = self._db.cursor() self.locked_execute(c, q) icaolist = c.fetchall() #now we have a list icaolist of all ICAOs seen in the last 5 minutes for icao in icaolist: #print "ICAO: %x" % icao q = "select * from positions where icao=%i and seen > datetime('now', '-2 hour') ORDER BY seen DESC" % icao self.locked_execute(c, q) track = c.fetchall() #print "Track length: %i" % len(track) if len(track) != 0: lat = track[0][3] if lat is None: lat = 0 lon = track[0][4] if lon is None: lon = 0 alt = track[0][2] if alt is None: alt = 0 metric_alt = alt * 0.3048 #google earth takes meters, the commie bastards trackstr = "" for pos in track: trackstr += " %f,%f,%f" % (pos[4], pos[3], pos[2]*0.3048) trackstr = trackstr.lstrip() else: alt = 0 metric_alt = 0 lat = 0 lon = 0 trackstr = str("") #now get metadata q = "select ident from ident where icao=%i" % icao self.locked_execute(c, q) r = c.fetchall() if len(r) != 0: ident = r[0][0] else: ident="" #if ident is None: ident = "" #get most recent speed/heading/vertical q = "select seen, speed, heading, vertical from vectors where icao=%i order by seen desc limit 1" % icao self.locked_execute(c, q) r = c.fetchall() if len(r) != 0: seen = r[0][0] speed = r[0][1] heading = r[0][2] vertical = r[0][3] else: seen = 0 speed = 0 heading = 0 vertical = 0 #now generate some KML retstr+= "\n\t\t\n\t\t\t%s\n\t\t\t\n\t\t\t#airplane\n\t\t\t\n\t\t\t\tHeading: %i
Speed: %i
Vertical speed: %i
ICAO: %x
Last seen: %s]]>\n\t\t\t
\n\t\t\t\n\t\t\t\tabsolute\n\t\t\t\t1\n\t\t\t\t%s,%s,%i\n\t\t\t\n\t\t
" % (ident, heading, alt, heading, speed, vertical, icao[0], seen, lon, lat, metric_alt, ) retstr+= "\n\t\t\n\t\t\t#track\n\t\t\t\n\t\t\t\t0\n\t\t\t\tabsolute\n\t\t\t\t%s\n\t\t\t\n\t\t" % (trackstr,) retstr+= '\n\t
\n
\n
' return retstr #we just inherit from output_kml because we're doing the same thing, only in a different format. class output_jsonp(output_kml): def set_highlight(self, icao): self.highlight = icao def genkml(self): retstr="""jsonp_callback([""" # if self.my_coords is not None: # retstr += """\n\t\n\t\tRange rings\n\t\t0""" # for rng in [100, 200, 300]: # retstr += """\n\t\t\n\t\t\t%inm\n\t\t\t#rangering\n\t\t\t\n\t\t\t\t%s\n\t\t\t\n\t\t""" % (rng, self.draw_circle(self.my_coords, rng),) # retstr += """\t\n""" # retstr += """\t\n\t\tAircraft locations\n\t\t0""" #read the database and add KML q = "select distinct icao from positions where seen > datetime('now', '-1 minute')" c = self._db.cursor() self.locked_execute(c, q) icaolist = c.fetchall() #now we have a list icaolist of all ICAOs seen in the last 5 minutes for icao in icaolist: icao = icao[0] #now get metadata q = "select ident, type from ident where icao=%i" % icao self.locked_execute(c, q) r = c.fetchall() if len(r) != 0: ident = r[0][0] actype = r[0][1] else: ident="" actype = "" if ident is None: ident = "" #get most recent speed/heading/vertical q = "select seen, speed, heading, vertical from vectors where icao=%i order by seen desc limit 1" % icao self.locked_execute(c, q) r = c.fetchall() if len(r) != 0: seen = r[0][0] speed = r[0][1] heading = r[0][2] vertical = r[0][3] else: seen = 0 speed = 0 heading = 0 vertical = 0 q = "select lat, lon, alt from positions where icao=%i order by seen desc limit 1" % icao self.locked_execute(c, q) r = c.fetchall() if len(r) != 0: lat = r[0][0] lon = r[0][1] alt = r[0][2] else: lat = 0 lon = 0 alt = 0 highlight = 0 if hasattr(self, 'highlight'): if self.highlight == icao: highlight = 1 #now generate some JSONP retstr+= """{"icao": "%.6x", "lat": %f, "lon": %f, "alt": %i, "hdg": %i, "speed": %i, "vertical": %i, "ident": "%s", "type": "%s", "highlight": %i},""" % (icao, lat, lon, alt, heading, speed, vertical, ident, actype, highlight) retstr+= """]);""" return retstr