+ /* This function generates a topographic map in Portable Pix Map
+ (PPM) format based on the signal strength values held in the
+ signal[][] array. The image created is rotated counter-clockwise
+ 90 degrees from its representation in dem[][] so that north
+ points up and east points right in the image generated. */
+
+ char mapfile[255], geofile[255], kmlfile[255], color=0;
+ unsigned width, height, terrain, red, green, blue;
+ unsigned char found, mask, cityorcounty;
+ int indx, x, y, z=1, x0, y0, signal, level, hundreds,
+ tens, units, match, colorwidth;
+ double lat, lon, one_pixel, conversion, one_over_gamma;
+ FILE *fd;
+
+ one_pixel=1.0/1200.0;
+ one_over_gamma=1.0/GAMMA;
+ conversion=255.0/pow((double)(max_elevation-min_elevation),one_over_gamma);
+
+ width=(unsigned)(1200*ReduceAngle(max_west-min_west));
+ height=(unsigned)(1200*ReduceAngle(max_north-min_north));
+
+ LoadSignalColors(xmtr[0]);
+
+ if (filename[0]==0)
+ strncpy(filename, xmtr[0].filename,254);
+
+ for (x=0; filename[x]!='.' && filename[x]!=0 && x<250; x++)
+ {
+ mapfile[x]=filename[x];
+ geofile[x]=filename[x];
+ kmlfile[x]=filename[x];
+ }
+
+ mapfile[x]='.';
+ geofile[x]='.';
+ kmlfile[x]='.';
+ mapfile[x+1]='p';
+ geofile[x+1]='g';
+ kmlfile[x+1]='k';
+ mapfile[x+2]='p';
+ geofile[x+2]='e';
+ kmlfile[x+2]='m';
+ mapfile[x+3]='m';
+ geofile[x+3]='o';
+ kmlfile[x+3]='l';
+ mapfile[x+4]=0;
+ geofile[x+4]=0;
+ kmlfile[x+4]=0;
+
+ if (geo && kml==0)
+ {
+ fd=fopen(geofile,"wb");
+
+ fprintf(fd,"FILENAME\t%s\n",mapfile);
+ fprintf(fd,"#\t\tX\tY\tLong\t\tLat\n");
+ fprintf(fd,"TIEPOINT\t0\t0\t%d.000\t\t%d.000\n",(max_west<180?-max_west:360-max_west),max_north);
+ fprintf(fd,"TIEPOINT\t%u\t%u\t%d.000\t\t%.3f\n",width-1,height+29,(min_west<180?-min_west:360-min_west),(double)(min_north-0.025));
+ fprintf(fd,"IMAGESIZE\t%u\t%u\n",width,height+30);
+ fprintf(fd,"#\n# Auto Generated by SPLAT! v%s\n#\n",splat_version);
+
+ fclose(fd);
+ }
+
+ if (kml && geo==0)
+ {
+ fd=fopen(kmlfile,"wb");
+
+ fprintf(fd,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(fd,"<kml xmlns=\"http://earth.google.com/kml/2.1\">\n");
+ fprintf(fd,"<!-- Generated by SPLAT! Version %s -->\n",splat_version);
+ fprintf(fd," <Folder>\n");
+ fprintf(fd," <name>SPLAT!</name>\n");
+ fprintf(fd," <description>%s Transmitter Coverage Overlay</description>\n",xmtr[0].name);
+ fprintf(fd," <GroundOverlay>\n");
+ fprintf(fd," <name>SPLAT! Signal Strength Overlay</name>\n");
+ fprintf(fd," <description>SPLAT! Coverage</description>\n");
+ fprintf(fd," <Icon>\n");
+ fprintf(fd," <href>%s</href>\n",mapfile);
+ fprintf(fd," </Icon>\n");
+ fprintf(fd," <opacity>128</opacity>\n");
+ fprintf(fd," <LatLonBox>\n");
+ fprintf(fd," <north>%.5f</north>\n",(double)max_north-one_pixel);
+ fprintf(fd," <south>%.5f</south>\n",(double)min_north);
+ fprintf(fd," <east>%.5f</east>\n",((double)min_west<180.0?(double)-min_west:360.0-(double)min_west));
+ fprintf(fd," <west>%.5f</west>\n",(((double)max_west-one_pixel)<180.0?-((double)max_west-one_pixel):(360.0-(double)max_west-one_pixel)));
+ fprintf(fd," <rotation>0.0</rotation>\n");
+ fprintf(fd," </LatLonBox>\n");
+ fprintf(fd," </GroundOverlay>\n");
+
+ for (x=0; x<txsites; x++)
+ {
+ fprintf(fd," <Placemark>\n");
+ fprintf(fd," <name>%s</name>\n",xmtr[x].name);
+ fprintf(fd," <visibility>1</visibility>\n");
+ fprintf(fd," <Style>\n");
+ fprintf(fd," <IconStyle>\n");
+ fprintf(fd," <Icon>\n");
+ fprintf(fd," <href>root://icons/palette-5.png</href>\n");
+ fprintf(fd," <x>224</x>\n");
+ fprintf(fd," <y>224</y>\n");
+ fprintf(fd," <w>32</w>\n");
+ fprintf(fd," <h>32</h>\n");
+ fprintf(fd," </Icon>\n");
+ fprintf(fd," </IconStyle>\n");
+ fprintf(fd," </Style>\n");
+ fprintf(fd," <Point>\n");
+ fprintf(fd," <extrude>1</extrude>\n");
+ fprintf(fd," <altitudeMode>relativeToGround</altitudeMode>\n");
+ fprintf(fd," <coordinates>%f,%f,%f</coordinates>\n",(xmtr[x].lon<180.0?-xmtr[x].lon:360.0-xmtr[x].lon), xmtr[x].lat, xmtr[x].alt);
+ fprintf(fd," </Point>\n");
+ fprintf(fd," </Placemark>\n");
+ }
+
+ fprintf(fd," </Folder>\n");
+ fprintf(fd,"</kml>\n");
+
+ fclose(fd);
+ }
+
+ fd=fopen(mapfile,"wb");
+
+ fprintf(fd,"P6\n%u %u\n255\n",width,(kml?height:height+30));
+ fprintf(stdout,"\nWriting \"%s\" (%ux%u pixmap image)... ",mapfile,width,(kml?height:height+30));
+ fflush(stdout);
+
+ for (y=0, lat=(double)max_north-one_pixel; y<(int)height; y++, lat=(double)max_north-(one_pixel*(double)y))
+ {
+ for (x=0, lon=(double)max_west-one_pixel; x<(int)width; x++, lon=(double)max_west-(one_pixel*(double)x))
+ {
+ if (lon<0.0)
+ lon+=360.0;
+
+ for (indx=0, found=0; indx<MAXPAGES && found==0;)
+ if (lat>=(double)dem[indx].min_north && lat<(double)dem[indx].max_north && LonDiff(lon,(double)dem[indx].min_west)>=0.0 && LonDiff(lon,(double)dem[indx].max_west)<0.0)
+ found=1;
+ else
+ indx++;
+
+ if (found)
+ {
+ x0=(int)(1199.0*(lat-floor(lat)));
+ y0=(int)(1199.0*(lon-floor(lon)));
+
+ mask=dem[indx].mask[x0][y0];
+ signal=(dem[indx].signal[x0][y0])-100;
+ cityorcounty=0;
+
+ match=255;
+
+ red=0;
+ green=0;
+ blue=0;
+
+ if (signal>=region.level[0])
+ match=0;
+ else
+ {
+ for (z=1; (z<region.levels && match==255); z++)
+ {
+ if (signal<region.level[z-1] && signal>=region.level[z])
+ match=z;
+ }
+ }
+
+ if (match<region.levels)
+ {
+ red=region.color[match][0];
+ green=region.color[match][1];
+ blue=region.color[match][2];
+
+ color=1;
+ }
+
+ if ((mask&2) && (kml==0))
+ {
+ /* Text Labels: Red or otherwise */
+
+ if (red>=180 && green<=75 && blue<=75)
+ fprintf(fd,"%c%c%c",255^red,255^green,255^blue);
+ else
+ fprintf(fd,"%c%c%c",255,0,0);
+
+ cityorcounty=1;
+ }
+
+ else if ((mask&4) && (kml==0))
+ {
+ /* County Boundaries: Black */
+
+ fprintf(fd,"%c%c%c",0,0,0);
+
+ cityorcounty=1;
+ }
+
+ if (cityorcounty==0)
+ {
+ if (dem[indx].signal[x0][y0]==0)
+ {
+ if (ngs)
+ fprintf(fd,"%c%c%c",255,255,255);
+ else
+ {
+ /* Display land or sea elevation */
+
+ if (dem[indx].data[x0][y0]==0)
+ fprintf(fd,"%c%c%c",0,0,170);
+ else
+ {
+ terrain=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
+ fprintf(fd,"%c%c%c",terrain,terrain,terrain);
+ }
+ }
+ }
+
+ else
+ {
+ /* Plot field strength regions in color */
+
+ if (red!=0 || green!=0 || blue!=0)
+ fprintf(fd,"%c%c%c",red,green,blue);
+
+ else /* terrain / sea-level */
+ {
+ if (ngs)
+ fprintf(fd,"%c%c%c",255,255,255);
+ else
+ {
+ if (dem[indx].data[x0][y0]==0)
+ fprintf(fd,"%c%c%c",0,0,170);
+ else
+ {
+ /* Elevation: Greyscale */
+ terrain=(unsigned)(0.5+pow((double)(dem[indx].data[x0][y0]-min_elevation),one_over_gamma)*conversion);
+ fprintf(fd,"%c%c%c",terrain,terrain,terrain);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ else
+ {
+ /* We should never get here, but if */
+ /* we do, display the region as black */
+
+ fprintf(fd,"%c%c%c",0,0,0);
+ }
+ }
+ }
+
+ if (kml==0 && color)
+ {
+ /* Display legend along bottom of image */
+
+ colorwidth=(int)rint((float)width/(float)region.levels);
+
+ for (y0=0; y0<30; y0++)
+ {
+ for (x0=0; x0<(int)width; x0++)
+ {
+ indx=x0/colorwidth;
+ x=x0%colorwidth;
+ level=region.level[indx];
+
+ hundreds=level/100;
+
+ if (hundreds>0)
+ level-=(hundreds*100);
+
+ tens=level/10;
+
+ if (tens>0)
+ level-=(tens*10);
+
+ units=level;
+
+ if (y0>=8 && y0<=23)
+ {
+ if (hundreds>0)
+ {
+ if (x>=5 && x<=12)
+ if (fontdata[16*(hundreds+'0')+(y0-8)]&(128>>(x-5)))
+ indx=255;
+ }
+
+ if (tens>0 || hundreds>0)
+ {
+ if (x>=13 && x<=20)
+ if (fontdata[16*(tens+'0')+(y0-8)]&(128>>(x-13)))
+ indx=255;
+ }
+
+ if (x>=21 && x<=28)
+ if (fontdata[16*(units+'0')+(y0-8)]&(128>>(x-21)))
+ indx=255;
+
+ if (x>=36 && x<=43)
+ if (fontdata[16*('d')+(y0-8)]&(128>>(x-36)))
+ indx=255;
+
+ if (x>=44 && x<=51)
+ if (fontdata[16*('B')+(y0-8)]&(128>>(x-44)))
+ indx=255;
+
+ if (x>=52 && x<=59)
+ if (fontdata[16*('u')+(y0-8)]&(128>>(x-52)))
+ indx=255;
+
+ if (x>=60 && x<=67)
+ if (fontdata[16*('V')+(y0-8)]&(128>>(x-60)))
+ indx=255;
+
+ if (x>=68 && x<=75)
+ if (fontdata[16*('/')+(y0-8)]&(128>>(x-68)))
+ indx=255;
+
+ if (x>=76 && x<=83)
+ if (fontdata[16*('m')+(y0-8)]&(128>>(x-76)))
+ indx=255;
+ }
+
+ if (indx>region.levels)
+ fprintf(fd,"%c%c%c",0,0,0);
+ else
+ {
+ red=region.color[indx][0];
+ green=region.color[indx][1];
+ blue=region.color[indx][2];
+
+ fprintf(fd,"%c%c%c",red,green,blue);
+ }
+ }
+ }
+ }
+
+ fclose(fd);
+ fprintf(stdout,"Done!\n");
+ fflush(stdout);
+}
+
+void GraphTerrain(struct site source, struct site destination, char *name)
+{
+ /* This function invokes gnuplot to generate an appropriate
+ output file indicating the terrain profile between the source
+ and destination locations. "filename" is the name assigned
+ to the output file generated by gnuplot. The filename extension