Radreise-Wiki:MakeGoogleMapsOverview.pl
Aus Radreise-Wiki
Version vom 20. Juni 2011, 20:52 Uhr von Jmages (Diskussion | Beiträge) (1000 m Auflösung der Tracks)
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.
Nach dem Löschen der KML-Unterordner "Knotenpunkte", "Anschluss-Placemarks" und "Rest-Placemarks" kann die Datei als gezipptes 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 = 0;
my $accuracy = 1000;
#===========================
# 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, $routeURL) = split " :: ", $line;
#if (($type eq "H") or ($type eq "h")) {
if ($type eq "H") {
$routeFileName = encode $encAnsi, $routeName;
chomp($routeURL);
&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);
}