zkv1000 / Nasal / map.nas /
Newer Older
643 lines | 23.293kb
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
        ];
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
21
        m.visibility = m.device.role == 'MFD';
maps centered by group (for ...
Sébastien MARQUE authored on 2017-04-13
22
        m.group = m.display.createGroup()
23
            .setCenter(
get map display size from da...
Sébastien MARQUE authored on 2017-04-18
24
                    m.device.data.mapsize[0] / 2 + m.device.data.mapclip.left,
25
                    m.device.data.mapsize[1] / 2 + m.device.data.mapclip.top
26
                )
27
            .setTranslation(
28
                    m.device.data.mapclip.left / 2,
29
                    m.device.data.mapclip.top / 2
30
                )
31
            .set('clip',
32
                    'rect('
33
                        ~ m.device.data.mapclip.top ~','
34
                        ~ m.device.data.mapclip.right ~','
35
                        ~ m.device.data.mapclip.bottom ~','
36
                        ~ m.device.data.mapclip.left ~')'
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
37
                )
38
            .setVisible(m.visibility);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
39
        m.tiles = setsize([], m.num_tiles[0]);
40
        m.last_tile = [-1,-1];
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
41
        m.last_type = data['tiles-type'];
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
42
        m.changeZoom(0);
43
        m.initialize_grid();
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
44
        return m;
45
    },
46

            
47
# Simple user interface (Buttons for zoom and label for displaying it)
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
48
    changeZoom : func (d) {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
49
        me.device.data.zoom = math.max(2, math.min(19, me.device.data.zoom + d));
50
        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
51
    },
52

            
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
53
    setVisible : func (v) {
54
        if (v != me.visibility) {
55
            me.visibility = v;
56
            me.group.setVisible(v);
57
        }
58
    },
59

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
60
# initialize the map by setting up a grid of raster images
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
61
    initialize_grid : func {
62
        for(var x = 0; x < me.num_tiles[0]; x += 1) {
63
            me.tiles[x] = setsize([], me.num_tiles[1]);
64
            for(var y = 0; y < me.num_tiles[1]; y += 1)
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
65
                me.tiles[x][y] = me.group.createChild('image', 'tile ' ~ x ~ ',' ~ y);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
66
        }
67
    },
68

            
69
# this is the callback that will be regularly called by the timer to update the map
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
70
    update : func {
71
         if (! me.visibility)
72
             return;
put lat/lon in global data s...
Sébastien MARQUE authored on 2017-04-12
73
#        me.group.setRotation(-data.hdg * D2R);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
74

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

            
82
        var ox = tile_index[0] - offset[0];
83
        var oy = tile_index[1] - offset[1];
84

            
85
        for(var x = 0; x < me.num_tiles[0]; x += 1)
86
            for(var y = 0; y < me.num_tiles[1]; y += 1)
87
                me.tiles[x][y]
88
                    .setTranslation(int((ox + x) * me.tile_size + 0.5), int((oy + y) * me.tile_size + 0.5));
89

            
90
        if(    tile_index[0] != me.last_tile[0]
91
                or tile_index[1] != me.last_tile[1]
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
92
                or data['tiles-type'] != me.last_type ) {
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
93
            for(var x = 0; x < me.num_tiles[0]; x += 1)
94
                for(var y = 0; y < me.num_tiles[1]; y += 1) {
95
                    var pos = {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
96
                        z: me.device.data.zoom,
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
97
                        x: int(offset[0] + x),
98
                        y: int(offset[1] + y),
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
99
                        type: data['tiles-type'],
100
                        server : data['tiles-server'],
101
                        apikey: data['tiles-apikey'],
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
102
                    };
103

            
104
                    (func {
105
                        var img_path = me.makePath(pos);
106
                        printlog('debug', 'img_path: ', img_path);
107
                        var tile = me.tiles[x][y];
108

            
109
                        if( io.stat(img_path) == nil ) { # image not found, save in $FG_HOME
110
                            var img_url = me.makeUrl(pos);
111
                            printlog('debug', 'requesting ' ~ img_url);
112
                            http.save(img_url, img_path)
113
                                .done(func {printlog('info', 'received image ' ~ img_path); tile.set("src", img_path);})
114
                                .fail(func (r) printlog('warn', 'Failed to get image ' ~ img_path ~ ' ' ~ r.status ~ ': ' ~ r.reason));
115
                        }
116
                        else { # cached image found, reusing
117
                            printlog('debug', 'loading ' ~ img_path);
118
                            tile.set("src", img_path);
119
                        }
120
                    })();
121
                }
122
            me.last_tile = tile_index;
moves some map infos in data...
Sébastien MARQUE authored on 2017-04-11
123
            me.last_type = data['tiles-type'];
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
124
        }
125
    },
