From 91dd7627368999a9f9918213134ce9b2fa75b9b3 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sun, 18 Feb 2018 21:41:17 +0000 Subject: [PATCH] Support for Runway numbers on RWY MapStructure layer - Change getInstance to getOrCreateInstance for FG1000. - Implement runway numbering on AirportInformation page. --- .../Instruments-3d/FG1000/Nasal/FG1000.nas | 4 +- .../Interfaces/GenericInterfaceController.nas | 2 +- .../MFDPages/AirportInfo/AirportInfo.nas | 2 +- .../AirportInfo/AirportInfoOptions.nas | 2 +- .../AirportInfo/AirportInfoStyles.nas | 19 ++- Aircraft/Instruments-3d/FG1000/README | 5 +- Nasal/canvas/map/APS-FG1000.lcontroller | 25 ++++ Nasal/canvas/map/APS-FG1000.symbol | 18 +++ Nasal/canvas/map/Images/genericAirplane.svg | 80 ++++++++++++ Nasal/canvas/map/RWY.lcontroller | 10 +- Nasal/canvas/map/RWY.symbol | 122 +++++++++++++----- Nasal/canvas/map/VOR-FG1000.lcontroller | 2 +- Nasal/canvas/map/VOR-FG1000.symbol | 15 ++- Nasal/canvas/map/VOR-g1000.lcontroller | 62 +++++++++ Nasal/canvas/map/VOR-g1000.symbol | 70 ++++++++++ gui/menubar.xml | 6 +- 16 files changed, 383 insertions(+), 61 deletions(-) create mode 100644 Nasal/canvas/map/APS-FG1000.lcontroller create mode 100644 Nasal/canvas/map/APS-FG1000.symbol create mode 100644 Nasal/canvas/map/Images/genericAirplane.svg create mode 100644 Nasal/canvas/map/VOR-g1000.lcontroller create mode 100644 Nasal/canvas/map/VOR-g1000.symbol diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/FG1000.nas b/Aircraft/Instruments-3d/FG1000/Nasal/FG1000.nas index ba881c88c..46e7edd8a 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/FG1000.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/FG1000.nas @@ -36,7 +36,7 @@ var FG1000 = { _instance : nil, # Factory method -getInstance : func(EIS_Class = nil, EIS_SVG = nil) { +getOrCreateInstance : func(EIS_Class = nil, EIS_SVG = nil) { if (FG1000._instance == nil) { FG1000._instance = FG1000.new(EIS_Class, EIS_SVG); } @@ -87,8 +87,6 @@ addMFD : func(index=nil, targetcanvas=nil, screenObject=nil) { if (index == nil) { index = size(keys(me.displays)); - debug.dump(keys(me.displays)); - print("No index passed. Defaulting to " ~ index); } else if (me.displays[index] != nil) { print("FG1000 Index " ~ index ~ " already exists!"); return diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas index fc3e2c844..2ac874175 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas @@ -32,7 +32,7 @@ var GenericInterfaceController = { _instance : nil, # Factory method - getInstance : func() { + getOrCreateInstance : func() { if (GenericInterfaceController._instance == nil) { GenericInterfaceController._instance = GenericInterfaceController.new(); } diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas index 5b99d2373..06d5d19ad 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas @@ -92,7 +92,7 @@ var AirportInfo = ); var r = func(name,vis=1,zindex=nil) return caller(0)[0]; - foreach(var type; [r('TAXI'),r('RWY')] ) { + foreach(var type; [r('TAXI'),r('RWY'),r('APT')] ) { obj.AirportChart.addLayer(canvas.SymbolLayer, type.name, 4, diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoOptions.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoOptions.nas index 61ea1b2ec..c64f489d3 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoOptions.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoOptions.nas @@ -34,7 +34,7 @@ var AirportInfoOptions = loadOptions : func() { me.clearOptions(); - me.Options.APS = {}; + me.Options.RWY = {}; }, clearOptions : func() { diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoStyles.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoStyles.nas index 09da9c26b..3dbf0f91f 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoStyles.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfoStyles.nas @@ -33,8 +33,23 @@ var AirportInfoStyles = }, loadStyles : func() { - me. clearStyles(); - me.Styles.XXX = {}; + me.clearStyles(); + me.Styles.RWY = {}; + me.Styles.RWY.text_color = [0,0,0,1]; # Black text ... + me.Styles.RWY.text_bgcolor = [1,1,1,1]; # ... on a white background + me.Styles.RWY.text_mode = canvas.Text.TEXT + canvas.Text.FILLEDBOUNDINGBOX; + me.Styles.RWY.text_padding = 1; + me.Styles.RWY.text_alignment = 'center-center'; + me.Styles.RWY.text_size = 14; + me.Styles.RWY.show_labels= 1; + + me.Styles.APT = {}; + me.Styles.APT.scale_factor = 0.4; # 40% (applied to whole group) + me.Styles.APT.line_width = 3.0; + me.Styles.APT.color_default = [0,0.6,0.85]; #rgb + me.Styles.APT.label_font_color = me.Styles.APT.color_default; + me.Styles.APT.label_font_size=28; + }, clearStyles : func() { diff --git a/Aircraft/Instruments-3d/FG1000/README b/Aircraft/Instruments-3d/FG1000/README index 925070373..b711b9f21 100644 --- a/Aircraft/Instruments-3d/FG1000/README +++ b/Aircraft/Instruments-3d/FG1000/README @@ -23,7 +23,8 @@ piston engine. You need to load it as follows: var nasal_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/FG1000/Nasal/"; -var interfaceController = fg1000.GenericInterfaceController.getInstance(); +io.load_nasal(nasal_dir ~ 'Interfaces/GenericInterfaceController.nas', "fg1000"); +var interfaceController = fg1000.GenericInterfaceController.getOrCreateInstance(); interfaceController.start(); You may want to create your own version depending on what properties you are @@ -59,4 +60,4 @@ fg1000system.display(1); fg1000system.display(2); # Display a GUI version of device 1 at 50% scale. -#fg1000system.displayGUI(1, 0.5); +#fg1000system.displayGUI(1, 0.5) diff --git a/Nasal/canvas/map/APS-FG1000.lcontroller b/Nasal/canvas/map/APS-FG1000.lcontroller new file mode 100644 index 000000000..bd7a609b2 --- /dev/null +++ b/Nasal/canvas/map/APS-FG1000.lcontroller @@ -0,0 +1,25 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'APS_FG1000'; +var parents = [SymbolLayer.Controller]; +var __self__ = caller(0)[0]; +SymbolLayer.Controller.add(name, __self__); +SymbolLayer.add(name, { + parents: [SingleSymbolLayer], + type: name, # Symbol type + df_controller: __self__, # controller to use by default -- this one + df_style: {}, +}); +# N.B.: if used, this SymbolLayer should be updated every frame +# by the Map Controller, or as often as the position is changed. +var new = func(layer) { + var __model = layer.map.getPosCoord(); + #debug.dump(typeof(layer.options)); + if(layer.options != nil and contains(layer.options, 'model')) + __model = layer.options.model; + return { + parents: [__self__], + _model: __model, + }; +}; +var del = func; diff --git a/Nasal/canvas/map/APS-FG1000.symbol b/Nasal/canvas/map/APS-FG1000.symbol new file mode 100644 index 000000000..f19709360 --- /dev/null +++ b/Nasal/canvas/map/APS-FG1000.symbol @@ -0,0 +1,18 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'APS_FG1000'; +var parents = [SVGSymbol]; +var __self__ = caller(0)[0]; +DotSym.makeinstance( name, __self__ ); + +var svg_path = "Nasal/canvas/map/Images/genericAirplane.svg"; +var element_id = "airplane"; + +# Rotate with the main aircraft. +# Will have to be adapted if intended for use with other aircraft +# (but one could simply copy the layer for that). +var draw = func { + var rot = getprop("/orientation/heading-deg"); + rot -= me.layer.map.getHdg(); + me.element.setRotation(rot*D2R); +}; diff --git a/Nasal/canvas/map/Images/genericAirplane.svg b/Nasal/canvas/map/Images/genericAirplane.svg new file mode 100644 index 000000000..72fc9f14c --- /dev/null +++ b/Nasal/canvas/map/Images/genericAirplane.svg @@ -0,0 +1,80 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/Nasal/canvas/map/RWY.lcontroller b/Nasal/canvas/map/RWY.lcontroller index 652786c14..b516ec1b8 100644 --- a/Nasal/canvas/map/RWY.lcontroller +++ b/Nasal/canvas/map/RWY.lcontroller @@ -8,12 +8,8 @@ SymbolLayer.add(name, { parents: [MultiSymbolLayer], type: name, # Symbol type df_controller: __self__, # controller to use by default -- this one - df_style: { - surface_color: canvas.SURFACECOLORS - }, - df_options: { # default configuration options - disable_position: 1, - }, + df_options: {}, + df_style: {}, }); var a_instance = nil; var new = func(layer) { @@ -28,13 +24,11 @@ var new = func(layer) { return m; }; var del = func() { - #print(name,".lcontroller.del()"); foreach (var l; me.listeners) removelistener(l); }; var searchCmd = func { - #print("Running query:", name); var range = me.map.getRange(); if (range == nil) return; return positioned.findAirportsWithinRange(me.map.getPosCoord(), range); diff --git a/Nasal/canvas/map/RWY.symbol b/Nasal/canvas/map/RWY.symbol index 0f2b12d16..a6d15a033 100644 --- a/Nasal/canvas/map/RWY.symbol +++ b/Nasal/canvas/map/RWY.symbol @@ -5,6 +5,18 @@ var parents = [DotSym]; var __self__ = caller(0)[0]; DotSym.makeinstance( name, __self__ ); +SymbolLayer.get(name).df_style = { + surface_color: canvas.SURFACECOLORS, + text_alignment: "center-center", + text_bgcolor: [0,0,0,0], + text_color: [0,0.6,0.85], + text_mode: canvas.Text.TEXT, + text_padding: 0, + text_size: 14, + text_font: "LiberationFonts/LiberationSans-Regular.ttf", + show_labels: 0, +}; + var element_type = "group"; # we want a group, becomes "me.element" var rwys = nil; @@ -98,40 +110,88 @@ var init = func { end_thr2[0], end_thr2[1] ] ); - #draw helipads - foreach(var hp; keys(apt.helipads)) - { - var hp = apt.runway(hp); - var clr = me.style.surface_color[hp.surface]; - if (clr == nil) { clr = SURFACECOLORS[hp.surface]}; - if (clr == nil) { clr = SURFACECOLORS[0]}; + if (me.style.show_labels == 1) { + var coord1 = geo.Coord.new(); + coord1.set_latlon(rw1.lat, rw1.lon); + coord1.apply_course_distance(rw1.heading, - 50.0); - var icon_hp = - me.element.createChild("path", "helipad-" ~ hp.id) - .setStrokeLineWidth(0.5) - .setColor(1.0,1.0,1.0) - .setColorFill(clr.r, clr.g, clr.b); + var coord2 = geo.Coord.new(); + coord2.set_latlon(rw2.lat, rw2.lon); + coord2.apply_course_distance(rw2.heading, - 50.0); - var heli = Runway.new(hp); - var p1 = heli.pointOffCenterline(0.5 * hp.length, 0.5 * hp.width); - var p2 = heli.pointOffCenterline(0.5 * hp.length, -0.5 * hp.width); - var p3 = heli.pointOffCenterline(-0.5 * hp.length, -0.5 * hp.width); - var p4 = heli.pointOffCenterline(-0.5 * hp.length, 0.5 * hp.width); - - icon_hp.setDataGeo - ( - [ canvas.Path.VG_MOVE_TO, - canvas.Path.VG_LINE_TO, - canvas.Path.VG_LINE_TO, - canvas.Path.VG_LINE_TO, - canvas.Path.VG_CLOSE_PATH ], - [ p1[0], p1[1], - p2[0], p2[1], - p3[0], p3[1], - p4[0], p4[1] ] - ); - } + var txt1 = me.element.createChild("text", "rwy1label") + .setText(rw1.id) + .setGeoPosition(coord1.lat(), coord1.lon()) + .setFont(me.style.text_font) + .setFontSize(me.style.text_size) + .setAlignment(me.style.text_alignment) + .setPadding(me.style.text_padding) + .setDrawMode(me.style.text_mode) + .setColor(me.style.text_color) + .setColorFill(me.style.text_bgcolor); + var txt1 = me.element.createChild("text", "rwy2label") + .setText(rw2.id) + .setGeoPosition(coord2.lat(), coord2.lon()) + .setFont(me.style.text_font) + .setFontSize(me.style.text_size) + .setAlignment(me.style.text_alignment) + .setPadding(me.style.text_padding) + .setDrawMode(me.style.text_mode) + .setColor(me.style.text_color) + .setColorFill(me.style.text_bgcolor); + } } + + #draw helipads + foreach(var hp; keys(apt.helipads)) + { + var hp = apt.runway(hp); + var clr = me.style.surface_color[hp.surface]; + if (clr == nil) { clr = SURFACECOLORS[hp.surface]}; + if (clr == nil) { clr = SURFACECOLORS[0]}; + + var icon_hp = + me.element.createChild("path", "helipad-" ~ hp.id) + .setStrokeLineWidth(0.5) + .setColor(1.0,1.0,1.0) + .setColorFill(clr.r, clr.g, clr.b); + + var heli = Runway.new(hp); + var p1 = heli.pointOffCenterline(0.5 * hp.length, 0.5 * hp.width); + var p2 = heli.pointOffCenterline(0.5 * hp.length, -0.5 * hp.width); + var p3 = heli.pointOffCenterline(-0.5 * hp.length, -0.5 * hp.width); + var p4 = heli.pointOffCenterline(-0.5 * hp.length, 0.5 * hp.width); + + icon_hp.setDataGeo + ( + [ canvas.Path.VG_MOVE_TO, + canvas.Path.VG_LINE_TO, + canvas.Path.VG_LINE_TO, + canvas.Path.VG_LINE_TO, + canvas.Path.VG_CLOSE_PATH ], + [ p1[0], p1[1], + p2[0], p2[1], + p3[0], p3[1], + p4[0], p4[1] ] + ); + + if (me.style.show_labels == 1) { + var coord1 = geo.Coord.new(); + coord1.set_latlon(rw1.lat, rw1.lon); + coord1.apply_course_distance(rw1.heading, - 50.0); + + var txt1 = me.element.createChild("text", "hplabel") + .setText(hp.id) + .setGeoPosition(coord1.lat(), coord1.lon()) + .setFont(me.style.text_font) + .setFontSize(me.style.text_size) + .setAlignment(me.style.text_alignment) + .setPadding(me.style.text_padding) + .setDrawMode(me.style.text_mode) + .setColor(me.style.text_color) + .setColorFill(me.style.text_bgcolor); + } + } }; var draw = func; diff --git a/Nasal/canvas/map/VOR-FG1000.lcontroller b/Nasal/canvas/map/VOR-FG1000.lcontroller index e2d048b75..b870a9477 100644 --- a/Nasal/canvas/map/VOR-FG1000.lcontroller +++ b/Nasal/canvas/map/VOR-FG1000.lcontroller @@ -16,7 +16,7 @@ var new = func(layer) { layer: layer, map: layer.map, listeners: [], - query_type:'ndb', + query_type:'vor', }; m.addVisibilityListener(); diff --git a/Nasal/canvas/map/VOR-FG1000.symbol b/Nasal/canvas/map/VOR-FG1000.symbol index e0b1fa6b5..2cf824157 100644 --- a/Nasal/canvas/map/VOR-FG1000.symbol +++ b/Nasal/canvas/map/VOR-FG1000.symbol @@ -104,15 +104,16 @@ var init = func { ); cache.render(me.element, me.style).setScale(me.style.scale_factor); - var txt_offset = me.getStyle('text_offset', [3, 0]); - var txt_alignment = me.getStyle('text_alignment', 'left-bottom'); - var txt_color = me.getStyle('text_color', [0,0.6,0.85]); - var txt_bgcolor = me.getStyle('text_bgcolor', [0,0,0,0]); - var txt_mode = me.getStyle('text_mode', canvas.Text.TEXT); - var txt_padding = me.getStyle('text_padding', 0); - var txt_size = me.getStyle('font_size', 14); # non-cached stuff: if (me.style.show_labels){ + var txt_offset = me.getStyle('text_offset', [3, 0]); + var txt_alignment = me.getStyle('text_alignment', 'center-bottom'); + var txt_color = me.getStyle('text_color', [0,0.6,0.85]); + var txt_bgcolor = me.getStyle('text_bgcolor', [0,0,0,0]); + var txt_mode = me.getStyle('text_mode', canvas.Text.TEXT); + var txt_padding = me.getStyle('text_padding', 0); + var txt_size = me.getStyle('font_size', 14); + me.text_fix = me.newText(me.model.id). setScale(me.style.scale_factor). setTranslation(txt_offset). diff --git a/Nasal/canvas/map/VOR-g1000.lcontroller b/Nasal/canvas/map/VOR-g1000.lcontroller new file mode 100644 index 000000000..73158374d --- /dev/null +++ b/Nasal/canvas/map/VOR-g1000.lcontroller @@ -0,0 +1,62 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name ='VOR-g1000'; +var parents = [SymbolLayer.Controller]; +var __self__ = caller(0)[0]; +SymbolLayer.Controller.add(name, __self__); +SymbolLayer.add(name, { + parents: [NavaidSymbolLayer], + type: name, # Symbol type + df_controller: __self__, # controller to use by default -- this one + df_options: { + nav1_frq: 'instrumentation/nav/frequencies/selected-mhz', + nav2_frq: 'instrumentation/nav[1]/frequencies/selected-mhz' + }, + df_style: { + scale: 1 + } +}); +var new = func(layer) { + var m = { + parents: [__self__], + layer: layer, + map: layer.map, + active_vors: [], + navNs: props.globals.getNode("instrumentation").getChildren("nav"), + listeners: [], + query_type:'vor', + }; + setsize(m.active_vors, size(m.navNs)); + foreach (var navN; m.navNs) { + append(m.listeners, setlistener( + navN.getNode("frequencies/selected-mhz"), + func m.changed_freq() + )); + } + #call(debug.dump, keys(layer)); + m.changed_freq(update:0); + m.addVisibilityListener(); + + return m; +}; +var del = func() { + printlog(_MP_dbg_lvl, name,".lcontroller.del()"); + foreach (var l; me.listeners) + removelistener(l); +}; + +# Controller methods +var isActive = func(model) { + var my_freq = model.frequency/100; + foreach (var freq; me.active_vors) + if (freq == my_freq) return 1; + return 0; +}; +var changed_freq = func(update=1) { + #debug.dump(me.active_vors); + foreach (var navN; me.navNs) + me.active_vors[ navN.getIndex() ] = navN.getValue("frequencies/selected-mhz"); + if (update) me.layer.update(); +}; + +var searchCmd = NavaidSymbolLayer.make('vor'); diff --git a/Nasal/canvas/map/VOR-g1000.symbol b/Nasal/canvas/map/VOR-g1000.symbol new file mode 100644 index 000000000..076520989 --- /dev/null +++ b/Nasal/canvas/map/VOR-g1000.symbol @@ -0,0 +1,70 @@ +# Class things: +var name = 'VOR-g1000'; +var parents = [SVGSymbol]; +var __self__ = caller(0)[0]; +DotSym.makeinstance( name, __self__ ); + +var element_type = "group"; # we want a group, becomes "me.element" +var text_vor = nil; + +var svg_path = 'Nasal/canvas/map/Garmin/Images/g1000_vor2.svg'; +#var svg_path = 'Nasal/canvas/map/Airbus/Images/airbus_vor.svg'; +var vor_sym = nil; +var vor_center = nil; + +var draw = func{ + if(me.vor_sym == nil) { + me.vor_sym = me.element.getElementById("vor"); + #me.vor_sym = me.element.getElementById("airbus-vor-sym"); + } + + me.vor_sym.setTranslation(-100,-100); + + var heading = me.map.getHdg(); + me.vor_sym.setRotation(heading); + + #me.vor_sym.setScale(0.5); + + if(me.text_vor == nil){ + var transl = me.getStyle('translation', [-10,20]); + var text_color = me.getStyle('text_color', [1,1,1]); + me.text_vor = me.element.createChild("text") + .setDrawMode( canvas.Text.TEXT ) + .setText(me.model.id) + .setFont("LiberationFonts/LiberationSans-Regular.ttf") + .setFontSize(12) + .setColor(text_color) + .setTranslation(transl); + } + if(me.vor_center == nil) { + var line_width = me.getStyle('line_width', 3); + var color = me.getStyle('color', [0.2,0.2,0.6]); + me.vor_center = me.element.createChild("path") + .moveTo(-15,0) + .lineTo(-7.5,12.5) + .lineTo(7.5,12.5) + .lineTo(15,0) + .lineTo(7.5,-12.5) + .lineTo(-7.5,-12.5) + .close() + .setStrokeLineWidth(line_width) + .setColor(color) + .set("z-index",-2); + } + + var frq = me.model.frequency; + if(frq != nil){ + var dfcolor = me.getStyle('color', [0.9,0,0.47]); + var tuned_color = me.getStyle('tuned_color', [0,0.62,0.84]); + frq = frq / 100; + var nav1_frq = getprop(me.options.nav1_frq); + var nav2_frq = getprop(me.options.nav2_frq); + if(nav1_frq == frq or nav2_frq == frq){ + me.text_vor.setColor(me.getStyle('text_color', [1,1,1])); + } else { + me.text_vor.setColor(me.getStyle('text_color', [0.7,0.7,0.7])); + } + } + + +} diff --git a/gui/menubar.xml b/gui/menubar.xml index 21b95afc2..ccde973f5 100644 --- a/gui/menubar.xml +++ b/gui/menubar.xml @@ -828,19 +828,17 @@