1
0
Fork 0

Boeing ND:

- add VOR, APP, PLAN and CTR modes.
- add true/mag switch
- display waypoint altitudes
This commit is contained in:
Gijs de Rooy 2013-12-28 16:18:35 +01:00
parent a4e35e255a
commit 2b6964911f
12 changed files with 1677 additions and 264 deletions

View file

@ -369,6 +369,5 @@ settimer(func {
me.del(); me.del();
}; };
}, 1); }, 1);
else print("MapStructure.nas: Testing code disabled, see $FG_ROOT/gui/dialogs/map-canvas.xml instead");
}, 0); # end ugly module init timer hack }, 0); # end ugly module init timer hack

View file

@ -0,0 +1,19 @@
##
# draw a single airplane symbol
#
var draw_airplane_symbol = func (group, apl, controller=nil, lod=0) {
var lat = apl.lat;
var lon = apl.lon;
var hdg = apl.hdg;
var airplane_grp = group.createChild("group","airplane");
canvas.parsesvg(airplane_grp, "Nasal/canvas/map/boeingAirplane.svg");
var aplSymbol = airplane_grp.getElementById("airplane");
aplSymbol.setTranslation(-45,-52)
.setCenter(0,0);
airplane_grp.setGeoPosition(lat, lon)
.set("z-index",10)
.setRotation(hdg*D2R);
}

View file

@ -0,0 +1,10 @@
var AirplaneSymbolLayer = {};
AirplaneSymbolLayer.new = func(group,name, controller) {
var m=Layer.new(group, name, AirplaneSymbolModel);
m._model._controller = controller; # set up the controller for the model !!!!!
m.setDraw (func draw_layer(layer:m, callback: draw_airplane_symbol, lod:0) );
return m;
}
register_layer("airplaneSymbol", AirplaneSymbolLayer);

View file

@ -0,0 +1,12 @@
var AirplaneSymbolModel = {};
AirplaneSymbolModel.new = func make( LayerModel, AirplaneSymbolModel );
AirplaneSymbolModel.init = func {
me._view.reset(); # wraps removeAllChildren() ATM
me.push( { lat: getprop("/position/latitude-deg"), lon : getprop("/position/longitude-deg"), hdg : getprop("/orientation/heading-deg") } );
me.notifyView();
}

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="87.8438"
height="108.844"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="boeingAirplane.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.9598"
inkscape:cx="19.8149"
inkscape:cy="54.088"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1366"
inkscape:window-height="716"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-364.652,-344.745)">
<g
id="airplane"
transform="translate(364.652,346.745)"
inkscape:label="#g3781">
<path
id="path3783"
d="M 29.126,102.65 29.2323,93.5433 35.3622,85.2874 34.6535,58.0039 2.12598,76.3228 1.98425,65.9764 35.185,35.5394 35.3976,15.0945 42.378,2.01969 50.563,15.5197 50.315,35.4685 85.8543,65.6575 85.748,75.0118 52.3701,56.9409 52.0157,86.2441 58.748,93.6496 58.6417,103.5 44.0787,95.4921 z"
style="fill:none;stroke:#ededed;stroke-width:3.9685px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View file

@ -4,23 +4,15 @@ FixModel.new = func make( LayerModel, FixModel );
FixModel.init = func { FixModel.init = func {
me._view.reset(); # wraps removeAllChildren() ATM me._view.reset(); # wraps removeAllChildren() ATM
#fgcommand('profiler-start');
#me._view._view.removeAllChildren(); # clear the "real" canvas drawables
#fgcommand('profiler-stop');
#me.clear();
#debug.dump( me._controller) ;
#print("Query range is:", me._controller['query_range']() );
var results = positioned.findWithinRange( me._controller['query_range']()*2 ,"fix"); var results = positioned.findWithinRange( me._controller['query_range']()*2 ,"fix");
var numNum = 0;
foreach(result; results) { foreach(result; results) {
# Skip airport navaids (real thing makes distinction between high/low altitude fixes)
if(string.match(result.id,"*[^0-9]")) {
me.push(result); me.push(result);
numNum = numNum + 1;
}
} }
#print("query range was:", me._controller['query_range']()*2);
#print("total fixes in results/model:", size(results));
me.notifyView(); me.notifyView();
} }

View file

@ -7,5 +7,3 @@ NavaidModel.init = func {
me.push(n); me.push(n);
me.notifyView(); me.notifyView();
} }

View file

