From d84c527ca747dd6bbd9634507f0664ff3631bdef Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Fri, 13 Oct 2017 17:38:27 +0100 Subject: [PATCH] Canvas MapLayers for Airport Add RWY, TAXI, TWR, PARKING map layers Add new static position controller Update Select Airport dialog to use new MapLayers. --- Nasal/canvas/api.nas | 6 +- Nasal/canvas/map/PARKING.lcontroller | 48 +++++ Nasal/canvas/map/PARKING.symbol | 46 ++++ Nasal/canvas/map/RWY.lcontroller | 41 ++++ Nasal/canvas/map/RWY.symbol | 137 ++++++++++++ Nasal/canvas/map/TAXI.lcontroller | 41 ++++ Nasal/canvas/map/TAXI.symbol | 60 ++++++ Nasal/canvas/map/TWR.lcontroller | 42 ++++ Nasal/canvas/map/TWR.symbol | 31 +++ Nasal/canvas/map/staticpos.controller | 74 +++++++ gui/dialogs/airports.xml | 299 ++++++++++++++++++++------ 11 files changed, 753 insertions(+), 72 deletions(-) create mode 100644 Nasal/canvas/map/PARKING.lcontroller create mode 100644 Nasal/canvas/map/PARKING.symbol create mode 100644 Nasal/canvas/map/RWY.lcontroller create mode 100644 Nasal/canvas/map/RWY.symbol create mode 100644 Nasal/canvas/map/TAXI.lcontroller create mode 100644 Nasal/canvas/map/TAXI.symbol create mode 100644 Nasal/canvas/map/TWR.lcontroller create mode 100644 Nasal/canvas/map/TWR.symbol create mode 100644 Nasal/canvas/map/staticpos.controller diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas index 3f1c2daac..60b053250 100644 --- a/Nasal/canvas/api.nas +++ b/Nasal/canvas/api.nas @@ -450,7 +450,7 @@ var Group = { # Map # ============================================================================== -# Class for a group element on a canvas with possibly geopgraphic positions +# Class for a group element on a canvas with possibly geographic positions # which automatically get projected according to the specified projection. # Each map consists of an arbitrary number of layers (canvas groups) # @@ -502,6 +502,10 @@ var Map = { return me; }, + getController: func() + { + return me.controller; + }, addLayer: func(factory, type_arg=nil, priority=nil, style=nil, opts=nil, visible=1) { if(contains(me.layers, type_arg)) diff --git a/Nasal/canvas/map/PARKING.lcontroller b/Nasal/canvas/map/PARKING.lcontroller new file mode 100644 index 000000000..d75d8fde3 --- /dev/null +++ b/Nasal/canvas/map/PARKING.lcontroller @@ -0,0 +1,48 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'PARKING'; +var parents = [SymbolLayer.Controller]; +var __self__ = caller(0)[0]; +SymbolLayer.Controller.add(name, __self__); +SymbolLayer.add(name, { + parents: [MultiSymbolLayer], + type: name, # Symbol type + df_controller: __self__, # controller to use by default -- this one + df_style: { + line_width: 3, + scale_factor: 1, + debug: 1, + color_default: [0,0.85,0.6], + label_font_color:[0,0.85,0.6], + label_font_size: 28, + text_offset: [10,0], + svg_path: nil + }, + df_options: { # default configuration options + disable_position: 1, + }, +}); +var a_instance = nil; +var new = func(layer) { + var m = { + parents: [__self__], + layer: layer, + map: layer.map, + listeners: [], + }; + m.addVisibilityListener(); + + 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/PARKING.symbol b/Nasal/canvas/map/PARKING.symbol new file mode 100644 index 000000000..e7962ab8d --- /dev/null +++ b/Nasal/canvas/map/PARKING.symbol @@ -0,0 +1,46 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'PARKING'; +var parents = [DotSym]; +var __self__ = caller(0)[0]; +DotSym.makeinstance( name, __self__ ); + +var element_type = "group"; # we want a group, becomes "me.element" +var rwys = nil; + +var init = func { + var apt=airportinfo(me.model.id); + var style = me.layer.style; + var svg_path = style.svg_path; + + var group = me.element.createChild("group", "parking-"~apt.id); + foreach(var park; apt.parking()) { + var p = me.element.createChild("group", "parking-"~park.name); + p.setGeoPosition(park.lat, park.lon); + + if (svg_path != nil) { + canvas.parsesvg(p, svg_path); + } else { + p.createChild("path", name ~ " icon" ) + .moveTo(-10,-10) + .lineTo(10,10) + .moveTo(10,-10) + .lineTo(-10,10) + .close() + .setColor(style.color_default) + .setStrokeLineWidth(style.line_width) + .setScale(style.scale_factor); + } + + p.createChild("text", "parking-" ~ park.name) + .setDrawMode( canvas.Text.ALIGNMENT + + canvas.Text.TEXT ) + .setTranslation([style.scale_factor * style.text_offset[0], style.scale_factor * style.text_offset[1]]) + .setText(park.name) + .setFont("LiberationFonts/LiberationSans-Regular.ttf") + .setColor(style.label_font_color) + .setFontSize(style.label_font_size, 1.3) + .setScale(style.scale_factor); + } +}; +var draw = func; diff --git a/Nasal/canvas/map/RWY.lcontroller b/Nasal/canvas/map/RWY.lcontroller new file mode 100644 index 000000000..652786c14 --- /dev/null +++ b/Nasal/canvas/map/RWY.lcontroller @@ -0,0 +1,41 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'RWY'; +var parents = [SymbolLayer.Controller]; +var __self__ = caller(0)[0]; +SymbolLayer.Controller.add(name, __self__); +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, + }, +}); +var a_instance = nil; +var new = func(layer) { + var m = { + parents: [__self__], + layer: layer, + map: layer.map, + listeners: [], + }; + m.addVisibilityListener(); + + 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 new file mode 100644 index 000000000..0f2b12d16 --- /dev/null +++ b/Nasal/canvas/map/RWY.symbol @@ -0,0 +1,137 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'RWY'; +var parents = [DotSym]; +var __self__ = caller(0)[0]; +DotSym.makeinstance( name, __self__ ); + +var element_type = "group"; # we want a group, becomes "me.element" +var rwys = nil; + +var SURFACECOLORS = { + 1 : { type: "asphalt", r:0.2, g:0.2, b:0.2 }, + 2 : { type: "concrete", r:0.3, g:0.3, b:0.3 }, + 3 : { type: "turf", r:0.2, g:0.5, b:0.2 }, + 4 : { type: "dirt", r:0.4, g:0.3, b:0.3 }, + 5 : { type: "gravel", r:0.35, g:0.3, b:0.3 }, +# Helipads + 6 : { type: "asphalt", r:0.2, g:0.2, b:0.2 }, + 7 : { type: "concrete", r:0.3, g:0.3, b:0.3 }, + 8 : { type: "turf", r:0.2, g:0.5, b:0.2 }, + 9 : { type: "dirt", r:0.4, g:0.3, b:0.3 }, + 0 : { type: "gravel", r:0.35, g:0.3, b:0.3 }, +}; + + +var init = func { + var apt=airportinfo(me.model.id); + var rwys = apt.runwaysWithoutReciprocals(); + + foreach (var rw1; rwys) + { + var clr = me.style.surface_color[rw1.surface]; + if (clr == nil) { clr = SURFACECOLORS[rw1.surface]}; + if (clr == nil) { clr = SURFACECOLORS[0]}; + + var icon_rw = + me.element.createChild("path", "runway-" ~ rw1.id) + .setStrokeLineWidth(0.5) + .setColor(1.0,1.0,1.0) + .setColorFill(clr.r, clr.g, clr.b); + + var rwy1 = Runway.new(rw1); + var beg_thr = rwy1.pointOffCenterline(rw1.threshold); + var beg_thr1 = rwy1.pointOffCenterline(rw1.threshold, 0.5 * rw1.width); + var beg_thr2 = rwy1.pointOffCenterline(rw1.threshold, -0.5 * rw1.width); + var beg1 = rwy1.pointOffCenterline(0, 0.5 * rw1.width); + var beg2 = rwy1.pointOffCenterline(0, -0.5 * rw1.width); + + var rw2 = rw1.reciprocal; + var rwy2 = Runway.new(rw2); + var end_thr = rwy2.pointOffCenterline(rw2.threshold); + var end_thr1 = rwy2.pointOffCenterline(rw2.threshold, 0.5 * rw2.width); + var end_thr2 = rwy2.pointOffCenterline(rw2.threshold, -0.5 * rw2.width); + var end1 = rwy2.pointOffCenterline(0, 0.5 * rw2.width); + var end2 = rwy2.pointOffCenterline(0, -0.5 * rw2.width); + + icon_rw.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 ], + [ beg1[0], beg1[1], + beg2[0], beg2[1], + end1[0], end1[1], + end2[0], end2[1] ] + ); + + var icon_cl = + me.element.createChild("path", "centerline") + .setStrokeLineWidth(0.5) + .setColor(1,1,1) + .setStrokeDashArray([15, 10]); + + icon_cl.setDataGeo + ( + [ canvas.Path.VG_MOVE_TO, + canvas.Path.VG_LINE_TO ], + [ beg_thr[0], beg_thr[1], + end_thr[0], end_thr[1] ] + ); + + var icon_thr = + me.element.createChild("path", "threshold") + .setStrokeLineWidth(1.5) + .setColor(1,1,1); + + icon_thr.setDataGeo + ( + [ canvas.Path.VG_MOVE_TO, + canvas.Path.VG_LINE_TO, + canvas.Path.VG_MOVE_TO, + canvas.Path.VG_LINE_TO ], + [ beg_thr1[0], beg_thr1[1], + beg_thr2[0], beg_thr2[1], + end_thr1[0], end_thr1[1], + 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]}; + + 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] ] + ); + } + + } +}; +var draw = func; diff --git a/Nasal/canvas/map/TAXI.lcontroller b/Nasal/canvas/map/TAXI.lcontroller new file mode 100644 index 000000000..f27cd8105 --- /dev/null +++ b/Nasal/canvas/map/TAXI.lcontroller @@ -0,0 +1,41 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'TAXI'; +var parents = [SymbolLayer.Controller]; +var __self__ = caller(0)[0]; +SymbolLayer.Controller.add(name, __self__); +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, + }, +}); +var a_instance = nil; +var new = func(layer) { + var m = { + parents: [__self__], + layer: layer, + map: layer.map, + listeners: [], + }; + m.addVisibilityListener(); + + 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/TAXI.symbol b/Nasal/canvas/map/TAXI.symbol new file mode 100644 index 000000000..d9900198e --- /dev/null +++ b/Nasal/canvas/map/TAXI.symbol @@ -0,0 +1,60 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'TAXI'; +var parents = [DotSym]; +var __self__ = caller(0)[0]; +DotSym.makeinstance( name, __self__ ); + +var element_type = "group"; # we want a group, becomes "me.element" +var rwys = nil; + +var SURFACECOLORS = { + 1 : { type: "asphalt", r:0.2, g:0.2, b:0.2 }, + 2 : { type: "concrete", r:0.3, g:0.3, b:0.3 }, + 3 : { type: "turf", r:0.2, g:0.5, b:0.2 }, + 4 : { type: "dirt", r:0.4, g:0.3, b:0.3 }, + 5 : { type: "gravel", r:0.35, g:0.3, b:0.3 }, +# Helipads + 6 : { type: "asphalt", r:0.2, g:0.2, b:0.2 }, + 7 : { type: "concrete", r:0.3, g:0.3, b:0.3 }, + 8 : { type: "turf", r:0.2, g:0.5, b:0.2 }, + 9 : { type: "dirt", r:0.4, g:0.3, b:0.3 }, + 0 : { type: "gravel", r:0.35, g:0.3, b:0.3 }, +}; + +var init = func { + var apt=airportinfo(me.model.id); + foreach (var taxi; apt.taxiways) + { + var clr = me.style.surface_color[taxi.surface]; + if (clr == nil) { clr = SURFACECOLORS[taxi.surface]}; + if (clr == nil) { clr = SURFACECOLORS[0]}; + + var taxi_paths = + me.element.createChild("path", "runway-" ~ taxi.id) + .setStrokeLineWidth(0.5) + .setColor(clr.r, clr.g, clr.b) + .setColorFill(clr.r, clr.g, clr.b); + + var txi = Runway.new(taxi); + var beg1 = txi.pointOffCenterline(0, 0.5 * taxi.width); + var beg2 = txi.pointOffCenterline(0, -0.5 * taxi.width); + var end1 = txi.pointOffCenterline(taxi.length, 0.5 * taxi.width); + var end2 = txi.pointOffCenterline(taxi.length, -0.5 * taxi.width); + + taxi_paths.setColorFill(clr.r, clr.g, clr.b) + .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 ], + [ beg1[0], beg1[1], + beg2[0], beg2[1], + end2[0], end2[1], + end1[0], end1[1] ] + ); + } +}; +var draw = func; diff --git a/Nasal/canvas/map/TWR.lcontroller b/Nasal/canvas/map/TWR.lcontroller new file mode 100644 index 000000000..44346e697 --- /dev/null +++ b/Nasal/canvas/map/TWR.lcontroller @@ -0,0 +1,42 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'TWR'; +var parents = [SymbolLayer.Controller]; +var __self__ = caller(0)[0]; +SymbolLayer.Controller.add(name, __self__); +SymbolLayer.add(name, { + parents: [MultiSymbolLayer], + type: name, # Symbol type + df_controller: __self__, # controller to use by default -- this one + df_style: { + color: { r:0.2, g:0.2, b:1.2 }, + line_width: 1, + }, + df_options: { # default configuration options + disable_position: 1, + }, +}); +var a_instance = nil; +var new = func(layer) { + var m = { + parents: [__self__], + layer: layer, + map: layer.map, + listeners: [], + }; + m.addVisibilityListener(); + + 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/TWR.symbol b/Nasal/canvas/map/TWR.symbol new file mode 100644 index 000000000..24cba5412 --- /dev/null +++ b/Nasal/canvas/map/TWR.symbol @@ -0,0 +1,31 @@ +# See: http://wiki.flightgear.org/MapStructure +# Class things: +var name = 'TWR'; +var parents = [DotSym]; +var __self__ = caller(0)[0]; +DotSym.makeinstance( name, __self__ ); + +var element_type = "group"; # we want a group, becomes "me.element" + +var init = func { + var apt=airportinfo(me.model.id); + + var clr = me.style.color; + var line_width = me.style.line_width; + + + var icon_tower = + me.element.createChild("path", "tower") + .setStrokeLineWidth(line_width) + .setScale(1.5) + .setColor(clr.r, clr.g, clr.b) + .moveTo(-3, 0) + .vert(-10) + .line(-3, -10) + .horiz(12) + .line(-3, 10) + .vert(10); + + icon_tower.setGeoPosition(apt.tower().lat, apt.tower().lon); +}; +var draw = func; diff --git a/Nasal/canvas/map/staticpos.controller b/Nasal/canvas/map/staticpos.controller new file mode 100644 index 000000000..b46cf18f1 --- /dev/null +++ b/Nasal/canvas/map/staticpos.controller @@ -0,0 +1,74 @@ +# Class things: +var parents = [Map.Controller]; +var __self__ = caller(0)[0]; +Map.Controller.add("Static position", __self__); +#Map.df_controller = __self__; + +## +# A controller to handle static updates of position, for example an airport +# diagram or non-moving map. +# +# Note that in contrast to the Aircraft Controllers, update_pos() or +# update_layers() must be called explicitly to trigger an update of the map. +## + +var new = func(map, source='main') { + var m = { + parents: [__self__], + map: map, + _pos: nil, _time: nil, _range: nil, + _alt: 0, _hdg: 0, + }; + m._pos = geo.Coord.new(); + m._pos.set_latlon(0.0,0.0); + m.update_pos(); + return m; +}; + +var del = func(map) { + if (map != me.map) die(); +}; + +var setHeading = func(hdg) { me._hdg = hdg; }; +var setAltitude = func(alt) { me._alt = alt; }; +var getHeading = func() { return me._hdg; }; +var getAltitude = func() { return me._alt; }; +var setPosition = func(lat, lon) { + me._pos.set_latlon(lat, lon); + me.update_pos(); +}; + +var applyOffset = func(x, y) { + # Apply an offset in screen coordinates, e.g. from a mouse event + var crs = 0.0; + if (x != 0.0) { + # Calculate course in degrees + crs = 90.0 + 180.0 / math.pi * math.atan(y/x); + if (x < 0.0 ) crs = crs + 180.0; + } else { + if (y < 0.0) crs = 0.0; + if (y > 0.0) crs = 180.0 + } + + # Screen resolution m/pixel is range/screen_range + var screen_range = me.map.getScreenRange() or 200; + var screen_resolution = me.map.getRange() * globals.NM2M / screen_range; + me._pos.apply_course_distance(crs, math.sqrt(x*x + y*y) * screen_resolution); + me.update_pos(); +}; + +# Controller methods +var update_pos = func { + me.map.setPos(lat: me._pos.lat(), lon: me._pos.lon(), + hdg: me._hdg,, + alt: me._alt,); + me.map.update(); +}; + +var update_layers = func { + me.map.update(); +}; + +var get_position = func { + return [ me._pos.lat(), me._pos.lon() ]; +} diff --git a/gui/dialogs/airports.xml b/gui/dialogs/airports.xml index a6a5c7e21..26fa2f308 100644 --- a/gui/dialogs/airports.xml +++ b/gui/dialogs/airports.xml @@ -42,15 +42,16 @@ var MAX_RUNWAYS = 28; # number of entries at KEDW var DIALOG = cmdarg(); + var listeners = []; ## "prologue" currently required by the canvas-generic-map var dialog_name ="airports"; #TODO: use substr() and cmdarg() to get this dynamically var dialog_property = func(p) return "/sim/gui/dialogs/airports/"~p; #TODO: generalize using cmdarg var DIALOG_CANVAS = gui.findElementByName(DIALOG, "airport-selection"); - canvas.GenericMap.setupGUI(DIALOG_CANVAS, "canvas-control"); #TODO: this is not a method! - ## end of canvas-generic-map prologue + setprop("/sim/gui/dialogs/airports/selected-airport/lat", 0); + setprop("/sim/gui/dialogs/airports/selected-airport/lon", 0); setprop("/sim/gui/dialogs/airports/selected-airport/rwy", ""); setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", ""); setprop("/sim/gui/dialogs/airports/mode", "search"); @@ -115,9 +116,11 @@ setprop("/sim/gui/dialogs/airports/selected-airport/name", info.name); setprop("/sim/gui/dialogs/airports/selected-airport/location", sprintf("%.3f / %.3f", info.lat, info.lon)); setprop("/sim/gui/dialogs/airports/selected-airport/lon", info.lon); + setprop("/sim/gui/dialogs/airports/selected-airport/lat", info.lat); setprop("/sim/gui/dialogs/airports/selected-airport/elevation-ft", 3.28 * info.elevation); setprop("/sim/gui/dialogs/airports/selected-airport/rwy", ""); setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", ""); + AirportChart.getController().setPosition(info.lat, info.lon); if (info.has_metar) { # Retrieve an updated METAR, and indicate that we've not got one currently. @@ -247,11 +250,15 @@ canvas.register_callback(update_info); # FIXME: this is a workaround to run dialog-specific code in the canvas block ]]> - + + #map.cleanup_listeners(); #TODO: We should be setting a signal when closing the dialog, so that cleanup code can be invoked automatically + AirportChart.del(); + foreach (var l; listeners) + removelistener(l); + setsize(listeners, 0); + ]]> @@ -648,86 +655,236 @@ 1 - - - + + canvas-map + fill + fill + true + 600 + 400 + airport-selection - fill - fill - true - 400 - 400 + # Initialize the controller: + AirportChart.setController("Static position", "main"); + var controller = AirportChart.getController(); - - - - - - /sim/gui/dialogs/airports - zoom + # Initialize a range and screen resolution. Setting a range + # to 4nm means we pick up a good set of surrounding fixes + # We will use the screen range for zooming. If we use range + # then as we zoom in the airport center goes out of range + # and all the runways disappear. + AirportChart.setRange(4.0); + AirportChart.setScreenRange(500); - + var range_step = 1.5; - - 0.1 - 0.25 - 0.5 - 1 - 2.5 - 5 - + # Center the map's origin: FIXME: move to api.nas, i.e. allow maps to have a size/view that differs from the actual canvas ?? + AirportChart.setTranslation( + myCanvas.get("view[0]")/2, + myCanvas.get("view[1]")/2 + ); - + ## + # Styling: This is a bit crude at the moment, i.e. no dedicated APIs yet - but it's + # just there to prototype things for now + var Styles = {}; + Styles.get = func(type) return Styles[type]; + var Options = {}; + Options.get = func(type) return Options[type]; - - runways - selected-airport/id - display-runways - Show Runways - enabled - true - - - taxiways - selected-airport/id - display-taxiways - Show Taxiways - enabled - + ## set up a few keys supported by the DME.symbol file to customize appearance: + Styles.DME = {}; + Styles.DME.debug = 1; # HACK for benchmarking/debugging purposes + Styles.DME.animation_test = 0; # for prototyping animated symbols - - parkings - selected-airport/id - display-parking - Show Parking - disabled - + Styles.DME.scale_factor = 0.4; # 40% (applied to whole group) + Styles.DME.line_width = 3.0; + Styles.DME.color_tuned = [0,1,0]; #rgb + Styles.DME.color_default = [1,1,0]; #rgb - - towers - selected-airport/id - display-tower - Show Tower - enabled - - + Styles.APT = {}; + Styles.APT.scale_factor = 0.4; # 40% (applied to whole group) + Styles.APT.line_width = 3.0; + Styles.APT.color_default = [0,0.6,0.85]; #rgb + Styles.APT.label_font_color = Styles.APT.color_default; + Styles.APT.label_font_size=28; - + Styles.PARKING = {}; + Styles.PARKING.scale_factor = 0.4; # 40% (applied to whole group) + Styles.PARKING.line_width = 3.0; + Styles.PARKING.color_default = [0,0.85,0.6]; #rgb + Styles.PARKING.label_font_color = Styles.APT.color_default; + Styles.PARKING.label_font_size=28; + + Styles.FLT = {}; + Styles.FLT.line_width = 3; + + Styles.FIX = {}; + Styles.FIX.color = [1,0,0]; + Styles.FIX.scale_factor = 0.4; # 40% + + Styles.VOR = {}; + Styles.VOR.range_line_width = 2; + Styles.VOR.radial_line_width = 1; + Styles.VOR.scale_factor = 0.6; # 60% + + var ToggleLayerVisible = func(name) { + (var l = AirportChart.getLayer(name)).setVisible(l.getVisible()); + }; + var SetLayerVisible = func(name,n=1) { + AirportChart.getLayer(name).setVisible(n); + }; + + Styles.APS = {}; + Styles.APS.scale_factor = 0.25; + + var r = func(name,vis=1,zindex=nil) return caller(0)[0]; + # TODO: we'll need some z-indexing here, right now it's in the layer order + foreach(var type; [r('TAXI',1,0),r('RWY',1,1),r('TWR',1,2),r('DME',0,3),r('VOR',0,4),r('NDB',0,5),r('FIX',0,6),r('PARKING',0,7)] ) { + AirportChart.addLayer(factory: canvas.SymbolLayer, type_arg: type.name, + visible: type.vis, priority: 4, + style: Styles.get(type.name), + options: Options.get(type.name) ); + (func { + # Notify MapStructure about layer visibility changes: + var name = type.name; + props.globals.initNode("/sim/gui/dialogs/map-canvas/draw-"~name, type.vis, "BOOL"); + append(listeners, + setlistener("/sim/gui/dialogs/map-canvas/draw-"~name, + func(n) SetLayerVisible(name,n.getValue())) + ); + + + })(); + } + + # Add some event listeners to handle mouse interactions + myCanvas.addEventListener("drag", func(e) + { + (func { + controller.applyOffset(-e.deltaX, -e.deltaY); })(); + }); + + myCanvas.addEventListener("click", func(e) + { + (func { + controller.applyOffset(e.localX - myCanvas.get("view[0]")/2, + e.localY - myCanvas.get("view[1]")/2); })(); + }); + + myCanvas.addEventListener("wheel", func(e) + { + var range = AirportChart.getScreenRange(); + if (e.deltaY >0) { + if (range < 10000) + AirportChart.setScreenRange(range*range_step); + } else { + if (range > 100) + AirportChart.setScreenRange(range/range_step); + } + setprop("/sim/gui/dialogs/airports/zoom-range", AirportChart.getScreenRange()); + }); + + if ((getprop("/sim/gui/dialogs/airports/selected-airport/lat") != nil) and + (getprop("/sim/gui/dialogs/airports/selected-airport/lon") != nil) ) + { + # If we've got some values from a previous instantiation of the dialog + # then use them to display the correct position, consistent with the + # rest of the dialog. + AirportChart.getController().setPosition( + getprop("/sim/gui/dialogs/airports/selected-airport/lat"), + getprop("/sim/gui/dialogs/airports/selected-airport/lon")); + } + ]]> - canvas-control hbox + + + + left + /sim/gui/dialogs/map-canvas/draw-DME + true + + property-toggle + + + nasal + + + dialog-apply + + + + + + + left + /sim/gui/dialogs/map-canvas/draw-PARKING + true + + dialog-apply + + + property-toggle + + + + 1 + + + + + zoomdisplay + + Zoom %d + /sim/gui/dialogs/airports/zoom-range + true + + + +