160 lines
3.3 KiB
Perl
160 lines
3.3 KiB
Perl
#!/usr/bin/perl -w
|
||
########################################################################
|
||
# calc-tile.pl
|
||
#
|
||
# Synopsis: Calculate a FlightGear tile base on longitude and latitude.
|
||
# Usage: perl calc-tile.pl <lon> <lat>
|
||
########################################################################
|
||
|
||
use strict;
|
||
use POSIX;
|
||
|
||
|
||
|
||
########################################################################
|
||
# Constants.
|
||
########################################################################
|
||
|
||
my $EPSILON = 0.0000001;
|
||
my $DIRSEP = '/';
|
||
|
||
|
||
|
||
########################################################################
|
||
# Functions.
|
||
########################################################################
|
||
|
||
#
|
||
# Calculate the number of columns of tiles in a degree of longitude.
|
||
#
|
||
sub bucket_span {
|
||
my ($lat) = (@_);
|
||
if ($lat>= 89.0 ) {
|
||
return 360.0;
|
||
} elsif ($lat>= 88.0 ) {
|
||
return 8.0;
|
||
} elsif ($lat>= 86.0 ) {
|
||
return 4.0;
|
||
} elsif ($lat>= 83.0 ) {
|
||
return 2.0;
|
||
} elsif ($lat>= 76.0 ) {
|
||
return 1.0;
|
||
} elsif ($lat>= 62.0 ) {
|
||
return 0.5;
|
||
} elsif ($lat>= 22.0 ) {
|
||
return 0.25;
|
||
} elsif ($lat>= -22.0 ) {
|
||
return 0.125;
|
||
} elsif ($lat>= -62.0 ) {
|
||
return 0.25;
|
||
} elsif ($lat>= -76.0 ) {
|
||
return 0.5;
|
||
} elsif ($lat>= -83.0 ) {
|
||
return 1.0;
|
||
} elsif ($lat>= -86.0 ) {
|
||
return 2.0;
|
||
} elsif ($lat>= -88.0 ) {
|
||
return 4.0;
|
||
} elsif ($lat>= -89.0 ) {
|
||
return 8.0;
|
||
} else {
|
||
return 360.0;
|
||
}
|
||
}
|
||
|
||
#
|
||
# Format longitude as e/w.
|
||
#
|
||
sub format_lon {
|
||
my ($lon) = (@_);
|
||
if ($lon < 0) {
|
||
return sprintf("w%03d", int(0-$lon));
|
||
} else {
|
||
return sprintf("e%03d", int($lon));
|
||
}
|
||
}
|
||
|
||
#
|
||
# Format latitude as n/s.
|
||
#
|
||
sub format_lat {
|
||
my ($lat) = (@_);
|
||
if ($lat < 0) {
|
||
return sprintf("s%02d", int(0-$lat));
|
||
} else {
|
||
return sprintf("n%02d", int($lat));
|
||
}
|
||
}
|
||
|
||
#
|
||
# Generate the directory name for a location.
|
||
#
|
||
sub directory_name {
|
||
my ($lon, $lat) = (@_);
|
||
my $lon_floor = POSIX::floor($lon);
|
||
my $lat_floor = POSIX::floor($lat);
|
||
my $lon_chunk = POSIX::floor($lon/10.0) * 10;
|
||
my $lat_chunk = POSIX::floor($lat/10.0) * 10;
|
||
return format_lon($lon_chunk) . format_lat($lat_chunk) . $DIRSEP
|
||
. format_lon($lon_floor) . format_lat($lat_floor);
|
||
}
|
||
|
||
#
|
||
# Generate the tile index for a location.
|
||
#
|
||
sub tile_index {
|
||
my ($lon, $lat) = (@_);
|
||
my $lon_floor = POSIX::floor($lon);
|
||
my $lat_floor = POSIX::floor($lat);
|
||
my $span = bucket_span($lat);
|
||
|
||
my $x;
|
||
if ($span < $EPSILON) {
|
||
$lon = 0;
|
||
$x = 0;
|
||
} elsif ($span <= 1.0) {
|
||
$x = int(($lon - $lon_floor) / $span);
|
||
} else {
|
||
if ($lon >= 0) {
|
||
$lon = int(int($lon/$span) * $span);
|
||
} else {
|
||
$lon = int(int(($lon+1)/$span) * $span - $span);
|
||
if ($lon < -180) {
|
||
$lon = -180;
|
||
}
|
||
}
|
||
$x = 0;
|
||
}
|
||
|
||
my $y;
|
||
$y = int(($lat - $lat_floor) * 8);
|
||
|
||
|
||
my $index = 0;
|
||
$index += ($lon_floor + 180) << 14;
|
||
$index += ($lat_floor + 90) << 6;
|
||
$index += $y << 3;
|
||
$index += $x;
|
||
|
||
return $index;
|
||
}
|
||
|
||
|
||
|
||
########################################################################
|
||
# Main program.
|
||
########################################################################
|
||
|
||
my ($lon, $lat) = (@ARGV);
|
||
|
||
my $dir = directory_name($lon, $lat);
|
||
my $index = tile_index($lon, $lat);
|
||
my $path = "$dir$DIRSEP$index.stg";
|
||
|
||
print "Longitude: $lon\n";
|
||
print "Latitude: $lat\n";
|
||
print "Tile: $index\n";
|
||
print "Path: \"$path\"\n";
|
||
|
||
1;
|