diff --git a/Nasal/canvas/MapStructure.nas b/Nasal/canvas/MapStructure.nas
index 39453056a..5474e9145 100644
--- a/Nasal/canvas/MapStructure.nas
+++ b/Nasal/canvas/MapStructure.nas
@@ -369,6 +369,5 @@ settimer(func {
me.del();
};
}, 1);
-else print("MapStructure.nas: Testing code disabled, see $FG_ROOT/gui/dialogs/map-canvas.xml instead");
}, 0); # end ugly module init timer hack
diff --git a/Nasal/canvas/map/airplane-symbol.draw b/Nasal/canvas/map/airplane-symbol.draw
new file mode 100644
index 000000000..1fbe0dd08
--- /dev/null
+++ b/Nasal/canvas/map/airplane-symbol.draw
@@ -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);
+}
diff --git a/Nasal/canvas/map/airplane-symbol.layer b/Nasal/canvas/map/airplane-symbol.layer
new file mode 100644
index 000000000..e7f7a99a8
--- /dev/null
+++ b/Nasal/canvas/map/airplane-symbol.layer
@@ -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);
+
diff --git a/Nasal/canvas/map/airplane-symbol.model b/Nasal/canvas/map/airplane-symbol.model
new file mode 100644
index 000000000..a5df549aa
--- /dev/null
+++ b/Nasal/canvas/map/airplane-symbol.model
@@ -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();
+}
+
+
diff --git a/Nasal/canvas/map/boeingAirplane.svg b/Nasal/canvas/map/boeingAirplane.svg
new file mode 100644
index 000000000..a877f76ec
--- /dev/null
+++ b/Nasal/canvas/map/boeingAirplane.svg
@@ -0,0 +1,70 @@
+
+
+
+
diff --git a/Nasal/canvas/map/boeingND.svg b/Nasal/canvas/map/boeingND.svg
index db5bcf84d..402c6dbaf 100644
--- a/Nasal/canvas/map/boeingND.svg
+++ b/Nasal/canvas/map/boeingND.svg
@@ -7,6 +7,7 @@
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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="boeingND.svg"
@@ -28,13 +29,13 @@
inkscape:window-height="716"
id="namedview102"
showgrid="false"
- inkscape:zoom="2"
- inkscape:cx="509.108"
- inkscape:cy="161.525"
+ inkscape:zoom="1.41422"
+ inkscape:cx="679.497"
+ inkscape:cy="381.256"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
- inkscape:current-layer="layer3"
+ inkscape:current-layer="layer1"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-object-midpoints="true"
@@ -445,10 +446,94 @@
99.9
+ y="126.12489">99.9NM
+
+
+
+
+
+
+
+
+
+
@@ -557,21 +657,14 @@
999
+ style="fill:none;stroke:#ededed;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:label="#path7253" />
+
+
+
+
@@ -629,6 +722,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -666,6 +769,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -680,14 +793,14 @@
999
@@ -703,6 +816,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -741,6 +864,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -757,11 +890,11 @@
sodipodi:linespacing="125%"
id="text3819"
y="53.306854"
- x="147.17084"
+ x="158.17084"
style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ededed;fill-opacity:1;stroke:none;display:inline;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
xml:space="preserve">TAS
@@ -790,39 +923,66 @@
-HDG
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ id="tspan3013"
+ x="476.28857"
+ y="65.781754"
+ style="font-size:48px">999
@@ -831,16 +991,44 @@
MAG
+ style="font-size:32px;fill:#32f519">HDG
+
+
+
+
+
+MAG
+
+
+
+
+
+
+
+
+
+
@@ -892,6 +1080,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -929,6 +1127,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -966,6 +1174,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1003,6 +1221,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1040,6 +1268,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1077,6 +1315,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1114,6 +1362,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1151,6 +1409,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1188,6 +1456,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1209,7 +1487,7 @@
sodipodi:cy="622"
sodipodi:rx="426"
sodipodi:ry="426"
- d="M 850,622 C 850,857.273 659.273,1048 424,1048 188.727,1048 -2,857.273 -2,622 -2,386.727 188.727,196 424,196 c 235.273,0 426,190.727 426,426 z"
+ d="m 850,622 a 426,426 0 1 1 -852,0 426,426 0 1 1 852,0 z"
transform="matrix(1.6472,0,0,1.6472,-186.253,-200.559)" />99
+
+
+
+
+
+
+
+
+
+
TA ONLY
+ style="font-size:32px;fill:#0099d9;fill-opacity:1">TA ONLY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1757,19 +2223,6 @@
-WXR
@@ -1786,19 +2239,6 @@
-ARPT
@@ -1815,19 +2255,6 @@
-WPT
@@ -1844,19 +2271,6 @@
-STA
@@ -1908,8 +2322,8 @@
inkscape:connector-curvature="0"
id="path3103"
d="m 168.665,820.476 c 0,-189.321 153.474,-342.796 342.795,-342.796 189.319,0 342.794,153.473 342.794,342.796 0,0 0,0 0,0"
- style="fill:none;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
\ No newline at end of file
+ style="fill:none;stroke:#ededed;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+33
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+30
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+27
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+24
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+21
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+18
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+WXR
+
+
+ARPT
+
+
+WPT
+
+
+STA
+
+
+N
+
+W
+
+E
+
+S
+
+
\ No newline at end of file
diff --git a/Nasal/canvas/map/fixes.model b/Nasal/canvas/map/fixes.model
index a07b01351..5d46eeee4 100644
--- a/Nasal/canvas/map/fixes.model
+++ b/Nasal/canvas/map/fixes.model
@@ -4,23 +4,15 @@ FixModel.new = func make( LayerModel, FixModel );
FixModel.init = func {
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 numNum = 0;
foreach(result; results) {
- me.push(result);
+ # Skip airport navaids (real thing makes distinction between high/low altitude fixes)
+ if(string.match(result.id,"*[^0-9]")) {
+ 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();
-}
-
-
+}
\ No newline at end of file
diff --git a/Nasal/canvas/map/navaids.model b/Nasal/canvas/map/navaids.model
index 09e200453..65cf37344 100644
--- a/Nasal/canvas/map/navaids.model
+++ b/Nasal/canvas/map/navaids.model
@@ -6,6 +6,4 @@ NavaidModel.init = func {
foreach(var n; navaids)
me.push(n);
me.notifyView();
-}
-
-
+}
\ No newline at end of file
diff --git a/Nasal/canvas/map/navdisplay.mfd b/Nasal/canvas/map/navdisplay.mfd
index 5d7f580e0..f65dc9b87 100644
--- a/Nasal/canvas/map/navdisplay.mfd
+++ b/Nasal/canvas/map/navdisplay.mfd
@@ -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: [
- { 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");
- var visible=nd.get_switch('toggle_waypoints');
- if(nd.rangeNm() <= 40 and visible and
- nd.get_switch('toggle_display_mode') == "MAP") {
- # print("fixes update requested!");
+ var visible=nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']);
+ if(nd.rangeNm() <= 40 and visible) {
trigger_update( layer );
} layer._view.setVisible(visible);
@@ -69,7 +67,16 @@ var NDStyles = {
# print("Running fixes predicate");
var visible=nd.get_switch('toggle_weather') and nd.get_switch('toggle_display_mode') != "PLAN";
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 );
} 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) {
# print("Running airports-nd predicate");
- if (nd.rangeNm() <= 80 and
- nd.get_switch('toggle_display_mode') == "MAP" ) {
- trigger_update( layer ); # clear & redraw
+ var visible = nd.get_switch('toggle_airports') and nd.in_mode('toggle_display_mode', ['MAP']);
+ if (nd.rangeNm() <= 80 and visible) {
+ trigger_update( layer ); # clear & redraw
}
- layer._view.setVisible( nd.get_switch('toggle_airports') );
+ layer._view.setVisible( visible);
}, # end of layer update predicate
}, # end of airports layer
{ name:'vor', update_on:['toggle_range','toggle_stations','toggle_display_mode'], predicate: func(nd, layer) {
- # print("Running vor layer predicate");
- if(nd.rangeNm() <= 40 and
- nd.get_switch('toggle_stations') and
- nd.get_switch('toggle_display_mode') == "MAP"){
+ var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']);
+ if(nd.rangeNm() <= 40 and visible) {
trigger_update( layer ); # clear & redraw
}
- layer._view.setVisible( nd.get_switch('toggle_stations') );
+ layer._view.setVisible( visible );
}, # end of layer update predicate
}, # end of VOR layer
- { name:'dme', update_on:['toggle_range','toggle_stations'], predicate: func(nd, layer) {
- if(nd.rangeNm() <= 40 and
- nd.get_switch('toggle_stations') and
- nd.get_switch('toggle_display_mode') == "MAP"){
+ { name:'dme', update_on:['toggle_range','toggle_stations','toggle_display_mode'], predicate: func(nd, layer) {
+ var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']);
+ if(nd.rangeNm() <= 40 and visible){
trigger_update( layer ); # clear & redraw
}
- layer._view.setVisible( nd.get_switch('toggle_stations') );
+ layer._view.setVisible( visible );
}, # end of layer update predicate
}, # end of DME layer
{ name:'mp-traffic', update_on:['toggle_range','toggle_traffic'], predicate: func(nd, layer) {
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 traffic 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)
trigger_update( layer ); # clear & redraw
layer._view.setVisible( visible );
}, # end of layer update predicate
}, # end of airports-nd layer
- { name:'route', update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) {
- trigger_update( layer ); # clear & redraw
- layer._view.setVisible( 1 ); #nd.get_switch('toggle_traffic')
+ { 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
+ }
+ layer._view.setVisible( visible );
}, # end of layer update predicate
}, # end of route layer
@@ -229,7 +235,7 @@ var NDStyles = {
{ id:'rangeArcs',
impl: {
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_false: func(nd) nd.symbols.rangeArcs.hide(),
}, # of rangeArcs.impl
@@ -256,10 +262,13 @@ var NDSourceDriver = {};
NDSourceDriver.new = func {
var m = {parents:[NDSourceDriver]};
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_tru= func getprop("/orientation/track-deg");
m.get_lat= func getprop("/position/latitude-deg");
m.get_lon= func getprop("/position/longitude-deg");
m.get_spd= func getprop("/velocities/groundspeed-kt");
+ m.get_vspd= func getprop("/velocities/vertical-speed-fps");
return m;
}
@@ -275,7 +284,7 @@ return m;
# TODO: switches are ND specific, so move to the NDStyle hash!
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_airports': {path: '/inputs/arpt', 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_data': {path: '/inputs/data',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_true_north': {path: '/mfd/true-north', value:0, type:'BOOL'},
};
# Hack to update weather radar once every 10 seconds
@@ -295,6 +306,14 @@ var update_weather = func {
}
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:
# - introduce a MFD class (use it also for PFD/EICAS)
@@ -342,13 +361,16 @@ var NavDisplay = {
# for creating NDs that are driven by AI traffic instead of the main aircraft (generalization rocks!)
connectAI: func(source=nil) {
- me.aircraft_source = {
- get_hdg_mag: func source.getNode('orientation/heading-magnetic-deg').getValue(),
- get_trk_mag: func source.getNode('orientation/track-magnetic-deg').getValue(),
- get_lat: func source.getNode('position/latitude-deg').getValue(),
- get_lon: func source.getNode('position/longitude-deg').getValue(),
- get_spd: func source.getNode('velocities/true-airspeed-kt').getValue(),
- };
+ me.aircraft_source = {
+ 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_tru: func source.getNode('orientation/track-deg').getValue(),
+ get_lat: func source.getNode('position/latitude-deg').getValue(),
+ get_lon: func source.getNode('position/longitude-deg').getValue(),
+ get_spd: func source.getNode('velocities/true-airspeed-kt').getValue(),
+ get_vspd: func source.getNode('velocities/vertical-speed-fps').getValue(),
+ };
}, # of connectAI
# TODO: the ctor should allow customization, for different aircraft
@@ -444,14 +466,14 @@ var NavDisplay = {
# 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
#
- foreach(var element; ["rotateComp","windArrow","selHdg",
- "curHdgPtr","staFromL","staToL","trkInd",
- "staFromR","staToR","compass","hdgTrk","truMag","altArc"] )
+ foreach(var element; ["rotateComp","rotateComp2","windArrow","selHdg","selHdg2","hdgGroup","northUp",
+ "aplSymMap","aplSymMapCtr","aplSymVor","curHdgPtr","curHdgPtr2",
+ "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();
# this should probably be using Philosopher's new SymbolLayer ?
me.map = me.nd.createChild("map","map")
- .setTranslation(512,824)
.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:
@@ -535,10 +557,10 @@ var NavDisplay = {
me.drawdme();
});
# TODO: move this to the route.model
+ # Hack to draw the route on rm activation
me.listen("/autopilot/route-manager/active", func(active) {
if(active.getValue()) {
- me.drawroute();
- me.drawrunways();
+ setprop(me.get_full_switch_path('toggle_display_mode'),getprop(me.get_full_switch_path('toggle_display_mode')));
} else {
print("TODO: navdisplay.mfd: implement route-manager/layer clearing!");
#me.route_group.removeAllChildren(); # HACK!
@@ -552,10 +574,9 @@ var NavDisplay = {
drawroute: func print("drawroute no longer used!"),
drawrunways: func print("drawrunways no longer used!"),
- in_mode:func(switch, modes) foreach(var m; modes) {
- if (me.get_switch(switch)==m) return 1;
- else continue;
- print("not in checked mode");
+ in_mode:func(switch, modes) {
+ foreach(var m; modes)
+ if (me.get_switch(switch)==m) return 1;
return 0;
},
@@ -579,17 +600,39 @@ var NavDisplay = {
# fgcommand('profiler-start');
+ # Heading update
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 userLat = me.aircraft_source.get_lat();
- var userLon = me.aircraft_source.get_lon();
+ 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 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)
- if (!userHdgMag or !userTrkMag or !userLat or !userLon) {
- print("aircraft source invalid, returning !");
- return;
+ if (!userHdg or !userTrk or !userLat or !userLon) {
+ print("aircraft source invalid, returning !");
+ 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
var userLatR = userLat*D2R;
var userLonR = userLon*D2R;
@@ -611,61 +654,149 @@ var NavDisplay = {
me.symbols.dmeRDist.setText(sprintf("%3.1f",nav1dist*0.000539));
me.symbols.range.setText(sprintf("%3.0f",me.rangeNm() ));
- #rangeNm=rangeNm*2;
# reposition the map, change heading & range:
- me.map._node.getNode("ref-lat",1).setDoubleValue(userLat);
- me.map._node.getNode("ref-lon",1).setDoubleValue(userLon);
+ 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-lon",1).setDoubleValue(userLon);
+ }
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' ) {
- me.symbols.rotateComp.setRotation(-userTrkMag*D2R);
+ if(me.in_mode('toggle_display_mode', ['MAP'])) {
+ me.symbols.rotateComp.setRotation(-userTrk*D2R);
+ me.symbols.rotateComp2.setRotation(-userTrk*D2R);
me.symbols.trkInd.setRotation(0);
- me.symbols.curHdgPtr.setRotation(userHdgMag*D2R);
- me.map._node.getNode("hdg",1).setDoubleValue(userTrkMag);
- me.symbols.compass.setRotation(-userTrkMag*D2R);
+ me.symbols.curHdgPtr.setRotation(userHdg*D2R);
+ me.symbols.curHdgPtr2.setRotation(userHdg*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.truMag.setText("MAG");
}
- if(me.get_switch('toggle_display_mode') == 'APP' or me.get_switch('toggle_display_mode') == 'VOR' ) {
- me.symbols.rotateComp.setRotation(-userHdgMag*D2R);
- me.symbols.trkInd.setRotation((userTrkMag-userHdgMag)*D2R);
- me.symbols.curHdgPtr.setRotation(userHdgMag*D2R);
- me.map._node.getNode("hdg",1).setDoubleValue(userHdgMag);
- me.symbols.compass.setRotation(-userHdgMag*D2R);
+ if(me.in_mode('toggle_display_mode', ['APP','VOR'])) {
+ me.symbols.rotateComp.setRotation(-userHdg*D2R);
+ me.symbols.rotateComp2.setRotation(-userHdg*D2R);
+ me.symbols.trkInd.setRotation((userTrk-userHdg)*D2R);
+ me.symbols.curHdgPtr.setRotation(userHdg*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.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) {
- var altRangeNm = (getprop("autopilot/settings/target-altitude-ft")-
- getprop("instrumentation/altimeter/indicated-altitude-ft"))/getprop("velocities/vertical-speed-fps")*
- getprop("/velocities/groundspeed-kt")*KT2MPS*M2NM;
-
- if(altRangeNm > 1) {
- var altRangePx = (350/me.rangeNm())*altRangeNm;
- if (altRangePx > 700)
- altRangePx = 700;
- me.symbols.altArc.setTranslation(0,-altRangePx);
- } # altRangeNm > 1
- me.symbols.altArc.show();
+ if ((me.get_switch('toggle_centered') and !me.in_mode('toggle_display_mode', ['PLAN'])) or me.in_mode('toggle_display_mode', ['PLAN'])) {
+ me.symbols.compass.hide();
+ } else {
+ 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) {
+ var altRangePx = (350/me.rangeNm())*altRangeNm;
+ if (altRangePx > 700)
+ altRangePx = 700;
+ me.symbols.altArc.setTranslation(0,-altRangePx);
+ }
+ me.symbols.altArc.show();
+ } else
+ me.symbols.altArc.hide();
} else {
me.symbols.altArc.hide();
- }# fps > 10
+ }
## 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);
- 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);
- 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);
- 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);
- 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.staToR2.setRotation((nav1hdg-userHdgMag)*D2R);
+ }
+
## 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,
## using listeners or timers would be more canvas-friendly whenever possible
@@ -690,13 +821,11 @@ var NavDisplay = {
## update the status flags shown on the ND (wxr, wpt, arpt, sta)
# this could/should be using listeners instead ...
-
- me.symbols['status.wxr'].setVisible( me.get_switch('toggle_weather') );
- me.symbols['status.wpt'].setVisible( me.get_switch('toggle_waypoints'));
- me.symbols['status.arpt'].setVisible( me.get_switch('toggle_airports'));
- me.symbols['status.sta'].setVisible( me.get_switch('toggle_stations') );
+ me.symbols['status.wxr'].setVisible( me.get_switch('toggle_weather') and me.in_mode('toggle_display_mode', ['MAP']));
+ me.symbols['status.wpt'].setVisible( me.get_switch('toggle_waypoints') and me.in_mode('toggle_display_mode', ['MAP']));
+ me.symbols['status.arpt'].setVisible( me.get_switch('toggle_airports') and me.in_mode('toggle_display_mode', ['MAP']));
+ me.symbols['status.sta'].setVisible( me.get_switch('toggle_stations') and me.in_mode('toggle_display_mode', ['MAP']));
-
}
};
diff --git a/Nasal/canvas/map/route.draw b/Nasal/canvas/map/route.draw
index 13418892a..a7edf838d 100644
--- a/Nasal/canvas/map/route.draw
+++ b/Nasal/canvas/map/route.draw
@@ -50,14 +50,14 @@ var draw_route = func (group, theroute, controller=nil, lod=0)
append(coords,"N"~leg.path()[0].lat);
append(coords,"E"~leg.path()[0].lon);
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;
}
var leg = fp.getWP(i);
append(coords,"N"~leg.path()[1].lat);
append(coords,"E"~leg.path()[1].lon);
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
diff --git a/Nasal/canvas/map/traffic.model b/Nasal/canvas/map/traffic.model
index 5665da34b..ee9fe2df3 100644
--- a/Nasal/canvas/map/traffic.model
+++ b/Nasal/canvas/map/traffic.model
@@ -8,31 +8,28 @@ MPTrafficModel.init = func {
myPosition.set_latlon( myPositionVec[0], myPositionVec[1]);
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()
- 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) {
pos.set_latlon( t.getNode("position/latitude-deg").getValue(),
t.getNode("position/longitude-deg").getValue()
);
- if (pos.distance_to( myPosition ) <= max_dist_nm*NM2M ) {
- #print("Pushing: ", t.getNode("callsign").getValue() );
+ if (pos.distance_to( myPosition ) <= max_dist_nm*NM2M )
+ 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();
@@ -40,5 +37,4 @@ MPTrafficModel.init = func {
# and the interval needs to be configurable via the controller
# so better use maketimer() here
settimer(func me.init(), 2);
-}
-
+}
\ No newline at end of file
diff --git a/Nasal/canvas/map/waypoint.draw b/Nasal/canvas/map/waypoint.draw
index 18be45a46..52cd51d01 100644
--- a/Nasal/canvas/map/waypoint.draw
+++ b/Nasal/canvas/map/waypoint.draw
@@ -2,7 +2,7 @@
# 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");
wp[i] = wp_group.createChild("path", "wp-" ~ i)
.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)
#
+ if (alt == 0)
+ alt = "";
+ else
+ alt = "\n"~alt;
var text_wps = wp_group.createChild("text", "wp-text-" ~ i)
.setDrawMode( canvas.Text.TEXT )
- .setText(name)
+ .setText(name~alt)
.setFont("LiberationFonts/LiberationSans-Regular.ttf")
.setFontSize(28)
.setTranslation(25,35)
- .setColor(1,0,1);
+ .setColor(1,1,1);
wp_group.setGeoPosition(lat, lon)
.set("z-index",4);
};