2018-03-04 20:02:16 +00:00
|
|
|
# Copyright 2018 Stuart Buchanan
|
|
|
|
# This file is part of FlightGear.
|
|
|
|
#
|
|
|
|
# FlightGear is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# FlightGear is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
# Common Navigation map functions
|
|
|
|
var NavMap = {
|
|
|
|
|
|
|
|
# Declutter levels.
|
|
|
|
DCLTR : [ "DCLTR", "DCLTR-1", "DCLTR-2", "DCLTR-3"],
|
|
|
|
|
|
|
|
# Airways levels.
|
|
|
|
AIRWAYS : [ "AIRWAYS", "AIRWY ON", "AIRWY LO", "AIRWY HI"],
|
|
|
|
|
2018-04-07 12:23:26 +00:00
|
|
|
# Lazy-loading - only create the map element when the page becomes visible,
|
|
|
|
# and delete afterwards.
|
|
|
|
LAZY_LOADING : 1,
|
|
|
|
|
2018-03-17 22:04:41 +00:00
|
|
|
new : func(page, element, center, clip="", zindex=0, vis_shift=0, static=0 )
|
2018-03-04 20:02:16 +00:00
|
|
|
{
|
|
|
|
var obj = {
|
|
|
|
parents : [ NavMap ],
|
|
|
|
_group : page.getGroup(),
|
|
|
|
_svg : page.getSVG(),
|
|
|
|
_page : page,
|
|
|
|
_pageName : page.getPageName(),
|
2018-04-07 12:23:26 +00:00
|
|
|
_element : element,
|
|
|
|
_center : center,
|
|
|
|
_clip : clip,
|
|
|
|
_zindex : zindex,
|
|
|
|
_vis_shift : vis_shift,
|
|
|
|
_static : static,
|
|
|
|
_current_zoom : 13,
|
|
|
|
_declutter : 0,
|
|
|
|
_airways : 0,
|
|
|
|
_map : nil,
|
2018-03-04 20:02:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
element.setTranslation(center[0], center[1]);
|
|
|
|
|
|
|
|
obj.Styles = fg1000.NavigationMapStyles.new();
|
|
|
|
obj.Options = fg1000.NavigationMapOptions.new();
|
|
|
|
|
|
|
|
obj._rangeDisplay = obj._svg.getElementById(obj._pageName ~ "RangeDisplay");
|
|
|
|
if (obj._rangeDisplay == nil) die("Unable to find element " ~ obj._pageName ~ "RangeDisplay");
|
|
|
|
|
|
|
|
obj._orientationDisplay = obj._svg.getElementById(obj._pageName ~ "OrientationDisplay");
|
|
|
|
if (obj._orientationDisplay == nil) die("Unable to find element " ~ obj._pageName ~ "OrientationDisplay");
|
|
|
|
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING == 0) {
|
|
|
|
obj.createMapElement();
|
|
|
|
obj._map.setVisible(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
},
|
|
|
|
|
|
|
|
# Create the map element itself. Depending on whether we are doing lazy loading
|
|
|
|
# or not, this may be called by the constructor, or when the NavMap is made visible.
|
|
|
|
createMapElement : func() {
|
|
|
|
|
|
|
|
if (me._map != nil) return;
|
|
|
|
|
|
|
|
me._map = me._element.createChild("map");
|
|
|
|
me._map.setScreenRange(689/2.0);
|
|
|
|
|
2018-03-04 20:02:16 +00:00
|
|
|
# Initialize the controllers:
|
2018-04-07 12:23:26 +00:00
|
|
|
if (me._static) {
|
|
|
|
me._map.setController("Static position", "main");
|
2018-03-17 22:04:41 +00:00
|
|
|
} else {
|
|
|
|
var ctrl_ns = canvas.Map.Controller.get("Aircraft position");
|
|
|
|
var source = ctrl_ns.SOURCES["current-pos"];
|
|
|
|
if (source == nil) {
|
2018-04-07 12:23:26 +00:00
|
|
|
# TODO: amend
|
|
|
|
var source = ctrl_ns.SOURCES["current-pos"] = {
|
|
|
|
getPosition: func subvec(geo.aircraft_position().latlon(), 0, 2),
|
|
|
|
getAltitude: func getprop('/position/altitude-ft'),
|
|
|
|
getHeading: func {
|
|
|
|
if (me.aircraft_heading)
|
|
|
|
getprop('/orientation/heading-deg')
|
|
|
|
else 0
|
|
|
|
},
|
|
|
|
aircraft_heading: 1,
|
|
|
|
};
|
|
|
|
setlistener("/sim/gui/dialogs/map-canvas/aircraft-heading-up", func(n) {
|
|
|
|
source.aircraft_heading = n.getBoolValue();
|
|
|
|
}, 1);
|
2018-03-17 22:04:41 +00:00
|
|
|
}
|
|
|
|
# Make it move with our aircraft:
|
2018-04-07 12:23:26 +00:00
|
|
|
me._map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
|
2018-03-04 20:02:16 +00:00
|
|
|
}
|
|
|
|
|
2018-04-07 12:23:26 +00:00
|
|
|
if (me._clip != "") {
|
|
|
|
me._map.set("clip-frame", canvas.Element.LOCAL);
|
|
|
|
me._map.set("clip", me._clip);
|
2018-03-04 20:02:16 +00:00
|
|
|
}
|
|
|
|
|
2018-04-07 12:23:26 +00:00
|
|
|
if (me._zindex != 0) {
|
|
|
|
me._element.setInt("z-index", me._zindex);
|
2018-03-04 20:02:16 +00:00
|
|
|
}
|
|
|
|
|
2018-03-17 22:04:41 +00:00
|
|
|
var r = func(name,on_static=1, vis=1,zindex=nil) return caller(0)[0];
|
2018-03-04 20:02:16 +00:00
|
|
|
# TODO: we'll need some z-indexing here, right now it's just random
|
2018-04-07 12:23:26 +00:00
|
|
|
foreach (var layer_name; me._page.mfd.ConfigStore.getLayerNames()) {
|
|
|
|
var layer = me._page.mfd.ConfigStore.getLayer(layer_name);
|
2018-03-04 20:02:16 +00:00
|
|
|
|
2018-04-07 12:23:26 +00:00
|
|
|
if ((me._static == 0) or (layer.static == 1)) {
|
2018-03-17 22:04:41 +00:00
|
|
|
# Not all layers are displayed for all map types. Specifically,
|
|
|
|
# some layers are not displayed on static maps - e.g. DirectTo
|
2018-04-07 12:23:26 +00:00
|
|
|
me._map.addLayer(
|
2018-03-17 22:04:41 +00:00
|
|
|
factory: layer.factory,
|
|
|
|
type_arg: layer_name,
|
|
|
|
priority: layer.priority,
|
2018-04-07 12:23:26 +00:00
|
|
|
style: me.Styles.getStyle(layer_name),
|
|
|
|
options: me.Options.getOption(layer_name),
|
2018-03-04 20:02:16 +00:00
|
|
|
visible: 0);
|
2018-03-17 22:04:41 +00:00
|
|
|
}
|
2018-03-04 20:02:16 +00:00
|
|
|
}
|
|
|
|
|
2018-04-07 12:23:26 +00:00
|
|
|
me.setZoom(me._current_zoom);
|
|
|
|
me.setOrientation(0);
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
2018-03-17 22:04:41 +00:00
|
|
|
setController : func(type, controller ) {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-04-06 18:52:18 +00:00
|
|
|
me._map.setController(type, controller);
|
2018-03-17 22:04:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
getController : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-04-06 18:52:18 +00:00
|
|
|
return me._map.getController();
|
2018-03-17 22:04:41 +00:00
|
|
|
},
|
|
|
|
|
2018-03-04 20:02:16 +00:00
|
|
|
toggleLayerVisible : func(name) {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
|
|
|
(var l = me._map.getLayer(name)).setVisible(l.getVisible());
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
setLayerVisible : func(name,n=1) {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
|
|
|
me._map.getLayer(name).setVisible(n);
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
setOrientation : func(orientation) {
|
|
|
|
# TODO - implment this
|
|
|
|
me._orientationDisplay.setText(fg1000.ORIENTATIONS[orientation].label);
|
|
|
|
},
|
|
|
|
|
|
|
|
setScreenRange : func(range) {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-04-06 18:52:18 +00:00
|
|
|
me._map.setScreenRange(range);
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
zoomIn : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
me.setZoom(me._current_zoom -1);
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
zoomOut : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
me.setZoom(me._current_zoom +1);
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
setZoom : func(zoom) {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-03-04 20:02:16 +00:00
|
|
|
if ((zoom < 0) or (zoom > (size(fg1000.RANGES) - 1))) return;
|
2018-04-07 12:23:26 +00:00
|
|
|
me._current_zoom = zoom;
|
2018-04-06 18:52:18 +00:00
|
|
|
me._rangeDisplay.setText(fg1000.RANGES[zoom].label);
|
|
|
|
me._map.setRange(fg1000.RANGES[zoom].range);
|
2018-03-04 20:02:16 +00:00
|
|
|
me.updateVisibility();
|
|
|
|
},
|
|
|
|
|
|
|
|
updateVisibility : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-03-04 20:02:16 +00:00
|
|
|
# Determine which layers should be visible.
|
|
|
|
foreach (var layer_name; me._page.mfd.ConfigStore.getLayerNames()) {
|
|
|
|
var layer = me._page.mfd.ConfigStore.getLayer(layer_name);
|
|
|
|
|
2018-04-06 18:52:18 +00:00
|
|
|
if (me._map.getLayer(layer_name) == nil) continue;
|
2018-03-17 22:04:41 +00:00
|
|
|
|
2018-03-04 20:02:16 +00:00
|
|
|
# Layers are only displayed if:
|
|
|
|
# 1) the user has enabled them.
|
|
|
|
# 2) The current zoom level is _less_ than the maximum range for the layer
|
|
|
|
# (i.e. as the range gets larger, we remove layers). Note that for
|
|
|
|
# inset maps, the range that items are removed is lower.
|
|
|
|
# 3) They haven't been removed due to the declutter level.
|
2018-04-07 12:23:26 +00:00
|
|
|
var effective_zoom = math.clamp(me._current_zoom + me._vis_shift, 0, size(fg1000.RANGES) -1);
|
2018-03-04 20:02:16 +00:00
|
|
|
var effective_range = fg1000.RANGES[effective_zoom].range;
|
|
|
|
if (layer.enabled and
|
|
|
|
(effective_range <= layer.range) and
|
2018-04-07 12:23:26 +00:00
|
|
|
(me._declutter <= layer.declutter) )
|
2018-03-04 20:02:16 +00:00
|
|
|
{
|
2018-04-06 18:52:18 +00:00
|
|
|
me._map.getLayer(layer_name).setVisible(1);
|
2018-03-04 20:02:16 +00:00
|
|
|
} else {
|
2018-04-06 18:52:18 +00:00
|
|
|
me._map.getLayer(layer_name).setVisible(0);
|
2018-03-04 20:02:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
isEnabled : func(layer) {
|
|
|
|
return me._page.mfd.ConfigStore.isLayerEnabled(layer);
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleLayer : func(layer) {
|
|
|
|
me._page.mfd.ConfigStore.toggleLayerEnabled(layer);
|
|
|
|
me.updateVisibility();
|
|
|
|
},
|
|
|
|
|
|
|
|
# Increment through the de-clutter levels, which impact what layers are
|
|
|
|
# displayed. We also need to update the declutter menu item.
|
|
|
|
incrDCLTR : func(device, menuItem) {
|
2018-04-07 12:23:26 +00:00
|
|
|
me._declutter = math.mod(me._declutter +1, 4);
|
2018-03-04 20:02:16 +00:00
|
|
|
me.updateVisibility();
|
2018-04-07 12:23:26 +00:00
|
|
|
return me.DCLTR[me._declutter];
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
getDCLTRTitle : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
return me.DCLTR[me._declutter];
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
# Increment through the AIRWAYS levels. At present this doesn't do anything
|
|
|
|
# except change the label. It should enable/disable different airways
|
|
|
|
# information.
|
|
|
|
incrAIRWAYS : func(device, menuItem) {
|
2018-04-07 12:23:26 +00:00
|
|
|
me._airways = math.mod(me._airways +1, 4);
|
2018-03-04 20:02:16 +00:00
|
|
|
me.updateVisibility();
|
2018-04-07 12:23:26 +00:00
|
|
|
return me.AIRWAYS[me._airways];
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
getAIRWAYSTitle : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
return me.AIRWAYS[me._airways];
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
# Set the DTO line target
|
|
|
|
setDTOLineTarget : func(lat, lon) {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-04-06 18:52:18 +00:00
|
|
|
me._map.getLayer("DTO").controller.setTarget(lat,lon);
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
enableDTO : func(enable) {
|
|
|
|
me._page.mfd.ConfigStore.setLayerEnabled("DTO", enable);
|
|
|
|
me.updateVisibility();
|
|
|
|
},
|
|
|
|
|
|
|
|
handleRange : func(val)
|
|
|
|
{
|
2020-02-29 19:23:51 +00:00
|
|
|
if (val >0) {
|
|
|
|
me.zoomOut();
|
|
|
|
} else {
|
|
|
|
me.zoomIn();
|
|
|
|
}
|
2019-02-10 22:06:31 +00:00
|
|
|
return emesary.Transmitter.ReceiptStatus_OK;
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
getMap : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-04-06 18:52:18 +00:00
|
|
|
return me._map;
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
show : func() {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
2018-04-06 18:52:18 +00:00
|
|
|
me._map.show();
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
hide : func() {
|
2018-04-15 18:44:10 +00:00
|
|
|
if (me._map != nil) me._map.hide();
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me._map = nil;
|
2018-03-04 20:02:16 +00:00
|
|
|
},
|
|
|
|
setVisible : func(visible) {
|
2018-04-07 12:23:26 +00:00
|
|
|
if (visible) {
|
|
|
|
if (NavMap.LAZY_LOADING) me.createMapElement();
|
|
|
|
me._map.setVisible(visible);
|
|
|
|
} else {
|
2018-04-15 18:44:10 +00:00
|
|
|
if (me._map != nil) me._map.setVisible(visible);
|
2018-04-07 12:23:26 +00:00
|
|
|
if (NavMap.LAZY_LOADING) me._map = nil;
|
|
|
|
}
|
|
|
|
},
|
2018-03-04 20:02:16 +00:00
|
|
|
};
|