Beispiel #1
0
    def setArea(self, *args):
        ''' Set Experiment Area. Aicraft leaving the experiment area are deleted.
        Input can be exisiting shape name, or a box with optional altitude constrainsts.'''

        # if all args are empty, then print out the current area status
        if len(args) == 0:
            return True, "Area is currently " + ("ON" if self.active else "OFF") + \
                         "\nCurrent Area name is: " + str(self.name)

        # start by checking if the first argument is a string -> then it is an area name
        if isinstance(args[0], str) and len(args) == 1:
            if areafilter.hasArea(args[0]):
                # switch on Area, set it to the shape name
                self.name = args[0]
                self.active = True
                return True, "Area is set to " + str(self.name)
            elif args[0] == 'OFF' or args[0] == 'OF':
                # switch off the area
                areafilter.deleteArea(self.name)
                self.active = False
                self.name = None
                return True, "Area is switched OFF"
            else:
                # shape name is unknown
                return False, "Shapename unknown. Please create shapename first or shapename is misspelled!"
        # if first argument is a float -> then make a box with the arguments
        elif (isinstance(args[0], float)
              or isinstance(args[0], int)) and 4 <= len(args) <= 6:
            self.active = True
            self.name = 'DELAREA'
            areafilter.defineArea(self.name, 'BOX', args[:4], args[4:])
            return True, "Area is ON. Area name is: " + str(self.name)
        else:
            return False,  "Incorrect arguments" + \
                           "\nAREA Shapename/OFF or\n Area lat,lon,lat,lon,[top,bottom]"
Beispiel #2
0
    def set_area(self, *args):
        """ Set Experiment Area. Aircraft leaving this experiment area raise an error.
        Input can be existing shape name, or a box with optional altitude constraints. """
        # Set both exp_area and del_area to the same size.
        curname = self.exp_area
        msgname = 'Experiment area'
        # If no args, print current area state.
        if not args:
            return True, f'{msgname} is currently ON (name={curname})' if self.active else \
                f'{msgname} is currently OFF'

        # If the first argument is a string, it is an area name.
        if isinstance(args[0], str) and len(args) == 1:
            if areafilter.hasArea(args[0]):
                # Switch on area, set it to the shape name.
                self.exp_area = args[0]
                self.active = True

                # Initiate the loggers.
                self.flst_log.start(prefix=self.log_prefix)
                self.conf_log.start(prefix=self.log_prefix)
                self.flst_log.write(flst_vars)
                self.conf_log.write(conf_vars)

                return True, f'{msgname} is set to {args[0]}'
            elif args[0][:2] == 'OF':
                # Switch off the area and reset the logger.
                self.close_log()
                return True, f'{msgname} is switched OFF\nLogs are closed'
            elif args[0][:2] == 'ON':
                if not curname:
                    return False, 'No area defined.'
                else:
                    self.active = True
                    return True, f'{msgname} switched ON (name={curname})'
            else:
                # Shape name is unknown.
                return False, 'Shapename unknown. ' + \
                       'Please create shapename first or shapename is misspelled!'
        # If first argument is a float, make a box with the arguments.
        if isinstance(args[0], (float, int)) and 4 <= len(args) <= 6:
            self.active = True
            self.exp_area = 'EXPAREA'
            areafilter.defineArea('EXPAREA', 'BOX', args[:4], *args[4:])

            # Initiate the loggers.
            self.flst_log.start(prefix=self.log_prefix)
            self.conf_log.start(prefix=self.log_prefix)
            self.flst_log.write(flst_vars)
            self.conf_log.write(conf_vars)

            return True, f'{msgname} is ON. Area name is: {self.exp_area}'
        else:
            return False, 'Incorrect arguments\n' + \
                   'AREA Shapename/OFF or\n Area lat,lon,lat,lon,[top,bottom]'
