zkv1000 / Nasal / map.nas /
Newer Older
240 lines | 8.91kb
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
1
# vim: set foldmethod=marker foldmarker={{{,}}} :
2
var MapTiles = {
3
# code from http://wiki.flightgear.org/Canvas_Snippets#A_simple_tile_map
4
    new : func (display) {
5
        var m = { parents: [MapTiles] };
6
        m.display = display;
7
        m.tile_size = 256;
8
        m.zoom = 10;
9
        m.maps_base = getprop("/sim/fg-home") ~ '/cache/maps';
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
10
        m.makeUrl = string.compileTemplate('https://{server}/{type}/{z}/{x}/{y}.png{apikey}');
11
        m.makePath = string.compileTemplate(m.maps_base ~ '/{server}/{type}/{z}/{x}/{y}.png');
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
12
        m.num_tiles = [
13
            math.ceil( m.display.get('view[0]') / m.tile_size ) + 1, 
14
            math.ceil( m.display.get('view[1]') / m.tile_size ) + 1
15
        ];
16
        m.center_tile_offset = [
17
            (m.num_tiles[0] - 1) / 2,
18
            (m.num_tiles[1] - 1) / 2
19
        ];
maps centered by group (for ...
Sébastien MARQUE authored on 2017-04-13
20
        m.group = m.display.createGroup()
21
            .setCenter(
22
                    m.display.get('view[0]') / 2,
23
                    m.display.get('view[1]') / 2
24
            );
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
25
        m.tiles = setsize([], m.num_tiles[0]);
26
        m.last_tile = [-1,-1];
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
27
        m.last_type = data['tiles-type'];
smoother map moves
Sébastien MARQUE authored on 2017-04-13
28
        m.update_timer = maketimer(1, m, m.updateTiles);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
29
        return m;
30
    },
31

            
32
# Simple user interface (Buttons for zoom and label for displaying it)
33
    changeZoom : func(d) {
34
        me.zoom = math.max(2, math.min(19, me.zoom + d));
35
        call(me.updateTiles, [], me);
36
    },
37

            
38
# initialize the map by setting up a grid of raster images  
39
    initialize_grid : func {
40
        for(var x = 0; x < me.num_tiles[0]; x += 1) {
41
            me.tiles[x] = setsize([], me.num_tiles[1]);
42
            for(var y = 0; y < me.num_tiles[1]; y += 1)
43
                me.tiles[x][y] = me.group.createChild("image", "map-tile");
44
        }
45
    },
46

            
47
# this is the callback that will be regularly called by the timer to update the map
48
    updateTiles : func() {
put lat/lon in global data s...
Sébastien MARQUE authored on 2017-04-12
49
#        me.group.setRotation(-data.hdg * D2R);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
50

            
51
        var n = math.pow(2, me.zoom);
52
        var offset = [
put lat/lon in global data s...
Sébastien MARQUE authored on 2017-04-12
53
            n * ((data.lon + 180) / 360) - me.center_tile_offset[0],
54
            (1 - math.ln(math.tan(data.lat * math.pi/180) + 1 / math.cos(data.lat * math.pi/180)) / math.pi) / 2 * n - me.center_tile_offset[1]
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
55
        ];
56
        var tile_index = [int(offset[0]), int(offset[1])];
57

            
58
        var ox = tile_index[0] - offset[0];
59
        var oy = tile_index[1] - offset[1];
60

            
61
        for(var x = 0; x < me.num_tiles[0]; x += 1)
62
            for(var y = 0; y < me.num_tiles[1]; y += 1)
63
                me.tiles[x][y]
64
                    .setTranslation(int((ox + x) * me.tile_size + 0.5), int((oy + y) * me.tile_size + 0.5));
65

            
66
        if(    tile_index[0] != me.last_tile[0]
67
                or tile_index[1] != me.last_tile[1]
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
68
                or data['tiles-type'] != me.last_type ) {
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
69
            for(var x = 0; x < me.num_tiles[0]; x += 1)
70
                for(var y = 0; y < me.num_tiles[1]; y += 1) {
71
                    var pos = {
72
                        z: me.zoom,
73
                        x: int(offset[0] + x),
74
                        y: int(offset[1] + y),
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
75
                        type: data['tiles-type'],
76
                        server : data['tiles-server'],
77
                        apikey: data['tiles-apikey'],
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
78
                    };
79

            
80
                    (func {
81
                        var img_path = me.makePath(pos);
82
                        printlog('debug', 'img_path: ', img_path);
83
                        var tile = me.tiles[x][y];
84

            
85
                        if( io.stat(img_path) == nil ) { # image not found, save in $FG_HOME
86
                            var img_url = me.makeUrl(pos);
87
                            printlog('debug', 'requesting ' ~ img_url);
88
                            http.save(img_url, img_path)
89
                                .done(func {printlog('info', 'received image ' ~ img_path); tile.set("src", img_path);})
90
                                .fail(func (r) printlog('warn', 'Failed to get image ' ~ img_path ~ ' ' ~ r.status ~ ': ' ~ r.reason));
91
                        }
92
                        else { # cached image found, reusing
93
                            printlog('debug', 'loading ' ~ img_path);
94
                            tile.set("src", img_path);
95
                        }
96
                    })();
97
                }
98
            me.last_tile = tile_index;
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
99
            me.last_type = data['tiles-type'];
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
100
        }
101
    },
102

            
103
    del : func() {
104
        me.update_timer.stop();
105
        call(canvas.Window.del, [], me);
106
    },
107
};
108

            
109
var MapNavDisplay = {
110
    new : func (display) {
111
        var m = { parents: [MapNavDisplay] };
112
        m.display = display;
113
        m.map = m.display.createGroup().createChild('map');
114
        m.ctrl_ns = canvas.Map.Controller.get("Aircraft position");
115
        m.ctrl_ns.SOURCES["map-dialog"] = {
116
            getPosition: func subvec(geo.aircraft_position().latlon(), 0, 2),
117
            getAltitude: func getprop('/position/altitude-ft'),
118
            getHeading:  func {
119
                if (me.aircraft_heading)
120
                    getprop('/orientation/heading-deg')
121
                else 0
122
            },
no heading up for maps by de...
Sébastien MARQUE authored on 2017-04-13
123
            aircraft_heading: 0,
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
124
        };
125

            
126
        m.Styles = {
127
            get : func(type) return m.Styles[type],
128
        };
129

            
130
        m.Options = {
131
            get : func(type) return m.Options[type],
132
        };
133

            
134
        m.listeners = [];
135

            
136
        return m;
137
    },
138

            
139
    showMap : func {
140
        me.setMap();
141
        me.setStyles();
142
        me.setOptions();
143
        me.refresh();
144
    },
145

            
146
    setMap : func {
147
        var source = me.ctrl_ns.SOURCES["map-dialog"];
148
        me.map.setController("Aircraft position", "map-dialog");
149
        me.map.setRange(40);
150
        me.map.setTranslation(
151
            me.display.get("view[0]")/2,
152
            me.display.get("view[1]")/2
153
        );
154
    },
155

            
156
    setStyles : func {
157
## set up a few keys supported by the DME.symbol file to customize appearance: {{{
158
        me.Styles.DME = {};
159
        me.Styles.DME.debug = 1; # HACK for benchmarking/debugging purposes
160
        me.Styles.DME.animation_test = 0; # for prototyping animated symbols
161

            
162
        me.Styles.DME.scale_factor = 0.4; # 40% (applied to whole group)
163
        me.Styles.DME.line_width = 3.0;
164
        me.Styles.DME.color_tuned = [0,1,0]; #rgb
165
        me.Styles.DME.color_default = [1,1,0];  #rgb
166

            
167
        me.Styles.APT = {};
168
        me.Styles.APT.scale_factor = 0.4; # 40% (applied to whole group)
169
        me.Styles.APT.line_width = 3.0;
170
        me.Styles.APT.color_default = [0,0.6,0.85];  #rgb
171
        me.Styles.APT.label_font_color = me.Styles.APT.color_default;
172
        me.Styles.APT.label_font_size=16;
173

            
174
        me.Styles.TFC = {};
175
        me.Styles.TFC.scale_factor = 0.4; # 40% (applied to whole group)
176

            
177
        me.Styles.WPT = {};
178
        me.Styles.WPT.scale_factor = 0.5; # 50% (applied to whole group)
179

            
180
        me.Styles.RTE = {};
181
        me.Styles.RTE.line_width = 2;
182

            
183
        me.Styles.FLT = {};
184
        me.Styles.FLT.line_width = 3;
185

            
186
        me.Styles.FIX = {};
187
        me.Styles.FIX.color = [1,0,0];
188
        me.Styles.FIX.scale_factor = 0.4; # 40%
189

            
190
        me.Styles.VOR = {};
191
        me.Styles.VOR.range_line_width = 2;
192
        me.Styles.VOR.radial_line_width = 1;
193
        me.Styles.VOR.scale_factor = 0.6; # 60%
194

            
195
        me.Styles.APS = {};
196
        me.Styles.APS.scale_factor = 0.5;
197
    },
198
#}}}
199

            
200
    setOptions : func {
201
        me.Options.FLT = {};
202
    },
203

            
204
    make_update_wrapper : func(name) {
205
        if (!contains(me.Options, name)) me.Options[name] = {};
206
        me.Options[name].update_wrapper = func(layer, fn) {
207
            fn();
commit initial
Sébastien MARQUE authored on 2017-03-07
208
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
209
    },
210

            
211
    ToggleLayerVisible : func(name) {
212
        (var l = me.map.getLayer(name)).setVisible(l.getVisible());
213
    },
214

            
215
    SetLayerVisible : func(name,n=1) {
216
        me.map.getLayer(name).setVisible(n);
217
    },
218

            
219
    refresh : func {
220
        var r = func(name,vis=1,zindex=nil) return caller(0)[0];
221
        # TODO: we'll need some z-indexing here, right now it's just random
222
        foreach(var type; [r('TFC',0),r('APT'),r('DME'),r('VOR'),r('NDB'),r('FIX',0),r('RTE'),r('WPT'),r('FLT'),r('WXR',0),r('APS'), ] ) {
223
            if (1 and type.name != 'APS' and type.name != 'FLT') me.make_update_wrapper(type.name);
224
            me.map.addLayer(factory: canvas.SymbolLayer, type_arg: type.name,
225
                    visible: type.vis, priority: type.zindex,
226
                    style: me.Styles.get(type.name),
227
                    options: me.Options.get(type.name) 
228
                    );
229
            (func {
230
                 # Notify MapStructure about layer visibility changes:
231
                 var name = type.name;
232
                 props.globals.initNode("/sim/gui/dialogs/map-canvas/draw-"~name, type.vis, "BOOL");
233
                 append(me.listeners,
234
                         setlistener("/sim/gui/dialogs/map-canvas/draw-"~name,
235
                             func(n) me.SetLayerVisible(name,n.getValue()), 1, 2)
236
                       );
237
             })();
commit initial
Sébastien MARQUE authored on 2017-03-07
238
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
239
    },
240
};