def new_departure_DEP(self, goal_point):
     acft_type = choice(
         self.parkable_aircraft_types if self.parkable_aircraft_types != []
         else self.playable_aircraft_types)
     rwy = rnd_rwy([
         rwy
         for rwy in env.airport_data.allRunways() if rwy.use_for_departures
     ], lambda rwy: rwy.acceptsAcftType(acft_type))
     if rwy == None:
         return None
     thr = rwy.threshold()
     hdg = rwy.orientation()
     pos = thr.moved(hdg, settings.solo_TWR_range_dist)
     try:  # Check for separation
         horiz_dist = [
             pos.distanceTo(acft.params.position)
             for acft in self.controlled_traffic if acft.isOutboundGoal()
         ]
         if time_to_fly(min(horiz_dist),
                        cruise_speed(acft_type)) < TTF_separation:
             return None
     except ValueError:
         pass  # No departures in the sky yet
     alt = GS_alt(env.elevation(thr), rwy.param_FPA, pos.distanceTo(thr))
     ias = restrict_speed_under_ceiling(cruise_speed(acft_type), alt,
                                        StdPressureAlt.fromFL(100))
     params = SoloParams(Status(Status.AIRBORNE), pos, alt, hdg, ias)
     params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_DEP)
     acft = self.mkAiAcft(acft_type, params, (goal_point, None))
     acft.instructions.append(
         Instruction(Instruction.VECTOR_ALT,
                     arg=settings.solo_initial_climb_reading))
     return acft
    def transitionLevel(self):
        '''
		Returns the lowest FL above the TA.
		This is NOT the lowest assignable, which takes more vertical separation
		'''
        return StdPressureAlt.fromAMSL(self.transitionAltitude(),
                                       self.QNH()).FL() + 1