Beispiel #3
0
    def set_area(self, *args, exparea=False):
        ''' Set Experiment Area. Aircraft leaving the experiment area are deleted.
        Input can be existing shape name, or a box with optional altitude constraints.'''
        curname = self.exparea if exparea else self.delarea
        msgname = 'Experiment area' if exparea else 'Deletion area'
        # if all args are empty, then print out the current area status
        if not args:
            return True, f'{msgname} is currently ON (name={curname})' if self.active else \
                         f'{msgname} is currently OFF'

        # start by checking if the first argument is a string -> then it is an area name
        if isinstance(args[0], str) and len(args) == 1:
            if areafilter.hasArea(args[0]):
                # switch on Area, set it to the shape name
                if exparea:
                    self.exparea = args[0]
                else:
                    self.delarea = args[0]

                self.active = True
                self.flst.start()
                self.conflog.start()
                return True, f'{msgname} is set to {args[0]}'
            if args[0][:2] == 'OF':
                # switch off the area and reset the logger
                self.active = False
                return True, f'{msgname} is switched OFF'
            if args[0][:2] == 'ON':
                if not self.name:
                    return False, 'No area defined.'
                else:
                    self.active = True
                    return True, f'{msgname} switched ON (name={curname})'
            # shape name is unknown
            return False, 'Shapename unknown. ' + \
                'Please create shapename first or shapename is misspelled!'
        # if first argument is a float -> then make a box with the arguments
        if isinstance(args[0], (float, int)) and 4 <= len(args) <= 6:
            self.active = True
            if exparea:
                self.exparea = 'EXPAREA'
                areafilter.defineArea('EXPAREA', 'BOX', args[:4], *args[4:])
            else:
                self.delarea = 'DELAREA'
                areafilter.defineArea('DELAREA', 'BOX', args[:4], *args[4:])
            self.flst.start()
            self.conflog.start()
            return True, f'{msgname} is ON. Area name is: {"EXP" if exparea else "DEL"}AREA'

        return False,  'Incorrect arguments' + \
                       '\nAREA Shapename/OFF or\n Area lat,lon,lat,lon,[top,bottom]'
def ilsgate(test):
    global apt_list, rwy_list, valid_hdg, cone_centre, lat_cone_list, lon_cone_list, area_list
    # EHAM: [1: 340 - 20]
    #       [2: 70-110]
    #       [3: 210-250]
    #
    # 2. EHGR/EHEH: [1: 260-300]
    #       [2: 190-230]
    #
    # 3. EHDL: [1: 190-230]
    # if '/' not in rwyname:
    #     return False, 'Argument is not a runway ' + rwyname
    # apt, rwy = rwyname.split('/RW')
    # rwy = rwy.lstrip('Y')
    apt_list = ['EHAM', 'EHGR', 'EHDL']
    rwy_list = [['18R', '09', '27'], ['28', '20'], ['02', '20']]
    valid_hdg = []
    cone_centre = [[], [], []]
    lat_cone_list = []
    lon_cone_list = []
    area_list = []
    for i, apt in enumerate(apt_list):
        apt_thresholds = navdb.rwythresholds.get(apt)
        for rwy in rwy_list[i]:
            rwy_threshold = apt_thresholds.get(rwy)
            lat, lon, hdg = rwy_threshold
            cone_length = 18  # nautical miles
            cone_angle = 10.0  # degrees
            valid_hdg.append((hdg - cone_angle % 360, hdg + cone_angle % 360))
            lat1, lon1 = geo.qdrpos(lat, lon, hdg - 180.0 + cone_angle,
                                    cone_length)
            lat2, lon2 = geo.qdrpos(lat, lon, hdg - 180.0 - cone_angle,
                                    cone_length)
            lat_centre, lon_centre = geo.qdrpos(lat, lon, hdg - 180,
                                                (cone_length / 5) * 4)
            cone_centre[i].append((lat_centre, lon_centre))
            lat_cone_list.append(lat_centre)
            lon_cone_list.append(lon_centre)
            area_list.append(apt + rwy)

            coordinates = np.array([lat, lon, lat1, lon1, lat2, lon2])
            areafilter.defineArea(apt + rwy,
                                  'POLYALT',
                                  coordinates,
                                  top=25000 * ft)

        # Extract runway threshold lat/lon, and runway heading

    # The ILS gate is defined as a triangular area pointed away from the runway
    # First calculate the two far corners in cartesian coordinates
    print('created ILS intecept beams')
