diff --git a/configure.ac b/configure.ac
index 033bd57c..5093078d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -424,6 +424,7 @@ AC_CONFIG_FILES([ \
 	src/Prep/TGVPF/Makefile \
 	src/Prep/Terra/Makefile \
 	src/Prep/TerraFit/Makefile \
+	src/Prep/Tower/Makefile \
 	src/Prep/UserDef/Makefile \
 	src/Utils/Makefile \
 	src/Utils/cdrom/Makefile \
diff --git a/src/BuildTiles/Main/main.cxx b/src/BuildTiles/Main/main.cxx
index d3451187..0caf156a 100644
--- a/src/BuildTiles/Main/main.cxx
+++ b/src/BuildTiles/Main/main.cxx
@@ -1020,9 +1020,9 @@ static void do_custom_objects( const TGConstruct& c ) {
                     cout << "running " << command << endl;
                     system( command.c_str() );
 
-                    fprintf(fp, "OBJECT %s\n", name.c_str());
+                    fprintf(fp, "OBJECT %s\n", name);
                 } else {
-                    fprintf(fp, "%s\n", line.c_str());
+                    fprintf(fp, "%s\n", line);
                 }
 	    }
 	}
diff --git a/src/BuildTiles/Parallel/fgfs-launch-clients b/src/BuildTiles/Parallel/fgfs-launch-clients
index 54fc0e25..a1aaa5b1 100755
--- a/src/BuildTiles/Parallel/fgfs-launch-clients
+++ b/src/BuildTiles/Parallel/fgfs-launch-clients
@@ -101,7 +101,7 @@ for i in $CLIENTS_RUDE; do
     # ssh -n $i "$KILL_COMMAND"
 
     # RMT_COMMAND="source ~/.profile; nice $CLIENT --host=$SERVER_HOST --port=$SERVER_PORT --work-dir=$WORK_BASE --output-dir=$OUTPUT_DIR --rude --cover=$WORK_BASE/LC-Global/gusgs2_0ll.img AirportArea AirportObj GSHHS-Ponds GSHHS-Islands GSHHS-Lakes GSHHS-LandMass USA-Hydro USA-Urban SRTM-United_States-1 SRTM-North_America-3 SRTM-South_America-3 SRTM-Eurasia-3 DEM-USGS-3 SRTM-30"
-    RMT_COMMAND="source ~/.profile; nice $CLIENT --host=$SERVER_HOST --port=$SERVER_PORT --work-dir=$WORK_BASE --output-dir=$OUTPUT_DIR --rude AirportArea AirportObj GSHHS-LandMass VPF-Canals VPF-Cities VPF-FloodLand VPF-Lakes VPF-LandCover VPF-Railroads VPF-Rivers VPF-Roads VPF-Towns SRTM-United_States-1 SRTM-North_America-3 SRTM-South_America-3 SRTM-Eurasia-3 DEM-USGS-3 SRTM-30"
+    RMT_COMMAND="source ~/.profile; nice $CLIENT --host=$SERVER_HOST --port=$SERVER_PORT --work-dir=$WORK_BASE --output-dir=$OUTPUT_DIR --rude AirportArea AirportObj GSHHS-LandMass VPF-Canals VPF-Cities VPF-FloodLand VPF-Lakes VPF-LandCover VPF-Railroads VPF-Rivers VPF-Roads VPF-Towns TowerObj SRTM-United_States-1 SRTM-North_America-3 SRTM-South_America-3 SRTM-Eurasia-3 SRTM-Africa-3 DEM-USGS-3 SRTM-30"
     echo "client command:"
     echo ""
     echo "$RMT_COMMAND"
diff --git a/src/Prep/Makefile.am b/src/Prep/Makefile.am
index 373d05b2..b651ca51 100644
--- a/src/Prep/Makefile.am
+++ b/src/Prep/Makefile.am
@@ -11,4 +11,5 @@ SUBDIRS = \
 	TGVPF \
 	Terra \
 	TerraFit \
+	Tower \
 	UserDef
