Subversion Repositories Projects

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
810 - 1
###############################################################################
2
#
3
# libmapdef.pl -  Map definition
4
#
5
## Copyright (C) 2009  Rainer Walther  (rainerwalther-mail@web.de)
6
#
7
# Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
8
#
9
# Es ist Ihnen gestattet: 
10
#     * das Werk vervielfältigen, verbreiten und öffentlich zugänglich machen
11
#     * Abwandlungen bzw. Bearbeitungen des Inhaltes anfertigen
12
# 
13
# Zu den folgenden Bedingungen:
14
#     * Namensnennung.
15
#       Sie müssen den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
16
#     * Keine kommerzielle Nutzung.
17
#       Dieses Werk darf nicht für kommerzielle Zwecke verwendet werden.
18
#     * Weitergabe unter gleichen Bedingungen.
19
#       Wenn Sie den lizenzierten Inhalt bearbeiten oder in anderer Weise umgestalten,
20
#       verändern oder als Grundlage für einen anderen Inhalt verwenden,
21
#       dürfen Sie den neu entstandenen Inhalt nur unter Verwendung von Lizenzbedingungen
22
#       weitergeben, die mit denen dieses Lizenzvertrages identisch oder vergleichbar sind.
23
# 
24
# Im Falle einer Verbreitung müssen Sie anderen die Lizenzbedingungen, unter welche dieses
25
# Werk fällt, mitteilen. Am Einfachsten ist es, einen Link auf diese Seite einzubinden.
26
# 
27
# Jede der vorgenannten Bedingungen kann aufgehoben werden, sofern Sie die Einwilligung
28
# des Rechteinhabers dazu erhalten.
29
# 
30
# Diese Lizenz lässt die Urheberpersönlichkeitsrechte unberührt.
31
# 
32
# Weitere Details zur Lizenzbestimmung gibt es hier:
33
#   Kurzform: http://creativecommons.org/licenses/by-nc-sa/3.0/de/
34
#   Komplett: http://creativecommons.org/licenses/by-nc-sa/3.0/de/legalcode
35
#
36
###############################################################################
37
##
38
# 2009-03-06 0.0.1 rw created
39
# 2009-04-01 0.1.0 rw RC1
40
# 2009-04-18 0.1.1 rw Select default map, if configured map does not exist
41
# 2009-07-22 0.1.2 rw Offset_x and Offset_y for adjustment of map calibration
42
# 2009-08-15 0.1.3 rw Tracking Antenne Home position added
43
#                     Player home position added
44
#                     Read map definition from XML file
45
# 2009-09-29 0.1.4 rw Read map definition from KML file (GE import)
46
#                     Allow Config lines in map definition file (like mkcockpit.xml)
47
# 2009-11-08 0.1.5 rw Avoid div/0, if P1=P2
48
# 2010-05-16 0.1.6 rw Check empty Border in XML
49
# 2010-09-09 0.1.7 rw Load JPEG/PNG containig Geo-Information
50
#                     rename map/map.pl --> libmapdef.pl
51
#
52
###############################################################################
53
 
54
$Version{'libmapdef.pl'} = "0.1.7 - 2010-09-09";
55
 
56
use XML::Simple;                  # http://search.cpan.org/dist/XML-Simple-2.18/lib/XML/Simple.pm
57
use Image::ExifTool qw(:Public);  # http://search.cpan.org/~exiftool/Image-ExifTool-8.25/lib/Image/ExifTool.pod
58
 
59
 
