X-Git-Url: https://git.gag.com/?p=debian%2Fsplat;a=blobdiff_plain;f=splat.cpp;h=844a12c3cb7e7822a291ff986847a779c14b1478;hp=9a96ef989b6f5cecc3559c5684d204033ea0ce40;hb=68a3cad00312b42922f10cc4822349802f50ed20;hpb=dcc481697c227c3b265d1e68a8a82910c818332c diff --git a/splat.cpp b/splat.cpp index 9a96ef9..844a12c 100644 --- a/splat.cpp +++ b/splat.cpp @@ -2,7 +2,7 @@ * 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. * @@ -30,39 +30,108 @@ #include #include #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; @@ -84,9 +153,9 @@ struct dem { int min_north; 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; @@ -106,7 +175,7 @@ struct region { unsigned char color[32][3]; 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, @@ -136,9 +205,30 @@ int ReduceAngle(double angle) 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) @@ -175,7 +265,7 @@ 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); } @@ -191,19 +281,20 @@ int PutMask(double lat, double lon, int value) char found; for (indx=0, found=0; indx=(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 @@ -222,19 +313,20 @@ int OrMask(double lat, double lon, int value) char found; for (indx=0, found=0; indx=(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 @@ -258,18 +350,19 @@ int PutSignal(double lat, double lon, unsigned char signal) char found; for (indx=0, found=0; indx=(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]); } @@ -287,19 +380,18 @@ unsigned char GetSignal(double lat, double lon) char found; for (indx=0, found=0; indx=(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; } @@ -314,19 +406,21 @@ double GetElevation(struct site location) 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=(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; } @@ -341,18 +435,20 @@ int AddElevation(double lat, double lon, double height) 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=(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; } @@ -363,10 +459,10 @@ double Distance(struct site site1, struct site site2) 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))); @@ -381,11 +477,11 @@ double Azimuth(struct site source, struct site destination) 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 */ @@ -422,7 +518,7 @@ double Azimuth(struct site source, struct site destination) if (diff>0.0) azimuth=TWOPI-azimuth; - return (azimuth/deg2rad); + return (azimuth/DEG2RAD); } double ElevationAngle(struct site source, struct site destination) @@ -456,28 +552,55 @@ void ReadPath(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 && cHALFPI+lat1)) - lon2=lon1+PI; + lon2=lon1+PI; else if (fabs(num/den)>1.0) - lon2=lon1; + lon2=lon1; else { @@ -507,8 +630,8 @@ void ReadPath(struct site source, struct site destination) 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; @@ -574,7 +697,7 @@ double ElevationAngle2(struct site source, struct site destination, double er) { 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); @@ -586,10 +709,10 @@ double ElevationAngle2(struct site source, struct site destination, double er) 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; } } @@ -597,7 +720,7 @@ double ElevationAngle2(struct site source, struct site destination, double er) elevation=first_obstruction_angle; else - elevation=((acos(cos_xmtr_angle))/deg2rad)-90.0; + elevation=((acos(cos_xmtr_angle))/DEG2RAD)-90.0; path=temp; @@ -618,15 +741,15 @@ double AverageTerrain(struct site source, double azimuthx, double start_distance 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)); @@ -636,10 +759,10 @@ double AverageTerrain(struct site source, double azimuthx, double start_distance 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 { @@ -655,8 +778,8 @@ double AverageTerrain(struct site source, double azimuthx, double start_distance while (lon2>TWOPI) lon2-=TWOPI; - lat2=lat2/deg2rad; - lon2=lon2/deg2rad; + lat2=lat2/DEG2RAD; + lon2=lon2/DEG2RAD; destination.lat=lat2; destination.lon=lon2; @@ -684,7 +807,7 @@ double AverageTerrain(struct site source, double azimuthx, double start_distance { if (path.distance[c]>=start_distance) { - terrain+=path.elevation[c]; + terrain+=(path.elevation[c]==0.0?path.elevation[c]:path.elevation[c]+clutter); samples++; } } @@ -737,27 +860,6 @@ double haat(struct site antenna) } } -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 @@ -775,29 +877,30 @@ void PlaceMarker(struct site location) 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 (latxmin && (LonDiff(lon,ymax)<0.0) && (LonDiff(lon,ymin)>0.0)) + if (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) @@ -809,7 +912,7 @@ void PlaceMarker(struct site location) 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 */ @@ -874,7 +977,7 @@ void PlaceMarker(struct site location) 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 */ @@ -945,8 +1048,8 @@ void PlaceMarker(struct site location) 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++) { @@ -963,9 +1066,9 @@ void PlaceMarker(struct site location) /* 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); } } @@ -1015,11 +1118,13 @@ double ReadBearing(char *input) 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; @@ -1044,18 +1149,20 @@ struct site LoadQTH(char *filename) 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; @@ -1068,7 +1175,7 @@ struct site LoadQTH(char *filename) if (fd!=NULL) { /* Site Name */ - fgets(string,49,fd); + s=fgets(string,49,fd); /* Strip and/or from end of site name */ @@ -1077,18 +1184,18 @@ struct site LoadQTH(char *filename) 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 and/or from antenna height string */ @@ -1133,7 +1240,7 @@ void LoadPAT(char *filename) 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, @@ -1181,7 +1288,7 @@ void LoadPAT(char *filename) in degrees measured clockwise from true North. */ - fgets(string,254,fd); + s=fgets(string,254,fd); pointer=strchr(string,';'); if (pointer!=NULL) @@ -1194,7 +1301,7 @@ void LoadPAT(char *filename) 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) @@ -1212,7 +1319,7 @@ void LoadPAT(char *filename) read_count[x]++; } - fgets(string,254,fd); + s=fgets(string,254,fd); pointer=strchr(string,';'); if (pointer!=NULL) @@ -1315,7 +1422,7 @@ void LoadPAT(char *filename) tilt azimuth in degrees measured clockwise from true North. */ - fgets(string,254,fd); + s=fgets(string,254,fd); pointer=strchr(string,';'); if (pointer!=NULL) @@ -1327,7 +1434,7 @@ void LoadPAT(char *filename) 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) @@ -1349,7 +1456,7 @@ void LoadPAT(char *filename) read_count[x]++; } - fgets(string,254,fd); + s=fgets(string,254,fd); pointer=strchr(string,';'); if (pointer!=NULL) @@ -1502,7 +1609,7 @@ int LoadSDF_SDF(char *name) 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++) @@ -1563,22 +1670,22 @@ int LoadSDF_SDF(char *name) 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; xmax_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_northmax_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_northmax_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_north0.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,';'); @@ -2199,28 +2306,44 @@ void LoadUDT(char *filename) 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); @@ -2229,6 +2352,8 @@ void LoadUDT(char *filename) else fprintf(stderr,"\n*** ERROR: \"%s\": not found!",filename); + + fprintf(stdout,"\n"); } void LoadBoundaries(char *filename) @@ -2241,7 +2366,7 @@ 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; @@ -2249,28 +2374,25 @@ void LoadBoundaries(char *filename) 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); @@ -2280,11 +2402,11 @@ void LoadBoundaries(char *filename) 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); @@ -2310,7 +2432,7 @@ char ReadLRParm(struct site txsite, char forced_read) "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; @@ -2349,7 +2471,7 @@ char ReadLRParm(struct site txsite, char forced_read) if (fd!=NULL) { - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2362,7 +2484,7 @@ char ReadLRParm(struct site txsite, char forced_read) { LR.eps_dielect=din; - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2376,7 +2498,7 @@ char ReadLRParm(struct site txsite, char forced_read) { LR.sgm_conductivity=din; - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2390,7 +2512,7 @@ char ReadLRParm(struct site txsite, char forced_read) { LR.eno_ns_surfref=din; - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2404,7 +2526,7 @@ char ReadLRParm(struct site txsite, char forced_read) { LR.frq_mhz=din; - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2418,7 +2540,7 @@ char ReadLRParm(struct site txsite, char forced_read) { LR.radio_climate=iin; - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2432,7 +2554,7 @@ char ReadLRParm(struct site txsite, char forced_read) { LR.pol=iin; - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2446,7 +2568,7 @@ char ReadLRParm(struct site txsite, char forced_read) { LR.conf=din; - fgets(string,80,fd); + s=fgets(string,80,fd); pointer=strchr(string,';'); @@ -2471,6 +2593,15 @@ char ReadLRParm(struct site txsite, char forced_read) 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)); } } @@ -2479,6 +2610,9 @@ char ReadLRParm(struct site txsite, char forced_read) 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); } @@ -2510,7 +2644,7 @@ char ReadLRParm(struct site txsite, char forced_read) 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); @@ -2521,7 +2655,7 @@ char ReadLRParm(struct site txsite, char forced_read) } else if (forced_read==0) - return_value=0; + return_value=0; if (forced_read && (fd==NULL || ok==0)) { @@ -2580,7 +2714,7 @@ void PlotPath(struct site source, struct site destination, char mask_value) 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); @@ -2591,7 +2725,7 @@ void PlotPath(struct site source, struct site destination, char mask_value) 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; } @@ -2613,17 +2747,22 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_ 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; xcos_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 @@ -2709,12 +2846,13 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_ 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, @@ -2725,10 +2863,15 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_ 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. */ @@ -2745,33 +2888,62 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_ { 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 @@ -2797,14 +2969,14 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_ 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 @@ -2815,13 +2987,11 @@ void PlotCoverage(struct site source, double altitude) 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'; @@ -2830,15 +3000,25 @@ void PlotCoverage(struct site source, double altitude) 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; @@ -2867,9 +3047,9 @@ void PlotCoverage(struct site source, double altitude) 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; @@ -2895,9 +3075,9 @@ void PlotCoverage(struct site source, double altitude) 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; @@ -2926,9 +3106,9 @@ void PlotCoverage(struct site source, double altitude) 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; @@ -2981,14 +3161,15 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename) 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'; @@ -2997,9 +3178,24 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename) 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) @@ -3012,12 +3208,14 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename) 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; @@ -3046,9 +3244,9 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename) 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; @@ -3074,9 +3272,9 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename) 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; @@ -3105,9 +3303,9 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename) 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; @@ -3142,7 +3340,7 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename) 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++) @@ -3251,7 +3449,7 @@ void LoadSignalColors(struct site xmtr) else { x=0; - fgets(string,80,fd); + s=fgets(string,80,fd); while (x<32 && feof(fd)==0) { @@ -3280,7 +3478,7 @@ void LoadSignalColors(struct site xmtr) x++; } - fgets(string,80,fd); + s=fgets(string,80,fd); } fclose(fd); @@ -3291,7 +3489,7 @@ void LoadSignalColors(struct site xmtr) 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++) @@ -3415,7 +3613,7 @@ void LoadLossColors(struct site xmtr) else { x=0; - fgets(string,80,fd); + s=fgets(string,80,fd); while (x<32 && feof(fd)==0) { @@ -3444,7 +3642,7 @@ void LoadLossColors(struct site xmtr) x++; } - fgets(string,80,fd); + s=fgets(string,80,fd); } fclose(fd); @@ -3452,54 +3650,246 @@ void LoadLossColors(struct site xmtr) } } -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+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; x360.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) { @@ -3507,10 +3897,10 @@ void WritePPM(char *filename, unsigned char geo, unsigned char kml, unsigned cha 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); } @@ -3522,23 +3912,50 @@ void WritePPM(char *filename, unsigned char geo, unsigned char kml, unsigned cha fprintf(fd,"\n"); fprintf(fd,"\n"); fprintf(fd," \n"); - fprintf(fd," SPLAT!\n"); + fprintf(fd," %s\n",splat_name); fprintf(fd," Line-of-Sight Overlay\n"); fprintf(fd," \n"); - fprintf(fd," SPLAT! Line-of-Sight Overlay\n"); + fprintf(fd," %s Line-of-Sight Overlay\n",splat_name); fprintf(fd," SPLAT! Coverage\n"); fprintf(fd," \n"); fprintf(fd," %s\n",mapfile); fprintf(fd," \n"); fprintf(fd," 128\n"); fprintf(fd," \n"); - fprintf(fd," %.5f\n",(double)max_north-one_pixel); - fprintf(fd," %.5f\n",(double)min_north); - fprintf(fd," %.5f\n",((double)min_west<180.0?(double)-min_west:360.0-(double)min_west)); - fprintf(fd," %.5f\n",(((double)max_west-one_pixel)<180.0?-((double)max_west-one_pixel):(360.0-(double)max_west-one_pixel))); + fprintf(fd," %.5f\n",north); + fprintf(fd," %.5f\n",south); + fprintf(fd," %.5f\n",east); + fprintf(fd," %.5f\n",west); fprintf(fd," 0.0\n"); fprintf(fd," \n"); fprintf(fd," \n"); + + for (x=0; x\n"); + fprintf(fd," %s\n",xmtr[x].name); + fprintf(fd," 1\n"); + fprintf(fd," \n"); + fprintf(fd," \n"); + fprintf(fd," 1\n"); + fprintf(fd," relativeToGround\n"); + fprintf(fd," %f,%f,%f\n",(xmtr[x].lon<180.0?-xmtr[x].lon:360.0-xmtr[x].lon), xmtr[x].lat, xmtr[x].alt); + fprintf(fd," \n"); + fprintf(fd," \n"); + } + + + fprintf(fd," \n"); fprintf(fd,"\n"); @@ -3551,24 +3968,26 @@ void WritePPM(char *filename, unsigned char geo, unsigned char kml, unsigned cha 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=(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) @@ -3697,27 +4116,38 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c 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; x360.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); } @@ -3760,9 +4207,9 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c fprintf(fd,"\n"); fprintf(fd,"\n"); - fprintf(fd,"\n",splat_version); + fprintf(fd,"\n",splat_name,splat_version); fprintf(fd," \n"); - fprintf(fd," SPLAT!\n"); + fprintf(fd," %s\n",splat_name); fprintf(fd," %s Transmitter Path Loss Overlay\n",xmtr[0].name); fprintf(fd," \n"); fprintf(fd," SPLAT! Path Loss Overlay\n"); @@ -3772,10 +4219,10 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c fprintf(fd," \n"); fprintf(fd," 128\n"); fprintf(fd," \n"); - fprintf(fd," %.5f\n",(double)max_north-one_pixel); - fprintf(fd," %.5f\n",(double)min_north); - fprintf(fd," %.5f\n",((double)min_west<180.0?(double)-min_west:360.0-(double)min_west)); - fprintf(fd," %.5f\n",(((double)max_west-one_pixel)<180.0?-((double)max_west-one_pixel):(360.0-(double)max_west-one_pixel))); + fprintf(fd," %.5f\n",north); + fprintf(fd," %.5f\n",south); + fprintf(fd," %.5f\n",east); + fprintf(fd," %.5f\n",west); fprintf(fd," 0.0\n"); fprintf(fd," \n"); fprintf(fd," \n"); @@ -3816,24 +4263,26 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c 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=(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; @@ -3860,11 +4309,9 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c 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 */ @@ -3876,7 +4323,7 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c cityorcounty=1; } - else if ((mask&4) && (kml==0)) + else if (mask&4) { /* County Boundaries: Black */ @@ -3887,7 +4334,7 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c 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); @@ -3937,9 +4384,11 @@ void WritePPMLR(char *filename, unsigned char geo, unsigned char kml, unsigned c } } - 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); @@ -4019,27 +4468,38 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c 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; x360.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); } @@ -4082,9 +4559,9 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c fprintf(fd,"\n"); fprintf(fd,"\n"); - fprintf(fd,"\n",splat_version); + fprintf(fd,"\n",splat_name,splat_version); fprintf(fd," \n"); - fprintf(fd," SPLAT!\n"); + fprintf(fd," %s\n",splat_name); fprintf(fd," %s Transmitter Coverage Overlay\n",xmtr[0].name); fprintf(fd," \n"); fprintf(fd," SPLAT! Signal Strength Overlay\n"); @@ -4094,10 +4571,10 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c fprintf(fd," \n"); fprintf(fd," 128\n"); fprintf(fd," \n"); - fprintf(fd," %.5f\n",(double)max_north-one_pixel); - fprintf(fd," %.5f\n",(double)min_north); - fprintf(fd," %.5f\n",((double)min_west<180.0?(double)-min_west:360.0-(double)min_west)); - fprintf(fd," %.5f\n",(((double)max_west-one_pixel)<180.0?-((double)max_west-one_pixel):(360.0-(double)max_west-one_pixel))); + fprintf(fd," %.5f\n",north); + fprintf(fd," %.5f\n",south); + fprintf(fd," %.5f\n",east); + fprintf(fd," %.5f\n",west); fprintf(fd," 0.0\n"); fprintf(fd," \n"); fprintf(fd," \n"); @@ -4138,24 +4615,26 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c 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=(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; @@ -4182,11 +4661,9 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c 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 */ @@ -4198,7 +4675,7 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c cityorcounty=1; } - else if ((mask&4) && (kml==0)) + else if (mask&4) { /* County Boundaries: Black */ @@ -4209,7 +4686,7 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c if (cityorcounty==0) { - if (dem[indx].signal[x0][y0]==0) + if (contour_threshold!=0 && signal=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) @@ -4354,66 +4833,501 @@ void WritePPMSS(char *filename, unsigned char geo, unsigned char kml, unsigned c 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; x360.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,"\n"); + fprintf(fd,"\n"); + fprintf(fd,"\n",splat_name,splat_version); + fprintf(fd," \n"); + fprintf(fd," %s\n",splat_name); + fprintf(fd," %s Transmitter Coverage Overlay\n",xmtr[0].name); + fprintf(fd," \n"); + fprintf(fd," SPLAT! Signal Power Level Overlay\n"); + fprintf(fd," SPLAT! Coverage\n"); + fprintf(fd," \n"); + fprintf(fd," %s\n",mapfile); + fprintf(fd," \n"); + fprintf(fd," 128\n"); + fprintf(fd," \n"); + fprintf(fd," %.5f\n",north); + fprintf(fd," %.5f\n",south); + fprintf(fd," %.5f\n",east); + fprintf(fd," %.5f\n",west); + fprintf(fd," 0.0\n"); + fprintf(fd," \n"); + fprintf(fd," \n"); + + for (x=0; x\n"); + fprintf(fd," %s\n",xmtr[x].name); + fprintf(fd," 1\n"); + fprintf(fd," \n"); + fprintf(fd," \n"); + fprintf(fd," 1\n"); + fprintf(fd," relativeToGround\n"); + fprintf(fd," %f,%f,%f\n",(xmtr[x].lon<180.0?-xmtr[x].lon:360.0-xmtr[x].lon), xmtr[x].lat, xmtr[x].alt); + fprintf(fd," \n"); + fprintf(fd," \n"); + } + + fprintf(fd," \n"); + fprintf(fd,"\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=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.level[z]) + match=z; + } + } + + if (match=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 && dBm0) + 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; xmaxheight) + maxheight=path.elevation[x]+clutter; + + if (path.elevation[x]0 && x0 && x0 && 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); } @@ -4426,21 +5340,21 @@ void GraphTerrain(struct site source, struct site destination, char *name) strncpy(ext,"ps\0",3); else if (strncmp(ext,"ps",2)==0) - strncpy(term,"postscript 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 @@ -4449,18 +5363,32 @@ void GraphTerrain(struct site source, struct site destination, char *name) 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); } @@ -4471,22 +5399,29 @@ void GraphTerrain(struct site source, struct site destination, char *name) 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; x0.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 (angle0 && 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); } @@ -4572,25 +5539,40 @@ void GraphElevation(struct site source, struct site destination, char *name) strncpy(ext,"ps\0",3); else if (strncmp(ext,"ps",2)==0) - strncpy(term,"postscript 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); @@ -4598,11 +5580,17 @@ void GraphElevation(struct site source, struct site destination, char *name) 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); } @@ -4610,25 +5598,27 @@ void GraphElevation(struct site source, struct site destination, char *name) fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n"); } -void GraphHeight(struct site source, struct site destination, char *name, 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); @@ -4638,13 +5628,13 @@ void GraphHeight(struct site source, struct site destination, char *name, double /* 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); @@ -4653,10 +5643,14 @@ void GraphHeight(struct site source, struct site destination, char *name, double } 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"); @@ -4675,7 +5669,7 @@ void GraphHeight(struct site source, struct site destination, char *name, double 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; @@ -4688,19 +5682,19 @@ void GraphHeight(struct site source, struct site destination, char *name, double * 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; @@ -4713,6 +5707,10 @@ void GraphHeight(struct site source, struct site destination, char *name, double if (metric) { fprintf(fd,"%f\t%f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*height); + + if (fd1!=NULL && x>0 && x0 && x=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot) { if (metric) { @@ -4742,8 +5744,8 @@ void GraphHeight(struct site source, struct site destination, char *name, double minheight=f_zone; } - if (height>maxheight) - maxheight=height; + if ((height+clutter)>maxheight) + maxheight=height+clutter; if (height=20.0) && (LR.frq_mhz<=20000.0) && fresnel_plot) { if (metric) { @@ -4797,48 +5799,53 @@ void GraphHeight(struct site source, struct site destination, char *name, double 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); } @@ -4851,7 +5858,7 @@ void GraphHeight(struct site source, struct site destination, char *name, double 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"); @@ -4880,18 +5887,18 @@ void GraphHeight(struct site source, struct site destination, char *name, double 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); @@ -4904,19 +5911,42 @@ void GraphHeight(struct site source, struct site destination, char *name, double 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); @@ -4924,18 +5954,24 @@ void GraphHeight(struct site source, struct site destination, char *name, double 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); } @@ -4969,6 +6005,18 @@ void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f, FILE *out 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. @@ -4989,7 +6037,7 @@ void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f, FILE *out 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. */ @@ -4999,23 +6047,23 @@ void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f, FILE *out 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); } } @@ -5061,40 +6109,40 @@ void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f, FILE *out 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); @@ -5118,19 +6166,20 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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) @@ -5138,8 +6187,8 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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) @@ -5194,10 +6243,10 @@ void PathReport(struct site source, struct site destination, char *name, char gr } 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); @@ -5217,7 +6266,7 @@ void PathReport(struct site source, struct site destination, char *name, char gr fprintf(fd2," angle to the first obstruction: %+.4f degrees\n",angle2); } - fprintf(fd2,"\n-------------------------------------------------------------------------\n\n"); + fprintf(fd2,"\n%s\n\n",dashes); /* Receiver */ @@ -5270,7 +6319,7 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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); @@ -5288,7 +6337,7 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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) { @@ -5349,19 +6398,43 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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); @@ -5370,10 +6443,16 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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; xcos_test_angle) + if (cos_xmtr_angle>=cos_test_angle) block=1; } @@ -5431,21 +6510,22 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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. */ @@ -5493,24 +6573,62 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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); @@ -5524,42 +6642,43 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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 @@ -5569,7 +6688,7 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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"); @@ -5577,7 +6696,7 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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)); @@ -5589,7 +6708,7 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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); @@ -5598,11 +6717,14 @@ void PathReport(struct site source, struct site destination, char *name, char gr 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); } @@ -5610,7 +6732,7 @@ void PathReport(struct site source, struct site destination, char *name, char gr fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n"); } - if (x!=-1) + if (x!=-1 && gpsav==0) unlink("profile.gp"); } @@ -5629,9 +6751,9 @@ void SiteReport(struct site xmtr) fd=fopen(report_name,"w"); - fprintf(fd,"\n\t--==[ SPLAT! v%s Site Analysis Report For: %s ]==--\n\n",splat_version,xmtr.name); + fprintf(fd,"\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) { @@ -5690,9 +6812,9 @@ void SiteReport(struct site xmtr) } } - 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) @@ -5725,7 +6847,10 @@ 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); } } @@ -5751,28 +6876,31 @@ 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); } } } -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) @@ -5780,7 +6908,7 @@ int LoadPLI(char *filename) sscanf(string,"%d, %d",&max_west, &min_west); - fgets(string,78,fd); + s=fgets(string,78,fd); pointer=strchr(string,';'); if (pointer!=NULL) @@ -5788,7 +6916,7 @@ int LoadPLI(char *filename) sscanf(string,"%d, %d",&max_north, &min_north); - fgets(string,78,fd); + s=fgets(string,78,fd); pointer=strchr(string,';'); if (pointer!=NULL) @@ -5799,19 +6927,64 @@ int LoadPLI(char *filename) 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); @@ -5846,7 +7019,7 @@ void WriteKML(struct site source, struct site destination) fprintf(fd,"\n"); fprintf(fd,"\n"); - fprintf(fd,"\n",splat_version); + fprintf(fd,"\n",splat_name, splat_version); fprintf(fd,"\n"); fprintf(fd,"SPLAT! Path\n"); fprintf(fd,"1\n"); @@ -5906,7 +7079,6 @@ void WriteKML(struct site source, struct site destination) fprintf(fd,"
%s West
\n",dec2dms(destination.lon)); - if (metric) fprintf(fd,"
%.2f km",distance*KM_PER_MILE); else @@ -6004,7 +7176,7 @@ void WriteKML(struct site source, struct site destination) 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; } @@ -6036,39 +7208,48 @@ void WriteKML(struct site source, struct site destination) fflush(stdout); } -int main(char argc, char *argv[]) +int main(int argc, char *argv[]) { int x, y, z=0, min_lat, min_lon, max_lat, max_lon, rxlat, rxlon, txlat, txlon, west_min, west_max, north_min, north_max; unsigned char coverage=0, LRmap=0, 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"); @@ -6079,7 +7260,7 @@ int main(char argc, char *argv[]) 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"); @@ -6088,20 +7269,40 @@ int main(char argc, char *argv[]) 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; @@ -6111,27 +7312,37 @@ int main(char argc, char *argv[]) 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++) { @@ -6187,6 +7398,19 @@ int main(char argc, char *argv[]) } } + 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; @@ -6211,7 +7435,7 @@ int main(char argc, char *argv[]) map=1; } - if (strcmp(argv[x],"-u")==0) + if (strcmp(argv[x],"-udt")==0) { z=x+1; @@ -6237,18 +7461,8 @@ int main(char argc, char *argv[]) { 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) @@ -6295,6 +7509,9 @@ int main(char argc, char *argv[]) if (strcmp(argv[x],"-metric")==0) metric=1; + if (strcmp(argv[x],"-gpsav")==0) + gpsav=1; + if (strcmp(argv[x],"-geo")==0) geo=1; @@ -6302,7 +7519,7 @@ int main(char argc, char *argv[]) kml=1; if (strcmp(argv[x],"-nf")==0) - nf=1; + fresnel_plot=0; if (strcmp(argv[x],"-ngs")==0) ngs=1; @@ -6310,6 +7527,9 @@ int main(char argc, char *argv[]) if (strcmp(argv[x],"-n")==0) nolospath=1; + if (strcmp(argv[x],"-dbm")==0) + dbm=1; + if (strcmp(argv[x],"-N")==0) { nolospath=1; @@ -6422,14 +7642,14 @@ int main(char argc, char *argv[]) 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) @@ -6445,20 +7665,20 @@ int main(char argc, char *argv[]) } } - 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); } } @@ -6488,7 +7708,7 @@ int main(char argc, char *argv[]) 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) { @@ -6514,6 +7734,7 @@ int main(char argc, char *argv[]) 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 @@ -6525,12 +7746,12 @@ int main(char argc, char *argv[]) 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 and/or from string */ @@ -6559,9 +7780,10 @@ int main(char argc, char *argv[]) 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; x0.0) + if (LonDiff(txlon,max_lon)>=0.0) max_lon=txlon; } @@ -6627,11 +7863,10 @@ int main(char argc, char *argv[]) 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); @@ -6653,21 +7888,20 @@ int main(char argc, char *argv[]) /* 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 @@ -6675,6 +7909,9 @@ int main(char argc, char *argv[]) switch (MAXPAGES) { + case 1: deg_limit=0.125; + break; + case 2: deg_limit=0.25; break; @@ -6684,16 +7921,26 @@ int main(char argc, char *argv[]) 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 */ @@ -6731,7 +7978,7 @@ int main(char argc, char *argv[]) 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; } @@ -6750,90 +7997,92 @@ int main(char argc, char *argv[]) { 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; x1) - 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 { @@ -6889,9 +8139,9 @@ int main(char argc, char *argv[]) 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); } @@ -6899,24 +8149,21 @@ int main(char argc, char *argv[]) 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); } } } @@ -6926,10 +8173,10 @@ int main(char argc, char *argv[]) for (x=0; x