Imported Upstream version 1.2.1
[debian/splat] / splat.cpp
index 3e17692aafa79b69d410cb869cc403462873f38d..9a96ef989b6f5cecc3559c5684d204033ea0ce40 100644 (file)
--- a/splat.cpp
+++ b/splat.cpp
@@ -1,30 +1,26 @@
-/****************************************************************************
-*      SPLAT: An RF Signal Propagation Loss and Terrain Analysis Tool       *
-*                        Last update: 31-Mar-2006                          *
-*****************************************************************************
-*           Project started in 1997 by John A. Magliacane, KD2BD           *
-*****************************************************************************
-*                                                                          *
-*     Extensively modified by J. D. McDonald in Jan. 2004 to include        *
-*    the Longley-Rice propagation model using C++ code from NTIA/ITS.      *
-*                                                                          *
-*              See: http://flattop.its.bldrdoc.gov/itm.html                 *
-*                                                                          *
-*****************************************************************************
-*                                                                           *
-* This program is free software; you can redistribute it and/or modify it   *
-* under the terms of the GNU General Public License as published by the     *
-* Free Software Foundation; either version 2 of the License or any later    *
-* version.                                                                 *
-*                                                                          *
-* This program is distributed in the hope that it will useful, but WITHOUT  *
-* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     *
-* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License     *
-* for more details.                                                        *
-*                                                                          *
-*****************************************************************************
- g++ -Wall -O3 -s -lm -lbz2 -fomit-frame-pointer itm.cpp splat.cpp -o splat 
-*****************************************************************************/
+/****************************************************************************\
+*         SPLAT!: An RF Signal Path Loss And Terrain Analysis Tool          *
+******************************************************************************
+*           Project started in 1997 by John A. Magliacane, KD2BD            *
+*                        Last update: 19-Oct-2007                           *
+******************************************************************************
+*         Please consult the documentation for a complete list of           *
+*           individuals who have contributed to this project.               *
+******************************************************************************
+*                                                                            *
+*  This program is free software; you can redistribute it and/or modify it   *
+*  under the terms of the GNU General Public License as published by the     *
+*  Free Software Foundation; either version 2 of the License or any later    *
+*  version.                                                                 *
+*                                                                           *
+*  This program is distributed in the hope that it will useful, but WITHOUT  *
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     *
+*  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License     *
+*  for more details.                                                        *
+*                                                                           *
+******************************************************************************
+* g++ -Wall -O3 -s -lm -lbz2 -fomit-frame-pointer itm.cpp splat.cpp -o splat * 
+\****************************************************************************/
 
 #include <stdio.h>
 #include <math.h>
 #include <bzlib.h>
 #include <unistd.h>
 #include "fontdata.h"
-#include "smallfont.h"
 
 #define GAMMA 2.5
-#define MAXSLOTS 9
+#define MAXPAGES 9
 #define BZBUFFER 65536
 
-#if MAXSLOTS==4
+#if MAXPAGES==4
 #define ARRAYSIZE 4950
 #endif
 
-#if MAXSLOTS==9
+#if MAXPAGES==9
 #define ARRAYSIZE 10870
 #endif
 
-#if MAXSLOTS==16
+#if MAXPAGES==16
 #define ARRAYSIZE 19240
 #endif
 
-#if MAXSLOTS==25
+#if MAXPAGES==25
 #define ARRAYSIZE 30025
 #endif
 
-char   string[255], sdf_path[255], opened=0, *splat_version={"1.1.1"};
+char   string[255], sdf_path[255], opened=0, *splat_version={"1.2.1"};
 
 double TWOPI=6.283185307179586, HALFPI=1.570796326794896,
        PI=3.141592653589793, deg2rad=1.74532925199e-02,
        EARTHRADIUS=20902230.97, METERS_PER_MILE=1609.344,
-       METERS_PER_FOOT=0.3048, earthradius, max_range=0.0;
+       METERS_PER_FOOT=0.3048, KM_PER_MILE=1.609344, earthradius,
+       max_range=0.0, forced_erp=-1.0, fzone_clearance=0.6;
 
 int    min_north=90, max_north=-90, min_west=360, max_west=-1,
        max_elevation=-32768, min_elevation=32768, bzerror, maxdB=230;
 
-struct site { double lat;
-             double lon;
-             double alt;
-             char name[50];
-           } site;
-
-struct path { float lat[ARRAYSIZE];
-              float lon[ARRAYSIZE];
-              float elevation[ARRAYSIZE];
-              float distance[ARRAYSIZE];
-              int length;
-            } path;
-
-struct dem { int min_north;
-            int max_north;
-            int min_west;
-            int max_west;
-            int max_el;
-            int min_el;
-            short data[1200][1200];
-            unsigned char mask[1200][1200];
-           } dem[MAXSLOTS];
-
-struct LR { double eps_dielect; 
-           double sgm_conductivity; 
-           double eno_ns_surfref;
-           double frq_mhz; 
-           double conf; 
-           double rel;
-           int radio_climate;  
-           int pol;
-          } LR;
+unsigned char got_elevation_pattern, got_azimuth_pattern, metric=0;
+
+struct site {  double lat;
+               double lon;
+               float alt;
+               char name[50];
+               char filename[255];
+           }   site;
+
+struct path {  double lat[ARRAYSIZE];
+               double lon[ARRAYSIZE];
+               double elevation[ARRAYSIZE];
+               double distance[ARRAYSIZE];
+               int length;
+           }   path;
+
+struct dem {   int min_north;
+               int max_north;
+               int min_west;
+               int max_west;
+               int max_el;
+               int min_el;
+               short data[1200][1200];
+               unsigned char mask[1200][1200];
+               unsigned char signal[1200][1200];
+           }   dem[MAXPAGES];
+
+struct LR {    double eps_dielect; 
+               double sgm_conductivity; 
+               double eno_ns_surfref;
+               double frq_mhz; 
+               double conf; 
+               double rel;
+               double erp;
+               int radio_climate;  
+               int pol;
+               float antenna_pattern[361][1001];
+          }    LR;
+
+struct region { unsigned char color[32][3];
+               int level[32];
+               int levels;
+             } region;
 
 double elev_l[ARRAYSIZE+10];
 
@@ -138,12 +145,19 @@ char *dec2dms(double decimal)
 {
        /* Converts decimal degrees to degrees, minutes, seconds,
           (DMS) and returns the result as a character string. */
-       int degrees, minutes, seconds;
-       double a, b, c, d;
+
+       char    sign;
+       int     degrees, minutes, seconds;
+       double  a, b, c, d;
 
        if (decimal<0.0)
+       {
                decimal=-decimal;
+               sign=-1;
+       }
+
+       else
+               sign=1;
 
        a=floor(decimal);
        b=60.0*(decimal-a);
@@ -161,10 +175,41 @@ char *dec2dms(double decimal)
                seconds=59;
 
        string[0]=0;
-       sprintf(string,"%d%c %d\' %d\"", degrees, 176, minutes, seconds);
+       sprintf(string,"%d%c %d\' %d\"", degrees*sign, 176, minutes, seconds);
        return (string);
 }
 
+int PutMask(double lat, double lon, int value)
+{
+       /* Lines, text, markings, and coverage areas are stored in a
+          mask that is combined with topology data when topographic
+          maps are generated by SPLAT!.  This function sets and resets
+          bits in the mask based on the latitude and longitude of the
+          area pointed to. */
+
+       int     x, y, indx;
+       char    found;
+
+       for (indx=0, found=0; indx<MAXPAGES && found==0;)
+               if (lat>=(double)dem[indx].min_north && lat<=(double)dem[indx].max_north && lon>=(double)dem[indx].min_west && lon<=(double)dem[indx].max_west)
+                       found=1;
+               else
+                       indx++;
+
+       if (found)
+       {
+               x=(int)(1199.0*(lat-floor(lat)));
+               y=(int)(1199.0*(lon-floor(lon)));
+
+               dem[indx].mask[x][y]=value;
+
+               return (dem[indx].mask[x][y]);
+       }
+
+       else
+               return -1;
+}
+
 int OrMask(double lat, double lon, int value)
 {
        /* Lines, text, markings, and coverage areas are stored in a
@@ -173,14 +218,11 @@ int OrMask(double lat, double lon, int value)
           the mask based on the latitude and longitude of the area
           pointed to. */
 
-       int x, y, indx, minlat, minlon;
-       char found;
+       int     x, y, indx;
+       char    found;
 
-       minlat=(int)floor(lat);
-       minlon=(int)floor(lon);
-
-       for (indx=0, found=0; indx<MAXSLOTS && found==0;)
-               if (minlat==dem[indx].min_north && minlon==dem[indx].min_west)
+       for (indx=0, found=0; indx<MAXPAGES && found==0;)
+               if (lat>=(double)dem[indx].min_north && lat<=(double)dem[indx].max_north && lon>=(double)dem[indx].min_west && lon<=(double)dem[indx].max_west)
                        found=1;
                else
                        indx++;
@@ -207,29 +249,80 @@ int GetMask(double lat, double lon)
        return (OrMask(lat,lon,0));
 }
 
