def updatePolygon(self, name, data_in): if not self.initialized: return nact = self.nodedata[manager.sender()[0]] if name in nact.polynames: # We're either updating a polygon, or deleting it. In both cases # we remove the current one. nact.polydata = np.delete(nact.polydata, list(range(*nact.polynames[name]))) del nact.polynames[name] # Break up polyline list of (lat,lon)s into separate line segments if data_in is not None: nact.polynames[name] = (len(nact.polydata), 2 * len(data_in)) newbuf = np.empty(2 * len(data_in), dtype=np.float32) newbuf[0::4] = data_in[0::2] # lat newbuf[1::4] = data_in[1::2] # lon newbuf[2:-2:4] = data_in[2::2] # lat newbuf[3:-3:4] = data_in[3::2] # lon newbuf[-2:] = data_in[0:2] nact.polydata = np.append(nact.polydata, newbuf) # If the updated polygon buffer is also currently viewed, also send # updates to the gpu buffer if manager.sender()[0] == self.iactconn: self.makeCurrent() update_buffer(self.allpolysbuf, nact.polydata) self.allpolys.set_vertex_count(int(len(nact.polydata) / 2))
def updatePolygon(self, name, data_in): if not self.initialized: return nact = self.nodedata[manager.sender()[0]] if name in nact.polynames: # We're either updating a polygon, or deleting it. In both cases # we remove the current one. nact.polydata = np.delete(nact.polydata, range(*nact.polynames[name])) del nact.polynames[name] # Break up polyline list of (lat,lon)s into separate line segments if data_in is not None: nact.polynames[name] = (len(nact.polydata), 2 * len(data_in)) newbuf = np.empty(2 * len(data_in), dtype=np.float32) newbuf[0::4] = data_in[0::2] # lat newbuf[1::4] = data_in[1::2] # lon newbuf[2:-2:4] = data_in[2::2] # lat newbuf[3:-3:4] = data_in[3::2] # lon newbuf[-2:] = data_in[0:2] nact.polydata = np.append(nact.polydata, newbuf) # If the updated polygon buffer is also currently viewed, also send # updates to the gpu buffer if manager.sender()[0] == self.iactconn: self.makeCurrent() update_buffer(self.allpolysbuf, nact.polydata) self.allpolys.set_vertex_count(len(nact.polydata) / 2)
def stack(self, text): # Add command to the command history self.command_history.append(text) self.echo(text) # Send stack command to sim process manager.sendEvent(StackTextEvent(cmdtext=text)) self.cmdline_stacked.emit(self.cmd, self.args) # reset commandline and the autocomplete history self.setCmdline('') autocomplete.reset()
def defwpt(self, wpdata): if not self.initialized: return nact = self.nodedata[manager.sender()[0]] nact.custwplbl += wpdata[0].ljust(5) nact.custwplat = np.append(nact.custwplat, np.float32(wpdata[1])) nact.custwplon = np.append(nact.custwplon, np.float32(wpdata[2])) if manager.sender()[0] == self.iactconn: self.makeCurrent() update_buffer(self.custwplblbuf, np.array(nact.custwplbl)) update_buffer(self.custwplatbuf, nact.custwplat) update_buffer(self.custwplonbuf, nact.custwplon) self.ncustwpts = len(nact.custwplat)
def MainLoop(): if node_only: runNode() else: # ====================================================================== # Create gui and simulation objects # ====================================================================== global navdb, manager, gui manager = MainManager() gui = Gui() navdb = Navdatabase('global') # Read database from specified folder telnet_in = StackTelnetServer() sim = Simulation(manager) # Initialize the gui (loading graphics data, etc.) gui.init(navdb) # Start the node manager manager.start() # Start the telnet input server for stack commands telnet_in.listen(port=settings.telnet_port) # Start the gui gui.start() print 'Stopping telnet server.' telnet_in.close() # Close the manager, stop all nodes manager.stop() sim.quit() # ====================================================================== # Clean up before exit. Comment this out when debugging for checking # variables in the shell. # ====================================================================== del gui print 'BlueSky normal end.'
def clearNodeData(self): if not self.initialized: return # Clear all data for sender node nact = self.nodedata[manager.sender()[0]] nact.polynames.clear() nact.polydata = np.array([], dtype=np.float32) nact.custwplbl = '' nact.custwplat = np.array([], dtype=np.float32) nact.custwplon = np.array([], dtype=np.float32) # Clear trail data nact.traillat0 = [] nact.traillon0 = [] nact.traillat1 = [] nact.traillon1 = [] # If the updated polygon buffer is also currently viewed, also send # updates to the gpu buffer if manager.sender()[0] == self.iactconn: self.allpolys.set_vertex_count(0) self.traillines.set_vertex_count(0) self.ncustwpts = 0
def setCmdline(self, text): if self.command_line == text: return self.command_line = text self.cmd, self.args = cmdsplit(self.command_line) hintline = '' allhints = node_stacks.get(manager.actnode()) if allhints: hint = allhints.get(self.cmd) if hint: if len(self.args) > 0: hintargs = hint.split(',') hintline = ' ' + str.join(',', hintargs[len(self.args):]) else: hintline = ' ' + hint self.lineEdit.setHtml('>>' + self.command_line + '<font color="#aaaaaa">' + hintline + '</font>')
def MainLoop(): if node_only: runNode() else: # ====================================================================== # Create gui and simulation objects # ====================================================================== global navdb, manager, gui manager = MainManager() gui = Gui() navdb = Navdatabase('global') # Read database from specified folder telnet_in = StackTelnetServer() # Initialize the gui (loading graphics data, etc.) gui.init(navdb) # Start the node manager manager.start() # Start the telnet input server for stack commands telnet_in.listen(port=settings.telnet_port) # Start the gui gui.start() print 'Stopping telnet server.' telnet_in.close() # Close the manager, stop all nodes manager.stop() # ====================================================================== # Clean up before exit. Comment this out when debugging for checking # variables in the shell. # ====================================================================== del gui print 'BlueSky normal end.'
def notify(self, receiver, event): # Keep track of event processing event_processed = False # Events from the simulation threads if receiver is self: if event.type() == PanZoomEventType: if event.zoom is not None: event.origin = (self.radarwidget.width / 2, self.radarwidget.height / 2) if event.pan is not None and not event.absolute: event.pan = ( 2.0 * event.pan[0] / (self.radarwidget.zoom * self.radarwidget.ar), 2.0 * event.pan[1] / (self.radarwidget.zoom * self.radarwidget.flat_earth)) # send the pan/zoom event to the radarwidget self.radarwidget.event(event) elif event.type() == ACDataEventType: self.acdata = event self.radarwidget.update_aircraft_data(event) if self.nd.ac_id in event.id: idx = event.id.index(self.nd.ac_id.upper()) lat = event.lat[idx] lon = event.lon[idx] trk = event.trk[idx] tas = event.tas[idx] self.nd.update_aircraft_data(idx, lat, lon, tas, trk, len(event.lat)) return True elif event.type() == RouteDataEventType: self.routedata = event self.radarwidget.update_route_data(event) return True elif event.type() == DisplayShapeEventType: self.radarwidget.updatePolygon(event.name, event.data) elif event.type() == SimInfoEventType: simt = tim2txt(event.simt)[:-3] simtclock = tim2txt(event.simtclock)[:-3] self.win.setNodeInfo(manager.sender()[0], simt, event.scenname) if manager.sender()[0] == manager.actnode(): self.simt = event.simt self.win.siminfoLabel.setText( u'<b>t:</b> %s, <b>\u0394t:</b> %.2f, <b>Speed:</b> %.1fx, <b>UTC:</b> %s, <b>Mode:</b> %s, <b>Aircraft:</b> %d, <b>Conflicts:</b> %d/%d, <b>LoS:</b> %d/%d' % (simt, event.simdt, event.sys_freq, simtclock, self.modes[event.mode], event.n_ac, self.acdata.nconf_cur, self.acdata.nconf_tot, self.acdata.nlos_cur, self.acdata.nlos_tot)) return True elif event.type() == StackTextEventType: event_processed = True if event.disptext: self.win.console.echo(event.disptext) if event.cmdtext: self.win.console.setCmdline(event.cmdtext) elif event.type() == StackInitEventType: event_processed = True self.win.console.addStackHelp(manager.sender()[0], event.stackdict) elif event.type() == ShowDialogEventType: if event.dialog_type == event.filedialog_type: self.show_file_dialog() elif event.dialog_type == event.docwin_type: self.show_doc_window(event.cmd) return True elif event.type() == DisplayFlagEventType: # Switch/toggle/cycle radar screen features e.g. from SWRAD command if event.switch == 'RESET': self.radarwidget.clearNodeData() # Coastlines elif event.switch == "GEO": self.radarwidget.show_coast = not self.radarwidget.show_coast # FIR boundaries elif event.switch == "FIR": self.radarwidget.showfir = not self.radarwidget.showfir # Airport: 0 = None, 1 = Large, 2= All elif event.switch == "APT": self.radarwidget.show_apt = not self.radarwidget.show_apt # Waypoint: 0 = None, 1 = VOR, 2 = also WPT, 3 = Also terminal area wpts elif event.switch == "VOR" or event.switch == "WPT" or event.switch == "WP" or event.switch == "NAV": self.radarwidget.show_apt = not self.radarwidget.show_apt # Satellite image background on/off elif event.switch == "SAT": self.radarwidget.show_map = not self.radarwidget.show_map # Satellite image background on/off elif event.switch == "TRAF": self.radarwidget.show_traf = not self.radarwidget.show_traf # ND window for selected aircraft elif event.switch == "ND": self.nd.setAircraftID(event.argument) self.nd.setVisible(not self.nd.isVisible()) elif event.switch == "SSD": self.radarwidget.show_ssd(event.argument) elif event.switch == "SYM": # For now only toggle PZ self.radarwidget.show_pz = not self.radarwidget.show_pz elif event.switch == "DEFWPT": self.radarwidget.defwpt(event.argument) elif event.switch == "FILTERALT": # First argument is an on/off flag nact = self.radarwidget.nodedata[manager.sender()[0]] if event.argument[0]: nact.filteralt = event.argument[1:] else: nact.filteralt = False return True elif event.type() == AMANEventType: # self.aman.update(self.simt, event) pass # Mouse/trackpad event handling for the Radar widget elif receiver is self.radarwidget and self.radarwidget.initialized: panzoom = None if event.type() == QEvent.Wheel: # For mice we zoom with control/command and the scrolwheel if event.modifiers() & Qt.ControlModifier: origin = (event.pos().x(), event.pos().y()) zoom = 1.0 try: if event.pixelDelta(): # High resolution scroll zoom *= (1.0 + 0.01 * event.pixelDelta().y()) else: # Low resolution scroll zoom *= (1.0 + 0.001 * event.angleDelta().y()) except: zoom *= (1.0 + 0.001 * event.delta()) panzoom = PanZoomEvent(zoom=zoom, origin=origin) # For touchpad scroll (2D) is used for panning else: try: dlat = 0.01 * event.pixelDelta().y() / ( self.radarwidget.zoom * self.radarwidget.ar) dlon = -0.01 * event.pixelDelta().x() / ( self.radarwidget.zoom * self.radarwidget.flat_earth) panzoom = PanZoomEvent(pan=(dlat, dlon)) except: pass # For touchpad, pinch gesture is used for zoom elif event.type() == QEvent.Gesture: zoom = None pan = None dlat = 0.0 dlon = 0.0 for g in event.gestures(): if g.gestureType() == Qt.PinchGesture: if zoom is None: zoom = 1.0 zoom *= g.scaleFactor() if correct_pinch: zoom /= g.lastScaleFactor() elif g.gestureType() == Qt.PanGesture: if abs(g.delta().y() + g.delta().x()) > 1e-1: dlat += 0.005 * g.delta().y() / ( self.radarwidget.zoom * self.radarwidget.ar) dlon -= 0.005 * g.delta().x() / ( self.radarwidget.zoom * self.radarwidget.flat_earth) pan = (dlat, dlon) if pan is not None or zoom is not None: panzoom = PanZoomEvent(pan, zoom, self.mousepos) elif event.type( ) == QEvent.MouseButtonPress and event.button() & Qt.LeftButton: event_processed = True self.mousedragged = False # For mice we pan with control/command and mouse movement. Mouse button press marks the beginning of a pan self.prevmousepos = (event.x(), event.y()) elif event.type() == QEvent.MouseButtonRelease and event.button( ) & Qt.LeftButton and not self.mousedragged: event_processed = True lat, lon = self.radarwidget.pixelCoordsToLatLon( event.x(), event.y()) tostack, tocmdline = radarclick(self.win.console.command_line, lat, lon, self.acdata, self.routedata) if len(tocmdline) > 0: if '\n' in tocmdline: self.win.console.setCmdline('') # Clear any shape command preview on the radar display self.radarwidget.previewpoly(None) else: self.win.console.appendCmdline(tocmdline) if len(tostack) > 0: self.win.console.stack(tostack) elif event.type() == QEvent.MouseMove: event_processed = True self.mousedragged = True self.mousepos = (event.x(), event.y()) if event.buttons() & Qt.LeftButton: dlat = 0.003 * (event.y() - self.prevmousepos[1]) / ( self.radarwidget.zoom * self.radarwidget.ar) dlon = 0.003 * (self.prevmousepos[0] - event.x()) / ( self.radarwidget.zoom * self.radarwidget.flat_earth) self.prevmousepos = (event.x(), event.y()) panzoom = PanZoomEvent(pan=(dlat, dlon)) # Update pan/zoom to simulation thread only when the pan/zoom gesture is finished elif (event.type() == QEvent.MouseButtonRelease or event.type() == QEvent.TouchEnd) and self.panzoomchanged: self.panzoomchanged = False manager.sendEvent( PanZoomEvent(pan=(self.radarwidget.panlat, self.radarwidget.panlon), zoom=self.radarwidget.zoom, absolute=True)) # If we've just processed a change to pan and/or zoom, send the event to the radarwidget if panzoom is not None: self.panzoomchanged = True return self.radarwidget.event(panzoom) # Send all key presses directly to the main window if event.type() == QEvent.KeyPress: self.win.keyPressEvent(event) return True # If we haven't processed the event: call Base Class Method to Continue Normal Event Processing if not event_processed: return super(Gui, self).notify(receiver, event) if self.win.console.cmd in [ 'AREA', 'BOX', 'POLY', 'POLYALT', 'POLYGON', 'CIRCLE', 'LINE' ]: if self.mousepos != self.prevmousepos and len( self.win.console.args) >= 2: self.prevmousepos = self.mousepos try: # get the largest even number of points start = 0 if self.win.console.cmd == 'AREA' else 3 if self.win.console.cmd == 'POLYALT' else 1 end = ( (len(self.win.console.args) - start) / 2) * 2 + start data = [float(v) for v in self.win.console.args[start:end]] data += self.radarwidget.pixelCoordsToLatLon( *self.mousepos) self.radarwidget.previewpoly(self.win.console.cmd, data) except ValueError: pass event.accept() return True
def buttonClicked(self): if self.sender() == self.shownodes: vis = not self.nodetree.isVisible() self.nodetree.setVisible(vis) self.shownodes.setText('>' if vis else '<') if self.sender() == self.zoomin: self.app.notify(self.app, PanZoomEvent(zoom=1.4142135623730951)) elif self.sender() == self.zoomout: self.app.notify(self.app, PanZoomEvent(zoom=0.70710678118654746)) elif self.sender() == self.pandown: self.app.notify(self.app, PanZoomEvent(pan=(-0.5, 0.0))) elif self.sender() == self.panup: self.app.notify(self.app, PanZoomEvent(pan=(0.5, 0.0))) elif self.sender() == self.panleft: self.app.notify(self.app, PanZoomEvent(pan=(0.0, -0.5))) elif self.sender() == self.panright: self.app.notify(self.app, PanZoomEvent(pan=(0.0, 0.5))) elif self.sender() == self.ic: self.app.show_file_dialog() elif self.sender() == self.sameic: manager.sendEvent(StackTextEvent(cmdtext='IC IC')) elif self.sender() == self.hold: manager.sendEvent(StackTextEvent(cmdtext='HOLD')) elif self.sender() == self.op: manager.sendEvent(StackTextEvent(cmdtext='OP')) elif self.sender() == self.fast: manager.sendEvent(StackTextEvent(cmdtext='FF')) elif self.sender() == self.fast10: manager.sendEvent(StackTextEvent(cmdtext='FF 0:0:10')) elif self.sender() == self.showac: self.radarwidget.show_traf = not self.radarwidget.show_traf elif self.sender() == self.showpz: self.radarwidget.show_pz = not self.radarwidget.show_pz elif self.sender() == self.showapt: if self.radarwidget.show_apt < 3: self.radarwidget.show_apt += 1 else: self.radarwidget.show_apt = 0 elif self.sender() == self.showwpt: if self.radarwidget.show_wpt < 2: self.radarwidget.show_wpt += 1 else: self.radarwidget.show_wpt = 0 elif self.sender() == self.showlabels: self.radarwidget.show_lbl = not self.radarwidget.show_lbl elif self.sender() == self.showmap: self.radarwidget.show_map = not self.radarwidget.show_map elif self.sender() == self.action_Save: manager.sendEvent(StackTextEvent(cmdtext='SAVEIC'))
def update_aircraft_data(self, data): if not self.initialized: return self.makeCurrent() curnode = self.nodedata[self.iactconn] if curnode.filteralt: idx = np.where((data.alt >= curnode.filteralt[0]) * (data.alt <= curnode.filteralt[1])) data.lat = data.lat[idx] data.lon = data.lon[idx] data.trk = data.trk[idx] data.alt = data.alt[idx] data.tas = data.tas[idx] self.naircraft = len(data.lat) if self.naircraft == 0: self.cpalines.set_vertex_count(0) else: # Update data in GPU buffers update_buffer(self.aclatbuf, np.array(data.lat, dtype=np.float32)) update_buffer(self.aclonbuf, np.array(data.lon, dtype=np.float32)) update_buffer(self.achdgbuf, np.array(data.trk, dtype=np.float32)) update_buffer(self.acaltbuf, np.array(data.alt, dtype=np.float32)) update_buffer(self.actasbuf, np.array(data.tas, dtype=np.float32)) # CPA lines to indicate conflicts ncpalines = len(data.confcpalat) cpalines = np.zeros(4 * ncpalines, dtype=np.float32) self.cpalines.set_vertex_count(2 * ncpalines) # Labels and colors rawlabel = '' color = np.empty((self.naircraft, 4), dtype=np.uint8) selssd = np.zeros(self.naircraft, dtype=np.uint8) for i, acid in enumerate(data.id): # Make label: 3 lines of 8 characters per aircraft if data.alt[i] <= 4500. * ft: rawlabel += '%-8s%-5d %-8d' % ( acid[:8], int(data.alt[i] / ft + 0.5), int(data.cas[i] / kts + 0.5)) else: rawlabel += '%-8sFL%03d %-8d' % ( acid[:8], int(data.alt[i] / ft / 100. + 0.5), int(data.cas[i] / kts + 0.5)) confindices = data.iconf[i] if len(confindices) > 0: if self.ssd_conflicts: selssd[i] = 255 color[i, :] = amber + (255, ) for confidx in confindices: cpalines[4 * confidx:4 * confidx + 4] = [ data.lat[i], data.lon[i], data.confcpalat[confidx], data.confcpalon[confidx] ] else: color[i, :] = green + (255, ) # Check if aircraft is selected to show SSD if acid in self.ssd_ownship: selssd[i] = 255 if len(self.ssd_ownship) > 0 or self.ssd_conflicts: update_buffer(self.ssd.selssdbuf, selssd) update_buffer(self.confcpabuf, cpalines) update_buffer(self.accolorbuf, color) update_buffer(self.aclblbuf, np.array(rawlabel, dtype=np.string_)) # If there is a visible route, update the start position if self.route_acid != "": if self.route_acid in data.id: idx = data.id.index(self.route_acid) update_buffer( self.routebuf, np.array([data.lat[idx], data.lon[idx]], dtype=np.float32)) nact = self.nodedata[manager.sender()[0]] # Update trails database with new lines if data.swtrails: nact.traillat0.extend(data.traillat0) nact.traillon0.extend(data.traillon0) nact.traillat1.extend(data.traillat1) nact.traillon1.extend(data.traillon1) update_buffer( self.trailbuf, np.array(zip(nact.traillat0, nact.traillon0, nact.traillat1, nact.traillon1) + zip(data.traillastlat, data.traillastlon, list(data.lat), list(data.lon)), dtype=np.float32)) self.traillines.set_vertex_count(2 * len(nact.traillat0) + 2 * len(data.lat)) else: nact.traillat0 = [] nact.traillon0 = [] nact.traillat1 = [] nact.traillon1 = [] self.traillines.set_vertex_count(0)
def notify(self, receiver, event): # Keep track of event processing event_processed = False # Events from the simulation threads if receiver is self: if event.type() == PanZoomEventType: if event.zoom is not None: event.origin = (self.radarwidget.width / 2, self.radarwidget.height / 2) if event.pan is not None and not event.absolute: event.pan = (2.0 * event.pan[0] / (self.radarwidget.zoom * self.radarwidget.ar), 2.0 * event.pan[1] / (self.radarwidget.zoom * self.radarwidget.flat_earth)) # send the pan/zoom event to the radarwidget self.radarwidget.event(event) elif event.type() == ACDataEventType: self.acdata = event self.radarwidget.update_aircraft_data(event) if self.nd.ac_id in event.id: idx = event.id.index(self.nd.ac_id.upper()) lat = event.lat[idx] lon = event.lon[idx] trk = event.trk[idx] tas = event.tas[idx] self.nd.update_aircraft_data(idx, lat, lon, tas, trk, len(event.lat)) return True elif event.type() == RouteDataEventType: self.routedata = event self.radarwidget.update_route_data(event) return True elif event.type() == DisplayShapeEventType: self.radarwidget.updatePolygon(event.name, event.data) elif event.type() == SimInfoEventType: simt = tim2txt(event.simt)[:-3] simtclock = tim2txt(event.simtclock)[:-3] self.win.setNodeInfo(manager.sender()[0], simt, event.scenname) if manager.sender()[0] == manager.actnode(): self.simt = event.simt self.win.siminfoLabel.setText(u'<b>t:</b> %s, <b>\u0394t:</b> %.2f, <b>Speed:</b> %.1fx, <b>UTC:</b> %s, <b>Mode:</b> %s, <b>Aircraft:</b> %d, <b>Conflicts:</b> %d/%d, <b>LoS:</b> %d/%d' % (simt, event.simdt, event.sys_freq, simtclock, self.modes[event.mode], event.n_ac, self.acdata.nconf_cur, self.acdata.nconf_tot, self.acdata.nlos_cur, self.acdata.nlos_tot)) return True elif event.type() == StackTextEventType: event_processed = True if event.disptext: self.win.console.echo(event.disptext) if event.cmdtext: self.win.console.setCmdline(event.cmdtext) elif event.type() == StackInitEventType: event_processed = True self.win.console.addStackHelp(manager.sender()[0], event.stackdict) elif event.type() == ShowDialogEventType: if event.dialog_type == event.filedialog_type: self.show_file_dialog() elif event.dialog_type == event.docwin_type: self.show_doc_window(event.cmd) return True elif event.type() == DisplayFlagEventType: # Switch/toggle/cycle radar screen features e.g. from SWRAD command if event.switch == 'RESET': self.radarwidget.clearNodeData() # Coastlines elif event.switch == "GEO": self.radarwidget.show_coast = not self.radarwidget.show_coast # FIR boundaries elif event.switch == "FIR": self.radarwidget.showfir = not self.radarwidget.showfir # Airport: 0 = None, 1 = Large, 2= All elif event.switch == "APT": self.radarwidget.show_apt = not self.radarwidget.show_apt # Waypoint: 0 = None, 1 = VOR, 2 = also WPT, 3 = Also terminal area wpts elif event.switch == "VOR" or event.switch == "WPT" or event.switch == "WP" or event.switch == "NAV": self.radarwidget.show_apt = not self.radarwidget.show_apt # Satellite image background on/off elif event.switch == "SAT": self.radarwidget.show_map = not self.radarwidget.show_map # Satellite image background on/off elif event.switch == "TRAF": self.radarwidget.show_traf = not self.radarwidget.show_traf # ND window for selected aircraft elif event.switch == "ND": self.nd.setAircraftID(event.argument) self.nd.setVisible(not self.nd.isVisible()) elif event.switch == "SSD": self.radarwidget.show_ssd(event.argument) elif event.switch == "SYM": # For now only toggle PZ self.radarwidget.show_pz = not self.radarwidget.show_pz elif event.switch == "DEFWPT": self.radarwidget.defwpt(event.argument) elif event.switch == "FILTERALT": # First argument is an on/off flag nact = self.radarwidget.nodedata[manager.sender()[0]] if event.argument[0]: nact.filteralt = event.argument[1:] else: nact.filteralt = False return True elif event.type() == AMANEventType: # self.aman.update(self.simt, event) pass # Mouse/trackpad event handling for the Radar widget elif receiver is self.radarwidget and self.radarwidget.initialized: panzoom = None if event.type() == QEvent.Wheel: # For mice we zoom with control/command and the scrolwheel if event.modifiers() & Qt.ControlModifier: origin = (event.pos().x(), event.pos().y()) zoom = 1.0 try: if event.pixelDelta(): # High resolution scroll zoom *= (1.0 + 0.01 * event.pixelDelta().y()) else: # Low resolution scroll zoom *= (1.0 + 0.001 * event.angleDelta().y()) except: zoom *= (1.0 + 0.001 * event.delta()) panzoom = PanZoomEvent(zoom=zoom, origin=origin) # For touchpad scroll (2D) is used for panning else: try: dlat = 0.01 * event.pixelDelta().y() / (self.radarwidget.zoom * self.radarwidget.ar) dlon = -0.01 * event.pixelDelta().x() / (self.radarwidget.zoom * self.radarwidget.flat_earth) panzoom = PanZoomEvent(pan=(dlat, dlon)) except: pass # For touchpad, pinch gesture is used for zoom elif event.type() == QEvent.Gesture: zoom = None pan = None dlat = 0.0 dlon = 0.0 for g in event.gestures(): if g.gestureType() == Qt.PinchGesture: if zoom is None: zoom = 1.0 zoom *= g.scaleFactor() if correct_pinch: zoom /= g.lastScaleFactor() elif g.gestureType() == Qt.PanGesture: if abs(g.delta().y() + g.delta().x()) > 1e-1: dlat += 0.005 * g.delta().y() / (self.radarwidget.zoom * self.radarwidget.ar) dlon -= 0.005 * g.delta().x() / (self.radarwidget.zoom * self.radarwidget.flat_earth) pan = (dlat, dlon) if pan is not None or zoom is not None: panzoom = PanZoomEvent(pan, zoom, self.mousepos) elif event.type() == QEvent.MouseButtonPress and event.button() & Qt.LeftButton: event_processed = True self.mousedragged = False # For mice we pan with control/command and mouse movement. Mouse button press marks the beginning of a pan self.prevmousepos = (event.x(), event.y()) elif event.type() == QEvent.MouseButtonRelease and event.button() & Qt.LeftButton and not self.mousedragged: event_processed = True lat, lon = self.radarwidget.pixelCoordsToLatLon(event.x(), event.y()) tostack, tocmdline = radarclick(self.win.console.command_line, lat, lon, self.acdata, self.routedata) if len(tocmdline) > 0: if '\n' in tocmdline: self.win.console.setCmdline('') # Clear any shape command preview on the radar display self.radarwidget.previewpoly(None) else: self.win.console.appendCmdline(tocmdline) if len(tostack) > 0: self.win.console.stack(tostack) elif event.type() == QEvent.MouseMove: event_processed = True self.mousedragged = True self.mousepos = (event.x(), event.y()) if event.buttons() & Qt.LeftButton: dlat = 0.003 * (event.y() - self.prevmousepos[1]) / (self.radarwidget.zoom * self.radarwidget.ar) dlon = 0.003 * (self.prevmousepos[0] - event.x()) / (self.radarwidget.zoom * self.radarwidget.flat_earth) self.prevmousepos = (event.x(), event.y()) panzoom = PanZoomEvent(pan=(dlat, dlon)) # Update pan/zoom to simulation thread only when the pan/zoom gesture is finished elif (event.type() == QEvent.MouseButtonRelease or event.type() == QEvent.TouchEnd) and self.panzoomchanged: self.panzoomchanged = False manager.sendEvent(PanZoomEvent( pan=(self.radarwidget.panlat, self.radarwidget.panlon), zoom=self.radarwidget.zoom, absolute=True)) # If we've just processed a change to pan and/or zoom, send the event to the radarwidget if panzoom is not None: self.panzoomchanged = True return self.radarwidget.event(panzoom) # Send all key presses directly to the main window if event.type() == QEvent.KeyPress: self.win.keyPressEvent(event) return True # If we haven't processed the event: call Base Class Method to Continue Normal Event Processing if not event_processed: return super(Gui, self).notify(receiver, event) if self.win.console.cmd in ['AREA', 'BOX', 'POLY', 'POLYALT', 'POLYGON', 'CIRCLE', 'LINE']: if self.mousepos != self.prevmousepos and len(self.win.console.args) >= 2: self.prevmousepos = self.mousepos try: # get the largest even number of points start = 0 if self.win.console.cmd == 'AREA' else 3 if self.win.console.cmd == 'POLYALT' else 1 end = ((len(self.win.console.args) - start) // 2) * 2 + start data = [float(v) for v in self.win.console.args[start:end]] data += self.radarwidget.pixelCoordsToLatLon(*self.mousepos) self.radarwidget.previewpoly(self.win.console.cmd, data) except ValueError: pass event.accept() return True
def buttonClicked(self): if self.sender() == self.shownodes: vis = not self.nodetree.isVisible() self.nodetree.setVisible(vis) self.shownodes.setText('>' if vis else '<') if self.sender() == self.zoomin: self.app.notify(self.app, PanZoomEvent(zoom=1.4142135623730951)) elif self.sender() == self.zoomout: self.app.notify(self.app, PanZoomEvent(zoom=0.70710678118654746)) elif self.sender() == self.pandown: self.app.notify(self.app, PanZoomEvent(pan=(-0.5, 0.0))) elif self.sender() == self.panup: self.app.notify(self.app, PanZoomEvent(pan=( 0.5, 0.0))) elif self.sender() == self.panleft: self.app.notify(self.app, PanZoomEvent(pan=( 0.0, -0.5))) elif self.sender() == self.panright: self.app.notify(self.app, PanZoomEvent(pan=( 0.0, 0.5))) elif self.sender() == self.ic: self.app.show_file_dialog() elif self.sender() == self.sameic: manager.sendEvent(StackTextEvent(cmdtext='IC IC')) elif self.sender() == self.hold: manager.sendEvent(StackTextEvent(cmdtext='HOLD')) elif self.sender() == self.op: manager.sendEvent(StackTextEvent(cmdtext='OP')) elif self.sender() == self.fast: manager.sendEvent(StackTextEvent(cmdtext='FF')) elif self.sender() == self.fast10: manager.sendEvent(StackTextEvent(cmdtext='FF 0:0:10')) elif self.sender() == self.showac: self.radarwidget.show_traf = not self.radarwidget.show_traf elif self.sender() == self.showpz: self.radarwidget.show_pz = not self.radarwidget.show_pz elif self.sender() == self.showapt: if self.radarwidget.show_apt < 3: self.radarwidget.show_apt += 1 else: self.radarwidget.show_apt = 0 elif self.sender() == self.showwpt: if self.radarwidget.show_wpt < 2: self.radarwidget.show_wpt += 1 else: self.radarwidget.show_wpt = 0 elif self.sender() == self.showlabels: self.radarwidget.show_lbl -= 1 if self.radarwidget.show_lbl < 0: self.radarwidget.show_lbl = 2 elif self.sender() == self.showmap: self.radarwidget.show_map = not self.radarwidget.show_map elif self.sender() == self.action_Save: manager.sendEvent(StackTextEvent(cmdtext='SAVEIC'))
def update_aircraft_data(self, data): if not self.initialized: return self.makeCurrent() curnode = self.nodedata[self.iactconn] if curnode.filteralt: idx = np.where((data.alt >= curnode.filteralt[0]) * (data.alt <= curnode.filteralt[1])) data.lat = data.lat[idx] data.lon = data.lon[idx] data.trk = data.trk[idx] data.alt = data.alt[idx] data.tas = data.tas[idx] data.vs = data.vs[idx] self.naircraft = len(data.lat) if self.naircraft == 0: self.cpalines.set_vertex_count(0) else: # Update data in GPU buffers update_buffer(self.aclatbuf, np.array(data.lat, dtype=np.float32)) update_buffer(self.aclonbuf, np.array(data.lon, dtype=np.float32)) update_buffer(self.achdgbuf, np.array(data.trk, dtype=np.float32)) update_buffer(self.acaltbuf, np.array(data.alt, dtype=np.float32)) update_buffer(self.actasbuf, np.array(data.tas, dtype=np.float32)) # CPA lines to indicate conflicts ncpalines = len(data.confcpalat) cpalines = np.zeros(4 * ncpalines, dtype=np.float32) self.cpalines.set_vertex_count(2 * ncpalines) # Labels and colors rawlabel = '' color = np.empty((self.naircraft, 4), dtype=np.uint8) selssd = np.zeros(self.naircraft, dtype=np.uint8) for i, acid in enumerate(data.id): vs = 30 if data.vs[i] > 0.25 else 31 if data.vs[i] < -0.25 else 32 # Make label: 3 lines of 8 characters per aircraft if self.show_lbl >= 1: rawlabel += '%-8s' % acid[:8] if self.show_lbl == 2: if data.alt[i] <= 4500. * ft: rawlabel += '%-5d' % int(data.alt[i]/ft + 0.5) else: rawlabel += 'FL%03d' % int(data.alt[i]/ft/100.+0.5) rawlabel += '%1s %-8d' % (chr(vs), int(data.cas[i] / kts+0.5)) else: rawlabel += 16 * ' ' confindices = data.iconf[i] if len(confindices) > 0: if self.ssd_conflicts: selssd[i] = 255 color[i, :] = palette.conflict + (255,) for confidx in confindices: cpalines[4 * confidx : 4 * confidx + 4] = [ data.lat[i], data.lon[i], data.confcpalat[confidx], data.confcpalon[confidx]] else: color[i, :] = palette.aircraft + (255,) # Check if aircraft is selected to show SSD if acid in self.ssd_ownship: selssd[i] = 255 if len(self.ssd_ownship) > 0 or self.ssd_conflicts: update_buffer(self.ssd.selssdbuf, selssd) update_buffer(self.confcpabuf, cpalines) update_buffer(self.accolorbuf, color) update_buffer(self.aclblbuf, np.array(rawlabel.encode('utf8'), dtype=np.string_)) # If there is a visible route, update the start position if self.route_acid != "": if self.route_acid in data.id: idx = data.id.index(self.route_acid) update_buffer(self.routebuf, np.array([data.lat[idx], data.lon[idx]], dtype=np.float32)) nact = self.nodedata[manager.sender()[0]] # Update trails database with new lines if data.swtrails: nact.traillat0.extend(data.traillat0) nact.traillon0.extend(data.traillon0) nact.traillat1.extend(data.traillat1) nact.traillon1.extend(data.traillon1) update_buffer(self.trailbuf, np.array( list(zip(nact.traillat0, nact.traillon0, nact.traillat1, nact.traillon1)) + list(zip(data.traillastlat, data.traillastlon, list(data.lat), list(data.lon))), dtype=np.float32)) self.traillines.set_vertex_count(2 * len(nact.traillat0) + 2 * len(data.lat)) else: nact.traillat0 = [] nact.traillon0 = [] nact.traillat1 = [] nact.traillon1 = [] self.traillines.set_vertex_count(0)