Beispiel #5
0
def ilsgate(rwyname):
    if '/' not in rwyname:
        return False, 'Argument is not a runway ' + rwyname
    apt, rwy = rwyname.split('/RW')
    rwy = rwy.lstrip('Y')
    apt_thresholds = navdb.rwythresholds.get(apt)
    if not apt_thresholds:
        return False, 'Argument is not a runway (airport not found) ' + apt
    rwy_threshold = apt_thresholds.get(rwy)
    if not rwy_threshold:
        return False, 'Argument is not a runway (runway not found) ' + rwy
    # Extract runway threshold lat/lon, and runway heading
    lat, lon, hdg = rwy_threshold

    # The ILS gate is defined as a triangular area pointed away from the runway
    # First calculate the two far corners in cartesian coordinates
    cone_length = 50 # nautical miles
    cone_angle  = 20.0 # degrees
    lat1, lon1 = geo.qdrpos(lat, lon, hdg - 180.0 + cone_angle, cone_length)
    lat2, lon2 = geo.qdrpos(lat, lon, hdg - 180.0 - cone_angle, cone_length)
    coordinates = np.array([lat, lon, lat1, lon1, lat2, lon2])
    areafilter.defineArea('ILS' + rwyname, 'POLYALT', coordinates, top=4000*ft)
Beispiel #6
0
    def set_area(self, *args):
        ''' Set Experiment Area. Aicraft leaving the experiment area are deleted.
        Input can be exisiting shape name, or a box with optional altitude constrainsts.'''

        # if all args are empty, then print out the current area status
        if not args:
            return True, "Area is currently " + ("ON" if self.active else "OFF") + \
                         "\nCurrent Area name is: " + str(self.name)

        # start by checking if the first argument is a string -> then it is an area name
        if isinstance(args[0], str) and len(args)==1:
            if areafilter.hasArea(args[0]):
                # switch on Area, set it to the shape name
                self.name = args[0]
                self.active = True
                self.logger.start()
                return True, "Area is set to " + str(self.name)
            if args[0]=='OFF' or args[0]=='OF':
                # switch off the area
                areafilter.deleteArea(self.name)
                self.logger.reset()
                self.active = False
                self.name = None
                return True, "Area is switched OFF"

            # shape name is unknown
            return False, "Shapename unknown. " + \
                "Please create shapename first or shapename is misspelled!"
        # if first argument is a float -> then make a box with the arguments
        if isinstance(args[0],(float, int)) and 4<=len(args)<=6:
            self.active = True
            self.name = 'DELAREA'
            areafilter.defineArea(self.name, 'BOX', args[:4], *args[4:])
            self.logger.start()
            return True, "Area is ON. Area name is: " + str(self.name)

        return False,  "Incorrect arguments" + \
                       "\nAREA Shapename/OFF or\n Area lat,lon,lat,lon,[top,bottom]"
Beispiel #7
0
    def update(self):
        """
        if random.randint(0,10000)< self.createconflict and bs.sim.simt > 5:
            print("creating conflict")
            bs.traf.creconfs(str(bs.traf.ntraf+1), actype = 'A388', 0, 100, 20, 600)
        """
        matrix = np.zeros(shape=(bs.traf.ntraf, bs.traf.ntraf), dtype=bool)
        areas = []
        combinations = list(itertools.combinations(range(bs.traf.ntraf), 2))
        #bs.scr.objdel()
        for ac in range(bs.traf.ntraf):
            areas.append(
                EcosystemAreas(lat=bs.traf.lat[ac],
                               lon=bs.traf.lon[ac],
                               v=bs.traf.cas[ac],
                               alpha_max=60,
                               alt=bs.traf.alt[ac]))
            #bs.scr.objappend('POLY', 'object'+str(ac), np.dstack((areas[-1].latitude, areas[-1].longitude)).flatten())

            areafilter.defineArea(
                'test', "POLY",
                np.dstack((areas[-1].latitude, areas[-1].longitude)).flatten())
            areas[-1].calculate()

        for combination in combinations:
            result = calculate_tlosh(areas[combination[0]],
                                     areas[combination[1]],
                                     bs.settings.asas_pzr * nm)
            matrix[combination[0], combination[1]] = result
            matrix[combination[1], combination[0]] = result
        print(matrix)
        for ac in range(bs.traf.ntraf):
            if self.zone.checkInside(bs.traf.lat[ac], bs.traf.lon[ac],
                                     bs.traf.alt[ac]) == False:
                bs.traf.delete(ac)
                break

        self.fix_index_bug()