+int PutSignal(double lat, double lon, unsigned char signal)
+{
+       /* This function writes a signal level (0-255)
+          at the specified location for later recall. */
+
+       int     x, y, indx;
+       char    found;
+
+       for (indx=0, found=0; indx<MAXPAGES && found==0;)
+               if (lat>=(double)dem[indx].min_north && lat<=(double)dem[indx].max_north && lon>=(double)dem[indx].min_west && lon<=(double)dem[indx].max_west)
+                       found=1;
+               else
+                       indx++;
+
+       if (found)
+       {
+               x=(int)(1199.0*(lat-floor(lat)));
+               y=(int)(1199.0*(lon-floor(lon)));
+
+               dem[indx].signal[x][y]=signal;
+
+               return (dem[indx].signal[x][y]);
+       }
+
+       else
+               return 0;
+}
+
+unsigned char GetSignal(double lat, double lon)
+{
+       /* This function reads the signal level (0-255) at the
+          specified location that was previously written by the
+          complimentary PutSignal() function. */
+
+       int     x, y, indx;
+       char    found;
+
+       for (indx=0, found=0; indx<MAXPAGES && found==0;)
+               if (lat>=(double)dem[indx].min_north && lat<=(double)dem[indx].max_north && lon>=(double)dem[indx].min_west && lon<=(double)dem[indx].max_west)
+                       found=1;
+               else
+                       indx++;
+
+       if (found)
+       {
+               x=(int)(1199.0*(lat-floor(lat)));
+               y=(int)(1199.0*(lon-floor(lon)));
+
+               return (dem[indx].signal[x][y]);
+       }
+
+       else
+               return 0;
+}
+
 double GetElevation(struct site location)
 {
        /* This function returns the elevation (in feet) of any location
           represented by the digital elevation model data in memory.
           Function returns -5000.0 for locations not found in memory. */
 
-       char found;
-       int x, y, indx, minlat, minlon;
-       double elevation;
+       char    found;
+       int     x, y, indx;
+       double  elevation;
 
        elevation=-5000.0;
 
-       minlat=(int)floor(location.lat);
-       minlon=(int)floor(location.lon);
-
        x=(int)(1199.0*(location.lat-floor(location.lat)));
        y=(int)(1199.0*(location.lon-floor(location.lon)));
 
-       for (indx=0, found=0; indx<MAXSLOTS && found==0; indx++)
+       for (indx=0, found=0; indx<MAXPAGES && found==0; indx++)
        {
-               if (minlat==dem[indx].min_north && minlon==dem[indx].min_west)
+               if (location.lat>=(double)dem[indx].min_north && location.lat<=(double)dem[indx].max_north && location.lon>=(double)dem[indx].min_west && location.lon<=(double)dem[indx].max_west)
                {
-
                        elevation=3.28084*dem[indx].data[x][y];
                        found=1;
                }
@@ -238,12 +331,37 @@ double GetElevation(struct site location)
        return elevation;
 }
 
+int AddElevation(double lat, double lon, double height)
+{
+       /* This function adds a user-defined terrain feature
+          (in meters AGL) to the digital elevation model data
+          in memory.  Does nothing and returns 0 for locations
+          not found in memory. */
+
+       char    found;
+       int     x, y, indx;
+
+       x=(int)(1199.0*(lat-floor(lat)));
+       y=(int)(1199.0*(lon-floor(lon)));
+
+       for (indx=0, found=0; indx<MAXPAGES && found==0; indx++)
+       {
+               if (lat>=(double)dem[indx].min_north && lat<=(double)dem[indx].max_north && lon>=(double)dem[indx].min_west && lon<=(double)dem[indx].max_west)
+               {
+                       dem[indx].data[x][y]+=(short)rint(height);
+                       found=1;
+               }
+       }
+       
+       return found;
+}
+
 double Distance(struct site site1, struct site site2)
 {
        /* This function returns the great circle distance
           in miles between any two site locations. */
 
-       double lat1, lon1, lat2, lon2, distance;
+       double  lat1, lon1, lat2, lon2, distance;
 
        lat1=site1.lat*deg2rad;
        lon1=site1.lon*deg2rad;
@@ -260,8 +378,8 @@ double Azimuth(struct site source, struct site destination)
        /* This function returns the azimuth (in degrees) to the
           destination as seen from the location of the source. */
 
-       double dest_lat, dest_lon, src_lat, src_lon,
-              beta, azimuth, diff, num, den, fraction;
+       double  dest_lat, dest_lon, src_lat, src_lon,
+               beta, azimuth, diff, num, den, fraction;
 
        dest_lat=destination.lat*deg2rad;
        dest_lon=destination.lon*deg2rad;
@@ -307,10 +425,10 @@ double Azimuth(struct site source, struct site destination)
        return (azimuth/deg2rad);               
 }
 
-double ElevationAngle(struct site local, struct site remote)
+double ElevationAngle(struct site source, struct site destination)
 {
        /* This function returns the angle of elevation (in degrees)
-          of the remote location as seen from the local site.
+          of the destination as seen from the source location.
           A positive result represents an angle of elevation (uptilt),
           while a negative result represents an angle of depression
           (downtilt), as referenced to a normal to the center of
@@ -318,10 +436,10 @@ double ElevationAngle(struct site local, struct site remote)
           
        register double a, b, dx;
 
-       a=GetElevation(remote)+remote.alt+earthradius;
-       b=GetElevation(local)+local.alt+earthradius;
+       a=GetElevation(destination)+destination.alt+earthradius;
+       b=GetElevation(source)+source.alt+earthradius;
 
-       dx=5280.0*Distance(local,remote);
+       dx=5280.0*Distance(source,destination);
 
        /* Apply the Law of Cosines */
 
@@ -331,22 +449,35 @@ double ElevationAngle(struct site local, struct site remote)
 void ReadPath(struct site source, struct site destination)
 {
        /* This function generates a sequence of latitude and
-          longitude positions between a source location and
-          a destination along a great circle path, and stores
-          elevation and distance information for points along
-          that path in the "path" structure for later use. */
+          longitude positions between source and destination
+          locations along a great circle path, and stores
+          elevation and distance information for points
+          along that path in the "path" structure. */
 
-       int c;
-       double azimuth, distance, lat1, lon1, beta,
-              den, num, lat2, lon2, total_distance;
-       struct site tempsite;
+       int     c;
+       double  azimuth, distance, lat1, lon1, beta, den, num,
+               lat2, lon2, total_distance, x, y, path_length,
+               increment;
+       struct  site tempsite;
 
        lat1=source.lat*deg2rad;
        lon1=source.lon*deg2rad;
+
+       lat2=destination.lat*deg2rad;
+       lon2=destination.lon*deg2rad;
+
        azimuth=Azimuth(source,destination)*deg2rad;
+
        total_distance=Distance(source,destination);
 
-       for (distance=0, c=0; distance<=total_distance; distance+=0.04)
+       x=68755.0*acos(cos(lon1-lon2));         /* 1200 samples per degree */
+       y=68755.0*acos(cos(lat1-lat2));         /* 68755 samples per radian */
+
+       path_length=sqrt((x*x)+(y*y));          /* Total number of samples */
+
+       increment=total_distance/path_length;   /* Miles per sample */
+
+       for (distance=0, c=0; (distance<=total_distance && c<ARRAYSIZE); distance+=increment, c++)
        {
                beta=distance/3959.0;
                lat2=asin(sin(lat1)*cos(beta)+cos(azimuth)*sin(beta)*cos(lat1));
@@ -379,16 +510,12 @@ void ReadPath(struct site source, struct site destination)
                lat2=lat2/deg2rad;
                lon2=lon2/deg2rad;
 
-               if (c<ARRAYSIZE)
-               {
-                       path.lat[c]=lat2;
-                       path.lon[c]=lon2;
-                       tempsite.lat=lat2;
-                       tempsite.lon=lon2;
-                       path.elevation[c]=GetElevation(tempsite);
-                       path.distance[c]=distance;
-                       c++;
-               }
+               path.lat[c]=lat2;
+               path.lon[c]=lon2;
+               tempsite.lat=lat2;
+               tempsite.lon=lon2;
+               path.elevation[c]=GetElevation(tempsite);
+               path.distance[c]=distance;
        }
 
        /* Make sure exact destination point is recorded at path.length-1 */
@@ -408,6 +535,75 @@ void ReadPath(struct site source, struct site destination)
                path.length=ARRAYSIZE-1;
 }
 
+double ElevationAngle2(struct site source, struct site destination, double er)
+{
+       /* This function returns the angle of elevation (in degrees)
+          of the destination as seen from the source location, UNLESS
+          the path between the sites is obstructed, in which case, the
+          elevation angle to the first obstruction is returned instead.
+          "er" represents the earth radius. */
+
+       int     x;
+       char    block=0;
+       double  source_alt, destination_alt, cos_xmtr_angle,
+               cos_test_angle, test_alt, elevation, distance,
+               source_alt2, first_obstruction_angle=0.0;
+       struct  path temp;
+
+       temp=path;
+
+       ReadPath(source,destination);
+
+       distance=5280.0*Distance(source,destination);
+       source_alt=er+source.alt+GetElevation(source);
+       destination_alt=er+destination.alt+GetElevation(destination);
+       source_alt2=source_alt*source_alt;
+
+       /* Calculate the cosine of the elevation angle of the
+          destination (receiver) as seen by the source (transmitter). */
+
+       cos_xmtr_angle=((source_alt2)+(distance*distance)-(destination_alt*destination_alt))/(2.0*source_alt*distance);
+
+       /* Test all points in between source and destination locations to
+          see if the angle to a topographic feature generates a higher
+          elevation angle than that produced by the destination.  Begin
+          at the source since we're interested in identifying the FIRST
+          obstruction along the path between source and destination. */
+       for (x=2, block=0; x<path.length && block==0; x++)
+       {
+               distance=5280.0*path.distance[x];
+
+               test_alt=earthradius+path.elevation[x];
+
+               cos_test_angle=((source_alt2)+(distance*distance)-(test_alt*test_alt))/(2.0*source_alt*distance);
+
+               /* Compare these two angles to determine if
+                  an obstruction exists.  Since we're comparing
+                  the cosines of these angles rather than
+                  the angles themselves, the sense of the
+                  following "if" statement is reversed from
+                  what it would be if the angles themselves
+                  were compared. */
+
+               if (cos_xmtr_angle>cos_test_angle)
+               {
+                       block=1;
+                       first_obstruction_angle=((acos(cos_test_angle))/deg2rad)-90.0;
+               }
+       }
+
+       if (block)
+               elevation=first_obstruction_angle;
+
+       else
+               elevation=((acos(cos_xmtr_angle))/deg2rad)-90.0;
+
+       path=temp;
+
+       return elevation;
+}
+
 double AverageTerrain(struct site source, double azimuthx, double start_distance, double end_distance)
 {
        /* This function returns the average terrain calculated in
@@ -418,9 +614,9 @@ double AverageTerrain(struct site source, double azimuthx, double start_distance
           memory to complete the survey (critical error), then
           -9999.0 is returned. */
  
-       int c, samples, endpoint;
-       double beta, lat1, lon1, lat2, lon2, num, den, azimuth, terrain=0.0;
-       struct site destination;
+       int     c, samples, endpoint;
+       double  beta, lat1, lon1, lat2, lon2, num, den, azimuth, terrain=0.0;
+       struct  site destination;
 
        lat1=source.lat*deg2rad;
        lon1=source.lon*deg2rad;
@@ -509,9 +705,9 @@ double haat(struct site antenna)
           error occurs, such as a lack of SDF data to complete the
           survey, -5000.0 is returned. */
 
-       int azi, c;
-       char error=0;
-       double terrain, avg_terrain, haat, sum=0.0;
+       int     azi, c;
+       char    error=0;
+       double  terrain, avg_terrain, haat, sum=0.0;
 
        /* Calculate the average terrain between 2 and 10 miles
           from the antenna site at azimuths of 0, 45, 90, 135,
@@ -586,7 +782,6 @@ void PlaceMarker(struct site location)
        lat=location.lat;
        lon=location.lon;
 
-
        if (lat<xmax && lat>xmin && (LonDiff(lon,ymax)<0.0) && (LonDiff(lon,ymin)>0.0))
        {
                p1=1.0/1200.0;
@@ -788,9 +983,9 @@ double ReadBearing(char *input)
           embedded within the numbers expressed in the
           input string.  Decimal seconds are permitted. */
  
-       double seconds, bearing=0.0;
-       char string[20];
-       int a, b, length, degrees, minutes;
+       double  seconds, bearing=0.0;
+       char    string[20];
+       int     a, b, length, degrees, minutes;
 
        /* Copy "input" to "string", and ignore any extra
           spaces that might be present in the process. */
@@ -800,7 +995,7 @@ double ReadBearing(char *input)
 
        for (a=0, b=0; a<length && a<18; a++)
        {
-               if ((input[a]!=32 && input[a]!='\n') || (input[a]==32 && input[a+1]!=32 && b!=0))
+               if ((input[a]!=32 && input[a]!='\n') || (input[a]==32 && input[a+1]!=32 && input[a+1]!='\n' && b!=0))
                {
                        string[b]=input[a];
                        b++;
@@ -823,12 +1018,16 @@ double ReadBearing(char *input)
        if (b==2)  /* Degree, Minute, Second Format (40 08 23) */
        {
                sscanf(string,"%d %d %lf",&degrees, &minutes, &seconds);
-               bearing=(double)degrees+((double)minutes/60)+(seconds/3600);
+
+               bearing=(double)abs(degrees)+((double)abs(minutes)/60)+(fabs(seconds)/3600);
+
+               if ((degrees<0) || (minutes<0) || (seconds<0.0))
+                       bearing=-bearing;
        }
 
        /* Anything else returns a 0.0 */
 
-       if (bearing>360.0 || bearing<-90.0)
+       if (bearing>360.0 || bearing<-360.0)
                bearing=0.0;
 
        return bearing;
@@ -844,10 +1043,10 @@ struct site LoadQTH(char *filename)
           or 'm', or by the word "meters" or "Meters", in which
           case meters is assumed, and is handled accordingly. */
 
-       int x;
-       char string[50], qthfile[255];
-       struct site tempsite;
-       FILE *fd=NULL;
+       int     x;
+       char    string[50], qthfile[255];
+       struct  site tempsite;
+       FILE    *fd=NULL;
 
        for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
                qthfile[x]=filename[x];
@@ -862,6 +1061,7 @@ struct site LoadQTH(char *filename)
        tempsite.lon=361.0;
        tempsite.alt=0.0;
        tempsite.name[0]=0;
+       tempsite.filename[0]=0;
 
        fd=fopen(qthfile,"r");
 
@@ -884,6 +1084,9 @@ struct site LoadQTH(char *filename)
                fgets(string,49,fd);
                tempsite.lon=ReadBearing(string);
 
+               if (tempsite.lon<0.0)
+                       tempsite.lon+=360.0;
+
                /* Antenna Height */
                fgets(string,49,fd);
                fclose(fd);
@@ -900,184 +1103,559 @@ struct site LoadQTH(char *filename)
                   must be converted to feet before exiting. */
 
                for (x=0; string[x]!='M' && string[x]!='m' && string[x]!=0 && x<48; x++);
+
                if (string[x]=='M' || string[x]=='m')
                {
                        string[x]=0;
-                       sscanf(string,"%lf",&tempsite.alt);
+                       sscanf(string,"%f",&tempsite.alt);
                        tempsite.alt*=3.28084;
                }
 
                else
                {
                        string[x]=0;
-                       sscanf(string,"%lf",&tempsite.alt);
+                       sscanf(string,"%f",&tempsite.alt);
                }
+
+               for (x=0; x<254 && qthfile[x]!=0; x++)
+                       tempsite.filename[x]=qthfile[x];
+
+               tempsite.filename[x]=0;
        }
 
        return tempsite;
 }
 
-int LoadSDF_SDF(char *name)
+void LoadPAT(char *filename)
 {
-       /* This function reads uncompressed SPLAT Data Files (.sdf)
-          containing digital elevation model data into memory.
-          Elevation data, maximum and minimum elevations, and
-          quadrangle limits are stored in the first available
-          dem[] structure. */
+       /* This function reads and processes antenna pattern (.az
+          and .el) files that correspond in name to previously
+          loaded SPLAT! .lrp files.  */
+
+       int     a, b, w, x, y, z, last_index, next_index, span;
+       char    string[255], azfile[255], elfile[255], *pointer=NULL;
+       float   az, xx, elevation, amplitude, rotation, valid1, valid2,
+               delta, azimuth[361], azimuth_pattern[361], el_pattern[10001],
+               elevation_pattern[361][1001], slant_angle[361], tilt,
+               mechanical_tilt=0.0, tilt_azimuth, tilt_increment, sum;
+       FILE    *fd=NULL;
+       unsigned char read_count[10001];
 
-       int x, y, data, indx, minlat, minlon, maxlat, maxlon;
-       char found, free_slot=0, line[20], sdf_file[255], path_plus_name[255];
-       FILE *fd;
+       for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
+       {
+               azfile[x]=filename[x];
+               elfile[x]=filename[x];
+       }
 
-       for (x=0; name[x]!='.' && name[x]!=0 && x<250; x++)
-               sdf_file[x]=name[x];
+       azfile[x]='.';
+       azfile[x+1]='a';
+       azfile[x+2]='z';
+       azfile[x+3]=0;
 
-       sdf_file[x]=0;
+       elfile[x]='.';
+       elfile[x+1]='e';
+       elfile[x+2]='l';
+       elfile[x+3]=0;
 
-       /* Parse filename for minimum latitude and longitude values */
+       rotation=0.0;
 
-       sscanf(sdf_file,"%d:%d:%d:%d",&minlat,&maxlat,&minlon,&maxlon);
+       got_azimuth_pattern=0;
+       got_elevation_pattern=0;
 
-       sdf_file[x]='.';
-       sdf_file[x+1]='s';
-       sdf_file[x+2]='d';
-       sdf_file[x+3]='f';
-       sdf_file[x+4]=0;
+       /* Load .az antenna pattern file */
 
-       /* Is it already in memory? */
+       fd=fopen(azfile,"r");
 
-       for (indx=0, found=0; indx<MAXSLOTS && found==0; indx++)
+       if (fd!=NULL)
        {
-               if (minlat==dem[indx].min_north && minlon==dem[indx].min_west && maxlat==dem[indx].max_north && maxlon==dem[indx].max_west)
-                       found=1;
-       }
+               /* Clear azimuth pattern array */
 
-       /* Is room available to load it? */
+               for (x=0; x<=360; x++)
+               {
+                       azimuth[x]=0.0;
+                       read_count[x]=0;
+               }
 
-       if (found==0)
-       {       
-               for (indx=0, free_slot=0; indx<MAXSLOTS && free_slot==0; indx++)
-                       if (dem[indx].max_north==-90)
-                               free_slot=1;
-       }
 
-       indx--;
+               /* Read azimuth pattern rotation
+                  in degrees measured clockwise
+                  from true North. */
 
-       if (free_slot && found==0 && indx>=0 && indx<MAXSLOTS)
-       {
-               /* Search for SDF file in current working directory first */
+               fgets(string,254,fd);
+               pointer=strchr(string,';');
 
-               strncpy(path_plus_name,sdf_file,255);
+               if (pointer!=NULL)
+                       *pointer=0;
 
-               fd=fopen(path_plus_name,"rb");
+               sscanf(string,"%f",&rotation);
 
-               if (fd==NULL)
-               {
-                       /* Next, try loading SDF file from path specified
-                          in $HOME/.splat_path file or by -d argument */
 
-                       strncpy(path_plus_name,sdf_path,255);
-                       strncat(path_plus_name,sdf_file,255);
+               /* Read azimuth (degrees) and corresponding
+                  normalized field radiation pattern amplitude
+                  (0.0 to 1.0) until EOF is reached. */
 
-                       fd=fopen(path_plus_name,"rb");
-               }
+               fgets(string,254,fd);
+               pointer=strchr(string,';');
 
-               if (fd!=NULL)
-               {
-                       fprintf(stdout,"Loading \"%s\" into slot %d...",path_plus_name,indx+1);
-                       fflush(stdout);
+               if (pointer!=NULL)
+                       *pointer=0;
 
-                       fgets(line,19,fd);
-                       sscanf(line,"%d",&dem[indx].max_west);
+               sscanf(string,"%f %f",&az, &amplitude);
 
-                       fgets(line,19,fd);
-                       sscanf(line,"%d",&dem[indx].min_north);
+               do
+               {
+                       x=(int)rintf(az);
 
-                       fgets(line,19,fd);
-                       sscanf(line,"%d",&dem[indx].min_west);
+                       if (x>=0 && x<=360 && fd!=NULL)
+                       {
+                               azimuth[x]+=amplitude;
+                               read_count[x]++;
+                       }
 
-                       fgets(line,19,fd);
-                       sscanf(line,"%d",&dem[indx].max_north);
+                       fgets(string,254,fd);
+                       pointer=strchr(string,';');
 
-                       for (x=0; x<1200; x++)
-                               for (y=0; y<1200; y++)
-                               {
-                                       fgets(line,19,fd);
-                                       sscanf(line,"%d",&data);
+                       if (pointer!=NULL)
+                               *pointer=0;
 
-                                       dem[indx].data[x][y]=data;
+                       sscanf(string,"%f %f",&az, &amplitude);
 
-                                       if (data>dem[indx].max_el)
-                                               dem[indx].max_el=data;
+               } while (feof(fd)==0);
 
-                                       if (data<dem[indx].min_el)
-                                               dem[indx].min_el=data;
-                               }
+               fclose(fd);
 
-                       fclose(fd);
 
-                       if (dem[indx].min_el<min_elevation)
-                               min_elevation=dem[indx].min_el;
+               /* Handle 0=360 degree ambiguity */
 
-                       if (dem[indx].max_el>max_elevation)
-                               max_elevation=dem[indx].max_el;
+               if ((read_count[0]==0) && (read_count[360]!=0))
+               {
+                       read_count[0]=read_count[360];
+                       azimuth[0]=azimuth[360];
+               }
 
-                       if (max_north==-90)
-                               max_north=dem[indx].max_north;
+               if ((read_count[0]!=0) && (read_count[360]==0))
+               {
+                       read_count[360]=read_count[0];
+                       azimuth[360]=azimuth[0];
+               }
 
-                       else if (dem[indx].max_north>max_north)
-                               max_north=dem[indx].max_north;
+               /* Average pattern values in case more than
+                   one was read for each degree of azimuth. */
 
-                       if (min_north==90)
-                               min_north=dem[indx].min_north;
+               for (x=0; x<=360; x++)
+               {
+                       if (read_count[x]>1)
+                               azimuth[x]/=(float)read_count[x];
+               }
 
-                       else if (dem[indx].min_north<min_north)
-                               min_north=dem[indx].min_north;
+               /* Interpolate missing azimuths
+                  to completely fill the array */
 
-                       if (max_west==-1)
-                               max_west=dem[indx].max_west;
+               last_index=-1;
+               next_index=-1;
 
-                       else
+               for (x=0; x<=360; x++)
+               {
+                       if (read_count[x]!=0)
                        {
-                               if (abs(dem[indx].max_west-max_west)<180)
-                               {
-                                       if (dem[indx].max_west>max_west)
-                                               max_west=dem[indx].max_west;
-                               }
-
+                               if (last_index==-1)
+                                       last_index=x;
                                else
-                               {
-                                       if (dem[indx].max_west<max_west)
-                                               max_west=dem[indx].max_west;
-                               }
+                                       next_index=x;
                        }
 
-                       if (min_west==360)
-                               min_west=dem[indx].min_west;
-
-                       else
+                       if (last_index!=-1 && next_index!=-1)
                        {
-                               if (abs(dem[indx].min_west-min_west)<180)
-                               {
-                                       if (dem[indx].min_west<min_west)
-                                               min_west=dem[indx].min_west;
-                               }
+                               valid1=azimuth[last_index];
+                               valid2=azimuth[next_index];
 
-                               else
-                               {
-                                       if (dem[indx].min_west>min_west)
-                                               min_west=dem[indx].min_west;
-                               }
-                       }
+                               span=next_index-last_index;
+                               delta=(valid2-valid1)/(float)span;
 
-                       fprintf(stdout," Done!\n");
-                       fflush(stdout);
-                       return 1;
+                               for (y=last_index+1; y<next_index; y++)
+                                       azimuth[y]=azimuth[y-1]+delta;
+
+                               last_index=y;
+                               next_index=-1;
+                       }
                }
 
-               else
-                       return -1;
-       }
+               /* Perform azimuth pattern rotation
+                  and load azimuth_pattern[361] with
+                  azimuth pattern data in its final form. */
+
+               for (x=0; x<360; x++)
+               {
+                       y=x+(int)rintf(rotation);
+
+                       if (y>=360)
+                               y-=360;
+
+                       azimuth_pattern[y]=azimuth[x];
+               }
+
+               azimuth_pattern[360]=azimuth_pattern[0];
+
+               got_azimuth_pattern=255;
+       }
+
+       /* Read and process .el file */
+
+       fd=fopen(elfile,"r");
+
+       if (fd!=NULL)
+       {
+               for (x=0; x<=10000; x++)
+               {
+                       el_pattern[x]=0.0;
+                       read_count[x]=0;
+               }
+
+               /* Read mechanical tilt (degrees) and
+                  tilt azimuth in degrees measured
+                  clockwise from true North. */  
+
+               fgets(string,254,fd);
+               pointer=strchr(string,';');
+
+               if (pointer!=NULL)
+                       *pointer=0;
+
+               sscanf(string,"%f %f",&mechanical_tilt, &tilt_azimuth);
+
+               /* Read elevation (degrees) and corresponding
+                  normalized field radiation pattern amplitude
+                  (0.0 to 1.0) until EOF is reached. */
+
+               fgets(string,254,fd);
+               pointer=strchr(string,';');
+
+               if (pointer!=NULL)
+                       *pointer=0;
+
+               sscanf(string,"%f %f", &elevation, &amplitude);
+
+               while (feof(fd)==0)
+               {
+                       /* Read in normalized radiated field values
+                          for every 0.01 degrees of elevation between
+                          -10.0 and +90.0 degrees */
+
+                       x=(int)rintf(100.0*(elevation+10.0));
+
+                       if (x>=0 && x<=10000)
+                       {
+                               el_pattern[x]+=amplitude;
+                               read_count[x]++;
+                       }
+
+                       fgets(string,254,fd);
+                       pointer=strchr(string,';');
+
+                       if (pointer!=NULL)
+                               *pointer=0;
+
+                       sscanf(string,"%f %f", &elevation, &amplitude);
+               }
+
+               fclose(fd);
+
+               /* Average the field values in case more than
+                  one was read for each 0.01 degrees of elevation. */
+
+               for (x=0; x<=10000; x++)
+               {
+                       if (read_count[x]>1)
+                               el_pattern[x]/=(float)read_count[x];
+               }
+
+               /* Interpolate between missing elevations (if
+                  any) to completely fill the array and provide
+                  radiated field values for every 0.01 degrees of
+                  elevation. */
+
+               last_index=-1;
+               next_index=-1;
+
+               for (x=0; x<=10000; x++)
+               {
+                       if (read_count[x]!=0)
+                       {
+                               if (last_index==-1)
+                                       last_index=x;
+                               else
+                                       next_index=x;
+                       }
+
+                       if (last_index!=-1 && next_index!=-1)
+                       {
+                               valid1=el_pattern[last_index];
+                               valid2=el_pattern[next_index];
+
+                               span=next_index-last_index;
+                               delta=(valid2-valid1)/(float)span;
+
+                               for (y=last_index+1; y<next_index; y++)
+                                       el_pattern[y]=el_pattern[y-1]+delta;
+
+                               last_index=y;
+                               next_index=-1;
+                       }
+               }
+
+               /* Fill slant_angle[] array with offset angles based
+                  on the antenna's mechanical beam tilt (if any)
+                  and tilt direction (azimuth). */
+
+               if (mechanical_tilt==0.0)
+               {
+                       for (x=0; x<=360; x++)
+                               slant_angle[x]=0.0;
+               }
+
+               else
+               {
+                       tilt_increment=mechanical_tilt/90.0;
+
+                       for (x=0; x<=360; x++)
+                       {
+                               xx=(float)x;
+                               y=(int)rintf(tilt_azimuth+xx);
+
+                               while (y>=360)
+                                       y-=360;
+
+                               while (y<0)
+                                       y+=360;
+
+                               if (x<=180)
+                                       slant_angle[y]=-(tilt_increment*(90.0-xx));
+
+                               if (x>180)
+                                       slant_angle[y]=-(tilt_increment*(xx-270.0));
+                       }
+               }
+
+               slant_angle[360]=slant_angle[0];   /* 360 degree wrap-around */
+
+               for (w=0; w<=360; w++)
+               {
+                       tilt=slant_angle[w];
+
+                       /** Convert tilt angle to
+                           an array index offset **/
+
+                       y=(int)rintf(100.0*tilt);
+
+                       /* Copy shifted el_pattern[10001] field
+                          values into elevation_pattern[361][1001]
+                          at the corresponding azimuth, downsampling
+                          (averaging) along the way in chunks of 10. */
+
+                       for (x=y, z=0; z<=1000; x+=10, z++)
+                       {
+                               for (sum=0.0, a=0; a<10; a++)
+                               {
+                                       b=a+x;
+
+                                       if (b>=0 && b<=10000)
+                                               sum+=el_pattern[b];
+                                       if (b<0)
+                                               sum+=el_pattern[0];
+                                       if (b>10000)
+                                               sum+=el_pattern[10000];
+                               }
+
+                               elevation_pattern[w][z]=sum/10.0;
+                       }
+               }
+
+               got_elevation_pattern=255;
+       }
+
+       for (x=0; x<=360; x++)
+       {
+               for (y=0; y<=1000; y++)
+               {
+                       if (got_elevation_pattern)
+                               elevation=elevation_pattern[x][y];
+                       else
+                               elevation=1.0;
+
+                       if (got_azimuth_pattern)
+                               az=azimuth_pattern[x];
+                       else
+                               az=1.0;
+
+                       LR.antenna_pattern[x][y]=az*elevation;
+               }
+       }
+}
+
+int LoadSDF_SDF(char *name)
+{
+       /* This function reads uncompressed SPLAT Data Files (.sdf)
+          containing digital elevation model data into memory.
+          Elevation data, maximum and minimum elevations, and
+          quadrangle limits are stored in the first available
+          dem[] structure. */
+
+       int     x, y, data, indx, minlat, minlon, maxlat, maxlon;
+       char    found, free_page=0, line[20], sdf_file[255],
+               path_plus_name[255];
+       FILE    *fd;
+
+       for (x=0; name[x]!='.' && name[x]!=0 && x<250; x++)
+               sdf_file[x]=name[x];
+
+       sdf_file[x]=0;
+
+       /* Parse filename for minimum latitude and longitude values */
+
+       sscanf(sdf_file,"%d:%d:%d:%d",&minlat,&maxlat,&minlon,&maxlon);
+
+       sdf_file[x]='.';
+       sdf_file[x+1]='s';
+       sdf_file[x+2]='d';
+       sdf_file[x+3]='f';
+       sdf_file[x+4]=0;
+
+       /* Is it already in memory? */
+
+       for (indx=0, found=0; indx<MAXPAGES && found==0; indx++)
+       {
+               if (minlat==dem[indx].min_north && minlon==dem[indx].min_west && maxlat==dem[indx].max_north && maxlon==dem[indx].max_west)
+                       found=1;
+       }
+
+       /* Is room available to load it? */
+
+       if (found==0)
+       {       
+               for (indx=0, free_page=0; indx<MAXPAGES && free_page==0; indx++)
+                       if (dem[indx].max_north==-90)
+                               free_page=1;
+       }
+
+       indx--;
+
+       if (free_page && found==0 && indx>=0 && indx<MAXPAGES)
+       {
+               /* Search for SDF file in current working directory first */
+
+               strncpy(path_plus_name,sdf_file,255);
+
+               fd=fopen(path_plus_name,"rb");
+
+               if (fd==NULL)
+               {
+                       /* Next, try loading SDF file from path specified
+                          in $HOME/.splat_path file or by -d argument */
+
+                       strncpy(path_plus_name,sdf_path,255);
+                       strncat(path_plus_name,sdf_file,255);
+
+                       fd=fopen(path_plus_name,"rb");
+               }
+
+               if (fd!=NULL)
+               {
+                       fprintf(stdout,"Loading \"%s\" into page %d...",path_plus_name,indx+1);
+                       fflush(stdout);
+
+                       fgets(line,19,fd);
+                       sscanf(line,"%d",&dem[indx].max_west);
+
+                       fgets(line,19,fd);
+                       sscanf(line,"%d",&dem[indx].min_north);
+
+                       fgets(line,19,fd);
+                       sscanf(line,"%d",&dem[indx].min_west);
+
+                       fgets(line,19,fd);
+                       sscanf(line,"%d",&dem[indx].max_north);
+
+                       for (x=0; x<1200; x++)
+                               for (y=0; y<1200; y++)
+                               {
+                                       fgets(line,19,fd);
+                                       data=atoi(line);
+
+                                       dem[indx].data[x][y]=data;
+                                       dem[indx].signal[x][y]=0;
+                                       dem[indx].mask[x][y]=0;
+
+                                       if (data>dem[indx].max_el)
+                                               dem[indx].max_el=data;
+
+                                       if (data<dem[indx].min_el)
+                                               dem[indx].min_el=data;
+                               }
+
+                       fclose(fd);
+
+                       if (dem[indx].min_el<min_elevation)
+                               min_elevation=dem[indx].min_el;
+
+                       if (dem[indx].max_el>max_elevation)
+                               max_elevation=dem[indx].max_el;
+
+                       if (max_north==-90)
+                               max_north=dem[indx].max_north;
+
+                       else if (dem[indx].max_north>max_north)
+                               max_north=dem[indx].max_north;
+
+                       if (min_north==90)
+                               min_north=dem[indx].min_north;
+
+                       else if (dem[indx].min_north<min_north)
+                               min_north=dem[indx].min_north;
+
+                       if (max_west==-1)
+                               max_west=dem[indx].max_west;
+
+                       else
+                       {
+                               if (abs(dem[indx].max_west-max_west)<180)
+                               {
+                                       if (dem[indx].max_west>max_west)
+                                               max_west=dem[indx].max_west;
+                               }
+
+                               else
+                               {
+                                       if (dem[indx].max_west<max_west)
+                                               max_west=dem[indx].max_west;
+                               }
+                       }
+
+                       if (min_west==360)
+                               min_west=dem[indx].min_west;
+
+                       else
+                       {
+                               if (abs(dem[indx].min_west-min_west)<180)
+                               {
+                                       if (dem[indx].min_west<min_west)
+                                               min_west=dem[indx].min_west;
+                               }
+
+                               else
+                               {
+                                       if (dem[indx].min_west>min_west)
+                                               min_west=dem[indx].min_west;
+                               }
+                       }
+
+                       fprintf(stdout," Done!\n");
+                       fflush(stdout);
+                       return 1;
+               }
+
+               else
+                       return -1;
+       }
 
        else
                return 0;
@@ -1149,10 +1727,10 @@ int LoadSDF_BZ(char *name)
           maximum and minimum elevations, and quadrangle limits are
           stored in the first available dem[] structure. */
 
-       int x, y, data, indx, minlat, minlon, maxlat, maxlon;
-       char found, free_slot=0, sdf_file[255], path_plus_name[255];
-       FILE *fd;
-       BZFILE *bzfd;
+       int     x, y, data, indx, minlat, minlon, maxlat, maxlon;
+       char    found, free_page=0, sdf_file[255], path_plus_name[255], *string;
+       FILE    *fd;
+       BZFILE  *bzfd;
 
        for (x=0; name[x]!='.' && name[x]!=0 && x<247; x++)
                sdf_file[x]=name[x];
@@ -1175,7 +1753,7 @@ int LoadSDF_BZ(char *name)
 
        /* Is it already in memory? */
 
-       for (indx=0, found=0; indx<MAXSLOTS && found==0; indx++)
+       for (indx=0, found=0; indx<MAXPAGES && found==0; indx++)
        {
                if (minlat==dem[indx].min_north && minlon==dem[indx].min_west && maxlat==dem[indx].max_north && maxlon==dem[indx].max_west)
                        found=1;
@@ -1185,14 +1763,14 @@ int LoadSDF_BZ(char *name)
 
        if (found==0)
        {       
-               for (indx=0, free_slot=0; indx<MAXSLOTS && free_slot==0; indx++)
+               for (indx=0, free_page=0; indx<MAXPAGES && free_page==0; indx++)
                        if (dem[indx].max_north==-90)
-                               free_slot=1;
+                               free_page=1;
        }
 
        indx--;
 
-       if (free_slot && found==0 && indx>=0 && indx<MAXSLOTS)
+       if (free_page && found==0 && indx>=0 && indx<MAXPAGES)
        {
                /* Search for SDF file in current working directory first */
 
@@ -1215,7 +1793,7 @@ int LoadSDF_BZ(char *name)
 
                if (fd!=NULL && bzerror==BZ_OK)
                {
-                       fprintf(stdout,"Loading \"%s\" into slot %d...",path_plus_name,indx+1);
+                       fprintf(stdout,"Loading \"%s\" into page %d...",path_plus_name,indx+1);
                        fflush(stdout);
 
                        sscanf(BZfgets(bzfd,255),"%d",&dem[indx].max_west);
@@ -1226,9 +1804,12 @@ int LoadSDF_BZ(char *name)
                        for (x=0; x<1200; x++)
                                for (y=0; y<1200; y++)
                                {
-                                       sscanf(BZfgets(bzfd,20),"%d",&data);
+                                       string=BZfgets(bzfd,20);
+                                       data=atoi(string);
 
                                        dem[indx].data[x][y]=data;
+                                       dem[indx].signal[x][y]=0;
+                                       dem[indx].mask[x][y]=0;
 
                                        if (data>dem[indx].max_el)
                                                dem[indx].max_el=data;
@@ -1299,9 +1880,11 @@ int LoadSDF_BZ(char *name)
                        fflush(stdout);
                        return 1;
                }
+
                else
                        return -1;
        }
+
        else
                return 0;
 }
@@ -1317,9 +1900,9 @@ char LoadSDF(char *name)
           exists for the region requested, and that the region
           requested must be entirely over water. */
 
-       int x, y, indx, minlat, minlon, maxlat, maxlon;
-       char found, free_slot=0;
-       int  return_value=-1;
+       int     x, y, indx, minlat, minlon, maxlat, maxlon;
+       char    found, free_page=0;
+       int     return_value=-1;
 
        /* Try to load an uncompressed SDF first. */
 
@@ -1340,7 +1923,7 @@ char LoadSDF(char *name)
 
                /* Is it already in memory? */
 
-               for (indx=0, found=0; indx<MAXSLOTS && found==0; indx++)
+               for (indx=0, found=0; indx<MAXPAGES && found==0; indx++)
                {
                        if (minlat==dem[indx].min_north && minlon==dem[indx].min_west && maxlat==dem[indx].max_north && maxlon==dem[indx].max_west)
                                found=1;
@@ -1350,16 +1933,16 @@ char LoadSDF(char *name)
 
                if (found==0)
                {       
-                       for (indx=0, free_slot=0; indx<MAXSLOTS && free_slot==0; indx++)
+                       for (indx=0, free_page=0; indx<MAXPAGES && free_page==0; indx++)
                                if (dem[indx].max_north==-90)
-                                       free_slot=1;
+                                       free_page=1;
                }
 
                indx--;
 
-               if (free_slot && found==0 && indx>=0 && indx<MAXSLOTS)
+               if (free_page && found==0 && indx>=0 && indx<MAXPAGES)
                {
-                       fprintf(stdout,"Region  \"%s\" assumed as sea-level into slot %d...",name,indx+1);
+                       fprintf(stdout,"Region  \"%s\" assumed as sea-level into page %d...",name,indx+1);
                        fflush(stdout);
 
                        dem[indx].max_west=maxlon;
@@ -1373,6 +1956,8 @@ char LoadSDF(char *name)
                                for (y=0; y<1200; y++)
                                {
                                        dem[indx].data[x][y]=0;
+                                       dem[indx].signal[x][y]=0;
+                                       dem[indx].mask[x][y]=0;
 
                                        if (dem[indx].min_el>0)
                                                dem[indx].min_el=0;
@@ -1448,10 +2033,10 @@ void LoadCities(char *filename)
           the locations and names of the cities and site locations
           read on topographic maps generated by SPLAT! */
 
-       int x, y, z;
-       char input[80], str[3][80];
-       struct site city_site;
-       FILE *fd=NULL;
+       int     x, y, z;
+       char    input[80], str[3][80];
+       struct  site city_site;
+       FILE    *fd=NULL;
 
        fd=fopen(filename,"r");
 
@@ -1459,7 +2044,7 @@ void LoadCities(char *filename)
        {
                fgets(input,78,fd);
 
-               fprintf(stdout,"Reading \"%s\"... ",filename);
+               fprintf(stdout,"\nReading \"%s\"... ",filename);
                fflush(stdout);
 
                while (fd!=NULL && feof(fd)==0)
@@ -1487,32 +2072,178 @@ void LoadCities(char *filename)
                        city_site.lon=ReadBearing(str[2]);
                        city_site.alt=0.0;
 
+                       if (city_site.lon<0.0)
+                               city_site.lon+=360.0;
+
                        PlaceMarker(city_site);
 
                        fgets(input,78,fd);
                }
 
                fclose(fd);
-               fprintf(stdout,"Done!\n");
+               fprintf(stdout,"Done!");
                fflush(stdout);
        }
+
        else
                fprintf(stderr,"*** ERROR: \"%s\": not found!\n",filename);
 }
 
-void LoadBoundaries(char *filename)
+void LoadUDT(char *filename)
 {
-       /* This function reads Cartographic Boundary Files available from
-          the U.S. Census Bureau, and plots the data contained in those
-          files on the PPM Map generated by SPLAT!.  Such files contain
+       /* This function reads a file containing User-Defined Terrain
+          features for their addition to the digital elevation model
+          data used by SPLAT!.  Elevations in the UDT file are evaluated
+          and then copied into a temporary file under /tmp.  Then the
+          contents of the temp file are scanned, and if found to be unique,
+          are added to the ground elevations described by the digital
+          elevation data already loaded into memory. */
+
+       int     i, x, y, z, fd=0;
+       char    input[80], str[3][80], tempname[15], *pointer=NULL;
+       double  latitude, longitude, height, templat, templon,
+               tempheight, one_pixel;
+       FILE    *fd1=NULL, *fd2=NULL;
+
+       strcpy(tempname,"/tmp/XXXXXX\0");
+       one_pixel=1.0/1200.0;
+
+       fd1=fopen(filename,"r");
+
+       if (fd1!=NULL)
+       {
+               fd=mkstemp(tempname);
+               fd2=fopen(tempname,"w");
+
+               fgets(input,78,fd1);
+
+               pointer=strchr(input,';');
+
+               if (pointer!=NULL)
+                       *pointer=0;
+
+               fprintf(stdout,"\nReading \"%s\"... ",filename);
+               fflush(stdout);
+
+               while (feof(fd1)==0)
+               {
+                       /* Parse line for latitude, longitude, height */
+
+                       for (x=0, y=0, z=0; x<78 && input[x]!=0 && z<3; x++)
+                       {
+                               if (input[x]!=',' && y<78)
+                               {
+                                       str[z][y]=input[x];
+                                       y++;
+                               }
+
+                               else
+                               {
+                                       str[z][y]=0;
+                                       z++;
+                                       y=0;
+                               }
+                       }
+
+                       latitude=ReadBearing(str[0]);
+                       longitude=ReadBearing(str[1]);
+
+                       if (longitude<0.0)
+                               longitude+=360.0;
+
+                       /* Remove <CR> and/or <LF> from antenna height string */
+
+                       for (i=0; str[2][i]!=13 && str[2][i]!=10 && str[2][i]!=0; i++);
+
+                       str[2][i]=0;
+
+                       /* The terrain feature may be expressed in either
+                          feet or meters.  If the letter 'M' or 'm' is
+                          discovered in the string, then this is an
+                          indication that the value given is expressed
+                          in meters.  Otherwise the height is interpreted
+                          as being expressed in feet.  */
+
+                       for (i=0; str[2][i]!='M' && str[2][i]!='m' && str[2][i]!=0 && i<48; i++);
+
+                       if (str[2][i]=='M' || str[2][i]=='m')
+                       {
+                               str[2][i]=0;
+                               height=rint(atof(str[2]));
+                       }
+
+                       else
+                       {
+                               str[2][i]=0;
+                               height=rint(3.28084*atof(str[2]));
+                       }
+
+                       if (height>0.0)
+                               fprintf(fd2,"%f, %f, %f\n",latitude, longitude, height);
+
+                       fgets(input,78,fd1);
+
+                       pointer=strchr(input,';');
+
+                       if (pointer!=NULL)
+                               *pointer=0;
+               }
+
+               fclose(fd1);
+               fclose(fd2);
+               close(fd);
+
+               fprintf(stdout,"Done!");
+               fflush(stdout);
+
+               fd1=fopen(tempname,"r");
+               fd2=fopen(tempname,"r");
+
+               fscanf(fd1,"%lf, %lf, %lf", &latitude, &longitude, &height);
+
+               for (y=0; feof(fd1)==0; y++)
+               {
+                       rewind(fd2);
+
+                       fscanf(fd2,"%lf, %lf, %lf", &templat, &templon, &tempheight);
+
+                       for (x=0, z=0; feof(fd2)==0; x++)
+                       {
+                               if (x>y)
+                                       if (fabs(latitude-templat)<=one_pixel && fabs(longitude-templon)<=one_pixel)
+                                               z=1;
+
+                               fscanf(fd2,"%lf, %lf, %lf", &templat, &templon, &tempheight);
+                       }
+
+                       if (z==0)
+                               AddElevation(latitude, longitude, height);
+
+                       fscanf(fd1,"%lf, %lf, %lf", &latitude, &longitude, &height);
+               }
+
+               fclose(fd1);
+               fclose(fd2);
+               unlink(tempname);
+       }
+
+       else
+               fprintf(stderr,"\n*** ERROR: \"%s\": not found!",filename);
+}
+
+void LoadBoundaries(char *filename)
+{
+       /* This function reads Cartographic Boundary Files available from
+          the U.S. Census Bureau, and plots the data contained in those
+          files on the PPM Map generated by SPLAT!.  Such files contain
           the coordinates that describe the boundaries of cities,
           counties, and states. */
 
-       int x;
-       double lat0, lon0, lat1, lon1;
-       char string[80];
-       struct site source, destination;
-       FILE *fd=NULL;
+       int     x;
+       double  lat0, lon0, lat1, lon1;
+       char    string[80];
+       struct  site source, destination;
+       FILE    *fd=NULL;
 
        fd=fopen(filename,"r");
 
@@ -1520,7 +2251,7 @@ void LoadBoundaries(char *filename)
        {
                fgets(string,78,fd);
 
-               fprintf(stdout,"Reading \"%s\"... ",filename);
+               fprintf(stdout,"\nReading \"%s\"... ",filename);
                fflush(stdout);
 
                do
@@ -1559,45 +2290,46 @@ void LoadBoundaries(char *filename)
 
                fclose(fd);
 
-               fprintf(stdout,"Done!\n");
+               fprintf(stdout,"Done!");
                fflush(stdout);
        }
 
        else
-               fprintf(stderr,"*** ERROR: \"%s\": not found!\n",filename);
+               fprintf(stderr,"\n*** ERROR: \"%s\": not found!",filename);
 }
 
-void ReadLRParm(char *txsite_filename)
+char ReadLRParm(struct site txsite, char forced_read)
 {
        /* This function reads Longley-Rice parameter data for the
           transmitter site.  The file name is the same as the txsite,
           except the filename extension is .lrp.  If the needed file
           is not found, then the file "splat.lrp" is read from the
-          current working directory.  Failure to load this file will
-          result in the default parameters hard coded into this
-          being used and written to "splat.lrp". */
-
-       double din;
-       char filename[255], lookup[256], string[80];
-       int iin, ok=0, x;
-       FILE *fd=NULL, *outfile=NULL;
-
-       /* Default parameters in case things go bad */
-
-       LR.eps_dielect=15.0;
-       LR.sgm_conductivity=0.005;
-       LR.eno_ns_surfref=301.0;
-       LR.frq_mhz=300.0;
-       LR.radio_climate=5;
+          current working directory.  Failure to load this file under
+          a forced_read condition will result in the default parameters
+          hard coded into this function to be used and written to
+          "splat.lrp". */
+
+       double  din;
+       char    filename[255], string[80], *pointer=NULL, return_value=0;
+       int     iin, ok=0, x;
+       FILE    *fd=NULL, *outfile=NULL;
+
+       /* Default parameters */
+
+       LR.eps_dielect=0.0;
+       LR.sgm_conductivity=0.0;
+       LR.eno_ns_surfref=0.0;
+       LR.frq_mhz=0.0;
+       LR.radio_climate=0;
        LR.pol=0;
-       LR.conf=0.50;
-       LR.rel=0.50;
+       LR.conf=0.0;
+       LR.rel=0.0;
+       LR.erp=0.0;
 
-       /* Modify txsite filename to one with a .lrp extension. */
+       /* Generate .lrp filename from txsite filename. */
 
-       strncpy(filename,txsite_filename,255);
-
-       for (x=0; filename[x]!='.' && filename[x]!=0 && filename[x]!='\n' && x<249; x++);
+       for (x=0; txsite.filename[x]!='.' && txsite.filename[x]!=0 && x<250; x++)
+               filename[x]=txsite.filename[x];
 
        filename[x]='.';
        filename[x+1]='l';
@@ -1605,20 +2337,6 @@ void ReadLRParm(char *txsite_filename)
        filename[x+3]='p';
        filename[x+4]=0;
 
-       /* Small lookup table to parse file, pass
-          numeric data, and ignore comments. */
-
-       for (x=0; x<=255; x++)
-               lookup[x]=0;
-
-       /* Valid characters */
-
-       for (x=48; x<=57; x++)
-               lookup[x]=x;
-
-       lookup[32]=32;
-       lookup[46]='.';
-
        fd=fopen(filename,"r");
 
        if (fd==NULL)
@@ -1633,10 +2351,10 @@ void ReadLRParm(char *txsite_filename)
        {
                fgets(string,80,fd);
 
-               for (x=0; lookup[(int)string[x]] && x<20; x++)
-                       string[x]=lookup[(int)string[x]];
+               pointer=strchr(string,';');
 
-               string[x]=0;
+               if (pointer!=NULL)
+                       *pointer=0;
 
                ok=sscanf(string,"%lf", &din);
 
@@ -1646,10 +2364,10 @@ void ReadLRParm(char *txsite_filename)
 
                        fgets(string,80,fd);
 
-                       for (x=0; lookup[(int)string[x]] && x<20; x++)
-                               string[x]=lookup[(int)string[x]];
+                       pointer=strchr(string,';');
 
-                       string[x]=0;
+                       if (pointer!=NULL)
+                               *pointer=0;
 
                        ok=sscanf(string,"%lf", &din);
                }
@@ -1660,10 +2378,10 @@ void ReadLRParm(char *txsite_filename)
 
                        fgets(string,80,fd);
 
-                       for (x=0; lookup[(int)string[x]] && x<20; x++)
-                               string[x]=lookup[(int)string[x]];
+                       pointer=strchr(string,';');
 
-                       string[x]=0;
+                       if (pointer!=NULL)
+                               *pointer=0;
 
                        ok=sscanf(string,"%lf", &din);
                }
@@ -1674,10 +2392,10 @@ void ReadLRParm(char *txsite_filename)
 
                        fgets(string,80,fd);
 
-                       for (x=0; lookup[(int)string[x]] && x<20; x++)
-                               string[x]=lookup[(int)string[x]];
+                       pointer=strchr(string,';');
 
-                       string[x]=0;
+                       if (pointer!=NULL)
+                               *pointer=0;
 
                        ok=sscanf(string,"%lf", &din);
                }
@@ -1688,10 +2406,10 @@ void ReadLRParm(char *txsite_filename)
 
                        fgets(string,80,fd);
 
-                       for (x=0; lookup[(int)string[x]] && x<20; x++)
-                               string[x]=lookup[(int)string[x]];
+                       pointer=strchr(string,';');
 
-                       string[x]=0;
+                       if (pointer!=NULL)
+                               *pointer=0;
 
                        ok=sscanf(string,"%d", &iin);
                }
@@ -1702,10 +2420,10 @@ void ReadLRParm(char *txsite_filename)
 
                        fgets(string,80,fd);
 
-                       for (x=0; lookup[(int)string[x]] && x<20; x++)
-                               string[x]=lookup[(int)string[x]];
+                       pointer=strchr(string,';');
 
-                       string[x]=0;
+                       if (pointer!=NULL)
+                               *pointer=0;
 
                        ok=sscanf(string,"%d", &iin);
                }
@@ -1716,10 +2434,10 @@ void ReadLRParm(char *txsite_filename)
 
                        fgets(string,80,fd);
 
-                       for (x=0; lookup[(int)string[x]] && x<20; x++)
-                               string[x]=lookup[(int)string[x]];
+                       pointer=strchr(string,';');
 
-                       string[x]=0;
+                       if (pointer!=NULL)
+                               *pointer=0;
 
                        ok=sscanf(string,"%lf", &din);
                }
@@ -1730,144 +2448,99 @@ void ReadLRParm(char *txsite_filename)
 
                        fgets(string,80,fd);
 
-                       for (x=0; lookup[(int)string[x]] && x<20; x++)
-                               string[x]=lookup[(int)string[x]];
+                       pointer=strchr(string,';');
 
-                       string[x]=0;
+                       if (pointer!=NULL)
+                               *pointer=0;
 
                        ok=sscanf(string,"%lf", &din);
                }
 
                if (ok)
