Canvas ND: also work on 747
[fg:toms-fgdata.git] / Aircraft / 747-400 / Models / Cockpit / Instruments / PFD / PFD.nas
1 # ==============================================================================
2 # Boeing 747-400 pfd by Gijs de Rooy
3 # ==============================================================================
4
5 var roundToNearest = func(n, m) {
6         var x = int(n/m)*m;
7         if((math.mod(n,m)) > (m/2))
8                         x = x + m;
9         return x;
10 }
11
12 var pfd_canvas = nil;
13 var pfd_display = nil;
14
15 var horizon = nil;
16 var markerBeacon = nil;
17 var markerBeaconText = nil;
18 var speedText = nil;
19 var machText = nil;
20 var altText = nil;
21 var selHdgText = nil;
22 var fdX = nil;
23 var fdY = nil;
24 var curAlt1 = nil;
25 var curAlt2 = nil;
26 var curAlt3 = nil;
27 var curAltBox = nil;
28 var curSpd = nil;
29 var curSpdTen = nil;
30 var spdTrend = nil;
31 var spdTrend_scale = nil;
32 var v1 = nil;
33 var vr = nil;
34 var flaps0 = nil;
35 var flaps1 = nil;
36 var flaps5 = nil;
37 var flaps10 = nil;
38 var flaps20 = nil;
39 var minSpdInd = nil;
40 var maxSpdInd = nil;
41 var spdTape = nil;
42 var altTape = nil;
43 var cmdSpd = nil;
44 var dhText = nil;
45 var radioAltInd = nil;
46 var ilsId = nil;
47 var ilsCourse = nil;
48 var dmeDist = nil;
49 var baroSet = nil;
50 var vertSpdText = nil;
51 var tenThousand = nil;
52 var vsiNeedle = nil;
53 var vsPointer = nil;
54 var bankPointer = nil;
55 var touchdownInd = nil;
56 var atMode = nil;
57 var rollMode = nil;
58 var pitchMode = nil;
59 var compass = nil;
60 var risingRwy = nil;
61 var risingRwyPtr = nil;
62 var risingRwyPtr_scale = nil;
63 var locPtr = nil;
64 var locScale = nil;
65 var locScaleExp = nil;
66 var selAltPtr = nil;
67 var gsScale = nil;
68 var gsPtr = nil;
69 var minimums = nil;
70
71 var canvas_PFD = {
72         new: func(canvas_group)
73         {
74                 var m = { parents: [canvas_PFD] };
75                 var pfd = canvas_group;
76                 var font_mapper = func(family, weight)
77                 {
78                         if( family == "Liberation Sans" and weight == "normal" )
79                                 return "LiberationFonts/LiberationSans-Regular.ttf";
80                 };
81                 
82                 canvas.parsesvg(pfd, "Aircraft/747-400/Models/Cockpit/Instruments/PFD/PFD.svg", {'font-mapper': font_mapper});
83                 
84                 horizon = pfd.getElementById("horizon").updateCenter();
85                 speedText = pfd.getElementById("speedText");
86                 markerBeacon = pfd.getElementById("markerBeacon");
87                 markerBeaconText = pfd.getElementById("markerBeaconText");
88                 machText = pfd.getElementById("machText");
89                 altText = pfd.getElementById("altText");
90                 selHdgText = pfd.getElementById("selHdgText");
91                 selAltPtr = pfd.getElementById("selAltPtr");
92                 fdX = pfd.getElementById("fdX");
93                 fdY = pfd.getElementById("fdY");
94                 curAlt1 = pfd.getElementById("curAlt1");
95                 curAlt2 = pfd.getElementById("curAlt2");
96                 curAlt3 = pfd.getElementById("curAlt3");
97                 vsPointer = pfd.getElementById("vsPointer");
98                 curAltBox = pfd.getElementById("curAltBox");
99                 curSpd = pfd.getElementById("curSpd");
100                 curSpdTen = pfd.getElementById("curSpdTen");
101                 spdTrend = pfd.getElementById("spdTrend");
102                 v1 = pfd.getElementById("v1");
103                 vr = pfd.getElementById("vr");
104                 dhText = pfd.getElementById("dhText");
105                 flaps0 = pfd.getElementById("flaps0");
106                 flaps1 = pfd.getElementById("flaps1");
107                 flaps5 = pfd.getElementById("flaps5");
108                 flaps10 = pfd.getElementById("flaps10");
109                 flaps20 = pfd.getElementById("flaps20");
110                 minSpdInd = pfd.getElementById("minSpdInd");
111                 maxSpdInd = pfd.getElementById("maxSpdInd");
112                 risingRwy = pfd.getElementById("risingRwy");
113                 risingRwyPtr = pfd.getElementById("risingRwyPtr");
114                 compass = pfd.getElementById("compass").updateCenter();
115                 touchdownInd = pfd.getElementById("touchdown");
116                 spdTape = pfd.getElementById("spdTape");
117                 altTape = pfd.getElementById("altTape");
118                 cmdSpd = pfd.getElementById("cmdSpd");
119                 radioAltInd = pfd.getElementById("radioAltInd");
120                 ilsId = pfd.getElementById("ilsId");
121                 ilsCourse = pfd.getElementById("ilsCourse");
122                 dmeDist = pfd.getElementById("dmeDist");
123                 baroSet = pfd.getElementById("baroSet");
124                 vertSpdText = pfd.getElementById("vertSpd");
125                 tenThousand = pfd.getElementById("tenThousand");
126                 vsiNeedle = pfd.getElementById("vsiNeedle").updateCenter();
127                 bankPointer = pfd.getElementById("bankPointer").updateCenter();
128                 atMode = pfd.getElementById("atMode");
129                 rollMode = pfd.getElementById("rollMode");
130                 pitchMode = pfd.getElementById("pitchMode");
131                 locPtr = pfd.getElementById("locPtr");
132                 locScale = pfd.getElementById("locScale");
133                 locScaleExp = pfd.getElementById("locScaleExp");
134                 gsScale = pfd.getElementById("gsScale");
135                 gsPtr = pfd.getElementById("gsPtr");
136                 minimums = pfd.getElementById("minimums");
137                 
138                 var c1 = spdTrend.getCenter();
139                 spdTrend.createTransform().setTranslation(-c1[0], -c1[1]);
140                 spdTrend_scale = spdTrend.createTransform();
141                 spdTrend.createTransform().setTranslation(c1[0], c1[1]);
142                 var c2 = risingRwyPtr.getCenter();
143                 risingRwyPtr.createTransform().setTranslation(-c2[0], -c2[1]);
144                 risingRwyPtr_scale = risingRwyPtr.createTransform();
145                 risingRwyPtr.createTransform().setTranslation(c2[0], c2[1]);
146                 
147                 horizon.set("clip", "rect(244, 705, 764, 230)");
148                 minSpdInd.set("clip", "rect(130, 1024, 896, 0)");
149                 maxSpdInd.set("clip", "rect(130, 1024, 896, 0)");
150                 spdTape.set("clip", "rect(130, 1024, 896, 0)");
151                 altTape.set("clip", "rect(130, 1024, 896, 0)");
152                 touchdownInd.set("clip", "rect(130, 1024, 896, 0)");
153                 minimums.set("clip", "rect(130, 1024, 896, 0)");
154                 cmdSpd.set("clip", "rect(130, 1024, 896, 0)");
155                 selAltPtr.set("clip", "rect(130, 1024, 896, 0)");
156                 vsiNeedle.set("clip", "rect(287, 1024, 739, 930)");
157                 compass.set("clip", "rect(700, 1024, 990, 0)");
158                 curAlt3.set("clip", "rect(464, 1024, 559, 0)");
159                 curSpdTen.set("clip", "rect(464, 1024, 559, 0)");
160                 
161                 return m;
162         },
163         update: func()
164         {
165                 var radioAlt = getprop("position/altitude-agl-ft")-16.5;
166                 var alt = getprop("instrumentation/altimeter/indicated-altitude-ft");
167                 if (alt < 0)
168                         alt = 0;
169                 var apAlt = getprop("autopilot/settings/target-altitude-ft");
170                 var ias = getprop("velocities/airspeed-kt");
171                 var flaps = getprop("/controls/flight/flaps");
172                 var pitch = getprop("orientation/pitch-deg");
173                 var roll =  getprop("orientation/roll-deg");
174                 
175                 #10 deg = 105px
176                 horizon.setTranslation(0,pitch*10.5);
177                 horizon.setRotation(-roll*D2R);
178                 bankPointer.setRotation(-roll*D2R);
179                 compass.setRotation(-getprop("orientation/heading-deg")*D2R);
180                 
181                 # Flight director
182                 #if (getprop("autopilot/internal/target-pitch-deg") != nil)
183                 #       fdY.setTranslation(0,(getprop("autopilot/internal/target-pitch-deg")-pitch)*10.5);
184                 if (getprop("autopilot/internal/target-roll-deg") != nil) {
185                         var fdRoll = (roll-getprop("/autopilot/internal/target-roll-deg"))*10.5;
186                         if (fdRoll > 300)
187                                 fdRoll = 300;
188                         elsif (fdRoll < -300)
189                                 fdRoll = -300;
190                         fdX.setTranslation(-fdRoll,0);
191                 }
192                 
193                 speedText.setText(sprintf("%3.0f",getprop("autopilot/settings/target-speed-kt")));
194                 machText.setText(sprintf("%.3f",getprop("velocities/mach")));
195                 altText.setText(sprintf("%5.0f",apAlt));
196                 selHdgText.setText(sprintf("%3.0f",getprop("autopilot/settings/true-heading-deg")));
197                 
198                 curAlt1.setText(sprintf("%2.0f",math.floor(alt/1000)));
199                 curAlt2.setText(sprintf("%1.0f",math.mod(math.floor(alt/100),10)));
200                 curAlt3.setTranslation(0,(math.mod(alt,100)/20)*35);
201                 var curAltDiff = alt-apAlt;
202                 if (abs(curAltDiff) > 300 and abs(curAltDiff) < 900) {
203                         curAltBox.setStrokeLineWidth(5);
204                         if ((alt > apAlt and getprop("velocities/vertical-speed-fps") > 10) or (alt < apAlt and getprop("velocities/vertical-speed-fps") < 10))
205                                 curAltBox.setColor(1,0,1);
206                         else
207                                 curAltBox.setColor(1,1,1);
208                 } else {
209                         curAltBox.setStrokeLineWidth(2);
210                         curAltBox.setColor(1,1,1);
211                 }
212                 if (curAltDiff > 420)
213                         curAltDiff = 420;
214                 elsif (curAltDiff < -420)
215                         curAltDiff = -420;
216                 selAltPtr.setTranslation(0,curAltDiff*0.9);
217
218                 curSpd.setText(sprintf("%2.0f",math.floor(ias/10)));
219                 curSpdTen.setTranslation(0,math.mod(ias,10)*45);
220                 baroSet.setText(sprintf("%2.2f",getprop("instrumentation/altimeter/setting-inhg")));
221                 ilsCourse.setText(sprintf("CRS %3.0f",getprop("instrumentation/nav/radials/selected-deg")));
222                 dhText.setText(sprintf("DH%3.0f",getprop("instrumentation/mk-viii/inputs/arinc429/decision-height")));
223                 
224                 if (getprop("instrumentation/marker-beacon/outer")) {
225                         markerBeacon.show();
226                         markerBeaconText.setText("OM");
227                 } elsif (getprop("instrumentation/marker-beacon/middle")) {
228                         markerBeacon.show();
229                         markerBeaconText.setText("MM");
230                 } elsif (getprop("instrumentation/marker-beacon/inner")) {
231                         markerBeacon.show();
232                         markerBeaconText.setText("IM");
233                 } else {
234                         markerBeacon.hide();
235                 }
236                 
237                 if(getprop("instrumentation/nav/heading-needle-deflection-norm") != nil) {
238                         var deflection = getprop("instrumentation/nav/heading-needle-deflection-norm");
239                         locPtr.show();
240                         
241                         if (radioAlt < 2500) {
242                                 risingRwy.show();
243                                 risingRwyPtr.show();
244                                 if (radioAlt< 200) {
245                                         risingRwy.setTranslation(deflection*150,-(200-radioAlt)*0.682);
246                                         risingRwyPtr_scale.setScale(1, ((200-radioAlt)*0.682)/11);
247                                 } else {
248                                         risingRwy.setTranslation(deflection*150,0);
249                                         risingRwyPtr_scale.setScale(1, 1);
250                                 }
251                         } else {
252                                 risingRwy.hide();
253                                 risingRwyPtr.hide();
254                         }
255                 
256                         if(abs(deflection) < 0.5) { # need to verify 0.5
257                                 locPtr.setTranslation(deflection*300,0);
258                                 risingRwyPtr.setTranslation(deflection*300,0);
259                                 locScaleExp.show();
260                                 locScale.hide();
261                         } else {
262                                 locPtr.setTranslation(deflection*150,0);
263                                 risingRwyPtr.setTranslation(deflection*150,0);
264                                 locScaleExp.hide();
265                                 locScale.show();
266                         }
267                 } else {
268                         locPtr.hide();
269                         locScaleExp.hide();
270                         locScale.hide();
271                         risingRwy.hide();
272                         risingRwyPtr.hide();
273                 }
274                 if (getprop("instrumentation/nav/nav-id") != nil)
275                         ilsId.setText(getprop("instrumentation/nav/nav-id"));
276                 if(getprop("instrumentation/nav/gs-needle-deflection-norm") != nil)
277                         gsPtr.setTranslation(0,-getprop("instrumentation/nav/gs-needle-deflection-norm")*150);
278                 
279                 if (alt < 10000)
280                         tenThousand.show();
281                 else 
282                         tenThousand.hide();
283                 if (getprop("velocities/vertical-speed-fps") != nil) {
284                         var vertSpd = getprop("velocities/vertical-speed-fps")*60;
285                         if (abs(vertSpd) > 400) {
286                                 vertSpdText.setText(sprintf("%4.0f",roundToNearest(vertSpd,50)));
287                                 vertSpdText.show();
288                         } else {
289                                 vertSpdText.hide();
290                         }
291                         if (getprop("instrumentation/pfd/target-vs") != nil)
292                                 vsPointer.setTranslation(0,-getprop("instrumentation/pfd/target-vs"));
293                 }
294                 if (radioAlt < 2500) {
295                         if (radioAlt > 500)
296                                 radioAltInd.setText(sprintf("%4.0f",roundToNearest(radioAlt,20)));
297                         elsif (radioAlt > 100)
298                                 radioAltInd.setText(sprintf("%4.0f",roundToNearest(radioAlt,10)));
299                         else
300                                 radioAltInd.setText(sprintf("%4.0f",roundToNearest(radioAlt,2)));
301                         radioAltInd.show();
302                 } else {
303                         radioAltInd.hide();
304                 }
305                 #if (getprop("instrumentation/dme/in-range")) {
306                 if(getprop("instrumentation/nav/nav-distance") != nil)
307                         dmeDist.setText(sprintf("DME %2.1f",getprop("instrumentation/nav/nav-distance")*0.000539));
308                 #       dmeDist.show();
309                 #} else {
310                 #       dmeDist.hide();
311                 #}
312                 if (getprop("instrumentation/pfd/speed-trend-up") != nil)
313                         spdTrend_scale.setScale(1, (getprop("instrumentation/pfd/speed-lookahead")-getprop("/velocities/airspeed-kt"))/20);
314                 
315                 if (getprop("instrumentation/pfd/v1-diff") != nil) {
316                         var v1Diff = getprop("instrumentation/pfd/v1-diff");
317                         if (getprop("gear/gear/wow") and v1Diff != -1) {
318                                 v1.show();
319                                 v1.setTranslation(0,-v1Diff*380);
320                         } else {
321                                 v1.hide();
322                         }
323                 } else {
324                         v1.hide();
325                 }
326                 if (getprop("instrumentation/pfd/vr-diff") != nil) {
327                         var vrDiff = getprop("instrumentation/pfd/vr-diff");
328                         if (getprop("gear/gear/wow") and abs(vrDiff) != 1) {
329                                 vr.show();
330                                 vr.setTranslation(0,-vrDiff*380);
331                         } else {
332                                 vr.hide();
333                         }
334                 } else {
335                         vr.hide();
336                 }
337                 if (getprop("instrumentation/pfd/flaps-0-diff") != nil)
338                         flaps0.setTranslation(0,-getprop("instrumentation/pfd/flaps-0-diff")*380);
339                 if (getprop("instrumentation/pfd/flaps-1-diff") != nil)
340                         flaps1.setTranslation(0,-getprop("instrumentation/pfd/flaps-1-diff")*380);
341                 if (getprop("instrumentation/pfd/flaps-5-diff") != nil)
342                         flaps5.setTranslation(0,-getprop("instrumentation/pfd/flaps-5-diff")*380);
343                 if (getprop("instrumentation/pfd/flaps-10-diff") != nil)
344                         flaps10.setTranslation(0,-getprop("instrumentation/pfd/flaps-10-diff")*380);
345                 if (getprop("instrumentation/pfd/flaps-20-diff") != nil)
346                         flaps20.setTranslation(0,-getprop("instrumentation/pfd/flaps-20-diff")*380);
347                 
348                 flaps0.hide();
349                 flaps1.hide();
350                 flaps5.hide();
351                 flaps10.hide();
352                 flaps20.hide();
353                 if (alt < 20000) {
354                         if (flaps == 0.033) {
355                                 flaps0.show(); flaps1.show();
356                         } elsif (flaps == 0.167) {
357                                 flaps1.show(); flaps5.show();
358                         } elsif (flaps == 0.333) {
359                                 flaps5.show(); flaps10.show();
360                         } elsif (flaps == 0.667) {
361                                 flaps10.show(); flaps20.show();
362                         }
363                 }
364                 if (getprop("instrumentation/pfd/stallspeed-diff") != nil)
365                         minSpdInd.setTranslation(0,-getprop("instrumentation/pfd/stallspeed-diff")*380);
366                 if (getprop("instrumentation/pfd/overspeed-diff") != nil)
367                         maxSpdInd.setTranslation(0,-getprop("instrumentation/pfd/overspeed-diff")*380);
368                 if (getprop("instrumentation/pfd/minimums-diff") != nil)
369                         minimums.setTranslation(0,-getprop("instrumentation/pfd/minimums-diff"));
370                 if (getprop("instrumentation/pfd/touchdown-zone-diff") != nil) {
371                         touchdownInd.setTranslation(0,-getprop("instrumentation/pfd/touchdown-zone-diff"));
372                         touchdownInd.show();
373                 } else
374                         touchdownInd.hide();
375                 
376                 if(getprop("/gear/gear/wow")) {
377                         minSpdInd.hide();
378                         maxSpdInd.hide();
379                 } else {
380                         minSpdInd.show();
381                         maxSpdInd.show();
382                 }
383                 
384                 spdTape.setTranslation(0,ias*6);
385                 altTape.setTranslation(0,alt*0.9);
386                 if (getprop("autopilot/settings/target-speed-kt") != nil )
387                         cmdSpd.setTranslation(0,-(getprop("autopilot/settings/target-speed-kt")-ias)*6);
388                 
389                 if(getprop("instrumentation/pfd/vsi-needle-deg") != nil)
390                         vsiNeedle.setRotation(getprop("instrumentation/pfd/vsi-needle-deg")*D2R);
391                 
392                 var apSpd = getprop("/autopilot/locks/speed");
393                 if (apSpd == "speed-with-throttle-mach" or apSpd == "speed-with-throttle-ias")
394                         atMode.setText("SPD");
395                 elsif (apSpd ==  "speed-with-pitch-trim")
396                         atMode.setText("THR");
397                 else
398                         atMode.setText("");
399                 var apRoll = getprop("/autopilot/locks/heading");
400                 if (apRoll == "wing-leveler")
401                         rollMode.setText("HDG HOLD");
402                 elsif (apRoll ==  "dg-heading-hold")
403                         rollMode.setText("HDG SEL");
404                 elsif (apRoll ==  "nav1-hold")
405                         rollMode.setText("LNAV");
406                 else
407                         rollMode.setText("");
408                 vsPointer.hide();
409                 var apPitch = getprop("/autopilot/locks/altitude");
410                 if (apPitch == "vertical-speed-hold") {
411                         pitchMode.setText("V/S");
412                         vsPointer.show();
413                 } elsif (apPitch ==  "altitude-hold")
414                         pitchMode.setText("ALT");
415                 else
416                         pitchMode.setText("");
417                 
418                 settimer(func me.update(), 0.05);
419         }
420 };
421
422 setlistener("sim/signals/fdm-initialized", func() {
423         pfd_display = canvas.new({
424                 "name": "PFD",
425                 "size": [1024, 1024],
426                 "view": [1024, 1024],
427                 "mipmapping": 1
428         });
429         pfd_display.addPlacement({"node": "pfdScreen"});
430         var group = pfd_display.createGroup();
431         pfd_canvas = canvas_PFD.new(group);
432         pfd_canvas.update();
433 });
434
435 setlistener("sim/signals/reinit", func pfd_display.del());
436
437 # The optional second arguments enables creating a window decoration
438 var showPfd = func() {
439         var dlg = canvas.Window.new([400, 400], "dialog");
440         dlg.setCanvas(pfd_display);
441 }