1#!/usr/bin/perl -w 2######################################################################## 3# calc-tile.pl 4# 5# Synopsis: Calculate a FlightGear tile base on longitude and latitude. 6# Usage: perl calc-tile.pl <lon> <lat> 7######################################################################## 8 9use strict; 10use POSIX; 11 12 13 14######################################################################## 15# Constants. 16######################################################################## 17 18my $EPSILON = 0.0000001; 19my $DIRSEP = '/'; 20 21 22 23######################################################################## 24# Functions. 25######################################################################## 26 27# 28# Calculate the number of columns of tiles in a degree of longitude. 29# 30sub bucket_span { 31 my ($lat) = (@_); 32 if ($lat>= 89.0 ) { 33 return 360.0; 34 } elsif ($lat>= 88.0 ) { 35 return 8.0; 36 } elsif ($lat>= 86.0 ) { 37 return 4.0; 38 } elsif ($lat>= 83.0 ) { 39 return 2.0; 40 } elsif ($lat>= 76.0 ) { 41 return 1.0; 42 } elsif ($lat>= 62.0 ) { 43 return 0.5; 44 } elsif ($lat>= 22.0 ) { 45 return 0.25; 46 } elsif ($lat>= -22.0 ) { 47 return 0.125; 48 } elsif ($lat>= -62.0 ) { 49 return 0.25; 50 } elsif ($lat>= -76.0 ) { 51 return 0.5; 52 } elsif ($lat>= -83.0 ) { 53 return 1.0; 54 } elsif ($lat>= -86.0 ) { 55 return 2.0; 56 } elsif ($lat>= -88.0 ) { 57 return 4.0; 58 } elsif ($lat>= -89.0 ) { 59 return 8.0; 60 } else { 61 return 360.0; 62 } 63} 64 65# 66# Format longitude as e/w. 67# 68sub format_lon { 69 my ($lon) = (@_); 70 if ($lon < 0) { 71 return sprintf("w%03d", int(0-$lon)); 72 } else { 73 return sprintf("e%03d", int($lon)); 74 } 75} 76 77# 78# Format latitude as n/s. 79# 80sub format_lat { 81 my ($lat) = (@_); 82 if ($lat < 0) { 83 return sprintf("s%02d", int(0-$lat)); 84 } else { 85 return sprintf("n%02d", int($lat)); 86 } 87} 88 89# 90# Generate the directory name for a location. 91# 92sub directory_name { 93 my ($lon, $lat) = (@_); 94 my $lon_floor = POSIX::floor($lon); 95 my $lat_floor = POSIX::floor($lat); 96 my $lon_chunk = POSIX::floor($lon/10.0) * 10; 97 my $lat_chunk = POSIX::floor($lat/10.0) * 10; 98 return format_lon($lon_chunk) . format_lat($lat_chunk) . $DIRSEP 99 . format_lon($lon_floor) . format_lat($lat_floor); 100} 101 102# 103# Generate the tile index for a location. 104# 105sub tile_index { 106 my ($lon, $lat) = (@_); 107 my $lon_floor = POSIX::floor($lon); 108 my $lat_floor = POSIX::floor($lat); 109 my $span = bucket_span($lat); 110 111 my $x; 112 if ($span < $EPSILON) { 113 $lon = 0; 114 $x = 0; 115 } elsif ($span <= 1.0) { 116 $x = int(($lon - $lon_floor) / $span); 117 } else { 118 if ($lon >= 0) { 119 $lon = int(int($lon/$span) * $span); 120 } else { 121 $lon = int(int(($lon+1)/$span) * $span - $span); 122 if ($lon < -180) { 123 $lon = -180; 124 } 125 } 126 $x = 0; 127 } 128 129 my $y; 130 $y = int(($lat - $lat_floor) * 8); 131 132 133 my $index = 0; 134 $index += ($lon_floor + 180) << 14; 135 $index += ($lat_floor + 90) << 6; 136 $index += $y << 3; 137 $index += $x; 138 139 return $index; 140} 141 142 143 144######################################################################## 145# Main program. 146######################################################################## 147 148my ($lon, $lat) = (@ARGV); 149 150my $dir = directory_name($lon, $lat); 151my $index = tile_index($lon, $lat); 152my $path = "$dir$DIRSEP$index.stg"; 153 154print "Longitude: $lon\n"; 155print "Latitude: $lat\n"; 156print "Tile: $index\n"; 157print "Path: \"$path\"\n"; 158 1591; 160