+               {
                        LR.rel=din;
+                       din=0.0;
+                       return_value=1;
+
+                       if (fgets(string,80,fd)!=NULL)
+                       {
+                               pointer=strchr(string,':');
+
+                               if (pointer!=NULL)
+                                       *pointer=0;
+
+                               if (sscanf(string,"%lf", &din))
+                                       LR.erp=din;
+                       }
+               }
 
                fclose(fd);
+
+               if (forced_erp!=-1.0)
+                       LR.erp=forced_erp;
+
+               if (ok)
+                       LoadPAT(filename);
        } 
 
-       if (fd==NULL)
+       if (fd==NULL && forced_read)
        {
-               /* Create a "splat.lrp" file since one
-                  could not be successfully loaded. */
+               /* Assign some default parameters
+                  for use in this run. */
+
+               LR.eps_dielect=15.0;
+               LR.sgm_conductivity=0.005;
+               LR.eno_ns_surfref=301.0;
+               LR.frq_mhz=300.0;
+               LR.radio_climate=5;
+               LR.pol=0;
+               LR.conf=0.50;
+               LR.rel=0.50;
+               LR.erp=0.0;
+
+               /* Write them to a "splat.lrp" file. */
 
                outfile=fopen("splat.lrp","w");
 
                fprintf(outfile,"%.3f\t; Earth Dielectric Constant (Relative permittivity)\n",LR.eps_dielect);
-
                fprintf(outfile,"%.3f\t; Earth Conductivity (Siemens per meter)\n", LR.sgm_conductivity);
-
                fprintf(outfile,"%.3f\t; Atmospheric Bending Constant (N-Units)\n",LR.eno_ns_surfref);
-
                fprintf(outfile,"%.3f\t; Frequency in MHz (20 MHz to 20 GHz)\n", LR.frq_mhz);
-
                fprintf(outfile,"%d\t; Radio Climate\n",LR.radio_climate);
-
                fprintf(outfile,"%d\t; Polarization (0 = Horizontal, 1 = Vertical)\n", LR.pol);
-
                fprintf(outfile,"%.2f\t; Fraction of situations\n",LR.conf);
-
-               fprintf(outfile, "%.2f\t; Fraction of time\n",LR.rel);
-
+               fprintf(outfile,"%.2f\t; Fraction of time\n",LR.rel);
+               fprintf(outfile,"%.2f\t; Transmitter Effective Radiated Power in Watts (optional)\n",LR.erp);
                fprintf(outfile,"\nPlease consult SPLAT! documentation for the meaning and use of this data.\n");
 
                fclose(outfile);
 
-               fprintf(stderr,"\n%c*** There were problems reading your \"%s\" file! ***\nA \"splat.lrp\" file was written to your directory with default data.\n",7,filename);
-       }
-
-       if (fd==NULL || ok==0)
-               fprintf(stderr,"Longley-Rice default parameters have been assumed for this analysis.\n");
-}
-
-struct site los(struct site source, struct site destination)
-{
-       /* This function determines whether a line-of-sight path
-          unobstructed by terrain exists between source (transmitter)
-          and destination (receiver) based on the geographical
-          locations of the two sites, their respective antenna
-          heights above ground, and the terrain between them.
-          A site structure is returned upon completion.  If the
-          first character of site.name is ' ', then a clear path
-          exists between source and destination.  If the first
-          character is '*', then an obstruction exists, and the
-          site.lat and site.lon elements of the structure provide
-          the geographical location of the obstruction. */
-          
-       int x;
-       char block;
-       struct site test, blockage;
-       register double distance, tx_alt, rx_alt,
-                cos_xmtr_angle, cos_test_angle, test_alt;
-
-       ReadPath(source,destination);
+               return_value=1;
 
-       distance=5280.0*Distance(source,destination);
-       tx_alt=earthradius+source.alt+GetElevation(source);
-       rx_alt=earthradius+destination.alt+GetElevation(destination);
-
-       /* Elevation angle of the xmtr (source) as seen by the rcvr */
-
-       cos_xmtr_angle=((rx_alt*rx_alt)+(distance*distance)-(tx_alt*tx_alt))/(2.0*rx_alt*distance);
-
-       /* Determine the elevation angle of each discrete location
-          along the path between the receiver and transmitter.
+               fprintf(stderr,"\n\n%c*** There were problems reading your \"%s\" file! ***\nA \"splat.lrp\" file was written to your directory with default data.\n",7,filename);
+       }
 
-          Since obstructions are more likely due to terrain effects
-          closest to the receiver rather than farther away, we start
-          looking for potential obstructions from the receiver's
-          location, and work our way towards the transmitter.
-          This loop is broken when the first obstruction is
-          detected.  If we can travel all the way to the transmitter
-          without detecting an obstruction, then we have a clear
-          unobstructed path between transmitter and receiver. */
+       else if (forced_read==0)
+               return_value=0;
 
-       for (x=path.length-1, block=0; x>0 && block==0; x--)
+       if (forced_read && (fd==NULL || ok==0))
        {
-               /* Build a structure for each test
-                  point along the path to be surveyed. */
-
-               test.lat=path.lat[x];
-               test.lon=path.lon[x];
-
-               /* Measure the distance between the
-                  test point and the receiver locations */
-
-               distance=5280.0*Distance(test,destination);
-               test_alt=earthradius+path.elevation[x];
-
-               /* Determine the cosine of the elevation of the test
-                  point as seen from the location of the receiver */
-
-               cos_test_angle=((rx_alt*rx_alt)+(distance*distance)-(test_alt*test_alt))/(2.0*rx_alt*distance);
-
-               /* If the elevation angle to the test point (as seen from
-                  the receiver) is greater than the elevation angle to the
-                  transmitter (as seen by the receiver), then we have a
-                  path obstructed by terrain.  Note: Since we're comparing
-                  the cosines of these angles rather than the angles
-                  themselves (eliminating the call to acos() saves
-                  considerable time), the following "if" statement is
-                  reversed from what it would normally be if the angles
-                  were compared. */
+               LR.eps_dielect=15.0;
+               LR.sgm_conductivity=0.005;
+               LR.eno_ns_surfref=301.0;
+               LR.frq_mhz=300.0;
+               LR.radio_climate=5;
+               LR.pol=0;
+               LR.conf=0.50;
+               LR.rel=0.50;
+               LR.erp=0.0;
 
-               if (cos_xmtr_angle>cos_test_angle)
-               {
-                       block=1;
-                       blockage.lat=path.lat[x];
-                       blockage.lon=path.lon[x];
-                       blockage.alt=path.elevation[x];
-                       blockage.name[0]='*';
-               }
-       }
+               fprintf(stderr,"Longley-Rice default parameters have been assumed for this analysis.\n");
 
-       if (block==0)
-       {
-               blockage.lat=0.0;
-               blockage.lon=0.0;
-               blockage.alt=0.0;
-               blockage.name[0]=' ';
+               return_value=1;
        }
 
-       return blockage;
+       return (return_value);
 }
 
 void PlotPath(struct site source, struct site destination, char mask_value)
@@ -1928,55 +2601,206 @@ void PlotPath(struct site source, struct site destination, char mask_value)
        }
 }
 
-void PlotLRPath(struct site source, struct site destination)
+void PlotLRPath(struct site source, struct site destination, unsigned char mask_value, FILE *fd)
 {
-       /* This function plots the RF signal path loss
-          between source and destination points based
-          on the Longley-Rice propagation model. */
-
-       char strmode[100];
-       int x, y, errnum;
-       double loss;
+       /* This function plots the RF path loss between source and
+          destination points based on the Longley-Rice propagation
+          model, taking into account antenna pattern data, if available. */
+
+       int     x, y, ifs, ofs, errnum;
+       char    block=0, strmode[100];
+       double  loss, azimuth, pattern=0.0, 
+               xmtr_alt, dest_alt, xmtr_alt2, dest_alt2,
+               cos_rcvr_angle, cos_test_angle=0.0, test_alt,
+               elevation=0.0, distance=0.0, four_thirds_earth,
+               field_strength=0.0;
+       struct  site temp;
 
        ReadPath(source,destination);
-       elev_l[1]=0.04*METERS_PER_MILE;
+
+       four_thirds_earth=EARTHRADIUS*(4.0/3.0);
+
+       /* Copy elevations along path into the elev_l[] array. */
 
        for (x=0; x<path.length; x++)
-               elev_l[x+2]=path.elevation[x]*METERS_PER_FOOT;  
-        
-       for (y=0; y<path.length; y++)
+               elev_l[x+2]=path.elevation[x]*METERS_PER_FOOT;
+
+       /* Since the only energy the Longley-Rice model considers
+          reaching the destination is based on what is scattered
+          or deflected from the first obstruction along the path,
+          we first need to find the location and elevation angle
+          of that first obstruction (if it exists).  This is done
+          using a 4/3rds Earth radius to match the model used by
+          Longley-Rice.  This information is required for properly
+          integrating the antenna's elevation pattern into the
+          calculation for overall path loss.  (Using path.length-1
+          below avoids a Longley-Rice model error from occuring at
+          the destination point.) */
+
+       for (y=2; (y<(path.length-1) && path.distance[y]<=max_range); y++)
        {
-               /* Test this point only if it has not already been tested. */
+               /* Process this point only if it
+                  has not already been processed. */
 
-               if (GetMask(path.lat[y],path.lon[y])==0 && 0.04*y<=max_range)
+               if ((GetMask(path.lat[y],path.lon[y])&248)!=(mask_value<<3))
                {
-                       elev_l[0]=y+1;
+                       distance=5280.0*path.distance[y];
+                       xmtr_alt=four_thirds_earth+source.alt+path.elevation[0];
+                       dest_alt=four_thirds_earth+destination.alt+path.elevation[y];
+                       dest_alt2=dest_alt*dest_alt;
+                       xmtr_alt2=xmtr_alt*xmtr_alt;
+
+                       /* Calculate the cosine of the elevation of
+                          the receiver as seen by the transmitter. */
+
+                       cos_rcvr_angle=((xmtr_alt2)+(distance*distance)-(dest_alt2))/(2.0*xmtr_alt*distance);
+
+                       if (cos_rcvr_angle>1.0)
+                               cos_rcvr_angle=1.0;
+
+                       if (cos_rcvr_angle<-1.0)
+                               cos_rcvr_angle=-1.0;
+
+                       if (got_elevation_pattern || fd!=NULL)
+                       {
+                               /* Determine the elevation angle to the first obstruction
+                                  along the path IF elevation pattern data is available
+                                  or an output (.plo) file has been designated. */
+
+                               for (x=2, block=0; (x<y && block==0); x++)
+                               {
+                                       distance=5280.0*path.distance[x];
+
+                                       test_alt=four_thirds_earth+path.elevation[x];
+
+                                       /* Calculate the cosine of the elevation
+                                          angle of the terrain (test point)
+                                          as seen by the transmitter. */
+
+                                       cos_test_angle=((xmtr_alt2)+(distance*distance)-(test_alt*test_alt))/(2.0*xmtr_alt*distance);
+
+                                       if (cos_test_angle>1.0)
+                                               cos_test_angle=1.0;
+
+                                       if (cos_test_angle<-1.0)
+                                               cos_test_angle=-1.0;
+
+                                       /* Compare these two angles to determine if
+                                          an obstruction exists.  Since we're comparing
+                                          the cosines of these angles rather than
+                                          the angles themselves, the sense of the
+                                          following "if" statement is reversed from
+                                          what it would be if the angles themselves
+                                          were compared. */
+
+                                       if (cos_rcvr_angle>cos_test_angle)
+                                               block=1;
+                               }
+
+                               if (block)
+                                       elevation=((acos(cos_test_angle))/deg2rad)-90.0;
+                               else
+                                       elevation=((acos(cos_rcvr_angle))/deg2rad)-90.0;
+                       }
+
+                       /* Determine attenuation for each point along the
+                          path using Longley-Rice's point_to_point mode
+                          starting at y=2 (number_of_points = 1), the
+                          shortest distance terrain can play a role in
+                          path loss. */
+                       elev_l[0]=y-1;  /* (number of points - 1) */
+
+                       /* Distance between elevation samples */
+                       elev_l[1]=METERS_PER_MILE*(path.distance[y]-path.distance[y-1]);
 
                        point_to_point(elev_l,source.alt*METERS_PER_FOOT, 
-                       destination.alt*METERS_PER_FOOT,
-                       LR.eps_dielect, LR.sgm_conductivity, LR.eno_ns_surfref,
-                       LR.frq_mhz, LR.radio_climate, LR.pol, LR.conf, LR.rel,
-                       loss, strmode, errnum);
+                       destination.alt*METERS_PER_FOOT, LR.eps_dielect,
+                       LR.sgm_conductivity, LR.eno_ns_surfref, LR.frq_mhz,
+                       LR.radio_climate, LR.pol, LR.conf, LR.rel, loss,
+                       strmode, errnum);
+
+                       temp.lat=path.lat[y];
+                       temp.lon=path.lon[y];
+
+                       azimuth=(Azimuth(source,temp));
+
+                       /* Write path loss data to output file */
+
+                       if (fd!=NULL)
+                               fprintf(fd,"%.7f, %.7f, %.3f, %.3f, %.2f",path.lat[y], path.lon[y], azimuth, elevation, loss);
+
+                       /* Integrate the antenna's radiation
+                          pattern into the overall path loss. */
+
+                       x=(int)rint(10.0*(10.0-elevation));
+
+                       if (x>=0 && x<=1000)
+                       {
+                               azimuth=rint(azimuth);
+
+                               pattern=(double)LR.antenna_pattern[(int)azimuth][x];
 
-                       /* Note: PASS BY REFERENCE ... loss and errnum are
-                          passed by reference, and are only used in this
-                          file by this function */
+                               if (pattern!=0.0)
+                               {
+                                       pattern=20.0*log10(pattern);
+                                       loss-=pattern;
+
+                                       if (fd!=NULL && (got_elevation_pattern || got_azimuth_pattern))
+                                               fprintf(fd,", %.2f",loss);
+                               }
+                       }
+
+                       if (LR.erp!=0.0)
+                       {
+                               field_strength=(137.26+(20.0*log10(LR.frq_mhz))-loss)+(10.0*log10(LR.erp/1000.0));
+
+                               ifs=100+(int)rint(field_strength);
+
+                               if (ifs<0)
+                                       ifs=0;
 
-                       if (loss>225.0)
-                               loss=225.0;
+                               if (ifs>255)
+                                       ifs=255;
 
-                       if (loss<75.0)
-                               loss=75.0;
+                               ofs=GetSignal(path.lat[y],path.lon[y]);
 
-                       loss-=75.0;
-                       loss/=10.0;
-                       loss+=1.0;
+                               if (ofs>ifs)
+                                       ifs=ofs;
+
+                               PutSignal(path.lat[y],path.lon[y],(unsigned char)ifs);
                
-                       OrMask(path.lat[y],path.lon[y],((unsigned char)(loss))<<3);
-               }
+                               if (fd!=NULL)
+                                       fprintf(fd,", %.3f",field_strength);
+                       }
+
+                       else
+                       {
+                               if (loss>255)
+                                       ifs=255;
+                               else
+                                       ifs=(int)rint(loss);
+
+                               ofs=GetSignal(path.lat[y],path.lon[y]);
 
-               else if (GetMask(path.lat[y],path.lon[y])==0 && 0.04*y>max_range)
-                       OrMask(path.lat[y],path.lon[y],1);
+                               if (ofs<ifs && ofs!=0)
+                                       ifs=ofs;
+
+                               PutSignal(path.lat[y],path.lon[y],(unsigned char)ifs);
+                       }
+
+                       if (fd!=NULL)
+                       {
+                               if (block)
+                                       fprintf(fd," *");
+
+                               fprintf(fd,"\n");
+                       }
+
+                       /* Mark this point as being analyzed */
+
+                       PutMask(path.lat[y],path.lon[y],(GetMask(path.lat[y],path.lon[y])&7)+mask_value<<3);
+               }
        }
 }
 
@@ -1992,16 +2816,11 @@ void PlotCoverage(struct site source, double altitude)
           is later invoked. */
 
        float lat, lon, one_pixel;
-       static unsigned char mask_value;
+       static unsigned char mask_value=1;
        int z, count;
        struct site edge;
        unsigned char symbol[4], x;
 
-       /* Initialize mask_value */
-
-       if (mask_value!=8 && mask_value!=16 && mask_value!=32)
-               mask_value=1;
-
        one_pixel=1.0/1200.0;
 
        symbol[0]='.';
@@ -2011,7 +2830,7 @@ void PlotCoverage(struct site source, double altitude)
 
        count=0;        
 
-       fprintf(stdout,"\nComputing line-of-sight coverage of %s with an RX antenna\nat %.2f feet AGL:\n\n 0%c to  25%c ",source.name,altitude,37,37);
+       fprintf(stdout,"\n\nComputing line-of-sight coverage of \"%s\" with an RX antenna\nat %.2f %s AGL...\n\n 0%c to  25%c ",source.name,metric?altitude*METERS_PER_FOOT:altitude,metric?"meters":"feet",37,37);
        fflush(stdout);
 
        /* 18.75=1200 pixels/degree divided by 64 loops
@@ -2151,7 +2970,7 @@ void PlotCoverage(struct site source, double altitude)
        }
 }
 
-void PlotLRMap(struct site source, double altitude)
+void PlotLRMap(struct site source, double altitude, char *plo_filename)
 {
        /* This function performs a 360 degree sweep around the
           transmitter site (source location), and plots the
@@ -2159,13 +2978,15 @@ void PlotLRMap(struct site source, double altitude)
           topographic map based on a receiver located at
           the specified altitude (in feet AGL).  Results
           are stored in memory, and written out in the form
-          of a topographic map when the WritePPMLR() function
-          is later invoked. */
+          of a topographic map when the WritePPMLR() or
+          WritePPMSS() functions are later invoked. */
 
        int z, count;
        struct site edge;
        float lat, lon, one_pixel;
-       unsigned char symbol[4], x;
+       unsigned char x, symbol[4];
+       static unsigned char mask_value=1;
+       FILE *fd=NULL;
 
        one_pixel=1.0/1200.0;
 
@@ -2176,10 +2997,21 @@ void PlotLRMap(struct site source, double altitude)
 
        count=0;
 
-       fprintf(stdout,"\nComputing Longley-Rice coverage of %s ", source.name);
-       fprintf(stdout,"out to a radius\nof %.2f miles with an RX antenna at %.2f feet AGL:\n\n 0%c to  25%c ",max_range,altitude,37,37);
+       fprintf(stdout,"\n\nComputing Longley-Rice contours of \"%s\" ", source.name);
+
+       fprintf(stdout,"out to a radius\nof %.2f %s with an RX antenna at %.2f %s AGL...\n\n 0%c to  25%c ",metric?max_range*KM_PER_MILE:max_range,metric?"kilometers":"miles",metric?altitude*METERS_PER_FOOT:altitude,metric?"meters":"feet",37,37);
        fflush(stdout);
 
+       if (plo_filename[0]!=0)
+               fd=fopen(plo_filename,"wb");
+
+       if (fd!=NULL)
+       {
+               /* Write header information to output file */
+
+               fprintf(fd,"%d, %d\t; max_west, min_west\n%d, %d\t; max_north, min_north\n",max_west, min_west, max_north, min_north);
+       }
+
        /* 18.75=1200 pixels/degree divided by 64 loops
           per progress indicator symbol (.oOo) printed. */
 
@@ -2194,7 +3026,7 @@ void PlotLRMap(struct site source, double altitude)
                edge.lon=lon;
                edge.alt=altitude;
 
-               PlotLRPath(source,edge);
+               PlotLRPath(source,edge,mask_value,fd);
                count++;
 
                if (count==z) 
@@ -2222,7 +3054,7 @@ void PlotLRMap(struct site source, double altitude)
                edge.lon=min_west;
                edge.alt=altitude;
 
-               PlotLRPath(source,edge);
+               PlotLRPath(source,edge,mask_value,fd);
                count++;
 
                if (count==z) 
@@ -2253,7 +3085,7 @@ void PlotLRMap(struct site source, double altitude)
                edge.lon=lon;
                edge.alt=altitude;
 
-               PlotLRPath(source,edge);
+               PlotLRPath(source,edge,mask_value,fd);
                count++;
 
                if (count==z)
@@ -2281,7 +3113,7 @@ void PlotLRMap(struct site source, double altitude)
                edge.lon=max_west;
                edge.alt=altitude;
 
-               PlotLRPath(source,edge);
+               PlotLRPath(source,edge,mask_value,fd);
                count++;
 
                if (count==z)
@@ -2297,72 +3129,442 @@ void PlotLRMap(struct site source, double altitude)
                }
        }
 
+       if (fd!=NULL)
+               fclose(fd);
+
        fprintf(stdout,"\nDone!\n");
        fflush(stdout);
+
+       if (mask_value<30)
+               mask_value++;
 }
 
