Imported Upstream version 1.1.1
[debian/splat] / utils / srtm2sdf.c
diff --git a/utils/srtm2sdf.c b/utils/srtm2sdf.c
new file mode 100644 (file)
index 0000000..a12ee35
--- /dev/null
@@ -0,0 +1,586 @@
+/************************************************************\
+ **      Created originally by Jonathan Naylor, G4KLX      **
+ **     Later embellished by John Magliacane, KD2BD to     **
+ **     detect and handle voids found in the SRTM data     **
+ ************************************************************
+ **                    Compile like this:                  **
+ **      cc -Wall -O3 -s -lbz2 srtm2sdf.c -o srtm2sdf      **
+ **              Last modification: 18-Mar-2006            **
+\************************************************************/ 
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <bzlib.h>
+
+#define BZBUFFER 65536
+
+char sdf_filename[25], sdf_path[255], replacement_flag, opened=0;
+int srtm[1201][1201], usgs[1200][1200], max_north, max_west,
+    min_north, min_west, merge=0, min_elevation, bzerror;
+
+int ReadSRTM(char *filename)
+{
+       int x, y, infile, byte, bytes_read;
+       unsigned char error, buffer[2];
+       char north[3], west[4], *base=NULL;
+
+       if (strstr(filename, ".zip")!=NULL)
+       {
+               fprintf(stderr, "*** Error: \"%s\" must be uncompressed\n",filename);
+               return -1;
+
+       }
+
+       if (strstr(filename, ".hgt")==NULL)
+       {
+               fprintf(stderr, "*** Error: \"%s\" does not have the correct extension (.hgt)\n",filename);
+               return -1;
+       }
+
+       base=strrchr(filename, '/');
+       
+       if (base==NULL)
+               base=filename;
+       else
+               base+=1;
+
+       north[0]=base[1];
+       north[1]=base[2];
+       north[2]=0;
+
+       west[0]=base[4];
+       west[1]=base[5];
+       west[2]=base[6];
+       west[3]=0;
+
+       if ((base[0]!='N' && base[0]!='S') || (base[3]!='W' && base[3]!='E'))
+       {
+               fprintf(stderr, "*** Error: \"%s\" doesn't look like a valid SRTM filename.\n", filename);
+               return -1;
+       }
+
+       max_west=atoi(west);
+
+       if (base[3]=='E')
+               max_west=360-max_west;
+
+       min_west=max_west-1;
+
+       if (max_west==360)
+               max_west=0;
+
+       if (base[0]=='N')
+               min_north=atoi(north);
+       else
+               min_north=-atoi(north);
+
+       max_north=min_north+1;
+
+       infile=open(filename, O_RDONLY);
+
+       if (infile==0)
+       {
+               fprintf(stderr, "*** Error: Cannot open \"%s\"\n", filename);
+               return -1;
+       }
+
+       read(infile,&buffer,2);
+
+       if ((buffer[0]=='P') && (buffer[1]=='K'))
+       {
+               fprintf(stderr, "*** Error: \"%s\" still appears to be compressed!\n",filename);
+               close(infile);
+               return -1;
+       }
+
+       lseek(infile,0L,SEEK_SET);
+
+       sprintf(sdf_filename, "%d:%d:%d:%d.sdf", min_north, max_north, min_west, max_west);
+
+       error=0;
+       replacement_flag=0;
+
+       printf("Reading %s... ", filename);
+       fflush(stdout);
+
+       for (x=0; (x<1201 && error==0); x++)
+               for (y=0; (y<1201 && error==0); y++)
+               {
+                       bytes_read=read(infile,&buffer,2);
+
+                       if (bytes_read==2)
+                       {
+                               byte=buffer[1]+(buffer[0]<<8);
+
+                               if (buffer[0]&128)
+                                       byte-=0x10000;
+
+                               /* Flag problem elevations here */
+
+                               if (byte<=min_elevation)
+                                       replacement_flag=1;
+
+                               srtm[x][y]=byte;
+                       }
+
+                       else
+                               error=1;
+               }
+
+       if (error)
+       {
+               fprintf(stderr,"\n*** Error: Premature EOF detected while reading \"%s\"!  :-(\n",filename);
+               return -1;
+       }
+
+       close(infile);
+
+       return 0;
+}
+
+int LoadSDF_SDF(char *name)
+{
+       /* This function reads uncompressed
+          SPLAT Data Files (.sdf) into memory. */
+
+       int x, y, dummy;
+       char sdf_file[255], path_plus_name[255];
+       FILE *infile;
+
+       for (x=0; name[x]!='.' && name[x]!=0 && x<250; x++)
+               sdf_file[x]=name[x];
+
+       sdf_file[x]='.';
+       sdf_file[x+1]='s';
+       sdf_file[x+2]='d';
+       sdf_file[x+3]='f';
+       sdf_file[x+4]=0;
+
+       strncpy(path_plus_name,sdf_path,255);
+       strncat(path_plus_name,sdf_file,255);
+
+       infile=fopen(path_plus_name,"rb");
+
+       if (infile==NULL)
+               return 0;
+
+       fscanf(infile,"%d", &dummy);
+       fscanf(infile,"%d", &dummy);
+       fscanf(infile,"%d", &dummy);
+       fscanf(infile,"%d", &dummy);
+
+       printf("\nReading %s... ",path_plus_name);
+       fflush(stdout);
+
+       for (x=0; x<1200; x++)
+               for (y=0; y<1200; y++)
+                       fscanf(infile,"%d",&usgs[x][y]);
+
+       fclose(infile);
+
+       return 1;
+}
+
+char *BZfgets(BZFILE *bzfd, unsigned length)
+{
+       /* This function returns at most one less than 'length' number
+          of characters from a bz2 compressed file whose file descriptor
+          is pointed to by *bzfd.  In operation, a buffer is filled with
+          uncompressed data (size = BZBUFFER), which is then parsed
+          and doled out as NULL terminated character strings every time
+          this function is invoked.  A NULL string indicates an EOF
+          or error condition. */
+
+       static int x, y, nBuf;
+       static char buffer[BZBUFFER+1], output[BZBUFFER+1];
+       char done=0;
+
+       if (opened!=1 && bzerror==BZ_OK)
+       {
+               /* First time through.  Initialize everything! */
+
+               x=0;
+               y=0;
+               nBuf=0;
+               opened=1;
+               output[0]=0;
+       }
+
+       do
+       {
+               if (x==nBuf && bzerror!=BZ_STREAM_END && bzerror==BZ_OK && opened)
+               {
+                       /* Uncompress data into a static buffer */
+
+                       nBuf=BZ2_bzRead(&bzerror, bzfd, buffer, BZBUFFER);
+                       buffer[nBuf]=0;
+                       x=0;
+               }
+
+               /* Build a string from buffer contents */
+
+               output[y]=buffer[x];
+
+               if (output[y]=='\n' || output[y]==0 || y==(int)length-1)
+               {
+                       output[y+1]=0;
+                       done=1;
+                       y=0;
+               }
+
+               else
+                       y++;
+               x++;
+
+       } while (done==0);
+
+       if (output[0]==0)
+               opened=0;
+
+       return (output);
+}
+
+int LoadSDF_BZ(char *name)
+{
+       /* This function reads .bz2 compressed
+          SPLAT Data Files into memory. */
+
+       int x, y, dummy;
+       char sdf_file[255], path_plus_name[255];
+       FILE *fd;
+       BZFILE *bzfd;
+
+       for (x=0; name[x]!='.' && name[x]!=0 && x<247; x++)
+               sdf_file[x]=name[x];
+
+       sdf_file[x]='.';
+       sdf_file[x+1]='s';
+       sdf_file[x+2]='d';
+       sdf_file[x+3]='f';
+       sdf_file[x+4]='.';
+       sdf_file[x+5]='b';
+       sdf_file[x+6]='z';
+       sdf_file[x+7]='2';
+       sdf_file[x+8]=0;
+
+       strncpy(path_plus_name,sdf_path,255);
+       strncat(path_plus_name,sdf_file,255);
+
+       fd=fopen(path_plus_name,"rb");
+       bzfd=BZ2_bzReadOpen(&bzerror,fd,0,0,NULL,0);
+
+       if (fd!=NULL && bzerror==BZ_OK)
+       {
+               printf("\nReading %s... ",path_plus_name);
+               fflush(stdout);
+
+               sscanf(BZfgets(bzfd,255),"%d",&dummy);
+               sscanf(BZfgets(bzfd,255),"%d",&dummy);
+               sscanf(BZfgets(bzfd,255),"%d",&dummy);
+               sscanf(BZfgets(bzfd,255),"%d",&dummy);
+       
+               for (x=0; x<1200; x++)
+                       for (y=0; y<1200; y++)
+                               sscanf(BZfgets(bzfd,20),"%d",&usgs[x][y]);
+
+               fclose(fd);
+
+               BZ2_bzReadClose(&bzerror,bzfd);
+
+               return 1;
+       }
+
+       else
+               return 0;
+}
+
+char LoadSDF(char *name)
+{
+       /* This function loads the requested SDF file from the filesystem.
+          First, it tries to invoke the LoadSDF_SDF() function to load an
+          uncompressed SDF file (since uncompressed files load slightly
+          faster).  Failing that, it tries to load a compressed SDF file
+          by invoking the LoadSDF_BZ() function. */
+
+       int return_value=-1;
+
+       /* Try to load an uncompressed SDF first. */
+
+       return_value=LoadSDF_SDF(name);
+
+       /* If that fails, try loading a compressed SDF. */
+
+       if (return_value==0 || return_value==-1)
+               return_value=LoadSDF_BZ(name);
+
+       return return_value;
+}
+
+int ReadUSGS()
+{
+       char usgs_filename[15];
+
+       /* usgs_filename is a minimal filename ("40:41:74:75").
+          Full path and extentions are added later though
+          subsequent function calls. */
+
+       sprintf(usgs_filename, "%d:%d:%d:%d", min_north, max_north, min_west, max_west);
+
+       return (LoadSDF(usgs_filename));
+}
+
+void average_terrain(x,y,z)
+int x, y, z;
+{
+       long accum;
+       int temp=0, count, bad_value;
+       double average;
+
+       bad_value=srtm[x][y];
+
+       accum=0L;
+       count=0;
+
+       if (x!=0)
+       {
+               temp=srtm[x-1][y];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if (x!=1201)
+       {
+               temp=srtm[x+1][y];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if ((x!=0) && (y!=1201))
+       {
+               temp=srtm[x-1][y+1];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if (y!=1201)
+       {
+               temp=srtm[x][y+1];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if ((x!=1201) && (y!=1201))
+       {
+               temp=srtm[x+1][y+1];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if ((x!=0) && (y!=0))
+       {
+               temp=srtm[x-1][y-1];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if (y!=0)
+       {
+               temp=srtm[x][y-1];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if ((x!=1201) && (y!=0))
+       {
+               temp=srtm[x+1][y-1];
+
+               if (temp>bad_value)
+               {
+                       accum+=temp;
+                       count++;
+               }
+       }
+
+       if (count!=0)
+       {
+               average=(((double)accum)/((double)count));
+               temp=(int)(average+0.5);
+       }
+
+       if (temp>min_elevation)
+               srtm[x][y]=temp;
+       else
+               srtm[x][y]=min_elevation;
+}
+
+void WriteSDF(char *filename)
+{
+       int x, y, byte, last_good_byte=0;
+       FILE *outfile;
+
+       printf("\nWriting %s... ", filename);
+       fflush(stdout);
+
+       outfile=fopen(filename,"wb");
+
+       fprintf(outfile, "%d\n%d\n%d\n%d\n", max_west, min_north, min_west, max_north);
+
+       for (x=1200; x>0; x--)
+               for (y=1200; y>0; y--)
+               {
+                       byte=srtm[x][y];
+
+                       if (byte>min_elevation)
+                               last_good_byte=byte;
+
+                       if (byte<min_elevation)
+                       {
+                               if (merge)
+                                       fprintf(outfile,"%d\n",usgs[1200-x][1200-y]);
+                               else
+                                       {
+                                               average_terrain(x,y,last_good_byte);
+                                               fprintf(outfile,"%d\n",srtm[x][y]);
+                                       }
+                       }
+                       else
+                               fprintf(outfile,"%d\n",byte);
+               }
+
+       printf("Done!\n");
+
+       fclose(outfile);
+}
+
+int main(int argc, char **argv)
+{
+       int x, y, z=0;
+       char *env=NULL, string[255];
+       FILE *fd;
+
+       if (argc==1 || (argc==2 && strncmp(argv[1],"-h",2)==0))
+       {
+               fprintf(stderr, "\nsrtm2sdf: Generates SPLAT! elevation data files from unzipped SRTM-3\nelevation data files, and replaces SRTM data voids with elevation\ndata from existing SDF files.\n\n");
+               fprintf(stderr, "\tAvailable Options...\n\n");
+               fprintf(stderr, "\t-d directory path of existing .sdf files\n\t   (overrides path in ~/.splat_path file)\n\n");
+               fprintf(stderr, "\t-n elevation (in meters) below which SRTM data\n\t   is replaced by existing SDF data (default=0)\n\n");
+
+               fprintf(stderr, "Examples: srtm2sdf N40W074.hgt\n");
+               fprintf(stderr, "          srtm2sdf -d /cdrom/sdf N40W074.hgt\n");
+               fprintf(stderr, "          srtm2sdf -d /dev/null N40W074.hgt  (prevents data replacement)\n");
+               fprintf(stderr, "          srtm2sdf -n -5 N40W074.hgt\n\n");
+
+               return 1;
+       }
+
+       y=argc-1;
+
+       min_elevation=0;
+
+       for (x=1, z=0; x<=y; x++)
+       {
+               if (strcmp(argv[x],"-d")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0] && argv[z][0]!='-')
+                               strncpy(sdf_path,argv[z],253);
+               }
+
+               if (strcmp(argv[x],"-n")==0)
+               {
+                       z=x+1;
+
+                       if (z<=y && argv[z][0])
+                       {
+                               sscanf(argv[z],"%d",&min_elevation);
+
+                               if (min_elevation<-32768)
+                                       min_elevation=0;
+                       }                        
+               }
+       }
+
+       /* If no SDF path was specified on the command line (-d), check
+          for a path specified in the $HOME/.splat_path file.  If the
+          file is not found, then sdf_path[] remains NULL, and a data
+          merge will not be attempted if voids are found in the SRTM file. */
+
+       if (sdf_path[0]==0)
+       {
+               env=getenv("HOME");
+
+               sprintf(string,"%s/.splat_path",env);
+
+               fd=fopen(string,"r");
+
+               if (fd!=NULL)
+               {
+                       fgets(string,253,fd);
+
+                       /* Remove <CR> and/or <LF> from string */
+
+                       for (x=0; string[x]!=13 && string[x]!=10 && string[x]!=0 && x<253; x++);
+                       string[x]=0;
+
+                       strncpy(sdf_path,string,253);
+
+                       fclose(fd);
+               }
+       }
+
+       /* Ensure a trailing '/' is present in sdf_path */
+
+       if (sdf_path[0])
+       {
+               x=strlen(sdf_path);
+
+               if (sdf_path[x-1]!='/' && x!=0)
+               {
+                       sdf_path[x]='/';
+                       sdf_path[x+1]=0;
+               }
+       }
+
+       if (ReadSRTM(argv[z+1])==0)
+       {
+               if (replacement_flag && sdf_path[0])
+                       merge=ReadUSGS();
+
+               WriteSDF(sdf_filename);
+       }
+
+       return 0;
+}
+