zkv1000 / Nasal / map.nas /
Newer Older
630 lines | 22.911kb
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
1
# vim: set foldmethod=marker foldmarker={{{,}}} :
2
var MapTiles = {
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
3
# displays maps background from web tiles {{{
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
4
# code from http://wiki.flightgear.org/Canvas_Snippets#A_simple_tile_map
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
5
    new : func (device) {
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
6
        var m = { parents: [MapTiles] };
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
7
        m.device = device;
8
        m.display = m.device.display.display;
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
9
        m.tile_size = 256;
10
        m.maps_base = getprop("/sim/fg-home") ~ '/cache/maps';
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
11
        m.makeUrl = string.compileTemplate('https://{server}/{type}/{z}/{x}/{y}.png{apikey}');
12
        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
13
        m.num_tiles = [
get map display size from da...
Sébastien MARQUE authored on 2017-04-18
14
            math.ceil( m.device.data.mapsize[0] / m.tile_size ) + 1,
15
            math.ceil( m.device.data.mapsize[1] / m.tile_size ) + 1
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
16
        ];
17
        m.center_tile_offset = [
18
            (m.num_tiles[0] - 1) / 2,
19
            (m.num_tiles[1] - 1) / 2
20
        ];
maps centered by group (for ...
Sébastien MARQUE authored on 2017-04-13
21
        m.group = m.display.createGroup()
22
            .setCenter(
get map display size from da...
Sébastien MARQUE authored on 2017-04-18
23
                    m.device.data.mapsize[0] / 2 + m.device.data.mapclip.left,
24
                    m.device.data.mapsize[1] / 2 + m.device.data.mapclip.top
25
                )
26
            .setTranslation(
27
                    m.device.data.mapclip.left / 2,
28
                    m.device.data.mapclip.top / 2
29
                )
30
            .set('clip',
31
                    'rect('
32
                        ~ m.device.data.mapclip.top ~','
33
                        ~ m.device.data.mapclip.right ~','
34
                        ~ m.device.data.mapclip.bottom ~','
35
                        ~ m.device.data.mapclip.left ~')'
36
                );
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
37
        m.tiles = setsize([], m.num_tiles[0]);
38
        m.last_tile = [-1,-1];
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
39
        m.last_type = data['tiles-type'];
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
40
        return m;
41
    },
42

            
43
# Simple user interface (Buttons for zoom and label for displaying it)
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
44
    changeZoom : func (d) {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
45
        me.device.data.zoom = math.max(2, math.min(19, me.device.data.zoom + d));
46
        me.device.data['range-nm'] = me.display.get('view[1]') / 2 * 84.53 * math.cos(data.lat) / math.pow(2, me.device.data.zoom);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
47
    },
48

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
49
# initialize the map by setting up a grid of raster images
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
50
    initialize_grid : func {
51
        for(var x = 0; x < me.num_tiles[0]; x += 1) {
52
            me.tiles[x] = setsize([], me.num_tiles[1]);
53
            for(var y = 0; y < me.num_tiles[1]; y += 1)
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
54
                me.tiles[x][y] = me.group.createChild('image', 'tile ' ~ x ~ ',' ~ y);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
55
        }
56
    },
57

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

            
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
62
        var n = math.pow(2, me.device.data.zoom);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
63
        var offset = [
put lat/lon in global data s...
Sébastien MARQUE authored on 2017-04-12
64
            n * ((data.lon + 180) / 360) - me.center_tile_offset[0],
65
            (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
66
        ];
67
        var tile_index = [int(offset[0]), int(offset[1])];
68

            
69
        var ox = tile_index[0] - offset[0];
70
        var oy = tile_index[1] - offset[1];
71

            
72
        for(var x = 0; x < me.num_tiles[0]; x += 1)
73
            for(var y = 0; y < me.num_tiles[1]; y += 1)
74
                me.tiles[x][y]
75
                    .setTranslation(int((ox + x) * me.tile_size + 0.5), int((oy + y) * me.tile_size + 0.5));
76

            
77
        if(    tile_index[0] != me.last_tile[0]
78
                or tile_index[1] != me.last_tile[1]
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
79
                or data['tiles-type'] != me.last_type ) {
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
80
            for(var x = 0; x < me.num_tiles[0]; x += 1)
81
                for(var y = 0; y < me.num_tiles[1]; y += 1) {
82
                    var pos = {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
83
                        z: me.device.data.zoom,
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
84
                        x: int(offset[0] + x),
85
                        y: int(offset[1] + y),
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
86
                        type: data['tiles-type'],
87
                        server : data['tiles-server'],
88
                        apikey: data['tiles-apikey'],
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
89
                    };
90

            
91
                    (func {
92
                        var img_path = me.makePath(pos);
93
                        printlog('debug', 'img_path: ', img_path);
94
                        var tile = me.tiles[x][y];
95

            
96
                        if( io.stat(img_path) == nil ) { # image not found, save in $FG_HOME
97
                            var img_url = me.makeUrl(pos);
98
                            printlog('debug', 'requesting ' ~ img_url);
99
                            http.save(img_url, img_path)
100
                                .done(func {printlog('info', 'received image ' ~ img_path); tile.set("src", img_path);})
101
                                .fail(func (r) printlog('warn', 'Failed to get image ' ~ img_path ~ ' ' ~ r.status ~ ': ' ~ r.reason));
102
                        }
103
                        else { # cached image found, reusing
104
                            printlog('debug', 'loading ' ~ img_path);
105
                            tile.set("src", img_path);
106
                        }
107
                    })();
108
                }
109
            me.last_tile = tile_index;
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
110
            me.last_type = data['tiles-type'];
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
111
        }
112
    },
113
};
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
114
# }}}
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
115

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
116
# The following is largely inspired from the Extra500 Avidyne Entegra 9 
117
# https://gitlab.com/extra500/extra500.git
118
# Many thanks to authors: Dirk Dittmann and Eric van den Berg
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
119

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
120
var MapIconCache = {
121
# creates at init an icons cache for navaids, airports and airplane {{{
122
    new : func (svgFile) {
123
        var m = { parents:[MapIconCache] };
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
124

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
125
        m._canvas = canvas.new( {
126
            'name': 'MapIconCache',
127
            'size': [512, 512],
128
            'view': [512, 512],
129
            'mipmapping': 1
130
        });
131
        m._canvas.addPlacement( {'type': 'ref'} );
132
        m._canvas.setColorBackground(1,1,1,0);
133
        m._group = m._canvas.createGroup('MapIcons');
134

            
135
        canvas.parsesvg(m._group, data.zkv1000_reldir ~ svgFile);
136

            
137
        m._sourceRectMap = {};
138

            
139
        var icons = [ 'airplane' ];
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
140

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
141
        foreach (var near; [0, 1])
142
            foreach (var surface; [0, 1])
143
                foreach (var tower; [0, 1])
144
                    foreach (var center; tower ? [0, 1] : [ 0 ])
145
                        append(icons, 'Airport_' ~ near ~ surface ~ tower ~ center);
146

            
147
        foreach (var type; ['VOR', 'DME', 'TACAN', 'NDB'])
148
            append(icons, 'Navaid_' ~ type);
149

            
150
        foreach (var i; icons)
151
            m.registerIcon(i);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
152

            
153
        return m;
154
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
155
    registerIcon : func (id) {
156
        me._sourceRectMap[id] = {
157
            'bound' : [],
158
            'size'  : [],
159
        };
160
        var element = me._group.getElementById(id);
161
        if (element != nil) {
162
            me._sourceRectMap[id].bound = element.getTransformedBounds();
163
            # TODO ugly hack ? check for reason!
164
            var top     = 512 - me._sourceRectMap[id].bound[3];
165
            var bottom  = 512 - me._sourceRectMap[id].bound[1];
166
            me._sourceRectMap[id].bound[1] = top;
167
            me._sourceRectMap[id].bound[3] = bottom;
168

            
169
            me._sourceRectMap[id].size = [
170
                me._sourceRectMap[id].bound[2] - me._sourceRectMap[id].bound[0],
171
                me._sourceRectMap[id].bound[3] - me._sourceRectMap[id].bound[1]
172
            ];
173
        }
174
        else {
175
            print('MapIconCache.registerIcon(' ~ id ~ ') fail');
176
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
177
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
178
    getBounds : func (id) {
179
        return me._sourceRectMap[id].bound;
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
180
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
181
    getSize : func (id) {
182
        return me._sourceRectMap[id].size;
183
    },
184
    boundIconToImage : func (id, image, center=1) {
185
        if (!contains(me._sourceRectMap, id)) {
186
            print('MapIconCache.boundIconToImage('~id~') ... no available.');
187
            id = 'Airport_0001';
188
        }
189
        image.setSourceRect(
190
                me._sourceRectMap[id].bound[0],
191
                me._sourceRectMap[id].bound[1],
192
                me._sourceRectMap[id].bound[2],
193
                me._sourceRectMap[id].bound[3],
194
                0);
195
        image.setSize(
196
                me._sourceRectMap[id].size[0],
197
                me._sourceRectMap[id].size[1]);
198
        if (center) {
199
            image.setTranslation(
200
                    -me._sourceRectMap[id].size[0]/2,
201
                    -me._sourceRectMap[id].size[1]/2);
202
        }
203
    },
204
};
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
205

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
206
var mapIconCache = MapIconCache.new('Models/MapIcons.svg');
207
# }}}
208

            
209
var MapAirportItem = {
210
# manage airports items by adding the ID and runways on associated icon {{{
211
    new : func (id) {
212
        var m = {parents:[MapAirportItem]};
213
        m._id = id;
214
        m._can = {
215
            'group' : nil,
216
            'label' : nil,
217
            'image' : nil,
218
            'layout': nil,
219
            'runway': [],
220
        };
221
        m._mapAirportIcon = {
222
            'near'      : 0,
223
            'surface'   : 0,
224
            'tower'     : 0,
225
            'center'    : 0,
226
            'displayed' : 0,
227
            'icon'      : '',
228
        };
229
        return m;
230
    },
231
    create : func (group) {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
232
        me._can.group = group
233
            .createChild('group', 'airport_' ~ me._id);
234

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
235
        me._can.image = me._can.group.createChild('image', 'airport-image_' ~ me._id)
236
            .setFile(mapIconCache._canvas.getPath())
237
            .setSourceRect(0,0,0,0,0);
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
238

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
239
        me._can.label = me._can.group.createChild('text', 'airport-label_' ~ me._id)
240
            .setDrawMode( canvas.Text.TEXT )
241
            .setTranslation(0, 37)
242
            .setAlignment('center-bottom-baseline')
243
            .setFont('LiberationFonts/LiberationSans-Regular.ttf')
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
244
            .setFontSize(24);
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
245

            
nicer airport label
Sébastien MARQUE authored on 2017-04-18
246
        me._can.label.set('fill','#BACBFB');
247
        me._can.label.set('stroke','#000000');
248

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
249
        me._can.layout = group.createChild('group','airport_layout' ~ me._id);
250
        me._can.layoutIcon = group.createChild('group','airport_layout_Icon' ~ me._id);
251
        return me._can.group;
252
    },
253
    draw : func (apt, mapOptions) {
254
        me._mapAirportIcon.near = mapOptions.range > 30 ? 0 : 1;
255
        me._mapAirportIcon.surface  = 0;
256
        me._mapAirportIcon.tower    = 0;
257
        me._mapAirportIcon.center   = 0;
258
        me._mapAirportIcon.displayed    = 0;
259

            
260
        # TODO make departure and destination airports specific
261
        var aptInfo = airportinfo(apt.id);
262

            
263
        me._can.layout.removeAllChildren();
264
        me._can.layoutIcon.removeAllChildren();
265

            
266
        me._mapAirportIcon.tower = (size(aptInfo.comms('tower')) > 0);
267
        me._mapAirportIcon.center = me._mapAirportIcon.tower and (size(aptInfo.comms('approach')) > 0);
268

            
269
        foreach (var rwy; keys(aptInfo.runways)) {
270
            var runway = aptInfo.runways[rwy];
271
            me._mapAirportIcon.surface = MAP_RUNWAY_SURFACE[runway.surface] ? 1 : me._mapAirportIcon.surface;
272
            me._mapAirportIcon.displayed = runway.length > mapOptions.runwayLength ? 1 : me._mapAirportIcon.displayed;
273

            
274
            if (mapOptions.range <= 10) {    # drawing real runways
275
                me._can.layout.createChild('path', 'airport-runway-' ~ me._id ~ '-' ~ runway.id)
276
                    .setStrokeLineWidth(7)
277
                    .setColor(1,1,1)
278
                    .setColorFill(1,1,1)
279
                    .setDataGeo([
280
                        canvas.Path.VG_MOVE_TO,
281
                        canvas.Path.VG_LINE_TO,
282
                        canvas.Path.VG_CLOSE_PATH
283
                    ],[
284
                        'N' ~ runway.lat, 'E' ~ runway.lon,
285
                        'N' ~ runway.reciprocal.lat, 'E' ~ runway.reciprocal.lon,
286
                    ]);
287
            }
288
            elsif (mapOptions.range <= 30) {     #draw icon runways
289
                me._can.layoutIcon.setGeoPosition(apt.lat, apt.lon);
290
                me._can.layoutIcon.createChild('path', 'airport-runway-' ~ me._id ~ '-' ~ runway.id)
291
                    .setStrokeLineWidth(7)
292
                    .setColor(1,1,1)
293
                    .setColorFill(1,1,1)
294
                    .setData([
295
                        canvas.Path.VG_MOVE_TO,
296
                        canvas.Path.VG_LINE_TO,
297
                        canvas.Path.VG_CLOSE_PATH
298
                    ],[
299
                        0, -20,
300
                        0, 20,
301
                    ])
302
                    .setRotation((runway.heading)* D2R);
303
            }
304
        }
305
        me._mapAirportIcon.icon = 'Airport_'
306
            ~ me._mapAirportIcon.near
307
            ~ me._mapAirportIcon.surface
308
            ~ me._mapAirportIcon.tower
309
            ~ me._mapAirportIcon.center;
310

            
311
        if (me._mapAirportIcon.displayed) {
312
            me._can.label.setText(apt.id);
313
            me._can.group.setGeoPosition(apt.lat, apt.lon);
314
            if (mapOptions.range <= 10) {
315
                me._can.image.setVisible(0);
316
                me._can.layout.setVisible(1);
317
            }
318
            elsif (mapOptions.range <= 30) {
319
                mapIconCache.boundIconToImage(me._mapAirportIcon.icon, me._can.image);
320
                me._can.image.setVisible(1);
321
                me._can.layout.setVisible(1);
322
            }
323
            else {
324
                mapIconCache.boundIconToImage(me._mapAirportIcon.icon, me._can.image);
325
                me._can.layout.setVisible(0);
326
                me._can.image.setVisible(1);
327
            }
328
            me._can.group.setVisible(1);
329
        }
330
        return me._mapAirportIcon.displayed;
331
    },
332
    update : func (mapOptions) {
333
        if (mapOptions.range <= 10) { }
334
        elsif (mapOptions.range <= 30)
335
            me._can.layoutIcon.setRotation(-mapOptions.orientation * D2R);
336
        else { }
337
    },
338
    setVisible : func (visibility) {
339
        me._can.group.setVisible(visibility);
340
        me._can.layout.setVisible(visibility);
341
        me._can.image.setVisible(visibility);
342
        me._can.layoutIcon.setVisible(visibility);
343
    },
344
};
345
# }}}
346

            
347
var MapNavaidItem = {
348
# manage navaids items by adding ID in the icon {{{
349
    new : func (id, type) {
350
        var m = {parents:[MapNavaidItem]};
351
        m._id = id;
352
        m._type = type;
353
        m._can = {
354
            'group' : nil,
355
            'label' : nil,
356
            'image' : nil,
357
        };
358
        return m;
359
    },
360
    create : func (group) {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
361
        me._can.group = group
362
            .createChild('group', me._type ~ '_' ~ me._id);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
363

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
364
        me._can.image = me._can.group.createChild('image', me._type ~ '-image_' ~ me._id)
365
            .setFile(mapIconCache._canvas.getPath())
366
            .setSourceRect(0,0,0,0,0);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
367

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
368
        me._can.label = me._can.group.createChild('text', me._type ~ '-label_' ~ me._id)
369
            .setDrawMode( canvas.Text.TEXT )
370
            .setTranslation(0,42)
371
            .setAlignment('center-bottom-baseline')
372
            .setFont('LiberationFonts/LiberationSans-Regular.ttf')
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
373
            .setFontSize(24);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
374

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
375
        me._can.label.set('fill','#BACBFB');
376
        me._can.label.set('stroke','#000000');
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
377

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
378
        return me._can.group;
379
    },
380
    setData : func (navaid, type) {
381
        mapIconCache.boundIconToImage('Navaid_' ~ type, me._can.image);
382
        me._can.label.setText(navaid.id);
383
        me._can.group.setGeoPosition(navaid.lat, navaid.lon);
384
    },
385
    setVisible : func (visibility) {
386
        me._can.group.setVisible(visibility);
387
    },
388
};
389
# }}}
390

            
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
391
var MapAirplaneItem = {
392
    new : func {
393
        var m = {parents:[MapAirplaneItem]};
394
        m._can = {
395
            'group' : nil,
396
            'image' : nil,
397
        };
398
        return m;
399
    },
400
    create : func (group) {
401
        me._can.group = group
402
            .createChild('group', 'airplane');
403
        me._can.image = me._can.group.createChild('image', 'airplane-image')
404
            .setFile(mapIconCache._canvas.getPath())
405
            .setSourceRect(0,0,0,0,0);
406
        return me._can.group;
407
    },
408
    setData : func {
409
        mapIconCache.boundIconToImage('airplane', me._can.image);
410
        me._can.group
411
            .setGeoPosition(data.lat, data.lon)
412
            .setRotation(data.hdg * D2R);
413
    },
414
    setVisible : func (visibility) {
415
        me._can.group.setVisible(visibility);
416
    },
417
};
418

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
419
var MAP_RUNWAY_SURFACE =  {0:0, 1:1, 2:1, 3:0, 4:0, 5:0, 6:1, 7:1, 8:0, 9:0, 10:0, 11:0, 12:0};
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
420
var MAP_RUNWAY_AT_RANGE = func (range) {
421
    if (range < 40) return 0;
422
    if (range < 50) return 250;
423
    if (range < 80) return 500;
424
    if (range < 160) return 1000;
425
    if (range < 240) return 3000;
426
    return 3000;
427
}
428
var MAP_TXRANGE_VOR = func (range) {
429
    if (range < 40) return 0;
430
    if (range < 50) return 20;
431
    if (range < 80) return 25;
432
    if (range < 160) return 30;
433
    if (range < 240) return 50;
434
    return 100;
435
}
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
436
####
437
# Declutter
438
#   land
439
#       0 : 'Terrain'
440
#       1 : 'Political boundaries'
441
#       2 : 'River/Lakes/Oceans'
442
#       3 : 'Roads'
443
#   Nav
444
#       0 : 'Airspace'
445
#       1 : 'Victor/Jet airways'
446
#       2 : 'Obstacles'
447
#       3 : 'Navaids'
448

            
449
var PositionedLayer = {
450
# the layer to show navaids, airports and airplane symbol {{{
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
451
    new : func (device) {
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
452
        var m = {parents : [PositionedLayer]};
453

            
454
        m._model = nil;
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
455
        m.device = device;
456
        var display = m.device.display.display;
457
        m._group = display.createGroup().createChild('map', 'MFD map')
get map display size from da...
Sébastien MARQUE authored on 2017-04-18
458
            .set('clip',
459
                    'rect('
460
                        ~ m.device.data.mapclip.top ~','
461
                        ~ m.device.data.mapclip.right ~','
462
                        ~ m.device.data.mapclip.bottom ~','
463
                        ~ m.device.data.mapclip.left ~')');
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
464
        m._group
465
            .setTranslation(
get map display size from da...
Sébastien MARQUE authored on 2017-04-18
466
                    m.device.data.mapsize[0] / 2 + m.device.data.mapclip.left,
467
                    m.device.data.mapsize[1] / 2 + m.device.data.mapclip.top
468
                );
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
469
        m._group._node.getNode('range', 1)
470
            .setDoubleValue(13.5); # TODO find a far less esoteric way to get range value
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
471

            
472
        m._can = {};
473
        m._cache = {};
474
        foreach (var n; ['airport', 'VOR', 'TACAN', 'NDB', 'DME']) {
475
            m._can[n] = m._group.createChild('group', n);
476
            m._cache[n] = {
477
                'data' : [],
478
                'index' : 0,
479
                'max' : 100,
480
            };
481
        }
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
482
        m._can['airplane'] = m._group.createChild('group', 'airplane');
483
        m._cache['airplane'] = {
484
            displayed : 0,
485
            item : nil,
486
        };
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
487

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
488
        m._mapOptions = {
489
            declutterLand : 3,
490
            declutterNAV  : 3,
491
            lightning     : 0,
492
            reports       : 0,
493
            overlay       : 0,
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
494
            range         : m.device.data['range-nm'],
495
            rangeLow      : m.device.data['range-nm'] / 2,
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
496
            runwayLength  : -1,
497
            orientation   : 0,
498
        };
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
499

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
500
        m._results = nil;
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
501

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
502
        m._visibility = 0;
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
503

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
504
        return m;
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
505
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
506
    update : func {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
507
        me._group._node.getNode('ref-lat', 1).setDoubleValue(data.lat);
508
        me._group._node.getNode('ref-lon', 1).setDoubleValue(data.lon);
509

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
510
        if (me._visibility == 1) {
511
            me.loadAirport();
512
            foreach (var n; ['VOR', 'TACAN', 'NDB', 'DME'])
513
                me.loadNavaid(n);
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
514
            me.loadAirplane();
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
515
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
516
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
517
    _onVisibilityChange : func {
518
        me._group.setVisible(me._visibility);
519
    },
520
    setMapOptions : func (mapOptions) {
521
        me._mapOptions = mapOptions;
522
        me.update();
523
    },
524
    updateOrientation : func (value) {
525
        me._mapOptions.orientation = value;
526
        for (var i = 0 ; i < me._cache.airport.index ; i +=1) {
527
            item = me._cache.airport.data[i];
528
            item.update(me._mapOptions);
commit initial
Sébastien MARQUE authored on 2017-03-07
529
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
530
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
531
    setRange : func (range=100) {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
532
        me._mapOptions.range = me.device.data['range-nm'];
533
        me._mapOptions.rangeLow = me._mapOptions.range/2;
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
534
        me.update();
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
535
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
536
    setRotation : func (deg) {
537
        me._group.setRotation(deg * D2R);
538
    },
539
    setVisible : func (v) {
540
        if (me._visibility != v) {
541
            me._visibility = v;
542
            me._onVisibilityChange();
543
        }
544
    },
545
    _onVisibilityChange : func {
546
        me._group.setVisible(me._visibility);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
547
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
548
    # positioned.findWithinRange : any, fix, vor, ndb, ils, dme, tacan
549

            
550
    loadAirport : func {
551
        me._cache.airport.index = 0;
552
        var results = positioned.findWithinRange(me._mapOptions.range * 2.5, 'airport');
553
        var item = nil;
554

            
555
        if (me._mapOptions.declutterNAV >= 2)
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
556
            me._mapOptions.runwayLength = MAP_RUNWAY_AT_RANGE(me._mapOptions.range);
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
557
        elsif (me._mapOptions.declutterNAV >= 1)
558
            me._mapOptions.runwayLength = 2000;
559
        else
560
            me._mapOptions.runwayLength = 3000;
561

            
562
        if (me._mapOptions.runwayLength >= 0) {
563
            foreach (var apt; results) {
564
                if (me._cache.airport.index >= me._cache.airport.max )
565
                    break;
566

            
567
                if (size(me._cache.airport.data) > me._cache.airport.index)
568
                    item = me._cache.airport.data[me._cache.airport.index];
569
                else {
570
                    item = MapAirportItem.new(me._cache.airport.index);
571
                    item.create(me._can.airport);
572
                    append(me._cache.airport.data, item);
573
                }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
574

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
575
                if (item.draw(apt, me._mapOptions)) {
576
                    item.setVisible(1);
577
                    me._cache.airport.index += 1;
578
                }
579
            }
580
        }
581

            
582
        for (var i = me._cache.airport.index ; i < size(me._cache.airport.data) ; i +=1) {
583
            item = me._cache.airport.data[i];
584
            item.setVisible(0);
585
        }
586
    },
587
    loadNavaid : func (type) {
588
        me._cache[type].index = 0;
589
        if (me._mapOptions.declutterNAV >= 3) { # TODO test for DME and NDB range < 100nm
590
            var range = me._mapOptions.range * 2.5;
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
591
            var txRange = MAP_TXRANGE_VOR(me._mapOptions.range);
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
592
            var results = positioned.findWithinRange(range, type);
593
            var item = nil;
594
            foreach (var n; results) {
595
                if (n.range_nm < txRange)
596
                    break;
597

            
598
                if (me._cache[type].index >= me._cache[type].max )
599
                    break;
600

            
601
                if (size(me._cache[type].data) > me._cache[type].index) {
602
                    item = me._cache[type].data[me._cache[type].index];
603
                    item.setData(n, type);
604
                }
605
                else {
606
                    item = MapNavaidItem.new(me._cache[type].index, type);
607
                    item.create(me._can[type]);
608
                    item.setData(n, type);
609
                    append(me._cache[type].data, item);
610
                }
611
                item.setVisible(1);
612
                me._cache[type].index += 1;
613
            }
614
        }
615
        for (var i = me._cache[type].index ; i < size(me._cache[type].data) ; i +=1) {
616
            item = me._cache[type].data[i];
617
            item.setVisible(0);
commit initial
Sébastien MARQUE authored on 2017-03-07
618
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
619
    },
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
620
    loadAirplane : func {
621
        if (!me._cache.airplane.displayed) {
622
            me._cache.airplane.item = MapAirplaneItem.new();
623
            me._cache.airplane.item.create(me._can['airplane']);
624
            me._cache.airplane.displayed = 1;
625
        }
626
        me._cache.airplane.item.setData();
627
        me._cache.airplane.item.setVisible(1);
628
    },
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
629
};
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
630
# }}}