-void WritePPM(char *filename)
+void LoadSignalColors(struct site xmtr)
 {
-       /* This function generates a topographic map in Portable Pix Map
-          (PPM) format based on logarithmically scaled topology data,
-          as well as the content of flags held in the mask[][] array.
-          The image created is rotated counter-clockwise 90 degrees
-          from its representation in dem[][] so that north points
-          up and east points right in the image generated. */
+       int x, y, ok, val[4];
+       char filename[255], string[80], *pointer=NULL;
+       FILE *fd=NULL;
 
-       char mapfile[255];
-       unsigned char found, mask;
-       unsigned width, height, output;
-       int indx, x, y, x0=0, y0=0, minlat, minlon;
-       float lat, lon, one_pixel, conversion, one_over_gamma;
-       FILE *fd;
+       for (x=0; xmtr.filename[x]!='.' && xmtr.filename[x]!=0 && x<250; x++)
+               filename[x]=xmtr.filename[x];
 
-       one_pixel=1.0/1200.0;
-       one_over_gamma=1.0/GAMMA;
-       conversion=255.0/pow((double)(max_elevation-min_elevation),one_over_gamma);
+       filename[x]='.';
+       filename[x+1]='s';
+       filename[x+2]='c';
+       filename[x+3]='f';
+       filename[x+4]=0;
 
-       width=(unsigned)(1200*ReduceAngle(max_west-min_west));
-       height=(unsigned)(1200*ReduceAngle(max_north-min_north));
+       /* Default values */
+
+       region.level[0]=128;
+       region.color[0][0]=255;
+       region.color[0][1]=0;
+       region.color[0][2]=0;
+
+       region.level[1]=118;
+       region.color[1][0]=255;
+       region.color[1][1]=165;
+       region.color[1][2]=0;
+
+       region.level[2]=108;
+       region.color[2][0]=255;
+       region.color[2][1]=206;
+       region.color[2][2]=0;
+
+       region.level[3]=98;
+       region.color[3][0]=255;
+       region.color[3][1]=255;
+       region.color[3][2]=0;
+
+       region.level[4]=88;
+       region.color[4][0]=184;
+       region.color[4][1]=255;
+       region.color[4][2]=0;
+
+       region.level[5]=78;
+       region.color[5][0]=0;
+       region.color[5][1]=255;
+       region.color[5][2]=0;
+
+       region.level[6]=68;
+       region.color[6][0]=0;
+       region.color[6][1]=208;
+       region.color[6][2]=0;
+
+       region.level[7]=58;
+       region.color[7][0]=0;
+       region.color[7][1]=196;
+       region.color[7][2]=196;
+
+       region.level[8]=48;
+       region.color[8][0]=0;
+       region.color[8][1]=148;
+       region.color[8][2]=255;
+
+       region.level[9]=38;
+       region.color[9][0]=80;
+       region.color[9][1]=80;
+       region.color[9][2]=255;
+
+       region.level[10]=28;
+       region.color[10][0]=0;
+       region.color[10][1]=38;
+       region.color[10][2]=255;
+
+       region.level[11]=18;
+       region.color[11][0]=142;
+       region.color[11][1]=63;
+       region.color[11][2]=255;
+
+       region.level[12]=8;
+       region.color[12][0]=140;
+       region.color[12][1]=0;
+       region.color[12][2]=128;
+
+       region.levels=13;
+
+       fd=fopen("splat.scf","r");
 
-       if (filename[0]==0)
-               strncpy(mapfile, "map.ppm\0",8);
-       else
-       {
-               for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
-                       mapfile[x]=filename[x];
+       if (fd==NULL)
+               fd=fopen(filename,"r");
 
-               mapfile[x]='.';
-               mapfile[x+1]='p';
-               mapfile[x+2]='p';
-               mapfile[x+3]='m';
-               mapfile[x+4]=0;
-       }
+       if (fd==NULL)
+       {
+               fd=fopen(filename,"w");
 
-       fd=fopen(mapfile,"wb");
+               fprintf(fd,"; SPLAT! Auto-generated Signal Color Definition (\"%s\") File\n",filename);
+               fprintf(fd,";\n; Format for the parameters held in this file is as follows:\n;\n");
+               fprintf(fd,";    dBuV/m: red, green, blue\n;\n");
+               fprintf(fd,"; ...where \"dBuV/m\" is the signal strength (in dBuV/m) and\n");
+               fprintf(fd,"; \"red\", \"green\", and \"blue\" are the corresponding RGB color\n");
+               fprintf(fd,"; definitions ranging from 0 to 255 for the region specified.\n");
+               fprintf(fd,";\n; The following parameters may be edited and/or expanded\n");
+               fprintf(fd,"; for future runs of SPLAT!  A total of 32 contour regions\n");
+               fprintf(fd,"; may be defined in this file.\n;\n;\n");
 
-       fprintf(fd,"P6\n%u %u\n255\n",width,height);
+               for (x=0; x<region.levels; x++)
+                       fprintf(fd,"%3d: %3d, %3d, %3d\n",region.level[x], region.color[x][0], region.color[x][1], region.color[x][2]);
 
-       fprintf(stdout,"\nWriting \"%s\" (%ux%u pixmap image)... ",mapfile,width,height);
-       fflush(stdout);
+               fclose(fd);
+       }
 
-       for (y=0, lat=((double)max_north)-one_pixel; y<(int)height; y++, lat-=one_pixel)
+       else
        {
-               minlat=(int)floor(lat);
+               x=0;
+               fgets(string,80,fd);
 
-               for (x=0, lon=((double)max_west)-one_pixel; x<(int)width; x++, lon-=one_pixel)
+               while (x<32 && feof(fd)==0)
                {
-                       if (lon<0.0)
-                               lon+=360.0;
+                       pointer=strchr(string,';');
 
-                       minlon=(int)floor(lon);
+                       if (pointer!=NULL)
+                               *pointer=0;
 
-                       for (indx=0, found=0; indx<MAXSLOTS && found==0;)
-                               if (minlat==dem[indx].min_north && minlon==dem[indx].min_west)
-                                       found=1;
-                               else
-                                       indx++;
+                       ok=sscanf(string,"%d: %d, %d, %d", &val[0], &val[1], &val[2], &val[3]);
 
-                       if (found)
+                       if (ok==4)
+                       {
+                               for (y=0; y<4; y++)
+                               {
+                                       if (val[y]>255)
+                                               val[y]=255;
+
+                                       if (val[y]<0)
+                                               val[y]=0;
+                               }
+       
+                               region.level[x]=val[0];
+                               region.color[x][0]=val[1];
+                               region.color[x][1]=val[2];
+                               region.color[x][2]=val[3];
+                               x++;
+                       }
+
+                       fgets(string,80,fd);
+               }
+
+               fclose(fd);
+               region.levels=x;
+       }
+}
+
+void LoadLossColors(struct site xmtr)
+{
+       int x, y, ok, val[4];
+       char filename[255], string[80], *pointer=NULL;
+       FILE *fd=NULL;
+
+       for (x=0; xmtr.filename[x]!='.' && xmtr.filename[x]!=0 && x<250; x++)
+               filename[x]=xmtr.filename[x];
+
+       filename[x]='.';
+       filename[x+1]='l';
+       filename[x+2]='c';
+       filename[x+3]='f';
+       filename[x+4]=0;
+
+       /* Default values */
+
+       region.level[0]=80;
+       region.color[0][0]=255;
+       region.color[0][1]=0;
+       region.color[0][2]=0;
+
+       region.level[1]=90;
+       region.color[1][0]=255;
+       region.color[1][1]=128;
+       region.color[1][2]=0;
+
+       region.level[2]=100;
+       region.color[2][0]=255;
+       region.color[2][1]=165;
+       region.color[2][2]=0;
+
+       region.level[3]=110;
+       region.color[3][0]=255;
+       region.color[3][1]=206;
+       region.color[3][2]=0;
+
+       region.level[4]=120;
+       region.color[4][0]=255;
+       region.color[4][1]=255;
+       region.color[4][2]=0;
+
+       region.level[5]=130;
+       region.color[5][0]=184;
+       region.color[5][1]=255;
+       region.color[5][2]=0;
+
+       region.level[6]=140;
+       region.color[6][0]=0;
+       region.color[6][1]=255;
+       region.color[6][2]=0;
+
+       region.level[7]=150;
+       region.color[7][0]=0;
+       region.color[7][1]=208;
+       region.color[7][2]=0;
+
+       region.level[8]=160;
+       region.color[8][0]=0;
+       region.color[8][1]=196;
+       region.color[8][2]=196;
+
+       region.level[9]=170;
+       region.color[9][0]=0;
+       region.color[9][1]=148;
+       region.color[9][2]=255;
+
+       region.level[10]=180;
+       region.color[10][0]=80;
+       region.color[10][1]=80;
+       region.color[10][2]=255;
+
+       region.level[11]=190;
+       region.color[11][0]=0;
+       region.color[11][1]=38;
+       region.color[11][2]=255;
+
+       region.level[12]=200;
+       region.color[12][0]=142;
+       region.color[12][1]=63;
+       region.color[12][2]=255;
+
+       region.level[13]=210;
+       region.color[13][0]=196;
+       region.color[13][1]=54;
+       region.color[13][2]=255;
+
+       region.level[14]=220;
+       region.color[14][0]=255;
+       region.color[14][1]=0;
+       region.color[14][2]=255;
+
+       region.level[15]=230;
+       region.color[15][0]=255;
+       region.color[15][1]=194;
+       region.color[15][2]=204;
+
+       region.levels=16;
+
+       fd=fopen("splat.lcf","r");
+
+       if (fd==NULL)
+               fd=fopen(filename,"r");
+
+       if (fd==NULL)
+       {
+               fd=fopen(filename,"w");
+
+               fprintf(fd,"; SPLAT! Auto-generated Path-Loss Color Definition (\"%s\") File\n",filename);
+               fprintf(fd,";\n; Format for the parameters held in this file is as follows:\n;\n");
+               fprintf(fd,";    dB: red, green, blue\n;\n");
+               fprintf(fd,"; ...where \"dB\" is the path loss (in dB) and\n");
+               fprintf(fd,"; \"red\", \"green\", and \"blue\" are the corresponding RGB color\n");
+               fprintf(fd,"; definitions ranging from 0 to 255 for the region specified.\n");
+               fprintf(fd,";\n; The following parameters may be edited and/or expanded\n");
+               fprintf(fd,"; for future runs of SPLAT!  A total of 32 contour regions\n");
+               fprintf(fd,"; may be defined in this file.\n;\n;\n");
+
+               for (x=0; x<region.levels; x++)
+                       fprintf(fd,"%3d: %3d, %3d, %3d\n",region.level[x], region.color[x][0], region.color[x][1], region.color[x][2]);
+
+               fclose(fd);
+       }
+
+       else
+       {
+               x=0;
+               fgets(string,80,fd);
+
+               while (x<32 && feof(fd)==0)
+               {
+                       pointer=strchr(string,';');
+
+                       if (pointer!=NULL)
+                               *pointer=0;
+
+                       ok=sscanf(string,"%d: %d, %d, %d", &val[0], &val[1], &val[2], &val[3]);
+
+                       if (ok==4)
+                       {
+                               for (y=0; y<4; y++)
+                               {
+                                       if (val[y]>255)
+                                               val[y]=255;
+
+                                       if (val[y]<0)
+                                               val[y]=0;
+                               }
+       
+                               region.level[x]=val[0];
+                               region.color[x][0]=val[1];
+                               region.color[x][1]=val[2];
+                               region.color[x][2]=val[3];
+                               x++;
+                       }
+
+                       fgets(string,80,fd);
+               }
+
+               fclose(fd);
+               region.levels=x;
+       }
+}
+
+void WritePPM(char *filename, unsigned char geo, unsigned char kml, unsigned char ngs)
+{
+       /* This function generates a topographic map in Portable Pix Map
+          (PPM) format based on logarithmically scaled topology data,
+          as well as the content of flags held in the mask[][] array.
+          The image created is rotated counter-clockwise 90 degrees
+          from its representation in dem[][] so that north points
+          up and east points right in the image generated. */
+
+       char mapfile[255], geofile[255], kmlfile[255];
+       unsigned char found, mask;
+       unsigned width, height, terrain;
+       int indx, x, y, x0=0, y0=0;
+       double lat, lon, one_pixel, conversion, one_over_gamma;  /* USED to be float... */
+       FILE *fd;
+
+       one_pixel=1.0/1200.0;
+       one_over_gamma=1.0/GAMMA;
+       conversion=255.0/pow((double)(max_elevation-min_elevation),one_over_gamma);
+
+       width=(unsigned)(1200*ReduceAngle(max_west-min_west));
+       height=(unsigned)(1200*ReduceAngle(max_north-min_north));
+
+       if (filename[0]==0)
+               strncpy(filename, "map.ppm\0",8);
+
+       for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
+       {
+               mapfile[x]=filename[x];
+               geofile[x]=filename[x];
+               kmlfile[x]=filename[x];
+       }
+
+       mapfile[x]='.';
+       geofile[x]='.';
+       kmlfile[x]='.';
+       mapfile[x+1]='p';
+       geofile[x+1]='g';
+       kmlfile[x+1]='k';
+       mapfile[x+2]='p';
+       geofile[x+2]='e';
+       kmlfile[x+2]='m';
+       mapfile[x+3]='m';
+       geofile[x+3]='o';
+       kmlfile[x+3]='l';
+       mapfile[x+4]=0;
+       geofile[x+4]=0;
+       kmlfile[x+4]=0;
+
+       if (kml==0 && geo)
+       {
+               fd=fopen(geofile,"wb");
+
+               fprintf(fd,"FILENAME\t%s\n",mapfile);
+               fprintf(fd,"#\t\tX\tY\tLong\t\tLat\n");
+               fprintf(fd,"TIEPOINT\t0\t0\t%d.000\t\t%d.000\n",(max_west<180?-max_west:360-max_west),max_north);
+               fprintf(fd,"TIEPOINT\t%u\t%u\t%d.000\t\t%d.000\n",width-1,height-1,(min_west<180?-min_west:360-min_west),min_north);
+               fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height);
+               fprintf(fd,"#\n# Auto Generated by SPLAT! v%s\n#\n",splat_version);
+
+               fclose(fd);
+       }
+
+       if (kml && geo==0)
+       {
+               fd=fopen(kmlfile,"wb");
+
+               fprintf(fd,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+               fprintf(fd,"<kml xmlns=\"http://earth.google.com/kml/2.1\">\n");
+               fprintf(fd,"  <Folder>\n");
+               fprintf(fd,"   <name>SPLAT!</name>\n");
+               fprintf(fd,"     <description>Line-of-Sight Overlay</description>\n");
+               fprintf(fd,"       <GroundOverlay>\n");
+               fprintf(fd,"         <name>SPLAT! Line-of-Sight Overlay</name>\n");
+               fprintf(fd,"           <description>SPLAT! Coverage</description>\n");
+               fprintf(fd,"            <Icon>\n");
+               fprintf(fd,"              <href>%s</href>\n",mapfile);
+               fprintf(fd,"            </Icon>\n");
+               fprintf(fd,"            <opacity>128</opacity>\n");
+               fprintf(fd,"            <LatLonBox>\n");
+               fprintf(fd,"               <north>%.5f</north>\n",(double)max_north-one_pixel);
+               fprintf(fd,"               <south>%.5f</south>\n",(double)min_north);
+               fprintf(fd,"               <east>%.5f</east>\n",((double)min_west<180.0?(double)-min_west:360.0-(double)min_west));
+               fprintf(fd,"               <west>%.5f</west>\n",(((double)max_west-one_pixel)<180.0?-((double)max_west-one_pixel):(360.0-(double)max_west-one_pixel)));
+               fprintf(fd,"               <rotation>0.0</rotation>\n");
+               fprintf(fd,"            </LatLonBox>\n");
+               fprintf(fd,"       </GroundOverlay>\n");
+               fprintf(fd,"  </Folder>\n");
+               fprintf(fd,"</kml>\n");
+
+               fclose(fd);
+       }
+
+       fd=fopen(mapfile,"wb");
+
+       fprintf(fd,"P6\n%u %u\n255\n",width,height);
+       fprintf(stdout,"\nWriting \"%s\" (%ux%u pixmap image)... ",mapfile,width,height);
+       fflush(stdout);
+
+       for (y=0, lat=(double)max_north-one_pixel; y<(int)height; y++, lat=(double)max_north-(one_pixel*(double)y))
+       {
+               for (x=0, lon=(double)max_west-one_pixel; x<(int)width; x++, lon=(double)max_west-(one_pixel*(double)x))
+               {
+                       if (lon<0.0)
+                               lon+=360.0;
+
+                       for (indx=0, found=0; indx<MAXPAGES && found==0;)
+                               if (lat>=(double)dem[indx].min_north && lat<(double)dem[indx].max_north && LonDiff(lon,(double)dem[indx].min_west)>=0.0 && LonDiff(lon,(double)dem[indx].max_west)<0.0)
+                                       found=1;
+                               else
+                                       indx++;
+
+                       if (found)
                        {
                                x0=(int)(1199.0*(lat-floor(lat)));
                                y0=(int)(1199.0*(lon-floor(lon)));
@@ -2455,14 +3657,19 @@ void WritePPM(char *filename)
                                        break;
 
                                        default:
-                                       /* Water: Medium Blue */
-                                       if (dem[indx].data[x0][y0]==0)
-                                               fprintf(fd,"%c%c%c",0,0,170);
+                                       if (ngs)  /* No terrain */
+                                               fprintf(fd,"%c%c%c",255,255,255);
                                        else
                                        {
-                                               /* Elevation: Greyscale */
-                                               output=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
-                                               fprintf(fd,"%c%c%c",output,output,output);
+                                               /* Sea-level: Medium Blue */
+                                               if (dem[indx].data[x0][y0]==0)
+                                                       fprintf(fd,"%c%c%c",0,0,170);
+                                               else
+                                               {
+                                                       /* Elevation: Greyscale */
+                                                       terrain=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
+                                                       fprintf(fd,"%c%c%c",terrain,terrain,terrain);
+                                               }
                                        }
                                }
                        }
@@ -2482,7 +3689,7 @@ void WritePPM(char *filename)
        fflush(stdout);
 }
 
-void WritePPMLR(char *filename)
+void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned char ngs, struct site *xmtr, unsigned char txsites)
 {
        /* This function generates a topographic map in Portable Pix Map
           (PPM) format based on the content of flags held in the mask[][] 
@@ -2490,11 +3697,12 @@ void WritePPMLR(char *filename)
           90 degrees from its representation in dem[][] so that north
           points up and east points right in the image generated. */
 
-       char mapfile[255];
-       unsigned width, height, output;
+       char mapfile[255], geofile[255], kmlfile[255], color=0;
+       unsigned width, height, red, green, blue, terrain=0;
        unsigned char found, mask, cityorcounty;
-       int indx, x, y, t, t2, x0, y0, minlat, minlon, loss;
-       float lat, lon, one_pixel, conversion, one_over_gamma;
+       int indx, x, y, z, colorwidth, x0, y0, loss, level,
+           hundreds, tens, units, match;
+       double lat, lon, one_pixel, conversion, one_over_gamma;
        FILE *fd;
 
        one_pixel=1.0/1200.0;
@@ -2504,66 +3712,171 @@ void WritePPMLR(char *filename)
        width=(unsigned)(1200*ReduceAngle(max_west-min_west));
        height=(unsigned)(1200*ReduceAngle(max_north-min_north));
 
+       LoadLossColors(xmtr[0]);
+
        if (filename[0]==0)
-               strncpy(mapfile, "map.ppm\0",8);
-       else
+               strncpy(filename, xmtr[0].filename,254);
+
+       for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
        {
-               for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
-                       mapfile[x]=filename[x];
+               mapfile[x]=filename[x];
+               geofile[x]=filename[x];
+               kmlfile[x]=filename[x];
+       }
+
+       mapfile[x]='.';
+       geofile[x]='.';
+       kmlfile[x]='.';
+       mapfile[x+1]='p';
+       geofile[x+1]='g';
+       kmlfile[x+1]='k';
+       mapfile[x+2]='p';
+       geofile[x+2]='e';
+       kmlfile[x+2]='m';
+       mapfile[x+3]='m';
+       geofile[x+3]='o';
+       kmlfile[x+3]='l';
+       mapfile[x+4]=0;
+       geofile[x+4]=0;
+       kmlfile[x+4]=0;
+
+       if (kml==0 && geo)
+       {
+               fd=fopen(geofile,"wb");
+
+               fprintf(fd,"FILENAME\t%s\n",mapfile);
+               fprintf(fd,"#\t\tX\tY\tLong\t\tLat\n");
+               fprintf(fd,"TIEPOINT\t0\t0\t%d.000\t\t%d.000\n",(max_west<180?-max_west:360-max_west),max_north);
+               fprintf(fd,"TIEPOINT\t%u\t%u\t%d.000\t\t%.3f\n",width-1,height+29,(min_west<180?-min_west:360-min_west),(double)(min_north-0.025));
+               fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height+30);
+               fprintf(fd,"#\n# Auto Generated by SPLAT! v%s\n#\n",splat_version);
 
-               mapfile[x]='.';
-               mapfile[x+1]='p';
-               mapfile[x+2]='p';
-               mapfile[x+3]='m';
-               mapfile[x+4]=0;
+               fclose(fd);
        }
 
-       fd=fopen(mapfile,"wb");
+       if (kml && geo==0)
+       {
+               fd=fopen(kmlfile,"wb");
+
+               fprintf(fd,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+               fprintf(fd,"<kml xmlns=\"http://earth.google.com/kml/2.1\">\n");
+               fprintf(fd,"<!-- Generated by SPLAT! Version %s -->\n",splat_version);
+               fprintf(fd,"  <Folder>\n");
+               fprintf(fd,"   <name>SPLAT!</name>\n");
+               fprintf(fd,"     <description>%s Transmitter Path Loss Overlay</description>\n",xmtr[0].name);
+               fprintf(fd,"       <GroundOverlay>\n");
+               fprintf(fd,"         <name>SPLAT! Path Loss Overlay</name>\n");
+               fprintf(fd,"           <description>SPLAT! Coverage</description>\n");
+               fprintf(fd,"            <Icon>\n");
+               fprintf(fd,"              <href>%s</href>\n",mapfile);
+               fprintf(fd,"            </Icon>\n");
+               fprintf(fd,"            <opacity>128</opacity>\n");
+               fprintf(fd,"            <LatLonBox>\n");
+               fprintf(fd,"               <north>%.5f</north>\n",(double)max_north-one_pixel);
+               fprintf(fd,"               <south>%.5f</south>\n",(double)min_north);
+               fprintf(fd,"               <east>%.5f</east>\n",((double)min_west<180.0?(double)-min_west:360.0-(double)min_west));
+               fprintf(fd,"               <west>%.5f</west>\n",(((double)max_west-one_pixel)<180.0?-((double)max_west-one_pixel):(360.0-(double)max_west-one_pixel)));
+               fprintf(fd,"               <rotation>0.0</rotation>\n");
+               fprintf(fd,"            </LatLonBox>\n");
+               fprintf(fd,"       </GroundOverlay>\n");
+
+               for (x=0; x<txsites; x++)
+               {
+                       fprintf(fd,"     <Placemark>\n");
+                       fprintf(fd,"       <name>%s</name>\n",xmtr[x].name);
+                       fprintf(fd,"       <visibility>1</visibility>\n");
+                       fprintf(fd,"       <Style>\n");
+                       fprintf(fd,"       <IconStyle>\n");
+                       fprintf(fd,"        <Icon>\n");
+                       fprintf(fd,"          <href>root://icons/palette-5.png</href>\n");
+                       fprintf(fd,"          <x>224</x>\n");
+                       fprintf(fd,"          <y>224</y>\n");
+                       fprintf(fd,"          <w>32</w>\n");
+                       fprintf(fd,"          <h>32</h>\n");
+                       fprintf(fd,"        </Icon>\n");
+                       fprintf(fd,"       </IconStyle>\n");
+                       fprintf(fd,"       </Style>\n");
+                       fprintf(fd,"      <Point>\n");
+                       fprintf(fd,"        <extrude>1</extrude>\n");
+                       fprintf(fd,"        <altitudeMode>relativeToGround</altitudeMode>\n");
+                       fprintf(fd,"        <coordinates>%f,%f,%f</coordinates>\n",(xmtr[x].lon<180.0?-xmtr[x].lon:360.0-xmtr[x].lon), xmtr[x].lat, xmtr[x].alt);
+                       fprintf(fd,"      </Point>\n");
+                       fprintf(fd,"     </Placemark>\n");
+               }
+
+               fprintf(fd,"  </Folder>\n");
+               fprintf(fd,"</kml>\n");
 
-       fprintf(fd,"P6\n%u %u\n255\n",width,height+30);
+               fclose(fd);
+       }
+
+       fd=fopen(mapfile,"wb");
 
-       fprintf(stdout,"\nWriting \"%s\" (%ux%u pixmap image)... ",mapfile,width,height+30);
+       fprintf(fd,"P6\n%u %u\n255\n",width,(kml?height:height+30));
+       fprintf(stdout,"\nWriting \"%s\" (%ux%u pixmap image)... ",mapfile,width,(kml?height:height+30));
        fflush(stdout);
 
-       for (y=0, lat=((double)max_north)-one_pixel; y<(int)height; y++, lat-=one_pixel)
+       for (y=0, lat=(double)max_north-one_pixel; y<(int)height; y++, lat=(double)max_north-(one_pixel*(double)y))
        {
-               minlat=(int)floor(lat);
-
-               for (x=0, lon=((double)max_west)-one_pixel; x<(int)width; x++, lon-=one_pixel)
+               for (x=0, lon=(double)max_west-one_pixel; x<(int)width; x++, lon=(double)max_west-(one_pixel*(double)x))
                {
                        if (lon<0.0)
                                lon+=360.0;
 
-                       minlon=(int)floor(lon);
-
-                       for (indx=0, found=0; indx<MAXSLOTS && found==0;)
-                               if (minlat==dem[indx].min_north && minlon==dem[indx].min_west)
+                       for (indx=0, found=0; indx<MAXPAGES && found==0;)
+                               if (lat>=(double)dem[indx].min_north && lat<(double)dem[indx].max_north && LonDiff(lon,(double)dem[indx].min_west)>=0.0 && LonDiff(lon,(double)dem[indx].max_west)<0.0)
                                        found=1;
                                else
                                        indx++;
+
                        if (found)
                        {
                                x0=(int)(1199.0*(lat-floor(lat)));
                                y0=(int)(1199.0*(lon-floor(lon)));
 
                                mask=dem[indx].mask[x0][y0];
-                               loss=70+(10*(int)((mask&248)>>3));
+                               loss=(dem[indx].signal[x0][y0]);
                                cityorcounty=0;
 
-                               if (mask&2)
+                               match=255;
+
+                               red=0;
+                               green=0;
+                               blue=0;
+
+                               if (loss<=region.level[0])
+                                       match=0;
+                               else
+                               {
+                                       for (z=1; (z<region.levels && match==255); z++)
+                                       {
+                                               if (loss>=region.level[z-1] && loss<region.level[z])
+                                                       match=z;
+                                       }
+                               }
+
+                               if (match<region.levels)
                                {
-                                       /* Text Labels - Black or Red */
+                                       red=region.color[match][0];
+                                       green=region.color[match][1];
+                                       blue=region.color[match][2];
 
-                                       /* if ((mask&120) && (loss<=maxdB)) */
-                                       if ((mask&120) && (loss<=90))
-                                               fprintf(fd,"%c%c%c",0,0,0);
-                                       else
-                                               fprintf(fd,"%c%c%c",255,0,0);
+                                       color=1;
+                               }
 
-                                       cityorcounty=1;
+                               if ((mask&2) && (kml==0))
+                               {
+                                       /* Text Labels: Red or otherwise */
+
+                                       if (red>=180 && green<=75 && blue<=75 && loss!=0)
+                                                fprintf(fd,"%c%c%c",255^red,255^green,255^blue);
+                                        else
+                                                fprintf(fd,"%c%c%c",255,0,0);
+
+                                        cityorcounty=1;
                                }
 
-                               else if (mask&4)
+                               else if ((mask&4) && (kml==0))
                                {
                                        /* County Boundaries: Black */
 
@@ -2574,97 +3887,41 @@ void WritePPMLR(char *filename)
 
                                if (cityorcounty==0)
                                {
-                                       if (loss>maxdB)
-
-                                       { /* Display land or sea elevation */
-
-                                               if (dem[indx].data[x0][y0]==0)
-                                                       fprintf(fd,"%c%c%c",0,0,170);
+                                       if (loss>maxdB || loss==0)
+                                       {
+                                               if (ngs)  /* No terrain */
+                                                       fprintf(fd,"%c%c%c",255,255,255);
                                                else
                                                {
-                                                       /* Elevation: Greyscale */
-                                                       output=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
-                                                       fprintf(fd,"%c%c%c",output,output,output);
+                                                       /* Display land or sea elevation */
+
+                                                       if (dem[indx].data[x0][y0]==0)
+                                                               fprintf(fd,"%c%c%c",0,0,170);
+                                                       else
+                                                       {
+                                                               terrain=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
+                                                               fprintf(fd,"%c%c%c",terrain,terrain,terrain);
+                                                       }
                                                }
                                        }
 
-                                       else switch (loss)
+                                       else
                                        {
-                                               /* Plot signal loss in color */
-
-                                               case 80:
-                                               fprintf(fd,"%c%c%c",255,0,0);
-                                               break;
-
-                                               case 90:
-                                               fprintf(fd,"%c%c%c",255,128,0);
-                                               break;
-
-                                               case 100:
-                                               fprintf(fd,"%c%c%c",255,165,0);
-                                               break;
-
-                                               case 110:
-                                               fprintf(fd,"%c%c%c",255,206,0);
-                                               break;
-
-                                               case 120:
-                                               fprintf(fd,"%c%c%c",255,255,0);
-                                               break;
-
-                                               case 130:
-                                               fprintf(fd,"%c%c%c",184,255,0);
-                                               break;
-
-                                               case 140:
-                                               fprintf(fd,"%c%c%c",0,255,0);
-                                               break;
-
-                                               case 150:
-                                               fprintf(fd,"%c%c%c",0,208,0);
-                                               break;
-
-                                               case 160:
-                                               fprintf(fd,"%c%c%c",0,196,196);
-                                               break;
-
-                                               case 170:
-                                               fprintf(fd,"%c%c%c",0,148,255);
-                                               break;
-
-                                               case 180:
-                                               fprintf(fd,"%c%c%c",80,80,255);
-                                               break;
-
-                                               case 190:
-                                               fprintf(fd,"%c%c%c",0,38,255);
-                                               break;
-
-                                               case 200:
-                                               fprintf(fd,"%c%c%c",142,63,255);
-                                               break;
-
-                                               case 210:
-                                               fprintf(fd,"%c%c%c",196,54,255);
-                                               break;
-
-                                               case 220:
-                                               fprintf(fd,"%c%c%c",255,0,255);
-                                               break;
-
-                                               case 230:
-                                               fprintf(fd,"%c%c%c",255,194,204);
-                                               break;
+                                               /* Plot path loss in color */
 
-                                               default:
+                                               if (red!=0 || green!=0 || blue!=0)
+                                                       fprintf(fd,"%c%c%c",red,green,blue);
 
-                                               if (dem[indx].data[x0][y0]==0)
-                                                       fprintf(fd,"%c%c%c",0,0,170);
-                                               else
+                                               else  /* terrain / sea-level */
                                                {
-                                                       /* Elevation: Greyscale */
-                                                       output=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
-                                                       fprintf(fd,"%c%c%c",output,output,output);
+                                                       if (dem[indx].data[x0][y0]==0)
+                                                               fprintf(fd,"%c%c%c",0,0,170);
+                                                       else
+                                                       {
+                                                               /* Elevation: Greyscale */
+                                                               terrain=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
+                                                               fprintf(fd,"%c%c%c",terrain,terrain,terrain);
+                                                       }
                                                }
                                        }
                                }
@@ -2680,106 +3937,70 @@ void WritePPMLR(char *filename)
                }
        }
 
-       /* Display legend along bottom of image */
+       if (kml==0 && color)
+       {
+               /* Display legend along bottom of image */
 
-       x0=width/16;
+               colorwidth=(int)rint((float)width/(float)region.levels);
 
-       for (y0=0; y0<30; y0++)
-       {
-               for (indx=0; indx<16; indx++)
+               for (y0=0; y0<30; y0++)
                {
-                       for (x=0; x<x0; x++)
+                       for (x0=0; x0<(int)width; x0++)
                        {
-                               t=indx;  
-                               t2=indx+8;
-
-                               if (y0>=10 && y0<=18)
-                               {  
-                                       if (t2>9)
-                                       {
-                                               if (x>=11 && x<=17)     
-                                                       if (smallfont[t2/10][y0-10][x-11])
-                                                               t=255; 
-                                       }
-
-                                       if (x>=19 && x<=25)     
-                                               if (smallfont[t2%10][y0-10][x-19])
-                                                       t=255;
-                                       if (x>=27 && x<=33)
-                                               if (smallfont[0][y0-10][x-27])
-                                                       t=255; 
-                               }
-
-                               switch (t)
-                               {
-                                       case 0:
-                                       fprintf(fd,"%c%c%c",255,0,0);
-                                       break;
-
-                                       case 1:
-                                       fprintf(fd,"%c%c%c",255,128,0);
-                                       break;
-
-                                       case 2:
-                                       fprintf(fd,"%c%c%c",255,165,0);
-                                       break;
-
-                                       case 3:
-                                       fprintf(fd,"%c%c%c",255,206,0);
-                                       break;
-
-                                       case 4:
-                                       fprintf(fd,"%c%c%c",255,255,0);
-                                       break;
-
-                                       case 5:
-                                       fprintf(fd,"%c%c%c",184,255,0);
-                                       break;
+                               indx=x0/colorwidth;
+                               x=x0%colorwidth;
+                               level=region.level[indx];
 
-                                       case 6:
-                                       fprintf(fd,"%c%c%c",0,255,0);
-                                       break;
+                               hundreds=level/100;
 
-                                       case 7:
-                                       fprintf(fd,"%c%c%c",0,208,0);
-                                       break;
+                               if (hundreds>0)
+                                       level-=(hundreds*100);
 
-                                       case 8:
-                                       fprintf(fd,"%c%c%c",0,196,196);
-                                       break;
+                               tens=level/10;
 
-                                       case 9:
-                                       fprintf(fd,"%c%c%c",0,148,255);
-                                       break;
+                               if (tens>0)
+                                       level-=(tens*10);
 
-                                       case 10:
-                                       fprintf(fd,"%c%c%c",80,80,255);
-                                       break;
+                               units=level;
 
-                                       case 11:
-                                       fprintf(fd,"%c%c%c",0,38,255);
-                                       break;
+                               if (y0>=8 && y0<=23)
+                               {  
+                                       if (hundreds>0)
+                                       {
+                                               if (x>=11 && x<=18)     
+                                                       if (fontdata[16*(hundreds+'0')+(y0-8)]&(128>>(x-11)))
+                                                               indx=255; 
+                                       }
 
-                                       case 12:
-                                       fprintf(fd,"%c%c%c",142,63,255);
-                                       break;
+                                       if (tens>0 || hundreds>0)
+                                       {
+                                               if (x>=19 && x<=26)     
+                                                       if (fontdata[16*(tens+'0')+(y0-8)]&(128>>(x-19)))
+                                                               indx=255;
+                                       }
+                                       if (x>=27 && x<=34)
+                                               if (fontdata[16*(units+'0')+(y0-8)]&(128>>(x-27)))
+                                                       indx=255;
 
-                                       case 13:
-                                       fprintf(fd,"%c%c%c",196,54,255);
-                                       break;
+                                       if (x>=42 && x<=49)
+                                               if (fontdata[16*('d')+(y0-8)]&(128>>(x-42)))
+                                                       indx=255;
 
-                                       case 14:
-                                       fprintf(fd,"%c%c%c",255,0,255);
-                                       break;
+                                       if (x>=50 && x<=57)
+                                               if (fontdata[16*('B')+(y0-8)]&(128>>(x-50)))
+                                                       indx=255;
+                               }
 
-                                       case 255:
-                                       /* Black */
+                               if (indx>region.levels)
                                        fprintf(fd,"%c%c%c",0,0,0);
-                                       break;
+                               else
+                               {
+                                       red=region.color[indx][0];
+                                       green=region.color[indx][1];
+                                       blue=region.color[indx][2];
 
-                                       default:
-                                       fprintf(fd,"%c%c%c",255,194,204);
+                                       fprintf(fd,"%c%c%c",red,green,blue);
                                }
                        } 
                }
@@ -2790,25 +4011,373 @@ void WritePPMLR(char *filename)
        fflush(stdout);
 }
 
-void GraphTerrain(struct site source, struct site destination, char *name)
+void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned char ngs, struct site *xmtr, unsigned char txsites)
 {
-       /* This function invokes gnuplot to generate an appropriate
-          output file indicating the terrain profile between the source
-          and destination locations.  "filename" is the name assigned
-          to the output file generated by gnuplot.  The filename extension
+       /* This function generates a topographic map in Portable Pix Map
+          (PPM) format based on the signal strength values held in the
+          signal[][] array.  The image created is rotated counter-clockwise
+          90 degrees from its representation in dem[][] so that north
+          points up and east points right in the image generated. */
+
+       char mapfile[255], geofile[255], kmlfile[255], color=0;
+       unsigned width, height, terrain, red, green, blue;
+       unsigned char found, mask, cityorcounty;
+       int indx, x, y, z=1, x0, y0, signal, level, hundreds,
+           tens, units, match, colorwidth;
+       double lat, lon, one_pixel, conversion, one_over_gamma;
+       FILE *fd;
+
+       one_pixel=1.0/1200.0;
+       one_over_gamma=1.0/GAMMA;
+       conversion=255.0/pow((double)(max_elevation-min_elevation),one_over_gamma);
+
+       width=(unsigned)(1200*ReduceAngle(max_west-min_west));
+       height=(unsigned)(1200*ReduceAngle(max_north-min_north));
+
+       LoadSignalColors(xmtr[0]);
+
+       if (filename[0]==0)
+               strncpy(filename, xmtr[0].filename,254);
+
+       for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
+       {
+               mapfile[x]=filename[x];
+               geofile[x]=filename[x];
+               kmlfile[x]=filename[x];
+       }
+
+       mapfile[x]='.';
+       geofile[x]='.';
+       kmlfile[x]='.';
+       mapfile[x+1]='p';
+       geofile[x+1]='g';
+       kmlfile[x+1]='k';
+       mapfile[x+2]='p';
+       geofile[x+2]='e';
+       kmlfile[x+2]='m';
+       mapfile[x+3]='m';
+       geofile[x+3]='o';
+       kmlfile[x+3]='l';
+       mapfile[x+4]=0;
+       geofile[x+4]=0;
+       kmlfile[x+4]=0;
+
+       if (geo && kml==0)
+       {
+               fd=fopen(geofile,"wb");
+
+               fprintf(fd,"FILENAME\t%s\n",mapfile);
+               fprintf(fd,"#\t\tX\tY\tLong\t\tLat\n");
+               fprintf(fd,"TIEPOINT\t0\t0\t%d.000\t\t%d.000\n",(max_west<180?-max_west:360-max_west),max_north);
+               fprintf(fd,"TIEPOINT\t%u\t%u\t%d.000\t\t%.3f\n",width-1,height+29,(min_west<180?-min_west:360-min_west),(double)(min_north-0.025));
+               fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height+30);
+               fprintf(fd,"#\n# Auto Generated by SPLAT! v%s\n#\n",splat_version);
+
+               fclose(fd);
+       }
+
+       if (kml && geo==0)
+       {
+               fd=fopen(kmlfile,"wb");
+
+               fprintf(fd,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+               fprintf(fd,"<kml xmlns=\"http://earth.google.com/kml/2.1\">\n");
+               fprintf(fd,"<!-- Generated by SPLAT! Version %s -->\n",splat_version);
+               fprintf(fd,"  <Folder>\n");
+               fprintf(fd,"   <name>SPLAT!</name>\n");
+               fprintf(fd,"     <description>%s Transmitter Coverage Overlay</description>\n",xmtr[0].name);
+               fprintf(fd,"       <GroundOverlay>\n");
+               fprintf(fd,"         <name>SPLAT! Signal Strength Overlay</name>\n");
+               fprintf(fd,"           <description>SPLAT! Coverage</description>\n");
+               fprintf(fd,"            <Icon>\n");
+               fprintf(fd,"              <href>%s</href>\n",mapfile);
+               fprintf(fd,"            </Icon>\n");
+               fprintf(fd,"            <opacity>128</opacity>\n");
+               fprintf(fd,"            <LatLonBox>\n");
+               fprintf(fd,"               <north>%.5f</north>\n",(double)max_north-one_pixel);
+               fprintf(fd,"               <south>%.5f</south>\n",(double)min_north);
+               fprintf(fd,"               <east>%.5f</east>\n",((double)min_west<180.0?(double)-min_west:360.0-(double)min_west));
+               fprintf(fd,"               <west>%.5f</west>\n",(((double)max_west-one_pixel)<180.0?-((double)max_west-one_pixel):(360.0-(double)max_west-one_pixel)));
+               fprintf(fd,"               <rotation>0.0</rotation>\n");
+               fprintf(fd,"            </LatLonBox>\n");
+               fprintf(fd,"       </GroundOverlay>\n");
+
+               for (x=0; x<txsites; x++)
+               {
+                       fprintf(fd,"     <Placemark>\n");
+                       fprintf(fd,"       <name>%s</name>\n",xmtr[x].name);
+                       fprintf(fd,"       <visibility>1</visibility>\n");
+                       fprintf(fd,"       <Style>\n");
+                       fprintf(fd,"       <IconStyle>\n");
+                       fprintf(fd,"        <Icon>\n");
+                       fprintf(fd,"          <href>root://icons/palette-5.png</href>\n");
+                       fprintf(fd,"          <x>224</x>\n");
+                       fprintf(fd,"          <y>224</y>\n");
+                       fprintf(fd,"          <w>32</w>\n");
+                       fprintf(fd,"          <h>32</h>\n");
+                       fprintf(fd,"        </Icon>\n");
+                       fprintf(fd,"       </IconStyle>\n");
+                       fprintf(fd,"       </Style>\n");
+                       fprintf(fd,"      <Point>\n");
+                       fprintf(fd,"        <extrude>1</extrude>\n");
+                       fprintf(fd,"        <altitudeMode>relativeToGround</altitudeMode>\n");
+                       fprintf(fd,"        <coordinates>%f,%f,%f</coordinates>\n",(xmtr[x].lon<180.0?-xmtr[x].lon:360.0-xmtr[x].lon), xmtr[x].lat, xmtr[x].alt);
+                       fprintf(fd,"      </Point>\n");
+                       fprintf(fd,"     </Placemark>\n");
+               }
+
+               fprintf(fd,"  </Folder>\n");
+               fprintf(fd,"</kml>\n");
+
+               fclose(fd);
+       }
+
+       fd=fopen(mapfile,"wb");
+
+       fprintf(fd,"P6\n%u %u\n255\n",width,(kml?height:height+30));
+       fprintf(stdout,"\nWriting \"%s\" (%ux%u pixmap image)... ",mapfile,width,(kml?height:height+30));
+       fflush(stdout);
+
+       for (y=0, lat=(double)max_north-one_pixel; y<(int)height; y++, lat=(double)max_north-(one_pixel*(double)y))
+       {
+               for (x=0, lon=(double)max_west-one_pixel; x<(int)width; x++, lon=(double)max_west-(one_pixel*(double)x))
+               {
+                       if (lon<0.0)
+                               lon+=360.0;
+
+                       for (indx=0, found=0; indx<MAXPAGES && found==0;)
+                               if (lat>=(double)dem[indx].min_north && lat<(double)dem[indx].max_north && LonDiff(lon,(double)dem[indx].min_west)>=0.0 && LonDiff(lon,(double)dem[indx].max_west)<0.0)
+                                       found=1;
+                               else
+                                       indx++;
+
+                       if (found)
+                       {
+                               x0=(int)(1199.0*(lat-floor(lat)));
+                               y0=(int)(1199.0*(lon-floor(lon)));
+
+                               mask=dem[indx].mask[x0][y0];
+                               signal=(dem[indx].signal[x0][y0])-100;
+                               cityorcounty=0;
+
+                               match=255;
+
+                               red=0;
+                               green=0;
+                               blue=0;
+
+                               if (signal>=region.level[0])
+                                       match=0;
+                               else
+                               {
+                                       for (z=1; (z<region.levels && match==255); z++)
+                                       {
+                                               if (signal<region.level[z-1] && signal>=region.level[z])
+                                                       match=z;
+                                       }
+                               }
+
+                               if (match<region.levels)
+                               {
+                                       red=region.color[match][0];
+                                       green=region.color[match][1];
+                                       blue=region.color[match][2];
+
+                                       color=1;
+                               }
+
+                               if ((mask&2) && (kml==0))
+                               {
+                                       /* Text Labels: Red or otherwise */
+
+                                       if (red>=180 && green<=75 && blue<=75)
+                                               fprintf(fd,"%c%c%c",255^red,255^green,255^blue);
+                                       else
+                                               fprintf(fd,"%c%c%c",255,0,0);
+
+                                       cityorcounty=1;
+                               }
+
+                               else if ((mask&4) && (kml==0))
+                               {
+                                       /* County Boundaries: Black */
+
+                                       fprintf(fd,"%c%c%c",0,0,0);
+
+                                       cityorcounty=1;
+                               }
+
+                               if (cityorcounty==0)
+                               {
+                                       if (dem[indx].signal[x0][y0]==0)
+                                       {
+                                               if (ngs)
+                                                       fprintf(fd,"%c%c%c",255,255,255);
+                                               else
+                                               {
+                                                       /* Display land or sea elevation */
+
+                                                       if (dem[indx].data[x0][y0]==0)
+                                                               fprintf(fd,"%c%c%c",0,0,170);
+                                                       else
+                                                       {
+                                                               terrain=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
+                                                               fprintf(fd,"%c%c%c",terrain,terrain,terrain);
+                                                       }
+                                               }
+                                       }
+
+                                       else
+                                       {
+                                               /* Plot field strength regions in color */
+
+                                               if (red!=0 || green!=0 || blue!=0)
+                                                       fprintf(fd,"%c%c%c",red,green,blue);
+
+                                               else  /* terrain / sea-level */
+                                               {
+                                                       if (ngs)
+                                                               fprintf(fd,"%c%c%c",255,255,255);
+                                                       else
+                                                       {
+                                                               if (dem[indx].data[x0][y0]==0)
+                                                                       fprintf(fd,"%c%c%c",0,0,170);
+                                                               else
+                                                               {
+                                                                       /* Elevation: Greyscale */
+                                                                       terrain=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
+                                                                       fprintf(fd,"%c%c%c",terrain,terrain,terrain);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       else
+                       {
+                               /* We should never get here, but if */
+                               /* we do, display the region as black */
+
+                               fprintf(fd,"%c%c%c",0,0,0);
+                       }
+               }
+       }
+
+       if (kml==0 && color)
+       {
+               /* Display legend along bottom of image */
+
+               colorwidth=(int)rint((float)width/(float)region.levels);
+
+               for (y0=0; y0<30; y0++)
+               {
+                       for (x0=0; x0<(int)width; x0++)
+                       {
+                               indx=x0/colorwidth;
+                               x=x0%colorwidth;
+                               level=region.level[indx];
+
+                               hundreds=level/100;
+
+                               if (hundreds>0)
+                                       level-=(hundreds*100);
+
+                               tens=level/10;
+
+                               if (tens>0)
+                                       level-=(tens*10);
+
+                               units=level;
+
+                               if (y0>=8 && y0<=23)
+                               {  
+                                       if (hundreds>0)
+                                       {
+                                               if (x>=5 && x<=12)     
+                                                       if (fontdata[16*(hundreds+'0')+(y0-8)]&(128>>(x-5)))
+                                                               indx=255; 
+                                       }
+
+                                       if (tens>0 || hundreds>0)
+                                       {
+                                               if (x>=13 && x<=20)     
+                                                       if (fontdata[16*(tens+'0')+(y0-8)]&(128>>(x-13)))
+                                                               indx=255;
+                                       }
+                                       if (x>=21 && x<=28)
+                                               if (fontdata[16*(units+'0')+(y0-8)]&(128>>(x-21)))
+                                                       indx=255;
+
+                                       if (x>=36 && x<=43)
+                                               if (fontdata[16*('d')+(y0-8)]&(128>>(x-36)))
+                                                       indx=255;
+
+                                       if (x>=44 && x<=51)
+                                               if (fontdata[16*('B')+(y0-8)]&(128>>(x-44)))
+                                                       indx=255;
+
+                                       if (x>=52 && x<=59)
+                                               if (fontdata[16*('u')+(y0-8)]&(128>>(x-52)))
+                                                       indx=255;
+
+                                       if (x>=60 && x<=67)
+                                               if (fontdata[16*('V')+(y0-8)]&(128>>(x-60)))
+                                                       indx=255;
+
+                                       if (x>=68 && x<=75)
+                                               if (fontdata[16*('/')+(y0-8)]&(128>>(x-68)))
+                                                       indx=255;
+
+                                       if (x>=76 && x<=83)
+                                               if (fontdata[16*('m')+(y0-8)]&(128>>(x-76)))
+                                                       indx=255;
+                               }
+
+                               if (indx>region.levels)
+                                       fprintf(fd,"%c%c%c",0,0,0);
+                               else
+                               {
+                                       red=region.color[indx][0];
+                                       green=region.color[indx][1];
+                                       blue=region.color[indx][2];
+
+                                       fprintf(fd,"%c%c%c",red,green,blue);
+                               }
+                       } 
+               }
+       }
+
+       fclose(fd);
+       fprintf(stdout,"Done!\n");
+       fflush(stdout);
+}
+
+void GraphTerrain(struct site source, struct site destination, char *name)
+{
+       /* This function invokes gnuplot to generate an appropriate
+          output file indicating the terrain profile between the source
+          and destination locations.  "filename" is the name assigned
+          to the output file generated by gnuplot.  The filename extension
           is used to set gnuplot's terminal setting and output file type.
-          If no extension is found, .gif is assumed.  */
+          If no extension is found, .png is assumed.  */
 
-       int x, y, z;
-       char filename[255], term[15], ext[15];
-       FILE *fd=NULL;
+       int     x, y, z;
+       char    filename[255], term[30], ext[15];
+       FILE    *fd=NULL;
 
        ReadPath(destination,source);
 
        fd=fopen("profile.gp","wb");
 
        for (x=0; x<path.length; x++)
-               fprintf(fd,"%f\t%f\n",path.distance[x],path.elevation[x]);
+       {
+               if (metric)
+                       fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*path.elevation[x]);
+               else
+                       fprintf(fd,"%f\t%f\n",path.distance[x],path.elevation[x]);
+       }
 
        fclose(fd);
 
@@ -2817,8 +4386,8 @@ void GraphTerrain(struct site source, struct site destination, char *name)
                /* Default filename and output file type */
 
                strncpy(filename,"profile\0",8);
-               strncpy(term,"gif\0",4);
-               strncpy(ext,"gif\0",4);
+               strncpy(term,"png\0",4);
+               strncpy(ext,"png\0",4);
        }
 
        else
@@ -2842,11 +4411,11 @@ void GraphTerrain(struct site source, struct site destination, char *name)
                }
 
                else
-               {       /* No extension -- Default is gif */
+               {       /* No extension -- Default is png */
 
                        filename[x]=0;
-                       strncpy(term,"gif\0",4);
-                       strncpy(ext,"gif\0",4);
+                       strncpy(term,"png\0",4);
+                       strncpy(ext,"png\0",4);
                }
        }
 
@@ -2857,18 +4426,29 @@ void GraphTerrain(struct site source, struct site destination, char *name)
                strncpy(ext,"ps\0",3);
 
        else if (strncmp(ext,"ps",2)==0)
-               strncpy(term,"postscript\0",11);
-
-       fprintf(stdout,"Writing \"%s.%s\"...",filename,ext);
-       fflush(stdout);
+               strncpy(term,"postscript enhanced color\0",26);
 
        fd=fopen("splat.gp","w");
        fprintf(fd,"set grid\n");
        fprintf(fd,"set autoscale\n");
+       fprintf(fd,"set encoding iso_8859_1\n");
        fprintf(fd,"set term %s\n",term);
-       fprintf(fd,"set title \"SPLAT! Terrain Profile\"\n");
-       fprintf(fd,"set xlabel \"Distance Between %s and %s (miles)\"\n",destination.name,source.name);
-       fprintf(fd,"set ylabel \"Ground Elevation Above Sea Level (feet)\"\n");
+       fprintf(fd,"set title \"SPLAT! Terrain Profile Between %s and %s (%.2f%c Azimuth)\"\n",destination.name, source.name, Azimuth(destination,source),176);
+
+       if (metric)
+       {
+               fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f kilometers)\"\n",destination.name,source.name,KM_PER_MILE*Distance(source,destination));
+               fprintf(fd,"set ylabel \"Ground Elevation Above Sea Level (meters)\"\n");
+
+
+       }
+
+       else
+       {
+               fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f miles)\"\n",destination.name,source.name,Distance(source,destination));
+               fprintf(fd,"set ylabel \"Ground Elevation Above Sea Level (feet)\"\n");
+       }
+
        fprintf(fd,"set output \"%s.%s\"\n",filename,ext);
        fprintf(fd,"plot \"profile.gp\" title \"\" with lines\n");
        fclose(fd);
@@ -2879,7 +4459,8 @@ void GraphTerrain(struct site source, struct site destination, char *name)
        {
                unlink("splat.gp");
                unlink("profile.gp");
-               fprintf(stdout," Done!\n");
+
+               fprintf(stdout,"\nTerrain plot written to: \"%s.%s\"",filename,ext);
                fflush(stdout);
        }
 
@@ -2894,13 +4475,13 @@ void GraphElevation(struct site source, struct site destination, char *name)
           and destination locations.  "filename" is the name assigned
           to the output file generated by gnuplot.  The filename extension
           is used to set gnuplot's terminal setting and output file type.
-          If no extension is found, .gif is assumed. */
+          If no extension is found, .png is assumed. */
 
-       int x, y, z;
-       char filename[255], term[15], ext[15];
-       double angle, refangle, maxangle=-90.0;
-       struct site remote;
-       FILE *fd=NULL, *fd2=NULL;
+       int     x, y, z;
+       char    filename[255], term[30], ext[15];
+       double  angle, refangle, maxangle=-90.0;
+       struct  site remote;
+       FILE    *fd=NULL, *fd2=NULL;
 
        ReadPath(destination,source);  /* destination=RX, source=TX */
        refangle=ElevationAngle(destination,source);
@@ -2914,15 +4495,34 @@ void GraphElevation(struct site source, struct site destination, char *name)
                remote.lon=path.lon[x];
                remote.alt=0.0;
                angle=ElevationAngle(destination,remote);
-               fprintf(fd,"%f\t%f\n",path.distance[x],angle);
-               fprintf(fd2,"%f\t%f\n",path.distance[x],refangle);
+
+               if (metric)
+               {
+                       fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[x],angle);
+                       fprintf(fd2,"%f\t%f\n",KM_PER_MILE*path.distance[x],refangle);
+               }
+
+               else
+               {
+                       fprintf(fd,"%f\t%f\n",path.distance[x],angle);
+                       fprintf(fd2,"%f\t%f\n",path.distance[x],refangle);
+               }
 
                if (angle>maxangle)
                        maxangle=angle;
        }
 
-       fprintf(fd,"%f\t%f\n",path.distance[path.length-1],refangle);
-       fprintf(fd2,"%f\t%f\n",path.distance[path.length-1],refangle);
+       if (metric)
+       {
+               fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[path.length-1],refangle);
+               fprintf(fd2,"%f\t%f\n",KM_PER_MILE*path.distance[path.length-1],refangle);
+       }
+
+       else
+       {
+               fprintf(fd,"%f\t%f\n",path.distance[path.length-1],refangle);
+               fprintf(fd2,"%f\t%f\n",path.distance[path.length-1],refangle);
+       }
 
        fclose(fd);
        fclose(fd2);
@@ -2932,8 +4532,8 @@ void GraphElevation(struct site source, struct site destination, char *name)
                /* Default filename and output file type */
 
                strncpy(filename,"profile\0",8);
-               strncpy(term,"gif\0",4);
-               strncpy(ext,"gif\0",4);
+               strncpy(term,"png\0",4);
+               strncpy(ext,"png\0",4);
        }
 
        else
@@ -2957,11 +4557,11 @@ void GraphElevation(struct site source, struct site destination, char *name)
                }
 
                else