diff --git a/src/Prep/Tower/Makefile.am b/src/Prep/Tower/Makefile.am
new file mode 100644
index 00000000..baa23b3d
--- /dev/null
+++ b/src/Prep/Tower/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = calc_tile.pl tower.pl
diff --git a/src/Prep/Tower/calc-tile.pl b/src/Prep/Tower/calc-tile.pl
new file mode 100644
index 00000000..44dc1a40
--- /dev/null
+++ b/src/Prep/Tower/calc-tile.pl
@@ -0,0 +1,161 @@
+#!/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.
+########################################################################
+
+if ( 0 ) {
+    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;
diff --git a/src/Prep/Tower/tower.pl b/src/Prep/Tower/tower.pl
new file mode 100755
index 00000000..87ba2d75
--- /dev/null
+++ b/src/Prep/Tower/tower.pl
@@ -0,0 +1,125 @@
+#!/usr/bin/perl
+
+use strict;
+
+require "calc-tile.pl";
+
+my( $arg );
+my( $infile ) = "";
+my( $outdir ) = "";
+
+sub usage {
+    die "Usage: $0 --input=<infile> --outdir=<output_dir_tree>\n";
+}
+
+
+# process arguments
+while( $arg = shift(@ARGV) ) {
+    if ( $arg =~ m/^--input=/ ) {
+        $arg =~ s/^--input=//;
+        $infile = $arg;
+        print "infile = $infile\n";
+    } elsif ( $arg =~ m/^--outdir=/ ) {
+        $arg =~ s/^--outdir=//;
+        $outdir = $arg;
+        print "outdir = $outdir\n";
+    } else {
+        usage();
+    }
+}
+
+if ( $infile eq "" || $outdir eq "" ) {
+    usage();
+}
+
+open( IN, "<$infile" ) || die "Cannot open $infile\n";
+
+my( @F );
+my( $total ) = 0.0;
+my( $count ) = 0;
+my( $shortcount ) = 0;
+my( $mediumcount ) = 0;
+my( $tallcount ) = 0;
+my( $min ) = 10000.0;
+my( $max ) = 0.0;
+
+while( <IN> ) {
+    # print "-> $_";
+    @F = split( /\|/, $_ );
+
+    my( $lat ) = $F[3] + $F[4]/60.0 + $F[5]/3600.0;
+    my( $lon ) = $F[8] + $F[9]/60.0 + $F[10]/3600.0;
+
+    # strip white space
+    $F[6] =~ s/\s+//g;
+    $F[11] =~ s/\s+//g;
+
+    if ( $F[6] eq "" || $F[6] eq " " || $F[6] eq "N" ) {
+        # do nothing
+    } else {
+        print $_;
+        $lat = -$lat;
+    }
+    if ( $F[11] eq "" || $F[11] eq " " || $F[11] eq "W" ) {
+        $lon = -$lon
+    } else {
+        # do nothing
+        print $_;
+    }
+
+    my( $ground ) = $F[13];
+    my( $height ) = $F[14];
+    my( $top_msl ) = $F[15];
+
+    if ( $height < $min ) {
+        $min = $height;
+    }
+    if ( $height > $max ) {
+        $max = $height;
+    }
+    $total += $height;
+    $count++;
+
+    my( $dir ) = directory_name($lon, $lat);
+    my( $index ) = tile_index($lon, $lat);
+
+    my( $model ) = "";
+    my( $base_elev ) = 0.0;
+
+    if ( $height < 50.0 ) {
+        # short tower
+        $model = "radio_short.xml";
+        $base_elev = $top_msl - 50.0;
+        $shortcount++;
+    } elsif ( $height < 100.0 ) {
+        # medium tower
+        $model = "radio_medium.xml";
+        $base_elev = $top_msl - 100.0;
+        $mediumcount++;
+    } else {
+        # tall tower
+        $model = "radio_tall.xml";
+        $base_elev = $top_msl - 610.0;
+        $tallcount++;
+    }
+
+    # printf("%11.6f %10.6f %.1f %.1f %.1f \n",
+    #        $lon, $lat, $ground, $height, $top_msl);
+    printf(" %s/%s/%s.ind -> OBJECT_SHARED %s %.6f %.6f %.1f 0.00\n", $outdir, $dir, $index, $model, $lon, $lat, $base_elev );
+
+    system( "mkdir -p $outdir/$dir" );
+    
+    my( $indfile ) = "$outdir/$dir/$index.ind";
+    open( INDEX, ">>$indfile" );
+    printf( INDEX "OBJECT_SHARED %s %.6f %.6f %.1f 0.00\n",
+            $model, $lon, $lat, $base_elev );
+}
+
+print "short count = $shortcount\n";
+print "medium count = $mediumcount\n";
+print "tall count = $tallcount\n";
+
+print "average height = " . $total / $count . "\n";
+print "min = $min  max = $max\n";
+
+close( IN );