Пример #1
0
 def saveChangesAndClose(self):
     # FPL.CALLSIGN
     self.set_detail(FPL.CALLSIGN, self.callsign_edit.text().upper())
     # FPL.FLIGHT_RULES
     self.set_detail(FPL.FLIGHT_RULES,
                     self.flightRules_select.currentText())
     # FPL.ACFT_TYPE
     self.set_detail(FPL.ACFT_TYPE,
                     self.aircraftType_edit.getAircraftType())
     # FPL.WTC
     self.set_detail(FPL.WTC, self.wakeTurbCat_select.currentText())
     # FPL.ICAO_DEP
     self.set_detail(FPL.ICAO_DEP,
                     self.depAirportPicker_widget.currentText())
     # FPL.ICAO_ARR
     self.set_detail(FPL.ICAO_ARR,
                     self.arrAirportPicker_widget.currentText())
     # FPL.ROUTE
     self.set_detail(FPL.ROUTE, self.route_edit.getRouteText())
     # FPL.CRUISE_ALT
     self.set_detail(FPL.CRUISE_ALT, self.cruiseAlt_edit.text())
     # FPL.TAS
     self.set_detail(FPL.TAS, (Speed(self.TAS_edit.value())
                               if self.TAS_enable.isChecked() else None))
     # FPL.COMMENTS
     self.set_detail(FPL.COMMENTS, self.comments_edit.toPlainText())
Пример #2
0
 def new_arrival_GND(self):
     acft_type = choice(self.parkable_aircraft_types)
     rwy = rnd_rwy([
         rwy
         for rwy in env.airport_data.allRunways() if rwy.use_for_arrivals
     ], lambda rwy: rwy.acceptsAcftType(acft_type))
     if rwy == None:
         return None
     turn_off_lists = l1, l2, l3, l4 = env.airport_data.ground_net.runwayTurnOffs(
         rwy, minroll=(rwy.length(dthr=True) * 2 / 3))
     for lst in turn_off_lists:
         pop_all(
             lst, lambda t: not self.groundPositionFullySeparated(
                 env.airport_data.ground_net.nodePosition(t[1]), acft_type))
     if all(lst == [] for lst in turn_off_lists):
         return None
     else:
         turn_off_choice = choice(l1) if l1 != [] else (l2 + l3)[0]
     pos = env.airport_data.ground_net.nodePosition(turn_off_choice[1])
     hdg = rwy.orientation() + turn_off_choice[3]
     params = SoloParams(Status(Status.TAXIING), pos,
                         env.groundStdPressureAlt(pos), hdg, Speed(0))
     params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_ARR)
     pk_request = choice(
         env.airport_data.ground_net.parkingPositions(acftType=acft_type))
     return self.mkAiAcft(acft_type, params, pk_request)
Пример #3
0
def str2detail(dstr, vstr):
    try:
        d = int(
            dstr
        )  # CAUTION this assumes there is no str detail key that looks like an int
    except ValueError:
        d = dstr
    if d in [FPL.CALLSIGN, FPL.ACFT_TYPE, FPL.WTC, FPL.ICAO_DEP, FPL.ICAO_ARR, FPL.ICAO_ALT, \
      FPL.CRUISE_ALT, FPL.ROUTE, FPL.COMMENTS, FPL.FLIGHT_RULES, assigned_altitude_detail]: # str
        v = vstr
    elif d in [FPL.SOULS, assigned_SQ_detail]:  # int
        v = int(vstr)
    elif d in [FPL.TAS, assigned_speed_detail]:  # Speed
        v = Speed(int(vstr))
    elif d == FPL.TIME_OF_DEP:  # datetime
        year, month, day, hour, minute = vstr.split()
        v = datetime(year=int(year),
                     month=int(month),
                     day=int(day),
                     hour=int(hour),
                     minute=int(minute),
                     tzinfo=timezone.utc)
    elif d == FPL.EET:  # timedelta
        v = timedelta(seconds=int(vstr))
    elif d == assigned_heading_detail:  # Heading
        v = Heading(int(vstr), False)
    else:
        raise ValueError('Unknown key for detail conversion: %s' % dstr)
    return d, v