-               {       /* No extension -- Default is gif */
+               {       /* No extension -- Default is png */
 
                        filename[x]=0;
-                       strncpy(term,"gif\0",4);
-                       strncpy(ext,"gif\0",4);
+                       strncpy(term,"png\0",4);
+                       strncpy(ext,"png\0",4);
                }
        }
 
@@ -2972,21 +4572,25 @@ void GraphElevation(struct site source, struct site destination, char *name)
                strncpy(ext,"ps\0",3);
 
        else if (strncmp(ext,"ps",2)==0)
-               strncpy(term,"postscript\0",11);
-
-       fprintf(stdout,"Writing \"%s.%s\"...",filename,ext);
-       fflush(stdout);
+               strncpy(term,"postscript enhanced color\0",26);
 
        fd=fopen("splat.gp","w");
 
        fprintf(fd,"set grid\n");
        fprintf(fd,"set yrange [%2.3f to %2.3f]\n", (-fabs(refangle)-0.25), maxangle+0.25);
+       fprintf(fd,"set encoding iso_8859_1\n");
        fprintf(fd,"set term %s\n",term);
-       fprintf(fd,"set title \"SPLAT! Elevation Profile\"\n");
-       fprintf(fd,"set xlabel \"Distance Between %s and %s (miles)\"\n",destination.name,source.name);
-       fprintf(fd,"set ylabel \"Elevation Angle Along Path Between %s and %s (degrees)\"\n",destination.name,source.name);
+       fprintf(fd,"set title \"SPLAT! Elevation Profile Between %s and %s (%.2f%c azimuth)\"\n",destination.name,source.name,Azimuth(destination,source),176);
+
+       if (metric)
+               fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f kilometers)\"\n",destination.name,source.name,KM_PER_MILE*Distance(source,destination));
+       else
+               fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f miles)\"\n",destination.name,source.name,Distance(source,destination));
+
+
+       fprintf(fd,"set ylabel \"Elevation Angle Along LOS Path Between %s and %s (degrees)\"\n",destination.name,source.name);
        fprintf(fd,"set output \"%s.%s\"\n",filename,ext);
-       fprintf(fd,"plot \"profile.gp\" title \"Real Earth Profile\" with lines, \"reference.gp\" title \"Line Of Sight Path\" with lines\n");
+       fprintf(fd,"plot \"profile.gp\" title \"Real Earth Profile\" with lines, \"reference.gp\" title \"Line of Sight Path (%.2f%c elevation)\" with lines\n",refangle,176);
 
        fclose(fd);
                        
@@ -2998,7 +4602,7 @@ void GraphElevation(struct site source, struct site destination, char *name)
                unlink("profile.gp");
                unlink("reference.gp"); 
 
-               fprintf(stdout," Done!\n");
+               fprintf(stdout,"\nElevation plot written to: \"%s.%s\"",filename,ext);
                fflush(stdout);
        }
 
@@ -3006,78 +4610,219 @@ void GraphElevation(struct site source, struct site destination, char *name)
                fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n");
 }
 
-void GraphHeight(struct site source, struct site destination, char *name)
+void GraphHeight(struct site source, struct site destination, char *name, double f, unsigned char n)
 {
        /* This function invokes gnuplot to generate an appropriate
           output file indicating the terrain profile between the source
-          and destination locations.  What is plotted is the height of
-          land above or below a straight line between the receibe and
-          transmit sites.  "filename" is the name assigned to the output
-          file generated by gnuplot.  The filename extension is used
-          to set gnuplot's terminal setting and output file type.
-          If no extension is found, .gif is assumed. */
-
-       int x, y, z;
-       char filename[255], term[15], ext[15];
-       double a, b, c, height, refangle, cangle, maxheight=-100000.0,
-              minheight=100000.0;
-       struct site remote;
-       FILE *fd=NULL, *fd2=NULL;
+          and destination locations referenced to the line-of-sight path
+          between the receive and transmit sites.  "filename" is the name
+          assigned to the output file generated by gnuplot.  The filename
+          extension is used to set gnuplot's terminal setting and output
+          file type.  If no extension is found, .png is assumed. */
+
+       int     x, y, z;
+       char    filename[255], term[30], ext[15];
+       double  a, b, c, height=0.0, refangle, cangle, maxheight=-100000.0,
+               minheight=100000.0, lambda=0.0, f_zone=0.0, fpt6_zone=0.0,
+               nm=0.0, nb=0.0, ed=0.0, es=0.0, r=0.0, d=0.0, d1=0.0,
+               terrain, azimuth, distance, dheight=0.0, minterrain=100000.0,
+               minearth=100000.0, miny, maxy, min2y, max2y;
+       struct  site remote;
+       FILE    *fd=NULL, *fd2=NULL, *fd3=NULL, *fd4=NULL, *fd5=NULL;
 
        ReadPath(destination,source);  /* destination=RX, source=TX */
+       azimuth=Azimuth(destination,source);
+       distance=Distance(destination,source);
        refangle=ElevationAngle(destination,source);
        b=GetElevation(destination)+destination.alt+earthradius;
 
+       /* Wavelength and path distance (great circle) in feet. */
+
+       if (f)
+       {
+               lambda=9.8425e8/(f*1e6);
+               d=5280.0*path.distance[path.length-1];
+       }
+
+       if (n)
+       {
+               ed=GetElevation(destination);
+               es=GetElevation(source);
+               nb=-destination.alt-ed;
+               nm=(-source.alt-es-nb)/(path.distance[path.length-1]);
+       }
+
        fd=fopen("profile.gp","wb");
        fd2=fopen("reference.gp","wb");
+       fd5=fopen("curvature.gp", "wb");
 
-       for (x=1; x<path.length-1; x++)
+       if (f)
+       {
+               fd3=fopen("fresnel.gp", "wb");
+               fd4=fopen("fresnel_pt_6.gp", "wb");
+       }
+
+       for (x=0; x<path.length-1; x++)
        {
                remote.lat=path.lat[x];
                remote.lon=path.lon[x];
                remote.alt=0.0;
 
-               a=GetElevation(remote)+earthradius;
+               terrain=GetElevation(remote);
 
-               cangle=5280.0*Distance(destination,remote)/earthradius;
+               if (x==0)
+                       terrain+=destination.alt;  /* RX antenna spike */
 
+               a=terrain+earthradius;
+               cangle=5280.0*Distance(destination,remote)/earthradius;
                c=b*sin(refangle*deg2rad+HALFPI)/sin(HALFPI-refangle*deg2rad-cangle);
 
                height=a-c;
 
-               fprintf(fd,"%f\t%f\n",path.distance[x],height);
-               fprintf(fd2,"%f\t%f\n",path.distance[x],0.);
+               /* Per Fink and Christiansen, Electronics
+                * Engineers' Handbook, 1989:
+                *
+                *   H = sqrt(lamba * d1 * (d - d1)/d)
+                *
+                * where H is the distance from the LOS
+                * path to the first Fresnel zone boundary.
+                */
+
+               if (f)
+               {
+                       d1=5280.0*path.distance[x];
+                       f_zone=-1.0*sqrt(lambda*d1*(d-d1)/d);
+                       fpt6_zone=f_zone*fzone_clearance;
+               }
+
+               if (n)
+               {
+                       r=-(nm*path.distance[x])-nb;
+                       height+=r;
+
+                       if (f>0) 
+                       {
+                               f_zone+=r;
+                               fpt6_zone+=r;
+                       }
+               }
+
+               else
+                       r=0.0;
+
+               if (metric)
+               {
+                       fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*height);
+                       fprintf(fd2,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*r);
+                       fprintf(fd5,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*(height-terrain));
+               }
+
+               else
+               {
+                       fprintf(fd,"%f\t%f\n",path.distance[x],height);
+                       fprintf(fd2,"%f\t%f\n",path.distance[x],r);
+                       fprintf(fd5,"%f\t%f\n",path.distance[x],height-terrain);
+               }
+
+               if (f)
+               {
+                       if (metric)
+                       {
+                               fprintf(fd3,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*f_zone);
+                               fprintf(fd4,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*fpt6_zone);
+                       }
+
+                       else
+                       {
+                               fprintf(fd3,"%f\t%f\n",path.distance[x],f_zone);
+                               fprintf(fd4,"%f\t%f\n",path.distance[x],fpt6_zone);
+                       }
+
+                       if (f_zone<minheight)
+                               minheight=f_zone;
+               }
 
                if (height>maxheight)
                        maxheight=height;
 
                if (height<minheight)
                        minheight=height;
-       }
 
-       fprintf(fd,"%f\t%f\n",path.distance[path.length-1],0.0);
-       fprintf(fd2,"%f\t%f\n",path.distance[path.length-1],0.0);
+               if (r>maxheight)
+                       maxheight=r;
 
-       fclose(fd);
-       fclose(fd2);
-
-       if (name[0]==0)
-       {
-               /* Default filename and output file type */
+               if (terrain<minterrain)
+                       minterrain=terrain;
 
-               strncpy(filename,"height\0",8);
-               strncpy(term,"gif\0",4);
-               strncpy(ext,"gif\0",4);
+               if ((height-terrain)<minearth)
+                       minearth=height-terrain;
        }
 
+       if (n)
+               r=-(nm*path.distance[path.length-1])-nb;
        else
+               r=0.0;
+
+       if (metric)
        {
-               /* Grab extension and terminal type from "name" */
+               fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[path.length-1],METERS_PER_FOOT*r);
+               fprintf(fd2,"%f\t%f\n",KM_PER_MILE*path.distance[path.length-1],METERS_PER_FOOT*r);
+       }
 
-               for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
-                       filename[x]=name[x];
+       else
+       {
+               fprintf(fd,"%f\t%f\n",path.distance[path.length-1],r);
+               fprintf(fd2,"%f\t%f\n",path.distance[path.length-1],r);
+       }
 
-               if (name[x]=='.')
+       if (f)
+       {
+               if (metric)
+               {
+                       fprintf(fd3,"%f\t%f\n",KM_PER_MILE*path.distance[path.length-1],METERS_PER_FOOT*r);
+                       fprintf(fd4,"%f\t%f\n",KM_PER_MILE*path.distance[path.length-1],METERS_PER_FOOT*r);
+               }
+
+               else
+               {
+                       fprintf(fd3,"%f\t%f\n",path.distance[path.length-1],r);
+                       fprintf(fd4,"%f\t%f\n",path.distance[path.length-1],r);
+               }
+       }
+       
+       if (r>maxheight)
+               maxheight=r;
+
+       if (r<minheight)
+               minheight=r;
+
+       fclose(fd);
+       fclose(fd2);
+       fclose(fd5);
+
+       if (f)
+       {
+               fclose(fd3);
+               fclose(fd4);
+       }
+
+       if (name[0]==0)
+       {
+               /* Default filename and output file type */
+
+               strncpy(filename,"height\0",8);
+               strncpy(term,"png\0",4);
+               strncpy(ext,"png\0",4);
+       }
+
+       else
+       {
+               /* Grab extension and terminal type from "name" */
+
+               for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
+                       filename[x]=name[x];
+
+               if (name[x]=='.')
                {
                        for (y=0, z=x, x++; name[x]!=0 && x<254 && y<14; x++, y++)
                        {
@@ -3091,11 +4836,11 @@ void GraphHeight(struct site source, struct site destination, char *name)
                }
 
                else
-               {       /* No extension -- Default is gif */
+               {       /* No extension -- Default is png */
 
                        filename[x]=0;
-                       strncpy(term,"gif\0",4);
-                       strncpy(ext,"gif\0",4);
+                       strncpy(term,"png\0",4);
+                       strncpy(ext,"png\0",4);
                }
        }
 
@@ -3106,27 +4851,72 @@ void GraphHeight(struct site source, struct site destination, char *name)
                strncpy(ext,"ps\0",3);
 
        else if (strncmp(ext,"ps",2)==0)
-               strncpy(term,"postscript\0",11);
-
-       fprintf(stdout,"Writing \"%s.%s\"...",filename,ext);
-       fflush(stdout);
+               strncpy(term,"postscript enhanced color\0",26);
 
        fd=fopen("splat.gp","w");
 
-       minheight-=20.0;
-       maxheight+=20.0;
+       dheight=maxheight-minheight;
+       miny=minheight-0.15*dheight;
+       maxy=maxheight+0.05*dheight;
+
+       if (maxy<20.0)
+               maxy=20.0;
+
+       dheight=maxheight-minheight;
+       min2y=miny-minterrain+0.05*dheight;
 
-       if (maxheight<20.0)
-               maxheight=20.0;
+       if (minearth<min2y)
+       {
+               miny-=min2y-minearth+0.05*dheight;
+               min2y=minearth-0.05*dheight;
+       }
 
+       max2y=min2y+maxy-miny;
        fprintf(fd,"set grid\n");
-       fprintf(fd,"set yrange [%2.3f to %2.3f]\n", minheight, maxheight);
+       fprintf(fd,"set yrange [%2.3f to %2.3f]\n", metric?miny*METERS_PER_FOOT:miny, metric?maxy*METERS_PER_FOOT:maxy);
+       fprintf(fd,"set y2range [%2.3f to %2.3f]\n", metric?min2y*METERS_PER_FOOT:min2y, metric?max2y*METERS_PER_FOOT:max2y);
+       fprintf(fd,"set xrange [-0.5 to %2.3f]\n",metric?KM_PER_MILE*rint(distance+0.5):rint(distance+0.5));
+       fprintf(fd,"set encoding iso_8859_1\n");
        fprintf(fd,"set term %s\n",term);
-       fprintf(fd,"set title \"SPLAT! Height Profile\"\n");
-       fprintf(fd,"set xlabel \"Distance Between %s and %s (miles)\"\n",destination.name,source.name);
-       fprintf(fd,"set ylabel \"Ground Height Above Path Between %s and %s (feet)\"\n",destination.name,source.name);
+
+       if (f)
+               fprintf(fd,"set title \"SPLAT! Path Profile Between %s and %s (%.2f%c azimuth)\\nWith First Fresnel Zone\"\n",destination.name, source.name, azimuth,176);
+
+       else
+               fprintf(fd,"set title \"SPLAT! Height Profile Between %s and %s (%.2f%c azimuth)\"\n",destination.name, source.name, azimuth,176);
+
+       if (metric)
+               fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f kilometers)\"\n",destination.name,source.name,KM_PER_MILE*Distance(source,destination));
+       else
+               fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f miles)\"\n",destination.name,source.name,Distance(source,destination));
+
+       if (n)
+       {
+               if (metric)
+                       fprintf(fd,"set ylabel \"Normalized Height Referenced To LOS Path Between\\n%s and %s (meters)\"\n",destination.name,source.name);
+
+               else
+                       fprintf(fd,"set ylabel \"Normalized Height Referenced To LOS Path Between\\n%s and %s (feet)\"\n",destination.name,source.name);
+
+       }
+
+       else
+       {
+               if (metric)
+                       fprintf(fd,"set ylabel \"Height Referenced To LOS Path Between %s and %s (meters)\"\n",destination.name,source.name);
+
+               else
+                       fprintf(fd,"set ylabel \"Height Referenced To LOS Path Between %s and %s (feet)\"\n",destination.name,source.name);
+       }
+
        fprintf(fd,"set output \"%s.%s\"\n",filename,ext);