126
};
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
127
# }}}
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
128

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

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

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
138
        m._canvas = canvas.new( {
139
            'name': 'MapIconCache',
140
            'size': [512, 512],
141
            'view': [512, 512],
142
            'mipmapping': 1
143
        });
144
        m._canvas.addPlacement( {'type': 'ref'} );
145
        m._canvas.setColorBackground(1,1,1,0);
146
        m._group = m._canvas.createGroup('MapIcons');
147

            
148
        canvas.parsesvg(m._group, data.zkv1000_reldir ~ svgFile);
149

            
150
        m._sourceRectMap = {};
151

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

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
154
        foreach (var near; [0, 1])
155
            foreach (var surface; [0, 1])
156
                foreach (var tower; [0, 1])
157
                    foreach (var center; tower ? [0, 1] : [ 0 ])
158
                        append(icons, 'Airport_' ~ near ~ surface ~ tower ~ center);
159

            
160
        foreach (var type; ['VOR', 'DME', 'TACAN', 'NDB'])
161
            append(icons, 'Navaid_' ~ type);
162

            
163
        foreach (var i; icons)
164
            m.registerIcon(i);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
165

            
166
        return m;
167
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
168
    registerIcon : func (id) {
169
        me._sourceRectMap[id] = {
170
            'bound' : [],
171
            'size'  : [],
172
        };
173
        var element = me._group.getElementById(id);
174
        if (element != nil) {
175
            me._sourceRectMap[id].bound = element.getTransformedBounds();
176
            # TODO ugly hack ? check for reason!
177
            var top     = 512 - me._sourceRectMap[id].bound[3];
178
            var bottom  = 512 - me._sourceRectMap[id].bound[1];
179
            me._sourceRectMap[id].bound[1] = top;
180
            me._sourceRectMap[id].bound[3] = bottom;
181

            
182
            me._sourceRectMap[id].size = [
183
                me._sourceRectMap[id].bound[2] - me._sourceRectMap[id].bound[0],
184
                me._sourceRectMap[id].bound[3] - me._sourceRectMap[id].bound[1]
185
            ];
186
        }
187
        else {
188
            print('MapIconCache.registerIcon(' ~ id ~ ') fail');
189
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
190
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
191
    getBounds : func (id) {
192
        return me._sourceRectMap[id].bound;
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
193
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
194
    getSize : func (id) {
195
        return me._sourceRectMap[id].size;
196
    },
197
    boundIconToImage : func (id, image, center=1) {
198
        if (!contains(me._sourceRectMap, id)) {
199
            print('MapIconCache.boundIconToImage('~id~') ... no available.');
200
            id = 'Airport_0001';
201
        }
202
        image.setSourceRect(
203
                me._sourceRectMap[id].bound[0],
204
                me._sourceRectMap[id].bound[1],
205
                me._sourceRectMap[id].bound[2],
206
                me._sourceRectMap[id].bound[3],
207
                0);
208
        image.setSize(
209
                me._sourceRectMap[id].size[0],
210
                me._sourceRectMap[id].size[1]);
211
        if (center) {
212
            image.setTranslation(
213
                    -me._sourceRectMap[id].size[0]/2,
214
                    -me._sourceRectMap[id].size[1]/2);
215
        }
216
    },
217
};
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
218

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

            
222
var MapAirportItem = {
223
# manage airports items by adding the ID and runways on associated icon {{{
224
    new : func (id) {
225
        var m = {parents:[MapAirportItem]};
226
        m._id = id;
227
        m._can = {
228
            'group' : nil,
229
            'label' : nil,
230
            'image' : nil,
231
            'layout': nil,
232
            'runway': [],
233
        };
234
        m._mapAirportIcon = {
235
            'near'      : 0,
236
            'surface'   : 0,
237
            'tower'     : 0,
238
            'center'    : 0,
239
            'displayed' : 0,
240
            'icon'      : '',
241
        };
242
        return m;
243
    },
244
    create : func (group) {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
245
        me._can.group = group
246
            .createChild('group', 'airport_' ~ me._id);
247

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

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

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

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
262
        me._can.layout = group.createChild('group','airport_layout' ~ me._id);
263
        me._can.layoutIcon = group.createChild('group','airport_layout_Icon' ~ me._id);
264
        return me._can.group;
265
    },
266
    draw : func (apt, mapOptions) {
267
        me._mapAirportIcon.near = mapOptions.range > 30 ? 0 : 1;
268
        me._mapAirportIcon.surface  = 0;
269
        me._mapAirportIcon.tower    = 0;
270
        me._mapAirportIcon.center   = 0;
271
        me._mapAirportIcon.displayed    = 0;
272

            
273
        # TODO make departure and destination airports specific
274
        var aptInfo = airportinfo(apt.id);
275

            
276
        me._can.layout.removeAllChildren();
277
        me._can.layoutIcon.removeAllChildren();
278

            
279
        me._mapAirportIcon.tower = (size(aptInfo.comms('tower')) > 0);
280
        me._mapAirportIcon.center = me._mapAirportIcon.tower and (size(aptInfo.comms('approach')) > 0);
281

            
282
        foreach (var rwy; keys(aptInfo.runways)) {
283
            var runway = aptInfo.runways[rwy];
284
            me._mapAirportIcon.surface = MAP_RUNWAY_SURFACE[runway.surface] ? 1 : me._mapAirportIcon.surface;
285
            me._mapAirportIcon.displayed = runway.length > mapOptions.runwayLength ? 1 : me._mapAirportIcon.displayed;
286

            
287
            if (mapOptions.range <= 10) {    # drawing real runways
288
                me._can.layout.createChild('path', 'airport-runway-' ~ me._id ~ '-' ~ runway.id)
289
                    .setStrokeLineWidth(7)
290
                    .setColor(1,1,1)
291
                    .setColorFill(1,1,1)
292
                    .setDataGeo([
293
                        canvas.Path.VG_MOVE_TO,
294
                        canvas.Path.VG_LINE_TO,
295
                        canvas.Path.VG_CLOSE_PATH
296
                    ],[
297
                        'N' ~ runway.lat, 'E' ~ runway.lon,
298
                        'N' ~ runway.reciprocal.lat, 'E' ~ runway.reciprocal.lon,
299
                    ]);
300
            }
301
            elsif (mapOptions.range <= 30) {     #draw icon runways
302
                me._can.layoutIcon.setGeoPosition(apt.lat, apt.lon);
303
                me._can.layoutIcon.createChild('path', 'airport-runway-' ~ me._id ~ '-' ~ runway.id)
304
                    .setStrokeLineWidth(7)
305
                    .setColor(1,1,1)
306
                    .setColorFill(1,1,1)
307
                    .setData([
308
                        canvas.Path.VG_MOVE_TO,
309
                        canvas.Path.VG_LINE_TO,
310
                        canvas.Path.VG_CLOSE_PATH
311
                    ],[
312
                        0, -20,
313
                        0, 20,
314
                    ])
315
                    .setRotation((runway.heading)* D2R);
316
            }
317
        }
318
        me._mapAirportIcon.icon = 'Airport_'
319
            ~ me._mapAirportIcon.near
320
            ~ me._mapAirportIcon.surface
321
            ~ me._mapAirportIcon.tower
322
            ~ me._mapAirportIcon.center;
323

            
324
        if (me._mapAirportIcon.displayed) {
325
            me._can.label.setText(apt.id);
326
            me._can.group.setGeoPosition(apt.lat, apt.lon);
327
            if (mapOptions.range <= 10) {
328
                me._can.image.setVisible(0);
329
                me._can.layout.setVisible(1);
330
            }
331
            elsif (mapOptions.range <= 30) {
332
                mapIconCache.boundIconToImage(me._mapAirportIcon.icon, me._can.image);
333
                me._can.image.setVisible(1);
334
                me._can.layout.setVisible(1);
335
            }
336
            else {
337
                mapIconCache.boundIconToImage(me._mapAirportIcon.icon, me._can.image);
338
                me._can.layout.setVisible(0);
339
                me._can.image.setVisible(1);
340
            }
341
            me._can.group.setVisible(1);
342
        }
343
        return me._mapAirportIcon.displayed;
344
    },
345
    update : func (mapOptions) {
346
        if (mapOptions.range <= 10) { }
347
        elsif (mapOptions.range <= 30)
348
            me._can.layoutIcon.setRotation(-mapOptions.orientation * D2R);
349
        else { }
350
    },
351
    setVisible : func (visibility) {
352
        me._can.group.setVisible(visibility);
353
        me._can.layout.setVisible(visibility);
354
        me._can.image.setVisible(visibility);
355
        me._can.layoutIcon.setVisible(visibility);
356
    },
357
};
358
# }}}
359

            
360
var MapNavaidItem = {
361
# manage navaids items by adding ID in the icon {{{
362
    new : func (id, type) {
363
        var m = {parents:[MapNavaidItem]};
364
        m._id = id;
365
        m._type = type;
366
        m._can = {
367
            'group' : nil,
368
            'label' : nil,
369
            'image' : nil,
370
        };
371
        return m;
372
    },
373
    create : func (group) {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
374
        me._can.group = group
375
            .createChild('group', me._type ~ '_' ~ me._id);
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
376

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

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

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

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
391
        return me._can.group;
392
    },
393
    setData : func (navaid, type) {
394
        mapIconCache.boundIconToImage('Navaid_' ~ type, me._can.image);
395
        me._can.label.setText(navaid.id);
396
        me._can.group.setGeoPosition(navaid.lat, navaid.lon);
397
    },
398
    setVisible : func (visibility) {
399
        me._can.group.setVisible(visibility);
400
    },
401
};
402
# }}}
403

            
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
404
var MapAirplaneItem = {
405
    new : func {
406
        var m = {parents:[MapAirplaneItem]};
407
        m._can = {
408
            'group' : nil,
409
            'image' : nil,
410
        };
411
        return m;
412
    },
413
    create : func (group) {
414
        me._can.group = group
415
            .createChild('group', 'airplane');
416
        me._can.image = me._can.group.createChild('image', 'airplane-image')
417
            .setFile(mapIconCache._canvas.getPath())
418
            .setSourceRect(0,0,0,0,0);
419
        return me._can.group;
420
    },
421
    setData : func {
422
        mapIconCache.boundIconToImage('airplane', me._can.image);
423
        me._can.group
424
            .setGeoPosition(data.lat, data.lon)
425
            .setRotation(data.hdg * D2R);
426
    },
427
    setVisible : func (visibility) {
428
        me._can.group.setVisible(visibility);
429
    },
430
};
431

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
432
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
433
var MAP_RUNWAY_AT_RANGE = func (range) {
434
    if (range < 40) return 0;
435
    if (range < 50) return 250;
436
    if (range < 80) return 500;
437
    if (range < 160) return 1000;
438
    if (range < 240) return 3000;
439
    return 3000;
440
}
441
var MAP_TXRANGE_VOR = func (range) {
442
    if (range < 40) return 0;
443
    if (range < 50) return 20;
444
    if (range < 80) return 25;
445
    if (range < 160) return 30;
446
    if (range < 240) return 50;
447
    return 100;
448
}
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
449
####
450
# Declutter
451
#   land
452
#       0 : 'Terrain'
453
#       1 : 'Political boundaries'
454
#       2 : 'River/Lakes/Oceans'
455
#       3 : 'Roads'
456
#   Nav
457
#       0 : 'Airspace'
458
#       1 : 'Victor/Jet airways'
459
#       2 : 'Obstacles'
460
#       3 : 'Navaids'
461

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

            
467
        m._model = nil;
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
468
        m.device = device;
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
469
        m._visibility = m.device.role == 'MFD';
470

            
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
471
        var display = m.device.display.display;
472
        m._group = display.createGroup().createChild('map', 'MFD map')
get map display size from da...
Sébastien MARQUE authored on 2017-04-18
473
            .set('clip',
474
                    'rect('
475
                        ~ m.device.data.mapclip.top ~','
476
                        ~ m.device.data.mapclip.right ~','
477
                        ~ m.device.data.mapclip.bottom ~','
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
478
                        ~ m.device.data.mapclip.left ~')')
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
479
            .setTranslation(
get map display size from da...
Sébastien MARQUE authored on 2017-04-18
480
                    m.device.data.mapsize[0] / 2 + m.device.data.mapclip.left,
481
                    m.device.data.mapsize[1] / 2 + m.device.data.mapclip.top
makes map available for PFD ...
Sébastien MARQUE authored on 2017-04-19
482
                )
483
            .setVisible(m._visibility);
484
            m._group._node
485
                .getNode('range', 1).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
486

            
487
        m._can = {};
488
        m._cache = {};
489
        foreach (var n; ['airport', 'VOR', 'TACAN', 'NDB', 'DME']) {
490
            m._can[n] = m._group.createChild('group', n);
491
            m._cache[n] = {
492
                'data' : [],
493
                'index' : 0,
494
                'max' : 100,
495
            };
496
        }
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
497
        m._can['airplane'] = m._group.createChild('group', 'airplane');
498
        m._cache['airplane'] = {
499
            displayed : 0,
500
            item : nil,
501
        };
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
502

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
503
        m._mapOptions = {
504
            declutterLand : 3,
505
            declutterNAV  : 3,
506
            lightning     : 0,
507
            reports       : 0,
508
            overlay       : 0,
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
509
            range         : m.device.data['range-nm'],
510
            rangeLow      : m.device.data['range-nm'] / 2,
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
511
            runwayLength  : -1,
512
            orientation   : 0,
513
        };
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
514

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
515
        m._results = nil;
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
        return m;
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
518
    },
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
519
    update : func {
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
520
        me._group._node.getNode('ref-lat', 1).setDoubleValue(data.lat);
521
        me._group._node.getNode('ref-lon', 1).setDoubleValue(data.lon);
522

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

            
563
    loadAirport : func {
564
        me._cache.airport.index = 0;
565
        var results = positioned.findWithinRange(me._mapOptions.range * 2.5, 'airport');
566
        var item = nil;
567

            
568
        if (me._mapOptions.declutterNAV >= 2)
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
569
            me._mapOptions.runwayLength = MAP_RUNWAY_AT_RANGE(me._mapOptions.range);
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
570
        elsif (me._mapOptions.declutterNAV >= 1)
571
            me._mapOptions.runwayLength = 2000;
572
        else
573
            me._mapOptions.runwayLength = 3000;
574

            
575
        if (me._mapOptions.runwayLength >= 0) {
576
            foreach (var apt; results) {
577
                if (me._cache.airport.index >= me._cache.airport.max )
578
                    break;
579

            
580
                if (size(me._cache.airport.data) > me._cache.airport.index)
581
                    item = me._cache.airport.data[me._cache.airport.index];
582
                else {
583
                    item = MapAirportItem.new(me._cache.airport.index);
584
                    item.create(me._can.airport);
585
                    append(me._cache.airport.data, item);
586
                }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
587

            
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
588
                if (item.draw(apt, me._mapOptions)) {
589
                    item.setVisible(1);
590
                    me._cache.airport.index += 1;
591
                }
592
            }
593
        }
594

            
595
        for (var i = me._cache.airport.index ; i < size(me._cache.airport.data) ; i +=1) {
596
            item = me._cache.airport.data[i];
597
            item.setVisible(0);
598
        }
599
    },
600
    loadNavaid : func (type) {
601
        me._cache[type].index = 0;
602
        if (me._mapOptions.declutterNAV >= 3) { # TODO test for DME and NDB range < 100nm
603
            var range = me._mapOptions.range * 2.5;
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
604
            var txRange = MAP_TXRANGE_VOR(me._mapOptions.range);
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
605
            var results = positioned.findWithinRange(range, type);
606
            var item = nil;
607
            foreach (var n; results) {
608
                if (n.range_nm < txRange)
609
                    break;
610

            
611
                if (me._cache[type].index >= me._cache[type].max )
612
                    break;
613

            
614
                if (size(me._cache[type].data) > me._cache[type].index) {
615
                    item = me._cache[type].data[me._cache[type].index];
616
                    item.setData(n, type);
617
                }
618
                else {
619
                    item = MapNavaidItem.new(me._cache[type].index, type);
620
                    item.create(me._can[type]);
621
                    item.setData(n, type);
622
                    append(me._cache[type].data, item);
623
                }
624
                item.setVisible(1);
625
                me._cache[type].index += 1;
626
            }
627
        }
628
        for (var i = me._cache[type].index ; i < size(me._cache[type].data) ; i +=1) {
629
            item = me._cache[type].data[i];
630
            item.setVisible(0);
commit initial
Sébastien MARQUE authored on 2017-03-07
631
        }
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
632
    },
navaids displayed with corre...
Sébastien MARQUE authored on 2017-04-18
633
    loadAirplane : func {
634
        if (!me._cache.airplane.displayed) {
635
            me._cache.airplane.item = MapAirplaneItem.new();
636
            me._cache.airplane.item.create(me._can['airplane']);
637
            me._cache.airplane.displayed = 1;
638
        }
639
        me._cache.airplane.item.setData();
640
        me._cache.airplane.item.setVisible(1);
641
    },
adds Map on MFD
Sébastien MARQUE authored on 2017-03-20
642
};
implements the ND from Extra...
Sébastien MARQUE authored on 2017-04-17
643
# }}}