2014-05-25 18:11:13 +00:00
# ==============================================================================
# Boeing Navigation Display by Gijs de Rooy
# See: http://wiki.flightgear.org/Canvas_ND_Framework
# ==============================================================================
# This file makes use of the MapStructure framework, see: http://wiki.flightgear.org/Canvas_MapStructure
#
# Sooner or later, some parts will be revamped by coming up with a simple animation framework: http://wiki.flightgear.org/NavDisplay#mapping_vs._SVG_animation
##
# pseudo DSL-ish: use these as placeholders in the config hash below
var ALWAYS = func 1;
var NOTHING = func nil;
##
# TODO: move ND-specific implementation details into this lookup hash
# so that other aircraft and ND types can be more easily supported
#
# any aircraft-specific ND behavior should be wrapped here,
# to isolate/decouple things in the generic NavDisplay class
#
# TODO: move this to an XML config file (maybe supporting SGCondition and/or SGStateMachine markup for the logic?)
#
var NDStyles = {
##
# this configures the 744 ND to help generalize the NavDisplay class itself
'Boeing': {
font_mapper: func(family, weight) {
if( family == "Liberation Sans" and weight == "normal" )
return "LiberationFonts/LiberationSans-Regular.ttf";
},
# where all the symbols are stored
# TODO: SVG elements should be renamed to use boeing/airbus prefix
# aircraft developers should all be editing the same ND.svg image
# the code can deal with the differences now
svg_filename: "Nasal/canvas/map/Images/boeingND.svg",
##
## this loads and configures existing layers (currently, *.layer files in Nasal/canvas/map)
##
# TODO: phase out isMapStructure flag once map.nas & *.draw files are killed
layers: [
# TODO: take z-indices from *.draw files -- now handled by MapStructure in the addLayer method.
2014-07-08 10:28:26 +00:00
{ name:'FIX', isMapStructure:1, update_on:['toggle_display_mode','toggle_range','toggle_waypoints'],
2014-05-25 18:11:13 +00:00
# FIXME: this is a really ugly place for controller code
predicate: func(nd, layer) {
# print("Running fix layer predicate");
# toggle visibility here
var visible=nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
2014-07-08 10:28:26 +00:00
layer.group.setVisible( visible );
2014-05-25 18:11:13 +00:00
if (visible) {
#print("Updating MapStructure ND layer: FIX");
# (Hopefully) smart update
layer.update();
}
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': -3,
2014-05-25 18:11:13 +00:00
}, # end of FIX layer
# Should redraw every 10 seconds TODO: use new MapStructure/WXR here once that works properly (Gijs should check first!)
{ name:'WXR', isMapStructure:1, update_on:[ {rate_hz: 0.1}, 'toggle_range','toggle_weather','toggle_display_mode'],
predicate: func(nd, layer) {
#print("Running storms predicate");
var visible=nd.get_switch('toggle_weather') and nd.get_switch('toggle_display_mode') != "PLAN";
layer.group.setVisible(visible);
if (visible) {
print("storms update requested! (timer issue when closing the dialog?)");
layer.update();
}
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': -4,
2014-05-25 18:11:13 +00:00
}, # end of storms/WXR layer
{ name:'APS', isMapStructure:1, update_on:['toggle_display_mode'],
predicate: func(nd, layer) {
var visible = nd.get_switch('toggle_display_mode') == "PLAN";
layer.group.setVisible( visible );
if (visible) {
layer.update();
}
},
},
{ name:'APT', isMapStructure:1, update_on:['toggle_range','toggle_airports','toggle_display_mode'],
predicate: func(nd, layer) {
# toggle visibility here
var visible=nd.get_switch('toggle_airports') and nd.in_mode('toggle_display_mode', ['MAP']);
layer.group.setVisible( visible );
if (visible) {
#print("Updating MapStructure ND layer: APT");
layer.update();
}
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': -1,
2014-05-25 18:11:13 +00:00
}, # end of APT layer
# Should distinct between low and high altitude navaids. Hiding above 40 NM for now, to prevent clutter/lag.
{ name:'VOR', isMapStructure:1, update_on:['toggle_range','toggle_stations','toggle_display_mode'],
# FIXME: this is a really ugly place for controller code
predicate: func(nd, layer) {
# toggle visibility here
var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
layer.group.setVisible( visible );
if (visible) {
#print("Updating MapStructure ND layer: VOR");
layer.update();
}
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': -2,
2014-05-25 18:11:13 +00:00
}, # end of VOR layer
2014-07-08 10:28:26 +00:00
{ name:'DME', isMapStructure:1, update_on:['toggle_display_mode','toggle_range','toggle_stations'],
2014-05-25 18:11:13 +00:00
# FIXME: this is a really ugly place for controller code
predicate: func(nd, layer) {
var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
# toggle visibility here
layer.group.setVisible( visible );
if (visible) {
#print("Updating MapStructure ND layer: DME");
layer.update();
}
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': -2,
2014-05-25 18:11:13 +00:00
}, # end of DME layer
{ name:'TFC', isMapStructure:1, update_on:['toggle_range','toggle_traffic'],
predicate: func(nd, layer) {
var visible = nd.get_switch('toggle_traffic');
layer.group.setVisible( visible );
if (visible) {
#print("Updating MapStructure ND layer: TFC");
layer.update();
}
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': 4,
2014-05-25 18:11:13 +00:00
}, # end of traffic layer
{ name:'runway-nd', update_on:['toggle_range','toggle_display_mode'],
predicate: func(nd, layer) {
#print("runway-nd wants to be ported to MapStructure");
var visible = (nd.rangeNm() <= 40) and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP','PLAN']) ;
if (visible)
layer._model.init(); # clear & redraw
layer._view.setVisible( visible );
}, # end of layer update predicate
}, # end of airports-nd layer
{ name:'RTE', isMapStructure:1, update_on:['toggle_range','toggle_display_mode'],
predicate: func(nd, layer) {
var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
layer.group.setVisible( visible );
if (visible)
layer.update();
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': 1,
2014-05-25 18:11:13 +00:00
}, # end of route layer
{ name:'WPT', isMapStructure:1, update_on:['toggle_range','toggle_display_mode'],
predicate: func(nd, layer) {
var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
layer.group.setVisible( visible );
if (visible)
layer.update();
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': 2,
2014-05-25 18:11:13 +00:00
}, # end of waypoint layer
{ name:'ALT-profile', isMapStructure:1, update_on:['toggle_range','toggle_display_mode'],
predicate: func(nd, layer) {
var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
layer.group.setVisible( visible );
if (visible)
layer.update();
}, # end of layer update predicate
2014-07-08 10:28:26 +00:00
'z-index': 3,
2014-05-25 18:11:13 +00:00
}, # end of altitude profile layer
## add other layers here, layer names must match the registered names as used in *.layer files for now
## this will all change once we're using Philosopher's MapStructure framework
], # end of vector with configured layers
# This is where SVG elements are configured by providing "behavior" hashes, i.e. for animations
# to animate each SVG symbol, specify behavior via callbacks (predicate, and true/false implementation)
# SVG identifier, callback etc
# TODO: update_on([]), update_mode (update() vs. timers/listeners)
# TODO: support putting symbols on specific layers
features: [
{
# TODO: taOnly doesn't need to use getprop polling in update(), use a listener instead!
id: 'taOnly', # the SVG ID
impl: { # implementation hash
init: func(nd, symbol), # for updateCenter stuff, called during initialization in the ctor
predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") == 2, # the condition
2014-07-10 21:07:47 +00:00
is_true: func(nd) nd.symbols.taOnly.show(),
is_false: func(nd) nd.symbols.taOnly.hide(),
2014-05-25 18:11:13 +00:00
}, # end of taOnly behavior/callbacks
2014-07-10 21:07:47 +00:00
},
{
id: 'tcasOff',
impl: {
init: func(nd, symbol),
predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") == 0 and nd.get_switch('toggle_traffic') and (nd.in_mode('toggle_display_mode', ['MAP']) or (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered'))),
is_true: func(nd) nd.symbols.tcasOff.show(),
is_false: func(nd) nd.symbols.tcasOff.hide(),
},
},
{
id: 'tcasFail',
impl: {
init: func(nd, symbol),
predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") != 0 and getprop("instrumentation/tcas/serviceable") != 1 and nd.get_switch('toggle_traffic') and (nd.in_mode('toggle_display_mode', ['MAP']) or (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered'))),
is_true: func(nd) nd.symbols.tcasFail.show(),
is_false: func(nd) nd.symbols.tcasFail.hide(),
},
},
{
id: 'tcasTest',
impl: {
init: func(nd, symbol),
predicate: func(nd) getprop("instrumentation/tcas/inputs/self-test") == 1 and getprop("instrumentation/tcas/serviceable") == 1,
is_true: func(nd) nd.symbols.tcasTest.show(),
is_false: func(nd) nd.symbols.tcasTest.hide(),
},
},
{
id: 'tfc',
impl: {
init: func(nd, symbol),
predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") != 0 and nd.get_switch('toggle_traffic') and (nd.in_mode('toggle_display_mode', ['MAP']) or (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered'))),
is_true: func(nd) nd.symbols.tfc.show(),
is_false: func(nd) nd.symbols.tfc.hide(),
},
},
{
id: 'traffic',
impl: {
init: func(nd, symbol),
predicate: func(nd) getprop("instrumentation/tcas/outputs/traffic-alert") != 0 or getprop("instrumentation/tcas/outputs/advisory-alert"),
is_true: func(nd) {
nd.symbols.traffic.show();
if (getprop("instrumentation/tcas/outputs/traffic-alert"))
nd.symbols.traffic.setColor(1,0,0);
else
nd.symbols.traffic.setColor(1,0.5,0);
},
is_false: func(nd) nd.symbols.traffic.hide(),
},
},
2014-05-25 18:11:13 +00:00
{
id: 'tas',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.aircraft_source.get_spd() > 100,
is_true: func(nd) {
2014-06-20 19:52:35 +00:00
nd.symbols.tas.setText(sprintf("%3.0f",nd.aircraft_source.get_spd() ));
2014-05-25 18:11:13 +00:00
nd.symbols.tas.show();
},
is_false: func(nd) nd.symbols.tas.hide(),
},
},
{
id: 'tasLbl',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.aircraft_source.get_spd() > 100,
is_true: func(nd) nd.symbols.tasLbl.show(),
is_false: func(nd) nd.symbols.tasLbl.hide(),
},
},
{
id: 'ilsFreq',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
is_true: func(nd) {
nd.symbols.ilsFreq.show();
if(getprop("instrumentation/nav/in-range"))
nd.symbols.ilsFreq.setText(getprop("instrumentation/nav/nav-id"));
else
nd.symbols.ilsFreq.setText(getprop("instrumentation/nav/frequencies/selected-mhz-fmt"));
},
is_false: func(nd) nd.symbols.ilsFreq.hide(),
},
},
{
id: 'ilsLbl',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
is_true: func(nd) {
nd.symbols.ilsLbl.show();
},
is_false: func(nd) nd.symbols.ilsLbl.hide(),
},
},
{
id: 'wpActiveId',
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("/autopilot/route-manager/wp/id") != nil and getprop("autopilot/route-manager/active")
and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
is_true: func(nd) {
nd.symbols.wpActiveId.setText(getprop("/autopilot/route-manager/wp/id"));
nd.symbols.wpActiveId.show();
},
is_false: func(nd) nd.symbols.wpActiveId.hide(),
}, # of wpActiveId.impl
}, # of wpActiveId
{
id: 'wpActiveDist',
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and getprop("autopilot/route-manager/active")
and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
is_true: func(nd) {
nd.symbols.wpActiveDist.setText(sprintf("%3.01f",getprop("/autopilot/route-manager/wp/dist")));
nd.symbols.wpActiveDist.show();
},
is_false: func(nd) nd.symbols.wpActiveDist.hide(),
},
},
{
id: 'wpActiveDistLbl',
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and getprop("autopilot/route-manager/active")
and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
is_true: func(nd) {
nd.symbols.wpActiveDistLbl.show();
if(getprop("/autopilot/route-manager/wp/dist") > 1000)
nd.symbols.wpActiveDistLbl.setText(" NM");
},
is_false: func(nd) nd.symbols.wpActiveDistLbl.hide(),
},
},
{
id: 'eta',
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("autopilot/route-manager/wp/eta") != nil and getprop("autopilot/route-manager/active")
and nd.in_mode('toggle_display_mode', ['MAP','PLAN']),
is_true: func(nd) {
var etaSec = getprop("/sim/time/utc/day-seconds")+getprop("autopilot/route-manager/wp/eta-seconds");
var h = math.floor(etaSec/3600);
etaSec=etaSec-3600*h;
var m = math.floor(etaSec/60);
etaSec=etaSec-60*m;
var s = etaSec/10;
if (h>24) h=h-24;
nd.symbols.eta.setText(sprintf("%02.0f%02.0f.%01.0fz",h,m,s));
nd.symbols.eta.show();
},
is_false: func(nd) nd.symbols.eta.hide(),
}, # of eta.impl
}, # of eta
{
id: 'gsGroup',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']),
is_true: func(nd) {
if(nd.get_switch('toggle_centered'))
nd.symbols.gsGroup.setTranslation(0,0);
else
nd.symbols.gsGroup.setTranslation(0,150);
nd.symbols.gsGroup.show();
},
is_false: func(nd) nd.symbols.gsGroup.hide(),
},
},
2014-07-06 21:17:47 +00:00
{
id: 'compassApp',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['APP','VOR'])),
is_true: func(nd) {
if(nd.get_switch('toggle_true_north'))
var hdg = nd.aircraft_source.get_trk_tru();
else
var hdg = nd.aircraft_source.get_trk_mag();
nd.symbols.compassApp.setRotation(-hdg*D2R);
nd.symbols.compassApp.show();
},
is_false: func(nd) nd.symbols.compassApp.hide(),
},
},
{
id: 'compassMapCtr',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['MAP'])),
is_true: func(nd) {
if(nd.get_switch('toggle_true_north'))
var hdg = nd.aircraft_source.get_trk_tru();
else
var hdg = nd.aircraft_source.get_trk_mag();
nd.symbols.compassMapCtr.setRotation(-hdg*D2R);
nd.symbols.compassMapCtr.show();
},
is_false: func(nd) nd.symbols.compassMapCtr.hide(),
},
},
2014-05-25 18:11:13 +00:00
{
id:'hdg',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']),
is_true: func(nd) {
var hdgText = "";
if((nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_display_type') == "CRT")
or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
{
if(nd.get_switch('toggle_true_north'))
hdgText = nd.aircraft_source.get_trk_tru();
else
hdgText = nd.aircraft_source.get_trk_mag();
} else {
if(nd.get_switch('toggle_true_north'))
hdgText = nd.aircraft_source.get_hdg_tru();
else
hdgText = nd.aircraft_source.get_hdg_mag();
}
if(hdgText < 0.5) hdgText = 360 + hdgText;
elsif(hdgText >= 360.5) hdgText = hdgText - 360;
nd.symbols.hdg.setText(sprintf("%03.0f", hdgText));
},
is_false: NOTHING,
},
},
{
id:'hdgGroup',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']),
is_true: func(nd) {
nd.symbols.hdgGroup.show();
if(nd.get_switch('toggle_centered'))
nd.symbols.hdgGroup.setTranslation(0,100);
else
nd.symbols.hdgGroup.setTranslation(0,0);
},
is_false: func(nd) nd.symbols.hdgGroup.hide(),
},
},
{
id:'gs',
impl: {
init: func(nd,symbol),
common: func(nd) nd.symbols.gs.setText(sprintf("%3.0f",nd.aircraft_source.get_gnd_spd() )),
predicate: func(nd) nd.aircraft_source.get_gnd_spd() >= 30,
is_true: func(nd) {
nd.symbols.gs.setFontSize(36);
},
is_false: func(nd) nd.symbols.gs.setFontSize(52),
},
},
2014-07-06 21:17:47 +00:00
{
id:'compass',
impl: {
init: func(nd,symbol),
predicate: func(nd) ((nd.get_switch('toggle_centered') and !nd.in_mode('toggle_display_mode', ['PLAN'])) or nd.in_mode('toggle_display_mode', ['PLAN'])),
is_true: func(nd) nd.symbols.compass.hide(),
is_false: func(nd) {
nd.symbols.compass.show();
nd.symbols.compass.setRotation(-nd.userHdgTrk*D2R);
},
},
},
{
id:'truMag',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.get_switch('toggle_true_north'),
is_true: func(nd) nd.symbols.truMag.setText("TRU"),
is_false: func(nd) nd.symbols.truMag.setText("MAG"),
},
},
{
id:'northUp',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['PLAN']),
is_true: func(nd) nd.symbols.northUp.show(),
is_false: func(nd) nd.symbols.northUp.hide(),
},
},
{
id:'planArcs',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['PLAN']),
is_true: func(nd) nd.symbols.planArcs.show(),
is_false: func(nd) nd.symbols.planArcs.hide(),
},
},
{
id:'aplSymMap',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']) and !nd.get_switch('toggle_centered')),
is_true: func(nd) nd.symbols.aplSymMap.show(),
is_false: func(nd) nd.symbols.aplSymMap.hide(),
},
},
{
id:'aplSymMapCtr',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_centered')),
is_true: func(nd) nd.symbols.aplSymMapCtr.show(),
is_false: func(nd) nd.symbols.aplSymMapCtr.hide(),
},
},
{
id:'aplSymVor',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered')),
is_true: func(nd) nd.symbols.aplSymVor.show(),
is_false: func(nd) nd.symbols.aplSymVor.hide(),
},
},
2014-05-25 18:11:13 +00:00
{
id:'rangeArcs',
impl: {
init: func(nd,symbol),
predicate: func(nd) !nd.get_switch('toggle_centered') and nd.get_switch('toggle_rangearc'),
is_true: func(nd) nd.symbols.rangeArcs.show(),
is_false: func(nd) nd.symbols.rangeArcs.hide(),
2014-07-06 21:17:47 +00:00
},
},
2014-05-25 18:11:13 +00:00
{
id:'rangePln1',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
is_true: func(nd) {
nd.symbols.rangePln1.show();
nd.symbols.rangePln1.setText(sprintf("%3.0f",nd.rangeNm()));
},
is_false: func(nd) nd.symbols.rangePln1.hide(),
},
},
{
id:'rangePln2',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
is_true: func(nd) {
nd.symbols.rangePln2.show();
nd.symbols.rangePln2.setText(sprintf("%3.0f",nd.rangeNm()/2));
},
is_false: func(nd) nd.symbols.rangePln2.hide(),
},
},
{
id:'rangePln3',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
is_true: func(nd) {
nd.symbols.rangePln3.show();
nd.symbols.rangePln3.setText(sprintf("%3.0f",nd.rangeNm()/2));
},
is_false: func(nd) nd.symbols.rangePln3.hide(),
},
},
{
id:'rangePln4',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN",
is_true: func(nd) {
nd.symbols.rangePln4.show();
nd.symbols.rangePln4.setText(sprintf("%3.0f",nd.rangeNm()));
},
is_false: func(nd) nd.symbols.rangePln4.hide(),
},
},
2014-07-06 21:17:47 +00:00
{
id:'range',
impl: {
init: func(nd,symbol),
predicate: func(nd) !nd.get_switch('toggle_centered'),
is_true: func(nd) {
nd.symbols.range.setText(sprintf("%3.0f",nd.rangeNm()/2));
},
is_false: func(nd) nd.symbols.rangePln4.hide(),
},
},
{
id:'rangeCtr1',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['APP','MAP','VOR'])),
is_true: func(nd) {
nd.symbols.rangeCtr1.show();
2014-07-08 10:28:26 +00:00
nd.symbols.rangeCtr1.setText(sprintf("%g",nd.rangeNm()/4));
2014-07-06 21:17:47 +00:00
},
is_false: func(nd) nd.symbols.rangeCtr1.hide(),
},
},
{
id:'rangeCtr2',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['APP','MAP','VOR'])),
is_true: func(nd) {
nd.symbols.rangeCtr2.show();
2014-07-08 10:28:26 +00:00
nd.symbols.rangeCtr2.setText(sprintf("%g",nd.rangeNm()/4));
2014-07-06 21:17:47 +00:00
},
is_false: func(nd) nd.symbols.rangeCtr2.hide(),
},
},
{
id:'altArc',
impl: {
init: func(nd,symbol),
predicate: func(nd) (!nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['MAP'])),
is_true: func(nd) {
var altDiff = (getprop("autopilot/settings/target-altitude-ft") or 0)-(getprop("instrumentation/altimeter/indicated-altitude-ft") or 0);
if (abs(altDiff) > 50 and altDiff/nd.aircraft_source.get_vspd() > 0) {
var altRangeNm = altDiff/nd.aircraft_source.get_vspd()*nd.aircraft_source.get_gnd_spd()*KT2MPS*M2NM;
if(altRangeNm > 1) {
var altRangePx = (350/nd.rangeNm())*altRangeNm;
if (altRangePx > 700)
altRangePx = 700;
nd.symbols.altArc.setTranslation(0,-altRangePx);
}
nd.symbols.altArc.show();
} else
nd.symbols.altArc.hide();
},
is_false: func(nd) nd.symbols.altArc.hide(),
},
},
{
id:'altArcCtr',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_centered') and nd.in_mode('toggle_display_mode', ['MAP'])),
is_true: func(nd) {
var altDiff = (getprop("autopilot/settings/target-altitude-ft") or 0)-(getprop("instrumentation/altimeter/indicated-altitude-ft") or 0);
if (abs(altDiff) > 50 and altDiff/nd.aircraft_source.get_vspd() > 0) {
var altRangeNm = altDiff/nd.aircraft_source.get_vspd()*nd.aircraft_source.get_gnd_spd()*KT2MPS*M2NM;
if(altRangeNm > 1) {
var altRangePx = (175/nd.rangeNm())*altRangeNm;
if (altRangePx > 350)
altRangePx = 350;
nd.symbols.altArcCtr.setTranslation(0,-altRangePx);
}
nd.symbols.altArcCtr.show();
} else
nd.symbols.altArcCtr.hide();
},
is_false: func(nd) nd.symbols.altArcCtr.hide(),
},
},
2014-05-25 18:11:13 +00:00
{
id:'crsLbl',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
is_true: func(nd) nd.symbols.crsLbl.show(),
is_false: func(nd) nd.symbols.crsLbl.hide(),
},
},
{
id:'crs',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
is_true: func(nd) {
nd.symbols.crs.show();
if(getprop("instrumentation/nav/radials/selected-deg") != nil)
nd.symbols.crs.setText(sprintf("%03.0f",getprop("instrumentation/nav/radials/selected-deg")));
},
is_false: func(nd) nd.symbols.crs.hide(),
},
},
{
id:'dmeLbl',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
is_true: func(nd) nd.symbols.dmeLbl.show(),
is_false: func(nd) nd.symbols.dmeLbl.hide(),
},
},
{
id:'dme',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']),
is_true: func(nd) {
nd.symbols.dme.show();
if(getprop("instrumentation/dme/in-range"))
nd.symbols.dme.setText(sprintf("%3.1f",getprop("instrumentation/dme/indicated-distance-nm")));
},
is_false: func(nd) nd.symbols.dme.hide(),
},
},
{
id:'trkInd2',
impl: {
init: func(nd,symbol),
2014-07-06 21:17:47 +00:00
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered')),
2014-05-25 18:11:13 +00:00
is_true: func(nd) {
2014-07-06 21:17:47 +00:00
if (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD")
nd.symbols.trkInd2.setRotation(0);
else
nd.symbols.trkInd2.setRotation((nd.userTrk-nd.userHdg)*D2R);
2014-05-25 18:11:13 +00:00
nd.symbols.trkInd2.show();
},
is_false: func(nd) nd.symbols.trkInd2.hide(),
},
},
2014-07-06 21:17:47 +00:00
{
id:'trkIndMapCtr',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_centered')),
is_true: func(nd) {
if (nd.get_switch('toggle_display_type') == "CRT" or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
nd.symbols.trkIndMapCtr.setRotation(0);
else
nd.symbols.trkIndMapCtr.setRotation((nd.userTrk-nd.userHdg)*D2R);
nd.symbols.trkIndMapCtr.show();
},
is_false: func(nd) nd.symbols.trkIndMapCtr.hide(),
},
},
2014-05-25 18:11:13 +00:00
{
id:'vorCrsPtr',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered')),
is_true: func(nd) {
nd.symbols.vorCrsPtr.show();
if((nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_display_type') == "CRT")
or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
nd.symbols.vorCrsPtr.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_trk_mag())*D2R);
else
nd.symbols.vorCrsPtr.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_hdg_mag())*D2R);
},
is_false: func(nd) nd.symbols.vorCrsPtr.hide(),
},
},
{
id:'vorCrsPtr2',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered')),
is_true: func(nd) {
nd.symbols.vorCrsPtr2.show();
if((nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_display_type') == "CRT")
or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
nd.symbols.vorCrsPtr2.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_trk_mag())*D2R);
else
nd.symbols.vorCrsPtr2.setRotation((getprop("instrumentation/nav/radials/selected-deg")-nd.aircraft_source.get_hdg_mag())*D2R);
},
is_false: func(nd) nd.symbols.vorCrsPtr2.hide(),
},
},
{
id: 'gsDiamond',
impl: {
init: func(nd,symbol),
predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']) and getprop("instrumentation/nav/gs-in-range"),
is_true: func(nd) {
var gs_deflection = getprop("instrumentation/nav/gs-needle-deflection-norm");
if(gs_deflection != nil)
nd.symbols.gsDiamond.setTranslation(gs_deflection*150,0);
if(abs(gs_deflection) < 0.99)
nd.symbols.gsDiamond.setColorFill(1,0,1,1);
else
nd.symbols.gsDiamond.setColorFill(0,0,0,1);
},
is_false: func(nd) nd.symbols.gsGroup.hide(),
},
},
{
id:'locPtr',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered') and getprop("instrumentation/nav/in-range")),
is_true: func(nd) {
nd.symbols.locPtr.show();
var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
nd.symbols.locPtr.setTranslation(deflection*150,0);
if(abs(deflection) < 0.99)
nd.symbols.locPtr.setColorFill(1,0,1,1);
else
nd.symbols.locPtr.setColorFill(0,0,0,1);
},
is_false: func(nd) nd.symbols.locPtr.hide(),
},
},
{
id:'locPtr2',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered') and getprop("instrumentation/nav/in-range")),
is_true: func(nd) {
nd.symbols.locPtr2.show();
var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
nd.symbols.locPtr2.setTranslation(deflection*150,0);
if(abs(deflection) < 0.99)
nd.symbols.locPtr2.setColorFill(1,0,1,1);
else
nd.symbols.locPtr2.setColorFill(0,0,0,1);
},
is_false: func(nd) nd.symbols.locPtr2.hide(),
},
},
{
id:'wind',
impl: {
init: func(nd,symbol),
2014-07-10 21:07:47 +00:00
predicate: func(nd) (nd.aircraft_source.get_spd() > 100 and getprop("environment/wind-speed-kt") > 4),
2014-05-25 18:11:13 +00:00
is_true: func(nd) {
var windDir = getprop("environment/wind-from-heading-deg");
2014-07-10 21:07:47 +00:00
var windSpd = getprop("environment/wind-speed-kt");
2014-05-25 18:11:13 +00:00
if(!nd.get_switch('toggle_true_north'))
windDir = windDir - getprop("environment/magnetic-variation-deg");
2015-05-16 11:53:01 +00:00
while(windDir < 0.5) windDir += 360;
while(windDir > 360.5) windDir -= 360;
2014-07-10 21:07:47 +00:00
if (windSpd > 6)
nd.windShown = 1;
if (nd.windShown != 0) {
nd.symbols.wind.setText(sprintf("%03.0f / %02.0f",windDir,windSpd));
nd.symbols.wind.show();
} else
nd.symbols.wind.hide();
},
is_false: func(nd) {
nd.windShown = 0;
nd.symbols.wind.hide();
2014-05-25 18:11:13 +00:00
},
},
},
{
id:'windArrow',
impl: {
init: func(nd,symbol),
2014-07-10 21:07:47 +00:00
predicate: func(nd) (!(nd.in_mode('toggle_display_mode', ['PLAN']) and (nd.get_switch('toggle_display_type') == "LCD")) and nd.aircraft_source.get_spd() > 100 and getprop("environment/wind-speed-kt") > 4),
2014-05-25 18:11:13 +00:00
is_true: func(nd) {
2014-07-10 21:07:47 +00:00
if (nd.windShown != 0) {
nd.symbols.windArrow.show();
var windArrowRot = getprop("environment/wind-from-heading-deg");
if((nd.in_mode('toggle_display_mode', ['MAP','PLAN']) and nd.get_switch('toggle_display_type') == "CRT")
or (nd.get_switch('toggle_track_heading') and nd.get_switch('toggle_display_type') == "LCD"))
windArrowRot = windArrowRot - nd.aircraft_source.get_trk_mag();
else
windArrowRot = windArrowRot - nd.aircraft_source.get_hdg_mag();
2014-05-25 18:11:13 +00:00
nd.symbols.windArrow.setRotation(windArrowRot*D2R);
2014-07-10 21:07:47 +00:00
} else {
nd.symbols.windArrow.hide();
}
2014-05-25 18:11:13 +00:00
},
is_false: func(nd) nd.symbols.windArrow.hide(),
},
},
2014-07-10 21:07:47 +00:00
{
id:'vorL',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
is_true: func(nd) {
if(nd.get_switch('toggle_lh_vor_adf') == 1) {
nd.symbols.vorL.setText("VOR L");
nd.symbols.vorL.setColor(0.195,0.96,0.097);
} else {
nd.symbols.vorL.setText("ADF L");
nd.symbols.vorL.setColor(0,0.6,0.85);
}
nd.symbols.vorL.show();
},
is_false: func(nd) nd.symbols.vorL.hide(),
},
},
{
id:'vorLId',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
is_true: func(nd) {
if(nd.get_switch('toggle_lh_vor_adf') == 1) {
if(getprop("instrumentation/nav/in-range"))
nd.symbols.vorLId.setText(getprop("instrumentation/nav/nav-id"));
else
nd.symbols.vorLId.setText(getprop("instrumentation/nav/frequencies/selected-mhz-fmt"));
nd.symbols.vorLId.setColor(0.195,0.96,0.097);
} else {
if((var navident=getprop("instrumentation/adf/ident")) != "")
nd.symbols.vorLId.setText(navident);
else
nd.symbols.vorLId.setText(sprintf("%3d",getprop("instrumentation/adf/frequencies/selected-khz")));
nd.symbols.vorLId.setColor(0,0.6,0.85);
}
nd.symbols.vorLId.show();
},
is_false: func(nd) nd.symbols.vorLId.hide(),
},
},
{
id:'dmeLDist',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
is_true: func(nd) {
if(nd.get_switch('toggle_lh_vor_adf') == 1) {
if(getprop("instrumentation/dme/in-range"))
nd.symbols.dmeLDist.setText(sprintf("%3.1f",getprop("instrumentation/dme/indicated-distance-nm")));
else
nd.symbols.dmeLDist.setText(" ---");
nd.symbols.dmeLDist.setColor(0.195,0.96,0.097);
} else {
nd.symbols.dmeLDist.setText("");
nd.symbols.dmeLDist.setColor(0,0.6,0.85);
}
nd.symbols.dmeLDist.show();
},
is_false: func(nd) nd.symbols.dmeLDist.hide(),
},
},
{
id:'dmeL',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0),
is_true: func(nd) {
if(nd.get_switch('toggle_lh_vor_adf') == 1) {
nd.symbols.dmeL.setText("DME");
nd.symbols.dmeL.setColor(0.195,0.96,0.097);
} else {
nd.symbols.dmeL.setText("");
nd.symbols.dmeL.setColor(0,0.6,0.85);
}
nd.symbols.dmeL.show();
},
is_false: func(nd) nd.symbols.dmeL.hide(),
},
},
2015-05-16 11:53:01 +00:00
# TACAN added by tikibar (J. Williams)
{
id:'TCNArrow',
impl: {
init: func(nd,symbol),
# predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and !nd.get_switch('toggle_centered') and getprop("instrumentation/efis/enable-canvas-tacan-display")),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and !nd.get_switch('toggle_centered') and nd.efis_switches['toggle_tacan'] != nil),
is_true: func(nd) {
if (nd.get_switch('toggle_tacan')) {
nd.symbols.TCNArrow.show();
nd.symbols.TCNArrow.setRotation((getprop("instrumentation/tacan/indicated-bearing-true-deg")-nd.aircraft_source.get_hdg_tru())*D2R);
} else {
nd.symbols.TCNArrow.hide();
}
},
is_false: func(nd) nd.symbols.TCNArrow.hide(),
},
},
{
id:'TCNArrow2',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.get_switch('toggle_centered') and nd.efis_switches['toggle_tacan'] != nil),
is_true: func(nd) {
if (nd.get_switch('toggle_tacan')) {
nd.symbols.TCNArrow2.show();
nd.symbols.TCNArrow2.setRotation((getprop("instrumentation/tacan/indicated-bearing-true-deg")-nd.aircraft_source.get_hdg_tru())*D2R);
} else {
nd.symbols.TCNArrow2.hide();
}
},
is_false: func(nd) nd.symbols.TCNArrow2.hide(),
},
},
{
id:'TACAN',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.efis_switches['toggle_tacan'] != nil),
is_true: func(nd) {
if (nd.get_switch('toggle_tacan')) {
nd.symbols.TACAN.setText("TACAN");
nd.symbols.TACAN.show();
} else {
nd.symbols.TACAN.hide();
}
},
is_false: func(nd) nd.symbols.TACAN.hide(),
},
},
{
id:'TACANId',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.efis_switches['toggle_tacan'] != nil),
is_true: func(nd) {
if (nd.get_switch('toggle_tacan') and getprop("instrumentation/tacan/in-range")) {
nd.symbols.TACANId.setText(getprop("instrumentation/tacan/ident"));
nd.symbols.TACANId.show();
} else {
nd.symbols.TACANId.hide();
}
},
is_false: func(nd) nd.symbols.TACANId.hide(),
},
},
{
id:'TACANdme',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.efis_switches['toggle_tacan'] != nil),
is_true: func(nd) {
if (nd.get_switch('toggle_tacan') and getprop("instrumentation/tacan/in-range")) {
nd.symbols.TACANdme.setText("DIST");
nd.symbols.TACANdme.show();
} else {
nd.symbols.TACANdme.hide();
}
},
is_false: func(nd) nd.symbols.TACANdme.hide(),
},
},
{
id:'TACANdmeDist',
impl: {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP']) and nd.efis_switches['toggle_tacan'] != nil),
is_true: func(nd) {
if (nd.get_switch('toggle_tacan') and getprop("instrumentation/tacan/in-range")) {
nd.symbols.TACANdmeDist.setText(sprintf("%3.1f",getprop("instrumentation/tacan/indicated-distance-nm")));
nd.symbols.TACANdmeDist.show();
} else {
nd.symbols.TACANdmeDist.hide();
}
},
is_false: func(nd) nd.symbols.TACANdmeDist.hide(),
},
},
2014-05-25 18:11:13 +00:00
], # end of vector with features
}, # end of Boeing style
#####
##
## add support for other aircraft/ND types and styles here (Airbus etc)
## or move to other files.
##
## see: http://wiki.flightgear.org/NavDisplay#Custom_ND_Styles
## and: http://wiki.flightgear.org/NavDisplay#Adding_new_features
}; # end of NDStyles