-       fprintf(fd,"plot \"profile.gp\" title \"Real Earth Profile\" with lines, \"reference.gp\" title \"Line Of Sight Path\" with lines\n");
+
+       if (f)
+               fprintf(fd,"plot \"profile.gp\" title \"Point-to-Point Profile\" with lines, \"reference.gp\" title \"Line of Sight Path\" with lines, \"curvature.gp\" axes x1y2 title \"Earth's Curvature Contour\" with lines, \"fresnel.gp\" axes x1y1 title \"First Fresnel Zone (%.3f MHz)\" with lines, \"fresnel_pt_6.gp\" title \"%.0f%% of First Fresnel Zone\" with lines\n",f,fzone_clearance*100.0);
+
+       else
+               fprintf(fd,"plot \"profile.gp\" title \"Point-to-Point Profile\" with lines, \"reference.gp\" title \"Line Of Sight Path\" with lines, \"curvature.gp\" axes x1y2 title \"Earth's Curvature Contour\" with lines\n");
 
        fclose(fd);
 
@@ -3136,8 +4926,16 @@ void GraphHeight(struct site source, struct site destination, char *name)
        {
                unlink("splat.gp");
                unlink("profile.gp");
-               unlink("reference.gp"); 
-               fprintf(stdout," Done!\n");
+               unlink("reference.gp");
+               unlink("curvature.gp");
+
+               if (f)
+               {
+                       unlink("fresnel.gp");
+                       unlink("fresnel_pt_6.gp");
+               }
+
+               fprintf(stdout,"\nHeight plot written to: \"%s.%s\"",filename,ext);
                fflush(stdout);
        }
 
@@ -3145,22 +4943,194 @@ void GraphHeight(struct site source, struct site destination, char *name)
                fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n");
 }
 
