--- /dev/null
+#!/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;
+
+
+\f
+########################################################################
+# Constants.
+########################################################################
+
+my $EPSILON = 0.0000001;
+my $DIRSEP = '/';
+
+
+\f
+########################################################################
+# 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;
+}
+
+
+\f
+########################################################################
+# 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;