Example #3
0
 def altitudeInstruction(self):
     qnh = env.QNH()
     alt = self.radar_contact.xpdrAlt()
     if alt == None:
         zero_cursor_ft = 0 if self.radar_contact.xpdrGND(
         ) else env.transitionAltitude()
     else:
         zero_cursor_ft = alt.ftAMSL(qnh)
     return env.readStdAlt(StdPressureAlt.fromAMSL(
         max(0, zero_cursor_ft + self.diff_alt_measured), qnh),
                           step=5,
                           unit=True)
    def assignedPressureAlt(self, qnh):
        '''
		returns the StdPressureAlt of the assigned_altitude_detail if valid
		returns None if None or invalid
		'''
        assAlt = self.lookup(assigned_altitude_detail)  # str reading
        if assAlt == None:
            return None
        try:
            return StdPressureAlt.fromReading(assAlt, qnh)
        except ValueError:
            return None
 def spawnNewUncontrolledAircraft(self):
     rndpos = env.radarPos().moved(Heading(randint(1, 360), True),
                                   uniform(10, .8 * settings.radar_range))
     rndalt = StdPressureAlt(randint(1, 10) * 1000)
     if self.airbornePositionFullySeparated(rndpos, rndalt):
         acft_type = choice(self.uncontrolled_aircraft_types)
         params = SoloParams(Status(Status.AIRBORNE), rndpos, rndalt,
                             Heading(randint(1, 360), True),
                             cruise_speed(acft_type))
         params.XPDR_code = settings.uncontrolled_VFR_XPDR_code
         new_acft = self.mkAiAcft(acft_type, params, goal=None)
         if new_acft != None:
             self.uncontrolled_traffic.append(new_acft)
 def new_arrival_APP(self, entry_point):
     type_choice = self.parkable_aircraft_types if self.parkable_aircraft_types != [] else self.playable_aircraft_types
     # must be landable too
     rwy_choice = [
         rwy for rwy in env.airport_data.allRunways()
         if rwy.use_for_arrivals
     ]
     if rwy_choice == []:
         rwy_choice = env.airport_data.allRunways()
     pop_all(
         type_choice,
         lambda t: all(not rwy.acceptsAcftType(t) for rwy in rwy_choice))
     if type_choice == []:
         return None
     acft_type = choice(type_choice)
     ils = any(rwy.hasILS() for rwy in
               rwy_choice) and random() >= settings.solo_ILSvsVisual_balance
     if entry_point == None:
         hdg = Heading(randint(1, 360), True)
         pos = env.radarPos().moved(
             hdg.opposite(),
             uniform(.33 * settings.radar_range,
                     .75 * settings.radar_range))
     else:
         pos = entry_point.coordinates
         hdg = pos.headingTo(env.radarPos())
     alt = StdPressureAlt.fromFL(
         10 * randint(settings.solo_APP_ceiling_FL_min // 10,
                      settings.solo_APP_ceiling_FL_max // 10))
     if not self.airbornePositionFullySeparated(pos, alt):
         return None
     ias = restrict_speed_under_ceiling(
         cruise_speed(acft_type), alt,
         StdPressureAlt.fromFL(150))  # 5000-ft anticipation
     params = SoloParams(Status(Status.AIRBORNE), pos, alt, hdg, ias)
     params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_ARR)
     return self.mkAiAcft(acft_type, params, ils)
 def xpdrData(self):
     res = {}
     if self.params.XPDR_mode != '0':
         res[Xpdr.CODE] = self.params.XPDR_code
         res[Xpdr.IDENT] = self.params.XPDR_idents
     if self.params.XPDR_mode not in '0A':
         res[Xpdr.ALT] = StdPressureAlt(
             rounded(self.params.altitude.ft1013(),
                     step=(100 if self.params.XPDR_mode == 'C' else 10)))
     if self.params.XPDR_mode not in '0AC':
         res[Xpdr.IAS] = self.params.ias
         res[Xpdr.GND] = self.xpdrGndBit()
         res[Xpdr.CALLSIGN] = self.identifier
         res[Xpdr.ACFT] = self.aircraft_type
     return res
 def handoverGuard(self, acft, next_atc):
     # Bad or untimely handovers
     if next_atc == 'Ramp':
         if acft.statusType() != Status.TAXIING:
             return 'Ramp only accepts taxiing aircraft.'
         if not acft.isInboundGoal():
             return 'This aircraft is outbound!'
         if not acft.canPark():
             return 'Bring aircraft close to parking position before handing over to ramp.'
     elif next_atc == 'GND':
         if acft.statusType() != Status.TAXIING:
             return 'Ground only accepts taxiing aircraft.'
     elif next_atc == 'TWR':
         if acft.isInboundGoal():
             if not inTWRrange(acft.params):
                 return 'Not in TWR range.'
         else:
             if not acft.statusType() != Status.READY:
                 return 'Aircraft has not reported ready for departure.'
     elif next_atc == 'APP':
         if not acft.isInboundGoal():
             return 'Why hand over to APP?!'
         elif inTWRrange(acft.params):
             return 'This aircraft is in TWR range.'
     elif next_atc == 'DEP':
         if acft.isInboundGoal():
             return 'DEP only controls departures!'
         elif inTWRrange(acft.params):
             return 'TWR must keep control of aircraft until they fly out of tower range.'
     elif next_atc == 'CTR':
         if acft.isInboundGoal():
             return 'This aircraft is inbound your airport.'
         if settings.solo_role_DEP:
             point, alt = acft.goal
             if point != None and acft.params.position.distanceTo(
                     point.coordinates) > exit_point_tolerance:
                 return 'Not close enough to exit point'
             if acft.params.altitude.diff(
                     StdPressureAlt.fromFL(
                         settings.solo_APP_ceiling_FL_min)) < 0:
                 return 'Not high enough for CTR: reach FL%03d before handing over.' % settings.solo_APP_ceiling_FL_min
         else:
             return 'You should not be handing over to the centre directly.'
     else:
         print(
             'INTERNAL ERROR: Please report unexpected ATC name "%s" in solo mode'
             % next_atc)
Example #9
0
	def acftInitParams(self):
		if self.ground_status_radioButton.isChecked():
			status = Status(Status.TAXIING)
		elif self.ready_status_radioButton.isChecked():
			status = Status(Status.READY, arg=self.depRWY_select.currentText())
		else: # airborne status radio button must be ticked
			status = Status(Status.AIRBORNE)
		pos = self.spawn_coords
		hdg = self.spawn_hdg
		if self.airborne_status_radioButton.isChecked():
			ias = cruise_speed(self.createAircraftType_edit.getAircraftType())
			alt = StdPressureAlt.fromFL(self.airborneFL_edit.value())
		else: # on ground
			ias = Speed(0)
			alt = env.groundStdPressureAlt(pos)
			if self.parked_tickBox.isChecked() and self.closest_PKG != None:
				pkinf = env.airport_data.ground_net.parkingPosInfo(self.closest_PKG)
				pos = pkinf[0]
				hdg = pkinf[1]
		return SoloParams(status, pos, alt, hdg, ias)
Example #10
0
 def saveChangesAndClose(self):
     SharedDetailSheet.saveChangesAndClose(self)
     ## Assigned stuff
     # Squawk code
     if self.assignSquawkCode.isChecked():
         self.set_detail(assigned_SQ_detail, self.xpdrCode_select.getSQ())
     else:
         self.set_detail(assigned_SQ_detail, None)
     # Heading
     if self.assignHeading.isChecked():
         self.set_detail(assigned_heading_detail,
                         Heading(self.assignedHeading_edit.value(), False))
     else:
         self.set_detail(assigned_heading_detail, None)
     # Altitude/FL
     if self.assignAltitude.isChecked():
         reading = self.assignedAltitude_edit.text()
         try:  # try reformating
             self.set_detail(assigned_altitude_detail,
                             StdPressureAlt.reformatReading(reading))
         except ValueError:
             self.set_detail(assigned_altitude_detail, reading)
     else:
         self.set_detail(assigned_altitude_detail, None)
     # Speed
     if self.assignSpeed.isChecked():
         self.set_detail(assigned_speed_detail,
                         Speed(self.assignedSpeed_edit.value()))
     else:
         self.set_detail(assigned_speed_detail, None)
     # DONE with details
     if self.strip.linkedFPL() == None:
         if self.linkFPL_tickBox.isChecked():
             if self.FPL_link_on_save == None:
                 signals.newLinkedFPLrequest.emit(self.strip)
             else:
                 self.strip.linkFPL(self.FPL_link_on_save)
     else:  # a flight plan is already linked
         if self.pushToFPL_tickBox.isChecked():
             self.strip.pushToFPL()
     self.accept()
 def groundStdPressureAlt(self, coords):
     return StdPressureAlt.fromAMSL(self.elevation(coords), self.QNH())
def infoTextLines(radar_contact, compact_display):
    strip = env.linkedStrip(radar_contact)

    # FL/ALT. & SPEED LINE
    ass_alt = None if strip == None else strip.lookup(assigned_altitude_detail)
    if ass_alt != None:
        try:
            ass_alt = StdPressureAlt.reformatReading(ass_alt, unit=False)
        except ValueError:
            ass_alt = None
    if settings.SSR_mode_capability in '0A':
        fl_speed_line = ''
    else:  # we may hope for altitude values from XPDR
        if radar_contact.xpdrGND():
            fl_speed_line = 'GND '
        else:
            xpdr_alt = radar_contact.xpdrAlt()
            if xpdr_alt == None:
                fl_speed_line = 'alt? '
            else:
                if settings.radar_tag_interpret_XPDR_FL:
                    alt_str = env.readStdAlt(xpdr_alt, unit=False)
                else:
                    alt_str = '%03d' % xpdr_alt.FL()
                vs = radar_contact.verticalSpeed()
                if vs == None:
                    comp_char = '-'
                elif abs(vs) < vertical_speed_sensitivity:
                    comp_char = '='
                elif vs > 0:
                    comp_char = '↗'
                else:
                    comp_char = '↘'
                fl_speed_line = '%s %c ' % (alt_str, comp_char)
    if ass_alt != None:
        fl_speed_line += ass_alt
    fl_speed_line += '  '
    if strip != None:
        fl_speed_line += some(strip.lookup(FPL.WTC, fpl=True), '')
    speed = radar_contact.groundSpeed()
    if speed != None:
        fl_speed_line += '%03d' % speed.kt

    # XPDR CODE || WAYPOINT/DEST LINE
    xpdr_code = radar_contact.xpdrCode()
    emg = False if xpdr_code == None else xpdr_code in XPDR_emergency_codes
    if emg or strip == None:  # Show XPDR code
        sq_wp_line = '' if xpdr_code == None else '%04o' % xpdr_code
        if emg:
            sq_wp_line += '  !!EMG'
    else:
        parsed_route = strip.lookup(parsed_route_detail)
        if parsed_route == None:
            dest = some(strip.lookup(FPL.ICAO_ARR, fpl=True), '')
            try:
                ad = world_navpoint_db.findAirfield(dest)
                sq_wp_line = '%s  %s°' % (ad.code,
                                          radar_contact.coords().headingTo(
                                              ad.coordinates).read())
            except NavpointError:  # not an airport
                sq_wp_line = dest
        else:  # got parsed route
            leg = parsed_route.currentLegIndex(radar_contact.coords())
            if leg == 0 and parsed_route.SID() != None:
                sq_wp_line = 'SID %s' % parsed_route.SID()
            elif leg == parsed_route.legCount() - 1 and parsed_route.STAR(
            ) != None:
                sq_wp_line = 'STAR %s' % parsed_route.STAR()
            else:
                wp = parsed_route.waypoint(leg)
                sq_wp_line = '%s  %s°' % (wp.code,
                                          radar_contact.coords().headingTo(
                                              wp.coordinates).read())

    result_lines = [
        sq_wp_line, fl_speed_line
    ] if settings.radar_tag_FL_at_bottom else [fl_speed_line, sq_wp_line]

    # CALLSIGN & ACFT TYPE LINE (top line, only if NOT compact display)
    if not compact_display:
        line1 = ''
        cs = radar_contact.xpdrCallsign()
        if cs == None and strip != None:
            cs = strip.callsign(fpl=True)
        if settings.session_manager.session_type == SessionType.TEACHER:
            dl = env.cpdlc.currentDataLink(radar_contact.identifier)
        else:
            dl = None if cs == None else env.cpdlc.currentDataLink(cs)
        if dl != None:
            line1 += {
                ConnectionStatus.OK: '⚡ ',
                ConnectionStatus.EXPECTING: '[⚡] ',
                ConnectionStatus.PROBLEM: '!![⚡] '
            }[dl.status()]
        line1 += some(cs, '?')
        if strip != None and strip.lookup(FPL.COMMENTS) != None:
            line1 += '*'
        if radar_contact.xpdrIdent():
            line1 += '  !!ident'
        t = radar_contact.xpdrAcftType()
        if t == None and strip != None:
            t = strip.lookup(FPL.ACFT_TYPE, fpl=True)
        if t != None:
            line1 += '  %s' % t
        result_lines.insert(0, line1)

    return '\n'.join(result_lines)
    def generateAircraftAndStrip(self):
        start_angle = uniform(0, 360)
        start_pos = env.radarPos().moved(Heading(start_angle, True),
                                         settings.solo_CTR_range_dist)
        end_pos = env.radarPos().moved(
            Heading(start_angle + 90 + uniform(1, 179), True),
            settings.solo_CTR_range_dist)
        transit_hdg = start_pos.headingTo(end_pos)
        dep_ad = world_navpoint_db.findClosest(env.radarPos().moved(transit_hdg.opposite(), \
          uniform(1.2 * settings.map_range, 5000)), types=[Navpoint.AD])
        dest_ad = world_navpoint_db.findClosest(env.radarPos().moved(transit_hdg, \
          uniform(1.2 * settings.map_range, 5000)), types=[Navpoint.AD])
        if env.pointOnMap(dep_ad.coordinates) or env.pointOnMap(
                dest_ad.coordinates):
            return None, None

        candidate_midpoints = [p for code in settings.solo_CTR_routing_points \
          for p in env.navpoints.findAll(code, types=[Navpoint.NDB, Navpoint.VOR, Navpoint.FIX]) \
          if start_pos.distanceTo(p.coordinates) < start_pos.distanceTo(end_pos)]
        midpoint = None if candidate_midpoints == [] else choice(
            candidate_midpoints)

        FLd10 = randint(settings.solo_CTR_floor_FL // 10,
                        settings.solo_CTR_ceiling_FL // 10)
        if settings.solo_CTR_semi_circular_rule == SemiCircRule.E_W and (FLd10 % 2 == 0) != (transit_hdg.magneticAngle() >= 180) \
         or settings.solo_CTR_semi_circular_rule == SemiCircRule.N_S and (FLd10 % 2 == 1) != (90 <= transit_hdg.magneticAngle() < 270):
            FLd10 += 1
            if 10 * FLd10 > settings.solo_CTR_ceiling_FL:
                return None, None
        p_alt = StdPressureAlt.fromFL(10 * FLd10)
        if not self.airbornePositionFullySeparated(start_pos, p_alt):
            return None, None
        acft_type = choice(self.playable_aircraft_types)
        hdg = start_pos.headingTo(some(midpoint, dest_ad).coordinates)
        params = SoloParams(Status(Status.AIRBORNE), start_pos, p_alt, hdg,
                            cruise_speed(acft_type))
        params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_transit)
        new_acft = self.mkAiAcft(acft_type, params, dest_ad)
        dist_key = lambda atc: env.ATCs.getATC(atc).position.distanceTo(
            start_pos)
        received_from = min(env.ATCs.knownATCs(), key=dist_key)

        strip = Strip()
        strip.writeDetail(FPL.CALLSIGN, new_acft.identifier)
        strip.writeDetail(FPL.ACFT_TYPE, new_acft.aircraft_type)
        strip.writeDetail(FPL.WTC, wake_turb_cat(new_acft.aircraft_type))
        strip.writeDetail(FPL.FLIGHT_RULES, 'IFR')
        strip.writeDetail(FPL.ICAO_DEP, dep_ad.code)
        strip.writeDetail(FPL.ICAO_ARR, dest_ad.code)
        strip.writeDetail(FPL.CRUISE_ALT,
                          env.readStdAlt(new_acft.params.altitude))
        strip.writeDetail(assigned_altitude_detail,
                          strip.lookup(FPL.CRUISE_ALT))
        strip.writeDetail(assigned_SQ_detail, new_acft.params.XPDR_code)
        strip.writeDetail(received_from_detail, received_from)
        if midpoint != None:
            strip.insertRouteWaypoint(midpoint)

        new_acft.instructions.append(
            Instruction(Instruction.FOLLOW_ROUTE,
                        arg=strip.lookup(parsed_route_detail).dup()))
        return new_acft, strip
 def stdPressureAlt(self, reading):
     return StdPressureAlt.fromReading(reading, self.QNH())
def inTWRrange(params):
    return params.position.distanceTo(env.radarPos()) <= settings.solo_TWR_range_dist \
     and params.altitude.diff(StdPressureAlt.fromFL(settings.solo_TWR_ceiling_FL)) < 0
	def saveRadarSnapshot(self):
		prev = self.lastSnapshot() # always exists
		if prev.time_stamp == self.live_update_time:
			return # No point saving values again: they were not updated since last snapshot
		
		# otherwise create a new snapshot
		snapshot = RadarSnapshot(self.live_update_time, self.liveCoords(), self.liveGeometricAlt())
		snapshot.xpdrData = self.live_XPDR_data.copy()
		if settings.radar_cheat or self.individual_cheat:
			# We try to compensate, but cannot always win so None values are possible.
			# Plus: CODE, IDENT and GND have no useful compensation.
			if Xpdr.ALT not in snapshot.xpdrData:
				stdpa = StdPressureAlt.fromAMSL(snapshot.geometric_alt, env.QNH())
				snapshot.xpdrData[Xpdr.ALT] = StdPressureAlt(stdpa.ft1013())
			if Xpdr.CALLSIGN not in snapshot.xpdrData:
				snapshot.xpdrData[Xpdr.CALLSIGN] = self.identifier
			if Xpdr.ACFT not in snapshot.xpdrData:
				snapshot.xpdrData[Xpdr.ACFT] = self.aircraft_type
		else: # contact is not cheated
			if settings.SSR_mode_capability == '0': # no SSR so no XPDR data can be snapshot
				snapshot.xpdrData.clear()
			else: # SSR on; check against A/C/S capability
				if settings.SSR_mode_capability == 'A': # radar does not have the capability to pick up altitude
					if Xpdr.ALT in snapshot.xpdrData:
						del snapshot.xpdrData[Xpdr.ALT]
				if settings.SSR_mode_capability != 'S': # radar does not have mode S interrogation capability
					for k in (Xpdr.CALLSIGN, Xpdr.ACFT, Xpdr.IAS, Xpdr.GND):
						if k in snapshot.xpdrData:
							del snapshot.xpdrData[k]
		
		# Inferred values
		if self.frozen: # copy from previous snapshot
			snapshot.heading = prev.heading
			snapshot.groundSpeed = prev.groundSpeed
			snapshot.verticalSpeed = prev.verticalSpeed
		else: # compute values from change between snapshots
			# Search history for best snapshot to use for diff
			diff_seconds = (snapshot.time_stamp - prev.time_stamp).total_seconds()
			i = 1 # index of currently selected prev
			while i < len(self.radar_snapshots) and diff_seconds < snapshot_diff_time:
				i += 1
				prev = self.radar_snapshots[-i]
				diff_seconds = (snapshot.time_stamp - prev.time_stamp).total_seconds()
			# Fill snapshot diffs
			if prev.coords != None and snapshot.coords != None:
				# ground speed
				snapshot.groundSpeed = Speed(prev.coords.distanceTo(snapshot.coords) * 3600 / diff_seconds)
				# heading
				if snapshot.groundSpeed != None and snapshot.groundSpeed.diff(min_taxiing_speed) > 0: # acft moving across the ground
					try: snapshot.heading = snapshot.coords.headingFrom(prev.coords)
					except ValueError: snapshot.heading = prev.heading # stopped: keep prev. hdg
				else:
					snapshot.heading = prev.heading
			# vertical speed
			prev_alt = prev.xpdrData.get(Xpdr.ALT, None)
			this_alt = snapshot.xpdrData.get(Xpdr.ALT, None)
			if prev_alt != None and this_alt != None:
				snapshot.verticalSpeed = (this_alt.diff(prev_alt)) * 60 / diff_seconds
		
		# Append snapshot to history
		self.radar_snapshots.append(snapshot)
		if len(self.radar_snapshots) > snapshot_history_size:
			del self.radar_snapshots[0]
Example #17
0
    def storeSettings(self):
        ## CHECK SETTINGS FIRST
        try:
            new_ranges = []
            for i in range(len(self.range_group_boxes)):
                if self.range_group_boxes[i].isChecked():
                    name = self.range_name_edits[i].text()
                    if any(rng.name == name for rng in new_ranges):
                        raise ValueError('Duplicate range name')
                    colour = self.range_col_edits[i].getChoice()
                    new_ranges.append(
                        XpdrAssignmentRange(name,
                                            self.range_lo_edits[i].value(),
                                            self.range_hi_edits[i].value(),
                                            colour))
        except ValueError as err:
            QMessageBox.critical(self, 'Assignment range error', str(err))
            return
        if env.airport_data == None:
            try:
                bad = next(p for p in self.routingPoints_edit.text().split()
                           if len(env.navpoints.findAll(code=p)) != 1)
                QMessageBox.critical(
                    self, 'Invalid entry',
                    'Unknown navpoint or navpoint not unique: %s' % bad)
                return
            except StopIteration:
                pass  # no bad navpoints
        else:
            try:
                alt_reading = StdPressureAlt.reformatReading(
                    self.initialClimb_edit.text())
            except ValueError:
                QMessageBox.critical(
                    self, 'Invalid entry',
                    'Could not read altitude or level for default initial climb.'
                )
                return

        ## ALL SETTINGS OK. Save them and accept the dialog.
        GeneralSettingsDialog.last_tab_used = self.settings_tabs.currentIndex()

        if env.airport_data != None:
            for i in range(self.runway_tabs.count()):
                self.runway_tabs.widget(i).applyToRWY()

        settings.SSR_mode_capability = '0' if self.capability_noSSR_radioButton.isChecked() \
          else 'A' if self.capability_modeA_radioButton.isChecked() \
          else 'C' if self.capability_modeC_radioButton.isChecked() else 'S'
        settings.radar_range = self.radarHorizontalRange_edit.value()
        settings.radar_signal_floor_level = self.radarFloor_edit.value()
        settings.radar_sweep_interval = timedelta(
            seconds=self.radarUpdateInterval_edit.value())
        settings.radio_direction_finding = self.radioDirectionFinding_tickBox.isChecked(
        )
        settings.controller_pilot_data_link = self.cpdlc_tickBox.isChecked()
        settings.auto_print_strips_include_DEP = self.stripAutoPrint_DEP_tickBox.isChecked(
        )
        settings.auto_print_strips_include_ARR = self.stripAutoPrint_ARR_tickBox.isChecked(
        )
        settings.auto_print_strips_IFR_only = self.stripAutoPrint_ifrOnly_tickBox.isChecked(
        )
        settings.auto_print_strips_anticipation = timedelta(
            minutes=self.stripAutoPrint_leadTime_edit.value())

        settings.vertical_separation = self.verticalSeparation_edit.value()
        settings.conflict_warning_floor_FL = self.conflictWarningFloorFL_edit.value(
        )
        settings.location_radio_name = self.radioName_edit.text()
        settings.transition_altitude = self.transitionAltitude_edit.value(
        )  # NOTE useless if a TA is set in apt.dat
        settings.uncontrolled_VFR_XPDR_code = self.uncontrolledVFRcode_edit.value(
        )
        settings.horizontal_separation = self.horizontalSeparation_edit.value()

        settings.XPDR_assignment_ranges = new_ranges

        if env.airport_data == None:  # CTR mode
            settings.solo_CTR_floor_FL = self.spawnCTR_minFL_edit.value()
            settings.solo_CTR_ceiling_FL = self.spawnCTR_maxFL_edit.value()
            settings.solo_CTR_range_dist = self.CTRrangeDistance_edit.value()
            settings.solo_CTR_routing_points = self.routingPoints_edit.text(
            ).split()
            settings.solo_CTR_semi_circular_rule = self.selectedSemiCircRule()
        else:  # AD mode
            settings.solo_APP_ceiling_FL_min = self.spawnAPP_minFL_edit.value(
            ) // 10 * 10
            settings.solo_APP_ceiling_FL_max = (
                (self.spawnAPP_maxFL_edit.value() - 1) // 10 + 1) * 10
            settings.solo_TWR_range_dist = self.TWRrangeDistance_edit.value()
            settings.solo_TWR_ceiling_FL = self.TWRrangeCeiling_edit.value()
            settings.solo_initial_climb_reading = alt_reading
        settings.ATIS_custom_appendix = self.atisCustomAppendix_edit.toPlainText(
        )

        signals.localSettingsChanged.emit()
        self.accept()