-void GraphLongley(struct site source, struct site destination, char *name)
+void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f, FILE *outfile)
 {
-       /* This function invokes gnuplot to generate an appropriate
-          output file indicating the Longley-Rice model loss between
-          the source and destination locations.   "filename" is the
-          name assigned to the output file generated by gnuplot.
-          The filename extension is used to set gnuplot's terminal
-          setting and output file type.  If no extension is found,
-          .gif is assumed.  */
+       /* Perform an obstruction analysis along the
+          path between receiver and transmitter. */
+
+       int     x;
+       struct  site site_x;
+       double  h_r, h_t, h_x, h_r_orig, cos_tx_angle, cos_test_angle,
+               cos_tx_angle_f1, cos_tx_angle_fpt6, d_tx, d_x,
+               h_r_f1, h_r_fpt6, h_f, h_los, lambda=0.0;
+       char    string[255], string_fpt6[255], string_f1[255];
+
+       ReadPath(xmtr,rcvr);
+       h_r=GetElevation(rcvr)+rcvr.alt+earthradius;
+       h_r_f1=h_r;
+       h_r_fpt6=h_r;
+       h_r_orig=h_r;
+       h_t=GetElevation(xmtr)+xmtr.alt+earthradius;
+       d_tx=5280.0*Distance(rcvr,xmtr);
+       cos_tx_angle=((h_r*h_r)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r*d_tx);
+       cos_tx_angle_f1=cos_tx_angle;
+       cos_tx_angle_fpt6=cos_tx_angle;
+
+       if (f)
+               lambda=9.8425e8/(f*1e6);
+
+       /* At each point along the path calculate the cosine
+          of a sort of "inverse elevation angle" at the receiver.
+          From the antenna, 0 deg. looks at the ground, and 90 deg.
+          is parallel to the ground.
+
+          Start at the receiver.  If this is the lowest antenna,
+          then terrain obstructions will be nearest to it.  (Plus,
+          that's the way SPLAT!'s original los() did it.)
+
+          Calculate cosines only.  That's sufficient to compare
+          angles and it saves the extra computational burden of
+          acos().  However, note the inverted comparison: if
+          acos(A) > acos(B), then B > A. */
+
+       for (x=path.length-1; x>0; x--)
+       {
+               site_x.lat=path.lat[x];
+               site_x.lon=path.lon[x];
+               site_x.alt=0.0;
+
+               h_x=GetElevation(site_x)+earthradius;
+               d_x=5280.0*Distance(rcvr,site_x);
+
+               /* Deal with the LOS path first. */
+
+               cos_test_angle=((h_r*h_r)+(d_x*d_x)-(h_x*h_x))/(2.0*h_r*d_x);
+
+               if (cos_tx_angle>cos_test_angle)
+               {
+                       if (h_r==h_r_orig)
+                               fprintf(outfile,"Between %s and %s, SPLAT! detected obstructions at:\n\n",rcvr.name,xmtr.name);
+
+                       if (site_x.lat>=0.0)
+                       {
+                               if (metric)
+                                       fprintf(outfile,"\t%.4f N, %.4f W, %5.2f kilometers, %6.2f meters AMSL\n",site_x.lat, site_x.lon, KM_PER_MILE*(d_x/5280.0), METERS_PER_FOOT*(h_x-earthradius));
+                               else
+                                       fprintf(outfile,"\t%.4f N, %.4f W, %5.2f miles, %6.2f feet AMSL\n",site_x.lat, site_x.lon, d_x/5280.0, h_x-earthradius);
+                       }
+
+                       else
+                       {
+                               if (metric)
+                                       fprintf(outfile,"\t%.4f S, %.4f W, %5.2f kilometers, %6.2f meters AMSL\n",-site_x.lat, site_x.lon, KM_PER_MILE*(d_x/5280.0), METERS_PER_FOOT*(h_x-earthradius));
+                               else
+
+                                       fprintf(outfile,"\t%.4f S, %.4f W, %5.2f miles, %6.2f feet AMSL\n",-site_x.lat, site_x.lon, d_x/5280.0, h_x-earthradius);
+                       }
+               }
+
+               while (cos_tx_angle>cos_test_angle)
+               {
+                       h_r+=1;
+                       cos_test_angle=((h_r*h_r)+(d_x*d_x)-(h_x*h_x))/(2.0*h_r*d_x);
+                       cos_tx_angle=((h_r*h_r)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r*d_tx);
+               }
+
+               if (f)
+               {
+                       /* Now clear the first Fresnel zone... */
+
+                       cos_tx_angle_f1=((h_r_f1*h_r_f1)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r_f1*d_tx);
+                       h_los=sqrt(h_r_f1*h_r_f1+d_x*d_x-2*h_r_f1*d_x*cos_tx_angle_f1);
+                       h_f=h_los-sqrt(lambda*d_x*(d_tx-d_x)/d_tx);
+
+                       while (h_f<h_x)
+                       {
+                               h_r_f1+=1;
+                               cos_tx_angle_f1=((h_r_f1*h_r_f1)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r_f1*d_tx);
+                               h_los=sqrt(h_r_f1*h_r_f1+d_x*d_x-2*h_r_f1*d_x*cos_tx_angle_f1);
+                               h_f=h_los-sqrt(lambda*d_x*(d_tx-d_x)/d_tx);
+                       }
+
+                       /* and clear the 60% F1 zone. */
+
+                       cos_tx_angle_fpt6=((h_r_fpt6*h_r_fpt6)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r_fpt6*d_tx);
+                       h_los=sqrt(h_r_fpt6*h_r_fpt6+d_x*d_x-2*h_r_fpt6*d_x*cos_tx_angle_fpt6);
+                       h_f=h_los-fzone_clearance*sqrt(lambda*d_x*(d_tx-d_x)/d_tx);
+
+                       while (h_f<h_x)
+                       {
+                               h_r_fpt6+=1;
+                               cos_tx_angle_fpt6=((h_r_fpt6*h_r_fpt6)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r_fpt6*d_tx);
+                               h_los=sqrt(h_r_fpt6*h_r_fpt6+d_x*d_x-2*h_r_fpt6*d_x*cos_tx_angle_fpt6);
+                               h_f=h_los-fzone_clearance*sqrt(lambda*d_x*(d_tx-d_x)/d_tx);
+                       }
+               }
+       }
+               
+       if (h_r>h_r_orig)
+       {
+               if (metric)
+                       sprintf(string,"\nAntenna at %s must be raised to at least %.2f meters AGL\nto clear all obstructions detected by SPLAT!\n",rcvr.name, METERS_PER_FOOT*(h_r-GetElevation(rcvr)-earthradius));
+               else
+                       sprintf(string,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear all obstructions detected by SPLAT!\n",rcvr.name, h_r-GetElevation(rcvr)-earthradius);
+       }
+
+       else
+               sprintf(string,"\nNo obstructions to LOS path due to terrain were detected by SPLAT!\n");
+
+       if (f)
+       {
+               if (h_r_fpt6>h_r_orig)
+               {
+                       if (metric)
+                               sprintf(string_fpt6,"\nAntenna at %s must be raised to at least %.2f meters AGL\nto clear %.0f%c of the first Fresnel zone.\n",rcvr.name, METERS_PER_FOOT*(h_r_fpt6-GetElevation(rcvr)-earthradius),fzone_clearance*100.0,37);
+
+                       else
+                               sprintf(string_fpt6,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear %.0f%c of the first Fresnel zone.\n",rcvr.name, h_r_fpt6-GetElevation(rcvr)-earthradius,fzone_clearance*100.0,37);
+               }
+
+               else
+                       sprintf(string_fpt6,"\n%.0f%c of the first Fresnel zone is clear.\n",fzone_clearance*100.0,37);
+       
+               if (h_r_f1>h_r_orig)
+               {
+                       if (metric)
+                               sprintf(string_f1,"\nAntenna at %s must be raised to at least %.2f meters AGL\nto clear the first Fresnel zone.\n",rcvr.name, METERS_PER_FOOT*(h_r_f1-GetElevation(rcvr)-earthradius));
+
+                       else                    
+                               sprintf(string_f1,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear the first Fresnel zone.\n",rcvr.name, h_r_f1-GetElevation(rcvr)-earthradius);
+
+               }
+
+               else
+                   sprintf(string_f1,"\nThe first Fresnel zone is clear.\n\n");
+       }
+
+       fprintf(outfile,"%s",string);
 
-       int x, y, z, errnum, errflag=0;
-       char filename[255], term[15], ext[15], strmode[100], report_name[80];
-       double maxloss=-100000.0, minloss=100000.0, loss, haavt, angle;
-       FILE *fd=NULL, *fd2=NULL;
+       if (f)
+       {
+               fprintf(outfile,"%s",string_f1);
+               fprintf(outfile,"%s",string_fpt6);
+       }
+}
 
-       sprintf(report_name,"%s-to-%s.lro",source.name,destination.name);
+void PathReport(struct site source, struct site destination, char *name, char graph_it)
+{
+       /* This function writes a SPLAT! Path Report (name.txt) to
+          the filesystem.  If (graph_it == 1), then gnuplot is invoked
+          to generate an appropriate output file indicating the Longley-Rice
+          model loss between the source and destination locations.
+          "filename" is the name assigned to the output file generated
+          by gnuplot.  The filename extension is used to set gnuplot's
+          terminal setting and output file type.  If no extension is
+          found, .png is assumed. */
+
+       int     x, y, z, errnum;
+       char    filename[255], term[30], ext[15], strmode[100],
+               report_name[80], block=0;
+       double  maxloss=-100000.0, minloss=100000.0, loss, haavt,
+               angle1, angle2, azimuth, pattern=1.0, patterndB=0.0,
+               total_loss=0.0, cos_xmtr_angle, cos_test_angle=0.0,
+               source_alt, test_alt, dest_alt, source_alt2, dest_alt2,
+               distance, elevation, four_thirds_earth, field_strength,
+               free_space_loss=0.0, voltage;
+       FILE    *fd=NULL, *fd2=NULL;
+
+       sprintf(report_name,"%s-to-%s.txt",source.name,destination.name);
+
+       four_thirds_earth=EARTHRADIUS*(4.0/3.0);
 
        for (x=0; report_name[x]!=0; x++)
                if (report_name[x]==32 || report_name[x]==17 || report_name[x]==92 || report_name[x]==42 || report_name[x]==47)
@@ -3168,9 +5138,8 @@ void GraphLongley(struct site source, struct site destination, char *name)
 
        fd2=fopen(report_name,"w");
 
-       fprintf(fd2,"\n\t--==[ SPLAT! v%s Longley-Rice Model Path Loss Report ]==--\n\n",splat_version);
-       fprintf(fd2,"Analysis of RF path conditions between %s and %s:\n",source.name, destination.name);
-       fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
+       fprintf(fd2,"\n\t\t--==[ SPLAT! v%s Path Analysis ]==--\n\n",splat_version);
+       fprintf(fd2,"-------------------------------------------------------------------------\n\n");
        fprintf(fd2,"Transmitter site: %s\n",source.name);
 
        if (source.lat>=0.0)
@@ -3187,24 +5156,66 @@ void GraphLongley(struct site source, struct site destination, char *name)
        }
        
        fprintf(fd2, "%s W)\n", dec2dms(source.lon));
-       fprintf(fd2,"Ground elevation: %.2f feet AMSL\n",GetElevation(source));
-       fprintf(fd2,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",source.alt, source.alt+GetElevation(source));
+
+       if (metric)
+       {
+               fprintf(fd2,"Ground elevation: %.2f meters AMSL\n",METERS_PER_FOOT*GetElevation(source));
+               fprintf(fd2,"Antenna height: %.2f meters AGL / %.2f meters AMSL\n",METERS_PER_FOOT*source.alt,METERS_PER_FOOT*(source.alt+GetElevation(source)));
+       }
+
+       else
+       {
+               fprintf(fd2,"Ground elevation: %.2f feet AMSL\n",GetElevation(source));
+               fprintf(fd2,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",source.alt, source.alt+GetElevation(source));
+       }
 
        haavt=haat(source);
 
        if (haavt>-4999.0)
-               fprintf(fd2,"Antenna height above average terrain: %.2f feet\n",haavt);
+       {
+               if (metric)
+                       fprintf(fd2,"Antenna height above average terrain: %.2f meters\n",METERS_PER_FOOT*haavt);
+               else
+                       fprintf(fd2,"Antenna height above average terrain: %.2f feet\n",haavt);
+       }
+
+       azimuth=Azimuth(source,destination);
+       angle1=ElevationAngle(source,destination);
+       angle2=ElevationAngle2(source,destination,earthradius);
+
+       if (got_azimuth_pattern || got_elevation_pattern)
+       {
+               x=(int)rint(10.0*(10.0-angle2));
+
+               if (x>=0 && x<=1000)
+                       pattern=(double)LR.antenna_pattern[(int)rint(azimuth)][x];
+
+               patterndB=20.0*log10(pattern);
+       }
+
+       if (metric)
+               fprintf(fd2,"Distance to %s: %.2f kilometers\n",destination.name,METERS_PER_FOOT*Distance(source,destination));
 
-       fprintf(fd2,"Distance to %s: %.2f miles.\n",destination.name,Distance(source,destination));
-       fprintf(fd2,"Azimuth to %s: %.2f degrees.\n",destination.name,Azimuth(source,destination));
+       else
+               fprintf(fd2,"Distance to %s: %.2f miles.\n",destination.name,Distance(source,destination));
 
-       angle=ElevationAngle(source,destination);
+       fprintf(fd2,"Azimuth to %s: %.2f degrees\n",destination.name,azimuth);
 
-       if (angle>=0.0)
-               fprintf(fd2,"Angle of elevation between %s and %s: %+.4f degrees.\n",source.name,destination.name,angle);
+       if (angle1>=0.0)
+               fprintf(fd2,"Elevation angle to %s: %+.4f degrees\n",destination.name,angle1);
 
-       if (angle<0.0)
-               fprintf(fd2,"Angle of depression between %s and %s: %+.4f degrees.\n",source.name,destination.name,angle);
+       else
+               fprintf(fd2,"Depression angle to %s: %+.4f degrees\n",destination.name,angle1);
+
+       if ((angle2-angle1)>0.0001)
+       {
+               if (angle2<0.0)
+                       fprintf(fd2,"Depression");
+               else
+                       fprintf(fd2,"Elevation");
+
+               fprintf(fd2," angle to the first obstruction: %+.4f degrees\n",angle2);
+       }
 
        fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
 
@@ -3225,373 +5236,607 @@ void GraphLongley(struct site source, struct site destination, char *name)
        }
 
        fprintf(fd2, "%s W)\n", dec2dms(destination.lon));
-       fprintf(fd2,"Ground elevation: %.2f feet AMSL\n",GetElevation(destination));
-       fprintf(fd2,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",destination.alt, destination.alt+GetElevation(destination));
+
+       if (metric)
+       {
+               fprintf(fd2,"Ground elevation: %.2f meters AMSL\n",METERS_PER_FOOT*GetElevation(destination));
+               fprintf(fd2,"Antenna height: %.2f meters AGL / %.2f meters AMSL\n",METERS_PER_FOOT*destination.alt, METERS_PER_FOOT*(destination.alt+GetElevation(destination)));
+       }
+
+       else
+       {
+               fprintf(fd2,"Ground elevation: %.2f feet AMSL\n",GetElevation(destination));
+               fprintf(fd2,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",destination.alt, destination.alt+GetElevation(destination));
+       }
 
        haavt=haat(destination);
 
        if (haavt>-4999.0)
-               fprintf(fd2,"Antenna height above average terrain: %.2f feet\n",haavt);
+       {
+               if (metric)
+                       fprintf(fd2,"Antenna height above average terrain: %.2f meters\n",METERS_PER_FOOT*haavt);
+               else
+                       fprintf(fd2,"Antenna height above average terrain: %.2f feet\n",haavt);
+       }
 
-       fprintf(fd2,"Distance to %s: %.2f miles.\n",source.name,Distance(source,destination));
-       fprintf(fd2,"Azimuth to %s: %.2f degrees.\n",source.name,Azimuth(destination,source));
+       if (metric)
+               fprintf(fd2,"Distance to %s: %.2f kilometers\n",source.name,KM_PER_MILE*Distance(source,destination));
 
-       angle=ElevationAngle(destination,source);
+       else
+               fprintf(fd2,"Distance to %s: %.2f miles\n",source.name,Distance(source,destination));
 
-       if (angle>=0.0)
-               fprintf(fd2,"Angle of elevation between %s and %s: %+.4f degrees.\n",destination.name,source.name,angle);
+       azimuth=Azimuth(destination,source);
 
-       if (angle<0.0)
-               fprintf(fd2,"Angle of depression between %s and %s: %+.4f degrees.\n",destination.name,source.name,angle);
+       angle1=ElevationAngle(destination,source);
+       angle2=ElevationAngle2(destination,source,earthradius);
 
-       fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
+       fprintf(fd2,"Azimuth to %s: %.2f degrees.\n",source.name,azimuth);
+
+       if (angle1>=0.0)
+               fprintf(fd2,"Elevation angle to %s: %+.4f degrees\n",source.name,angle1);
 
-       fprintf(fd2,"Longley-Rice path calculation parameters used in this analysis:\n\n");
-       fprintf(fd2,"Earth's Dielectric Constant: %.3lf\n",LR.eps_dielect);
-       fprintf(fd2,"Earth's Conductivity: %.3lf\n",LR.sgm_conductivity);
-       fprintf(fd2,"Atmospheric Bending Constant (N): %.3lf\n",LR.eno_ns_surfref);
-       fprintf(fd2,"Frequency: %.3lf (MHz)\n",LR.frq_mhz);
-       fprintf(fd2,"Radio Climate: %d (",LR.radio_climate);
+       else
+               fprintf(fd2,"Depression angle to %s: %+.4f degrees\n",source.name,angle1);
 
-       switch (LR.radio_climate)
+       if ((angle2-angle1)>0.0001)
        {
-               case 1:
-               fprintf(fd2,"Equatorial");
-               break;
+               if (angle2<0.0)
+                       fprintf(fd2,"Depression");
+               else
+                       fprintf(fd2,"Elevation");
 
-               case 2:
-               fprintf(fd2,"Continental Subtropical");
-               break;
+               fprintf(fd2," angle to the first obstruction: %+.4f degrees\n",angle2);
+       }
 
-               case 3:
-               fprintf(fd2,"Maritime Subtropical");
-               break;
+       fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
 
-               case 4:
-               fprintf(fd2,"Desert");
-               break;
+       if (LR.frq_mhz>0.0)
+       {
+               fprintf(fd2,"Longley-Rice path calculation parameters used in this analysis:\n\n");
+               fprintf(fd2,"Earth's Dielectric Constant: %.3lf\n",LR.eps_dielect);
+               fprintf(fd2,"Earth's Conductivity: %.3lf Siemens/meter\n",LR.sgm_conductivity);
+               fprintf(fd2,"Atmospheric Bending Constant (N-units): %.3lf ppm\n",LR.eno_ns_surfref);
+               fprintf(fd2,"Frequency: %.3lf MHz\n",LR.frq_mhz);
+               fprintf(fd2,"Radio Climate: %d (",LR.radio_climate);
+
+               switch (LR.radio_climate)
+               {
+                       case 1:
+                       fprintf(fd2,"Equatorial");
+                       break;
 
-               case 5:
-               fprintf(fd2,"Continental Temperate");
-               break;
+                       case 2:
+                       fprintf(fd2,"Continental Subtropical");
+                       break;
 
-               case 6:
-               fprintf(fd2,"Martitime Temperate, Over Land");
-               break;
+                       case 3:
+                       fprintf(fd2,"Maritime Subtropical");
+                       break;
 
-               case 7:
-               fprintf(fd2,"Maritime Temperate, Over Sea");
-               break;
+                       case 4:
+                       fprintf(fd2,"Desert");
+                       break;
 
-               default:
-               fprintf(fd2,"Unknown");
-       }
+                       case 5:
+                       fprintf(fd2,"Continental Temperate");
+                       break;
 
-       fprintf(fd2,")\nPolarization: %d (",LR.pol);
+                       case 6:
+                       fprintf(fd2,"Martitime Temperate, Over Land");
+                       break;
 
-       if (LR.pol==0)
-               fprintf(fd2,"Horizontal");
+                       case 7:
+                       fprintf(fd2,"Maritime Temperate, Over Sea");
+                       break;
 
-       if (LR.pol==1)
-               fprintf(fd2,"Vertical");
+                       default:
+                       fprintf(fd2,"Unknown");
+               }
 
-       fprintf(fd2,")\nFraction of Situations: %.1lf%c\n",LR.conf*100.0,37);
-       fprintf(fd2,"Fraction of Time: %.1lf%c\n",LR.rel*100.0,37);
+               fprintf(fd2,")\nPolarization: %d (",LR.pol);
 
-       fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
+               if (LR.pol==0)
+                       fprintf(fd2,"Horizontal");
 
-       fprintf(fd2,"Analysis Results:\n\n");
+               if (LR.pol==1)
+                       fprintf(fd2,"Vertical");
 
-       ReadPath(source, destination);  /* destination=RX, source=TX */
+               fprintf(fd2,")\nFraction of Situations: %.1lf%c\n",LR.conf*100.0,37);
+               fprintf(fd2,"Fraction of Time: %.1lf%c\n",LR.rel*100.0,37);
 
-       elev_l[1]=0.04*METERS_PER_MILE;
+               if (LR.erp!=0.0)
+               {
+                       fprintf(fd2,"Transmitter ERP: ");
 
-       for (x=1; x<path.length; x++)
-               elev_l[x+1]=path.elevation[x]*METERS_PER_FOOT;  
+                       if (LR.erp<1.0)
+                               fprintf(fd2,"%.1lf milliwatts\n",1000.0*LR.erp);
 
-       fprintf(fd2,"Distance (mi)\tLoss (dB)\tErrnum\tComment\n\n"); 
+                       if (LR.erp>=1.0 && LR.erp<10.0)
+                               fprintf(fd2,"%.1lf Watts\n",LR.erp);
 
-       fd=fopen("profile.gp","w");
+                       if (LR.erp>=10.0 && LR.erp<10.0e3)
+                               fprintf(fd2,"%.0lf Watts\n",LR.erp);
 
-       for (x=2; x<path.length; x++)
-       {
-               elev_l[0]=x-1;
+                       if (LR.erp>=10.0e3)
+                               fprintf(fd2,"%.3lf kilowatts\n",LR.erp/1.0e3);
+               }
 
-               point_to_point(elev_l, source.alt*METERS_PER_FOOT, 
-                       destination.alt*METERS_PER_FOOT,
-                       LR.eps_dielect, LR.sgm_conductivity, LR.eno_ns_surfref,
-                       LR.frq_mhz, LR.radio_climate, LR.pol, LR.conf, LR.rel,
-                       loss, strmode, errnum);
+                       fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
 
-                       /* Note: PASS BY REFERENCE ... loss and errnum are
-                          passed by reference, and are only used in this
-                          file by this function */
+               fprintf(fd2,"Summary for the link between %s and %s:\n\n",source.name, destination.name);
 
+               if (patterndB!=0.0)
+                       fprintf(fd2,"%s antenna pattern towards %s: %.3f (%.2f dB)\n", source.name, destination.name, pattern, patterndB);
 
-               fprintf(fd,"%f\t%f\n",path.distance[path.length-1]-path.distance[x],loss);
-               fprintf(fd2,"%7.2f\t\t%7.2f\t\t  %d\t%s\n",path.distance[x],loss, errnum, strmode);
+               ReadPath(source, destination);  /* source=TX, destination=RX */
 
-               errflag|=errnum;
-                 
-               if (loss>maxloss)
-                       maxloss=loss;
+               /* Copy elevations along path into the elev_l[] array. */
 
-               if (loss<minloss)
-                       minloss=loss;
-       }
+               for (x=0; x<path.length; x++)
+                       elev_l[x+2]=path.elevation[x]*METERS_PER_FOOT;  
 
-       fclose(fd);
+               fd=fopen("profile.gp","w");
 
-       if (errflag)
-       {
-               fprintf(fd2,"\nNotes on \"errnum\"...\n\n");
-               fprintf(fd2,"  0: No error.  :-)\n");
-               fprintf(fd2,"  1: Warning!  Some parameters are nearly out of range.\n");
-               fprintf(fd2,"     Results should be used with caution.\n");
-               fprintf(fd2,"  2: Note: Default parameters have been substituted for impossible ones.\n");
-               fprintf(fd2,"  3: Warning!  A combination of parameters is out of range.\n");
-               fprintf(fd2,"     Results are probably invalid.\n");
-               fprintf(fd2,"  Other: Warning!  Some parameters are out of range.\n");
-               fprintf(fd2,"    Results are probably invalid.\n\nEnd of Report\n");
+               azimuth=rint(Azimuth(source,destination));
+
+               for (y=2; y<(path.length-1); y++)  /* path.length-1 avoids LR error */
+               {
+                       distance=5280.0*path.distance[y];
+                       source_alt=four_thirds_earth+source.alt+path.elevation[0];
+                       dest_alt=four_thirds_earth+destination.alt+path.elevation[y];
+                       dest_alt2=dest_alt*dest_alt;
+                       source_alt2=source_alt*source_alt;
+
+                       /* Calculate the cosine of the elevation of
+                          the receiver as seen by the transmitter. */
+
+                       cos_xmtr_angle=((source_alt2)+(distance*distance)-(dest_alt2))/(2.0*source_alt*distance);
+
+                       if (got_elevation_pattern)
+                       {
+                               /* If an antenna elevation pattern is available, the
+                                  following code determines the elevation angle to
+                                  the first obstruction along the path. */
+
+                               for (x=2, block=0; x<y && block==0; x++)
+                               {
+                                       distance=5280.0*(path.distance[y]-path.distance[x]);
+                                       test_alt=four_thirds_earth+path.elevation[x];
+
+                                       /* Calculate the cosine of the elevation
+                                          angle of the terrain (test point)
+                                          as seen by the transmitter. */
+
+                                       cos_test_angle=((source_alt2)+(distance*distance)-(test_alt*test_alt))/(2.0*source_alt*distance);
+
+                                       /* Compare these two angles to determine if
+                                          an obstruction exists.  Since we're comparing
+                                          the cosines of these angles rather than
+                                          the angles themselves, the sense of the
+                                          following "if" statement is reversed from
+                                          what it would be if the angles themselves
+                                          were compared. */
+
+                                       if (cos_xmtr_angle>cos_test_angle)
+                                               block=1;
+                               }
+
+                               /* At this point, we have the elevation angle
+                                  to the first obstruction (if it exists). */
+                       }
+
+                       /* Determine path loss for each point along the
+                          path using Longley-Rice's point_to_point mode
+                          starting at x=2 (number_of_points = 1), the
+                          shortest distance terrain can play a role in
+                          path loss. */
+
+                       elev_l[0]=y-1;  /* (number of points - 1) */
+
+                       /* Distance between elevation samples */
+                       elev_l[1]=METERS_PER_MILE*(path.distance[y]-path.distance[y-1]);
+
+                       point_to_point(elev_l, source.alt*METERS_PER_FOOT, 
+                       destination.alt*METERS_PER_FOOT, LR.eps_dielect,
+                       LR.sgm_conductivity, LR.eno_ns_surfref, LR.frq_mhz,
+                       LR.radio_climate, LR.pol, LR.conf, LR.rel, loss,
+                       strmode, errnum);
+
+                       if (block)
+                               elevation=((acos(cos_test_angle))/deg2rad)-90.0;
+                       else
+                               elevation=((acos(cos_xmtr_angle))/deg2rad)-90.0;
+
+                       /* Integrate the antenna's radiation
+                          pattern into the overall path loss. */
+
+                       x=(int)rint(10.0*(10.0-elevation));
+
+                       if (x>=0 && x<=1000)
+                       {
+                               pattern=(double)LR.antenna_pattern[(int)azimuth][x];
+
+                               if (pattern!=0.0)
+                                       patterndB=20.0*log10(pattern);
+                       }
+
+                       else
+                               patterndB=0.0;
+
+                       total_loss=loss-patterndB;
+
+                       if (metric)
+                               fprintf(fd,"%f\t%f\n",KM_PER_MILE*(path.distance[path.length-1]-path.distance[y]),total_loss);
+
+                       else
+                               fprintf(fd,"%f\t%f\n",path.distance[path.length-1]-path.distance[y],total_loss);
+
+                       if (total_loss>maxloss)
+                               maxloss=total_loss;
+
+                       if (total_loss<minloss)
+                               minloss=total_loss;
+               }
+
+               fclose(fd);
+
+               distance=Distance(source,destination);
+
+
+               if (distance!=0.0)
+               {
+                       free_space_loss=36.6+(20.0*log10(LR.frq_mhz))+(20.0*log10(distance));
+
+                       fprintf(fd2,"Free space path loss: %.2f dB\n",free_space_loss);
+               }
+
+               fprintf(fd2,"Longley-Rice path loss: %.2f dB\n",loss);
+
+               if (free_space_loss!=0.0)
+                       fprintf(fd2,"Attenuation due to effects of terrain: %.2f dB\n",loss-free_space_loss);
+
+               if (patterndB!=0.0)
+                       fprintf(fd2,"Total path loss including %s antenna pattern: %.2f dB\n",source.name,total_loss);
+
+               if (LR.erp!=0.0)
+               {
+                       field_strength=(137.26+(20.0*log10(LR.frq_mhz))-total_loss)+(10.0*log10(LR.erp/1000.0));
+                       fprintf(fd2,"Field strength at %s: %.2f dBuV/meter\n", destination.name,field_strength);
+                       voltage=(pow(10.0,field_strength/20.0)*39.52726907)/LR.frq_mhz;
+                       fprintf(fd2,"Voltage produced by a terminated 50 ohm 0 dBd gain antenna: %.2f uV\n",voltage);
+                       voltage=(pow(10.0,field_strength/20.0)*48.41082007)/LR.frq_mhz;
+                       fprintf(fd2,"Voltage produced by a terminated 75 ohm 0 dBd gain antenna: %.2f uV\n",voltage);
+               }
+
+               fprintf(fd2,"Mode of propagation: %s\n",strmode);
+
+               fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
        }
 
-       fprintf(stdout,"Longley-Rice Path Loss between %s and %s is %.2f db\n",source.name, destination.name, loss);
-       fprintf(stdout,"Path Loss Report written to: \"%s\"\n",report_name);
+       fprintf(stdout,"\nPath Loss Report written to: \"%s\"\n",report_name);
        fflush(stdout);
 
-       fclose(fd2);
+       ObstructionAnalysis(source, destination, LR.frq_mhz, fd2);
 
-       if (name[0]==0)
-       {
-               /* Default filename and output file type */
+       fclose(fd2);
 
-               strncpy(filename,"loss\0",5);
-               strncpy(term,"gif\0",4);
-               strncpy(ext,"gif\0",4);
-       }
+       /* Skip plotting the graph if ONLY a path-loss report is needed. */
 
-       else
+       if (graph_it)
        {
-               /* Grab extension and terminal type from "name" */
+               if (name[0]==0)
+               {
+                       /* Default filename and output file type */
 
-               for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
-                       filename[x]=name[x];
+                       strncpy(filename,"loss\0",5);
+                       strncpy(term,"png\0",4);
+                       strncpy(ext,"png\0",4);
+               }
 
-               if (name[x]=='.')
+               else
                {
-                       for (y=0, z=x, x++; name[x]!=0 && x<254 && y<14; x++, y++)
+                       /* Grab extension and terminal type from "name" */
+
+                       for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
+                               filename[x]=name[x];
+
+                       if (name[x]=='.')
                        {
-                               term[y]=tolower(name[x]);
-                               ext[y]=term[y];
+                               for (y=0, z=x, x++; name[x]!=0 && x<254 && y<14; x++, y++)
+                               {
+                                       term[y]=tolower(name[x]);
+                                       ext[y]=term[y];
+                               }
+
+                               ext[y]=0;
+                               term[y]=0;
+                               filename[z]=0;
                        }
 
-                       ext[y]=0;
-                       term[y]=0;
-                       filename[z]=0;
+                       else
+                       {       /* No extension -- Default is png */
+
+                               filename[x]=0;
+                               strncpy(term,"png\0",4);
+                               strncpy(ext,"png\0",4);
+                       }
                }
 
+               /* Either .ps or .postscript may be used
+                  as an extension for postscript output. */
+
+               if (strncmp(term,"postscript",10)==0)
+                       strncpy(ext,"ps\0",3);
+
+               else if (strncmp(ext,"ps",2)==0)
+                       strncpy(term,"postscript enhanced color\0",26);
+
+               fd=fopen("splat.gp","w");
+
+               fprintf(fd,"set grid\n");
+               fprintf(fd,"set yrange [%2.3f to %2.3f]\n", minloss, maxloss);
+               fprintf(fd,"set encoding iso_8859_1\n");
+               fprintf(fd,"set term %s\n",term);
+               fprintf(fd,"set title \"SPLAT! Loss Profile Along Path Between %s and %s (%.2f%c azimuth)\"\n",destination.name, source.name, Azimuth(destination,source),176);
+
+               if (metric)
+                       fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f kilometers)\"\n",destination.name,source.name,KM_PER_MILE*Distance(destination,source));
                else
-               {       /* No extension -- Default is gif */
+                       fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f miles)\"\n",destination.name,source.name,Distance(destination,source));
 
-                       filename[x]=0;
-                       strncpy(term,"gif\0",4);
-                       strncpy(ext,"gif\0",4);
+               if (got_azimuth_pattern || got_elevation_pattern)
+                       fprintf(fd,"set ylabel \"Total Path Loss (including TX antenna pattern) (dB)");
+               else
+                       fprintf(fd,"set ylabel \"Longley-Rice Path Loss (dB)");
+
+               fprintf(fd,"\"\nset output \"%s.%s\"\n",filename,ext);
+               fprintf(fd,"plot \"profile.gp\" title \"Path Loss\" with lines\n");
+
+               fclose(fd);
+                       
+               x=system("gnuplot splat.gp");
+
+               if (x!=-1)
+               {
+                       unlink("splat.gp");
+                       unlink("profile.gp");
+                       unlink("reference.gp"); 
+
+                       fprintf(stdout,"Path loss plot written to: \"%s.%s\"\n",filename,ext);
+                       fflush(stdout);
                }
+
+               else
+                       fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n");
        }
 
-       /* Either .ps or .postscript may be used
-          as an extension for postscript output. */
+       if (x!=-1)
+               unlink("profile.gp");
+}
 
-       if (strncmp(term,"postscript",10)==0)
-               strncpy(ext,"ps\0",3);
+void SiteReport(struct site xmtr)
+{
+       char    report_name[80];
+       double  terrain;
+       int     x, azi;
+       FILE    *fd;
 
-       else if (strncmp(ext,"ps",2)==0)
-               strncpy(term,"postscript\0",11);
+       sprintf(report_name,"%s-site_report.txt",xmtr.name);
 
-       fprintf(stdout,"Writing \"%s.%s\"...",filename,ext);
-       fflush(stdout);
+       for (x=0; report_name[x]!=0; x++)
+               if (report_name[x]==32 || report_name[x]==17 || report_name[x]==92 || report_name[x]==42 || report_name[x]==47)
+                       report_name[x]='_';     
 
-       fd=fopen("splat.gp","w");
+       fd=fopen(report_name,"w");
 
-       fprintf(fd,"set grid\n");
-       fprintf(fd,"set yrange [%2.3f to %2.3f]\n", minloss, maxloss);
-       fprintf(fd,"set term %s\n",term);
-       fprintf(fd,"set title \"SPLAT! Loss Profile\"\n");
-       fprintf(fd,"set xlabel \"Distance Between %s and %s (miles)\"\n",destination.name,source.name);
-       fprintf(fd,"set ylabel \"Longley-Rice Loss (dB)\"\n");
-       fprintf(fd,"set output \"%s.%s\"\n",filename,ext);
-       fprintf(fd,"plot \"profile.gp\" title \"Longley-Rice Loss\" with lines\n");
+       fprintf(fd,"\n\t--==[ SPLAT! v%s Site Analysis Report For: %s ]==--\n\n",splat_version,xmtr.name);
 
-       fclose(fd);
-                       
-       x=system("gnuplot splat.gp");
+       fprintf(fd,"---------------------------------------------------------------------------\n\n");
 
-       if (x!=-1)
+       if (xmtr.lat>=0.0)
        {
-               unlink("splat.gp");
-               unlink("profile.gp");
-               unlink("reference.gp"); 
+               fprintf(fd,"Site location: %.4f North / %.4f West",xmtr.lat, xmtr.lon);
+               fprintf(fd, " (%s N / ",dec2dms(xmtr.lat));
+       }
+
+       else
+       {
+               fprintf(fd,"Site location: %.4f South / %.4f West",-xmtr.lat, xmtr.lon);
+               fprintf(fd, " (%s S / ",dec2dms(xmtr.lat));
+       }
+
+       fprintf(fd, "%s W)\n",dec2dms(xmtr.lon));
+
+       if (metric)
+       {
+               fprintf(fd,"Ground elevation: %.2f meters AMSL\n",METERS_PER_FOOT*GetElevation(xmtr));
+               fprintf(fd,"Antenna height: %.2f meters AGL / %.2f meters AMSL\n",METERS_PER_FOOT*xmtr.alt, METERS_PER_FOOT*(xmtr.alt+GetElevation(xmtr)));
+       }
+
+       else
+       {
+               fprintf(fd,"Ground elevation: %.2f feet AMSL\n",GetElevation(xmtr));
+               fprintf(fd,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",xmtr.alt, xmtr.alt+GetElevation(xmtr));
+       }
+
+       terrain=haat(xmtr);
+
+       if (terrain>-4999.0)
+       {
+               if (metric)
+                       fprintf(fd,"Antenna height above average terrain: %.2f meters\n\n",METERS_PER_FOOT*terrain);
+               else
+                       fprintf(fd,"Antenna height above average terrain: %.2f feet\n\n",terrain);
+
+               /* Display the average terrain between 2 and 10 miles
+                  from the transmitter site at azimuths of 0, 45, 90,
+                  135, 180, 225, 270, and 315 degrees. */
+
+               for (azi=0; azi<=315; azi+=45)
+               {
+                       fprintf(fd,"Average terrain at %3d degrees azimuth: ",azi);
+                       terrain=AverageTerrain(xmtr,(double)azi,2.0,10.0);
+
+                       if (terrain>-4999.0)
+                       {
+                               if (metric)
+                                       fprintf(fd,"%.2f meters AMSL\n",METERS_PER_FOOT*terrain);
+                               else
+                                       fprintf(fd,"%.2f feet AMSL\n",terrain);
+                       }
 
-               fprintf(stdout," Done!\n");
-               fflush(stdout);
+                       else
+                               fprintf(fd,"No terrain\n");
+               }
        }
 
-       else
-               fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n");
+       fprintf(fd,"\n---------------------------------------------------------------------------\n\n");
+       fclose(fd);
+       fprintf(stdout,"\nSite analysis report written to: \"%s\"",report_name);
 }
 
-void ObstructionReport(struct site xmtr, struct site rcvr, char report)
+void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat)
 {
-       struct site result, result2, new_site;
-       double angle, haavt;
-       unsigned char block;
-       char report_name[80], string[255];
-       int x;
-       FILE *fd;
-
-       sprintf(report_name,"%s-to-%s.txt",xmtr.name,rcvr.name);
-
-       for (x=0; report_name[x]!=0; x++)
-               if (report_name[x]==32 || report_name[x]==17 || report_name[x]==92 || report_name[x]==42 || report_name[x]==47)
-                       report_name[x]='_';     
-
-       fd=fopen(report_name,"w");
+       /* This function loads the SDF files required
+          to cover the limits of the region specified. */ 
 
-       fprintf(fd,"\n\t\t--==[ SPLAT! v%s Obstruction Report ]==--\n\n",splat_version);
-       fprintf(fd,"Analysis of line-of-sight path conditions between %s and %s:\n",xmtr.name, rcvr.name);
-       fprintf(fd,"\n-------------------------------------------------------------------------\n\n");
-       fprintf(fd,"Transmitter site: %s\n",xmtr.name);
+       int x, y, width, ymin, ymax;
 
+       width=ReduceAngle(max_lon-min_lon);
 
-       if (xmtr.lat>=0.0)
+       if ((max_lon-min_lon)<=180.0)
        {
-               fprintf(fd,"Site location: %.4f North / %.4f West",xmtr.lat, xmtr.lon);
-               fprintf(fd, " (%s N / ", dec2dms(xmtr.lat));
-       }
+               for (y=0; y<=width; y++)
+                       for (x=min_lat; x<=max_lat; x++)
+                       {
+                               ymin=(int)(min_lon+(double)y);
 
-       else
-       {
-               fprintf(fd,"Site location: %.4f South / %.4f West",-xmtr.lat, xmtr.lon);
-               fprintf(fd, " (%s S / ", dec2dms(xmtr.lat));
-       }
+                               while (ymin<0)
+                                       ymin+=360;
 
-       fprintf(fd, "%s W)\n", dec2dms(xmtr.lon));
-       fprintf(fd,"Ground elevation: %.2f feet AMSL\n",GetElevation(xmtr));
-       fprintf(fd,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",xmtr.alt, xmtr.alt+GetElevation(xmtr));
+                               while (ymin>=360)
+                                       ymin-=360;
 
-       haavt=haat(xmtr);
+                               ymax=ymin+1;
 
-       if (haavt>-4999.0)
-               fprintf(fd,"Antenna height above average terrain: %.2f feet\n",haavt);
+                               while (ymax<0)
+                                       ymax+=360;
 
-       fprintf(fd,"Distance to %s: %.2f miles.\n",rcvr.name,Distance(xmtr,rcvr));
-       fprintf(fd,"Azimuth to %s: %.2f degrees.\n",rcvr.name,Azimuth(xmtr,rcvr));
+                               while (ymax>=360)
+                                       ymax-=360;
 
-       angle=ElevationAngle(xmtr,rcvr);
+                               sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
+                               LoadSDF(string);
+                       }
+       }
 
-       if (angle>=0.0)
-               fprintf(fd,"Angle of elevation between %s and %s: %+.4f degrees.\n",xmtr.name,rcvr.name,angle);
+       else
+       {
+               for (y=0; y<=width; y++)
+                       for (x=min_lat; x<=max_lat; x++)
+                       {
+                               ymin=max_lon+y;
 
-       if (angle<0.0)
-               fprintf(fd,"Angle of depression between %s and %s: %+.4f degrees.\n",xmtr.name,rcvr.name,angle);
+                               while (ymin<0)
+                                       ymin+=360;
 
-       fprintf(fd,"\n-------------------------------------------------------------------------\n\n");
+                               while (ymin>=360)
+                                       ymin-=360;
+                                       
+                               ymax=ymin+1;
 
-       /* Receiver */
+                               while (ymax<0)
+                                       ymax+=360;
 
-       fprintf(fd,"Receiver site: %s\n",rcvr.name);
+                               while (ymax>=360)
+                                       ymax-=360;
 
-       if (rcvr.lat>=0.0)
-       {
-               fprintf(fd,"Site location: %.4f North / %.4f West",rcvr.lat, rcvr.lon);
-               fprintf(fd, " (%s N / ", dec2dms(rcvr.lat));
+                               sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
+                               LoadSDF(string);
+                       }
        }
+}
 
-       else
-       {
-               fprintf(fd,"Site location: %.4f South / %.4f West",-rcvr.lat, rcvr.lon);
-               fprintf(fd, " (%s S / ", dec2dms(rcvr.lat));
-       }
+int LoadPLI(char *filename)
+{
+       /* This function reads a SPLAT! path-loss output 
+          file (-plo) for analysis and/or map generation. */
 
-       fprintf(fd, "%s W)\n", dec2dms(rcvr.lon));
-       fprintf(fd,"Ground elevation: %.2f feet AMSL\n",GetElevation(rcvr));
-       fprintf(fd,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",rcvr.alt, rcvr.alt+GetElevation(rcvr));
+       int     error=0, max_west, min_west, max_north, min_north;
+       char    string[80], *pointer=NULL;
+       double  latitude=0.0, longitude=0.0, azimuth=0.0, elevation=0.0,
+               loss=0.0;
+       FILE    *fd;
 
-       haavt=haat(rcvr);
+       fd=fopen(filename,"r");
 
-       if (haavt>-4999.0)
-               fprintf(fd,"Antenna height above average terrain: %.2f feet\n",haavt);
+       if (fd!=NULL)
+       {
+               fgets(string,78,fd);
+               pointer=strchr(string,';');
 
-       fprintf(fd,"Distance to %s: %.2f miles.\n",xmtr.name,Distance(xmtr,rcvr));
-       fprintf(fd,"Azimuth to %s: %.2f degrees.\n",xmtr.name,Azimuth(rcvr,xmtr));
+               if (pointer!=NULL)
+                       *pointer=0;
 
-       angle=ElevationAngle(rcvr,xmtr);
+               sscanf(string,"%d, %d",&max_west, &min_west);
 
-       if (angle>=0.0)
-               fprintf(fd,"Angle of elevation between %s and %s: %+.4f degrees.\n",rcvr.name,xmtr.name,angle);
+               fgets(string,78,fd);
+               pointer=strchr(string,';');
 
-       if (angle<0.0)
-               fprintf(fd,"Angle of depression between %s and %s: %+.4f degrees.\n",rcvr.name,xmtr.name,angle);
+               if (pointer!=NULL)
+                       *pointer=0;
 
-       fprintf(fd,"\n-------------------------------------------------------------------------\n\n");
+               sscanf(string,"%d, %d",&max_north, &min_north);
 
-       if (report=='y')
-       {
-               /* Write an Obstruction Report */
+               fgets(string,78,fd);
+               pointer=strchr(string,';');
 
-               new_site=rcvr;
-               result=los(xmtr,rcvr);
-               result2=result;
-               result2.alt-=1;
-               block=result.name[0];
+               if (pointer!=NULL)
+                       *pointer=0;
 
-               if (block=='*')
-                       fprintf(fd,"SPLAT! detected obstructions at:\n\n");
+               LoadTopoData(max_west-1, min_west, max_north-1, min_north);
 
-               while (block=='*')
-               {
-                       if (result.lat!=result2.lat || result.lon!=result2.lon || result.alt!=result2.alt)
-                       {
-                               if (result.lat>=0.0)
-                                       fprintf(fd,"\t%.4f N, %.4f W, %5.2f miles, %6.2f feet AMSL.\n",result.lat, result.lon, Distance(rcvr,result), result.alt);
-                               else
+               fprintf(stdout,"\nReading \"%s\"... ",filename);
+               fflush(stdout);
 
-                                       fprintf(fd,"\t%.4f S, %.4f W, %5.2f miles, %6.2f feet AMSL.\n",-result.lat, result.lon, Distance(rcvr,result), result.alt);
-                       }
+               fgets(string,78,fd);
+               sscanf(string,"%lf, %lf, %lf, %lf, %lf",&latitude, &longitude, &azimuth, &elevation, &loss);
 
-                       result2=result;
-                       new_site.alt+=1.0;
+               while (feof(fd)==0)
+               {
+                       if (loss>255.0)
+                               loss=255.0;
 
-                       /* Can you hear me now? :-) */
+                       if (loss<=(double)maxdB)
+                               PutSignal(latitude,longitude,((unsigned char)round(loss)));
 
-                       result=los(xmtr,new_site);
-                       block=result.name[0];
+                       fgets(string,78,fd);
+                       sscanf(string,"%lf, %lf, %lf, %lf, %lf",&latitude, &longitude, &azimuth, &elevation, &loss);
                }
 
-               if (new_site.alt!=rcvr.alt)
-                       sprintf(string,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear all obstructions detected by SPLAT!\n\n",rcvr.name, new_site.alt);
-               else
-                       sprintf(string,"\nNo obstructions due to terrain were detected by SPLAT!\n\n");
-       }
-
-       fprintf(fd,"%s",string);
+               fclose(fd);
 
-       fclose(fd);
+               fprintf(stdout," Done!\n");
+               fflush(stdout);
+       }
 
-       /* Display LOS status to terminal */
+       else
+               error=1;
 
-       fprintf(stdout,"%sObstruction report written to: \"%s\"\n",string,report_name);
-       fflush(stdout);
+       return error;
 }
 
-void SiteReport(struct site xmtr)
+void WriteKML(struct site source, struct site destination)
 {
-       char report_name[80];
-       double terrain;
-       int x, azi;
-       FILE *fd;
+       int     x, y;
+       char    block, report_name[80];
+       double  distance, rx_alt, tx_alt, cos_xmtr_angle,
+               azimuth, cos_test_angle, test_alt;
+       FILE    *fd=NULL;
 
-       sprintf(report_name,"%s-site_report.txt",xmtr.name);
+       ReadPath(source,destination);
+
+       sprintf(report_name,"%s-to-%s.kml",source.name,destination.name);
 
        for (x=0; report_name[x]!=0; x++)
                if (report_name[x]==32 || report_name[x]==17 || report_name[x]==92 || report_name[x]==42 || report_name[x]==47)
@@ -3599,106 +5844,274 @@ void SiteReport(struct site xmtr)
 
        fd=fopen(report_name,"w");
 
-       fprintf(fd,"\n\t--==[ SPLAT! v%s Site Analysis Report For: %s ]==--\n\n",splat_version,xmtr.name);
+       fprintf(fd,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+       fprintf(fd,"<kml xmlns=\"http://earth.google.com/kml/2.0\">\n");
+       fprintf(fd,"<!-- Generated by SPLAT! Version %s -->\n",splat_version);
+       fprintf(fd,"<Folder>\n");
+       fprintf(fd,"<name>SPLAT! Path</name>\n");
+       fprintf(fd,"<open>1</open>\n");
+       fprintf(fd,"<description>Path Between %s and %s</description>\n",source.name,destination.name);
 
-       fprintf(fd,"---------------------------------------------------------------------------\n\n");
+       fprintf(fd,"<Placemark>\n");
+       fprintf(fd,"    <name>%s</name>\n",source.name);
+       fprintf(fd,"    <description>\n");
+       fprintf(fd,"       Transmit Site\n");
 
-       if (xmtr.lat>=0.0)
-       {
-               fprintf(fd,"Site location: %.4f North / %.4f West",xmtr.lat, xmtr.lon);
-               fprintf(fd, " (%s N / ",dec2dms(xmtr.lat));
-       }
+       if (source.lat>=0.0)
+               fprintf(fd,"       <BR>%s North</BR>\n",dec2dms(source.lat));
+       else
+               fprintf(fd,"       <BR>%s South</BR>\n",dec2dms(source.lat));
+
+       fprintf(fd,"       <BR>%s West</BR>\n",dec2dms(source.lon));
+
+       azimuth=Azimuth(source,destination);
+       distance=Distance(source,destination);
 
+       if (metric)
+               fprintf(fd,"       <BR>%.2f km",distance*KM_PER_MILE);
        else
-       {
-               fprintf(fd,"Site location: %.4f South / %.4f West",-xmtr.lat, xmtr.lon);
-               fprintf(fd, " (%s S / ",dec2dms(xmtr.lat));
-       }
+               fprintf(fd,"       <BR>%.2f miles",distance);
+
+       fprintf(fd," to %s</BR>\n       <BR>toward an azimuth of %.2f%c</BR>\n",destination.name,azimuth,176);
+
+       fprintf(fd,"    </description>\n");
+       fprintf(fd,"    <visibility>1</visibility>\n");
+       fprintf(fd,"    <Style>\n");
+       fprintf(fd,"      <IconStyle>\n");
+       fprintf(fd,"        <Icon>\n");
+       fprintf(fd,"          <href>root://icons/palette-5.png</href>\n");
+       fprintf(fd,"          <x>224</x>\n");
+       fprintf(fd,"          <y>224</y>\n");
+       fprintf(fd,"          <w>32</w>\n");
+       fprintf(fd,"          <h>32</h>\n");
+       fprintf(fd,"        </Icon>\n");
+       fprintf(fd,"      </IconStyle>\n");
+       fprintf(fd,"    </Style>\n");
+       fprintf(fd,"    <Point>\n");
+       fprintf(fd,"      <extrude>1</extrude>\n");
+       fprintf(fd,"      <altitudeMode>relativeToGround</altitudeMode>\n");
+       fprintf(fd,"      <coordinates>%f,%f,30</coordinates>\n",(source.lon<180.0?-source.lon:360.0-source.lon),source.lat);
+       fprintf(fd,"    </Point>\n");
+       fprintf(fd,"</Placemark>\n");
+
+       fprintf(fd,"<Placemark>\n");
+       fprintf(fd,"    <name>%s</name>\n",destination.name);
+       fprintf(fd,"    <description>\n");
+       fprintf(fd,"       Receive Site\n");
 
-       fprintf(fd, "%s W)\n",dec2dms(xmtr.lon));
-       fprintf(fd,"Ground elevation: %.2f feet AMSL\n",GetElevation(xmtr));
-       fprintf(fd,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",xmtr.alt, xmtr.alt+GetElevation(xmtr));
+       if (destination.lat>=0.0)
+               fprintf(fd,"       <BR>%s North</BR>\n",dec2dms(destination.lat));
+       else
+               fprintf(fd,"       <BR>%s South</BR>\n",dec2dms(destination.lat));
 
-       terrain=haat(xmtr);
+       fprintf(fd,"       <BR>%s West</BR>\n",dec2dms(destination.lon));
 
-       if (terrain>-4999.0)
+
+       if (metric)
+               fprintf(fd,"       <BR>%.2f km",distance*KM_PER_MILE);
+       else
+               fprintf(fd,"       <BR>%.2f miles",distance);
+
+       fprintf(fd," to %s</BR>\n       <BR>toward an azimuth of %.2f%c</BR>\n",source.name,Azimuth(destination,source),176);
+
+       fprintf(fd,"    </description>\n");
+       fprintf(fd,"    <visibility>1</visibility>\n");
+       fprintf(fd,"    <Style>\n");
+       fprintf(fd,"      <IconStyle>\n");
+       fprintf(fd,"        <Icon>\n");
+       fprintf(fd,"          <href>root://icons/palette-5.png</href>\n");
+       fprintf(fd,"          <x>224</x>\n");
+       fprintf(fd,"          <y>224</y>\n");
+       fprintf(fd,"          <w>32</w>\n");
+       fprintf(fd,"          <h>32</h>\n");
+       fprintf(fd,"        </Icon>\n");
+       fprintf(fd,"      </IconStyle>\n");
+       fprintf(fd,"    </Style>\n");
+       fprintf(fd,"    <Point>\n");
+       fprintf(fd,"      <extrude>1</extrude>\n");
+       fprintf(fd,"      <altitudeMode>relativeToGround</altitudeMode>\n");
+       fprintf(fd,"      <coordinates>%f,%f,30</coordinates>\n",(destination.lon<180.0?-destination.lon:360.0-destination.lon),destination.lat);
+       fprintf(fd,"    </Point>\n");
+       fprintf(fd,"</Placemark>\n");
+
+       fprintf(fd,"<Placemark>\n");
+       fprintf(fd,"<name>Point-to-Point Path</name>\n");
+       fprintf(fd,"  <visibility>1</visibility>\n");
+       fprintf(fd,"  <open>0</open>\n");
+       fprintf(fd,"  <Style>\n");
+       fprintf(fd,"    <LineStyle>\n");
+       fprintf(fd,"      <color>7fffffff</color>\n");
+       fprintf(fd,"    </LineStyle>\n");
+       fprintf(fd,"    <PolyStyle>\n");
+       fprintf(fd,"       <color>7fffffff</color>\n");
+       fprintf(fd,"    </PolyStyle>\n");
+       fprintf(fd,"  </Style>\n");
+       fprintf(fd,"  <LineString>\n");
+       fprintf(fd,"    <extrude>1</extrude>\n");
+       fprintf(fd,"    <tessellate>1</tessellate>\n");
+       fprintf(fd,"    <altitudeMode>relativeToGround</altitudeMode>\n");
+       fprintf(fd,"    <coordinates>\n");
+
+       for (x=0; x<path.length; x++)
+               fprintf(fd,"      %f,%f,5\n",(path.lon[x]<180.0?-path.lon[x]:360.0-path.lon[x]),path.lat[x]);
+
+       fprintf(fd,"    </coordinates>\n");
+       fprintf(fd,"   </LineString>\n");
+       fprintf(fd,"</Placemark>\n");
+
+       fprintf(fd,"<Placemark>\n");
+       fprintf(fd,"<name>Line-of-Sight Path</name>\n");
+       fprintf(fd,"  <visibility>1</visibility>\n");
+       fprintf(fd,"  <open>0</open>\n");
+       fprintf(fd,"  <Style>\n");
+       fprintf(fd,"    <LineStyle>\n");
+       fprintf(fd,"      <color>ff00ff00</color>\n");
+       fprintf(fd,"    </LineStyle>\n");
+       fprintf(fd,"    <PolyStyle>\n");
+       fprintf(fd,"       <color>7f00ff00</color>\n");
+       fprintf(fd,"    </PolyStyle>\n");
+       fprintf(fd,"  </Style>\n");
+       fprintf(fd,"  <LineString>\n");
+       fprintf(fd,"    <extrude>1</extrude>\n");
+       fprintf(fd,"    <tessellate>1</tessellate>\n");
+       fprintf(fd,"    <altitudeMode>relativeToGround</altitudeMode>\n");
+       fprintf(fd,"    <coordinates>\n");
+
+       /* Walk across the "path", indentifying obstructions along the way */
+
+       for (y=0; y<path.length; y++)
        {
-               fprintf(fd,"Antenna height above average terrain: %.2f feet\n\n",terrain);
+               distance=5280.0*path.distance[y];
+               tx_alt=earthradius+source.alt+path.elevation[0];
+               rx_alt=earthradius+destination.alt+path.elevation[y];
 
-               /* Display the average terrain between 2 and 10 miles
-                  from the transmitter site at azimuths of 0, 45, 90,
-                  135, 180, 225, 270, and 315 degrees. */
+               /* Calculate the cosine of the elevation of the
+                  transmitter as seen at the temp rx point. */
 
-               for (azi=0; azi<=315; azi+=45)
+               cos_xmtr_angle=((rx_alt*rx_alt)+(distance*distance)-(tx_alt*tx_alt))/(2.0*rx_alt*distance);
+
+               for (x=y, block=0; x>=0 && block==0; x--)
                {
-                       fprintf(fd,"Average terrain at %3d degrees azimuth: ",azi);
-                       terrain=AverageTerrain(xmtr,(double)azi,2.0,10.0);
+                       distance=5280.0*(path.distance[y]-path.distance[x]);
+                       test_alt=earthradius+path.elevation[x];
 
-                       if (terrain>-4999.0)
-                               fprintf(fd,"%.2f feet AMSL\n",terrain);
-                       else
-                               fprintf(fd,"No terrain\n");
+                       cos_test_angle=((rx_alt*rx_alt)+(distance*distance)-(test_alt*test_alt))/(2.0*rx_alt*distance);
+
+                       /* Compare these two angles to determine if
+                          an obstruction exists.  Since we're comparing
+                          the cosines of these angles rather than
+                          the angles themselves, the following "if"
+                          statement is reversed from what it would
+                          be if the actual angles were compared. */
+
+                       if (cos_xmtr_angle>cos_test_angle)
+                               block=1;
                }
+
+               if (block)
+                       fprintf(fd,"      %f,%f,-30\n",(path.lon[y]<180.0?-path.lon[y]:360.0-path.lon[y]),path.lat[y]);
+               else
+                       fprintf(fd,"      %f,%f,5\n",(path.lon[y]<180.0?-path.lon[y]:360.0-path.lon[y]),path.lat[y]);
        }
 
-       fprintf(fd,"\n---------------------------------------------------------------------------\n\n");
+       fprintf(fd,"    </coordinates>\n");
+       fprintf(fd,"  </LineString>\n");
+       fprintf(fd,"</Placemark>\n");
+
+       fprintf(fd,"    <LookAt>\n");
+       fprintf(fd,"      <longitude>%f</longitude>\n",(source.lon<180.0?-source.lon:360.0-source.lon));
+       fprintf(fd,"      <latitude>%f</latitude>\n",source.lat);
+       fprintf(fd,"      <range>300.0</range>\n");
+       fprintf(fd,"      <tilt>45.0</tilt>\n");
+       fprintf(fd,"      <heading>%f</heading>\n",azimuth);
+       fprintf(fd,"    </LookAt>\n");
+
+       fprintf(fd,"</Folder>\n");
+       fprintf(fd,"</kml>\n");
+
        fclose(fd);
-       fprintf(stdout,"\nSite analysis report written to: \"%s\"\n",report_name);
+
+       fprintf(stdout, "\nKML file written to: \"%s\"",report_name);
+
+       fflush(stdout);
 }
 
 int main(char argc, char *argv[])
 {
-       int             x, y, ymin, ymax, width, z=0, min_lat, min_lon,
-                       max_lat, max_lon, rxlat, rxlon, txlat, txlon,
-                       west_min, west_max, north_min, north_max;
+       int             x, y, z=0, min_lat, min_lon, max_lat, max_lon,
+                       rxlat, rxlon, txlat, txlon, west_min, west_max,
+                       north_min, north_max;
 
-       unsigned char   coverage=0, LRmap=0, ext[20], terrain_plot=0,
-                       elevation_plot=0, height_plot=0, 
+       unsigned char   coverage=0, LRmap=0, terrain_plot=0,
+                       elevation_plot=0, height_plot=0, map=0, nf=0,
                        longley_plot=0, cities=0, bfs=0, txsites=0,
-                       count, report='y';
+                       norm=0, topomap=0, geo=0, kml=0, pt2pt_mode=0,
+                       area_mode=0, max_txsites, ngs=0, nolospath=0,
+                       nositereports=0;
  
        char            mapfile[255], header[80], city_file[5][255], 
                        elevation_file[255], height_file[255], 
                        longley_file[255], terrain_file[255],
                        string[255], rxfile[255], *env=NULL,
-                       txfile[255], map=0, boundary_file[5][255],
-                       rxsite=0;
+                       txfile[255], boundary_file[5][255],
+                       udt_file[255], rxsite=0, plo_filename[255],
+                       pli_filename[255], ext[20];
 
        double          altitude=0.0, altitudeLR=0.0, tx_range=0.0,
                        rx_range=0.0, deg_range=0.0, deg_limit,
-                       deg_range_lon, er_mult;
+                       deg_range_lon, er_mult, freq=0.0;
 
-       struct          site tx_site[4], rx_site;
+       struct          site tx_site[32], rx_site;
 
        FILE            *fd;
 
-       sprintf(header,"\n\t\t--==[ Welcome To SPLAT! v%s ]==--\n\n", splat_version);
 
        if (argc==1)
        {
-               fprintf(stdout, "%sAvailable Options...\n\n\t -t txsite(s).qth (max of 4)\n\t -r rxsite.qth\n",header);
-               fprintf(stdout,"\t -c plot coverage area(s) of TX(s) based on an RX antenna at X feet AGL\n");
-               fprintf(stdout,"\t -L plot path loss map of TX based on an RX antenna at X feet AGL\n");
-               fprintf(stdout,"\t -s filename(s) of city/site file(s) to import (max of 5)\n");
-               fprintf(stdout,"\t -b filename(s) of cartographic boundary file(s) to import (max of 5)\n");
-               fprintf(stdout,"\t -p filename of terrain profile graph to plot\n");
-               fprintf(stdout,"\t -e filename of terrain elevation graph to plot\n");
-               fprintf(stdout,"\t -h filename of terrain height graph to plot\n");
-               fprintf(stdout,"\t -l filename of Longley-Rice graph to plot\n");
-               fprintf(stdout,"\t -o filename of topographic map to generate (.ppm)\n");
-               fprintf(stdout,"\t -d sdf file directory path (overrides path in ~/.splat_path file)\n");
-               fprintf(stdout,"\t -n no analysis, brief report\n\t -N no analysis, no report\n");
-               fprintf(stdout,"\t -m earth radius multiplier\n");
-               fprintf(stdout,"\t -R modify default range for -c or -L (miles)\n");
-               fprintf(stdout,"\t-db maximum loss contour to display on path loss maps (80-230 dB)\n\n");
-
+               fprintf(stdout,"\n\t\t --==[ SPLAT! v%s Available Options... ]==--\n\n",splat_version);
+               fprintf(stdout,"       -t txsite(s).qth (max of 4 with -c, max of 30 with -L)\n");
+               fprintf(stdout,"       -r rxsite.qth\n");
+               fprintf(stdout,"       -c plot coverage of TX(s) with an RX antenna at X feet/meters AGL\n");
+               fprintf(stdout,"       -L plot path loss map of TX based on an RX at X feet/meters AGL\n");
+               fprintf(stdout,"       -s filename(s) of city/site file(s) to import (5 max)\n");
+               fprintf(stdout,"       -b filename(s) of cartographic boundary file(s) to import (5 max)\n");
+               fprintf(stdout,"       -p filename of terrain profile graph to plot\n");
+               fprintf(stdout,"       -e filename of terrain elevation graph to plot\n");
+               fprintf(stdout,"       -h filename of terrain height graph to plot\n");
+               fprintf(stdout,"       -H filename of normalized terrain height graph to plot\n");
+               fprintf(stdout,"       -l filename of Longley-Rice graph to plot\n");
+               fprintf(stdout,"       -o filename of topographic map to generate (.ppm)\n");
+               fprintf(stdout,"       -u filename of user-defined terrain file to import\n");
+               fprintf(stdout,"       -d sdf file directory path (overrides path in ~/.splat_path file)\n");
+               fprintf(stdout,"       -m earth radius multiplier\n");
+               fprintf(stdout,"       -n do not plot LOS paths in .ppm maps\n");
+               fprintf(stdout,"       -N do not produce unnecessary site or obstruction reports\n");   
+               fprintf(stdout,"       -f frequency for Fresnel zone calculation (MHz)\n");
+               fprintf(stdout,"       -R modify default range for -c or -L (miles/kilometers)\n");
+               fprintf(stdout,"      -db maximum loss contour to display on path loss maps (80-230 dB)\n");
+               fprintf(stdout,"      -nf do not plot Fresnel zones in height plots\n");
+               fprintf(stdout,"      -fz Fresnel zone clearance percentage (default = 60)\n");
+               fprintf(stdout,"     -ngs display greyscale topography as white in .ppm files\n");      
+               fprintf(stdout,"     -erp override ERP in .lrp file (Watts)\n");
+               fprintf(stdout,"     -pli filename of path-loss input file\n");
+               fprintf(stdout,"     -plo filename of path-loss output file\n");
+               fprintf(stdout,"     -udt filename of user defined terrain input file\n");
+               fprintf(stdout,"     -kml generate Google Earth (.kml) compatible output\n");
+               fprintf(stdout,"     -geo generate an Xastir .geo georeference file (with .ppm output)\n");
+               fprintf(stdout,"  -metric employ metric rather than imperial units for all user I/O\n\n");
+               fprintf(stdout,"If that flew by too fast, consider piping the output through 'less':\n");
+               fprintf(stdout,"\n\tsplat | less\n\n");
                fprintf(stdout,"Type 'man splat', or see the documentation for more details.\n\n");
                fflush(stdout);
+
                return 1;
        }
 
        y=argc-1;
 
+       kml=0;
+       geo=0;
+       metric=0;
        rxfile[0]=0;
        txfile[0]=0;
        string[0]=0;
@@ -3706,18 +6119,27 @@ int main(char argc, char *argv[])
        elevation_file[0]=0;
        terrain_file[0]=0;
        sdf_path[0]=0;
+       udt_file[0]=0;
        path.length=0;
+       max_txsites=30;
+       LR.frq_mhz=0.0;
+       fzone_clearance=0.6;
        rx_site.lat=91.0;
        rx_site.lon=361.0;
+       longley_file[0]=0;
+       plo_filename[0]=0;
+       pli_filename[0]=0;
        earthradius=EARTHRADIUS;
 
+       sprintf(header,"\n\t\t--==[ Welcome To SPLAT! v%s ]==--\n\n", splat_version);
+
        for (x=0; x<4; x++)
        {
                tx_site[x].lat=91.0;
                tx_site[x].lon=361.0;
        }
 
-       for (x=0; x<MAXSLOTS; x++)
+       for (x=0; x<MAXPAGES; x++)
        {
                dem[x].min_el=32768;
                dem[x].max_el=-32768;
@@ -3727,7 +6149,6 @@ int main(char argc, char *argv[])
                dem[x].max_west=-1;
        }
 
-
        /* Scan for command line arguments */
 
        for (x=1; x<=y; x++)
@@ -3766,6 +6187,21 @@ int main(char argc, char *argv[])
                        }                        
                }
 
+               if (strcmp(argv[x],"-fz")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0] && argv[z][0]!='-')
+                       {
+                               sscanf(argv[z],"%lf",&fzone_clearance);
+
+                               if (fzone_clearance<0.0 || fzone_clearance>100.0)
+                                       fzone_clearance=60.0;
+
+                               fzone_clearance/=100.0;
+                       }
+               }
+
                if (strcmp(argv[x],"-o")==0)
                {
                        z=x+1;
@@ -3775,6 +6211,14 @@ int main(char argc, char *argv[])
                        map=1;
                }
 
+               if (strcmp(argv[x],"-u")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0] && argv[z][0]!='-')
+                               strncpy(udt_file,argv[z],253);
+               }
+
                if (strcmp(argv[x],"-c")==0)
                {
                        z=x+1;
@@ -3782,11 +6226,14 @@ int main(char argc, char *argv[])
                        if (z<=y && argv[z][0] && argv[z][0]!='-')
                        {
                                sscanf(argv[z],"%lf",&altitude);
+                               map=1;
                                coverage=1;
+                               area_mode=1;
+                               max_txsites=4;
                        }
                }
 
-               if (strcmp(argv[x],"-db")==0)
+               if (strcmp(argv[x],"-db")==0 || strcmp(argv[x],"-dB")==0)
                {
                        z=x+1;
 
@@ -3812,6 +6259,7 @@ int main(char argc, char *argv[])
                        {
                                strncpy(terrain_file,argv[z],253);
                                terrain_plot=1;
+                               pt2pt_mode=1;
                        }
                }
 
@@ -3823,10 +6271,11 @@ int main(char argc, char *argv[])
                        {
                                strncpy(elevation_file,argv[z],253);
                                elevation_plot=1;
+                               pt2pt_mode=1;
                        }
                }
 
-               if (strcmp(argv[x],"-h")==0)
+               if (strcmp(argv[x],"-h")==0 || strcmp(argv[x],"-H")==0)
                {
                        z=x+1;
 
@@ -3834,25 +6283,37 @@ int main(char argc, char *argv[])
                        {
                                strncpy(height_file,argv[z],253);
                                height_plot=1;
+                               pt2pt_mode=1;
                        }
+
+                       if (strcmp(argv[x],"-H")==0)
+                               norm=1;
+                       else
+                               norm=0;
                }
 
+               if (strcmp(argv[x],"-metric")==0)
+                       metric=1;
+
+               if (strcmp(argv[x],"-geo")==0)
+                       geo=1;
+
+               if (strcmp(argv[x],"-kml")==0)
+                       kml=1;
+
+               if (strcmp(argv[x],"-nf")==0)
+                       nf=1;
+
+               if (strcmp(argv[x],"-ngs")==0)
+                       ngs=1;
+
                if (strcmp(argv[x],"-n")==0)
-               {
-                       if (z<=y && argv[z][0] && argv[z][0]!='-')
-                       {
-                               report='n';
-                               map=1;
-                       }
-               }
+                       nolospath=1;
 
                if (strcmp(argv[x],"-N")==0)
                {
-                       if (z<=y && argv[z][0] && argv[z][0]!='-');
-                       {
-                               report='N';
-                               map=1;
-                       }
+                       nolospath=1;
+                       nositereports=1;
                }
 
                if (strcmp(argv[x],"-d")==0)
@@ -3869,13 +6330,14 @@ int main(char argc, char *argv[])
 
                        z=x+1;
 
-                       while (z<=y && argv[z][0] && argv[z][0]!='-' && txsites<4)
+                       while (z<=y && argv[z][0] && argv[z][0]!='-' && txsites<30)
                        {
                                strncpy(txfile,argv[z],253);
                                tx_site[txsites]=LoadQTH(txfile);
                                txsites++;
                                z++;
                        }
+
                        z--;
                }
 
@@ -3886,14 +6348,12 @@ int main(char argc, char *argv[])
                        if (z<=y && argv[z][0] && argv[z][0]!='-')
                        {
                                sscanf(argv[z],"%lf",&altitudeLR);
+                               map=1;
+                               LRmap=1;
+                               area_mode=1;
 
                                if (coverage)
                                        fprintf(stdout,"c and L are exclusive options, ignoring L.\n");
-                               else
-                               {
-                                       LRmap=1;
-                                       ReadLRParm(txfile);
-                               } 
                        }
                }
 
