7 use Math::Trig qw(deg2rad pip2 great_circle_distance);
 
  12 my $source = shift @ARGV;
 
  13 my $zone = shift @ARGV;
 
  14 my $servers = YAML::LoadFile("src/${source}");
 
  18 my $countries = XML::TreeBuilder->new;
 
  20 $countries->parsefile("lib/countries.xml");
 
  22 foreach my $country ($countries->look_down("_tag" => "country"))
 
  24     my $code = $country->look_down("_tag" => "countryCode")->as_text;
 
  25     my $name = $country->look_down("_tag" => "countryName")->as_text;
 
  26     my $continent = $country->look_down("_tag" => "continent")->as_text;
 
  27     my $west = $country->look_down("_tag" => "bBoxWest")->as_text;
 
  28     my $north = $country->look_down("_tag" => "bBoxNorth")->as_text;
 
  29     my $east = $country->look_down("_tag" => "bBoxEast")->as_text;
 
  30     my $south = $country->look_down("_tag" => "bBoxSouth")->as_text;
 
  31     my $lat = centre_lat( $south, $north );
 
  32     my $lon = centre_lon( $west, $east );
 
  35     foreach my $servername (keys %$servers)
 
  37         my $server = $servers->{$servername};
 
  38         my $match = match_country($server, $code, $continent);
 
  40         if ($match eq "preferred" || $match eq "allowed")
 
  42             my $priority = $match eq "preferred" ? 20 : 10;
 
  43             my $distance = distance($lat, $lon, $server->{lat}, $server->{lon});
 
  45 #            print STDERR "$servername is $match for $name with distance $distance\n";
 
  47             push @servers, { name => $servername, priority => $priority, distance => $distance };
 
  52         code => $code, name => $name, continent => $continent,
 
  53         lat => $lat, lon => $lon, servers => \@servers
 
  59 my $zonefile = IO::File->new("> data/${zone}") || die "$!";
 
  60 my $kmlfile = IO::File->new("> kml/${zone}.kml") || die "$!";
 
  61 my $kmlwriter = XML::Writer->new(OUTPUT => $kmlfile, ENCODING => 'utf-8');
 
  63 $kmlwriter->xmlDecl();
 
  64 $kmlwriter->startTag("kml", "xmlns" => "http://www.opengis.net/kml/2.2");
 
  65 $kmlwriter->startTag("Document");
 
  67 foreach my $country (values %countries)
 
  69     my @servers = sort { $b->{priority} <=> $a->{priority} || $a->{distance} <=> $b->{distance} } @{$country->{servers}};
 
  70     my $server = $servers->{$servers[0]->{name}};
 
  71     my $clon = $country->{lon};
 
  72     my $clat = $country->{lat};
 
  73     my $slon = $server->{lon};
 
  74     my $slat = $server->{lat};
 
  76     if ($clon > 0 && $slon < 0 && 360 + $slon - $clon < $clon - $slon)
 
  81     $zonefile->print("C\L$country->{code}\E.${zone}:$servers[0]->{name}.${zone}:600\n");
 
  83     $kmlwriter->startTag("Placemark");
 
  84     $kmlwriter->dataElement("name", $country->{name});
 
  85     $kmlwriter->startTag("LineString");
 
  86     $kmlwriter->dataElement("coordinates", "$clon,$clat $slon,$slat");
 
  87     $kmlwriter->endTag("LineString");
 
  88     $kmlwriter->endTag("Placemark");
 
  91 foreach my $server (keys %$servers)
 
  93     $zonefile->print("Cxx.${zone}:${server}.${zone}:600\n");
 
  96 $kmlwriter->endTag("Document");
 
  97 $kmlwriter->endTag("kml");
 
 110     return ( $south + $north ) / 2;
 
 121         $lon = ( $west + $east ) / 2;
 
 125         $lon = ( $west + $east + 360 ) / 2;
 
 128     $lon = $lon - 360 if $lon > 180;
 
 137     my $continent = shift;
 
 140     if ($server->{preferred} &&
 
 141         $server->{preferred}->{countries} &&
 
 142         grep { $_ eq $country } @{$server->{preferred}->{countries}})
 
 144         $match = "preferred";
 
 146     elsif ($server->{preferred} &&
 
 147            $server->{preferred}->{continents} &&
 
 148            grep { $_ eq $continent } @{$server->{preferred}->{continents}})
 
 150         $match = "preferred";
 
 152     elsif ($server->{allowed} &&
 
 153            $server->{allowed}->{countries} &&
 
 154            grep { $_ eq $country } @{$server->{allowed}->{countries}})
 
 158     elsif ($server->{allowed} &&
 
 159            $server->{allowed}->{continents} &&
 
 160            grep { $_ eq $continent } @{$server->{allowed}->{continents}})
 
 164     elsif ($server->{allowed})
 
 178     my $lat1 = deg2rad(shift);
 
 179     my $lon1 = deg2rad(shift);
 
 180     my $lat2 = deg2rad(shift);
 
 181     my $lon2 = deg2rad(shift);
 
 183     return great_circle_distance($lon1, pip2 - $lat1, $lon2, pip2 - $lat2);