Пример #4
0
 def speedInstruction(self):
     zero_cursor = self.radar_contact.IAS()
     if zero_cursor == None:
         zero_cursor = some(self.radar_contact.groundSpeed(),
                            speedInstruction_defaultZeroCursor)
     return Speed(
         bounded(min_speed_instruction,
                 zero_cursor.kt + self.diff_speed_measured,
                 max_speed_instruction)).rounded(step=10)
Пример #5
0
def stall_speed(t):
    cat = acft_cat(t)
    if cat == 'helos':
        return None
    else:
        fact = stall_speed_factors.get(cat, None)
        crspd = cruise_speed(t)
        return Speed(fact *
                     crspd.kt) if fact != None and crspd != None else None
Пример #6
0
 def viewRoute(self):
     tas = Speed(
         self.TAS_edit.value()) if self.TAS_enable.isChecked() else None
     route_to_view = Route(self.route_edit.data_DEP,
                           self.route_edit.data_ARR,
                           self.route_edit.getRouteText())
     RouteDialog(route_to_view,
                 speedHint=tas,
                 acftHint=self.aircraftType_edit.getAircraftType(),
                 parent=self).exec()
 def updateEET(self):
     if self.EETfromSpeed_radioButton.isChecked():
         self.EET_info.setText(
             TTF_str(self.route_length, Speed(self.speed_edit.value())))
     elif self.EETfromACFT_radioButton.isChecked():
         crspd = cruise_speed(self.acftType_select.getAircraftType())
         if crspd == None:
             self.EET_info.setText('(unknown ACFT cruise speed)')
         else:
             try:
                 self.EET_info.setText(TTF_str(self.route_length, crspd))
             except ValueError:
                 self.EET_info.setText('(speed too low)')
Пример #8
0
 def new_departure_GND(self, goal_point):
     acft_type = choice(self.parkable_aircraft_types)
     gn = env.airport_data.ground_net
     pk = [
         p for p in gn.parkingPositions(acftType=acft_type) if
         self.groundPositionFullySeparated(gn.parkingPosition(p), acft_type)
     ]
     if pk == []:
         return None
     pkinfo = env.airport_data.ground_net.parkingPosInfo(choice(pk))
     params = SoloParams(Status(Status.TAXIING), pkinfo[0],
                         env.groundStdPressureAlt(pkinfo[0]), pkinfo[1],
                         Speed(0))
     params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_DEP)
     return self.mkAiAcft(acft_type, params, (goal_point, None))
Пример #9
0
 def new_departure_TWR(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
     hdg = rwy.orientation() + 60
     pos = rwy.threshold(dthr=True).moved(
         hdg.opposite(),
         .04)  # FUTURE use turn-offs backwards when ground net present
     params = SoloParams(Status(Status.READY, arg=rwy.name), pos,
                         env.groundStdPressureAlt(pos), hdg, Speed(0))
     params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_DEP)
     return self.mkAiAcft(acft_type, params, (goal_point, None))
Пример #10
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)
Пример #11
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 load_aircraft_db():
    '''
	loads the dict: ICAO desig -> (category, WTC, cruise speed)
	where category is either of those used in X-plane, e.g. for parking positions
	any of tuple elements can use the "unavailable_acft_info_token" to signify unknown info
	'''
    try:
        with open(aircraft_db_spec_file, encoding='utf8') as f:
            for line in f:
                tokens = line.split('#', maxsplit=1)[0].split()
                if len(tokens) == 4:
                    desig, xplane_cat, wtc, cruise = tokens
                    if xplane_cat == unavailable_acft_info_token:
                        xplane_cat = None
                    if wtc == unavailable_acft_info_token:
                        wtc = None
                    acft_db[desig] = xplane_cat, wtc, (Speed(
                        float(cruise)) if cruise != unavailable_acft_info_token
                                                       else None)
                elif tokens != []:
                    print('Error on ACFT spec line: %s' % line.strip())
    except FileNotFoundError:
        print('Aircraft data base file not found: %s' % aircraft_db_spec_file)
Пример #13
0
from session.config import settings
from session.env import env

from data.utc import now
from data.params import Speed, StdPressureAlt
from data.conflict import Conflict


# ---------- Constants ----------

snapshot_history_size = 120 # number of radar snapshots
snapshot_diff_time = 6 # seconds (how long to look back in history for snapshot diffs)
min_taxiing_speed = Speed(5)
max_ground_height = 100 # ft

# -------------------------------