60
# Load maps from filesystem (XML, KML, JPEG/PNG)
61
sub MapDefLoad()
62
    {
63
 
64
    %Maps =
65
        (
66
        Default => {
67
            'Name' => "Default",
68
            'File' => 'default-800.gif',
69
            # 'Size_X' => '800',
70
            # 'Size_Y  => '600',
71
 
72
            'P1_x' => '71',               # calibration P1, P2
73
            'P1_y' => '472',
74
            'P2_x' => '500',
75
            'P2_y' => '103',
76
            'P1_Lat' => '48.856253',
77
            'P1_Lon' => '2.3500000',
78
            'P2_Lat' => '54.090153',
79
            'P2_Lon' => '12.133249',
80
 
81
            # 'Offset_x' =>  5,             # Optional Pixel offset MK to right
82
            # 'Offset_y' =>  5,             # Optional pixel offset MK to top
83
 
84
            # 'Home_Lat' => '54.090153',    # Optional home position for player
85
            # 'Home_Lon' => '12.133249',    # Optional home position for player
86
 
87
            # 'Poi_Lat' => '54.090153',    # Optional POI position for player
88
            # 'Poi_Lon' => '12.133249',    # Optional POI position for player
89
 
90
            # 'Track_Lat' => '49.685333',   # Optional Tracking Antenna pos
91
            # 'Track_Lon' => '10.950134',   # Optional Tracking Antenna pos
92
            # 'Track_Alt' => '500',         # Optional Tracking Antenna altitude
93
            # 'Track_Bearing' =>  10,       # Optional Tracking antenne direction
94
 
95
            #  'Border' => [ 555, 430,       # airfield border
96
            #              516, 555,
97
            #              258, 555,
98
            #              100, 300,
99
            #              580, 260,
100
            #              530, 94,
101
            #              627, 130,
102
            #              735, 300,
103
            #              680, 400,
104
            #              757, 470,
105
            #              720, 515,
106
            #              575, 420,
107
            #            ],
108
            },
109
        );
110
 
111
 
112
    #
113
    # load additional Maps from XML files
114
    #
115
    my $MapDir = $Cfg->{'map'}->{'MapDir'} || "map";
116
    if ( -d $MapDir )
117
        {
118
        opendir DIR, $MapDir;
119
        my @Files = readdir DIR;
120
        @Files = grep /\.xml$/, @Files;
121
        closedir DIR;
122
 
123
        foreach $Xml (@Files)
124
            {
125
            my $MapConfigFile = "$MapDir/$Xml";
126
            if ( -f $MapConfigFile )
127
                {
128
                my $XmlMap = XMLin($MapConfigFile);
129
 
130
                foreach $Location (keys %{$XmlMap})
131
                    {
132
                    foreach $Key (keys %{$XmlMap->{$Location}} )
133
                        {
134
                        my $Value = $XmlMap->{$Location}->{$Key};
135
                        if ( $Key =~ /Border/i )
136
                            {
137
                            $Value =~ s/\s//g;
138
                            if ( $Value ne "" )
139
                                {
140
                                my @Border = split ',', $Value;
141
                                @{$Maps{$Location}->{$Key}}  = @Border;
142
                                }
143
                            }
144
                        else
145
                            {
146
                            $Maps{$Location}->{$Key}  = $Value;
147
                            }
148
                        }
149
                    }
150
                }
151
            }
152
        }
153
 
154
 
155
    #
156
    # load additional Maps from KML files
157
    #
158
    my $MapDir = $Cfg->{'map'}->{'MapDir'} || "map";
159
    if ( -d $MapDir )
160
        {
161
        opendir DIR, $MapDir;
162
        my @Files = readdir DIR;
163
        @Files = grep /\.kml$/, @Files;
164
        closedir DIR;
165
 
166
        foreach $Kml (@Files)
167
            {
168
            my $MapConfigFile = "$MapDir/$Kml";
169
            if ( -f $MapConfigFile )
170
                {
171
                my $KmlMap = XMLin($MapConfigFile);
172
 
173
                my $Name = $KmlMap->{'Document'}->{'Folder'}->{'name'};
174
                my $Desc = $KmlMap->{'Document'}->{'Folder'}->{'description'};
175
 
176
                $Maps{$Name}->{'Name'} = $Name;
177
 
178
                # Airfield Border
179
                my $Border = "";
180
                my $bBorder = 0;
181
 
182
                # parse config lines
183
                @DescLines = split '\n', $Desc;
184
                foreach $Line (@DescLines)
185
                    {
186
                    if ( $bBorder )
187
                        {
188
                        # collect border lines
189
                        if ( $Line =~ /=/i )
190
                            {
191
                            # New keyword found. End of multi-line border config
192
                            $bBorder = 0;
193
                            }
194
                        else
195
                            {
196
                            $Border = "$Border" . "$Line";
197
                            }
198
                        }
199
 
200
                    if ( $Line =~ /\s*(\S*)\s*=\s*(.*)/i)
201
                        {
202
                        my $Key = $1;
203
                        my $Value = $2;
204
                        chomp $Value;
205
 
206
                        # search for border keyword
207
                        if ($Key =~ /border/i )
208
                            {
209
                            $Border = $Value;
210
                            $bBorder = 1;
211
                            }
212
                        else
213
                            {
214
                            $Maps{$Name}->{$Key} = $Value;
215
                            }
216
                        }
217
                    }
218
 
219
                if ( $Border ne "" )
220
                    {
221
                    $Border =~ s/\s//g;
222
                    my @Border = split ',', $Border;
223
                    @{$Maps{$Name}->{'Border'}}  = @Border;
224
                    }
225
 
226
                # P1 calibration point
227
                my $P1 = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'P1'}->{'Point'}->{'coordinates'};
228
                my $P1Desc = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'P1'}->{'description'};
229
                ($Maps{$Name}->{'P1_Lon'}, $Maps{$Name}->{'P1_Lat'}) = split ',', $P1;
230
                if ( $P1Desc =~ /\s*x\s*=\s*(\d*)/i)  { $Maps{$Name}->{'P1_x'} = $1; }  # x=nnn
231
                if ( $P1Desc =~ /\s*y\s*=\s*(\d*)/i)  { $Maps{$Name}->{'P1_y'} = $1; }  # y=nnn
232
 
233
                # P2 calibration point
234
                my $P2 = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'P2'}->{'Point'}->{'coordinates'};
235
                my $P2Desc = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'P2'}->{'description'};