@ -1,5 +1,5 @@
# ============================================================================== # ==============================================================================
# Boeing Navigation Display by Gijs de Rooy (currently specific to the 744) # Boeing Navigation Display by Gijs de Rooy
# ============================================================================== # ==============================================================================
@ -52,12 +52,10 @@ var NDStyles = {
## ##
layers: [ layers: [
{ name:'fixes', update_on:['toggle_range','toggle_waypoints'], predicate: func(nd, layer) { { name:'fixes', update_on:['toggle_range','toggle_waypoints','toggle_display_mode'], predicate: func(nd, layer) {
# print("Running fixes predicate"); # print("Running fixes predicate");
var visible=nd.get_switch('toggle_waypoints'); var visible=nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']);
if(nd.rangeNm() <= 40 and visible and if(nd.rangeNm() <= 40 and visible) {
nd.get_switch('toggle_display_mode') == "MAP") {
# print("fixes update requested!");
trigger_update( layer ); trigger_update( layer );
} layer._view.setVisible(visible); } layer._view.setVisible(visible);
@ -69,7 +67,16 @@ var NDStyles = {
# print("Running fixes predicate"); # print("Running fixes predicate");
var visible=nd.get_switch('toggle_weather') and nd.get_switch('toggle_display_mode') != "PLAN"; var visible=nd.get_switch('toggle_weather') and nd.get_switch('toggle_display_mode') != "PLAN";
if (visible) { if (visible) {
print("storms update requested!"); trigger_update( layer );
} layer._view.setVisible(visible);
}, # end of layer update predicate
}, # end of storms layer
{ name:'airplaneSymbol', update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) {
# print("Running fixes predicate");
var visible=nd.get_switch('toggle_display_mode') == "PLAN";
if (visible) {
trigger_update( layer ); trigger_update( layer );
} layer._view.setVisible(visible); } layer._view.setVisible(visible);
@ -78,54 +85,53 @@ var NDStyles = {
{ name:'airports-nd', update_on:['toggle_range','toggle_airports','toggle_display_mode'], predicate: func(nd, layer) { { name:'airports-nd', update_on:['toggle_range','toggle_airports','toggle_display_mode'], predicate: func(nd, layer) {
# print("Running airports-nd predicate"); # print("Running airports-nd predicate");
if (nd.rangeNm() <= 80 and var visible = nd.get_switch('toggle_airports') and nd.in_mode('toggle_display_mode', ['MAP']);
nd.get_switch('toggle_display_mode') == "MAP" ) { if (nd.rangeNm() <= 80 and visible) {
trigger_update( layer ); # clear & redraw trigger_update( layer ); # clear & redraw
} }
layer._view.setVisible( nd.get_switch('toggle_airports') ); layer._view.setVisible( visible);
}, # end of layer update predicate }, # end of layer update predicate
}, # end of airports layer }, # end of airports layer
{ name:'vor', update_on:['toggle_range','toggle_stations','toggle_display_mode'], predicate: func(nd, layer) { { name:'vor', update_on:['toggle_range','toggle_stations','toggle_display_mode'], predicate: func(nd, layer) {
# print("Running vor layer predicate"); var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']);
if(nd.rangeNm() <= 40 and if(nd.rangeNm() <= 40 and visible) {
nd.get_switch('toggle_stations') and
nd.get_switch('toggle_display_mode') == "MAP"){
trigger_update( layer ); # clear & redraw trigger_update( layer ); # clear & redraw
} }
layer._view.setVisible( nd.get_switch('toggle_stations') ); layer._view.setVisible( visible );
}, # end of layer update predicate }, # end of layer update predicate
}, # end of VOR layer }, # end of VOR layer
{ name:'dme', update_on:['toggle_range','toggle_stations'], predicate: func(nd, layer) { { name:'dme', update_on:['toggle_range','toggle_stations','toggle_display_mode'], predicate: func(nd, layer) {
if(nd.rangeNm() <= 40 and var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']);
nd.get_switch('toggle_stations') and if(nd.rangeNm() <= 40 and visible){
nd.get_switch('toggle_display_mode') == "MAP"){
trigger_update( layer ); # clear & redraw trigger_update( layer ); # clear & redraw
} }
layer._view.setVisible( nd.get_switch('toggle_stations') ); layer._view.setVisible( visible );
}, # end of layer update predicate }, # end of layer update predicate
}, # end of DME layer }, # end of DME layer
{ name:'mp-traffic', update_on:['toggle_range','toggle_traffic'], predicate: func(nd, layer) { { name:'mp-traffic', update_on:['toggle_range','toggle_traffic'], predicate: func(nd, layer) {
trigger_update( layer ); # clear & redraw trigger_update( layer ); # clear & redraw
layer._view.setVisible( 1 ); #nd.get_switch('toggle_traffic') layer._view.setVisible( nd.get_switch('toggle_traffic') );
}, # end of layer update predicate }, # end of layer update predicate
}, # end of traffic layer }, # end of traffic layer
{ name:'runway-nd', update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) { { name:'runway-nd', update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) {
var visible = (nd.rangeNm() <= 40 and getprop("autopilot/route-manager/active") ) ; var visible = (nd.rangeNm() <= 40 and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP','PLAN'])) ;
if (visible) if (visible)
trigger_update( layer ); # clear & redraw trigger_update( layer ); # clear & redraw
layer._view.setVisible( visible ); layer._view.setVisible( visible );
}, # end of layer update predicate }, # end of layer update predicate
}, # end of airports-nd layer }, # end of airports-nd layer
{ name:'route', update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) { { name:'route', update_on:['toggle_display_mode',], predicate: func(nd, layer) {
var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
if (visible) {
trigger_update( layer ); # clear & redraw trigger_update( layer ); # clear & redraw
layer._view.setVisible( 1 ); #nd.get_switch('toggle_traffic') }
layer._view.setVisible( visible );
}, # end of layer update predicate }, # end of layer update predicate
}, # end of route layer }, # end of route layer
@ -229,7 +235,7 @@ var NDStyles = {
{ id:'rangeArcs', { id:'rangeArcs',
impl: { impl: {
init: func(nd,symbol), init: func(nd,symbol),
predicate: func(nd) (((nd.get_switch('toggle_display_mode') == "APP" or nd.get_switch('toggle_display_mode') == "VOR") and nd.get_switch('toggle_weather')) or nd.get_switch('toggle_display_mode') == "MAP"), predicate: func(nd) ((nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_weather')) or (nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered'))),
is_true: func(nd) nd.symbols.rangeArcs.show(), is_true: func(nd) nd.symbols.rangeArcs.show(),
is_false: func(nd) nd.symbols.rangeArcs.hide(), is_false: func(nd) nd.symbols.rangeArcs.hide(),
}, # of rangeArcs.impl }, # of rangeArcs.impl
@ -256,10 +262,13 @@ var NDSourceDriver = {};
NDSourceDriver.new = func { NDSourceDriver.new = func {
var m = {parents:[NDSourceDriver]}; var m = {parents:[NDSourceDriver]};
m.get_hdg_mag= func getprop("/orientation/heading-magnetic-deg"); m.get_hdg_mag= func getprop("/orientation/heading-magnetic-deg");
m.get_hdg_tru= func getprop("/orientation/heading-deg");
m.get_trk_mag= func getprop("/orientation/track-magnetic-deg"); m.get_trk_mag= func getprop("/orientation/track-magnetic-deg");
m.get_trk_tru= func getprop("/orientation/track-deg");
m.get_lat= func getprop("/position/latitude-deg"); m.get_lat= func getprop("/position/latitude-deg");
m.get_lon= func getprop("/position/longitude-deg"); m.get_lon= func getprop("/position/longitude-deg");
m.get_spd= func getprop("/velocities/groundspeed-kt"); m.get_spd= func getprop("/velocities/groundspeed-kt");
m.get_vspd= func getprop("/velocities/vertical-speed-fps");
return m; return m;
} }
@ -275,7 +284,7 @@ return m;
# TODO: switches are ND specific, so move to the NDStyle hash! # TODO: switches are ND specific, so move to the NDStyle hash!
var default_switches = { var default_switches = {
'toggle_range': {path: '/inputs/range-nm', value:40, type:'INT'}, 'toggle_range': {path: '/inputs/range-nm', value:10, type:'INT'},
'toggle_weather': {path: '/inputs/wxr', value:0, type:'BOOL'}, 'toggle_weather': {path: '/inputs/wxr', value:0, type:'BOOL'},
'toggle_airports': {path: '/inputs/arpt', value:0, type:'BOOL'}, 'toggle_airports': {path: '/inputs/arpt', value:0, type:'BOOL'},
'toggle_stations': {path: '/inputs/sta', value:0, type:'BOOL'}, 'toggle_stations': {path: '/inputs/sta', value:0, type:'BOOL'},
@ -283,8 +292,10 @@ var default_switches = {
'toggle_position': {path: '/inputs/pos', value:0, type:'BOOL'}, 'toggle_position': {path: '/inputs/pos', value:0, type:'BOOL'},
'toggle_data': {path: '/inputs/data',value:0, type:'BOOL'}, 'toggle_data': {path: '/inputs/data',value:0, type:'BOOL'},
'toggle_terrain': {path: '/inputs/terr',value:0, type:'BOOL'}, 'toggle_terrain': {path: '/inputs/terr',value:0, type:'BOOL'},
'toggle_traffic': {path: '/inputs/tcas',value:0, type:'BOOL'}, 'toggle_traffic': {path: '/inputs/tfc',value:0, type:'BOOL'},
'toggle_centered': {path: '/inputs/nd-centered',value:0, type:'BOOL'},
'toggle_display_mode': {path: '/mfd/display-mode', value:'MAP', type:'STRING'}, 'toggle_display_mode': {path: '/mfd/display-mode', value:'MAP', type:'STRING'},
'toggle_true_north': {path: '/mfd/true-north', value:0, type:'BOOL'},
}; };
# Hack to update weather radar once every 10 seconds # Hack to update weather radar once every 10 seconds
@ -295,6 +306,14 @@ var update_weather = func {
} }
update_weather(); update_weather();
# Hack to update airplane symbol location on PLAN mode every 5 seconds
var update_apl_sym = func {
if (getprop("/instrumentation/efis/mfd/display-mode") == "PLAN")
setprop("/instrumentation/efis/mfd/display-mode","PLAN");
settimer(update_apl_sym, 5);
}
update_apl_sym();
## ##
# TODO: # TODO:
# - introduce a MFD class (use it also for PFD/EICAS) # - introduce a MFD class (use it also for PFD/EICAS)
@ -344,10 +363,13 @@ var NavDisplay = {
connectAI: func(source=nil) { connectAI: func(source=nil) {
me.aircraft_source = { me.aircraft_source = {
get_hdg_mag: func source.getNode('orientation/heading-magnetic-deg').getValue(), get_hdg_mag: func source.getNode('orientation/heading-magnetic-deg').getValue(),
get_hdg_tru: func source.getNode('orientation/heading-deg').getValue(),
get_trk_mag: func source.getNode('orientation/track-magnetic-deg').getValue(), get_trk_mag: func source.getNode('orientation/track-magnetic-deg').getValue(),
get_trk_tru: func source.getNode('orientation/track-deg').getValue(),
get_lat: func source.getNode('position/latitude-deg').getValue(), get_lat: func source.getNode('position/latitude-deg').getValue(),
get_lon: func source.getNode('position/longitude-deg').getValue(), get_lon: func source.getNode('position/longitude-deg').getValue(),
get_spd: func source.getNode('velocities/true-airspeed-kt').getValue(), get_spd: func source.getNode('velocities/true-airspeed-kt').getValue(),
get_vspd: func source.getNode('velocities/vertical-speed-fps').getValue(),
}; };
}, # of connectAI }, # of connectAI
@ -444,14 +466,14 @@ var NavDisplay = {
# load elements from vector image, and create instance variables using identical names, and call updateCenter() on each # load elements from vector image, and create instance variables using identical names, and call updateCenter() on each
# anything that needs updatecenter called, should be added to the vector here # anything that needs updatecenter called, should be added to the vector here
# #
foreach(var element; ["rotateComp","windArrow","selHdg", foreach(var element; ["rotateComp","rotateComp2","windArrow","selHdg","selHdg2","hdgGroup","northUp",
"curHdgPtr","staFromL","staToL","trkInd", "aplSymMap","aplSymMapCtr","aplSymVor","curHdgPtr","curHdgPtr2",
"staFromR","staToR","compass","hdgTrk","truMag","altArc"] ) "staFromL","staToL","staFromR","staToR","staFromL2","staToL2","staFromR2","staToR2",
"trkInd","vorCrsPtr2","locPtr","compass","compassApp","hdgTrk","truMag","altArc","planArcs"] )
me.symbols[element] = me.nd.getElementById(element).updateCenter(); me.symbols[element] = me.nd.getElementById(element).updateCenter();
# this should probably be using Philosopher's new SymbolLayer ? # this should probably be using Philosopher's new SymbolLayer ?
me.map = me.nd.createChild("map","map") me.map = me.nd.createChild("map","map")
.setTranslation(512,824)
.set("clip", "rect(124, 1024, 1024, 0)"); .set("clip", "rect(124, 1024, 1024, 0)");
# this callback will be passed onto the model via the controller hash, and used for the positioned queries, to specify max query range: # this callback will be passed onto the model via the controller hash, and used for the positioned queries, to specify max query range:
@ -535,10 +557,10 @@ var NavDisplay = {
me.drawdme(); me.drawdme();
}); });
# TODO: move this to the route.model # TODO: move this to the route.model
# Hack to draw the route on rm activation
me.listen("/autopilot/route-manager/active", func(active) { me.listen("/autopilot/route-manager/active", func(active) {
if(active.getValue()) { if(active.getValue()) {
me.drawroute(); setprop(me.get_full_switch_path('toggle_display_mode'),getprop(me.get_full_switch_path('toggle_display_mode')));
me.drawrunways();
} else { } else {
print("TODO: navdisplay.mfd: implement route-manager/layer clearing!"); print("TODO: navdisplay.mfd: implement route-manager/layer clearing!");
#me.route_group.removeAllChildren(); # HACK! #me.route_group.removeAllChildren(); # HACK!
@ -552,10 +574,9 @@ var NavDisplay = {
drawroute: func print("drawroute no longer used!"), drawroute: func print("drawroute no longer used!"),
drawrunways: func print("drawrunways no longer used!"), drawrunways: func print("drawrunways no longer used!"),
in_mode:func(switch, modes) foreach(var m; modes) { in_mode:func(switch, modes) {
foreach(var m; modes)
if (me.get_switch(switch)==m) return 1; if (me.get_switch(switch)==m) return 1;
else continue;
print("not in checked mode");
return 0; return 0;
}, },
@ -579,17 +600,39 @@ var NavDisplay = {
# fgcommand('profiler-start'); # fgcommand('profiler-start');
# Heading update
var userHdgMag = me.aircraft_source.get_hdg_mag(); var userHdgMag = me.aircraft_source.get_hdg_mag();
var userTrkMag = me.aircraft_source.get_trk_mag(); # getprop("orientation/heading-deg"); # orientation/track-magnetic-deg is noisy var userHdgTru = me.aircraft_source.get_hdg_tru();
var userTrkMag = me.aircraft_source.get_trk_mag();
var userTrkTru = me.aircraft_source.get_trk_tru();
if (me.get_switch('toggle_true_north')) {
me.symbols.truMag.setText("TRU");
var userHdg=userHdgTru;
var userTrk=userTrkTru;
} else {
me.symbols.truMag.setText("MAG");
var userHdg=userHdgMag;
var userTrk=userTrkMag;
}
if (me.aircraft_source.get_spd() < 80)
userTrk = userHdg;
var userLat = me.aircraft_source.get_lat(); var userLat = me.aircraft_source.get_lat();
var userLon = me.aircraft_source.get_lon(); var userLon = me.aircraft_source.get_lon();
var userSpd = me.aircraft_source.get_spd();
var userVSpd = me.aircraft_source.get_vspd();
# this should only ever happen when testing the experimental AI/MP ND driver hash (not critical) # this should only ever happen when testing the experimental AI/MP ND driver hash (not critical)
if (!userHdgMag or !userTrkMag or !userLat or !userLon) { if (!userHdg or !userTrk or !userLat or !userLon) {
print("aircraft source invalid, returning !"); print("aircraft source invalid, returning !");
return; return;
} }
if (me.get_switch('toggle_centered') or me.in_mode('toggle_display_mode', ['PLAN']))
me.map.setTranslation(512,512);
else
me.map.setTranslation(512,824);
# Calculate length in NM of one degree at current location TODO: expose as methods, for external callbacks # Calculate length in NM of one degree at current location TODO: expose as methods, for external callbacks
var userLatR = userLat*D2R; var userLatR = userLat*D2R;
var userLonR = userLon*D2R; var userLonR = userLon*D2R;
@ -611,60 +654,148 @@ var NavDisplay = {
me.symbols.dmeRDist.setText(sprintf("%3.1f",nav1dist*0.000539)); me.symbols.dmeRDist.setText(sprintf("%3.1f",nav1dist*0.000539));
me.symbols.range.setText(sprintf("%3.0f",me.rangeNm() )); me.symbols.range.setText(sprintf("%3.0f",me.rangeNm() ));
#rangeNm=rangeNm*2;
# reposition the map, change heading & range: # reposition the map, change heading & range:
if(me.in_mode('toggle_display_mode', ['PLAN'])) {
me.symbols.windArrow.hide();
me.map._node.getNode("hdg",1).setDoubleValue(0);
if (getprop(me.efis_path ~ "/inputs/plan-wpt-index") >= 0) {
me.map._node.getNode("ref-lat",1).setDoubleValue(getprop("/autopilot/route-manager/route/wp["~getprop(me.efis_path ~ "/inputs/plan-wpt-index")~"]/latitude-deg"));
me.map._node.getNode("ref-lon",1).setDoubleValue(getprop("/autopilot/route-manager/route/wp["~getprop(me.efis_path ~ "/inputs/plan-wpt-index")~"]/longitude-deg"));
}
} else {
me.symbols.windArrow.show();
me.map._node.getNode("ref-lat",1).setDoubleValue(userLat); me.map._node.getNode("ref-lat",1).setDoubleValue(userLat);
me.map._node.getNode("ref-lon",1).setDoubleValue(userLon); me.map._node.getNode("ref-lon",1).setDoubleValue(userLon);
}
me.map._node.getNode("range",1).setDoubleValue(me.rangeNm()/2); # avoid this here, use a listener instead me.map._node.getNode("range",1).setDoubleValue(me.rangeNm()/2); # avoid this here, use a listener instead
if(me.get_switch('toggle_display_mode') == 'MAP' or me.get_switch('toggle_display_mode') == 'PLAN' ) { if(me.in_mode('toggle_display_mode', ['MAP'])) {
me.symbols.rotateComp.setRotation(-userTrkMag*D2R); me.symbols.rotateComp.setRotation(-userTrk*D2R);
me.symbols.rotateComp2.setRotation(-userTrk*D2R);
me.symbols.trkInd.setRotation(0); me.symbols.trkInd.setRotation(0);
me.symbols.curHdgPtr.setRotation(userHdgMag*D2R); me.symbols.curHdgPtr.setRotation(userHdg*D2R);
me.map._node.getNode("hdg",1).setDoubleValue(userTrkMag); me.symbols.curHdgPtr2.setRotation(userHdg*D2R);
me.symbols.compass.setRotation(-userTrkMag*D2R); me.map._node.getNode("hdg",1).setDoubleValue(userTrk);
me.symbols.compass.setRotation(-userTrk*D2R);
me.symbols.compassApp.setRotation(-userTrk*D2R);
me.symbols.hdgTrk.setText("TRK"); me.symbols.hdgTrk.setText("TRK");
me.symbols.truMag.setText("MAG");
} }
if(me.get_switch('toggle_display_mode') == 'APP' or me.get_switch('toggle_display_mode') == 'VOR' ) { if(me.in_mode('toggle_display_mode', ['APP','VOR'])) {
me.symbols.rotateComp.setRotation(-userHdgMag*D2R); me.symbols.rotateComp.setRotation(-userHdg*D2R);
me.symbols.trkInd.setRotation((userTrkMag-userHdgMag)*D2R); me.symbols.rotateComp2.setRotation(-userHdg*D2R);
me.symbols.curHdgPtr.setRotation(userHdgMag*D2R); me.symbols.trkInd.setRotation((userTrk-userHdg)*D2R);
me.map._node.getNode("hdg",1).setDoubleValue(userHdgMag); me.symbols.curHdgPtr.setRotation(userHdg*D2R);
me.symbols.compass.setRotation(-userHdgMag*D2R); me.symbols.curHdgPtr2.setRotation(userHdg*D2R);
me.map._node.getNode("hdg",1).setDoubleValue(userHdg);
me.symbols.compass.setRotation(-userHdg*D2R);
me.symbols.compassApp.setRotation(-userHdg*D2R);
me.symbols.hdgTrk.setText("HDG"); me.symbols.hdgTrk.setText("HDG");
me.symbols.truMag.setText("MAG"); }
if(me.get_switch('toggle_centered')) {
if (me.in_mode('toggle_display_mode', ['APP','VOR'])) {
me.symbols.vorCrsPtr2.show();
me.symbols.compassApp.show();
if(getprop("instrumentation/nav/in-range")) {
var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
me.symbols.locPtr.show();
me.symbols.locPtr.setTranslation(deflection*150,0);
if(abs(deflection < 0.99))
me.symbols.locPtr.setColorFill(1,0,1,1);
else
me.symbols.locPtr.setColorFill(1,0,1,0);
} else {
me.symbols.locPtr.hide();
}
me.symbols.vorCrsPtr2.setRotation((getprop("instrumentation/nav/radials/selected-deg")-userHdg)*D2R);
me.symbols.hdgGroup.setTranslation(0,100);
} else {
me.symbols.vorCrsPtr2.hide();
me.symbols.hdgGroup.setTranslation(0,100*me.in_mode('toggle_display_mode', ['MAP']));
me.symbols.compassApp.setVisible(me.in_mode('toggle_display_mode', ['MAP']));
}
} else {
me.symbols.vorCrsPtr2.hide();
me.symbols.hdgGroup.setTranslation(0,0);
me.symbols.compassApp.hide();
} }
if (abs(getprop("velocities/vertical-speed-fps")) > 10) { if ((me.get_switch('toggle_centered') and !me.in_mode('toggle_display_mode', ['PLAN'])) or me.in_mode('toggle_display_mode', ['PLAN'])) {
var altRangeNm = (getprop("autopilot/settings/target-altitude-ft")- me.symbols.compass.hide();
getprop("instrumentation/altimeter/indicated-altitude-ft"))/getprop("velocities/vertical-speed-fps")* } else {
getprop("/velocities/groundspeed-kt")*KT2MPS*M2NM; me.symbols.compass.show();
}
var staPtrVis = !me.in_mode('toggle_display_mode', ['APP','PLAN']);
if (!me.get_switch('toggle_centered') and me.in_mode('toggle_display_mode', ['APP','MAP','VOR'])) {
me.symbols.trkInd.show();
me.symbols.staFromL.setVisible(staPtrVis);
me.symbols.staFromL2.hide();
me.symbols.staFromR.setVisible(staPtrVis);
me.symbols.staFromR2.hide();
me.symbols.staToL.setVisible(staPtrVis);
me.symbols.staToL2.hide();
me.symbols.staToR.setVisible(staPtrVis);
me.symbols.staToR2.hide();
me.symbols.rotateComp.setVisible(staPtrVis);
me.symbols.rotateComp2.hide();
} else {
me.symbols.trkInd.hide();
me.symbols.staFromL.hide();
me.symbols.staFromL2.setVisible(staPtrVis);
me.symbols.staFromR.hide();
me.symbols.staFromR2.setVisible(staPtrVis);
me.symbols.staToL.hide();
me.symbols.staToL2.setVisible(staPtrVis);
me.symbols.staToR.hide();
me.symbols.staToR2.setVisible(staPtrVis);
me.symbols.rotateComp.hide();
me.symbols.rotateComp2.setVisible(staPtrVis);
}
me.symbols.hdgGroup.setVisible(!me.in_mode('toggle_display_mode', ['PLAN']));
me.symbols.northUp.setVisible(me.in_mode('toggle_display_mode', ['PLAN']));
me.symbols.aplSymMap.setVisible(me.in_mode('toggle_display_mode', ['APP','MAP','VOR']) and !me.get_switch('toggle_centered'));
me.symbols.aplSymMapCtr.setVisible(me.in_mode('toggle_display_mode', ['MAP']) and me.get_switch('toggle_centered'));
me.symbols.aplSymVor.setVisible(me.in_mode('toggle_display_mode', ['APP','VOR']) and me.get_switch('toggle_centered'));
me.symbols.planArcs.setVisible(me.in_mode('toggle_display_mode', ['PLAN']));
if (abs(userVSpd) > 5) {
var altDiff = getprop("autopilot/settings/target-altitude-ft")-getprop("instrumentation/altimeter/indicated-altitude-ft");
if (abs(altDiff) > 50 and altDiff/userVSpd > 0) {
var altRangeNm = altDiff/userVSpd*userSpd*KT2MPS*M2NM;
if(altRangeNm > 1) { if(altRangeNm > 1) {
var altRangePx = (350/me.rangeNm())*altRangeNm; var altRangePx = (350/me.rangeNm())*altRangeNm;
if (altRangePx > 700) if (altRangePx > 700)
altRangePx = 700; altRangePx = 700;
me.symbols.altArc.setTranslation(0,-altRangePx); me.symbols.altArc.setTranslation(0,-altRangePx);
} # altRangeNm > 1 }
me.symbols.altArc.show(); me.symbols.altArc.show();
} else
me.symbols.altArc.hide();
} else { } else {
me.symbols.altArc.hide(); me.symbols.altArc.hide();
}# fps > 10 }
## these would require additional arguments to be moved to an external config hash currently ## these would require additional arguments to be moved to an external config hash currently
me.symbols.selHdg.setRotation(getprop("autopilot/settings/true-heading-deg")*D2R); me.symbols.selHdg.setRotation(getprop("autopilot/settings/true-heading-deg")*D2R);
if (var nav0hdg=getprop("instrumentation/nav/heading-deg") != nil) me.symbols.selHdg2.setRotation(getprop("autopilot/settings/true-heading-deg")*D2R);
if (var nav0hdg=getprop("instrumentation/nav/heading-deg") != nil) {
me.symbols.staFromL.setRotation((nav0hdg-userHdgMag+180)*D2R); me.symbols.staFromL.setRotation((nav0hdg-userHdgMag+180)*D2R);
if (var nav0hdg=getprop("instrumentation/nav/heading-deg") != nil) me.symbols.staFromL2.setRotation((nav0hdg-userHdgMag+180)*D2R);
}
if (var nav0hdg=getprop("instrumentation/nav/heading-deg") != nil) {
me.symbols.staToL.setRotation((nav0hdg-userHdgMag)*D2R); me.symbols.staToL.setRotation((nav0hdg-userHdgMag)*D2R);
if (var nav1hdg=getprop("instrumentation/nav[1]/heading-deg") != nil) me.symbols.staToL2.setRotation((nav0hdg-userHdgMag)*D2R);
}
if (var nav1hdg=getprop("instrumentation/nav[1]/heading-deg") != nil) {
me.symbols.staFromR.setRotation((nav1hdg-userHdgMag+180)*D2R); me.symbols.staFromR.setRotation((nav1hdg-userHdgMag+180)*D2R);
if (var nav1hdg=getprop("instrumentation/nav[1]/heading-deg") != nil) me.symbols.staFromR2.setRotation((nav1hdg-userHdgMag+180)*D2R);
}
if (var nav1hdg=getprop("instrumentation/nav[1]/heading-deg") != nil) {
me.symbols.staToR.setRotation((nav1hdg-userHdgMag)*D2R); me.symbols.staToR.setRotation((nav1hdg-userHdgMag)*D2R);
me.symbols.staToR2.setRotation((nav1hdg-userHdgMag)*D2R);
}
## run all predicates in the NDStyle hash and evaluate their true/false behavior callbacks ## run all predicates in the NDStyle hash and evaluate their true/false behavior callbacks
## this is in line with the original design, but normally we don't need to getprop/poll here, ## this is in line with the original design, but normally we don't need to getprop/poll here,
@ -691,12 +822,10 @@ var NavDisplay = {
## update the status flags shown on the ND (wxr, wpt, arpt, sta) ## update the status flags shown on the ND (wxr, wpt, arpt, sta)
# this could/should be using listeners instead ... # this could/should be using listeners instead ...
me.symbols['status.wxr'].setVisible( me.get_switch('toggle_weather') and me.in_mode('toggle_display_mode', ['MAP']));
me.symbols['status.wxr'].setVisible( me.get_switch('toggle_weather') ); me.symbols['status.wpt'].setVisible( me.get_switch('toggle_waypoints') and me.in_mode('toggle_display_mode', ['MAP']));
me.symbols['status.wpt'].setVisible( me.get_switch('toggle_waypoints')); me.symbols['status.arpt'].setVisible( me.get_switch('toggle_airports') and me.in_mode('toggle_display_mode', ['MAP']));
me.symbols['status.arpt'].setVisible( me.get_switch('toggle_airports')); me.symbols['status.sta'].setVisible( me.get_switch('toggle_stations') and me.in_mode('toggle_display_mode', ['MAP']));
me.symbols['status.sta'].setVisible( me.get_switch('toggle_stations') );
} }
}; };

View file

@ -50,14 +50,14 @@ var draw_route = func (group, theroute, controller=nil, lod=0)
append(coords,"N"~leg.path()[0].lat); append(coords,"N"~leg.path()[0].lat);
append(coords,"E"~leg.path()[0].lon); append(coords,"E"~leg.path()[0].lon);
append(cmds,2); append(cmds,2);
canvas.drawwp(group, leg.path()[0].lat,leg.path()[0].lon,fp.getWP(0).wp_name,i, wp); canvas.drawwp(group, leg.path()[0].lat, leg.path()[0].lon, fp.getWP(0).alt_cstr, fp.getWP(0).wp_name, i, wp);
i+=1; i+=1;
} }
var leg = fp.getWP(i); var leg = fp.getWP(i);
append(coords,"N"~leg.path()[1].lat); append(coords,"N"~leg.path()[1].lat);
append(coords,"E"~leg.path()[1].lon); append(coords,"E"~leg.path()[1].lon);
append(cmds,4); append(cmds,4);
canvas.drawwp(group, leg.path()[1].lat,leg.path()[1].lon,leg.wp_name,i, wp); canvas.drawwp(group, leg.path()[1].lat, leg.path()[1].lon, leg.alt_cstr, leg.wp_name, i, wp);
} }
# Update route coordinates # Update route coordinates

View file

@ -8,31 +8,28 @@ MPTrafficModel.init = func {
myPosition.set_latlon( myPositionVec[0], myPositionVec[1]); myPosition.set_latlon( myPositionVec[0], myPositionVec[1]);
var max_dist_nm = me._controller['query_range'](); var max_dist_nm = me._controller['query_range']();
##
# uncomment this for showing MP traffic
# var traffic_type = "multiplayer";
# and use this for development purposes:
var traffic_type = "aircraft";
#if (traffic_type == "aircraft")
# print("INFO: traffic.model is still showing AI traffic instead of MP traffic!");
me._view.reset(); # hides: removeAllChildren() me._view.reset(); # hides: removeAllChildren()
var traffic = props.globals.initNode("/ai/models/").getChildren( traffic_type );
#print("Total traffic:", size(traffic)); # AI traffic
var traffic = props.globals.initNode("/ai/models/").getChildren( "aircraft" );
foreach(var t; traffic) { foreach(var t; traffic) {
pos.set_latlon( t.getNode("position/latitude-deg").getValue(), pos.set_latlon( t.getNode("position/latitude-deg").getValue(),
t.getNode("position/longitude-deg").getValue() t.getNode("position/longitude-deg").getValue()
); );
if (pos.distance_to( myPosition ) <= max_dist_nm*NM2M ) { if (pos.distance_to( myPosition ) <= max_dist_nm*NM2M )
#print("Pushing: ", t.getNode("callsign").getValue() );
me.push(t); me.push(t);
} }
# Multiplayer traffic
var traffic = props.globals.initNode("/ai/models/").getChildren( "multiplayer" );
foreach(var t; traffic) {
pos.set_latlon( t.getNode("position/latitude-deg").getValue(),
t.getNode("position/longitude-deg").getValue()
);
if (pos.distance_to( myPosition ) <= max_dist_nm*NM2M )
me.push(t);
} }
#print("traffic.model: Query range:", max_dist_nm, " Items:", me.hasData() );
me.notifyView(); me.notifyView();
@ -41,4 +38,3 @@ MPTrafficModel.init = func {
# so better use maketimer() here # so better use maketimer() here
settimer(func me.init(), 2); settimer(func me.init(), 2);
} }

View file

@ -2,7 +2,7 @@
# Draw a waypoint symbol and waypoint name (Gijs' 744 ND.nas code) # Draw a waypoint symbol and waypoint name (Gijs' 744 ND.nas code)
# #
var drawwp = func (group, lat, lon, name, i, wp) { var drawwp = func (group, lat, lon, alt, name, i, wp) {
var wp_group = group.createChild("group","wp"); var wp_group = group.createChild("group","wp");
wp[i] = wp_group.createChild("path", "wp-" ~ i) wp[i] = wp_group.createChild("path", "wp-" ~ i)
.setStrokeLineWidth(3) .setStrokeLineWidth(3)
@ -22,13 +22,17 @@ var drawwp = func (group, lat, lon, name, i, wp) {
# #
# text_wp[i] = wp_group.createChild("text", "wp-text-" ~ i) # text_wp[i] = wp_group.createChild("text", "wp-text-" ~ i)
# #
if (alt == 0)
alt = "";
else
alt = "\n"~alt;
var text_wps = wp_group.createChild("text", "wp-text-" ~ i) var text_wps = wp_group.createChild("text", "wp-text-" ~ i)
.setDrawMode( canvas.Text.TEXT ) .setDrawMode( canvas.Text.TEXT )
.setText(name) .setText(name~alt)
.setFont("LiberationFonts/LiberationSans-Regular.ttf") .setFont("LiberationFonts/LiberationSans-Regular.ttf")
.setFontSize(28) .setFontSize(28)
.setTranslation(25,35) .setTranslation(25,35)
.setColor(1,0,1); .setColor(1,1,1);
wp_group.setGeoPosition(lat, lon) wp_group.setGeoPosition(lat, lon)
.set("z-index",4); .set("z-index",4);
}; };