Radreise-Wiki:MakeGoogleMapsOverview.pl

Aus Radreise-Wiki

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 = 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);
 }