236
                ($Maps{$Name}->{'P2_Lon'}, $Maps{$Name}->{'P2_Lat'}) = split ',', $P2;
237
                if ( $P2Desc =~ /\s*x\s*=\s*(\d*)/i)  { $Maps{$Name}->{'P2_x'} = $1; }  # x=nnn
238
                if ( $P2Desc =~ /\s*y\s*=\s*(\d*)/i)  { $Maps{$Name}->{'P2_y'} = $1; }  # y=nnn
239
 
240
                # Home position
241
                if ( $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'Home'}->{'visibility'} ne "0" )
242
                    {
243
                    my $Home = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'Home'}->{'Point'}->{'coordinates'};
244
                    my $HomeDesc = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'Home'}->{'description'};
245
                    ($Maps{$Name}->{'Home_Lon'}, $Maps{$Name}->{'Home_Lat'}) = split ',', $Home;
246
                    }
247
 
248
                # POI position
249
                if ( $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'POI'}->{'visibility'} ne "0" )
250
                    {
251
                    my $Poi = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'POI'}->{'Point'}->{'coordinates'};
252
                    my $PoiDesc = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'POI'}->{'description'};
253
                    ($Maps{$Name}->{'Poi_Lon'}, $Maps{$Name}->{'Poi_Lat'}) = split ',', $Poi;
254
                    }
255
 
256
                # Antenna tracker position
257
                if ( $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'Antenna'}->{'visibility'} ne "0" )
258
                    {
259
                    my $Track = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'Antenna'}->{'Point'}->{'coordinates'};
260
                    my $TrackDesc = $KmlMap->{'Document'}->{'Folder'}->{'Placemark'}->{'Antenna'}->{'description'};
261
                    ($Maps{$Name}->{'Track_Lon'}, $Maps{$Name}->{'Track_Lat'}) = split ',', $Track;
262
                    if ( $TrackDesc =~ /\s*Track_Alt\s*=\s*(\d*)/i)      { $Maps{$Name}->{'Track_Alt'} = $1; }      # Track_Alt=nnn
263
                    if ( $TrackDesc =~ /\s*Track_Bearing\s*=\s*(\d*)/i)  { $Maps{$Name}->{'Track_Bearing'} = $1; }  # Track_Bearing=nnn
264
                    }
265
 
266
                if ( $Maps{$Name}->{'P1_x'} == $Maps{$Name}->{'P2_x'}  and
267
                     $Maps{$Name}->{'P1_y'} == $Maps{$Name}->{'P2_y'} )