class Xpdr:
	all_keys = CODE, IDENT, ALT, CALLSIGN, ACFT, GND, IAS = range(7)



class RadarSnapshot:
	def __init__(self, time_stamp, coords, geom_alt):
		# Obligatory constructor data
		self.time_stamp = time_stamp
		self.coords = coords
		self.geometric_alt = geom_alt
Пример #14
0
from session.env import env

from data.util import some, bounded
from data.strip import rack_detail
from data.coords import EarthCoords, RadarCoords, dist_str
from data.params import StdPressureAlt, Speed

from gui.misc import signals
from ext.resources import pixmap_corner_sep

# ---------- Constants ----------

altitude_sensitivity = 40  # NM to ft
speed_sensitivity = 1  # NM to kt

speedInstruction_defaultZeroCursor = Speed(200)

min_speed_instruction = 80
max_speed_instruction = 800
taxi_tool_snap_dist = .1  # NM
groundnet_pos_taxi_precision = .03  # NM
min_taxi_drag = .02  # NM

text_label_max_rect = QRect(-100, -40, 200, 80)

# -------------------------------


def withMargins(rect, margin):
    return QRectF(rect.topLeft() - QPointF(margin, margin),
                  rect.bottomRight() + QPointF(margin, margin))
Пример #15
0
def restrict_speed_under_ceiling(spd, alt, ceiling):
    if alt.diff(ceiling) <= 0:
        return Speed(min(spd.kt, 250))
    else:
        return spd
Пример #16
0
    def run(self):
        ## PREPARING QUERY
        pos = env.radarPos()
        qdict = {
            'username': settings.MP_social_name,
            'lon': pos.lon,
            'lat': pos.lat,
            'range': some(settings.ORSX_handover_range, settings.radar_range),
            'xmlVersion': '1.0',
            'contacts': ','.join(
                acft.identifier for acft in
                env.radar.contacts())  # should this be all FGMS connections?
        }
        if settings.publicised_frequency != None:
            qdict['frequency'] = str(settings.publicised_frequency)
        server_response = server_query('getFlightplans', qdict)
        ## USING RESPONSE
        if server_response != None:
            try:
                ww_root = ElementTree.fromstring(server_response)
            except ElementTree.ParseError as parse_error:
                print('Parse error in SX server data: %s' % parse_error)
                return
            new_ATCs = []

            # ATCs first
            for ww_atc in ww_root.find('atcsInRange').iter(
                    'atc'):  # NOTE the server sends the full list each time
                atc = ATC(ww_atc.find('callsign').text)
                atc.social_name = ww_atc.find('username').text
                atc.position = EarthCoords(float(ww_atc.find('lat').text),
                                           float(ww_atc.find('lon').text))
                ww_frq = ww_atc.find('frequency').text
                try:
                    atc.frequency = CommFrequency(ww_frq)
                except ValueError:
                    atc.frequency = None
                new_ATCs.append(atc)
            self.ATCs_on_last_run = new_ATCs

            # Then strip data (contact claims and handover)
            for ww_flightplan in ww_root.iter(
                    'flightplan'
            ):  # NOTE the server only sends those when something changes
                ww_header = ww_flightplan.find('header')
                ww_callsign = ww_header.find('callsign').text
                ww_owner = ww_header.find('owner').text
                if ww_owner == None:
                    if ww_callsign in self.current_contact_claims:
                        del self.current_contact_claims[ww_callsign]
                else:
                    self.current_contact_claims[ww_callsign] = ww_owner

                if ww_header.find(
                        'handover'
                ).text == settings.session_manager.myCallsign(
                ):  # RECEIVE A STRIP!
                    strip = Strip()
                    strip.writeDetail(received_from_detail, ww_owner)
                    strip.writeDetail(
                        assigned_SQ_detail,
                        ck_int(ww_header.find('squawk').text, base=8))
                    strip.writeDetail(assigned_altitude_detail,
                                      ww_header.find('assignedAlt').text)
                    # Ignored from WW header above: <flags>, <assignedRunway>, <assignedRoute>, <status>, <flight>
                    # Ignored from WW data below: <fuelTime>; used with ulterior motive: <pilot>
                    ww_data = ww_flightplan.find('data')
                    # ATC-pie hides a token in <pilot>, wake turb. on its left and callsign to its right
                    # e.g. <pilot>M__ATC-pie__X-FOO</pilot> for M turb. and X-FOO strip callsign
                    # If the token is absent, we know the strip is from OpenRadar
                    hidden_tokens = some(ww_data.find('pilot').text,
                                         '').split(ATCpie_hidden_string,
                                                   maxsplit=1)
                    if len(
                            hidden_tokens
                    ) == 1:  # hidden marker NOT present; previous strip editor was OpenRadar
                        strip.writeDetail(FPL.CALLSIGN, ww_callsign)
                    else:  # recognise strip edited with ATC-pie
                        strip.writeDetail(FPL.WTC, hidden_tokens[0])
                        strip.writeDetail(FPL.CALLSIGN, hidden_tokens[1])
                    strip.writeDetail(FPL.FLIGHT_RULES,
                                      ww_data.find('type').text)
                    strip.writeDetail(FPL.ACFT_TYPE,
                                      ww_data.find('aircraft').text)
                    strip.writeDetail(FPL.ICAO_DEP,
                                      ww_data.find('departure').text)
                    strip.writeDetail(FPL.ICAO_ARR,
                                      ww_data.find('destination').text)
                    strip.writeDetail(FPL.ROUTE, ww_data.find('route').text)
                    strip.writeDetail(FPL.CRUISE_ALT,
                                      ww_data.find('cruisingAlt').text)
                    spd = ck_int(ww_data.find('trueAirspeed').text)
                    if spd != None:
                        strip.writeDetail(FPL.TAS, Speed(spd))
                    strip.writeDetail(FPL.COMMENTS,
                                      ww_data.find('remarks').text)
                    # Possibly ignored details (OpenRadar confuses FPLs and strips): DEP time, EET, alt. AD, souls [*]
                    signals.receiveStrip.emit(strip)
                    send_update(ww_callsign, strip)  # Acknowledge strip
