* SPLAT!: An RF Signal Path Loss And Terrain Analysis Tool *
******************************************************************************
* Project started in 1997 by John A. Magliacane, KD2BD *
-* Last update: 19-Oct-2007 *
+* Last update: 10-Apr-2009 *
******************************************************************************
* Please consult the documentation for a complete list of *
* individuals who have contributed to this project. *
#include <bzlib.h>
#include <unistd.h>
#include "fontdata.h"
+#include "splat.h"
#define GAMMA 2.5
-#define MAXPAGES 9
#define BZBUFFER 65536
-#if MAXPAGES==4
-#define ARRAYSIZE 4950
+#if HD_MODE==0
+ #if MAXPAGES==4
+ #define ARRAYSIZE 4950
+ #endif
+
+ #if MAXPAGES==9
+ #define ARRAYSIZE 10870
+ #endif
+
+ #if MAXPAGES==16
+ #define ARRAYSIZE 19240
+ #endif
+
+ #if MAXPAGES==25
+ #define ARRAYSIZE 30025
+ #endif
+
+ #if MAXPAGES==36
+ #define ARRAYSIZE 43217
+ #endif
+
+ #if MAXPAGES==49
+ #define ARRAYSIZE 58813
+ #endif
+
+ #if MAXPAGES==64
+ #define ARRAYSIZE 76810
+ #endif
+
+ #define IPPD 1200
+#endif
+
+#if HD_MODE==1
+ #if MAXPAGES==1
+ #define ARRAYSIZE 5092
+ #endif
+
+ #if MAXPAGES==4
+ #define ARRAYSIZE 14844
+ #endif
+
+ #if MAXPAGES==9
+ #define ARRAYSIZE 32600
+ #endif
+
+ #if MAXPAGES==16
+ #define ARRAYSIZE 57713
+ #endif
+
+ #if MAXPAGES==25
+ #define ARRAYSIZE 90072
+ #endif
+
+ #if MAXPAGES==36
+ #define ARRAYSIZE 129650
+ #endif
+
+ #if MAXPAGES==49
+ #define ARRAYSIZE 176437
+ #endif
+
+ #if MAXPAGES==64
+ #define ARRAYSIZE 230430
+ #endif
+
+ #define IPPD 3600
#endif
-#if MAXPAGES==9
-#define ARRAYSIZE 10870
+#ifndef PI
+#define PI 3.141592653589793
#endif
-#if MAXPAGES==16
-#define ARRAYSIZE 19240
+#ifndef TWOPI
+#define TWOPI 6.283185307179586
#endif
-#if MAXPAGES==25
-#define ARRAYSIZE 30025
+#ifndef HALFPI
+#define HALFPI 1.570796326794896
#endif
-char string[255], sdf_path[255], opened=0, *splat_version={"1.2.1"};
+#define DEG2RAD 1.74532925199e-02
+#define EARTHRADIUS 20902230.97
+#define METERS_PER_MILE 1609.344
+#define METERS_PER_FOOT 0.3048
+#define KM_PER_MILE 1.609344
+#define FOUR_THIRDS 1.3333333333333
+
+char string[255], sdf_path[255], opened=0, gpsav=0, splat_name[10],
+ splat_version[6], dashes[80];
-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, KM_PER_MILE=1.609344, earthradius,
- max_range=0.0, forced_erp=-1.0, fzone_clearance=0.6;
+double earthradius, max_range=0.0, forced_erp=-1.0, dpp, ppd,
+ fzone_clearance=0.6, forced_freq, clutter;
-int min_north=90, max_north=-90, min_west=360, max_west=-1,
- max_elevation=-32768, min_elevation=32768, bzerror, maxdB=230;
+int min_north=90, max_north=-90, min_west=360, max_west=-1, ippd, mpi,
+ max_elevation=-32768, min_elevation=32768, bzerror, contour_threshold;
-unsigned char got_elevation_pattern, got_azimuth_pattern, metric=0;
+unsigned char got_elevation_pattern, got_azimuth_pattern, metric=0, dbm=0;
struct site { double lat;
double lon;
int max_west;
int max_el;
int min_el;
- short data[1200][1200];
- unsigned char mask[1200][1200];
- unsigned char signal[1200][1200];
+ short data[IPPD][IPPD];
+ unsigned char mask[IPPD][IPPD];
+ unsigned char signal[IPPD][IPPD];
} dem[MAXPAGES];
struct LR { double eps_dielect;
int levels;
} region;
-double elev_l[ARRAYSIZE+10];
+double elev[ARRAYSIZE+10];
void point_to_point(double elev[], double tht_m, double rht_m,
double eps_dielect, double sgm_conductivity, double eno_ns_surfref,
double temp;
- temp=acos(cos(angle*deg2rad));
+ temp=acos(cos(angle*DEG2RAD));
+
+ return (int)rint(temp/DEG2RAD);
+}
+
+double LonDiff(double lon1, double lon2)
+{
+ /* This function returns the short path longitudinal
+ difference between longitude1 and longitude2
+ as an angle between -180.0 and +180.0 degrees.
+ If lon1 is west of lon2, the result is positive.
+ If lon1 is east of lon2, the result is negative. */
+
+ double diff;
+
+ diff=lon1-lon2;
+
+ if (diff<=-180.0)
+ diff+=360.0;
+
+ if (diff>=180.0)
+ diff-=360.0;
- return (int)rint(temp/deg2rad);
+ return diff;
}
char *dec2dms(double decimal)
seconds=59;
string[0]=0;
- sprintf(string,"%d%c %d\' %d\"", degrees*sign, 176, minutes, seconds);
+ snprintf(string,250,"%d%c %d\' %d\"", degrees*sign, 176, minutes, seconds);
return (string);
}
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)
+ {
+ x=(int)rint(ppd*(lat-dem[indx].min_north));
+ y=mpi-(int)rint(ppd*(LonDiff(dem[indx].max_west,lon)));
+
+ if (x>=0 && x<=mpi && y>=0 && y<=mpi)
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]);
+ return ((int)dem[indx].mask[x][y]);
}
else
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)
+ {
+ x=(int)rint(ppd*(lat-dem[indx].min_north));
+ y=mpi-(int)rint(ppd*(LonDiff(dem[indx].max_west,lon)));
+
+ if (x>=0 && x<=mpi && y>=0 && y<=mpi)
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]);
+ return ((int)dem[indx].mask[x][y]);
}
else
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)
+ {
+ x=(int)rint(ppd*(lat-dem[indx].min_north));
+ y=mpi-(int)rint(ppd*(LonDiff(dem[indx].max_west,lon)));
+
+ if (x>=0 && x<=mpi && y>=0 && y<=mpi)
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]);
}
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)
+ {
+ x=(int)rint(ppd*(lat-dem[indx].min_north));
+ y=mpi-(int)rint(ppd*(LonDiff(dem[indx].max_west,lon)));
+
+ if (x>=0 && x<=mpi && y>=0 && y<=mpi)
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;
}
int x, y, indx;
double elevation;
- elevation=-5000.0;
-
- x=(int)(1199.0*(location.lat-floor(location.lat)));
- y=(int)(1199.0*(location.lon-floor(location.lon)));
-
- for (indx=0, found=0; indx<MAXPAGES && found==0; indx++)
+ for (indx=0, found=0; indx<MAXPAGES && found==0;)
{
- 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];
+ x=(int)rint(ppd*(location.lat-dem[indx].min_north));
+ y=mpi-(int)rint(ppd*(LonDiff(dem[indx].max_west,location.lon)));
+
+ if (x>=0 && x<=mpi && y>=0 && y<=mpi)
found=1;
- }
+ else
+ indx++;
}
+
+ if (found)
+ elevation=3.28084*dem[indx].data[x][y];
+ else
+ elevation=-5000.0;
return elevation;
}
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++)
+ 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)
- {
- dem[indx].data[x][y]+=(short)rint(height);
+ x=(int)rint(ppd*(lat-dem[indx].min_north));
+ y=mpi-(int)rint(ppd*(LonDiff(dem[indx].max_west,lon)));
+
+ if (x>=0 && x<=mpi && y>=0 && y<=mpi)
found=1;
- }
+ else
+ indx++;
}
-
+
+ if (found)
+ dem[indx].data[x][y]+=(short)rint(height);
+
return found;
}
double lat1, lon1, lat2, lon2, distance;
- lat1=site1.lat*deg2rad;
- lon1=site1.lon*deg2rad;
- lat2=site2.lat*deg2rad;
- lon2=site2.lon*deg2rad;
+ lat1=site1.lat*DEG2RAD;
+ lon1=site1.lon*DEG2RAD;
+ lat2=site2.lat*DEG2RAD;
+ lon2=site2.lon*DEG2RAD;
distance=3959.0*acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos((lon1)-(lon2)));
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;
+ dest_lat=destination.lat*DEG2RAD;
+ dest_lon=destination.lon*DEG2RAD;
- src_lat=source.lat*deg2rad;
- src_lon=source.lon*deg2rad;
+ src_lat=source.lat*DEG2RAD;
+ src_lon=source.lon*DEG2RAD;
/* Calculate Surface Distance */
if (diff>0.0)
azimuth=TWOPI-azimuth;
- return (azimuth/deg2rad);
+ return (azimuth/DEG2RAD);
}
double ElevationAngle(struct site source, struct site destination)
int c;
double azimuth, distance, lat1, lon1, beta, den, num,
- lat2, lon2, total_distance, x, y, path_length,
- increment;
+ lat2, lon2, total_distance, dx, dy, path_length,
+ miles_per_sample, samples_per_radian=68755.0;
struct site tempsite;
- lat1=source.lat*deg2rad;
- lon1=source.lon*deg2rad;
+ lat1=source.lat*DEG2RAD;
+ lon1=source.lon*DEG2RAD;
+
+ lat2=destination.lat*DEG2RAD;
+ lon2=destination.lon*DEG2RAD;
- lat2=destination.lat*deg2rad;
- lon2=destination.lon*deg2rad;
+ if (ppd==1200.0)
+ samples_per_radian=68755.0;
- azimuth=Azimuth(source,destination)*deg2rad;
+ if (ppd==3600.0)
+ samples_per_radian=206265.0;
+
+ azimuth=Azimuth(source,destination)*DEG2RAD;
total_distance=Distance(source,destination);
- x=68755.0*acos(cos(lon1-lon2)); /* 1200 samples per degree */
- y=68755.0*acos(cos(lat1-lat2)); /* 68755 samples per radian */
+ if (total_distance>(30.0/ppd)) /* > 0.5 pixel distance */
+ {
+ dx=samples_per_radian*acos(cos(lon1-lon2));
+ dy=samples_per_radian*acos(cos(lat1-lat2));
+
+ path_length=sqrt((dx*dx)+(dy*dy)); /* Total number of samples */
+
+ miles_per_sample=total_distance/path_length; /* Miles per sample */
+ }
+
+ else
+ {
+ c=0;
+ dx=0.0;
+ dy=0.0;
+ path_length=0.0;
+ miles_per_sample=0.0;
+ total_distance=0.0;
- path_length=sqrt((x*x)+(y*y)); /* Total number of samples */
+ lat1=lat1/DEG2RAD;
+ lon1=lon1/DEG2RAD;
- increment=total_distance/path_length; /* Miles per sample */
+ path.lat[c]=lat1;
+ path.lon[c]=lon1;
+ path.elevation[c]=GetElevation(source);
+ path.distance[c]=0.0;
+ }
- for (distance=0, c=0; (distance<=total_distance && c<ARRAYSIZE); distance+=increment, c++)
+ for (distance=0.0, c=0; (total_distance!=0.0 && distance<=total_distance && c<ARRAYSIZE); c++, distance=miles_per_sample*(double)c)
{
beta=distance/3959.0;
lat2=asin(sin(lat1)*cos(beta)+cos(azimuth)*sin(beta)*cos(lat1));
lon2=lon1+PI;
else if (azimuth==HALFPI && (beta>HALFPI+lat1))
- lon2=lon1+PI;
+ lon2=lon1+PI;
else if (fabs(num/den)>1.0)
- lon2=lon1;
+ lon2=lon1;
else
{
while (lon2>TWOPI)
lon2-=TWOPI;
- lat2=lat2/deg2rad;
- lon2=lon2/deg2rad;
+ lat2=lat2/DEG2RAD;
+ lon2=lon2/DEG2RAD;
path.lat[c]=lat2;
path.lon[c]=lon2;
{
distance=5280.0*path.distance[x];
- test_alt=earthradius+path.elevation[x];
+ test_alt=earthradius+(path.elevation[x]==0.0?path.elevation[x]:path.elevation[x]+clutter);
cos_test_angle=((source_alt2)+(distance*distance)-(test_alt*test_alt))/(2.0*source_alt*distance);
what it would be if the angles themselves
were compared. */
- if (cos_xmtr_angle>cos_test_angle)
+ if (cos_xmtr_angle>=cos_test_angle)
{
block=1;
- first_obstruction_angle=((acos(cos_test_angle))/deg2rad)-90.0;
+ first_obstruction_angle=((acos(cos_test_angle))/DEG2RAD)-90.0;
}
}
elevation=first_obstruction_angle;
else
- elevation=((acos(cos_xmtr_angle))/deg2rad)-90.0;
+ elevation=((acos(cos_xmtr_angle))/DEG2RAD)-90.0;
path=temp;
double beta, lat1, lon1, lat2, lon2, num, den, azimuth, terrain=0.0;
struct site destination;
- lat1=source.lat*deg2rad;
- lon1=source.lon*deg2rad;
+ lat1=source.lat*DEG2RAD;
+ lon1=source.lon*DEG2RAD;
/* Generate a path of elevations between the source
location and the remote location provided. */
beta=end_distance/3959.0;
- azimuth=deg2rad*azimuthx;
+ azimuth=DEG2RAD*azimuthx;
lat2=asin(sin(lat1)*cos(beta)+cos(azimuth)*sin(beta)*cos(lat1));
num=cos(beta)-(sin(lat1)*sin(lat2));
lon2=lon1+PI;
else if (azimuth==HALFPI && (beta>HALFPI+lat1))
- lon2=lon1+PI;
+ lon2=lon1+PI;
else if (fabs(num/den)>1.0)
- lon2=lon1;
+ lon2=lon1;
else
{
while (lon2>TWOPI)
lon2-=TWOPI;
- lat2=lat2/deg2rad;
- lon2=lon2/deg2rad;
+ lat2=lat2/DEG2RAD;
+ lon2=lon2/DEG2RAD;
destination.lat=lat2;
destination.lon=lon2;
{
if (path.distance[c]>=start_distance)
{
- terrain+=path.elevation[c];
+ terrain+=(path.elevation[c]==0.0?path.elevation[c]:path.elevation[c]+clutter);
samples++;
}
}
}
}
-float LonDiff(float lon1, float lon2)
-{
- /* This function returns the short path longitudinal
- difference between longitude1 and longitude2
- as an angle between -180.0 and +180.0 degrees.
- If lon1 is west of lon2, the result is positive.
- If lon1 is east of lon2, the result is negative. */
-
- float diff;
-
- diff=lon1-lon2;
-
- if (diff<=-180.0)
- diff+=360.0;
-
- if (diff>=180.0)
- diff-=360.0;
-
- return diff;
-}
-
void PlaceMarker(struct site location)
{
/* This function places text and marker data in the mask array
double x, y, lat, lon, textx=0.0, texty=0.0, xmin, xmax,
ymin, ymax, p1, p3, p6, p8, p12, p16, p24, label_length;
- xmin=min_north;
- xmax=max_north;
- ymin=min_west;
- ymax=max_west;
+ xmin=(double)min_north;
+ xmax=(double)max_north;
+ ymin=(double)min_west;
+ ymax=(double)max_west;
lat=location.lat;
lon=location.lon;
- if (lat<xmax && lat>xmin && (LonDiff(lon,ymax)<0.0) && (LonDiff(lon,ymin)>0.0))
+ if (lat<xmax && lat>=xmin && (LonDiff(lon,ymax)<=0.0) && (LonDiff(lon,ymin)>=dpp))
{
- p1=1.0/1200.0;
- p3=3.0/1200.0;
- p6=6.0/1200.0;
- p8=8.0/1200.0;
- p12=12.0/1200.0;
- p16=16.0/1200.0;
- p24=24.0/1200.0;
+ p1=1.0/ppd;
+ p3=3.0/ppd;
+ p6=6.0/ppd;
+ p8=8.0/ppd;
+ p12=12.0/ppd;
+ p16=16.0/ppd;
+ p24=24.0/ppd;
+
ok2print=0;
occupied=0;
/* Is Marker Position Clear Of Text Or Other Markers? */
- for (x=lat-p3; (x<=xmax && x>=xmin && x<=lat+p3); x+=p1)
- for (y=lon-p3; (LonDiff(y,ymax)<=0.0) && (LonDiff(y,ymin)>=0.0) && (LonDiff(y,lon+p3)<=0.0); y+=p1)
+ for (a=0, x=lat-p3; (x<=xmax && x>=xmin && a<7); x+=p1, a++)
+ for (b=0, y=lon-p3; (LonDiff(y,ymax)<=0.0) && (LonDiff(y,ymin)>=dpp) && b<7; y+=p1, b++)
occupied|=(GetMask(x,y)&2);
if (occupied==0)
label_length=p1*(double)(strlen(location.name)<<3);
- if ((LonDiff(lon+label_length,ymax)<=0.0) && (LonDiff(lon-label_length,ymin)>=0.0))
+ if ((LonDiff(lon+label_length,ymax)<=0.0) && (LonDiff(lon-label_length,ymin)>=dpp))
{
/* Default: Centered Text */
if (ok2print==0)
{
- if (LonDiff(lon-label_length,ymin)>=0.0)
+ if (LonDiff(lon-label_length,ymin)>=dpp)
{
/* Position Text To The
Right Of The Marker */
x=textx;
y=texty;
-
- for (a=0; a<16 && ok2print; a++)
+
+ for (a=0; a<16; a++)
{
for (b=0; b<(int)strlen(location.name); b++)
{
/* Draw Square Marker Centered
On Location Specified */
-
- for (x=lat-p3; (x<=xmax && x>=xmin && x<=lat+p3); x+=p1)
- for (y=lon-p3; (LonDiff(y,ymax)<=0.0) && (LonDiff(y,ymin)>=0.0) && (LonDiff(y,lon+p3)<=0.0); y+=p1)
+
+ for (a=0, x=lat-p3; (x<=xmax && x>=xmin && a<7); x+=p1, a++)
+ for (b=0, y=lon-p3; (LonDiff(y,ymax)<=0.0) && (LonDiff(y,ymin)>=dpp) && b<7; y+=p1, b++)
OrMask(x,y,2);
}
}
if (b==0) /* Decimal Format (40.139722) */
sscanf(string,"%lf",&bearing);
- if (b==2) /* Degree, Minute, Second Format (40 08 23) */
+ if (b==2) /* Degree, Minute, Second Format (40 08 23.xx) */
{
sscanf(string,"%d %d %lf",°rees, &minutes, &seconds);
- bearing=(double)abs(degrees)+((double)abs(minutes)/60)+(fabs(seconds)/3600);
+ bearing=fabs((double)degrees);
+ bearing+=fabs(((double)minutes)/60.0);
+ bearing+=fabs(seconds/3600.0);
if ((degrees<0) || (minutes<0) || (seconds<0.0))
bearing=-bearing;
case meters is assumed, and is handled accordingly. */
int x;
- char string[50], qthfile[255];
+ char string[50], qthfile[255], *s=NULL;
struct site tempsite;
FILE *fd=NULL;
- for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
- qthfile[x]=filename[x];
+ x=strlen(filename);
+ strncpy(qthfile, filename, 254);
+
+ if (qthfile[x-3]!='q' || qthfile[x-2]!='t' || qthfile[x-1]!='h')
+ {
+ if (x>249)
+ qthfile[249]=0;
- qthfile[x]='.';
- qthfile[x+1]='q';
- qthfile[x+2]='t';
- qthfile[x+3]='h';
- qthfile[x+4]=0;
+ strncat(qthfile,".qth\0",5);
+ }
tempsite.lat=91.0;
tempsite.lon=361.0;
if (fd!=NULL)
{
/* Site Name */
- fgets(string,49,fd);
+ s=fgets(string,49,fd);
/* Strip <CR> and/or <LF> from end of site name */
tempsite.name[x]=0;
/* Site Latitude */
- fgets(string,49,fd);
+ s=fgets(string,49,fd);
tempsite.lat=ReadBearing(string);
/* Site Longitude */
- fgets(string,49,fd);
+ s=fgets(string,49,fd);
tempsite.lon=ReadBearing(string);
if (tempsite.lon<0.0)
tempsite.lon+=360.0;
/* Antenna Height */
- fgets(string,49,fd);
+ s=fgets(string,49,fd);
fclose(fd);
/* Remove <CR> and/or <LF> from antenna height string */
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;
+ char string[255], azfile[255], elfile[255], *pointer=NULL, *s=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,
in degrees measured clockwise
from true North. */
- fgets(string,254,fd);
+ s=fgets(string,254,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
normalized field radiation pattern amplitude
(0.0 to 1.0) until EOF is reached. */
- fgets(string,254,fd);
+ s=fgets(string,254,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
read_count[x]++;
}
- fgets(string,254,fd);
+ s=fgets(string,254,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
tilt azimuth in degrees measured
clockwise from true North. */
- fgets(string,254,fd);
+ s=fgets(string,254,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
normalized field radiation pattern amplitude
(0.0 to 1.0) until EOF is reached. */
- fgets(string,254,fd);
+ s=fgets(string,254,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
read_count[x]++;
}
- fgets(string,254,fd);
+ s=fgets(string,254,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
int x, y, data, indx, minlat, minlon, maxlat, maxlon;
char found, free_page=0, line[20], sdf_file[255],
- path_plus_name[255];
+ path_plus_name[255], *s=NULL;
FILE *fd;
for (x=0; name[x]!='.' && name[x]!=0 && x<250; x++)
fprintf(stdout,"Loading \"%s\" into page %d...",path_plus_name,indx+1);
fflush(stdout);
- fgets(line,19,fd);
+ s=fgets(line,19,fd);
sscanf(line,"%d",&dem[indx].max_west);
- fgets(line,19,fd);
+ s=fgets(line,19,fd);
sscanf(line,"%d",&dem[indx].min_north);
- fgets(line,19,fd);
+ s=fgets(line,19,fd);
sscanf(line,"%d",&dem[indx].min_west);
- fgets(line,19,fd);
+ s=fgets(line,19,fd);
sscanf(line,"%d",&dem[indx].max_north);
- for (x=0; x<1200; x++)
- for (y=0; y<1200; y++)
+ for (x=0; x<ippd; x++)
+ for (y=0; y<ippd; y++)
{
- fgets(line,19,fd);
+ s=fgets(line,19,fd);
data=atoi(line);
dem[indx].data[x][y]=data;
max_north=dem[indx].max_north;
else if (dem[indx].max_north>max_north)
- max_north=dem[indx].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;
+ min_north=dem[indx].min_north;
if (max_west==-1)
max_west=dem[indx].max_west;
else
{
- if (abs(dem[indx].min_west-min_west)<180)
+ if (fabs(dem[indx].min_west-min_west)<180.0)
{
if (dem[indx].min_west<min_west)
min_west=dem[indx].min_west;
fprintf(stdout," Done!\n");
fflush(stdout);
+
return 1;
}
sscanf(BZfgets(bzfd,255),"%d",&dem[indx].min_west);
sscanf(BZfgets(bzfd,255),"%d",&dem[indx].max_north);
- for (x=0; x<1200; x++)
- for (y=0; y<1200; y++)
+ for (x=0; x<ippd; x++)
+ for (y=0; y<ippd; y++)
{
string=BZfgets(bzfd,20);
data=atoi(string);
max_north=dem[indx].max_north;
else if (dem[indx].max_north>max_north)
- max_north=dem[indx].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;
+ min_north=dem[indx].min_north;
if (max_west==-1)
max_west=dem[indx].max_west;
fprintf(stdout," Done!\n");
fflush(stdout);
+
return 1;
}
/* Fill DEM with sea-level topography */
- for (x=0; x<1200; x++)
- for (y=0; y<1200; y++)
+ for (x=0; x<ippd; x++)
+ for (y=0; y<ippd; y++)
{
dem[indx].data[x][y]=0;
dem[indx].signal[x][y]=0;
max_north=dem[indx].max_north;
else if (dem[indx].max_north>max_north)
- max_north=dem[indx].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;
+ min_north=dem[indx].min_north;
if (max_west==-1)
max_west=dem[indx].max_west;
read on topographic maps generated by SPLAT! */
int x, y, z;
- char input[80], str[3][80];
+ char input[80], str[3][80], *s=NULL;
struct site city_site;
FILE *fd=NULL;
if (fd!=NULL)
{
- fgets(input,78,fd);
+ s=fgets(input,78,fd);
fprintf(stdout,"\nReading \"%s\"... ",filename);
fflush(stdout);
PlaceMarker(city_site);
- fgets(input,78,fd);
+ s=fgets(input,78,fd);
}
fclose(fd);
}
else
- fprintf(stderr,"*** ERROR: \"%s\": not found!\n",filename);
+ fprintf(stderr,"\n*** ERROR: \"%s\": not found!",filename);
}
void LoadUDT(char *filename)
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;
+ int i, x, y, z, ypix, xpix, tempxpix, tempypix, fd=0, n=0;
+ char input[80], str[3][80], tempname[15], *pointer=NULL, *s=NULL;
+ double latitude, longitude, height, tempheight;
FILE *fd1=NULL, *fd2=NULL;
strcpy(tempname,"/tmp/XXXXXX\0");
- one_pixel=1.0/1200.0;
fd1=fopen(filename,"r");
fd=mkstemp(tempname);
fd2=fopen(tempname,"w");
- fgets(input,78,fd1);
+ s=fgets(input,78,fd1);
pointer=strchr(input,';');
else
{
str[2][i]=0;
- height=rint(3.28084*atof(str[2]));
+ height=rint(METERS_PER_FOOT*atof(str[2]));
}
if (height>0.0)
- fprintf(fd2,"%f, %f, %f\n",latitude, longitude, height);
+ fprintf(fd2,"%d, %d, %f\n",(int)rint(latitude/dpp), (int)rint(longitude/dpp), height);
- fgets(input,78,fd1);
+ s=fgets(input,78,fd1);
pointer=strchr(input,';');
fd1=fopen(tempname,"r");
fd2=fopen(tempname,"r");
- fscanf(fd1,"%lf, %lf, %lf", &latitude, &longitude, &height);
+ y=0;
+
+ n=fscanf(fd1,"%d, %d, %lf", &xpix, &ypix, &height);
- for (y=0; feof(fd1)==0; y++)
+ do
{
- rewind(fd2);
+ x=0;
+ z=0;
- fscanf(fd2,"%lf, %lf, %lf", &templat, &templon, &tempheight);
+ n=fscanf(fd2,"%d, %d, %lf", &tempxpix, &tempypix, &tempheight);
- for (x=0, z=0; feof(fd2)==0; x++)
+ do
{
- if (x>y)
- if (fabs(latitude-templat)<=one_pixel && fabs(longitude-templon)<=one_pixel)
- z=1;
+ if (x>y && xpix==tempxpix && ypix==tempypix)
+ {
+ z=1; /* Dupe! */
- fscanf(fd2,"%lf, %lf, %lf", &templat, &templon, &tempheight);
- }
+ if (tempheight>height)
+ height=tempheight;
+ }
- if (z==0)
- AddElevation(latitude, longitude, height);
+ else
+ {
+ n=fscanf(fd2,"%d, %d, %lf", &tempxpix, &tempypix, &tempheight);
+ x++;
+ }
- fscanf(fd1,"%lf, %lf, %lf", &latitude, &longitude, &height);
- }
+ } while (feof(fd2)==0 && z==0);
+
+ if (z==0) /* No duplicate found */
+ AddElevation(xpix*dpp, ypix*dpp, height);
+
+ n=fscanf(fd1,"%d, %d, %lf", &xpix, &ypix, &height);
+ y++;
+
+ rewind(fd2);
+
+ } while (feof(fd1)==0);
fclose(fd1);
fclose(fd2);
else
fprintf(stderr,"\n*** ERROR: \"%s\": not found!",filename);
+
+ fprintf(stdout,"\n");
}
void LoadBoundaries(char *filename)
int x;
double lat0, lon0, lat1, lon1;
- char string[80];
+ char string[80], *s=NULL;
struct site source, destination;
FILE *fd=NULL;
if (fd!=NULL)
{
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
fprintf(stdout,"\nReading \"%s\"... ",filename);
fflush(stdout);
do
{
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
sscanf(string,"%lf %lf", &lon0, &lat0);
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
do
{
sscanf(string,"%lf %lf", &lon1, &lat1);
- lon0=fabs(lon0);
- lon1=fabs(lon1);
-
source.lat=lat0;
- source.lon=lon0;
+ source.lon=(lon0>0.0 ? 360.0-lon0 : -lon0);
destination.lat=lat1;
- destination.lon=lon1;
+ destination.lon=(lon1>0.0 ? 360.0-lon1 : -lon1);
ReadPath(source,destination);
lat0=lat1;
lon0=lon1;
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
} while (strncmp(string,"END",3)!=0 && feof(fd)==0);
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
} while (strncmp(string,"END",3)!=0 && feof(fd)==0);
"splat.lrp". */
double din;
- char filename[255], string[80], *pointer=NULL, return_value=0;
+ char filename[255], string[80], *pointer=NULL, *s=NULL, return_value=0;
int iin, ok=0, x;
FILE *fd=NULL, *outfile=NULL;
if (fd!=NULL)
{
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
{
LR.eps_dielect=din;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
{
LR.sgm_conductivity=din;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
{
LR.eno_ns_surfref=din;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
{
LR.frq_mhz=din;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
{
LR.radio_climate=iin;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
{
LR.pol=iin;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
{
LR.conf=din;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
pointer=strchr(string,';');
if (sscanf(string,"%lf", &din))
LR.erp=din;
+
+ /* ERP in SPLAT! is referenced to 1 Watt
+ into a dipole (0 dBd). If ERP is
+ expressed in dBm (referenced to a
+ 0 dBi radiator), convert dBm in EIRP
+ to ERP. */
+
+ if ((strstr(string, "dBm")!=NULL) || (strstr(string,"dbm")!=NULL))
+ LR.erp=(pow(10.0,(LR.erp-32.14)/10.0));
}
}
if (forced_erp!=-1.0)
LR.erp=forced_erp;
+ if (forced_freq>=20.0 && forced_freq<=20000.0)
+ LR.frq_mhz=forced_freq;
+
if (ok)
LoadPAT(filename);
}
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; Transmitter Effective Radiated Power in Watts (optional)\n",LR.erp);
+ fprintf(outfile,"%.2f\t; Transmitter Effective Radiated Power in Watts or dBm (optional)\n",LR.erp);
fprintf(outfile,"\nPlease consult SPLAT! documentation for the meaning and use of this data.\n");
fclose(outfile);
}
else if (forced_read==0)
- return_value=0;
+ return_value=0;
if (forced_read && (fd==NULL || ok==0))
{
for (x=y, block=0; x>=0 && block==0; x--)
{
distance=5280.0*(path.distance[y]-path.distance[x]);
- test_alt=earthradius+path.elevation[x];
+ test_alt=earthradius+(path.elevation[x]==0.0?path.elevation[x]:path.elevation[x]+clutter);
cos_test_angle=((rx_alt*rx_alt)+(distance*distance)-(test_alt*test_alt))/(2.0*rx_alt*distance);
statement is reversed from what it would
be if the actual angles were compared. */
- if (cos_xmtr_angle>cos_test_angle)
+ if (cos_xmtr_angle>=cos_test_angle)
block=1;
}
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;
+ field_strength=0.0, rxp, dBm;
struct site temp;
ReadPath(source,destination);
- four_thirds_earth=EARTHRADIUS*(4.0/3.0);
+ four_thirds_earth=FOUR_THIRDS*EARTHRADIUS;
- /* Copy elevations along path into the elev_l[] array. */
+ /* Copy elevations plus clutter along path into the elev[] array. */
- for (x=0; x<path.length; x++)
- elev_l[x+2]=path.elevation[x]*METERS_PER_FOOT;
+ for (x=1; x<path.length-1; x++)
+ elev[x+2]=(path.elevation[x]==0.0?path.elevation[x]*METERS_PER_FOOT:(clutter+path.elevation[x])*METERS_PER_FOOT);
+
+ /* Copy ending points without clutter */
+
+ elev[2]=path.elevation[0]*METERS_PER_FOOT;
+ elev[path.length+1]=path.elevation[path.length-1]*METERS_PER_FOOT;
/* Since the only energy the Longley-Rice model considers
reaching the destination is based on what is scattered
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.) */
+ calculation for overall path loss. */
for (y=2; (y<(path.length-1) && path.distance[y]<=max_range); y++)
{
{
/* 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. */
+ or an output (.ano) 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];
+ test_alt=four_thirds_earth+(path.elevation[x]==0.0?path.elevation[x]:path.elevation[x]+clutter);
/* Calculate the cosine of the elevation
angle of the terrain (test point)
what it would be if the angles themselves
were compared. */
- if (cos_rcvr_angle>cos_test_angle)
+ if (cos_rcvr_angle>=cos_test_angle)
block=1;
}
if (block)
- elevation=((acos(cos_test_angle))/deg2rad)-90.0;
+ elevation=((acos(cos_test_angle))/DEG2RAD)-90.0;
else
- elevation=((acos(cos_rcvr_angle))/deg2rad)-90.0;
+ elevation=((acos(cos_rcvr_angle))/DEG2RAD)-90.0;
}
/* Determine attenuation for each point along the
shortest distance terrain can play a role in
path loss. */
- elev_l[0]=y-1; /* (number of points - 1) */
+ elev[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,
+ elev[1]=METERS_PER_MILE*(path.distance[y]-path.distance[y-1]);
+
+ point_to_point(elev,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,
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);
+ fprintf(fd,"%.7f, %.7f, %.3f, %.3f, ",path.lat[y], path.lon[y], azimuth, elevation);
+
+ /* If ERP==0, write path loss to alphanumeric
+ output file. Otherwise, write field strength
+ or received power level (below), as appropriate. */
+
+ if (fd!=NULL && LR.erp==0.0)
+ fprintf(fd,"%.2f",loss);
/* Integrate the antenna's radiation
pattern into the overall path loss. */
{
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));
+ if (dbm)
+ {
+ /* dBm is based on EIRP (ERP + 2.14) */
- ifs=100+(int)rint(field_strength);
+ rxp=LR.erp/(pow(10.0,(loss-2.14)/10.0));
- if (ifs<0)
- ifs=0;
+ dBm=10.0*(log10(rxp*1000.0));
- if (ifs>255)
- ifs=255;
+ if (fd!=NULL)
+ fprintf(fd,"%.3f",dBm);
- ofs=GetSignal(path.lat[y],path.lon[y]);
+ /* Scale roughly between 0 and 255 */
- if (ofs>ifs)
- ifs=ofs;
+ ifs=200+(int)rint(dBm);
- PutSignal(path.lat[y],path.lon[y],(unsigned char)ifs);
-
- if (fd!=NULL)
- fprintf(fd,", %.3f",field_strength);
+ if (ifs<0)
+ ifs=0;
+
+ if (ifs>255)
+ ifs=255;
+
+ ofs=GetSignal(path.lat[y],path.lon[y]);
+
+ if (ofs>ifs)
+ ifs=ofs;
+
+ PutSignal(path.lat[y],path.lon[y],(unsigned char)ifs);
+ }
+
+ else
+ {
+ field_strength=(139.4+(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 (ifs>255)
+ ifs=255;
+
+ ofs=GetSignal(path.lat[y],path.lon[y]);
+
+ if (ofs>ifs)
+ ifs=ofs;
+
+ PutSignal(path.lat[y],path.lon[y],(unsigned char)ifs);
+
+ if (fd!=NULL)
+ fprintf(fd,"%.3f",field_strength);
+ }
}
else
fprintf(fd,"\n");
}
- /* Mark this point as being analyzed */
+ /* Mark this point as having been analyzed */
- PutMask(path.lat[y],path.lon[y],(GetMask(path.lat[y],path.lon[y])&7)+mask_value<<3);
+ PutMask(path.lat[y],path.lon[y],(GetMask(path.lat[y],path.lon[y])&7)+(mask_value<<3));
}
}
}
-void PlotCoverage(struct site source, double altitude)
+void PlotLOSMap(struct site source, double altitude)
{
/* This function performs a 360 degree sweep around the
transmitter site (source location), and plots the
of a topographic map when the WritePPM() function
is later invoked. */
- float lat, lon, one_pixel;
- static unsigned char mask_value=1;
- int z, count;
+ int y, z, count;
struct site edge;
unsigned char symbol[4], x;
-
- one_pixel=1.0/1200.0;
+ double lat, lon, minwest, maxnorth, th;
+ static unsigned char mask_value=1;
symbol[0]='.';
symbol[1]='o';
count=0;
- 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);
+ fprintf(stdout,"\nComputing line-of-sight coverage of \"%s\" with an RX antenna\nat %.2f %s AGL",source.name,metric?altitude*METERS_PER_FOOT:altitude,metric?"meters":"feet");
+
+ if (clutter>0.0)
+ fprintf(stdout," and %.2f %s of ground clutter",metric?clutter*METERS_PER_FOOT:clutter,metric?"meters":"feet");
+
+ fprintf(stdout,"...\n\n 0%c to 25%c ",37,37);
fflush(stdout);
- /* 18.75=1200 pixels/degree divided by 64 loops
- per progress indicator symbol (.oOo) printed. */
+ /* th=pixels/degree divided by 64 loops per
+ progress indicator symbol (.oOo) printed. */
+
+ th=ppd/64.0;
+
+ z=(int)(th*ReduceAngle(max_west-min_west));
- z=(int)(18.75*ReduceAngle(max_west-min_west));
+ minwest=dpp+(double)min_west;
+ maxnorth=(double)max_north-dpp;
- for (lon=min_west, x=0; (LonDiff(lon,max_west)<=0.0); lon+=one_pixel)
+ for (lon=minwest, x=0, y=0; (LonDiff(lon,(double)max_west)<=0.0); y++, lon=minwest+(dpp*(double)y))
{
if (lon>=360.0)
lon-=360.0;
fprintf(stdout,"\n25%c to 50%c ",37,37);
fflush(stdout);
- z=(int)(18.75*(max_north-min_north));
+ z=(int)(th*(double)(max_north-min_north));
- for (lat=max_north, x=0; lat>=min_north; lat-=one_pixel)
+ for (lat=maxnorth, x=0, y=0; lat>=(double)min_north; y++, lat=maxnorth-(dpp*(double)y))
{
edge.lat=lat;
edge.lon=min_west;
fprintf(stdout,"\n50%c to 75%c ",37,37);
fflush(stdout);
- z=(int)(18.75*ReduceAngle(max_west-min_west));
+ z=(int)(th*ReduceAngle(max_west-min_west));
- for (lon=min_west, x=0; (LonDiff(lon,max_west)<=0.0); lon+=one_pixel)
+ for (lon=minwest, x=0, y=0; (LonDiff(lon,(double)max_west)<=0.0); y++, lon=minwest+(dpp*(double)y))
{
if (lon>=360.0)
lon-=360.0;
fprintf(stdout,"\n75%c to 100%c ",37,37);
fflush(stdout);
- z=(int)(18.75*(max_north-min_north));
+ z=(int)(th*(double)(max_north-min_north));
- for (lat=min_north, x=0; lat<=max_north; lat+=one_pixel)
+ for (lat=(double)min_north, x=0, y=0; lat<(double)max_north; y++, lat=(double)min_north+(dpp*(double)y))
{
edge.lat=lat;
edge.lon=max_west;
of a topographic map when the WritePPMLR() or
WritePPMSS() functions are later invoked. */
- int z, count;
+ int y, z, count;
struct site edge;
- float lat, lon, one_pixel;
+ double lat, lon, minwest, maxnorth, th;
unsigned char x, symbol[4];
static unsigned char mask_value=1;
FILE *fd=NULL;
- one_pixel=1.0/1200.0;
+ minwest=dpp+(double)min_west;
+ maxnorth=(double)max_north-dpp;
symbol[0]='.';
symbol[1]='o';
count=0;
- fprintf(stdout,"\n\nComputing Longley-Rice contours of \"%s\" ", source.name);
+ fprintf(stdout,"\nComputing Longley-Rice ");
+
+ if (LR.erp==0.0)
+ fprintf(stdout,"path loss");
+ else
+ {
+ if (dbm)
+ fprintf(stdout,"signal power level");
+ else
+ fprintf(stdout,"field strength");
+ }
+
+ fprintf(stdout," contours of \"%s\"\nout to a radius of %.2f %s with an RX antenna at %.2f %s AGL",source.name,metric?max_range*KM_PER_MILE:max_range,metric?"kilometers":"miles",metric?altitude*METERS_PER_FOOT:altitude,metric?"meters":"feet");
+
+ if (clutter>0.0)
+ fprintf(stdout,"\nand %.2f %s of ground clutter",metric?clutter*METERS_PER_FOOT:clutter,metric?"meters":"feet");
- 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);
+ fprintf(stdout,"...\n\n 0%c to 25%c ",37,37);
fflush(stdout);
if (plo_filename[0]!=0)
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. */
+ /* th=pixels/degree divided by 64 loops per
+ progress indicator symbol (.oOo) printed. */
+
+ th=ppd/64.0;
- z=(int)(18.75*ReduceAngle(max_west-min_west));
+ z=(int)(th*ReduceAngle(max_west-min_west));
- for (lon=min_west, x=0; (LonDiff(lon,max_west)<=0.0); lon+=one_pixel)
+ for (lon=minwest, x=0, y=0; (LonDiff(lon,(double)max_west)<=0.0); y++, lon=minwest+(dpp*(double)y))
{
if (lon>=360.0)
lon-=360.0;
fprintf(stdout,"\n25%c to 50%c ",37,37);
fflush(stdout);
- z=(int)(18.75*(max_north-min_north));
+ z=(int)(th*(double)(max_north-min_north));
- for (lat=max_north, x=0; lat>=min_north; lat-=one_pixel)
+ for (lat=maxnorth, x=0, y=0; lat>=(double)min_north; y++, lat=maxnorth-(dpp*(double)y))
{
edge.lat=lat;
edge.lon=min_west;
fprintf(stdout,"\n50%c to 75%c ",37,37);
fflush(stdout);
- z=(int)(18.75*ReduceAngle(max_west-min_west));
+ z=(int)(th*ReduceAngle(max_west-min_west));
- for (lon=min_west, x=0; (LonDiff(lon,max_west)<=0.0); lon+=one_pixel)
+ for (lon=minwest, x=0, y=0; (LonDiff(lon,(double)max_west)<=0.0); y++, lon=minwest+(dpp*(double)y))
{
if (lon>=360.0)
lon-=360.0;
fprintf(stdout,"\n75%c to 100%c ",37,37);
fflush(stdout);
- z=(int)(18.75*(max_north-min_north));
+ z=(int)(th*(double)(max_north-min_north));
- for (lat=min_north, x=0; lat<=max_north; lat+=one_pixel)
+ for (lat=(double)min_north, x=0, y=0; lat<(double)max_north; y++, lat=(double)min_north+(dpp*(double)y))
{
edge.lat=lat;
edge.lon=max_west;
void LoadSignalColors(struct site xmtr)
{
int x, y, ok, val[4];
- char filename[255], string[80], *pointer=NULL;
+ char filename[255], string[80], *pointer=NULL, *s=NULL;
FILE *fd=NULL;
for (x=0; xmtr.filename[x]!='.' && xmtr.filename[x]!=0 && x<250; x++)
else
{
x=0;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
while (x<32 && feof(fd)==0)
{
x++;
}
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
}
fclose(fd);
void LoadLossColors(struct site xmtr)
{
int x, y, ok, val[4];
- char filename[255], string[80], *pointer=NULL;
+ char filename[255], string[80], *pointer=NULL, *s=NULL;
FILE *fd=NULL;
for (x=0; xmtr.filename[x]!='.' && xmtr.filename[x]!=0 && x<250; x++)
else
{
x=0;
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
while (x<32 && feof(fd)==0)
{
x++;
}
- fgets(string,80,fd);
+ s=fgets(string,80,fd);
}
fclose(fd);
}
}
-void WritePPM(char *filename, unsigned char geo, unsigned char kml, unsigned char ngs)
+void LoadDBMColors(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, *s=NULL;
+ FILE *fd=NULL;
- 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;
+ 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]='d';
+ 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 */
- if (filename[0]==0)
- strncpy(filename, "map.ppm\0",8);
+ region.level[0]=0;
+ region.color[0][0]=255;
+ region.color[0][1]=0;
+ region.color[0][2]=0;
- for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
- {
- mapfile[x]=filename[x];
- geofile[x]=filename[x];
- kmlfile[x]=filename[x];
- }
+ region.level[1]=-10;
+ region.color[1][0]=255;
+ region.color[1][1]=128;
+ region.color[1][2]=0;
- 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;
+ region.level[2]=-20;
+ region.color[2][0]=255;
+ region.color[2][1]=165;
+ region.color[2][2]=0;
+
+ region.level[3]=-30;
+ region.color[3][0]=255;
+ region.color[3][1]=206;
+ region.color[3][2]=0;
+
+ region.level[4]=-40;
+ region.color[4][0]=255;
+ region.color[4][1]=255;
+ region.color[4][2]=0;
+
+ region.level[5]=-50;
+ region.color[5][0]=184;
+ region.color[5][1]=255;
+ region.color[5][2]=0;
+
+ region.level[6]=-60;
+ region.color[6][0]=0;
+ region.color[6][1]=255;
+ region.color[6][2]=0;
+
+ region.level[7]=-70;
+ region.color[7][0]=0;
+ region.color[7][1]=208;
+ region.color[7][2]=0;
+
+ region.level[8]=-80;
+ region.color[8][0]=0;
+ region.color[8][1]=196;
+ region.color[8][2]=196;
+
+ region.level[9]=-90;
+ region.color[9][0]=0;
+ region.color[9][1]=148;
+ region.color[9][2]=255;
+
+ region.level[10]=-100;
+ region.color[10][0]=80;
+ region.color[10][1]=80;
+ region.color[10][2]=255;
+
+ region.level[11]=-110;
+ region.color[11][0]=0;
+ region.color[11][1]=38;
+ region.color[11][2]=255;
+
+ region.level[12]=-120;
+ region.color[12][0]=142;
+ region.color[12][1]=63;
+ region.color[12][2]=255;
+
+ region.level[13]=-130;
+ region.color[13][0]=196;
+ region.color[13][1]=54;
+ region.color[13][2]=255;
+
+ region.level[14]=-140;
+ region.color[14][0]=255;
+ region.color[14][1]=0;
+ region.color[14][2]=255;
+
+ region.level[15]=-150;
+ region.color[15][0]=255;
+ region.color[15][1]=194;
+ region.color[15][2]=204;
+
+ region.levels=16;
+
+ fd=fopen("splat.dcf","r");
+
+ if (fd==NULL)
+ fd=fopen(filename,"r");
+
+ if (fd==NULL)
+ {
+ fd=fopen(filename,"w");
+
+ fprintf(fd,"; SPLAT! Auto-generated DBM Signal Level Color Definition (\"%s\") File\n",filename);
+ fprintf(fd,";\n; Format for the parameters held in this file is as follows:\n;\n");
+ fprintf(fd,"; dBm: red, green, blue\n;\n");
+ fprintf(fd,"; ...where \"dBm\" is the received signal power level between +40 dBm\n");
+ fprintf(fd,"; and -200 dBm, and \"red\", \"green\", and \"blue\" are the corresponding\n");
+ fprintf(fd,"; RGB color 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,"%+4d: %3d, %3d, %3d\n",region.level[x], region.color[x][0], region.color[x][1], region.color[x][2]);
+
+ fclose(fd);
+ }
+
+ else
+ {
+ x=0;
+ s=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)
+ {
+ if (val[0]<-200)
+ val[0]=-200;
+
+ if (val[0]>+40)
+ val[0]=+40;
+
+ region.level[x]=val[0];
+
+ for (y=1; y<4; y++)
+ {
+ if (val[y]>255)
+ val[y]=255;
+
+ if (val[y]<0)
+ val[y]=0;
+ }
+
+ region.color[x][0]=val[1];
+ region.color[x][1]=val[2];
+ region.color[x][2]=val[3];
+ x++;
+ }
+
+ s=fgets(string,80,fd);
+ }
+
+ fclose(fd);
+ region.levels=x;
+ }
+}
+
+void WritePPM(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 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, conversion, one_over_gamma,
+ north, south, east, west, minwest;
+ FILE *fd;
+
+ one_over_gamma=1.0/GAMMA;
+ conversion=255.0/pow((double)(max_elevation-min_elevation),one_over_gamma);
+
+ width=(unsigned)(ippd*ReduceAngle(max_west-min_west));
+ height=(unsigned)(ippd*ReduceAngle(max_north-min_north));
+
+ if (filename[0]==0)
+ {
+ strncpy(filename, xmtr[0].filename,254);
+ filename[strlen(filename)-4]=0; /* Remove .qth */
+ }
+
+ y=strlen(filename);
+
+ if (y>4)
+ {
+ if (filename[y-1]=='m' && filename[y-2]=='p' && filename[y-3]=='p' && filename[y-4]=='.')
+ y-=4;
+ }
+
+ for (x=0; x<y; 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;
+
+ minwest=((double)min_west)+dpp;
+
+ if (minwest>360.0)
+ minwest-=360.0;
+
+ north=(double)max_north-dpp;
+ south=(double)min_north;
+ east=(minwest<180.0?-minwest:360.0-min_west);
+ west=(double)(max_west<180?-max_west:360-max_west);
if (kml==0 && geo)
{
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,"TIEPOINT\t0\t0\t%.3f\t\t%.3f\n",west,north);
+ fprintf(fd,"TIEPOINT\t%u\t%u\t%.3f\t\t%.3f\n",width-1,height-1,east,south);
fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height);
- fprintf(fd,"#\n# Auto Generated by SPLAT! v%s\n#\n",splat_version);
+ fprintf(fd,"#\n# Auto Generated by %s v%s\n#\n",splat_name,splat_version);
fclose(fd);
}
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," <name>%s</name>\n",splat_name);
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," <name>%s Line-of-Sight Overlay</name>\n",splat_name);
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," <north>%.5f</north>\n",north);
+ fprintf(fd," <south>%.5f</south>\n",south);
+ fprintf(fd," <east>%.5f</east>\n",east);
+ fprintf(fd," <west>%.5f</west>\n",west);
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(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 (y=0, lat=north; y<(int)height; y++, lat=north-(dpp*(double)y))
{
- for (x=0, lon=(double)max_west-one_pixel; x<(int)width; x++, lon=(double)max_west-(one_pixel*(double)x))
+ for (x=0, lon=max_west; x<(int)width; x++, lon=(double)max_west-(dpp*(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)
+ {
+ x0=(int)rint(ppd*(lat-(double)dem[indx].min_north));
+ y0=mpi-(int)rint(ppd*(LonDiff((double)dem[indx].max_west,lon)));
+
+ if (x0>=0 && x0<=mpi && y0>=0 && y0<=mpi)
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];
if (mask&2)
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;
+ char mapfile[255], geofile[255], kmlfile[255];
unsigned width, height, red, green, blue, terrain=0;
unsigned char found, mask, cityorcounty;
int indx, x, y, z, colorwidth, x0, y0, loss, level,
hundreds, tens, units, match;
- double lat, lon, one_pixel, conversion, one_over_gamma;
+ double lat, lon, conversion, one_over_gamma,
+ north, south, east, west, minwest;
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));
+ width=(unsigned)(ippd*ReduceAngle(max_west-min_west));
+ height=(unsigned)(ippd*ReduceAngle(max_north-min_north));
LoadLossColors(xmtr[0]);
if (filename[0]==0)
+ {
strncpy(filename, xmtr[0].filename,254);
+ filename[strlen(filename)-4]=0; /* Remove .qth */
+ }
- for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
+ y=strlen(filename);
+
+ if (y>4)
+ {
+ if (filename[y-1]=='m' && filename[y-2]=='p' && filename[y-3]=='p' && filename[y-4]=='.')
+ y-=4;
+ }
+
+ for (x=0; x<y; x++)
{
mapfile[x]=filename[x];
geofile[x]=filename[x];
geofile[x+4]=0;
kmlfile[x+4]=0;
+ minwest=((double)min_west)+dpp;
+
+ if (minwest>360.0)
+ minwest-=360.0;
+
+ north=(double)max_north-dpp;
+
+ if (kml || geo)
+ south=(double)min_north; /* No bottom legend */
+ else
+ south=(double)min_north-(30.0/ppd); /* 30 pixels for bottom legend */
+
+ east=(minwest<180.0?-minwest:360.0-min_west);
+ west=(double)(max_west<180?-max_west:360-max_west);
+
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);
+ fprintf(fd,"TIEPOINT\t0\t0\t%.3f\t\t%.3f\n",west,north);
+
+ fprintf(fd,"TIEPOINT\t%u\t%u\t%.3f\t\t%.3f\n",width-1,height-1,east,south);
+ fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height);
+
+ fprintf(fd,"#\n# Auto Generated by %s v%s\n#\n",splat_name,splat_version);
fclose(fd);
}
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,"<!-- Generated by %s Version %s -->\n",splat_name,splat_version);
fprintf(fd," <Folder>\n");
- fprintf(fd," <name>SPLAT!</name>\n");
+ fprintf(fd," <name>%s</name>\n",splat_name);
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," </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," <north>%.5f</north>\n",north);
+ fprintf(fd," <south>%.5f</south>\n",south);
+ fprintf(fd," <east>%.5f</east>\n",east);
+ fprintf(fd," <west>%.5f</west>\n",west);
fprintf(fd," <rotation>0.0</rotation>\n");
fprintf(fd," </LatLonBox>\n");
fprintf(fd," </GroundOverlay>\n");
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 (y=0, lat=north; y<(int)height; y++, lat=north-(dpp*(double)y))
{
- for (x=0, lon=(double)max_west-one_pixel; x<(int)width; x++, lon=(double)max_west-(one_pixel*(double)x))
+ for (x=0, lon=max_west; x<(int)width; x++, lon=max_west-(dpp*(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)
+ {
+ x0=(int)rint(ppd*(lat-(double)dem[indx].min_north));
+ y0=mpi-(int)rint(ppd*(LonDiff((double)dem[indx].max_west,lon)));
+
+ if (x0>=0 && x0<=mpi && y0>=0 && y0<=mpi)
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=(dem[indx].signal[x0][y0]);
cityorcounty=0;
red=region.color[match][0];
green=region.color[match][1];
blue=region.color[match][2];
-
- color=1;
}
- if ((mask&2) && (kml==0))
+ if (mask&2)
{
/* Text Labels: Red or otherwise */
cityorcounty=1;
}
- else if ((mask&4) && (kml==0))
+ else if (mask&4)
{
/* County Boundaries: Black */
if (cityorcounty==0)
{
- if (loss>maxdB || loss==0)
+ if (loss==0 || (contour_threshold!=0 && loss>abs(contour_threshold)))
{
if (ngs) /* No terrain */
fprintf(fd,"%c%c%c",255,255,255);
}
}
- if (kml==0 && color)
+ if (kml==0 && geo==0)
{
- /* Display legend along bottom of image */
+ /* Display legend along bottom of image
+ * if not generating .kml or .geo output.
+ */
colorwidth=(int)rint((float)width/(float)region.levels);
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;
+ char mapfile[255], geofile[255], kmlfile[255];
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;
+ double conversion, one_over_gamma, lat, lon,
+ north, south, east, west, minwest;
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));
+ width=(unsigned)(ippd*ReduceAngle(max_west-min_west));
+ height=(unsigned)(ippd*ReduceAngle(max_north-min_north));
LoadSignalColors(xmtr[0]);
if (filename[0]==0)
+ {
strncpy(filename, xmtr[0].filename,254);
+ filename[strlen(filename)-4]=0; /* Remove .qth */
+ }
- for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
+ y=strlen(filename);
+
+ if (y>4)
+ {
+ if (filename[y-1]=='m' && filename[y-2]=='p' && filename[y-3]=='p' && filename[y-4]=='.')
+ y-=4;
+ }
+
+ for (x=0; x<y; x++)
{
mapfile[x]=filename[x];
geofile[x]=filename[x];
geofile[x+4]=0;
kmlfile[x+4]=0;
+ minwest=((double)min_west)+dpp;
+
+ if (minwest>360.0)
+ minwest-=360.0;
+
+ north=(double)max_north-dpp;
+
+ if (kml || geo)
+ south=(double)min_north; /* No bottom legend */
+ else
+ south=(double)min_north-(30.0/ppd); /* 30 pixels for bottom legend */
+
+ east=(minwest<180.0?-minwest:360.0-min_west);
+ west=(double)(max_west<180?-max_west:360-max_west);
+
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);
+ fprintf(fd,"TIEPOINT\t0\t0\t%.3f\t\t%.3f\n",west,north);
+
+ fprintf(fd,"TIEPOINT\t%u\t%u\t%.3f\t\t%.3f\n",width-1,height-1,east,south);
+ fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height);
+
+ fprintf(fd,"#\n# Auto Generated by %s v%s\n#\n",splat_name,splat_version);
fclose(fd);
}
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,"<!-- Generated by %s Version %s -->\n",splat_name,splat_version);
fprintf(fd," <Folder>\n");
- fprintf(fd," <name>SPLAT!</name>\n");
+ fprintf(fd," <name>%s</name>\n",splat_name);
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," </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," <north>%.5f</north>\n",north);
+ fprintf(fd," <south>%.5f</south>\n",south);
+ fprintf(fd," <east>%.5f</east>\n",east);
+ fprintf(fd," <west>%.5f</west>\n",west);
fprintf(fd," <rotation>0.0</rotation>\n");
fprintf(fd," </LatLonBox>\n");
fprintf(fd," </GroundOverlay>\n");
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 (y=0, lat=north; y<(int)height; y++, lat=north-(dpp*(double)y))
{
- for (x=0, lon=(double)max_west-one_pixel; x<(int)width; x++, lon=(double)max_west-(one_pixel*(double)x))
+ for (x=0, lon=max_west; x<(int)width; x++, lon=max_west-(dpp*(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)
+ {
+ x0=(int)rint(ppd*(lat-(double)dem[indx].min_north));
+ y0=mpi-(int)rint(ppd*(LonDiff((double)dem[indx].max_west,lon)));
+
+ if (x0>=0 && x0<=mpi && y0>=0 && y0<=mpi)
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;
red=region.color[match][0];
green=region.color[match][1];
blue=region.color[match][2];
-
- color=1;
}
- if ((mask&2) && (kml==0))
+ if (mask&2)
{
/* Text Labels: Red or otherwise */
cityorcounty=1;
}
- else if ((mask&4) && (kml==0))
+ else if (mask&4)
{
/* County Boundaries: Black */
if (cityorcounty==0)
{
- if (dem[indx].signal[x0][y0]==0)
+ if (contour_threshold!=0 && signal<contour_threshold)
{
if (ngs)
fprintf(fd,"%c%c%c",255,255,255);
}
}
- if (kml==0 && color)
+ if (kml==0 && geo==0)
{
- /* Display legend along bottom of image */
+ /* Display legend along bottom of image
+ * if not generating .kml or .geo output.
+ */
colorwidth=(int)rint((float)width/(float)region.levels);
indx=255;
if (x>=52 && x<=59)
- if (fontdata[16*('u')+(y0-8)]&(128>>(x-52)))
+ if (fontdata[16*(230)+(y0-8)]&(128>>(x-52)))
indx=255;
if (x>=60 && x<=67)
fflush(stdout);
}
-void GraphTerrain(struct site source, struct site destination, char *name)
+void WritePPMDBM(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
- is used to set gnuplot's terminal setting and output file type.
- If no extension is found, .png is assumed. */
+ /* This function generates a topographic map in Portable Pix Map
+ (PPM) format based on the signal power level 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. */
- int x, y, z;
- char filename[255], term[30], ext[15];
- FILE *fd=NULL;
+ char mapfile[255], geofile[255], kmlfile[255];
+ unsigned width, height, terrain, red, green, blue;
+ unsigned char found, mask, cityorcounty;
+ int indx, x, y, z=1, x0, y0, dBm, level, hundreds,
+ tens, units, match, colorwidth;
+ double conversion, one_over_gamma, lat, lon,
+ north, south, east, west, minwest;
+ FILE *fd;
+
+ one_over_gamma=1.0/GAMMA;
+ conversion=255.0/pow((double)(max_elevation-min_elevation),one_over_gamma);
+
+ width=(unsigned)(ippd*ReduceAngle(max_west-min_west));
+ height=(unsigned)(ippd*ReduceAngle(max_north-min_north));
+
+ LoadDBMColors(xmtr[0]);
+
+ if (filename[0]==0)
+ {
+ strncpy(filename, xmtr[0].filename,254);
+ filename[strlen(filename)-4]=0; /* Remove .qth */
+ }
+
+ y=strlen(filename);
+
+ if (y>4)
+ {
+ if (filename[y-1]=='m' && filename[y-2]=='p' && filename[y-3]=='p' && filename[y-4]=='.')
+ y-=4;
+ }
+
+ for (x=0; x<y; 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;
+
+ minwest=((double)min_west)+dpp;
+
+ if (minwest>360.0)
+ minwest-=360.0;
+
+ north=(double)max_north-dpp;
+
+ if (kml || geo)
+ south=(double)min_north; /* No bottom legend */
+ else
+ south=(double)min_north-(30.0/ppd); /* 30 pixels for bottom legend */
+
+ east=(minwest<180.0?-minwest:360.0-min_west);
+ west=(double)(max_west<180?-max_west:360-max_west);
+
+ 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%.3f\t\t%.3f\n",west,north);
+
+ fprintf(fd,"TIEPOINT\t%u\t%u\t%.3f\t\t%.3f\n",width-1,height-1,east,south);
+ fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height);
+
+ fprintf(fd,"#\n# Auto Generated by %s v%s\n#\n",splat_name,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 %s Version %s -->\n",splat_name,splat_version);
+ fprintf(fd," <Folder>\n");
+ fprintf(fd," <name>%s</name>\n",splat_name);
+ fprintf(fd," <description>%s Transmitter Coverage Overlay</description>\n",xmtr[0].name);
+ fprintf(fd," <GroundOverlay>\n");
+ fprintf(fd," <name>SPLAT! Signal Power Level 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",north);
+ fprintf(fd," <south>%.5f</south>\n",south);
+ fprintf(fd," <east>%.5f</east>\n",east);
+ fprintf(fd," <west>%.5f</west>\n",west);
+ 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=north; y<(int)height; y++, lat=north-(dpp*(double)y))
+ {
+ for (x=0, lon=max_west; x<(int)width; x++, lon=max_west-(dpp*(double)x))
+ {
+ if (lon<0.0)
+ lon+=360.0;
+
+ for (indx=0, found=0; indx<MAXPAGES && found==0;)
+ {
+ x0=(int)rint(ppd*(lat-(double)dem[indx].min_north));
+ y0=mpi-(int)rint(ppd*(LonDiff((double)dem[indx].max_west,lon)));
+
+ if (x0>=0 && x0<=mpi && y0>=0 && y0<=mpi)
+ found=1;
+ else
+ indx++;
+ }
+
+ if (found)
+ {
+ mask=dem[indx].mask[x0][y0];
+ dBm=(dem[indx].signal[x0][y0])-200;
+ cityorcounty=0;
+
+ match=255;
+
+ red=0;
+ green=0;
+ blue=0;
+
+ if (dBm>=region.level[0])
+ match=0;
+ else
+ {
+ for (z=1; (z<region.levels && match==255); z++)
+ {
+ if (dBm<region.level[z-1] && dBm>=region.level[z])
+ match=z;
+ }
+ }
+
+ if (match<region.levels)
+ {
+ red=region.color[match][0];
+ green=region.color[match][1];
+ blue=region.color[match][2];
+ }
+
+ if (mask&2)
+ {
+ /* Text Labels: Red or otherwise */
+
+ if (red>=180 && green<=75 && blue<=75 && dBm!=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)
+ {
+ /* County Boundaries: Black */
+
+ fprintf(fd,"%c%c%c",0,0,0);
+
+ cityorcounty=1;
+ }
+
+ if (cityorcounty==0)
+ {
+ if (contour_threshold!=0 && dBm<contour_threshold)
+ {
+ if (ngs) /* No terrain */
+ 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 signal power level 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 && geo==0)
+ {
+ /* Display legend along bottom of image
+ if not generating .kml or .geo output. */
+
+ 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=abs(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 (region.level[indx]<0)
+ {
+ if (x>=5 && x<=12)
+ if (fontdata[16*('-')+(y0-8)]&(128>>(x-5)))
+ indx=255;
+ }
+
+ else
+ {
+ if (x>=5 && x<=12)
+ if (fontdata[16*('+')+(y0-8)]&(128>>(x-5)))
+ indx=255;
+ }
+
+ if (x>=13 && x<=20)
+ if (fontdata[16*(hundreds+'0')+(y0-8)]&(128>>(x-13)))
+ indx=255;
+ }
+
+ if (tens>0 || hundreds>0)
+ {
+ if (hundreds==0)
+ {
+ if (region.level[indx]<0)
+ {
+ if (x>=13 && x<=20)
+ if (fontdata[16*('-')+(y0-8)]&(128>>(x-13)))
+ indx=255;
+ }
+
+ else
+ {
+ if (x>=13 && x<=20)
+ if (fontdata[16*('+')+(y0-8)]&(128>>(x-13)))
+ indx=255;
+ }
+ }
+
+ if (x>=21 && x<=28)
+ if (fontdata[16*(tens+'0')+(y0-8)]&(128>>(x-21)))
+ indx=255;
+ }
+
+ if (hundreds==0 && tens==0)
+ {
+ if (region.level[indx]<0)
+ {
+ if (x>=21 && x<=28)
+ if (fontdata[16*('-')+(y0-8)]&(128>>(x-21)))
+ indx=255;
+ }
+
+ else
+ {
+ if (x>=21 && x<=28)
+ if (fontdata[16*('+')+(y0-8)]&(128>>(x-21)))
+ indx=255;
+ }
+ }
+
+ if (x>=29 && x<=36)
+ if (fontdata[16*(units+'0')+(y0-8)]&(128>>(x-29)))
+ indx=255;
+
+ if (x>=37 && x<=44)
+ if (fontdata[16*('d')+(y0-8)]&(128>>(x-37)))
+ indx=255;
+
+ if (x>=45 && x<=52)
+ if (fontdata[16*('B')+(y0-8)]&(128>>(x-45)))
+ indx=255;
+
+ if (x>=53 && x<=60)
+ if (fontdata[16*('m')+(y0-8)]&(128>>(x-53)))
+ 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 when the -p command line option
+ is used. "basename" 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 basename[255], term[30], ext[15];
+ double minheight=100000.0, maxheight=-100000.0;
+ FILE *fd=NULL, *fd1=NULL;
ReadPath(destination,source);
fd=fopen("profile.gp","wb");
+ if (clutter>0.0)
+ fd1=fopen("clutter.gp","wb");
+
for (x=0; x<path.length; x++)
{
+ if ((path.elevation[x]+clutter)>maxheight)
+ maxheight=path.elevation[x]+clutter;
+
+ if (path.elevation[x]<minheight)
+ minheight=path.elevation[x];
+
if (metric)
+ {
fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*path.elevation[x]);
+
+ if (fd1!=NULL && x>0 && x<path.length-2)
+ fprintf(fd1,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*(path.elevation[x]==0.0?path.elevation[x]:(path.elevation[x]+clutter)));
+ }
+
else
+ {
fprintf(fd,"%f\t%f\n",path.distance[x],path.elevation[x]);
+
+ if (fd1!=NULL && x>0 && x<path.length-2)
+ fprintf(fd1,"%f\t%f\n",path.distance[x],(path.elevation[x]==0.0?path.elevation[x]:(path.elevation[x]+clutter)));
+ }
}
fclose(fd);
- if (name[0]==0)
+ if (fd1!=NULL)
+ fclose(fd1);
+
+ if (name[0]=='.')
{
/* Default filename and output file type */
- strncpy(filename,"profile\0",8);
+ strncpy(basename,"profile\0",8);
strncpy(term,"png\0",4);
strncpy(ext,"png\0",4);
}
else
{
- /* Grab extension and terminal type from "name" */
+ /* Extract extension and terminal type from "name" */
- for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
- filename[x]=name[x];
+ ext[0]=0;
+ y=strlen(name);
+ strncpy(basename,name,254);
- if (name[x]=='.')
+ for (x=y-1; x>0 && name[x]!='.'; x--);
+
+ if (x>0) /* Extension found */
{
- for (y=0, z=x, x++; name[x]!=0 && x<254 && y<14; x++, y++)
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
{
- term[y]=tolower(name[x]);
- ext[y]=term[y];
+ ext[z-(x+1)]=tolower(name[z]);
+ term[z-(x+1)]=name[z];
}
- ext[y]=0;
- term[y]=0;
- filename[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ term[z-(x+1)]=0;
+ basename[x]=0;
}
- else
- { /* No extension -- Default is png */
-
- filename[x]=0;
+ if (ext[0]==0) /* No extension -- Default is png */
+ {
strncpy(term,"png\0",4);
strncpy(ext,"png\0",4);
}
strncpy(ext,"ps\0",3);
else if (strncmp(ext,"ps",2)==0)
- strncpy(term,"postscript enhanced color\0",26);
+ strncpy(term,"postscript enhanced color\0",26);
+
+ minheight-=(0.01*maxheight);
fd=fopen("splat.gp","w");
fprintf(fd,"set grid\n");
- fprintf(fd,"set autoscale\n");
+ fprintf(fd,"set yrange [%2.3f to %2.3f]\n", metric?minheight*METERS_PER_FOOT:minheight, metric?maxheight*METERS_PER_FOOT:maxheight);
fprintf(fd,"set encoding iso_8859_1\n");
fprintf(fd,"set term %s\n",term);
- fprintf(fd,"set title \"SPLAT! Terrain Profile Between %s and %s (%.2f%c Azimuth)\"\n",destination.name, source.name, Azimuth(destination,source),176);
+ fprintf(fd,"set title \"%s Terrain Profile Between %s and %s (%.2f%c Azimuth)\"\n",splat_name,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 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");
+ fprintf(fd,"set output \"%s.%s\"\n",basename,ext);
+
+ if (clutter>0.0)
+ {
+ if (metric)
+ fprintf(fd,"plot \"profile.gp\" title \"Terrain Profile\" with lines, \"clutter.gp\" title \"Clutter Profile (%.2f meters)\" with lines\n",clutter*METERS_PER_FOOT);
+ else
+ fprintf(fd,"plot \"profile.gp\" title \"Terrain Profile\" with lines, \"clutter.gp\" title \"Clutter Profile (%.2f feet)\" with lines\n",clutter);
+ }
+
+ else
+ fprintf(fd,"plot \"profile.gp\" title \"\" with lines\n");
+
fclose(fd);
x=system("gnuplot splat.gp");
if (x!=-1)
{
- unlink("splat.gp");
- unlink("profile.gp");
+ if (gpsav==0)
+ {
+ unlink("splat.gp");
+ unlink("profile.gp");
+ }
- fprintf(stdout,"\nTerrain plot written to: \"%s.%s\"",filename,ext);
+ fprintf(stdout,"Terrain plot written to: \"%s.%s\"\n",basename,ext);
fflush(stdout);
}
void GraphElevation(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, .png is assumed. */
+ output file indicating the terrain elevation profile between
+ the source and destination locations when the -e command line
+ option is used. "basename" 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 angle, refangle, maxangle=-90.0;
- struct site remote;
- FILE *fd=NULL, *fd2=NULL;
+ char basename[255], term[30], ext[15];
+ double angle, clutter_angle=0.0, refangle, maxangle=-90.0,
+ minangle=90.0, distance;
+ struct site remote, remote2;
+ FILE *fd=NULL, *fd1=NULL, *fd2=NULL;
ReadPath(destination,source); /* destination=RX, source=TX */
refangle=ElevationAngle(destination,source);
+ distance=Distance(source,destination);
fd=fopen("profile.gp","wb");
+
+ if (clutter>0.0)
+ fd1=fopen("clutter.gp","wb");
+
fd2=fopen("reference.gp","wb");
for (x=1; x<path.length-1; x++)
remote.alt=0.0;
angle=ElevationAngle(destination,remote);
+ if (clutter>0.0)
+ {
+ remote2.lat=path.lat[x];
+ remote2.lon=path.lon[x];
+
+ if (path.elevation[x]!=0.0)
+ remote2.alt=clutter;
+ else
+ remote2.alt=0.0;
+
+ clutter_angle=ElevationAngle(destination,remote2);
+ }
+
if (metric)
{
fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[x],angle);
+
+ if (fd1!=NULL)
+ fprintf(fd1,"%f\t%f\n",KM_PER_MILE*path.distance[x],clutter_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);
+
+ if (fd1!=NULL)
+ fprintf(fd1,"%f\t%f\n",path.distance[x],clutter_angle);
+
fprintf(fd2,"%f\t%f\n",path.distance[x],refangle);
}
if (angle>maxangle)
maxangle=angle;
+
+ if (clutter_angle>maxangle)
+ maxangle=clutter_angle;
+
+ if (angle<minangle)
+ minangle=angle;
}
if (metric)
}
fclose(fd);
+
+ if (fd1!=NULL)
+ fclose(fd1);
+
fclose(fd2);
- if (name[0]==0)
+ if (name[0]=='.')
{
/* Default filename and output file type */
- strncpy(filename,"profile\0",8);
+ strncpy(basename,"profile\0",8);
strncpy(term,"png\0",4);
strncpy(ext,"png\0",4);
}
else
{
- /* Grab extension and terminal type from "name" */
+ /* Extract extension and terminal type from "name" */
- for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
- filename[x]=name[x];
+ ext[0]=0;
+ y=strlen(name);
+ strncpy(basename,name,254);
- if (name[x]=='.')
+ for (x=y-1; x>0 && name[x]!='.'; x--);
+
+ if (x>0) /* Extension found */
{
- for (y=0, z=x, x++; name[x]!=0 && x<254 && y<14; x++, y++)
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
{
- term[y]=tolower(name[x]);
- ext[y]=term[y];
+ ext[z-(x+1)]=tolower(name[z]);
+ term[z-(x+1)]=name[z];
}
- ext[y]=0;
- term[y]=0;
- filename[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ term[z-(x+1)]=0;
+ basename[x]=0;
}
- else
- { /* No extension -- Default is png */
-
- filename[x]=0;
+ if (ext[0]==0) /* No extension -- Default is png */
+ {
strncpy(term,"png\0",4);
strncpy(ext,"png\0",4);
}
strncpy(ext,"ps\0",3);
else if (strncmp(ext,"ps",2)==0)
- strncpy(term,"postscript enhanced color\0",26);
+ 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);
+
+ if (distance>2.0)
+ fprintf(fd,"set yrange [%2.3f to %2.3f]\n", (-fabs(refangle)-0.25), maxangle+0.25);
+ else
+ fprintf(fd,"set yrange [%2.3f to %2.3f]\n", minangle, refangle+(-minangle/8.0));
+
fprintf(fd,"set encoding iso_8859_1\n");
fprintf(fd,"set term %s\n",term);
- fprintf(fd,"set title \"SPLAT! Elevation Profile Between %s and %s (%.2f%c azimuth)\"\n",destination.name,source.name,Azimuth(destination,source),176);
+ fprintf(fd,"set title \"%s Elevation Profile Between %s and %s (%.2f%c azimuth)\"\n",splat_name,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 xlabel \"Distance Between %s and %s (%.2f kilometers)\"\n",destination.name,source.name,KM_PER_MILE*distance);
else
- fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f miles)\"\n",destination.name,source.name,Distance(source,destination));
+ fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f miles)\"\n",destination.name,source.name,distance);
- 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 (%.2f%c elevation)\" with lines\n",refangle,176);
+ fprintf(fd,"set ylabel \"Elevation Angle Along LOS Path Between\\n%s and %s (degrees)\"\n",destination.name,source.name);
+ fprintf(fd,"set output \"%s.%s\"\n",basename,ext);
+
+ if (clutter>0.0)
+ {
+ if (metric)
+ fprintf(fd,"plot \"profile.gp\" title \"Real Earth Profile\" with lines, \"clutter.gp\" title \"Clutter Profile (%.2f meters)\" with lines, \"reference.gp\" title \"Line of Sight Path (%.2f%c elevation)\" with lines\n",clutter*METERS_PER_FOOT,refangle,176);
+ else
+ fprintf(fd,"plot \"profile.gp\" title \"Real Earth Profile\" with lines, \"clutter.gp\" title \"Clutter Profile (%.2f feet)\" with lines, \"reference.gp\" title \"Line of Sight Path (%.2f%c elevation)\" with lines\n",clutter,refangle,176);
+ }
+
+ else
+ 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);
if (x!=-1)
{
- unlink("splat.gp");
- unlink("profile.gp");
- unlink("reference.gp");
+ if (gpsav==0)
+ {
+ unlink("splat.gp");
+ unlink("profile.gp");
+ unlink("reference.gp");
+
+ if (clutter>0.0)
+ unlink("clutter.gp");
+ }
- fprintf(stdout,"\nElevation plot written to: \"%s.%s\"",filename,ext);
+ fprintf(stdout,"Elevation plot written to: \"%s.%s\"\n",basename,ext);
fflush(stdout);
}
fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n");
}
-void GraphHeight(struct site source, struct site destination, char *name, double f, unsigned char n)
+void GraphHeight(struct site source, struct site destination, char *name, unsigned char fresnel_plot, unsigned char normalized)
{
/* This function invokes gnuplot to generate an appropriate
- output file indicating the terrain profile between the source
- 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. */
+ output file indicating the terrain height profile between
+ the source and destination locations referenced to the
+ line-of-sight path between the receive and transmit sites
+ when the -h or -H command line option is used. "basename"
+ 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];
+ char basename[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;
+ FILE *fd=NULL, *fd1=NULL, *fd2=NULL, *fd3=NULL, *fd4=NULL, *fd5=NULL;
ReadPath(destination,source); /* destination=RX, source=TX */
azimuth=Azimuth(destination,source);
/* Wavelength and path distance (great circle) in feet. */
- if (f)
+ if (fresnel_plot)
{
- lambda=9.8425e8/(f*1e6);
+ lambda=9.8425e8/(LR.frq_mhz*1e6);
d=5280.0*path.distance[path.length-1];
}
- if (n)
+ if (normalized)
{
ed=GetElevation(destination);
es=GetElevation(source);
}
fd=fopen("profile.gp","wb");
+
+ if (clutter>0.0)
+ fd1=fopen("clutter.gp","wb");
+
fd2=fopen("reference.gp","wb");
fd5=fopen("curvature.gp", "wb");
- if (f)
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
{
fd3=fopen("fresnel.gp", "wb");
fd4=fopen("fresnel_pt_6.gp", "wb");
a=terrain+earthradius;
cangle=5280.0*Distance(destination,remote)/earthradius;
- c=b*sin(refangle*deg2rad+HALFPI)/sin(HALFPI-refangle*deg2rad-cangle);
+ c=b*sin(refangle*DEG2RAD+HALFPI)/sin(HALFPI-refangle*DEG2RAD-cangle);
height=a-c;
* path to the first Fresnel zone boundary.
*/
- if (f)
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
{
d1=5280.0*path.distance[x];
f_zone=-1.0*sqrt(lambda*d1*(d-d1)/d);
fpt6_zone=f_zone*fzone_clearance;
}
- if (n)
+ if (normalized)
{
r=-(nm*path.distance[x])-nb;
height+=r;
- if (f>0)
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
{
f_zone+=r;
fpt6_zone+=r;
if (metric)
{
fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*height);
+
+ if (fd1!=NULL && x>0 && x<path.length-2)
+ fprintf(fd1,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*(terrain==0.0?height:(height+clutter)));
+
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);
+
+ if (fd1!=NULL && x>0 && x<path.length-2)
+ fprintf(fd1,"%f\t%f\n",path.distance[x],(terrain==0.0?height:(height+clutter)));
+
fprintf(fd2,"%f\t%f\n",path.distance[x],r);
fprintf(fd5,"%f\t%f\n",path.distance[x],height-terrain);
}
- if (f)
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
{
if (metric)
{
minheight=f_zone;
}
- if (height>maxheight)
- maxheight=height;
+ if ((height+clutter)>maxheight)
+ maxheight=height+clutter;
if (height<minheight)
minheight=height;
minearth=height-terrain;
}
- if (n)
+ if (normalized)
r=-(nm*path.distance[path.length-1])-nb;
else
r=0.0;
fprintf(fd2,"%f\t%f\n",path.distance[path.length-1],r);
}
- if (f)
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
{
if (metric)
{
minheight=r;
fclose(fd);
+
+ if (fd1!=NULL)
+ fclose(fd1);
+
fclose(fd2);
fclose(fd5);
- if (f)
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
{
fclose(fd3);
fclose(fd4);
}
- if (name[0]==0)
+ if (name[0]=='.')
{
/* Default filename and output file type */
- strncpy(filename,"height\0",8);
+ strncpy(basename,"profile\0",8);
strncpy(term,"png\0",4);
strncpy(ext,"png\0",4);
}
else
{
- /* Grab extension and terminal type from "name" */
+ /* Extract extension and terminal type from "name" */
- for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
- filename[x]=name[x];
+ ext[0]=0;
+ y=strlen(name);
+ strncpy(basename,name,254);
- if (name[x]=='.')
+ for (x=y-1; x>0 && name[x]!='.'; x--);
+
+ if (x>0) /* Extension found */
{
- for (y=0, z=x, x++; name[x]!=0 && x<254 && y<14; x++, y++)
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
{
- term[y]=tolower(name[x]);
- ext[y]=term[y];
+ ext[z-(x+1)]=tolower(name[z]);
+ term[z-(x+1)]=name[z];
}
- ext[y]=0;
- term[y]=0;
- filename[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ term[z-(x+1)]=0;
+ basename[x]=0;
}
- else
- { /* No extension -- Default is png */
-
- filename[x]=0;
+ if (ext[0]==0) /* No extension -- Default is png */
+ {
strncpy(term,"png\0",4);
strncpy(ext,"png\0",4);
}
strncpy(ext,"ps\0",3);
else if (strncmp(ext,"ps",2)==0)
- strncpy(term,"postscript enhanced color\0",26);
+ strncpy(term,"postscript enhanced color\0",26);
fd=fopen("splat.gp","w");
fprintf(fd,"set encoding iso_8859_1\n");
fprintf(fd,"set term %s\n",term);
- 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);
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
+ fprintf(fd,"set title \"%s Path Profile Between %s and %s (%.2f%c azimuth)\\nWith First Fresnel Zone\"\n",splat_name, 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);
+ fprintf(fd,"set title \"%s Height Profile Between %s and %s (%.2f%c azimuth)\"\n",splat_name, 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 (normalized)
{
if (metric)
fprintf(fd,"set ylabel \"Normalized Height Referenced To LOS Path Between\\n%s and %s (meters)\"\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);
+ fprintf(fd,"set ylabel \"Height Referenced To LOS Path Between\\n%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 ylabel \"Height Referenced To LOS Path Between\\n%s and %s (feet)\"\n",destination.name,source.name);
}
- fprintf(fd,"set output \"%s.%s\"\n",filename,ext);
+ fprintf(fd,"set output \"%s.%s\"\n",basename,ext);
- 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);
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
+ {
+ if (clutter>0.0)
+ {
+ if (metric)
+ fprintf(fd,"plot \"profile.gp\" title \"Point-to-Point Profile\" with lines, \"clutter.gp\" title \"Ground Clutter (%.2f meters)\" 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",clutter*METERS_PER_FOOT,LR.frq_mhz,fzone_clearance*100.0);
+ else
+ fprintf(fd,"plot \"profile.gp\" title \"Point-to-Point Profile\" with lines, \"clutter.gp\" title \"Ground Clutter (%.2f feet)\" 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",clutter,LR.frq_mhz,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, \"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",LR.frq_mhz,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");
+ {
+ if (clutter>0.0)
+ {
+ if (metric)
+ fprintf(fd,"plot \"profile.gp\" title \"Point-to-Point Profile\" with lines, \"clutter.gp\" title \"Ground Clutter (%.2f meters)\" with lines, \"reference.gp\" title \"Line Of Sight Path\" with lines, \"curvature.gp\" axes x1y2 title \"Earth's Curvature Contour\" with lines\n",clutter*METERS_PER_FOOT);
+ else
+ fprintf(fd,"plot \"profile.gp\" title \"Point-to-Point Profile\" with lines, \"clutter.gp\" title \"Ground Clutter (%.2f feet)\" with lines, \"reference.gp\" title \"Line Of Sight Path\" with lines, \"curvature.gp\" axes x1y2 title \"Earth's Curvature Contour\" with lines\n",clutter);
+ }
+
+ 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);
if (x!=-1)
{
- unlink("splat.gp");
- unlink("profile.gp");
- unlink("reference.gp");
- unlink("curvature.gp");
-
- if (f)
+ if (gpsav==0)
{
- unlink("fresnel.gp");
- unlink("fresnel_pt_6.gp");
+ unlink("splat.gp");
+ unlink("profile.gp");
+ unlink("reference.gp");
+ unlink("curvature.gp");
+
+ if (fd1!=NULL)
+ unlink("clutter.gp");
+
+ if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot)
+ {
+ unlink("fresnel.gp");
+ unlink("fresnel_pt_6.gp");
+ }
}
- fprintf(stdout,"\nHeight plot written to: \"%s.%s\"",filename,ext);
+ fprintf(stdout,"\nHeight plot written to: \"%s.%s\"",basename,ext);
fflush(stdout);
}
if (f)
lambda=9.8425e8/(f*1e6);
+ if (clutter>0.0)
+ {
+ fprintf(outfile,"Terrain has been raised by");
+
+ if (metric)
+ fprintf(outfile," %.2f meters",METERS_PER_FOOT*clutter);
+ else
+ fprintf(outfile," %.2f feet",clutter);
+
+ fprintf(outfile," to account for ground clutter.\n\n");
+ }
+
/* 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.
site_x.lon=path.lon[x];
site_x.alt=0.0;
- h_x=GetElevation(site_x)+earthradius;
+ h_x=GetElevation(site_x)+earthradius+clutter;
d_x=5280.0*Distance(rcvr,site_x);
/* Deal with the LOS path first. */
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);
+ fprintf(outfile,"Between %s and %s, %s detected obstructions at:\n\n",rcvr.name,xmtr.name,splat_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));
+ fprintf(outfile," %8.4f N,%9.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);
+ fprintf(outfile," %8.4f N,%9.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));
+ fprintf(outfile," %8.4f S,%9.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);
+ fprintf(outfile," %8.4f S,%9.4f W, %5.2f miles, %6.2f feet AMSL\n",-site_x.lat, site_x.lon, d_x/5280.0, h_x-earthradius);
}
}
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));
+ snprintf(string,150,"\nAntenna at %s must be raised to at least %.2f meters AGL\nto clear all obstructions detected by %s.\n",rcvr.name, METERS_PER_FOOT*(h_r-GetElevation(rcvr)-earthradius),splat_name);
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);
+ snprintf(string,150,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear all obstructions detected by %s.\n",rcvr.name, h_r-GetElevation(rcvr)-earthradius,splat_name);
}
else
- sprintf(string,"\nNo obstructions to LOS path due to terrain were detected by SPLAT!\n");
+ snprintf(string,150,"\nNo obstructions to LOS path due to terrain were detected by %s\n",splat_name);
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);
+ snprintf(string_fpt6,150,"\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);
+ snprintf(string_fpt6,150,"\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);
+ snprintf(string_fpt6,150,"\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));
+ snprintf(string_f1,150,"\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);
+ snprintf(string_f1,150,"\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");
+ snprintf(string_f1,150,"\nThe first Fresnel zone is clear.\n");
}
fprintf(outfile,"%s",string);
found, .png is assumed. */
int x, y, z, errnum;
- char filename[255], term[30], ext[15], strmode[100],
+ char basename[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;
+ free_space_loss=0.0, eirp=0.0, voltage, rxp, dBm,
+ power_density;
FILE *fd=NULL, *fd2=NULL;
sprintf(report_name,"%s-to-%s.txt",source.name,destination.name);
- four_thirds_earth=EARTHRADIUS*(4.0/3.0);
+ four_thirds_earth=FOUR_THIRDS*EARTHRADIUS;
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)
fd2=fopen(report_name,"w");
- fprintf(fd2,"\n\t\t--==[ SPLAT! v%s Path Analysis ]==--\n\n",splat_version);
- fprintf(fd2,"-------------------------------------------------------------------------\n\n");
+ fprintf(fd2,"\n\t\t--==[ %s v%s Path Analysis ]==--\n\n",splat_name,splat_version);
+ fprintf(fd2,"%s\n\n",dashes);
fprintf(fd2,"Transmitter site: %s\n",source.name);
if (source.lat>=0.0)
}
if (metric)
- fprintf(fd2,"Distance to %s: %.2f kilometers\n",destination.name,METERS_PER_FOOT*Distance(source,destination));
+ fprintf(fd2,"Distance to %s: %.2f kilometers\n",destination.name,KM_PER_MILE*Distance(source,destination));
else
- fprintf(fd2,"Distance to %s: %.2f miles.\n",destination.name,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);
fprintf(fd2," angle to the first obstruction: %+.4f degrees\n",angle2);
}
- fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
+ fprintf(fd2,"\n%s\n\n",dashes);
/* Receiver */
angle1=ElevationAngle(destination,source);
angle2=ElevationAngle2(destination,source,earthradius);
- fprintf(fd2,"Azimuth to %s: %.2f degrees.\n",source.name,azimuth);
+ 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," angle to the first obstruction: %+.4f degrees\n",angle2);
}
- fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
+ fprintf(fd2,"\n%s\n\n",dashes);
if (LR.frq_mhz>0.0)
{
fprintf(fd2,"Transmitter ERP: ");
if (LR.erp<1.0)
- fprintf(fd2,"%.1lf milliwatts\n",1000.0*LR.erp);
+ fprintf(fd2,"%.1lf milliwatts",1000.0*LR.erp);
if (LR.erp>=1.0 && LR.erp<10.0)
- fprintf(fd2,"%.1lf Watts\n",LR.erp);
+ fprintf(fd2,"%.1lf Watts",LR.erp);
if (LR.erp>=10.0 && LR.erp<10.0e3)
- fprintf(fd2,"%.0lf Watts\n",LR.erp);
+ fprintf(fd2,"%.0lf Watts",LR.erp);
if (LR.erp>=10.0e3)
- fprintf(fd2,"%.3lf kilowatts\n",LR.erp/1.0e3);
+ fprintf(fd2,"%.3lf kilowatts",LR.erp/1.0e3);
+
+ dBm=10.0*(log10(LR.erp*1000.0));
+ fprintf(fd2," (%+.2f dBm)\n",dBm);
+
+ /* EIRP = ERP + 2.14 dB */
+
+ fprintf(fd2,"Transmitter EIRP: ");
+
+ eirp=LR.erp*1.636816521;
+
+ if (eirp<1.0)
+ fprintf(fd2,"%.1lf milliwatts",1000.0*eirp);
+
+ if (eirp>=1.0 && eirp<10.0)
+ fprintf(fd2,"%.1lf Watts",eirp);
+
+ if (eirp>=10.0 && eirp<10.0e3)
+ fprintf(fd2,"%.0lf Watts",eirp);
+
+ if (eirp>=10.0e3)
+ fprintf(fd2,"%.3lf kilowatts",eirp/1.0e3);
+
+ dBm=10.0*(log10(eirp*1000.0));
+ fprintf(fd2," (%+.2f dBm)\n",dBm);
}
- fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
+ fprintf(fd2,"\n%s\n\n",dashes);
fprintf(fd2,"Summary for the link between %s and %s:\n\n",source.name, destination.name);
ReadPath(source, destination); /* source=TX, destination=RX */
- /* Copy elevations along path into the elev_l[] array. */
+ /* Copy elevations plus clutter along
+ path into the elev[] array. */
+
+ for (x=1; x<path.length-1; x++)
+ elev[x+2]=METERS_PER_FOOT*(path.elevation[x]==0.0?path.elevation[x]:(clutter+path.elevation[x]));
- for (x=0; x<path.length; x++)
- elev_l[x+2]=path.elevation[x]*METERS_PER_FOOT;
+ /* Copy ending points without clutter */
+
+ elev[2]=path.elevation[0]*METERS_PER_FOOT;
+ elev[path.length+1]=path.elevation[path.length-1]*METERS_PER_FOOT;
fd=fopen("profile.gp","w");
what it would be if the angles themselves
were compared. */
- if (cos_xmtr_angle>cos_test_angle)
+ if (cos_xmtr_angle>=cos_test_angle)
block=1;
}
shortest distance terrain can play a role in
path loss. */
- elev_l[0]=y-1; /* (number of points - 1) */
+ elev[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,
+ elev[1]=METERS_PER_MILE*(path.distance[y]-path.distance[y-1]);
+
+ point_to_point(elev, 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;
+ elevation=((acos(cos_test_angle))/DEG2RAD)-90.0;
else
- elevation=((acos(cos_xmtr_angle))/deg2rad)-90.0;
+ elevation=((acos(cos_xmtr_angle))/DEG2RAD)-90.0;
/* Integrate the antenna's radiation
pattern into the overall path 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);
+ fprintf(fd2,"Attenuation due to terrain shielding: %.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));
+ field_strength=(139.4+(20.0*log10(LR.frq_mhz))-total_loss)+(10.0*log10(LR.erp/1000.0));
+
+ /* dBm is referenced to EIRP */
+
+ rxp=eirp/(pow(10.0,(total_loss/10.0)));
+ dBm=10.0*(log10(rxp*1000.0));
+ power_density=(eirp/(pow(10.0,(total_loss-free_space_loss)/10.0)));
+ /* divide by 4*PI*distance_in_meters squared */
+ power_density/=(4.0*PI*distance*distance*2589988.11);
+
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,"Signal power level at %s: %+.2f dBm\n",destination.name,dBm);
+ fprintf(fd2,"Signal power density at %s: %+.2f dBW per square meter\n",destination.name,10.0*log10(power_density));
+ voltage=1.0e6*sqrt(50.0*(eirp/(pow(10.0,(total_loss-2.14)/10.0))));
+ fprintf(fd2,"Voltage across 50 ohm dipole at %s: %.2f uV (%.2f dBuV)\n",destination.name,voltage,20.0*log10(voltage));
+
+ voltage=1.0e6*sqrt(75.0*(eirp/(pow(10.0,(total_loss-2.14)/10.0))));
+ fprintf(fd2,"Voltage across 75 ohm dipole at %s: %.2f uV (%.2f dBuV)\n",destination.name,voltage,20.0*log10(voltage));
}
fprintf(fd2,"Mode of propagation: %s\n",strmode);
+ fprintf(fd2,"Longley-Rice model error number: %d",errnum);
+
+ switch (errnum)
+ {
+ case 0:
+ fprintf(fd2," (No error)\n");
+ break;
- fprintf(fd2,"\n-------------------------------------------------------------------------\n\n");
+ case 1:
+ fprintf(fd2,"\n Warning: Some parameters are nearly out of range.\n");
+ fprintf(fd2," Results should be used with caution.\n");
+ break;
+
+ case 2:
+ fprintf(fd2,"\n Note: Default parameters have been substituted for impossible ones.\n");
+ break;
+
+ case 3:
+ fprintf(fd2,"\n Warning: A combination of parameters is out of range.\n");
+ fprintf(fd2," Results are probably invalid.\n");
+ break;
+
+ default:
+ fprintf(fd2,"\n Warning: Some parameters are out of range.\n");
+ fprintf(fd2," Results are probably invalid.\n");
+ }
+
+ fprintf(fd2,"\n%s\n\n",dashes);
}
fprintf(stdout,"\nPath Loss Report written to: \"%s\"\n",report_name);
if (graph_it)
{
- if (name[0]==0)
+ if (name[0]=='.')
{
/* Default filename and output file type */
- strncpy(filename,"loss\0",5);
+ strncpy(basename,"profile\0",8);
strncpy(term,"png\0",4);
strncpy(ext,"png\0",4);
}
else
{
- /* Grab extension and terminal type from "name" */
+ /* Extract extension and terminal type from "name" */
+
+ ext[0]=0;
+ y=strlen(name);
+ strncpy(basename,name,254);
- for (x=0; name[x]!='.' && name[x]!=0 && x<254; x++)
- filename[x]=name[x];
+ for (x=y-1; x>0 && name[x]!='.'; x--);
- if (name[x]=='.')
+ if (x>0) /* Extension found */
{
- for (y=0, z=x, x++; name[x]!=0 && x<254 && y<14; x++, y++)
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
{
- term[y]=tolower(name[x]);
- ext[y]=term[y];
+ ext[z-(x+1)]=tolower(name[z]);
+ term[z-(x+1)]=name[z];
}
- ext[y]=0;
- term[y]=0;
- filename[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ term[z-(x+1)]=0;
+ basename[x]=0;
}
+ }
- else
- { /* No extension -- Default is png */
-
- filename[x]=0;
- strncpy(term,"png\0",4);
- strncpy(ext,"png\0",4);
- }
+ if (ext[0]==0) /* No extension -- Default is png */
+ {
+ strncpy(term,"png\0",4);
+ strncpy(ext,"png\0",4);
}
/* Either .ps or .postscript may be used
strncpy(ext,"ps\0",3);
else if (strncmp(ext,"ps",2)==0)
- strncpy(term,"postscript enhanced color\0",26);
+ strncpy(term,"postscript enhanced color\0",26);
fd=fopen("splat.gp","w");
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);
+ fprintf(fd,"set title \"%s Loss Profile Along Path Between %s and %s (%.2f%c azimuth)\"\n",splat_name, 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
fprintf(fd,"set ylabel \"Longley-Rice Path Loss (dB)");
- fprintf(fd,"\"\nset output \"%s.%s\"\n",filename,ext);
+ fprintf(fd,"\"\nset output \"%s.%s\"\n",basename,ext);
fprintf(fd,"plot \"profile.gp\" title \"Path Loss\" with lines\n");
fclose(fd);
if (x!=-1)
{
- unlink("splat.gp");
- unlink("profile.gp");
- unlink("reference.gp");
+ if (gpsav==0)
+ {
+ unlink("splat.gp");
+ unlink("profile.gp");
+ unlink("reference.gp");
+ }
- fprintf(stdout,"Path loss plot written to: \"%s.%s\"\n",filename,ext);
+ fprintf(stdout,"Path loss plot written to: \"%s.%s\"\n",basename,ext);
fflush(stdout);
}
fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n");
}
- if (x!=-1)
+ if (x!=-1 && gpsav==0)
unlink("profile.gp");
}
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,"\n\t--==[ %s v%s Site Analysis Report For: %s ]==--\n\n",splat_name, splat_version, xmtr.name);
- fprintf(fd,"---------------------------------------------------------------------------\n\n");
+ fprintf(fd,"%s\n\n",dashes);
if (xmtr.lat>=0.0)
{
}
}
- fprintf(fd,"\n---------------------------------------------------------------------------\n\n");
+ fprintf(fd,"\n%s\n\n",dashes);
fclose(fd);
- fprintf(stdout,"\nSite analysis report written to: \"%s\"",report_name);
+ fprintf(stdout,"\nSite analysis report written to: \"%s\"\n",report_name);
}
void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat)
while (ymax>=360)
ymax-=360;
- sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
+ if (ippd==3600)
+ snprintf(string,19,"%d:%d:%d:%d-hd",x, x+1, ymin, ymax);
+ else
+ snprintf(string,16,"%d:%d:%d:%d",x, x+1, ymin, ymax);
LoadSDF(string);
}
}
while (ymax>=360)
ymax-=360;
- sprintf(string,"%d:%d:%d:%d",x, x+1, ymin, ymax);
+ if (ippd==3600)
+ snprintf(string,19,"%d:%d:%d:%d-hd",x, x+1, ymin, ymax);
+ else
+ snprintf(string,16,"%d:%d:%d:%d",x, x+1, ymin, ymax);
LoadSDF(string);
}
}
}
-int LoadPLI(char *filename)
+int LoadANO(char *filename)
{
- /* This function reads a SPLAT! path-loss output
- file (-plo) for analysis and/or map generation. */
+ /* This function reads a SPLAT! alphanumeric output
+ file (-ani option) for analysis and/or map generation. */
int error=0, max_west, min_west, max_north, min_north;
- char string[80], *pointer=NULL;
+ char string[80], *pointer=NULL, *s=NULL;
double latitude=0.0, longitude=0.0, azimuth=0.0, elevation=0.0,
- loss=0.0;
+ ano=0.0;
FILE *fd;
fd=fopen(filename,"r");
if (fd!=NULL)
{
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
sscanf(string,"%d, %d",&max_west, &min_west);
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
sscanf(string,"%d, %d",&max_north, &min_north);
- fgets(string,78,fd);
+ s=fgets(string,78,fd);
pointer=strchr(string,';');
if (pointer!=NULL)
fprintf(stdout,"\nReading \"%s\"... ",filename);
fflush(stdout);
- fgets(string,78,fd);
- sscanf(string,"%lf, %lf, %lf, %lf, %lf",&latitude, &longitude, &azimuth, &elevation, &loss);
+ s=fgets(string,78,fd);
+ sscanf(string,"%lf, %lf, %lf, %lf, %lf",&latitude, &longitude, &azimuth, &elevation, &ano);
while (feof(fd)==0)
{
- if (loss>255.0)
- loss=255.0;
+ if (LR.erp==0.0)
+ {
+ /* Path loss */
+
+ if (contour_threshold==0 || (fabs(ano)<=(double)contour_threshold))
+ {
+ ano=fabs(ano);
+
+ if (ano>255.0)
+ ano=255.0;
+
+ PutSignal(latitude,longitude,((unsigned char)round(ano)));
+ }
+ }
+
+ if (LR.erp!=0.0 && dbm!=0)
+ {
+ /* signal power level in dBm */
+
+ if (contour_threshold==0 || (ano>=(double)contour_threshold))
+ {
+ ano=200.0+rint(ano);
+
+ if (ano<0.0)
+ ano=0.0;
+
+ if (ano>255.0)
+ ano=255.0;
+
+ PutSignal(latitude,longitude,((unsigned char)round(ano)));
+ }
+ }
+
+ if (LR.erp!=0.0 && dbm==0)
+ {
+ /* field strength dBuV/m */
+
+ if (contour_threshold==0 || (ano>=(double)contour_threshold))
+ {
+ ano=100.0+rint(ano);
+
+ if (ano<0.0)
+ ano=0.0;
+
+ if (ano>255.0)
+ ano=255.0;
- if (loss<=(double)maxdB)
- PutSignal(latitude,longitude,((unsigned char)round(loss)));
+ PutSignal(latitude,longitude,((unsigned char)round(ano)));
+ }
+ }
- fgets(string,78,fd);
- sscanf(string,"%lf, %lf, %lf, %lf, %lf",&latitude, &longitude, &azimuth, &elevation, &loss);
+ s=fgets(string,78,fd);
+ sscanf(string,"%lf, %lf, %lf, %lf, %lf",&latitude, &longitude, &azimuth, &elevation, &ano);
}
fclose(fd);
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,"<!-- Generated by %s Version %s -->\n",splat_name, splat_version);
fprintf(fd,"<Folder>\n");
fprintf(fd,"<name>SPLAT! Path</name>\n");
fprintf(fd,"<open>1</open>\n");
fprintf(fd," <BR>%s West</BR>\n",dec2dms(destination.lon));
-
if (metric)
fprintf(fd," <BR>%.2f km",distance*KM_PER_MILE);
else
statement is reversed from what it would
be if the actual angles were compared. */
- if (cos_xmtr_angle>cos_test_angle)
+ if (cos_xmtr_angle>=cos_test_angle)
block=1;
}
north_min, north_max;
unsigned char coverage=0, LRmap=0, terrain_plot=0,
- elevation_plot=0, height_plot=0, map=0, nf=0,
+ elevation_plot=0, height_plot=0, map=0,
longley_plot=0, cities=0, bfs=0, txsites=0,
norm=0, topomap=0, geo=0, kml=0, pt2pt_mode=0,
area_mode=0, max_txsites, ngs=0, nolospath=0,
- nositereports=0;
+ nositereports=0, fresnel_plot=1;
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], boundary_file[5][255],
- udt_file[255], rxsite=0, plo_filename[255],
- pli_filename[255], ext[20];
+ udt_file[255], rxsite=0, ani_filename[255],
+ ano_filename[255], ext[20], *s=NULL;
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, freq=0.0;
+ rx_range=0.0, deg_range=0.0, deg_limit=0.0,
+ deg_range_lon, er_mult;
struct site tx_site[32], rx_site;
FILE *fd;
+ strncpy(splat_version,"1.3.0\0",6);
+
+ if (HD_MODE==1)
+ strncpy(splat_name,"SPLAT! HD\0",10);
+ else
+ strncpy(splat_name,"SPLAT!\0",7);
+
+ strncpy(dashes,"---------------------------------------------------------------------------\0",76);
if (argc==1)
{
- fprintf(stdout,"\n\t\t --==[ SPLAT! v%s Available Options... ]==--\n\n",splat_version);
+ fprintf(stdout,"\n\t\t --==[ %s v%s Available Options... ]==--\n\n",splat_name, 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," -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," -l filename of path loss 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," -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," -db threshold beyond which contours will not be displayed\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," -gc ground clutter height (feet/meters)\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," -ano name of alphanumeric output file\n");
+ fprintf(stdout," -ani name of alphanumeric input file\n");
+ fprintf(stdout," -udt name 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," -dbm plot signal power level contours rather than field strength\n");
+ fprintf(stdout," -gpsav preserve gnuplot temporary working files after SPLAT! execution\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");
+
+ if (HD_MODE==0)
+ fprintf(stdout,"\n\tsplat | less\n\n");
+ else
+ fprintf(stdout,"\n\tsplat-hd | less\n\n");
+
fprintf(stdout,"Type 'man splat', or see the documentation for more details.\n\n");
+
+ y=(int)sqrt((int)MAXPAGES);
+
+ fprintf(stdout,"This compilation of %s supports analysis over a region of\n%d square ",splat_name,y);
+
+ if (y==1)
+
+ fprintf(stdout,"degree");
+ else
+ fprintf(stdout,"degrees");
+
+ fprintf(stdout," of terrain.\n\n");
fflush(stdout);
return 1;
kml=0;
geo=0;
+ dbm=0;
+ gpsav=0;
metric=0;
rxfile[0]=0;
txfile[0]=0;
string[0]=0;
mapfile[0]=0;
+ clutter=0.0;
+ forced_erp=-1.0;
+ forced_freq=0.0;
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;
+ contour_threshold=0;
rx_site.lat=91.0;
rx_site.lon=361.0;
longley_file[0]=0;
- plo_filename[0]=0;
- pli_filename[0]=0;
+ ano_filename[0]=0;
+ ani_filename[0]=0;
earthradius=EARTHRADIUS;
- sprintf(header,"\n\t\t--==[ Welcome To SPLAT! v%s ]==--\n\n", splat_version);
+ ippd=IPPD; /* pixels per degree (integer) */
+ ppd=(double)ippd; /* pixels per degree (double) */
+ dpp=1.0/ppd; /* degrees per pixel */
+ mpi=ippd-1; /* maximum pixel index per degree */
+
+ sprintf(header,"\n\t\t--==[ Welcome To %s v%s ]==--\n\n", splat_name, splat_version);
for (x=0; x<4; x++)
{
}
}
+ if (strcmp(argv[x],"-gc")==0)
+ {
+ z=x+1;
+
+ if (z<=y && argv[z][0] && argv[z][0]!='-')
+ {
+ sscanf(argv[z],"%lf",&clutter);
+
+ if (clutter<0.0)
+ clutter=0.0;
+ }
+ }
+
if (strcmp(argv[x],"-fz")==0)
{
z=x+1;
map=1;
}
- if (strcmp(argv[x],"-u")==0)
+ if (strcmp(argv[x],"-udt")==0)
{
z=x+1;
{
z=x+1;
- if (z<=y && argv[z][0] && argv[z][0]!='-')
- {
- sscanf(argv[z],"%d",&maxdB);
-
- maxdB=abs(maxdB);
-
- if (maxdB<80)
- maxdB=80;
-
- if (maxdB>230)
- maxdB=230;
- }
+ if (z<=y && argv[z][0]) /* A minus argument is legal here */
+ sscanf(argv[z],"%d",&contour_threshold);
}
if (strcmp(argv[x],"-p")==0)
if (strcmp(argv[x],"-metric")==0)
metric=1;
+ if (strcmp(argv[x],"-gpsav")==0)
+ gpsav=1;
+
if (strcmp(argv[x],"-geo")==0)
geo=1;
kml=1;
if (strcmp(argv[x],"-nf")==0)
- nf=1;
+ fresnel_plot=0;
if (strcmp(argv[x],"-ngs")==0)
ngs=1;
if (strcmp(argv[x],"-n")==0)
nolospath=1;
+ if (strcmp(argv[x],"-dbm")==0)
+ dbm=1;
+
if (strcmp(argv[x],"-N")==0)
{
nolospath=1;
if (z<=y && argv[z][0] && argv[z][0]!='-')
{
- sscanf(argv[z],"%lf",&freq);
+ sscanf(argv[z],"%lf",&forced_freq);
- if (freq<20)
- freq=20;
+ if (forced_freq<20.0)
+ forced_freq=0.0;
- if (freq>20e3)
- freq=20e3;
- }
+ if (forced_freq>20.0e3)
+ forced_freq=20.0e3;
+ }
}
if (strcmp(argv[x],"-erp")==0)
}
}
- if (strcmp(argv[x],"-plo")==0)
+ if (strcmp(argv[x],"-ano")==0)
{
z=x+1;
if (z<=y && argv[z][0] && argv[z][0]!='-')
- strncpy(plo_filename,argv[z],253);
+ strncpy(ano_filename,argv[z],253);
}
- if (strcmp(argv[x],"-pli")==0)
+ if (strcmp(argv[x],"-ani")==0)
{
z=x+1;
if (z<=y && argv[z][0] && argv[z][0]!='-')
- strncpy(pli_filename,argv[z],253);
+ strncpy(ani_filename,argv[z],253);
}
}
exit (-1);
}
- if ((coverage+LRmap+pli_filename[0])==0 && rx_site.lat==91.0 && rx_site.lon==361.0)
+ if ((coverage+LRmap+ani_filename[0])==0 && rx_site.lat==91.0 && rx_site.lon==361.0)
{
if (max_range!=0.0 && txsites!=0)
{
altitudeLR/=METERS_PER_FOOT; /* meters --> feet */
max_range/=KM_PER_MILE; /* kilometers --> miles */
altitude/=METERS_PER_FOOT; /* meters --> feet */
+ clutter/=METERS_PER_FOOT; /* meters --> feet */
}
/* If no SDF path was specified on the command line (-d), check
if (sdf_path[0]==0)
{
env=getenv("HOME");
- sprintf(string,"%s/.splat_path",env);
+ snprintf(string,253,"%s/.splat_path",env);
fd=fopen(string,"r");
if (fd!=NULL)
{
- fgets(string,253,fd);
+ s=fgets(string,253,fd);
/* Remove <CR> and/or <LF> from string */
fprintf(stdout,"%s",header);
fflush(stdout);
- if (pli_filename[0])
+ if (ani_filename[0])
{
- y=LoadPLI(pli_filename);
+ ReadLRParm(tx_site[0],0); /* Get ERP status */
+ y=LoadANO(ani_filename);
for (x=0; x<txsites && x<max_txsites; x++)
PlaceMarker(tx_site[x]);
{
for (x=0; x<bfs; x++)
LoadBoundaries(boundary_file[x]);
+
+ fprintf(stdout,"\n");
+ fflush(stdout);
}
if (cities)
{
for (x=0; x<cities; x++)
LoadCities(city_file[x]);
+
+ fprintf(stdout,"\n");
+ fflush(stdout);
}
- WritePPMLR(mapfile,geo,kml,ngs,tx_site,txsites);
+ if (LR.erp==0.0)
+ WritePPMLR(mapfile,geo,kml,ngs,tx_site,txsites);
+ else
+ {
+ if (dbm)
+ WritePPMDBM(mapfile,geo,kml,ngs,tx_site,txsites);
+ else
+ WritePPMSS(mapfile,geo,kml,ngs,tx_site,txsites);
+ }
exit(0);
}
if (LonDiff(txlon,min_lon)<0.0)
min_lon=txlon;
- if (LonDiff(txlon,max_lon)>0.0)
+ if (LonDiff(txlon,max_lon)>=0.0)
max_lon=txlon;
}
if (LonDiff(rxlon,min_lon)<0.0)
min_lon=rxlon;
- if (LonDiff(rxlon,max_lon)>0.0)
+ if (LonDiff(rxlon,max_lon)>=0.0)
max_lon=rxlon;
}
-
/* Load the required SDF files */
LoadTopoData(max_lon, min_lon, max_lat, min_lat);
/* deg_range determines the maximum
amount of topo data we read */
- deg_range=(tx_range+rx_range)/69.0;
+ deg_range=(tx_range+rx_range)/57.0;
- /* max_range sets the maximum size of the
+ /* max_range regulates the size of the
analysis. A small, non-zero amount can
be used to shrink the size of the analysis
and limit the amount of topo data read by
- SPLAT! A very large number will only increase
- the width of the analysis, not the size of
+ SPLAT! A large number will increase the
+ width of the analysis and the size of
the map. */
if (max_range==0.0)
max_range=tx_range+rx_range;
- if (max_range<(tx_range+rx_range))
- deg_range=max_range/69.0;
+ deg_range=max_range/57.0;
/* Prevent the demand for a really wide coverage
from allocating more "pages" than are available
switch (MAXPAGES)
{
+ case 1: deg_limit=0.125;
+ break;
+
case 2: deg_limit=0.25;
break;
case 9: deg_limit=1.0;
break;
- case 16: deg_limit=2.0;
+ case 16: deg_limit=1.5; /* WAS 2.0 */
+ break;
+
+ case 25: deg_limit=2.0; /* WAS 3.0 */
+ break;
+
+ case 36: deg_limit=2.5; /* New! */
+ break;
+
+ case 49: deg_limit=3.0; /* New! */
break;
- case 25: deg_limit=3.0;
+ case 64: deg_limit=3.5; /* New! */
+ break;
}
- if (tx_site[z].lat<70.0)
- deg_range_lon=deg_range/cos(deg2rad*tx_site[z].lat);
+ if (fabs(tx_site[z].lat)<70.0)
+ deg_range_lon=deg_range/cos(DEG2RAD*tx_site[z].lat);
else
- deg_range_lon=deg_range/cos(deg2rad*70.0);
+ deg_range_lon=deg_range/cos(DEG2RAD*70.0);
/* Correct for squares in degrees not being square in miles */
if (LonDiff(west_min,min_lon)<0.0)
min_lon=west_min;
- if (LonDiff(west_max,max_lon)>0.0)
+ if (LonDiff(west_max,max_lon)>=0.0)
max_lon=west_max;
}
{
PlaceMarker(rx_site);
- if (longley_plot)
+ if (terrain_plot)
{
- /* Grab extension to determine graphic file type */
+ /* Extract extension (if present)
+ from "terrain_file" */
- for (x=0; longley_file[x]!='.' && longley_file[x]!=0 && x<80; x++);
+ y=strlen(terrain_file);
- if (longley_file[x]=='.')
+ for (x=y-1; x>0 && terrain_file[x]!='.'; x--);
+
+ if (x>0) /* Extension found */
{
- ext[0]='.';
- for (y=1, z=x, x++; longley_file[x]!=0 && x<253 && y<14; x++, y++)
- ext[y]=longley_file[x];
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
+ ext[z-(x+1)]=tolower(terrain_file[z]);
- ext[y]=0;
- longley_file[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ terrain_file[x]=0; /* Chop off extension */
}
else
- {
- ext[0]=0; /* No extension */
- longley_file[x]=0;
- }
+ strncpy(ext,"png\0",4);
}
- if (terrain_plot)
+ if (elevation_plot)
{
- for (x=0; terrain_file[x]!='.' && terrain_file[x]!=0 && x<80; x++);
+ /* Extract extension (if present)
+ from "elevation_file" */
- if (terrain_file[x]=='.') /* extension */
+ y=strlen(elevation_file);
+
+ for (x=y-1; x>0 && elevation_file[x]!='.'; x--);
+
+ if (x>0) /* Extension found */
{
- ext[0]='.';
- for (y=1, z=x, x++; terrain_file[x]!=0 && x<253 && y<14; x++, y++)
- ext[y]=terrain_file[x];
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
+ ext[z-(x+1)]=tolower(elevation_file[z]);
- ext[y]=0;
- terrain_file[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ elevation_file[x]=0; /* Chop off extension */
}
else
- {
- ext[0]=0; /* No extension */
- terrain_file[x]=0;
- }
+ strncpy(ext,"png\0",4);
}
- if (elevation_plot)
+ if (height_plot)
{
- for (x=0; elevation_file[x]!='.' && elevation_file[x]!=0 && x<80; x++);
+ /* Extract extension (if present)
+ from "height_file" */
+
+ y=strlen(height_file);
- if (elevation_file[x]=='.') /* extension */
+ for (x=y-1; x>0 && height_file[x]!='.'; x--);
+
+ if (x>0) /* Extension found */
{
- ext[0]='.';
- for (y=1, z=x, x++; elevation_file[x]!=0 && x<253 && y<14; x++, y++)
- ext[y]=elevation_file[x];
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
+ ext[z-(x+1)]=tolower(height_file[z]);
- ext[y]=0;
- elevation_file[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ height_file[x]=0; /* Chop off extension */
}
else
- {
- ext[0]=0; /* No extension */
- elevation_file[x]=0;
- }
+ strncpy(ext,"png\0",4);
}
- if (height_plot)
+ if (longley_plot)
{
- for (x=0; height_file[x]!='.' && height_file[x]!=0 && x<80; x++);
+ /* Extract extension (if present)
+ from "longley_file" */
+
+ y=strlen(longley_file);
+
+ for (x=y-1; x>0 && longley_file[x]!='.'; x--);
- if (height_file[x]=='.') /* extension */
+ if (x>0) /* Extension found */
{
- ext[0]='.';
- for (y=1, z=x, x++; height_file[x]!=0 && x<253 && y<14; x++, y++)
- ext[y]=height_file[x];
+ for (z=x+1; z<=y && (z-(x+1))<10; z++)
+ ext[z-(x+1)]=tolower(longley_file[z]);
- ext[y]=0;
- height_file[z]=0;
+ ext[z-(x+1)]=0; /* Ensure an ending 0 */
+ longley_file[x]=0; /* Chop off extension */
}
else
- {
- ext[0]=0; /* No extension */
- height_file[x]=0;
- }
+ strncpy(ext,"png\0",4);
}
for (x=0; x<txsites && x<4; x++)
WriteKML(tx_site[x],rx_site);
if (txsites>1)
- sprintf(string,"%s-%c%s%c",longley_file,'1'+x,ext,0);
+ snprintf(string,250,"%s-%c.%s%c",longley_file,'1'+x,ext,0);
else
- sprintf(string,"%s%s%c",longley_file,ext,0);
+ snprintf(string,250,"%s.%s%c",longley_file,ext,0);
if (nositereports==0)
{
if (longley_file[0]==0)
{
ReadLRParm(tx_site[x],0);
- PathReport(tx_site[x],rx_site,string,0); }
+ PathReport(tx_site[x],rx_site,string,0);
+ }
else
{
if (terrain_plot)
{
if (txsites>1)
- sprintf(string,"%s-%c%s%c",terrain_file,'1'+x,ext,0);
+ snprintf(string,250,"%s-%c.%s%c",terrain_file,'1'+x,ext,0);
else
- sprintf(string,"%s%s%c",terrain_file,ext,0);
+ snprintf(string,250,"%s.%s%c",terrain_file,ext,0);
GraphTerrain(tx_site[x],rx_site,string);
}
if (elevation_plot)
{
if (txsites>1)
- sprintf(string,"%s-%c%s%c",elevation_file,'1'+x,ext,0);
+ snprintf(string,250,"%s-%c.%s%c",elevation_file,'1'+x,ext,0);
else
- sprintf(string,"%s%s%c",elevation_file,ext,0);
+ snprintf(string,250,"%s.%s%c",elevation_file,ext,0);
GraphElevation(tx_site[x],rx_site,string);
}
if (height_plot)
{
- 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);
+ snprintf(string,250,"%s-%c.%s%c",height_file,'1'+x,ext,0);
else
- sprintf(string,"%s%s%c",height_file,ext,0);
+ snprintf(string,250,"%s.%s%c",height_file,ext,0);
- GraphHeight(tx_site[x],rx_site,string,freq,norm);
+ GraphHeight(tx_site[x],rx_site,string,fresnel_plot,norm);
}
}
}
for (x=0; x<txsites && x<max_txsites; x++)
{
if (coverage)
- PlotCoverage(tx_site[x],altitude);
+ PlotLOSMap(tx_site[x],altitude);
else if (ReadLRParm(tx_site[x],1))
- PlotLRMap(tx_site[x],altitudeLR,plo_filename);
+ PlotLRMap(tx_site[x],altitudeLR,ano_filename);
SiteReport(tx_site[x]);
}
{
/* Label the map */
+ if (kml==0)
+ {
+ for (x=0; x<txsites && x<max_txsites; x++)
+ PlaceMarker(tx_site[x]);
+ }
+
if (cities)
{
- if (kml==0)
- {
- for (x=0; x<txsites && x<max_txsites; x++)
- PlaceMarker(tx_site[x]);
- }
for (y=0; y<cities; y++)
LoadCities(city_file[y]);
+
+ fprintf(stdout,"\n");
+ fflush(stdout);
}
/* Load city and county boundary data files */
{
for (y=0; y<bfs; y++)
LoadBoundaries(boundary_file[y]);
+
+ fprintf(stdout,"\n");
+ fflush(stdout);
}
/* Plot the map */
if (coverage || pt2pt_mode || topomap)
- WritePPM(mapfile,geo,kml,ngs);
+ WritePPM(mapfile,geo,kml,ngs,tx_site,txsites);
else
{
if (LR.erp==0.0)
WritePPMLR(mapfile,geo,kml,ngs,tx_site,txsites);
else
- WritePPMSS(mapfile,geo,kml,ngs,tx_site,txsites);
+ if (dbm)
+ WritePPMDBM(mapfile,geo,kml,ngs,tx_site,txsites);
+ else
+ WritePPMSS(mapfile,geo,kml,ngs,tx_site,txsites);
}
}