268
                    {
269
                    # Avoid div/0 if P1=P2
270
                    $Maps{$Name}->{'P1_x'} += 1;
271
                    }
272
                }
273
            }
274
        }
275
 
276
    #
277
    # load additional Maps from JPEG/PNG containing Geo-Information
278
    #
279
    my $MapDir = $Cfg->{'map'}->{'MapDir'} || "map";
280
    if ( -d $MapDir )
281
        {
282
        opendir DIR, $MapDir;
283
        my @Files = readdir DIR;
284
        closedir DIR;
285
 
286
        my @ImgFiles;
287
        push @ImgFiles, grep /\.jpg$/, @Files;
288
        push @ImgFiles, grep /\.png$/, @Files;
289
 
290
        foreach $Image (@ImgFiles)
291
            {
292
            my $ImgFile = "$MapDir/$Image";
293
            if ( -f $ImgFile )
294
                {
295
                # take only image files which are not already used in %Maps
296
                $bUsed = "";
297
                foreach $Map (keys %Maps)
298
                    {
299
                    if ( $Maps{$Map}->{'File'} =~ /^${Image}$/i )
300
                        {
301
                        $bUsed = "X";
302
                        last;
303
                        }
304
                    }
305
 
306
                if ( $bUsed ne "X" )
307
                    {
308
                    # take image
309
                    my ($Width, $Height, $ImgInfo) = &GetImageInfo($ImgFile);
310
                    my $Comment = $$ImgInfo{'Comment'};
311
                    my $Name = substr ($Image, 0, -4);  # remove extension
312
 
313
                    # Image from Kopter-Tool
314
                    my @Fields = split ",", $Comment;
315
                    if ( $Fields[0] =~ /Geo-Information/i )
316
                        {
317
                        my ($RoLat, $RoLon) = split ":", $Fields[1];
318
                        my ($LoLat, $LoLon) = split ":", $Fields[2];
319
                        my ($RuLat, $RuLon) = split ":", $Fields[3];
320
                        my ($LuLat, $LuLon) = split ":", $Fields[4];
321
 
322
                        $Maps{$Name}->{'Name'} =  $Name;
323
                        $Maps{$Name}->{'File'} =  $Image;
324
                        $Maps{$Name}->{'P1_x'} =  0;
325
                        $Maps{$Name}->{'P1_y'} =  0;
326
                        $Maps{$Name}->{'P2_x'} =  $Width;
327
                        $Maps{$Name}->{'P2_y'} =  $Height;
328
                        $Maps{$Name}->{'P1_Lat'} =  $LoLat;
329
                        $Maps{$Name}->{'P1_Lon'} =  $LoLon;
330
                        $Maps{$Name}->{'P2_Lat'} =  $RuLat;
331
                        $Maps{$Name}->{'P2_Lon'} =  $RuLon;
332
                        }
333
 
334
                    # GeoMapTool Image for Mission Cockpit
335
                    my @Fields = split ";", $Comment;
336
                    foreach $Param (@Fields)
337
                        {
338
                        my ($Key, $Value) = split ":", $Param;
339
                        if ( $Key eq "P" )
340
                            {
341
                            my ($P1_x, $P1_y, $P2_x, $P2_y, $P1_Lat, $P1_Lon, $P2_Lat, $P2_Lon) = split ",", $Value;
342
                            $Maps{$Name}->{'P1_x'} =  $P1_x;
343
                            $Maps{$Name}->{'P1_y'} =  $P1_y;
344
                            $Maps{$Name}->{'P2_x'} =  $P2_x;
345
                            $Maps{$Name}->{'P2_y'} =  $P2_y;
346
                            $Maps{$Name}->{'P1_Lat'} =  $P1_Lat;
347
                            $Maps{$Name}->{'P1_Lon'} =  $P1_Lon;
348
                            $Maps{$Name}->{'P2_Lat'} =  $P2_Lat;
349
                            $Maps{$Name}->{'P2_Lon'} =  $P2_Lon;
350
 
351
                            $Maps{$Name}->{'File'} =  $Image;
352
                            $Maps{$Name}->{'Name'} =  $Name;
353
                            }
354
                        if ( $Key eq "Home" )
355
                            {
356
                            my ($Home_Lat, $Home_Lon) = split ",", $Value;
357
                            $Maps{$Name}->{'Home_Lat'} =  $Home_Lat;
358
                            $Maps{$Name}->{'Home_Lon'} =  $Home_Lon;
359
                            }
360
                        if ( $Key eq "Poi" )
361
                            {
362
                            my ($Poi_Lat, $Poi_Lon) = split ",", $Value;
363
                            $Maps{$Name}->{'Poi_Lat'} =  $Poi_Lat;
364
                            $Maps{$Name}->{'Poi_Lon'} =  $Poi_Lon;
365
                            }
366
                        if ( $Key eq "Border" )
367
                            {
368
                            my @Border = split ',', $Value;
369
                            @{$Maps{$Name}->{'Border'}}  = @Border;
370
                            }
371
                        }
372
                    }
373
                }
374
            }
375
        }