@@ -3905,8 +6365,7 @@ int main(char argc, char *argv[])
                        {
                                strncpy(longley_file,argv[z],253);
                                longley_plot=1;
-                               /* Doing this twice is harmless */
-                               ReadLRParm(txfile);
+                               pt2pt_mode=1;
                        }
                }
 
@@ -3921,6 +6380,7 @@ int main(char argc, char *argv[])
                                strncpy(rxfile,argv[z],253);
                                rx_site=LoadQTH(rxfile);
                                rxsite=1;
+                               pt2pt_mode=1;
                        }
                }
 
@@ -3936,6 +6396,7 @@ int main(char argc, char *argv[])
                                cities++;
                                z++;
                        }
+
                        z--;
                }
 
@@ -3951,8 +6412,54 @@ int main(char argc, char *argv[])
                                bfs++;
                                z++;
                        }
+
                        z--;
                }
+               
+               if (strcmp(argv[x],"-f")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0] && argv[z][0]!='-')
+                       {
+                               sscanf(argv[z],"%lf",&freq);
+
+                               if (freq<20)
+                                       freq=20;
+
+                               if (freq>20e3)
+                                       freq=20e3;
+                       }                        
+               }
+
+               if (strcmp(argv[x],"-erp")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0] && argv[z][0]!='-')
+                       {
+                               sscanf(argv[z],"%lf",&forced_erp);
+
+                               if (forced_erp<0.0)
+                                       forced_erp=-1.0;
+                       }                        
+               }
+
+               if (strcmp(argv[x],"-plo")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0] && argv[z][0]!='-')
+                               strncpy(plo_filename,argv[z],253);
+               }
+
+               if (strcmp(argv[x],"-pli")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0] && argv[z][0]!='-')
+                               strncpy(pli_filename,argv[z],253);
+               }
        }
 
        /* Perform some error checking on the arguments
@@ -3981,13 +6488,33 @@ int main(char argc, char *argv[])
                exit (-1);
        }
 
-       if ((coverage+LRmap)==0 && rx_site.lat==91.0 && rx_site.lon==361.0)
+       if ((coverage+LRmap+pli_filename[0])==0 && rx_site.lat==91.0 && rx_site.lon==361.0)
        {
-               fprintf(stderr,"\n%c*** ERROR: No receiver site found or specified!\n\n",7);
-               exit (-1);
+               if (max_range!=0.0 && txsites!=0)
+               {
+                       /* Plot topographic map of radius "max_range" */
+
+                       map=0;
+                       topomap=1;
+               }
+
+               else
+               {
+                       fprintf(stderr,"\n%c*** ERROR: No receiver site found or specified!\n\n",7);
+                       exit (-1);
+               }
        }
 
-       /* No errors were detected.  Whew!  :-) */
+       /* No major errors were detected.  Whew!  :-) */
+
+       /* Adjust input parameters if -metric option is used */
+
+       if (metric)
+       {
+               altitudeLR/=METERS_PER_FOOT;    /* meters --> feet */
+               max_range/=KM_PER_MILE;         /* kilometers --> miles */
+               altitude/=METERS_PER_FOOT;      /* meters --> feet */
+       }
 
        /* If no SDF path was specified on the command line (-d), check
           for a path specified in the $HOME/.splat_path file.  If the
@@ -4022,15 +6549,42 @@ int main(char argc, char *argv[])
        {
                x=strlen(sdf_path);
 
-               if (sdf_path[x-1]!='/' && x!=0)
+               if (sdf_path[x-1]!='/' && x!=0)
+               {
+                       sdf_path[x]='/';
+                       sdf_path[x+1]=0;
+               }
+       }
+
+       fprintf(stdout,"%s",header);
+       fflush(stdout);
+
+       if (pli_filename[0])
+       {
+               y=LoadPLI(pli_filename);
+
+               for (x=0; x<txsites && x<max_txsites; x++)
+                       PlaceMarker(tx_site[x]);
+
+               if (rxsite)
+                       PlaceMarker(rx_site);
+
+               if (bfs)
+               {
+                       for (x=0; x<bfs; x++)
+                               LoadBoundaries(boundary_file[x]);
+               }
+
+               if (cities)
                {
-                       sdf_path[x]='/';
-                       sdf_path[x+1]=0;
+                       for (x=0; x<cities; x++)
+                               LoadCities(city_file[x]);
                }
-       }
 
-       fprintf(stdout,"%s",header);
-       fflush(stdout);
+               WritePPMLR(mapfile,geo,kml,ngs,tx_site,txsites);
+
+               exit(0);
+       }
 
        x=0;
        y=0;
@@ -4041,7 +6595,7 @@ int main(char argc, char *argv[])
        min_lon=(int)floor(tx_site[0].lon);
        max_lon=(int)floor(tx_site[0].lon);
 
-       for (y=0, z=0; z<txsites; z++)
+       for (y=0, z=0; z<txsites && z<max_txsites; z++)
        {
                txlat=(int)floor(tx_site[z].lat);
                txlon=(int)floor(tx_site[z].lon);
@@ -4080,66 +6634,11 @@ int main(char argc, char *argv[])
 
        /* Load the required SDF files */ 
 
-       width=ReduceAngle(max_lon-min_lon);
-
-       if ((max_lon-min_lon)<=180.0)
-       {
-               for (y=0; y<=width; y++)
-                       for (x=min_lat; x<=max_lat; x++)
-                       {
-                               ymin=(int)(min_lon+(double)y);
-
-                               while (ymin<0)
-                                       ymin+=360;
-
-                               while (ymin>=360)
-                                       ymin-=360;
-
-                               ymax=ymin+1;
-
-                               while (ymax<0)
-                                       ymax+=360;
-
-                               while (ymax>=360)
-                                       ymax-=360;
-
-                               sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
-                               LoadSDF(string);
-                       }
-       }
-
-       else
-       {
-               for (y=0; y<=width; y++)
-                       for (x=min_lat; x<=max_lat; x++)
-                       {
-                               ymin=max_lon+y;
-
-                               while (ymin<0)
-                                       ymin+=360;
-
-                               while (ymin>=360)
-                                       ymin-=360;
-                                       
-                               ymax=ymin+1;
-
-                               while (ymax<0)
-                                       ymax+=360;
-
-                               while (ymax>=360)
-                                       ymax-=360;
-
-                               sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
-                               LoadSDF(string);
-                       }
-       }
+       LoadTopoData(max_lon, min_lon, max_lat, min_lat);
 
-       if (coverage | LRmap)
+       if (area_mode || topomap)
        {
-               if (LRmap)
-                       txsites=1;
-
-               for (z=0; z<txsites; z++)
+               for (z=0; z<txsites && z<max_txsites; z++)
                {
                        /* "Ball park" estimates used to load any additional
                           SDF files required to conduct this analysis. */
@@ -4171,10 +6670,10 @@ int main(char argc, char *argv[])
                                deg_range=max_range/69.0;
 
                        /* Prevent the demand for a really wide coverage
-                          from allocating more slots than are available
+                          from allocating more "pages" than are available
                           in memory. */
 
-                       switch (MAXSLOTS)
+                       switch (MAXPAGES)
                        {
                                case 2: deg_limit=0.25;
                                        break;
@@ -4204,7 +6703,6 @@ int main(char argc, char *argv[])
                        if (deg_range_lon>deg_limit)
                                deg_range_lon=deg_limit;
 
-
                        north_min=(int)floor(tx_site[z].lat-deg_range);
                        north_max=(int)floor(tx_site[z].lat+deg_range);
 
@@ -4237,144 +6735,45 @@ int main(char argc, char *argv[])
                                max_lon=west_max;
                }
 
+               /* Load any additional SDF files, if required */ 
 
-               /* Load the required SDF files */ 
-
-               width=ReduceAngle(max_lon-min_lon);
-
-               if ((max_lon-min_lon)<=180.0)
-               {
-                       for (y=0; y<=width; y++)
-                               for (x=min_lat; x<=max_lat; x++)
-                               {
-                                       ymin=(int)(min_lon+(double)y);
-
-                                       while (ymin<0)
-                                               ymin+=360;
-
-                                       while (ymin>=360)
-                                               ymin-=360;
-
-                                       ymax=ymin+1;
-
-                                       while (ymax<0)
-                                               ymax+=360;
-
-                                       while (ymax>=360)
-                                               ymax-=360;
-
-                                       sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
-                                       LoadSDF(string);
-                               }
-               }
-
-               else
-               {
-                       for (y=0; y<=width; y++)
-                               for (x=min_lat; x<=max_lat; x++)
-                               {
-                                       ymin=(int)(max_lon+(double)y);
-
-                                       while (ymin<0)
-                                               ymin+=360;
-
-                                       while (ymin>=360)
-                                               ymin-=360;
-                                       
-                                       ymax=ymin+1;
-
-                                       while (ymax<0)
-                                               ymax+=360;
-
-                                       while (ymax>=360)
-                                               ymax-=360;
-
-                                       sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
-                                       LoadSDF(string);
-                               }
-               }
+               LoadTopoData(max_lon, min_lon, max_lat, min_lat);
        }
+       
+       if (udt_file[0])
+               LoadUDT(udt_file);
 
 
-       if (mapfile[0])
-               map=1;
-
-       if (coverage | LRmap)
-       {
-               for (x=0; x<txsites; x++)
-               {
-                       if (coverage)
-                               PlotCoverage(tx_site[x],altitude);
-
-                       if (LRmap)
-                               PlotLRMap(tx_site[x],altitudeLR);
-
-                       PlaceMarker(tx_site[x]);
-
-                       if (report!='N')
-                               SiteReport(tx_site[x]);
-               }
-
-               map=1;
-       }
+       /***** Let the SPLATting begin! *****/
 
-       if (coverage==0 && LRmap==0)       
+       if (pt2pt_mode)
        {
                PlaceMarker(rx_site);
 
-               for (x=0; x<txsites; x++)
+               if (longley_plot)
                {
-                       PlaceMarker(tx_site[x]);
-
-                       if (report=='y')
-                       {
-                               switch (x)
-                               {
-                                       case 0:
-                                               PlotPath(tx_site[x],rx_site,1);
-                                               break;
+                       /* Grab extension to determine graphic file type */
 
-                                       case 1:
-                                               PlotPath(tx_site[x],rx_site,8);
-                                               break;
+                       for (x=0; longley_file[x]!='.' && longley_file[x]!=0 && x<80; x++);
 
-                                       case 2:
-                                               PlotPath(tx_site[x],rx_site,16);
-                                               break;
+                       if (longley_file[x]=='.')
+                       {
+                               ext[0]='.';
+                               for (y=1, z=x, x++; longley_file[x]!=0 && x<253 && y<14; x++, y++)
+                                       ext[y]=longley_file[x];
 
-                                       case 3:
-                                               PlotPath(tx_site[x],rx_site,32);
-                               }
+                               ext[y]=0;
+                               longley_file[z]=0;
                        }
 
-                       if (report!='N')
-                               ObstructionReport(tx_site[x],rx_site,report);
-               }
-       }
-
-       if (map)
-       {
-               if (bfs)
-               {
-                       for (x=0; x<bfs; x++)
-                               LoadBoundaries(boundary_file[x]);
-               }
-
-               if (cities)
-               {
-                       for (x=0; x<cities; x++)
-                               LoadCities(city_file[x]);
+                       else
+                       {
+                               ext[0]=0;  /* No extension */
+                               longley_file[x]=0;
+                       }
                }
-                               
-               if (!LRmap)
-                       WritePPM(mapfile);
-               else
-                       WritePPMLR(mapfile);
-       }
 
-       if (terrain_plot)
-       {
-               if (txsites>1)
+               if (terrain_plot)
                {
                        for (x=0; terrain_file[x]!='.' && terrain_file[x]!=0 && x<80; x++);
 
@@ -4393,21 +6792,9 @@ int main(char argc, char *argv[])
                                ext[0]=0;  /* No extension */
                                terrain_file[x]=0;
                        }
-
-                       for (count=0; count<txsites; count++)
-                       {
-                               sprintf(string,"%s-%c%s%c",terrain_file,'1'+count,ext,0);
-                               GraphTerrain(tx_site[count],rx_site,string);
-                       }
                }
 
-               else
-                       GraphTerrain(tx_site[0],rx_site,terrain_file);
-       }
-
-       if (elevation_plot)
-       {
-               if (txsites>1)
+               if (elevation_plot)
                {
                        for (x=0; elevation_file[x]!='.' && elevation_file[x]!=0 && x<80; x++);
 
@@ -4426,21 +6813,9 @@ int main(char argc, char *argv[])
                                ext[0]=0;  /* No extension */
                                elevation_file[x]=0;
                        }
-
-                       for (count=0; count<txsites; count++)
-                       {
-                               sprintf(string,"%s-%c%s%c",elevation_file,'1'+count,ext,0);
-                               GraphElevation(tx_site[count],rx_site,string);
-                       }
                }
 
-               else
-                       GraphElevation(tx_site[0],rx_site,elevation_file);
-       }
-
-       if (height_plot)
-       {
-               if (txsites>1)
+               if (height_plot)
                {
                        for (x=0; height_file[x]!='.' && height_file[x]!=0 && x<80; x++);
 
@@ -4459,51 +6834,148 @@ int main(char argc, char *argv[])
                                ext[0]=0;  /* No extension */
                                height_file[x]=0;
                        }
+               }
+
+               for (x=0; x<txsites && x<4; x++)
+               {
+                       PlaceMarker(tx_site[x]);
+
+                       if (nolospath==0)
+                       {
+                               switch (x)
+                               {
+                                       case 0:
+                                               PlotPath(tx_site[x],rx_site,1);
+                                               break;
+
+                                       case 1:
+                                               PlotPath(tx_site[x],rx_site,8);
+                                               break;
+
+                                       case 2:
+                                               PlotPath(tx_site[x],rx_site,16);
+                                               break;
+
+                                       case 3:
+                                               PlotPath(tx_site[x],rx_site,32);
+                               }
+                       }
+
+                       if (nositereports==0)
+                               SiteReport(tx_site[x]);
+
+                       if (kml)
+                               WriteKML(tx_site[x],rx_site);
+
+                       if (txsites>1)
+                               sprintf(string,"%s-%c%s%c",longley_file,'1'+x,ext,0);
+                       else
+                               sprintf(string,"%s%s%c",longley_file,ext,0);
 
-                       for (count=0; count<txsites; count++)
+                       if (nositereports==0)
                        {
-                               sprintf(string,"%s-%c%s%c",height_file,'1'+count,ext,0);
-                               GraphHeight(tx_site[count],rx_site,string);
+                               if (longley_file[0]==0)
+                               {
+                                       ReadLRParm(tx_site[x],0);
+                                       PathReport(tx_site[x],rx_site,string,0);                                }
+
+                               else
+                               {
+                                       ReadLRParm(tx_site[x],1);
+                                       PathReport(tx_site[x],rx_site,string,longley_file[0]);
+                               }
                        }
-               }
 
-               else
-                       GraphHeight(tx_site[0],rx_site,height_file);
-       }
+                       if (terrain_plot)
+                       {
+                               if (txsites>1)
+                                       sprintf(string,"%s-%c%s%c",terrain_file,'1'+x,ext,0);
+                               else
+                                       sprintf(string,"%s%s%c",terrain_file,ext,0);
 
-       if (longley_plot)
-       {
-               if (txsites>1)
-               {
-                       for (x=0; longley_file[x]!='.' && longley_file[x]!=0 && x<80; x++);
+                               GraphTerrain(tx_site[x],rx_site,string);
+                       }
 
-                       if (longley_file[x]=='.')  /* extension */
+                       if (elevation_plot)
                        {
-                               ext[0]='.';
-                               for (y=1, z=x, x++; longley_file[x]!=0 && x<253 && y<14; x++, y++)
-                                       ext[y]=longley_file[x];
+                               if (txsites>1)
+                                       sprintf(string,"%s-%c%s%c",elevation_file,'1'+x,ext,0);
+                               else
+                                       sprintf(string,"%s%s%c",elevation_file,ext,0);
 
-                               ext[y]=0;
-                               longley_file[z]=0;
+                               GraphElevation(tx_site[x],rx_site,string);
                        }
 
-                       else
+                       if (height_plot)
                        {
-                               ext[0]=0;  /* No extension */
-                               longley_file[x]=0;
+                               if (freq==0.0 && nf==0)
+                                       freq=LR.frq_mhz;
+
+                               if (txsites>1)
+                                       sprintf(string,"%s-%c%s%c",height_file,'1'+x,ext,0);
+                               else
+                                       sprintf(string,"%s%s%c",height_file,ext,0);
+
+                               GraphHeight(tx_site[x],rx_site,string,freq,norm);
                        }
+               }
+       }
+
+       if (area_mode && topomap==0)
+       {
+               for (x=0; x<txsites && x<max_txsites; x++)
+               {
+                       if (coverage)
+                               PlotCoverage(tx_site[x],altitude);
+
+                       else if (ReadLRParm(tx_site[x],1))
+                               PlotLRMap(tx_site[x],altitudeLR,plo_filename);
+
+                       SiteReport(tx_site[x]);
+               }
+       }
+
+       if (map || topomap)
+       {
+               /* Label the map */
 
-                       for (count=0; count<txsites; count++)
+               if (cities)
+               {
+                       if (kml==0)
                        {
-                               sprintf(string,"%s-%c%s%c",longley_file,'1'+count,ext,0);
-                               GraphLongley(tx_site[count],rx_site,string);
+                               for (x=0; x<txsites && x<max_txsites; x++)
+                                       PlaceMarker(tx_site[x]);
                        }
+
+                       for (y=0; y<cities; y++)
+                               LoadCities(city_file[y]);
+               }
+
+               /* Load city and county boundary data files */
+
+               if (bfs)
+               {
+                       for (y=0; y<bfs; y++)
+                               LoadBoundaries(boundary_file[y]);
                }
 
+               /* Plot the map */
+
+               if (coverage || pt2pt_mode || topomap)
+                       WritePPM(mapfile,geo,kml,ngs);
+
                else
-                       GraphLongley(tx_site[0],rx_site,longley_file);
+               {
+                       if (LR.erp==0.0)
+                               WritePPMLR(mapfile,geo,kml,ngs,tx_site,txsites);
+                       else
+                               WritePPMSS(mapfile,geo,kml,ngs,tx_site,txsites);
+               }
        }
 
+       printf("\n");
+
+       /* That's all, folks! */
+
        return 0;
 }
-