def setup(self): self.application = QtWidgets.QApplication(sys.argv) # Create an initital flight track. initial_waypoints = [ ft.Waypoint(flightlevel=0, location="EDMO", comments="take off OP"), ft.Waypoint(48.10, 10.27, 200), ft.Waypoint(52.32, 09.21, 200), ft.Waypoint(52.55, 09.99, 200), ft.Waypoint(flightlevel=0, location="Hamburg", comments="landing HH") ] waypoints_model = ft.WaypointsTableModel("") waypoints_model.insertRows(0, rows=len(initial_waypoints), waypoints=initial_waypoints) self.window = tv.MSSTableViewWindow(model=waypoints_model) self.window.show() QtWidgets.QApplication.processEvents() QtTest.QTest.qWaitForWindowExposed(self.window) QtWidgets.QApplication.processEvents()
def setup(self): self.application = QtWidgets.QApplication(sys.argv) self.port = PORTS.pop() self.tempdir = tempfile.mkdtemp() if not os.path.exists(self.tempdir): os.mkdir(self.tempdir) self.thread = multiprocessing.Process(target=application.run, args=("127.0.0.1", self.port)) self.thread.start() initial_waypoints = [ ft.Waypoint(40., 25., 0), ft.Waypoint(60., -10., 0), ft.Waypoint(40., 10, 0) ] waypoints_model = ft.WaypointsTableModel("") waypoints_model.insertRows(0, rows=len(initial_waypoints), waypoints=initial_waypoints) self.window = tv.MSSLinearViewWindow(model=waypoints_model) self.window.show() QtWidgets.QApplication.processEvents() QtTest.QTest.qWait(2000) QtTest.QTest.qWaitForWindowExposed(self.window) QtWidgets.QApplication.processEvents() self.window.cbTools.currentIndexChanged.emit(1) QtWidgets.QApplication.processEvents() self.wms_control = self.window.docks[0].widget() self.wms_control.multilayers.cbWMS_URL.setEditText("")
def _setup(self, widget_type): self.port = PORTS.pop() self.application = QtWidgets.QApplication(sys.argv) if widget_type == "hsec": self.view = HSecViewMockup() else: self.view = VSecViewMockup() self.tempdir = tempfile.mkdtemp() if not os.path.exists(self.tempdir): os.mkdir(self.tempdir) QtTest.QTest.qWait(3000) self.thread = multiprocessing.Process( target=application.run, args=("127.0.0.1", self.port)) self.thread.start() if widget_type == "hsec": self.window = wc.HSecWMSControlWidget(view=self.view, wms_cache=self.tempdir) else: initial_waypoints = [ft.Waypoint(40., 25., 0), ft.Waypoint(60., -10., 0), ft.Waypoint(40., 10, 0)] waypoints_model = ft.WaypointsTableModel("") waypoints_model.insertRows(0, rows=len(initial_waypoints), waypoints=initial_waypoints) self.window = wc.VSecWMSControlWidget( view=self.view, wms_cache=self.tempdir, waypoints_model=waypoints_model) self.window.show() QtWidgets.QApplication.processEvents() QtTest.QTest.qWait(2000) QtTest.QTest.qWaitForWindowExposed(self.window) QtTest.QTest.mouseClick(self.window.cbCacheEnabled, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents()
def setup(self): self.application = QtWidgets.QApplication(sys.argv) initial_waypoints = [ft.Waypoint(40., 25., 0), ft.Waypoint(60., -10., 0), ft.Waypoint(40., 10, 0)] waypoints_model = ft.WaypointsTableModel("") waypoints_model.insertRows( 0, rows=len(initial_waypoints), waypoints=initial_waypoints) self.window = tv.MSSTopViewWindow(model=waypoints_model) self.window.show() QtWidgets.QApplication.processEvents() QtTest.QTest.qWaitForWindowExposed(self.window) QtWidgets.QApplication.processEvents()
def _add_hexagon(self): table_view = self.view.tableWayPoints waypoints_model = self.view.waypoints_model params = self._get_parameters() if params["radius"] < 0.01: QtWidgets.QMessageBox.warning( self, "Add hexagon", "You cannot create a hexagon with zero radius!") return points = create_hexagon(params["center_lat"], params["center_lon"], params["radius"], params["angle"]) index = table_view.currentIndex() if not index.isValid(): row = 0 flightlevel = config_loader(dataset="new_flighttrack_flightlevel", default=mss_default.new_flighttrack_flightlevel) else: row = index.row() + 1 flightlevel = waypoints_model.waypoint_data(row - 1).flightlevel waypoints = [] for i, point in enumerate(points): waypoints.append( ft.Waypoint(lon=float(point[1]), lat=float(point[0]), flightlevel=float(flightlevel), comments="Hexagon {:d}".format(i + 1))) waypoints_model.insertRows(row, rows=len(waypoints), waypoints=waypoints) index = waypoints_model.index(row, 0) table_view.setCurrentIndex(index) table_view.resizeRowsToContents()
def cloneWaypoint(self): """ Handler for button <btCloneWaypoint>. Adds a new waypoint after the currently selected waypoint, with same data. """ tableView = self.tableWayPoints index = tableView.currentIndex() lon, lat = 0, 0 if not index.isValid(): row = 0 flightlevel = 0 else: row = index.row() + 1 wp = self.waypoints_model.waypoint_data(row - 1) lon = wp.lon lat = wp.lat flightlevel = self.waypoints_model.waypoint_data(row - 1).flightlevel self.waypoints_model.insertRows( row, waypoints=[ft.Waypoint(lat=lat, lon=lon, flightlevel=flightlevel)]) index = self.waypoints_model.index(row, 0) tableView = self.tableWayPoints tableView.setFocus() tableView.setCurrentIndex(index) # tableView.edit(index) tableView.resizeRowsToContents()
def addWayPoint(self): """ Handler for button <btAddWayPointToFlightTrack>. Adds a new waypoint behind the currently selected waypoint. """ tableView = self.tableWayPoints index = tableView.currentIndex() lon, lat = 0, 0 if not index.isValid(): row = 0 flightlevel = 0 else: row = index.row() + 1 flightlevel = self.waypoints_model.waypoint_data(row - 1).flightlevel if row < len(self.waypoints_model.all_waypoint_data()): wp_prev = self.waypoints_model.waypoint_data(row - 1) wp_next = self.waypoints_model.waypoint_data(row) gc = pyproj.Geod(ellps="WGS84") # a=40e6, b=40e6) lon, lat = gc.npts(wp_prev.lon, wp_prev.lat, wp_next.lon, wp_next.lat, 3)[1] self.waypoints_model.insertRows( row, waypoints=[ft.Waypoint(lat=lat, lon=lon, flightlevel=flightlevel)]) index = self.waypoints_model.index(row, 0) tableView = self.tableWayPoints tableView.setFocus() tableView.setCurrentIndex(index) # tableView.edit(index) tableView.resizeRowsToContents()
def button_release_insert_callback(self, event): """Called whenever a mouse button is released. From the click event's coordinates, best_index is calculated as the index of a vertex whose x coordinate > clicked x coordinate. This is the position where the waypoint is to be inserted. 'lat' and 'lon' are calculated as an average of each of the first waypoint in left and right neighbourhood of inserted waypoint. The coordinates are checked against "locations" defined in mss' config. A new waypoint with the coordinates, and name is inserted into the waypoints_model. """ if not self.showverts or event.button != 1 or event.inaxes is None: return y = event.ydata wpm = self.waypoints_model flightlevel = float(pressure2flightlevel(y)) [lat, lon], best_index = self.get_lat_lon(event) loc = find_location( lat, lon) # skipped tolerance which uses appropriate_epsilon_km if loc is not None: (lat, lon), location = loc else: location = "" new_wp = ft.Waypoint(lat, lon, flightlevel, location=location) wpm.insertRows(best_index, rows=1, waypoints=[new_wp]) self.redraw_figure() self._ind = None
def load_from_csv(filename): waypoints = [] _dirname, _name = os.path.split(filename) _fs = open_fs(_dirname) with _fs.open(_name, "rb") as in_file: lines = in_file.readlines() if len(lines) < 4: raise SyntaxError("CSV file requires at least 4 lines!") dialect = csv.Sniffer().sniff(lines[-1].decode("utf-8")) csv_reader = csv.reader(lines, encoding="utf-8", dialect=dialect) name = next(csv_reader)[0] next(csv_reader) # header for row in csv_reader: wp = ft.Waypoint() wp.location = row[1] wp.lat = float(row[2]) wp.lon = float(row[3]) wp.flightlevel = float(row[4]) wp.pressure = float(row[5]) * 100. wp.distance_to_prev = float(row[6]) wp.distance_total = float(row[7]) wp.comments = row[8] waypoints.append(wp) name = os.path.basename(filename.replace(".csv", "").strip()) return name, waypoints
def _setup(self, widget_type): wc.WMS_SERVICE_CACHE = {} self.port = PORTS.pop() self.application = QtWidgets.QApplication(sys.argv) if widget_type == "hsec": self.view = HSecViewMockup() else: self.view = VSecViewMockup() self.tempdir = tempfile.mkdtemp() if not os.path.exists(self.tempdir): os.mkdir(self.tempdir) QtTest.QTest.qWait(3000) self.thread = multiprocessing.Process(target=application.run, args=("127.0.0.1", self.port)) self.thread.start() if widget_type == "hsec": self.window = wc.HSecWMSControlWidget(view=self.view, wms_cache=self.tempdir) else: initial_waypoints = [ ft.Waypoint(40., 25., 0), ft.Waypoint(60., -10., 0), ft.Waypoint(40., 10, 0) ] waypoints_model = ft.WaypointsTableModel("") waypoints_model.insertRows(0, rows=len(initial_waypoints), waypoints=initial_waypoints) self.window = wc.VSecWMSControlWidget( view=self.view, wms_cache=self.tempdir, waypoints_model=waypoints_model) self.window.show() # Remove all previous cached URLs for url in self.window.multilayers.layers.copy(): server = self.window.multilayers.listLayers.findItems( url, QtCore.Qt.MatchFixedString)[0] self.window.multilayers.delete_server(server) QtWidgets.QApplication.processEvents() QtTest.QTest.qWait(2000) QtTest.QTest.qWaitForWindowExposed(self.window) QtTest.QTest.mouseClick(self.window.cbCacheEnabled, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents()
def load_from_txt(filename): name = os.path.basename(filename.replace(".txt", "").strip()) waypoints = [] _dirname, _name = os.path.split(filename) _fs = open_fs(_dirname) with _fs.open(_name, "r") as in_file: pos = [] for line in in_file: if line.startswith("#"): continue if line.startswith("Index"): pos.append(0) # 0 pos.append(line.find("Location")) # 1 pos.append(line.find("Lat (+-90)")) # 2 pos.append(line.find("Lon (+-180)")) # 3 pos.append(line.find("Flightlevel")) # 4 pos.append(line.find("Pressure (hPa)")) # 5 pos.append(line.find("Leg dist. (km)")) # 6 pos.append(line.find("Cum. dist. (km)")) # 7 pos.append(line.find("Comments")) # 8 continue if line.startswith("Track name: "): continue if len(pos) == 0: raise SyntaxError( "TXT Import could not parse column headings.") if len(line) < max(pos): raise SyntaxError(f"TXT Import could not parse line: '{line}'") wp = ft.Waypoint() attr_names = [ "location", "lat", "lon", "flightlevel", "pressure", "distance_to_prev", "distance_total", "comments" ] setattr(wp, attr_names[0], line[pos[1]:pos[2]].strip()) setattr(wp, attr_names[7], line[pos[8]:].strip()) for i in range(2, len(pos) - 1): if pos[i] >= 0: if i == 5: setattr(wp, attr_names[i - 1], float(line[pos[i]:pos[i + 1]].strip()) * 100.) else: setattr(wp, attr_names[i - 1], float(line[pos[i]:pos[i + 1]].strip())) else: if i == 5: logging.debug('calculate pressure from FL ' + str( thermolib.flightlevel2pressure( float(wp.flightlevel) * units.hft).magnitude)) setattr( wp, attr_names[i - 1], thermolib.flightlevel2pressure( float(wp.flightlevel) * units.hft).magnitude) waypoints.append(wp) return name, waypoints
def make_roundtrip(self): """ Copies the first waypoint and inserts it at the back of the list again Essentially creating a roundtrip """ # This case should never be True for users, but might be for developers at some point if not self.is_roundtrip_possible(): return first_waypoint = self.waypoints_model.waypoint_data(0) self.waypoints_model.insertRows(self.waypoints_model.rowCount(), rows=1, waypoints=[ ft.Waypoint(lat=first_waypoint.lat, lon=first_waypoint.lon, flightlevel=first_waypoint.flightlevel, location=first_waypoint.location)])
def button_release_insert_callback(self, event): """Called whenever a mouse button is released. From the click event's coordinates, best_index is calculated if it can be optimally fit as a prior waypoint in the path. A vertex with same coordinates is inserted into the path in canvas. The coordinates are checked against "locations" defined in mss' config. A new waypoint with the coordinates, and name is inserted into the waypoints_model. """ if not self.showverts or event.button != 1 or event.inaxes is None: return # Get position for new vertex. x, y = event.xdata, event.ydata best_index = self.pathpatch.get_path().index_of_closest_segment( x, y, eps=self.appropriate_epsilon()) logging.debug( "TopView insert point: clicked at (%f, %f), " "best index: %d", x, y, best_index) self.pathpatch.get_path().insert_vertex(best_index, [x, y], WaypointsPath.LINETO) lon, lat = self.map(x, y, inverse=True) loc = find_location(lat, lon, tolerance=self.appropriate_epsilon_km(px=15)) if loc is not None: (lat, lon), location = loc else: location = "" wpm = self.waypoints_model if len(wpm.all_waypoint_data()) > 0 and 0 < best_index <= len( wpm.all_waypoint_data()): flightlevel = wpm.waypoint_data(best_index - 1).flightlevel elif len(wpm.all_waypoint_data()) > 0 and best_index == 0: flightlevel = wpm.waypoint_data(0).flightlevel else: logging.error("Cannot copy flightlevel. best_index: %s, len: %s", best_index, len(wpm.all_waypoint_data())) flightlevel = 0 new_wp = ft.Waypoint(lat, lon, flightlevel, location=location) wpm.insertRows(best_index, rows=1, waypoints=[new_wp]) self.redraw_path() self._ind = None
def create_new_flight_track(self, template=None, filename=None): """Creates a new flight track model from a template. Adds a new entry to the list of flight tracks. Called when the user selects the 'new/open flight track' menu entries. Arguments: template -- copy the specified template to the new flight track (so that it is not empty). filename -- if not None, load the flight track in the specified file. """ if template is None: template = [] waypoints = config_loader(dataset="new_flighttrack_template") default_flightlevel = config_loader( dataset="new_flighttrack_flightlevel") for wp in waypoints: template.append( ft.Waypoint(flightlevel=default_flightlevel, location=wp)) if len(template) < 2: QtWidgets.QMessageBox.critical( self, self.tr("flighttrack template"), self. tr("ERROR:Flighttrack template in configuration is too short. " "Please add at least two valid locations.")) if filename is not None: waypoints_model = ft.WaypointsTableModel(filename=filename) else: # Create a new flight track from the waypoints template. self.new_flight_track_counter += 1 waypoints_model = ft.WaypointsTableModel( name=f"new flight track ({self.new_flight_track_counter:d})") # Make a copy of the template. Otherwise all new flight tracks would # use the same data structure in memory. template_copy = copy.deepcopy(template) waypoints_model.insertRows(0, rows=len(template_copy), waypoints=template_copy) # Create a new list entry for the flight track. Make the item name # editable. listitem = QFlightTrackListWidgetItem(waypoints_model, self.listFlightTracks) listitem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.activate_flight_track(listitem)
def load_from_flitestar(filename): waypoints = [] _dirname, _name = os.path.split(filename) _fs = open_fs(_dirname) with _fs.open(_name, 'r') as f: firstline = f.readline() if not firstline.startswith( "# FliteStar/FliteMap generated flight plan."): raise SyntaxError("The file does not seem to be a FliteStar file!") for line in f: if line.startswith('FWP'): line = line.split() if len(line) < 10: raise SyntaxError(f"Line {line} has less than 9 fields.") alt = round(float(line[-1]) / 100., 2) if line[4] == 'N': NS = 1. elif line[4] == 'S': NS = -1. else: NS = np.nan lat = round((float(line[5]) + (float(line[6]) / 60.)) * NS, 3) if line[7] == 'E': EW = 1. elif line[7] == 'W': EW = -1. else: EW = np.nan lon = round((float(line[8]) + (float(line[9]) / 60.)) * EW, 3) wp = ft.Waypoint() wp.location = line[3] wp.lat = float(lat) wp.lon = float(lon) wp.flightlevel = float(alt) wp.pressure = thermolib.flightlevel2pressure( float(wp.flightlevel)) waypoints.append(wp) name = os.path.basename(filename).strip('.txt') return name, waypoints