Пример #17
0
def touch_down_speed(t):
    stall = stall_speed(t)
    return Speed(touch_down_speed_factor * stall.kt) if stall != None else None
Пример #18
0
def take_off_speed(t):
    stall = stall_speed(t)
    return Speed(take_off_speed_factor * stall.kt) if stall != None else None
Пример #19
0
def FPLdetails_from_XMLelement(fpl_elt):
    fpl_id = None  # tbd below
    details = {}
    online_comments = []
    online_status = None
    dep_date = dep_time = None
    arr_date = arr_time = None
    for elt in fpl_elt:
        if elt.tag == 'flightplanId':
            fpl_id = int(elt.text)
        elif elt.tag == 'status':
            try:
                # dict keys truncated below because of possible messy spelling at Lenny64 (e.g. "close" vs. "closed")
                online_status = {
                    'f': FPL.FILED,
                    'o': FPL.OPEN,
                    'c': FPL.CLOSED
                }[elt.text[0]]
            except (KeyError, IndexError):
                print(
                    'Please report unrecognised status string from Lenny64: %s'
                    % elt.text)
        elif elt.tag == 'callsign':
            details[FPL.CALLSIGN] = elt.text
        elif elt.tag == 'aircraft':
            details[FPL.ACFT_TYPE] = elt.text
        elif elt.tag == 'airportFrom':
            details[FPL.ICAO_DEP] = elt.text
        elif elt.tag == 'airportTo':
            details[FPL.ICAO_ARR] = elt.text
        elif elt.tag == 'alternateDestination':
            details[FPL.ICAO_ALT] = elt.text
        elif elt.tag == 'cruiseAltitude':
            details[FPL.CRUISE_ALT] = elt.text
        elif elt.tag == 'trueAirspeed' and elt.text != None:
            try:
                details[FPL.TAS] = Speed(int(elt.text))
            except ValueError:
                pass  # Ignore unreadable integer, check with Lenny for authorised string formats
        elif elt.tag == 'soulsOnBoard' and elt.text != None:
            try:
                details[FPL.SOULS] = int(elt.text)
            except ValueError:
                pass  # Ignore unreadable integer, check with Lenny for authorised string formats
        elif elt.tag == 'dateDeparture':
            match = lenny64_date_regexp.fullmatch(elt.text)
            if match:
                yyyy, mm, dd = int(match.group(1)), int(match.group(2)), int(
                    match.group(3))
                dep_date = date(yyyy, mm, dd)
        elif elt.tag == 'departureTime':
            match = lenny64_time_regexp.fullmatch(elt.text)
            if match:
                hh, mm, ss = int(match.group(1)), int(match.group(2)), int(
                    match.group(3))
                dep_time = time(hh, mm, ss)
        elif elt.tag == 'dateArrival':
            match = lenny64_date_regexp.fullmatch(elt.text)
            if match:
                yyyy, mm, dd = int(match.group(1)), int(match.group(2)), int(
                    match.group(3))
                arr_date = date(yyyy, mm, dd)
        elif elt.tag == 'arrivalTime':
            match = lenny64_time_regexp.fullmatch(elt.text)
            if match:
                hh, mm, ss = int(match.group(1)), int(match.group(2)), int(
                    match.group(3))
                arr_time = time(hh, mm, ss)
        elif elt.tag == 'category':
            details[FPL.FLIGHT_RULES] = elt.text
        elif elt.tag == 'waypoints':
            details[FPL.ROUTE] = elt.text
        elif elt.tag == 'additionalInformation':
            found = elt.find(ATCpie_comment_element_tag)  # ATC comments
            if found != None:
                details[FPL.COMMENTS] = found.text
            found = elt.find(
                ATCpie_wakeTurb_element_tag)  # wake turbulence category
            if found != None:
                details[FPL.WTC] = found.text
        elif elt.tag == 'comments':
            for comment_elt in elt.iter('comment'):
                comment = comment_elt.find('message').text
                if comment != None and comment != '':
                    user = comment_elt.find('user').text
                    online_comments.append('%s: %s' %
                                           (some(user, 'N/A'), comment))
    if dep_date != None and dep_time != None:
        details[FPL.TIME_OF_DEP] = datetime(dep_date.year, dep_date.month, dep_date.day, \
           hour=dep_time.hour, minute=dep_time.minute, second=dep_time.second, tzinfo=timezone.utc)
        if arr_date != None and arr_time != None:  # makes no sense without a departure datetime
            eta = datetime(arr_date.year, arr_date.month, arr_date.day, \
               hour=arr_time.hour, minute=arr_time.minute, second=arr_time.second, tzinfo=timezone.utc)
            details[FPL.EET] = eta - details[FPL.TIME_OF_DEP]
    return fpl_id, details, online_comments, online_status
