Radreise-Wiki:MakeGoogleMapsOverview.pl
Aus Radreise-Wiki
Version vom 8. September 2011, 09:45 Uhr von Jmages (Diskussion | Beiträge)
Das Perl-Skript makeGoogleMapsOverview.pl generiert ein KMZ-File mit der Übersicht aller Wiki-Strecken des Hauptnetzes. Zusätzlich wird die Konsistenz der Knotenpunkte (Anschlüsse) überprüft. Mit der erzeugten Radfernwege_Übersicht.kml können fehlende Anschlusspunkte schnell gefunden werden.
Einstellungen:
- my $showNodes = 0; Es werden keine Ortspunkte im Output-File gespeichert
- my $accuracy = 1000; Auflösung der Tracks in Meter.
Die generierte Datei kann als KMZ ins Wiki hochgeladen werden (siehe Datei:Radfernwege Übersicht.kmz).
use strict; use Encode qw(encode decode); my $encUTF8 = 'utf-8'; my $encAnsi = 'cp1252'; # Windows Ansi my $encOut = 'cp850' ; # DOS Fenster use URI::Escape qw( uri_escape_utf8 ); use CGI; my $cgi = new CGI; #========================= # Important Control-Flags my $showNodes = 1; my $accuracy = 000; #=========================== # Important Paths and Files require "ini.pl"; my ($baseDir, $outDir, $username, $password) = getIni(); my $dir_txt = "$baseDir/text"; my $dir_kml = "$baseDir/kml"; #========================== # Parsing aller Routefiles my $fileCounter = 0; my $routeName; my $routeFileName; my $routeURL; my $category; # ================== # Reading RouteList my @routeList; open FIN, "$baseDir/RouteList.txt" or die "$! : $baseDir/RouteList.txt"; while (<FIN>) { push @routeList, decode $encUTF8, $_; } close (FIN); my @routeFile = (); my @Fluss_Radfernweg = (); my @Anderer_Radfernweg = (); my @Querverbindung = (); my @Direktverbindung = (); my @Regionaler_Radwanderweg = (); my @AnschlussPlacemarks = (); my @RestPlacemarks = (); foreach my $line (@routeList) { (my $dateTXT, my $dateKML, my $type, $routeName) = split " :: ", $line; if ($type eq "H") { chomp($routeName); $routeFileName = encode $encAnsi, $routeName; my $urlstring = uri_escape_utf8($routeFileName); $urlstring =~ s/%20/\_/g; $urlstring =~ s/\(/%28/g; $urlstring =~ s/\)/%29/g; $urlstring =~ s/\'/%27/g; $routeURL = $urlstring; &process_txt_file; &saveRouteFile; } } print "\n $fileCounter Route-Files found\n\n"; #========================================================== # Generieren des Overview-Files my @rfwAllFile = (); push @rfwAllFile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; push @rfwAllFile, "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"; push @rfwAllFile, "<Document>\n"; push @rfwAllFile, "<Style id=\"green_site\">\n"; push @rfwAllFile, " <IconStyle>\n"; push @rfwAllFile, " <color>ff00f00f</color>\n"; push @rfwAllFile, " <scale>0.8</scale>\n"; push @rfwAllFile, " <Icon>\n"; push @rfwAllFile, " <href>D:/a/data/Radfernwege-Wiki/Tracks/placemark_circle.png</href>\n"; push @rfwAllFile, " </Icon>\n"; push @rfwAllFile, " </IconStyle>\n"; push @rfwAllFile, " <LabelStyle>\n"; push @rfwAllFile, " <scale>0.5</scale>\n"; push @rfwAllFile, " </LabelStyle>\n"; push @rfwAllFile, "</Style>\n"; push @rfwAllFile, " <name>Radfernwege_Übersicht</name>\n"; push @rfwAllFile, " <open>1</open>\n"; push @rfwAllFile, " <Folder>\n"; push @rfwAllFile, " <name>Fluss-Radfernweg</name>\n"; push @rfwAllFile, " <open>0</open>\n"; push @rfwAllFile, @Fluss_Radfernweg; push @rfwAllFile, " </Folder>\n"; push @rfwAllFile, " <Folder>\n"; push @rfwAllFile, " <name>Anderer Radfernweg</name>\n"; push @rfwAllFile, " <open>0</open>\n"; push @rfwAllFile, @Anderer_Radfernweg; push @rfwAllFile, " </Folder>\n"; push @rfwAllFile, " <Folder>\n"; push @rfwAllFile, " <name>Querverbindung</name>\n"; push @rfwAllFile, " <open>0</open>\n"; push @rfwAllFile, @Querverbindung; push @rfwAllFile, " </Folder>\n"; push @rfwAllFile, " <Folder>\n"; push @rfwAllFile, " <name>Direktverbindung</name>\n"; push @rfwAllFile, " <open>0</open>\n"; push @rfwAllFile, @Direktverbindung; push @rfwAllFile, " </Folder>\n"; #============================= # Bestimmung der Knotenpunkte if ($showNodes) { my %nodes; my $warning = 0; push @rfwAllFile, " <Folder>\n"; push @rfwAllFile, " <name>Knotenpunkte</name>\n"; push @rfwAllFile, " <open>0</open>\n"; for (my $i=0; $i<=$#AnschlussPlacemarks; $i++) { #unless ($warning) { print $#AnschlussPlacemarks-$i, "\n"; } for (my $j=0; $j<$i; $j++) { if ($AnschlussPlacemarks[$i][0] ne $AnschlussPlacemarks[$j][0]) { my $dist = getDistance ( $AnschlussPlacemarks[$i][2], $AnschlussPlacemarks[$i][3], $AnschlussPlacemarks[$j][2], $AnschlussPlacemarks[$j][3] ); if ($dist < 20) { push @rfwAllFile, " <Placemark>\n"; push @rfwAllFile, " <name>$AnschlussPlacemarks[$i][1] :: $AnschlussPlacemarks[$i][0]</name>\n"; push @rfwAllFile, " <styleUrl>green_site</styleUrl>\n"; push @rfwAllFile, " <visibility>0</visibility>\n"; push @rfwAllFile, " <Point>\n"; push @rfwAllFile, " <coordinates>\n"; push @rfwAllFile, " $AnschlussPlacemarks[$i][3],$AnschlussPlacemarks[$i][2]\n"; push @rfwAllFile, " </coordinates>\n"; push @rfwAllFile, " </Point>\n"; push @rfwAllFile, " </Placemark>\n"; push @rfwAllFile, " <Placemark>\n"; push @rfwAllFile, " <name>$AnschlussPlacemarks[$j][1] :: $AnschlussPlacemarks[$j][0]</name>\n"; push @rfwAllFile, " <styleUrl>green_site</styleUrl>\n"; push @rfwAllFile, " <visibility>0</visibility>\n"; push @rfwAllFile, " <Point>\n"; push @rfwAllFile, " <coordinates>\n"; push @rfwAllFile, " $AnschlussPlacemarks[$j][3],$AnschlussPlacemarks[$j][2]\n"; push @rfwAllFile, " </coordinates>\n"; push @rfwAllFile, " </Point>\n"; push @rfwAllFile, " </Placemark>\n"; my $co_1 = sprintf "%.4f %.4f", $AnschlussPlacemarks[$i][2],$AnschlussPlacemarks[$i][3]; my $co_2 = sprintf "%.4f %.4f", $AnschlussPlacemarks[$j][2],$AnschlussPlacemarks[$j][3]; if ($co_1 ne $co_2) { print " Koordinaten: $co_1\n $co_2\n\n"; $warning = 1; } if ($AnschlussPlacemarks[$i][1] ne $AnschlussPlacemarks[$j][1]) { print " Namen: $co_1\n $co_2\n\n"; $warning = 1; } if (defined $nodes{$co_1}) { } else { } } } } } push @rfwAllFile, " </Folder>\n"; # =============================================== # Write all Anschluss-Placemarks in extra Folder push @rfwAllFile, " <Folder>\n"; push @rfwAllFile, " <name>Anschluss-Placemarks</name>\n"; push @rfwAllFile, " <open>0</open>\n"; for (my $i=0; $i<=$#AnschlussPlacemarks; $i++) { push @rfwAllFile, " <Placemark>\n"; push @rfwAllFile, " <name>$AnschlussPlacemarks[$i][1]</name>\n"; push @rfwAllFile, " <visibility>0</visibility>\n"; push @rfwAllFile, " <description>\n"; push @rfwAllFile, " <![CDATA[<a href=\"http://radreise-wiki.de/$AnschlussPlacemarks[$i][4]#$AnschlussPlacemarks[$i][5]\">$AnschlussPlacemarks[$i][0]</a>]]> \n"; push @rfwAllFile, " </description>\n"; push @rfwAllFile, " <Point>\n"; push @rfwAllFile, " <coordinates>\n"; push @rfwAllFile, " $AnschlussPlacemarks[$i][3],$AnschlussPlacemarks[$i][2]\n"; push @rfwAllFile, " </coordinates>\n"; push @rfwAllFile, " </Point>\n"; push @rfwAllFile, " </Placemark>\n"; } push @rfwAllFile, " </Folder>\n"; # ========================================== # Write all Rest-Placemarks in extra Folder push @rfwAllFile, " <Folder>\n"; push @rfwAllFile, " <name>Rest-Placemarks</name>\n"; push @rfwAllFile, " <open>0</open>\n"; for (my $i=0; $i<=$#RestPlacemarks; $i++) { push @rfwAllFile, " <Placemark>\n"; push @rfwAllFile, " <name>$RestPlacemarks[$i][1]</name>\n"; push @rfwAllFile, " <visibility>0</visibility>\n"; push @rfwAllFile, " <description>\n"; push @rfwAllFile, " <![CDATA[<a href=\"http://radreise-wiki.de/$RestPlacemarks[$i][4]#$RestPlacemarks[$i][5]\">$RestPlacemarks[$i][0]</a>]]> \n"; push @rfwAllFile, " </description>\n"; push @rfwAllFile, " <Point>\n"; push @rfwAllFile, " <coordinates>\n"; push @rfwAllFile, " $RestPlacemarks[$i][3],$RestPlacemarks[$i][2]\n"; push @rfwAllFile, " </coordinates>\n"; push @rfwAllFile, " </Point>\n"; push @rfwAllFile, " </Placemark>\n"; } push @rfwAllFile, " </Folder>\n"; } #============================ # Write Footer and save File push @rfwAllFile, "</Document>\n"; push @rfwAllFile, "</kml>\n"; my $content = ""; foreach my $line (@rfwAllFile) { $content .= $line; } my $fileName = "Radfernwege_Übersicht.kml"; &saveFileIfChangedOrNew ("$baseDir/", $fileName, encode ($encUTF8, $content), 1); exit; #========================================================== #========================================================== sub saveRouteFile { if ($routeName ne "") { my @routeFileAll = (); push @routeFileAll, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; push @routeFileAll, "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"; push @routeFileAll, "<Document>\n"; push @routeFileAll, @routeFile; push @routeFileAll, "</Document>\n"; push @routeFileAll, "</kml>\n"; my $content = ""; foreach my $line (@routeFileAll) { $content .= $line; } if ($category eq "Fluss-Radfernweg") { push @Fluss_Radfernweg, " <Folder>\n"; push @Fluss_Radfernweg, @routeFile; push @Fluss_Radfernweg, " </Folder>\n"; } elsif ($category eq "Anderer Radfernweg") { push @Anderer_Radfernweg, " <Folder>\n"; push @Anderer_Radfernweg, @routeFile; push @Anderer_Radfernweg, " </Folder>\n"; } elsif ($category eq "Querverbindung") { push @Querverbindung, " <Folder>\n"; push @Querverbindung, @routeFile; push @Querverbindung, " </Folder>\n"; } elsif ($category eq "Direktverbindung") { push @Direktverbindung, " <Folder>\n"; push @Direktverbindung, @routeFile; push @Direktverbindung, " </Folder>\n"; } elsif ($category eq "Regionaler Radwanderweg") { @Regionaler_Radwanderweg = (); } elsif ($category eq "Routenplaner Testroute") { # do nothing } else { print "Error: No matching Category: $category\n"; exit; } } } #========================================================== sub process_txt_file { if (open(FILE, "$baseDir/text/$routeFileName.txt")) { # legal file found print encode $encOut, "$routeName\n"; my $trackData = ""; my @placeList = (); $fileCounter++; my $ucontent = ""; while (<FILE>) { $ucontent .= $_; } close FILE; my $content = decode ($encUTF8, $ucontent); if ($content !~ / {{TOC_Radfernweg}}\n .* \n==\ Roadbook\ ==\n .* \n==\ GPS-Tracks\ ==\n .* \[\[Kategorie:\s*( Fluss-Radfernweg| Anderer\ Radfernweg| Querverbindung| Regionaler\ Radwanderweg| Streckenvorschlag| Direktverbindung| Stadtrundfahrt )\]\] /xs) { print encode $encOut, "Chapters in $routeName are not correct!\n"; exit(1); } $category = $1; if ($category eq "Regionaler Radwanderweg") { $category = "Querverbindung"; } if ($category eq "Streckenvorschlag") { $category = "Querverbindung"; } if ($category eq "Stadtrundfahrt") { $category = "Querverbindung"; } my $color = "ffffffff"; if ($category eq "Fluss-Radfernweg") { $color = "ffff0000"; # Blau } if ($category eq "Anderer Radfernweg") { $color = "ff00ff00"; # Grün } if ($category eq "Querverbindung") { $color = "ff00ffff"; # Gelb } if ($category eq "Direktverbindung") { $color = "ff0000ff"; # Rot } my @content = split "\n", $content; @routeFile = (); push @routeFile, " <name>$routeName</name>\n"; push @routeFile, " <Metadata>\n"; push @routeFile, " <![CDATA[<!--$routeURL-->]]>\n"; push @routeFile, " </Metadata>\n"; push @routeFile, " <open>0</open>\n"; my $roadBook = 0; my $place = 0; my $touri = 0; my $geo = 0; my $lon = 0; my $lat = 0; my $alt = 0; my $road = 0; my $kilo = 0; my $placeName = ""; my $touriInfo = ""; my $geoData = ""; my $roadInfo = ""; my $kilometer = ""; foreach my $line (@content) { # Last Placemark is finished, Roadbook is finished if (($roadBook) and ($line =~ /^== .* ==$/)) { # Status-Übersicht if ($touriInfo ne "") { $touri = 1; } if ($roadInfo ne "") { $road = 1; } my $placeNameURL = $cgi->escape($placeName); $placeNameURL =~ s/\%20/\_/g; $placeNameURL =~ s/\%/\./g; if ($touriInfo =~ /\* Anschl[u|ü]ss[^\n]*\[\[/) { my @info = ( $routeName, $placeName, $lat, $lon, $routeURL, $placeNameURL); my $ref_zeile = \@info; push @AnschlussPlacemarks, $ref_zeile; push @placeList, $ref_zeile; } else { my @info = ( $routeName, $placeName, $lat, $lon, $routeURL, $placeNameURL); my $ref_zeile = \@info; push @RestPlacemarks, $ref_zeile; push @placeList, $ref_zeile; } $trackData .= "$lon,$lat,$alt "; $roadBook = 0; $place = 0; $touri = 0; $geo = 0; $lon = 0; $lat = 0; $alt = 0; $road = 0; $kilo = 0; $placeName = ""; $touriInfo = ""; $geoData = ""; $roadInfo = ""; $kilometer = ""; # Start of Roadbook } elsif ($line =~ /^== Roadbook ==$/) { $roadBook = 1; # A new Place within the Roadbook } elsif ($roadBook and ($line =~ /^=== (.*) ===$/)) { if ($place and not $kilo) { print " No Kilometers: $routeName :: $placeName\n"; #exit; } # Save previous place if ($place) { # Status-Übersicht if ($touriInfo ne "") { $touri = 1; } if ($roadInfo ne "") { $road = 1; } my $placeNameURL = $cgi->escape($placeName); $placeNameURL =~ s/\%20/\_/g; $placeNameURL =~ s/\%/\./g; if ($touriInfo =~ /\* Anschl[u|ü]ss[^\n]*\[\[/) { my @info = ( $routeName, $placeName, $lat, $lon, $routeURL, $placeNameURL); my $ref_zeile = \@info; push @AnschlussPlacemarks, $ref_zeile; push @placeList, $ref_zeile; } else { my @info = ( $routeName, $placeName, $lat, $lon, $routeURL, $placeNameURL); my $ref_zeile = \@info; push @RestPlacemarks, $ref_zeile; push @placeList, $ref_zeile; } $trackData .= "$lon,$lat,$alt "; } $place = 1; $touri = 0; $geo = 0; $lon = 0; $lat = 0; $alt = 0; $road = 0; $kilo = 0; $placeName = $1; $touriInfo = ""; $geoData = ""; $roadInfo = ""; $kilometer = ""; # Geodata within the Placemark } elsif ($place and ($line =~ /^{{Geodaten\|(.*)}}$/)) { $geo = 1; $geoData = $1; if ($geoData =~ /^([-]?\d+\.\d+)\|([-]?\d+\.\d+)\|([-]?\d+)\|([^\|]+)$/) { $lat = $1; $lon = $2; $alt = $3; } else { print "Error in Geodata: $routeName :: $placeName: $geoData\n"; exit; } # Kilometrierung within Placemark } elsif ($place and ($line =~ /^{{Kilometrierung\|(.*)}}$/)) { if (not $geo) { print "No Coordinates: $routeName :: $placeName\n"; exit; } if ($kilo) { print " Multiple Kilometers: $routeName :: $placeName\n"; #exit; } $kilo = 1; $kilometer = $1; # KilometrierungHm within Placemark } elsif ($place and ($line =~ /^{{KilometrierungHm\|(.*)}}$/)) { if (not $geo) { print "No Coordinates: $routeName :: $placeName\n"; exit; } if ($kilo) { print " Multiple Kilometers: $routeName :: $placeName\n"; #exit; } $kilo = 1; $kilometer = $1; #print " $kilometer\n"; # Empty Line } elsif ($line =~ /^\s*$/) { } elsif ($line =~ /<br style="clear:both" \/>/) { } elsif ($line =~ /\[\[Bild/) { } elsif ($place and not $geo and not $kilo) { $touriInfo .= "$line\n"; } elsif ($place and $geo and not $kilo) { $roadInfo .= "$line\n"; } } if (($accuracy) and (open(FILE, "$baseDir/tracks/$routeFileName.txt"))) { my $rawTrack = <FILE>; close FILE; my @rawTrack = split " ", $rawTrack; my @track = (); my @trackNew = (); foreach (@rawTrack) { my ($lon, $lat, $alt) = split ","; my @zeile = ( $lat, $lon, $alt ); my $ref_zeile = \@zeile; push @track, $ref_zeile; } my @zeile = ( $track[0][1], $track[0][0] ); my $ref_zeile = \@zeile; push @trackNew, $ref_zeile; my $length = 0; for (my $i = 0; $i < $#track ; $i++) { my $dist = getDistance ( $track[$i][0], $track[$i][1], $track[$i+1][0], $track[$i+1][1] ); $length += $dist; if ($length > $accuracy) { my @zeile = ( $track[$i+1][1], $track[$i+1][0] ); my $ref_zeile = \@zeile; push @trackNew, $ref_zeile; $length = 0; } } my @zeile = ( $track[$#track][1], $track[$#track][0] ); my $ref_zeile = \@zeile; push @trackNew, $ref_zeile; for (my $i = 0; $i <= $#placeList ; $i++) { my $minDist = 111111111; my $point = -1; for (my $j = 0; $j <= $#trackNew ; $j++) { my $dist = getDistance ( $trackNew[$j][1], $trackNew[$j][0], $placeList[$i][2], $placeList[$i][3] ); if ($dist < $minDist) { $minDist = $dist; $point = $j; } } $trackNew[$point][1] = $placeList[$i][2]; $trackNew[$point][0] = $placeList[$i][3]; } $trackData = ""; for (my $i = 0; $i <= $#trackNew ; $i++) { $trackData .= sprintf "%.4f,%.4f ", $trackNew[$i][0], $trackNew[$i][1]; } } push @routeFile, " <Placemark>\n"; push @routeFile, " <name>$routeName</name>\n"; push @routeFile, " <description>\n"; push @routeFile, " <![CDATA[<a href=\"http://radreise-wiki.de/$routeURL\">Wiki</a>]]> \n"; push @routeFile, " </description>\n"; push @routeFile, " <Style>\n"; push @routeFile, " <LineStyle>\n"; push @routeFile, " <color>$color</color>\n"; push @routeFile, " <colorMode>random</colorMode>\n"; push @routeFile, " <width>2</width>\n"; push @routeFile, " </LineStyle>\n"; push @routeFile, " </Style>\n"; push @routeFile, " <LineString>\n"; push @routeFile, " <tessellate>1</tessellate>\n"; push @routeFile, " <coordinates>\n"; push @routeFile, " $trackData\n"; push @routeFile, " </coordinates>\n"; push @routeFile, " </LineString>\n"; push @routeFile, " </Placemark>\n"; } } #========================================================== use Digest::MD5; qw(md5_hex); use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); sub saveFileIfChangedOrNew { (my $path, my $fileName, my $file, my $kmz) = @_; if (open(FILE, "< $path$fileName")) { my $md5 = Digest::MD5->new; while (<FILE>) { $md5->add($_); } close(FILE); my $md5_old = $md5->hexdigest; $md5 = Digest::MD5->new; $md5->add($file); my $md5_new = $md5->hexdigest; unless ($md5_old eq $md5_new) { print encode $encOut, "****************** Overwriting file $fileName ******************\n"; open FT,"> $path$fileName"; print FT $file; close FT; if ($kmz) { my $zip = Archive::Zip->new(); $zip->addFile("$path$fileName",$fileName); $fileName =~ s/\.kml/\.kmz/; unless ( $zip->writeToFileNamed("$outDir/$fileName") == AZ_OK ) { die 'write error'; } } } } else { print encode $encOut, "****************** Creating new file $fileName ******************\n"; open FT,"> $path$fileName"; print FT $file; close FT; if ($kmz) { my $zip = Archive::Zip->new(); $zip->addFile("$path$fileName",$fileName); $fileName =~ s/\.kml/\.kmz/; unless ( $zip->writeToFileNamed("$outDir/$fileName") == AZ_OK ) { die 'write error'; } } } } #========================================================== sub getDistance { use POSIX qw(acos); my ($tp1_lat, $tp1_lon, $tp2_lat, $tp2_lon) = @_; my $PI = 3.1415926; my $lat1 = $tp1_lat / 180 * $PI; my $lon1 = $tp1_lon / 180 * $PI; my $lat2 = $tp2_lat / 180 * $PI; my $lon2 = $tp2_lon / 180 * $PI; my $val = sin($lat1) * sin($lat2) + cos($lat1) * cos($lat2) * cos($lon2-$lon1); if ($val > +1) { $val = +1; #print " ACOS-Error: $tp1_lon,$tp1_lat !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; } if ($val < -1) { $val = -1; #print " ACOS-Error: $tp1_lon,$tp1_lat !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; } my $dist = acos($val) * 6378.137; # radius of the equator in km #if (Double.isNaN(dist)) dist = 0; return $dist*1000; } #========================================================== sub del_double { my %all = (); @all{@_} = 1; return (keys %all); }