Beispiel #8
0
def initbasecmds():
    ''' Initialise BlueSky base stack commands. '''
    # Command dictionary with command as key, gives a list with:
    #
    #         command: [ helptext ,
    #                    arglist ,
    #                    function to call,
    #                    description in one line ]
    #
    # Regarding the arglist:
    #    - Separate aruments with a comma ","
    #    - Enclose optional arguments with "[" and "]"
    #    - Separate different argument type variants in one argument with "/"
    #    - Repeat last one using "..." ,    (see e.g. WIND or POLY)
    #
    # Argtypes = syntax parsing (see below in this module for parsing):
    #
    #   acid      = aircraft id (text => index)
    #   alt       = altitude (FL250, 25000  ft+. meters)
    #   spd       = CAS or Mach (when <1)   => m/s
    #   hdg       = heading in degrees, True or Magnetic
    #
    #   float     = plain float
    #   int       = integer
    #   txt       = text will be converted to upper case
    #               (for keywords, navaids, flags, waypoints,acid etc)
    #   word      = single, case sensitive word
    #   string    = case sensitive string
    #   on/off    = text => boolean
    #
    #   latlon    = converts acid, wpt, airport etc => lat,lon (deg) so 2 args!
    #   wpt       = converts postext or lat,lon into a text string,
    #               to be used as named waypoint
    #   wpinroute = text string with name of waypoint in route
    #   pandir    = text with LEFT, RIGHT, UP/ABOVE or DOWN
    #
    # Below this dictionary also a dictionary of synonym commands is given
    #
    # --------------------------------------------------------------------
    cmddict = {
        "ADDNODES": [
            "ADDNODES number",
            "int",
            bs.net.addnodes,
            "Add a simulation instance/node",
        ],
        "ADDWPT": [
            "ADDWPT acid, (wpname/lat,lon/FLYBY/FLYOVER/ TAKEOFF,APT/RWY),[alt,spd,afterwp]",
            "acid,wpt,[alt,spd,wpinroute,wpinroute]",
            #
            # lambda *arg: short-hand for using function output as argument, equivalent with:
            #
            # def fun(idx, args):
            #     return bs.traf.ap.route[idx].addwptStack(idx, *args)
            # fun(idx,*args)
            #
            lambda idx, *args: bs.traf.ap.route[idx].addwptStack(idx, *args),
            "Add a waypoint to route of aircraft (FMS)",
        ],
        "AFTER": [
            "acid AFTER afterwp ADDWPT (wpname/lat,lon),[alt,spd]",
            "acid,wpinroute,txt,wpt,[alt,spd]",
            lambda idx, * \
            args: bs.traf.ap.route[idx].afteraddwptStack(idx, *args),
            "After waypoint, add a waypoint to route of aircraft (FMS)",
        ],
        "AIRWAY": [
            "AIRWAY wp/airway",
            "txt",
            bs.traf.airwaycmd,
            "Get info on airway or connections of a waypoint",
        ],
        "ALT": [
            "ALT acid, alt, [vspd]",
            "acid,alt,[vspd]",
            bs.traf.ap.selaltcmd,
            "Altitude command (autopilot)",
        ],
        "AT": [
            "acid AT wpname [DEL] SPD/ALT [spd/alt]",
            "acid,wpinroute,[txt,txt]",
            lambda idx, *args: bs.traf.ap.route[idx].atwptStack(idx, *args),
            "Edit, delete or show spd/alt constraints at a waypoint in the route",
        ],
        "ATALT": [
            "acid ATALT alt cmd ",
            "acid,alt,string",
            bs.traf.cond.ataltcmd,
            "When a/c at given altitude , execute a command cmd",
        ],
        "ATSPD": [
            "acid ATSPD spd cmd ",
            "acid,spd,string",
            bs.traf.cond.atspdcmd,
            "When a/c reaches given speed, execute a command cmd",
        ],
        "BANK": [
            "BANK bankangle[deg]",
            "acid,[float]",
            bs.traf.setbanklim,
            "Set or show bank limit for this vehicle",
        ],
        "BATCH": [
            "BATCH filename",
            "string",
            bs.sim.batch,
            "Start a scenario file as batch simulation",
        ],

        "BEFORE": [
            "acid BEFORE beforewp ADDWPT (wpname/lat,lon),[alt,spd]",
            "acid,wpinroute,txt,wpt,[alt,spd]",
            lambda idx, * \
            args: bs.traf.ap.route[idx].beforeaddwptStack(idx, *args),
            "Before waypoint, add a waypoint to route of aircraft (FMS)",
        ],
        "BLUESKY": ["BLUESKY", "", singbluesky, "Sing"],
        "BENCHMARK": [
            "BENCHMARK [scenfile,time]",
            "[string,time]",
            bs.sim.benchmark,
            "Run benchmark",
        ],
        "BOX": [
            "BOX name,lat,lon,lat,lon,[top,bottom]",
            "txt,latlon,latlon,[alt,alt]",
            lambda name, *coords: areafilter.defineArea(
                name, "BOX", coords[:4], *coords[4:]
            ),
            "Define a box-shaped area",
        ],
        "CALC": [
            "CALC expression",
            "string",
            calculator,
            "Simple in-line math calculator, evaluates expression",
        ],
        "CD": [
            "CD [path]",
            "[word]",
            setscenpath,
            "Change to a different scenario folder",
        ],
        "CIRCLE": [
            "CIRCLE name,lat,lon,radius,[top,bottom]",
            "txt,latlon,float,[alt,alt]",
            lambda name, *coords: areafilter.defineArea(
                name, "CIRCLE", coords[:3], *coords[3:]
            ),
            "Define a circle-shaped area",
        ],
        "COLOR": [
            "COLOR name,color (named color or r,g,b)",
            "txt,color",
            bs.scr.color,
            "Set a custom color for an aircraft or shape",
        ],
        "CRE": [
            "CRE acid,type,lat,lon,hdg,alt,spd",
            "txt,txt,latlon,hdg,alt,spd",
            bs.traf.cre,
            "Create an aircraft",
        ],
        "CRECONFS": [
            "CRECONFS id, type, targetid, dpsi, cpa, tlos_hor, dH, tlos_ver, spd",
            "txt,txt,acid,hdg,float,time,[alt,time,spd]",
            bs.traf.creconfs,
            "Create an aircraft that is in conflict with 'targetid'",
        ],
        "DATE": [
            "DATE [day,month,year,HH:MM:SS.hh]",
            "[int,int,int,txt]",
            bs.sim.setutc,
            "Set simulation date",
        ],
        "DEFWPT": [
            "DEFWPT wpname,lat,lon,[FIX/VOR/DME/NDB]",
            "txt,latlon,[txt]",
            bs.navdb.defwpt,
            "Define a waypoint only for this scenario/run",
        ],
        "DEL": [
            "DEL acid/ALL/WIND/shape",
            "acid/txt,...",
            lambda *a: bs.traf.wind.clear()
            if isinstance(a[0], str) and a[0] == "WIND"
            else areafilter.deleteArea(a[0])
            if isinstance(a[0], str)
            else bs.traf.groups.delgroup(a[0])
            if hasattr(a[0], "groupname")
            else bs.traf.delete(a),
            "Delete command (aircraft, wind, area)",
        ],
        "DELAY": [
            "DELAY time offset, COMMAND+ARGS",
            "time,string",
            lambda time, *args: sched_cmd(time, args, relative=True),
            "Add a delayed command to stack",
        ],
        "DELRTE": [
            "DELRTE acid",
            "acid",
            lambda idx: bs.traf.ap.route[idx].delrte(idx),
            "Delete for this a/c the complete route/dest/orig (FMS)",
        ],
        "DELWPT": [
            "DELWPT acid,wpname",
            "acid,wpinroute",
            lambda idx, wpname: bs.traf.ap.route[idx].delwpt(wpname, idx),
            "Delete a waypoint from a route (FMS)",
        ],
        "DEST": [
            "DEST acid, latlon/airport",
            "acid,wpt",
            lambda idx, *args: bs.traf.ap.setdestorig("DEST", idx, *args),
            "Set destination of aircraft, aircraft wil fly to this airport",
        ],
        "DIRECT": [
            "DIRECT acid wpname",
            "acid,txt",
            lambda idx, wpname: bs.traf.ap.route[idx].direct(idx, wpname),
            "Go direct to specified waypoint in route (FMS)",
        ],
        "DIST": [
            "DIST lat0, lon0, lat1, lon1",
            "latlon,latlon",
            distcalc,
            "Distance and direction calculation between two positions",
        ],
        "DOC": [
            "DOC [command]",
            "[txt]",
            bs.scr.show_cmd_doc,
            "Show extended help window for given command, or the main documentation page if no command is given.",
        ],
        "DT": [
            "DT [dt] OR [target,dt]",
            "[float/txt,float]",
            lambda *args: simtime.setdt(*reversed(args)),
            "Set simulation time step",
        ],
        "DTMULT": [
            "DTMULT multiplier",
            "float",
            bs.sim.set_dtmult,
            "Sel multiplication factor for fast-time simulation",
        ],
        "DUMPRTE": [
            "DUMPRTE acid",
            "acid",
            lambda idx: bs.traf.ap.route[idx].dumpRoute(idx),
            "Write route to output/routelog.txt",
        ],
        "ECHO": [
            "ECHO txt",
            "string",
            bs.scr.echo,
            "Show a text in command window for user to read",
        ],
        "FF": [
            "FF [timeinsec]",
            "[time]",
            bs.sim.fastforward,
            "Fast forward the simulation",
        ],
        "FILTERALT": [
            "FILTERALT ON/OFF,[bottom,top]",
            "bool,[alt,alt]",
            bs.scr.filteralt,
            "Display aircraft on only a selected range of altitudes",
        ],
        "FIXDT": [
            "FIXDT ON/OFF [tend]",
            "onoff,[time]",
            lambda flag, *args: bs.sim.ff(*args) if flag else bs.op(),
            "Legacy function for TMX compatibility",
        ],
        "GETWIND": [
            "GETWIND lat,lon,[alt]",
            "latlon,[alt]",
            bs.traf.wind.get,
            "Get wind at a specified position (and optionally at altitude)",
        ],
        "GROUP": [
            "GROUP [grname, (areaname OR acid,...) ]",
            "[txt,acid/txt,...]",
            bs.traf.groups.group,
            "Add aircraft to a group. OR all aircraft in given area.\n"
            + "Returns list of groups when no argument is passed.\n"
            + "Returns list of aircraft in group when only a groupname is passed.\n"
            + "A group is created when a group with the given name doesn't exist yet.",
        ],
        "HDG": [
            "HDG acid,hdg (deg,True or Magnetic)",
            "acid,hdg",
            bs.traf.ap.selhdgcmd,
            "Heading command (autopilot)",
        ],
        "HOLD": ["HOLD", "", bs.sim.hold, "Pause(hold) simulation"],
        "IMPLEMENTATION": [
            "IMPLEMENTATION [base, implementation]",
            "[txt,txt]",
            select_implementation,
            "Select an alternate implementation for a Bluesky base class"
        ],
        "INSEDIT": [
            "INSEDIT txt",
            "string",
            bs.scr.cmdline,
            "Insert text op edit line in command window",
        ],
        "LEGEND": [
            "LEGEND label1, ..., labeln",
            "word,...",
            lambda *labels: plotter.legend(labels),
            "Add a legend to the last created plot",
        ],
        "LINE": [
            "LINE name,lat,lon,lat,lon",
            "txt,latlon,latlon",
            lambda name, *coords: areafilter.defineArea(name, "LINE", coords),
            "Draw a line on the radar screen",
        ],
        "LISTRTE": [
            "LISTRTE acid, [pagenr]",
            "acid,[int]",
            lambda idx, *args: bs.traf.ap.route[idx].listrte(idx, *args),
            "Show list of route in window per page of 5 waypoints",
        ],
        "LNAV": [
            "LNAV acid,[ON/OFF]",
            "acid,[onoff]",
            bs.traf.ap.setLNAV,
            "LNAV (lateral FMS mode) switch for autopilot",
        ],
        "LSVAR": [
            "LSVAR path.to.variable",
            "[word]",
            ve.lsvar,
            "Inspect any variable in a bluesky simulation",
        ],
        "MCRE": [
            "MCRE n, [type/*, alt/*, spd/*, dest/*]",
            "int,[txt,alt,spd,txt]",
            bs.traf.mcre,
            "Multiple random create of n aircraft in current view",
        ],
        "MOVE": [
            "MOVE acid,lat,lon,[alt,hdg,spd,vspd]",
            "acid,latlon,[alt,hdg,spd,vspd]",
            bs.traf.move,
            "Move an aircraft to a new position",
        ],
        "ND": [
            "ND acid",
            "txt",
            bs.scr.shownd,
            "Show navigation display with CDTI"
        ],
        "NOISE": [
            "NOISE [ON/OFF]",
            "[onoff]",
            bs.traf.setnoise,
            "Turbulence/noise switch",
        ],
        "NOM": [
            "NOM acid",
            "acid",
            bs.traf.nom,
            "Set nominal acceleration for this aircraft (perf model)",
        ],
        "OP": [
            "OP",
            "",
            bs.sim.op,
            "Start/Run simulation or continue after hold"
        ],
        "ORIG": [
            "ORIG acid, latlon/airport",
            "acid,wpt",
            lambda *args: bs.traf.ap.setdestorig("ORIG", *args),
            "Set origin airport of aircraft",
        ],
        "PAN": [
            "PAN latlon/acid/airport/waypoint/LEFT/RIGHT/ABOVE/DOWN",
            "pandir/latlon",
            bs.scr.pan,
            "Pan screen (move view) to a waypoint, direction or aircraft",
        ],
        "PLOT": [
            "PLOT [x], y [,dt,color,figure]",
            "[word,word,float,txt,int]",
            plotter.plot,
            "Create a graph of variables x versus y.",
        ],
        "PLUGINS": [
            "PLUGINS LIST or PLUGINS LOAD/REMOVE plugin ",
            "[txt,txt]",
            plugin.manage,
            "List all plugins, load a plugin, or remove a loaded plugin.",
        ],
        "POLY": [
            "POLY name,[lat,lon,lat,lon, ...]",
            "txt,[latlon,...]",
            lambda name, *coords: areafilter.defineArea(name, "POLY", coords),
            "Define a polygon-shaped area",
        ],
        "POLYALT": [
            "POLYALT name,top,bottom,lat,lon,lat,lon, ...",
            "txt,alt,alt,latlon,...",
            lambda name, top, bottom, *coords: areafilter.defineArea(
                name, "POLYALT", coords, top, bottom
            ),
            "Define a polygon-shaped area in 3D: between two altitudes",
        ],
        "POLYLINE": [
            "POLYLINE name,lat,lon,lat,lon,...",
            "txt,latlon,...",
            lambda name, *coords: areafilter.defineArea(name, "LINE", coords),
            "Draw a multi-segment line on the radar screen",
        ],
        "POS": [
            "POS acid/waypoint",
            "acid/wpt",
            bs.traf.poscommand,
            "Get info on aircraft, airport or waypoint",
        ],
        "QUIT": ["QUIT", "", bs.sim.stop, "Quit program/Stop simulation"],
        "REALTIME": [
            "REALTIME [ON/OFF]",
            "[bool]",
            bs.sim.realtime,
            "En-/disable realtime running allowing a variable timestep."],
        "RESET": ["RESET", "", bs.sim.reset, "Reset simulation"],
        "RTA": [
            "RTA acid,wpinroute,RTAtime",
            "acid,wpinroute,txt",
            lambda idx, *args: bs.traf.ap.route[idx].SetRTA(idx, *args),
            "Set required time of arrival (RTA) at waypoint in route",
        ],
        "SEED": [
            "SEED value",
            "int",
            bs.sim.setseed,
            "Set seed for all functions using a randomizer (e.g.mcre,noise)",
        ],
        "SPD": [
            "SPD acid,spd (CAS-kts/Mach)",
            "acid,spd",
            bs.traf.ap.selspdcmd,
            "Speed command (autopilot)",
        ],
        "SSD": [
            "SSD ALL/CONFLICTS/OFF or SSD acid0, acid1, ...",
            "txt,[...]",
            lambda *args: bs.scr.feature("SSD", args),
            "Show state-space diagram (=conflict prevention display/predictive ASAS)",
        ],
        "SWRAD": [
            "SWRAD GEO/GRID/APT/VOR/WPT/LABEL/ADSBCOVERAGE/TRAIL/POLY [dt]/[value]",
            "txt,[float]",
            bs.scr.feature,
            "Switch on/off elements and background of map/radar view",
        ],
        "SYMBOL": ["SYMBOL", "", bs.scr.symbol, "Toggle aircraft symbol"],
        "THR": [
            "THR acid, IDLE/0.0/throttlesetting/1.0/AUTO(default)",
            "acid[,txt]",
            bs.traf.setthrottle,
            "Set throttle or autotothrottle(default)",
        ],
        "TIME": [
            "TIME RUN(default) / HH:MM:SS.hh / REAL / UTC ",
            "[txt]",
            bs.sim.setutc,
            "Set simulated clock time",
        ],
        "TRAIL": [
            "TRAIL ON/OFF, [dt] OR TRAIL acid color",
            "[acid/bool],[float/txt]",
            bs.traf.trails.setTrails,
            "Toggle aircraft trails on/off",
        ],
        "UNGROUP": [
            "UNGROUP grname, acid",
            "txt,acid,...",
            bs.traf.groups.ungroup,
            "Remove aircraft from a group",
        ],
        "VNAV": [
            "VNAV acid,[ON/OFF]",
            "acid,[onoff]",
            bs.traf.ap.setVNAV,
            "Switch on/off VNAV mode, the vertical FMS mode (autopilot)",
        ],
        "VS": [
            "VS acid,vspd (ft/min)",
            "acid,vspd",
            bs.traf.ap.selvspdcmd,
            "Vertical speed command (autopilot)",
        ],
        "WIND": [
            "WIND lat,lon,alt/*,dir,spd,[alt,dir,spd,alt,...]",
            # last 3 args are repeated
            "latlon,[alt],float,float,...,",
            bs.traf.wind.add,
            "Define a wind vector as part of the 2D or 3D wind field",
        ],
        "ZOOM": [
            "ZOOM IN/OUT or factor",
            "float/txt",
            lambda a: bs.scr.zoom(1.4142135623730951)
            if a == "IN"
            else bs.scr.zoom(0.7071067811865475)
            if a == "OUT"
            else bs.scr.zoom(a, True),
            "Zoom display in/out, you can also use +++ or -----",
        ],
    }

    #
    # Command synonym dictionary definea equivalent commands globally in stack
    #
    # Actual command definitions: see dictionary in def init(...) below
    #
    synonyms = {
        "ADDAIRWAY": "ADDAWY",
        "AWY": "POS",
        "AIRPORT": "POS",
        "AIRWAYS": "AIRWAY",
        "BANKLIM": "BANK",
        "CHDIR": "CD",
        "COL": "COLOR",
        "COLOUR": "COLOR",
        "CONTINUE": "OP",
        "CREATE": "CRE",
        "CLOSE": "QUIT",
        "DEBUG": "CALC",
        "DELETE": "DEL",
        "DELWP": "DELWPT",
        "DELROUTE": "DELRTE",
        "DIRECTTO": "DIRECT",
        "DIRTO": "DIRECT",
        "DISP": "SWRAD",
        "END": "QUIT",
        "EXIT": "QUIT",
        "FWD": "FF",
        "HEADING": "HDG",
        "IMPL": "IMPLEMENTATION",
        "IMPLEMENT": "IMPLEMENTATION",
        "LINES": "POLYLINE",
        "PAUSE": "HOLD",
        "PLUGIN": "PLUGINS",
        "PLUG-IN": "PLUGINS",
        "PLUG-INS": "PLUGINS",
        "POLYGON": "POLY",
        "POLYLINES": "POLYLINE",
        "PRINT": "ECHO",
        "Q": "QUIT",
        "RT": "REALTIME",
        "RTF": "DTMULT",
        "STOP": "QUIT",
        "RUN": "OP",
        "RUNWAYS": "POS",
        "SAVE": "SAVEIC",
        "SPEED": "SPD",
        "START": "OP",
        "TRAILS": "TRAIL",
        "TURN": "HDG",
    }

    append_commands(cmddict, synonyms)