376
 
377
    # Die verwendete Karte
378
    &MapSetCurrentFromCfg();
379
    }
380
 
381
 
382
# Set $Maps{'Current'} from Cfg-Setting
383
sub MapSetCurrentFromCfg()
384
    {
385
 
386
    # Todo: Karte automatisch anhand der aktuellen GPS Position auswählen
387
 
388
    my $MapDefault = $Cfg->{'map'}->{'MapDefault'};
389
    if ( defined $Maps{$MapDefault} )
390
        {
391
        $Maps{'Current'} = $Maps{$MapDefault};
392
        }
393
    else
394
        {
395
        $Maps{'Current'} = $Maps{'Default'};
396
        print "Map \"$MapDefault\" not found in map.pl. Using \"Default\" map\n";
397
        }
398
 
399
    # optional map specific Cfg setup from map definition
400
    # Aktuell gültige Karte
401
    my %Map = %{$Maps{'Current'}};
402
 
403
    foreach $Key (keys %Map)
404
        {
405
        # Cfg:Section:Keyword
406
        if ( $Key =~ /^Cfg:(\S*):(\S*)/i )
407
            {
408
            $Section = $1;
409
            $Keyword = $2;
410
            $Cfg->{$Section}->{$Keyword} = $Map{$Key};
411
            }
412
        }
413
 
414
    # Get size of image
415
    my $ImgFile = "$Cfg->{'map'}->{'MapDir'}/$Map{'File'}";
416
    my ($Width, $Height) = &GetImageInfo($ImgFile);
417
    if ( $Maps{'Current'}->{'Size_X'} eq "" )
418
        {
419
        $Maps{'Current'}->{'Size_X'} = $Width;
420
        }
421
    if ( $Maps{'Current'}->{'Size_Y'} eq "" )
422
        {
423
        $Maps{'Current'}->{'Size_Y'} = $Height;
424
        }
425
 
426
    # Option list from map config dialog
427
    @{ $CfgOpt{MapDefault} } = sort keys %Maps
428
    }
429
 
430
 
431
# Get size and EXIF data of Image
432
sub GetImageInfo()
433
    {
434
    my ($File) = @_;
435
 
436
    my $ExifTool = new Image::ExifTool;
437
    my $ImgInfo = $ExifTool->ImageInfo($File);
438
 
439
    my $Width;
440
    my $Height;
441
 
442
    my $ImageSize  = $$ImgInfo{'ImageSize'};
443
    ($Width, $Height) = split "x", $ImageSize;
444
 
445
    if ( $Width eq "" )
446
        {
447
        $Width  = $$ImgInfo{'ImageWidth'};
448
        }
449
    if ( $Height eq "" )
450
        {
451
        $Height  = $$ImgInfo{'ImageHeight'};
452
        }
453
 
454
    if ( $Width eq "" )
455
        {
456
        $Width  = $$ImgInfo{'ExifImageWidth'};
457
        }
458
    if ( $Height eq "" )
459
        {
460
        $Height  = $$ImgInfo{'ExifImageHeight'};
461
        }
462
 
463
    return ($Width, $Height, $ImgInfo);
464
    }
465
 
466
 
467
1;
468
 
469
__END__