Пример #20
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]
Пример #21
0
def interpret_string(string):
    tokens = string.split()
    named_runways = pop_named_runways(tokens)
    rwy_to_expect = ' '.join(named_runways)

    ## Callsign recognition
    ialnum, alnumtk = find_tokens(is_alphanum_token, tokens, 0, False)
    addressee_tokens = []
    for i in range(ialnum + len(alnumtk)):
        addressee_tokens.append(tokens.pop(0))

    ## Instruction list
    recognised_instructions = []

    # Instruction.CANCEL_APP
    try:
        try:
            i = tokens.index('go-around')
            j = i + 1
        except ValueError:
            i = tokens.index('cancel')  # cf. "cancel approach"
            j = i + 2
    except ValueError:
        pass
    else:
        SR_log('RECOGNISED: cancel app', tokens)
        recognised_instructions.append(
            Instruction(Instruction.CANCEL_APP, voiceData={}))
        del tokens[i:j]

    # Instruction.EXPECT_RWY
    try:
        i = tokens.index('expect')
    except ValueError:
        pass
    else:
        # 'j' below is last index to remove once instr is recognised; runway tokens are already removed
        j_max = min(len(tokens), i + 3)
        j = next((j for j in range(i + 1, j_max)
                  if tokens[j] not in ['ils', 'visual', 'approach']), j_max)
        app = next((b for t, b in [('ils', True), ('visual', False)]
                    if t in tokens[i + 1:j + 1]), None)
        SR_log('RECOGNISED: rwy/app', rwy_to_expect, app, tokens)
        recognised_instructions.append(
            Instruction(Instruction.EXPECT_RWY,
                        arg=rwy_to_expect,
                        voiceData={'app': app}))
        del tokens[i:j + 1]

    # Instruction.VECTOR_HDG
    try:
        try:
            i = tokens.index('turn')
        except ValueError:
            i = tokens.index('heading')
    except ValueError:
        pass
    else:
        try:
            ni, ntk = find_num_tokens(tokens, i + 1)
            hdg = convert_num_tokens(ntk)
        except ValueError as err:
            SR_log('Please report bug with heading instruction: %s' % err,
                   tokens)
        else:
            SR_log('RECOGNISED: hdg', hdg, tokens)
            recognised_instructions.append(
                Instruction(Instruction.VECTOR_HDG,
                            arg=Heading(hdg, False),
                            voiceData={}))
            del tokens[i:ni + len(ntk)]

    # Instruction.VECTOR_ALT
    try:
        ifl = tokens.index('flight-level')  # "flight level"
    except ValueError:  # try altitude
        th = hu = None
        try:
            ith = tokens.index('thousand')
            nith, thtk = find_num_tokens(tokens, ith - 1, bwd=True)
            del tokens[nith:ith + 1]
            SR_log('Tokens left after "thousand":', tokens)
            th = convert_num_tokens(thtk)  # STYLE catch a fail here?
        except ValueError:
            pass
        try:
            ihu = tokens.index('hundred')
            nihu, hutk = find_num_tokens(tokens, ihu - 1, bwd=True)
            del tokens[nihu:ihu + 1]
            SR_log('Tokens left after "hundred":', tokens)
            hu = convert_num_tokens(hutk)  # STYLE catch a fail here?
        except ValueError:
            pass
        if th != None or hu != None:  # got altitude
            alt = 1000 * some(th, 0) + 100 * some(hu, 0)
            SR_log('RECOGNISED: alt', alt)
            recognised_instructions.append(
                Instruction(Instruction.VECTOR_ALT,
                            arg=('%d ft' % alt),
                            voiceData={}))
    else:  # got FL
        try:
            nifl, fltk = find_num_tokens(tokens, ifl + 1)
            fl = convert_num_tokens(fltk)
        except ValueError as err:
            SR_log('Please report bug with FL instruction: %s' % err, tokens)
        else:
            SR_log('RECOGNISED: FL', fl, tokens)
            recognised_instructions.append(
                Instruction(Instruction.VECTOR_ALT,
                            arg=('FL%03d' % fl),
                            voiceData={}))
            del tokens[ifl:nifl + len(fltk)]

    # Instruction.VECTOR_SPD
    try:
        i = tokens.index('speed')
    except ValueError:
        pass
    else:
        if tokens[i + 1:i + 3] == ['your', 'discretion']:
            SR_log('RECOGNISED: cancel spd')
            recognised_instructions.append(
                Instruction(Instruction.CANCEL_VECTOR_SPD, voiceData={}))
            del tokens[i:i + 3]
        else:
            try:
                ni, ntk = find_num_tokens(tokens, i + 1)
                spd = convert_num_tokens(ntk)
            except ValueError as err:
                SR_log('Please report bug with speed instruction: %s' % err,
                       tokens)
            else:
                SR_log('RECOGNISED: spd', spd, tokens)
                recognised_instructions.append(
                    Instruction(Instruction.VECTOR_SPD,
                                arg=Speed(spd),
                                voiceData={}))
                del tokens[i:ni + len(ntk)]

    # Instruction.SQUAWK
    try:
        i = tokens.index('squawk')
    except ValueError:
        pass
    else:
        sq = [digit_tokens[tokens[k]] for k in range(i + 1, i + 5)]
        sq_code = 8 * 8 * 8 * sq[0] + 8 * 8 * sq[1] + 8 * sq[2] + sq[3]
        SR_log('RECOGNISED: sq', sq_code, tokens)
        recognised_instructions.append(
            Instruction(Instruction.SQUAWK, arg=sq_code, voiceData={}))
        del tokens[i:i + 5]

    # Instruction.HAND_OVER
    try:
        i = tokens.index('contact')
    except ValueError:
        pass
    else:
        try:
            atc = atc_tokens[tokens[i + 1]]
        except (KeyError, IndexError) as err:
            SR_log('Please report bug with h/o instruction: %s' % err, tokens)
        else:
            SR_log('RECOGNISED: handover', tokens)
            recognised_instructions.append(
                Instruction(Instruction.HAND_OVER,
                            arg=(atc, None),
                            voiceData={}))
            del tokens[i:i + 2]

    # Instruction.INTERCEPT_LOC
    try:
        iloc = tokens.index('localiser')
        i, tk = find_tokens('intercept'.__eq__, tokens, iloc - 1, True)
    except ValueError:
        pass
    else:
        SR_log('RECOGNISED: loc', tokens)
        recognised_instructions.append(
            Instruction(Instruction.INTERCEPT_LOC,
                        voiceData={'rwy': rwy_to_expect}))
        del tokens[i:iloc + 1]

    # Instruction.CLEARED_APP
    try:
        try:
            iapp = tokens.index(
                'approach'
            )  # WARNING "approach" also appears in CANCEL_APP, EXPECT_RWY and HAND_OVER, but should be removed by now
        except ValueError:
            iapp = tokens.index(
                'ils'
            )  # WARNING "ils" also appears in EXPECT_RWY, but should be removed by now
        i, tk1_ignore = find_tokens('cleared'.__eq__, tokens, iapp - 1, True)
    except ValueError:
        pass
    else:
        app = next((b for t, b in [('ils', True), ('visual', False)]
                    if t in tokens[i + 1:iapp + 1]), None)
        SR_log('RECOGNISED: app', app, tokens)
        recognised_instructions.append(
            Instruction(Instruction.CLEARED_APP,
                        voiceData={
                            'rwy': rwy_to_expect,
                            'app': app
                        }))
        del tokens[i:iapp + 1]

    # Instruction.LINE_UP
    try:
        i = tokens.index('wait')
    except ValueError:
        pass
    else:
        SR_log('RECOGNISED: luw', tokens)
        recognised_instructions.append(
            Instruction(Instruction.LINE_UP, voiceData={'rwy': rwy_to_expect}))
        del tokens[i - 2:i + 1]

    # Instruction.CLEARED_TKOF
    try:
        i = tokens.index('take-off')
    except ValueError:
        pass
    else:
        SR_log('RECOGNISED: cto', tokens)
        recognised_instructions.append(
            Instruction(Instruction.CLEARED_TKOF,
                        voiceData={'rwy': rwy_to_expect}))
        del tokens[i - 2:i + 1]

    # Instruction.CLEARED_TO_LAND
    try:
        i = tokens.index('land')
    except ValueError:
        pass
    else:
        SR_log('RECOGNISED: ctl', tokens)
        recognised_instructions.append(
            Instruction(Instruction.CLEARED_TO_LAND,
                        voiceData={'rwy': rwy_to_expect}))
        del tokens[i - 2:i + 1]

    # Instruction.SAY_INTENTIONS
    try:
        i = tokens.index('intentions')
    except ValueError:
        pass
    else:
        SR_log('RECOGNISED: intentions?', tokens)
        recognised_instructions.append(
            Instruction(Instruction.SAY_INTENTIONS, voiceData={}))
        del tokens[i - 1:i + 1]

    # Instruction.VECTOR_DCT
    try:
        i = tokens.index('proceed')
    except ValueError:
        pass
    else:
        try:
            pi, ptk = find_tokens(is_navpoint_token, tokens, i + 1, False)
            point = convert_navpoint_tokens(ptk)
        except ValueError as err:
            SR_log('Please report bug with DCT instruction: %s' % err, tokens)
        else:
            SR_log('RECOGNISED: dct', point, tokens)
            recognised_instructions.append(
                Instruction(Instruction.VECTOR_DCT, arg=point, voiceData={}))
            del tokens[i:pi + len(ptk)]

    # Instruction.HOLD, Instruction.HOLD_POSITION
    try:
        i = tokens.index('hold')
    except ValueError:
        pass
    else:
        if i + 1 < len(tokens) and tokens[i + 1] == 'position':
            SR_log('RECOGNISED: hold-position', tokens)
            recognised_instructions.append(
                Instruction(Instruction.HOLD_POSITION, voiceData={}))
            del tokens[i:i + 2]
        else:
            try:
                pi, ptk = find_tokens(is_navpoint_token, tokens, i + 1, False)
                point = convert_navpoint_tokens(ptk)
            except ValueError as err:
                SR_log('Please report bug with hold instruction: %s' % err,
                       tokens)
            else:
                j = pi + len(ptk)
                if j < len(tokens) and tokens[j] in ['left', 'right']:
                    turns = tokens[j] == 'right'
                    j += 2
                else:
                    turns = True
                SR_log('RECOGNISED: hold', point, tokens)
                recognised_instructions.append(
                    Instruction(Instruction.HOLD,
                                arg=(point, turns),
                                voiceData={}))
                del tokens[i:j]

    return addressee_tokens, recognised_instructions