source: subversion/applications/share/map-icons/update_icons.pl @ 6809

Last change on this file since 6809 was 6641, checked in by ulf, 12 years ago

don't create a backup file, that's what svn is for!

  • Property svn:executable set to *
File size: 16.0 KB
Line 
1#!/usr/bin/perl
2#####################################################################
3#
4#  This script handles the XML-Files for the POI-Types in gpsdrive.
5#  It has to be run from the data directory.
6
7#  Default actions, when no options are given:
8#  - Create basic XML-File if none is available
9#  - Search icons directories for PNG files
10#  - Add those files as new POI-Types if they are not yet existent
11#  - Create overview.html from the XML-File to show all
12#    available poi_types and icons.
13#
14#####################################################################
15#
16#  Scheme for the entries (only poi_type relevant elements are shown):
17#
18#  <rule>
19#    <condition k="poi" v="$NAME" />
20#    <scale_min>$SCALE_MIN</scale_min>
21#    <scale_max>$SCALE_MAX</scale_max>
22#    <title lang="$LANG">$TITLE</title>
23#    <description lang="$LANG">$DESCRIPTION</description>
24#    <geoinfo>
25#      <poi_type_id>$POI_TYPE_ID</poi_type_1id>
26#      <name>$NAME</name>
27#    </geoinfo>
28#  </rule>
29#
30#####################################################################
31
32#use diagnostics;
33use strict;
34use warnings;
35
36use utf8;
37use IO::File;
38use File::Find;
39use File::Copy;
40use XML::Twig;
41use Getopt::Std;
42use Pod::Usage;
43use Image::Magick;
44use File::Slurp;
45use File::Basename;
46use File::Path;
47use Data::Dumper;
48
49our ($opt_v, $opt_f, $opt_h, $opt_i, $opt_n, $opt_r,$opt_s) = 0;
50getopts('hvinrsf:') or $opt_h = 1;
51pod2usage( -exitval => '1', 
52           -verbose => '1') if $opt_h;
53
54my $file_xml = './icons.xml';
55my %ICONS = ('','');
56my $i = 0;
57my $poi_reserved = 30;
58my $poi_type_id_base = $poi_reserved;
59my $default_scale_min = 1;
60my $default_scale_max = 50000;
61my $default_title_en = '';
62my $default_desc_en = '';
63my $VERBOSE = $opt_v;
64
65my @ALL_TYPES = qw(square.big square.small classic.big classic.small svg japan );
66
67
68#####################################################################
69#
70#  M A I N
71#
72#
73chdir('./map-icons');
74unless (-e $file_xml)
75{
76  create_xml(); # Create a new XML-File if none exists
77}
78get_icons();             # read available icons from dirs
79update_xml();            # parse and update contents  of XML-File
80chdir('..');
81exit (0);
82
83
84
85#####################################################################
86#
87#  Parse available XML-File aund update with contents from icons dirs
88#
89#
90sub update_xml
91{
92  print STDOUT "\n----- Parsing and updating '$file_xml' -----\n";
93 
94  # Parse XML-File and look for already existing POI-Type entries
95  #
96  my $twig= new XML::Twig
97    (
98      pretty_print => 'indented',
99      empty_tags => 'normal',
100      comments => 'keep',
101      TwigHandlers => { 
102          geoinfo => \&sub_geoinfo # also deletes the entry from %ICONS
103     }
104    );
105  $twig->parsefile( "$file_xml");       # build the twig
106  my $rules= $twig->root;       # get the root of the twig (rules)
107
108  # Insert new POI-Type entries from hash of available icons
109  #
110  $i = 0;
111  my @tmp_icons = sort(keys(%ICONS));
112 
113  for my $icon (@tmp_icons)
114  {
115     insert_poi_type($icon,\$rules);
116     $i++;
117  }
118  print STDOUT "  New POI-Types added:\t$i\n";
119
120  # Print Status for poi_type_ids
121  #
122  my @rule= $rules->children;   # get the updated rule list
123
124  my @a_id;
125  $i = 0;
126  my $id_max = 0;
127  foreach my $entry (@rule)
128  {
129    if  (my $id =
130         $entry->first_child('geoinfo')->first_child('poi_type_id')->text)
131    {
132      $i++;
133      $a_id[$i] = $id; # XXX besser mit push(@a_id,$id)? denn a_id[0] wird nie belegt?
134      $id_max = $id if $id >$id_max;
135    }
136  }
137  my %unused = ('','');
138  for ( my $k = 1; $k<$id_max; $k++ ) { $unused{$k}=$k; } 
139  print STDOUT "  POI-Types defined:\t$i\n";
140  print STDOUT "  Max. poi_type_id:\t$id_max\n";
141  print STDOUT "  Unused IDs:\n  \t";
142  foreach (@a_id)
143  { 
144    if (defined($_) && exists $unused{$_}) { delete $unused{$_}; }
145  }
146  foreach (sort(keys(%unused)))
147    { print STDOUT "$_  " if ($_ > $poi_reserved) }
148  print STDOUT "\n\n";
149
150  # Write XML-File containing modified contents
151  #
152  open TMPFILE,">:utf8","./icons.tmp";
153    select TMPFILE;
154    print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
155    print "<rules>\n";
156   
157    my $j=1;
158
159
160sub entry_name($){
161    my $entry = shift;
162    return $entry->first_child('geoinfo')->first_child('name')->text();
163}
164
165    foreach my $entry (sort {entry_name($a) cmp entry_name($b) } @rule)
166     {
167       my $name = $entry->first_child('geoinfo')->first_child('name')->text();
168       next if not($opt_i) && $name =~ m/^incomming/;
169
170       $entry->print;
171       print "\n"; 
172     }
173    print "</rules>\n";
174  close TMPFILE;
175
176  # Create backup copy of old XML-File
177  #
178  #move("$file_xml","$file_xml.bak") or die (" Couldn't create backup file!");
179  move("./icons.tmp","$file_xml") or die (" Couldn't remove temp file!");
180  print STDOUT " XML-File successfully updated!\n";
181
182  $twig->purge;
183
184  return;
185
186  # look, if POI-Type already exists in the file by checking for a
187  # known name inside the geoinfo tag. If true, kick it from the icons
188  # hash, because it's not needed anymore.
189  sub sub_geoinfo
190   {
191     my( $twig, $geoinfo)= @_;
192     my $poi_type_id = $geoinfo->first_child('poi_type_id')->text;
193     my $name = $geoinfo->first_child('name')->text;
194
195     if (exists $ICONS{$name}) 
196     {
197       print STDOUT "  o  $poi_type_id\t\t$name\n" if $VERBOSE;
198       $poi_type_id_base = $poi_type_id 
199           if ($poi_type_id > $poi_type_id_base);
200       delete $ICONS{"$name"};
201     }
202   }
203}
204
205
206#####################################################################
207#
208#  Insert new POI-Type into the file
209#
210#
211sub insert_poi_type
212{
213  my $name = shift(@_);
214  my $twig_root = shift(@_);
215
216  my $new_rule = new XML::Twig::Elt( 'rule');
217  $poi_type_id_base++;
218 
219  my $new_condition = new XML::Twig::Elt('condition');
220  $new_condition->set_att(k=>'poi');
221  $new_condition->set_att(v=>"$name");
222  my $new_title_en = new XML::Twig::Elt('title',$default_title_en);
223  $new_title_en->set_att(lang=>'en');
224  my $new_desc_en = new XML::Twig::Elt('description',$default_desc_en);
225  $new_desc_en->set_att(lang=>'en');
226  my $new_scale_min = new XML::Twig::Elt('scale_min',$default_scale_min);
227  my $new_scale_max = new XML::Twig::Elt('scale_max',$default_scale_max);
228  my $new_poi_type_id = new XML::Twig::Elt('poi_type_id',$poi_type_id_base);
229  my $new_name = new XML::Twig::Elt('name',$name);
230
231  $new_poi_type_id->paste('last_child',$new_rule);
232  $new_name->paste('last_child',$new_rule);
233  $new_rule->insert('geoinfo');
234  $new_desc_en->paste('first_child',$new_rule);
235  $new_title_en->paste('first_child',$new_rule);
236  $new_scale_max->paste('first_child',$new_rule);
237  $new_scale_min->paste('first_child',$new_rule);
238  $new_condition->paste('first_child',$new_rule);
239
240  $new_rule->paste('last_child',$$twig_root); 
241
242  print STDOUT "  +  $poi_type_id_base\t\t$name\n" if $VERBOSE;
243}
244
245
246#####################################################################
247#
248#  Get all the available icons in data/icons
249#
250#
251sub get_icons
252{
253  print STDOUT "\n----- Looking for available icons -----\n";
254  $i = 0;
255  find( \&format_icons,  @ALL_TYPES );
256  sub format_icons()
257  { 
258      my $icon_file = $File::Find::name;
259      if ( $icon_file =~ m/\.svn/ ) {
260      } elsif ( not($opt_i) && $icon_file =~ m/incomming/ ) {
261          print STDOUT "ignore incomming: $icon_file\n" if $VERBOSE;
262      } elsif ( $icon_file =~ m/\.(png|svg)$/ && $icon_file !~ m/empty\.(png|svg)$/ ) {
263          $i++;
264          print STDOUT "  Found icon:\t$i\t$icon_file\n" if $VERBOSE;
265          for my $type ( @ALL_TYPES ) {
266              $icon_file =~ s,^$type/,,g;
267          }
268          $icon_file =~ s,\.(png|svg)$,,g;
269          $icon_file =~ s,/,.,g;
270          $ICONS{"$icon_file"} = '1';
271      }
272  }
273  delete $ICONS{''} if (exists $ICONS{''});
274  print STDOUT " $i icons for ".keys(%ICONS)." POI-Types found in data/map-icons\n";
275 
276}
277
278#####################################################################
279#
280#  Create a new XML File and fill it with the basic POI-Types
281#
282#
283sub create_xml
284 { 
285   print STDOUT "\n----- Creating new basic XML-File \"$file_xml\" -----\n";
286   print STDOUT "\n  ATTENTION: It is possible, that the IDs will change,\n";
287   print STDOUT "\n  so it would be better, if you update an existing icons.xml!\n";
288   my @poi_types = (
289
290     { name => 'unknown',
291       poi_type_id => '1',
292       scale_min => '1',
293       scale_max => '50000',
294       description_en => 'Unassigned POI',
295       description_de => 'Nicht zugewiesener POI',
296       title_en => 'Unknown',
297       title_de => 'Unbekannt',
298     },
299     { name => 'accommodation',
300       poi_type_id => '2',
301       scale_min => '1',
302       scale_max => '50000',
303       description_en => 'Places to stay',
304       description_de => 'Hotels, Jugendherbergen, Campingpl&#228;tze',
305       title_en => 'Accommodation',
306       title_de => 'Unterkunft',
307     },
308     { name => 'education',
309       poi_type_id => '3',
310       scale_min => '1',
311       scale_max => '25000',
312       description_en => 'Schools and other educational facilities',
313       description_de => 'Schulen und andere Bildungseinrichtungen',
314       title_en => 'Education',
315       title_de => 'Bildung',
316     },
317     { name => 'food',
318       poi_type_id => '4',
319       scale_min => '1',
320       scale_max => '25000',
321       description_en => 'Restaurants, Bars, and so on...',
322       description_de => 'Restaurants, Bars, usw.',
323       title_en => 'Food',
324       title_de => 'Speiselokal',
325     },
326     { name => 'geocache',
327       poi_type_id => '5',
328       scale_min => '1',
329       scale_max => '50000',
330       description_en => 'Geocaches',
331       description_de => 'Geocaches',
332       title_en => 'Geocache',
333       title_de => 'Geocache',
334     },
335     { name => 'health',
336       poi_type_id => '6',
337       scale_min => '1',
338       scale_max => '25000',
339       description_en => 'Hospital, Doctor, Pharmacy, etc.',
340       description_de => 'Krankenh&#228;user, &#196;rzte, Apotheken',
341       title_en => 'Health',
342       title_de => 'Gesundheit',
343     },
344     { name => 'money',
345       poi_type_id => '7',
346       scale_min => '1',
347       scale_max => '25000',
348       description_en => 'Bank, ATMs, and other money-related places',
349       description_de => 'Banken, Geldautomaten, und &#228;hnliches',
350       title_en => 'Money',
351       title_de => 'Geld',
352     },
353     { name => 'nautical',
354       poi_type_id => '8',
355       scale_min => '1',
356       scale_max => '50000',
357       description_en => 'Special aeronautical Points',
358       description_de => 'Spezielle aeronautische Punkte',
359       title_en => 'aeronautical',
360       title_de => 'aeronautisch',
361     },
362     { name => 'people',
363       poi_type_id => '9',
364       scale_min => '1',
365       scale_max => '50000',
366       description_en => 'Your home, work, friends, and other people',
367       description_de => 'Dein Zuhause, die Arbeitsstelle, Freunde, und andere Personen',
368       title_en => 'People',
369       title_de => 'Person',
370     },
371     { name => 'places',
372       poi_type_id => '10',
373       scale_min => '10000',
374       scale_max => '500000',
375       description_en => 'Settlements, Mountains, and other geographical stuff',
376       description_de => 'Siedlungen, Berggipfel, und anderes geografisches Zeug',
377       title_en => 'Place',
378       title_de => 'Ort',
379     },
380     { name => 'public',
381       poi_type_id => '11',
382       scale_min => '1',
383       scale_max => '25000',
384       description_en => 'Public facilities and Administration',
385       description_de => 'Verwaltung und andere &#246;ffentliche Einrichtungen',
386
387       title_en => 'Public',
388       title_de => '&#214;ffentlich',
389     },
390     { name => 'recreation',
391       poi_type_id => '12',
392       scale_min => '1',
393       scale_max => '25000',
394       description_en => 'Places used for recreation (no sports)',
395       description_de => 'Freizeiteinrichtungen (kein Sport)',
396       title_en => 'Recreation',
397       title_de => 'Freizeit',
398     },
399     { name => 'religion',
400       poi_type_id => '13',
401       scale_min => '1',
402       scale_max => '25000',
403       description_en => 'Places and facilities related to religion',
404       description_de => 'Kirchen und andere religi&#246;se Einrichtungen',
405       title_en => 'Religion',
406       title_de => 'Religion',
407     },
408     { name => 'shopping',
409       poi_type_id => '14',
410       scale_min => '1',
411       scale_max => '25000',
412       description_en => 'All the places, where you can buy something',
413       description_de => 'Orte, an denen man etwas k&#228;uflich erwerben kann',
414       title_en => 'Shopping',
415       title_de => 'Einkaufen',
416     },
417     { name => 'sightseeing',
418       poi_type_id => '15',
419       scale_min => '1',
420       scale_max => '25000',
421       description_en => 'Historic places and other interesting buildings',
422       description_de => 'Historische Orte und andere interessante Bauwerke',
423       title_en => 'Sightseeing',
424       title_de => 'Sehensw&#252;rdigkeit',
425     },
426     { name => 'sports',
427       poi_type_id => '16',
428       scale_min => '1',
429       scale_max => '25000',
430       description_en => 'Sports clubs, stadiums, and other sports facilities',
431       description_de => 'Sportpl&#228;tze und andere sportliche Einrichtungen',
432       title_en => 'Sports',
433       title_de => 'Sport',
434     },
435     { name => 'transport',
436       poi_type_id => '17',
437       scale_min => '1',
438       scale_max => '25000',
439       description_en => 'Airports and public transportation',
440       description_de => 'Flugh&#228;fen und &#246;ffentliche Transportmittel',
441       title_en => 'Public Transport',
442       title_de => '&#214;ffentliches Transportmittel',
443     },
444     { name => 'vehicle',
445       poi_type_id => '18',
446       scale_min => '1',
447       scale_max => '25000',
448       description_en => 'Facilites for drivers, like gas stations or parking places',
449       description_de => 'Dinge f&#252;r Selbstfahrer, z.B. Tankstellen oder Parkpl&#228;tze',
450       title_en => 'Vehicle',
451       title_de => 'Fahrzeug',
452     },
453     { name => 'wlan',
454       poi_type_id => '19',
455       scale_min => '1',
456       scale_max => '25000',
457       description_en => 'WiFi-related points (Kismet)',
458       description_de => 'Accesspoints und andere WLAN-Einrichtungen (Kismet)',
459       title_en => 'WLAN',
460       title_de => 'WLAN',
461     },
462     { name => 'misc',
463       poi_type_id => '20',
464       scale_min => '1',
465       scale_max => '25000',
466       description_en => 'POIs not suitable for another category, and custom types',
467       description_de => 'Eigenkreationen, und Punkte, die in keine der anderen Kategorien passen',
468       title_en => 'Miscellaneous',
469       title_de => 'Verschiedenes',
470     },
471     { name => 'waypoint',
472       poi_type_id => '21',
473       scale_min => '1',
474       scale_max => '50000',
475       description_en => 'Waypoints, for example  to temporarily mark several places',
476       description_de => 'Wegpunkte, um z.B. temporäre Punkte zu markieren',
477       title_en => 'Waypoint',
478       title_de => 'Wegpunkt',
479     },
480   
481   );
482
483   open NEWFILE,">:utf8","./$file_xml";
484   select NEWFILE;
485
486   print"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
487   print"<rules>\n\n";
488   foreach (@poi_types)
489     {
490       print"  <rule>\n";
491       print"    <condition k=\"poi\" v=\"$$_{'name'}\" />\n";
492       print"    <scale_min>$$_{'scale_min'}</scale_min>\n";
493       print"    <scale_max>$$_{'scale_max'}</scale_max>\n";
494       print"    <title lang=\"de\">$$_{'title_de'}</title>\n";
495       print"    <title lang=\"en\">$$_{'title_en'}</title>\n";
496       print"    <description lang=\"de\">$$_{'description_de'}</description>\n";
497       print"    <description lang=\"en\">$$_{'description_en'}</description>\n";
498       print"    <geoinfo>\n";
499       print"      <poi_type_id>$$_{'poi_type_id'}</poi_type_id>\n";
500       print"      <name>$$_{'name'}</name>\n";
501       print"    </geoinfo>\n";
502       print"  </rule>\n\n";
503       print STDOUT "  +  $$_{'poi_type_id'}\t\t$$_{'name'}\n" if $VERBOSE;
504     }
505   print "</rules>\n";
506 
507   close NEWFILE;
508
509   if (-e $file_xml)
510     { print STDOUT " New XML-File \"$file_xml\" successfully created!\n"; }
511   else
512     { die " ERROR: Failed in creating new XML-File \"$file_xml\" !\n"; }
513
514 }
515
516
517__END__
518
519
520=head1 SYNOPSIS
521 
522update_icons.pl [-h] [-v] [-i] [-r] [-f XML-FILE]
523 
524=head1 OPTIONS
525 
526=over 2
527 
528=item B<--h>
529
530 Show this help
531
532=item B<-f> XML-FILE
533
534 Set file, that holds all the necessary icon and poi_type information.
535 The default file is 'icons.xml'.
536
537=item B<-v>
538
539 Enable verbose output
540
541=back
Note: See TracBrowser for help on using the repository browser.