/* EarthView Copyright Jean-Pierre Demailly Released under the LGPL GenEarth displays a color map of the Earth, using info from topographic/bathymetric or population data. It can also convert or compress these data in various forms. This program is published without any warranty */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct { int data, w_data, h_data; char *name; double lon1, lon2, lat1, lat2; } record; Display * dpy = NULL; Visual * visual; Colormap cmap; GC gc; Atom wm_delete_window, wm_protocols; int scr; int depth; Window root, win; Pixmap pixmap; Pixel black, white, *pix=NULL; /* input modes */ enum {UNDEF=-1, POP=0, ALT, AZ2, PZ2, CPS, GTOPO30, MIXED }; /* output modes */ enum {RAW=0, PACK, STAT, PPM, XWIN }; int verbose=0; int input=UNDEF, output=XWIN; int header_data=0, header_out=1, aspect=1, listheader=0, num_scheme=1; int w_data, h_data, im_data, jm_data, xm_data, ym_data; int width, height; int x_orig, y_orig, rectangle=0; int new_colors=1; int num_cps; double londata1, londata2, latdata1, latdata2; double lat1, lat2, lon1, lon2; double lonbak1, lonbak2, latbak1=120.0, latbak2; double gamma_f, speed = 2.0; char **buf_out=NULL; record *cps=NULL; /* Default Digital Elevation Model file */ char *default_alt_file; char *default_pop_file; char *data_dir = NULL; char *data_file = NULL; char *cps_file, *cps_dir; FILE *fd = NULL; gzFile *gzd = NULL; /* Predefined color schemes */ /* You can of course add as many as you like... */ char *color_scheme_alt[] = { /* Topography color schemes */ "-11000,0x000080,0,0x80C0FF,1,0x008000,200,0x00FF00,400,0xBBBB00,1000,0xFFFF00,2000,0xFF9000,3000,0xAA6000,3750,0x994000,4200,0x882000,4500,0x771000,5000,0x660000,8000,0x000000", "-11000,0x000080,0,0x80C0FF,1,0x00AA00,200,0x00FF00,400,0xFFFF00,800,0xFF9000,1200,0xAE00AE,2000,0xA0A0A0,8000,0xFFFFFF", "-11000,0x000080,0,0x80C0FF,1,0x008000,200,0x00FF00,400,0xFFFF00,1000,0xFF9000,2000,0xAE20AE,3000,0xAE00AE,5000,0x61009E,9000,0x230046", "-11000,0x000080,0,0x80C0FF,1,0x00AA00,200,0x00FF00,400,0xFFFF00,800,0xFF9000,1200,0xD000D0,2000,0xB0A0B0,2500,0xA080A0,4000,0x808080,8000,0x000000" }; char *color_scheme_pop[] = { /* Population color schemes */ "-12000,0x80C0FF,-1,0x80C0FF,0,0xFFD7A6,1280,0xFF96AE,2560,0xCFCFCF,3840,0x9E9E9E,5120,0xAE69AE,6400,0xAE20AE,7680,0xAE00AE,8960,0x61009E,10240,0x230046", "-12000,0x80C0FF,-1,0x80C0FF,0,0xFFFF7F,2560,0x7FFF7F,5120,0x7F7F7F,7680,0xFF007F,10240,0xFF0000" }; char *range = NULL; int max_scheme_alt, max_scheme_pop; int endian_data, endian_out, min_alt, max_alt; double invcosphi = 1.0, min_den, max_den; short int ocean_bit=0, in_ocean=0; /* Red, Green, Blue values */ unsigned char *red=NULL, *green=NULL, *blue=NULL; /* Deta files for GTOPO30 */ char * gtopo30_blocks[] = { "W180N90.DEM", "W140N90.DEM", "W100N90.DEM", "W060N90.DEM", "W020N90.DEM", "E020N90.DEM", "E060N90.DEM", "E100N90.DEM", "E140N90.DEM", "W180N40.DEM", "W140N40.DEM", "W100N40.DEM", "W060N40.DEM", "W020N40.DEM", "E020N40.DEM", "E060N40.DEM", "E100N40.DEM", "E140N40.DEM", "W180S10.DEM", "W140S10.DEM", "W100S10.DEM", "W060S10.DEM", "W020S10.DEM", "E020S10.DEM", "E060S10.DEM", "E100S10.DEM", "E140S10.DEM", "W180S60.DEM", "W120S60.DEM", "W060S60.DEM", "W000S60.DEM", "E060S60.DEM", "E120S60.DEM" }; FILE *gfd[33]; void usage() { printf("\n" "GenEarth displays a color map of the Earth, using info from\n" "topographic/bathymetric or population data. It can also convert or\n" "compress these data in various forms.\n\n" "Usage: earthview [-help] [-verbose] [-population]\n" " [-nointerp] [-noaspect] [-listheader] [-oceanbit]\n" " [-w width] [-h height] [-wdata width] [-hdata height]\n" " [-lon val1 val2] [-lat val1 val2]\n" " [-londata val1 val2] [-latdata val1 val2]\n" " [-scheme num] [-range i1,color1,i2,color2...]\n" " [-data {pop|alt|az2|pz2|gtopo30|gtopo30+}]\n" " [-endian {data+|data-|out+|out-}]\n" " [-header {data+|data-|out+|out-}]\n" " [-output {xwin|raw|ppm|stat}]\n" " [-pack num1 num2] [-gamma value(0.0...2.0)]\n" " [-datadir directory] [-file filename] [> outfile.xxx]\n" "There are %d predefined color schemes (-scheme 1,..,-scheme %d)\n" "for topographic data, and %d schemes for the density of population.\n" "Color specifications should be in the RGB hexadecimal form 0xUVWXYZ\n" "The color range is meant to specify density colors for\n" "i=-12000,...i=+12000, indices i1,i2,... should therefore be in\n" "that interval.\n" "GenEarth automatically interpolates the other color values.\n\n", max_scheme_alt, max_scheme_alt, max_scheme_pop); exit(0); } int nfread(FILE * fd) { unsigned char c; int n; c = fgetc(fd); if (feof(fd)) return -1; n = c; c = fgetc(fd); if (feof(fd)) return -1; n = (n<<8) | c; c = fgetc(fd); if (feof(fd)) return -1; n = (n<<8) | c; c = fgetc(fd); if (feof(fd)) return -1; n = (n<<8) | c; return n; } int ngzread(gzFile *gzd) { unsigned char c; int n; c = gzgetc(gzd); if (gzeof(gzd)) return -2; n = c; c = gzgetc(gzd); if (gzeof(gzd)) return -2; n = (n<<8) | c; c = gzgetc(gzd); if (gzeof(gzd)) return -2; n = (n<<8) | c; c = gzgetc(gzd); if (gzeof(gzd)) return -2; n = (n<<8) | c; return n; } void nprintf(FILE * fo, int n) { fprintf(fo, "%c", (n>>24) & 0xFF); fprintf(fo, "%c", (n>>16) & 0xFF); fprintf(fo, "%c", (n>>8) & 0xFF); fprintf(fo, "%c", n & 0xFF); } #define NOVALUE -12000 int read_input(int i) { double den; int n; int ip, j, k, l, u, v, x, y, xp, yp, s1, s2; unsigned char c1, c2, c3; char *buf_in; unsigned int destlen; if ((input|1)==PZ2) { x = i%w_data; y = i/w_data; u = x/xm_data; v = y/ym_data; xp = x%xm_data; yp = y%ym_data; k = u+v*im_data; /* allocate new output buffer if this is not yet done */ if (!buf_out[k]) { /* before that, free all buffers that are no longer needed */ if (v>0 && buf_out[k-im_data]) { for (l=0; lmax_alt) max_alt = n; in_ocean = c1>>7; return n; } else { l = 3*(xp + yp*xm_data); /* I've decided that PZ2 is always smallendian !! */ c1 = buf_out[k][l]; c2 = buf_out[k][l+1]; c3 = buf_out[k][l+2]; k = (int)((c1<<16) | (c2<<8) | c3); if (output<=PACK) return k; if (c1==255) return NOVALUE; den = ((double)k)*invcosphi; if (denmax_den) max_den = den; n = (int) (913.036*(log(den+40)-3.6888)); if (n>10240) n=10240; return n; } } if (input>=GTOPO30) { x = i%43200; y = i/43200; if (y<18000) { u = x/4800; v = y/6000; j = u+9*v; xp = x-u*4800; yp = y-v*6000; ip = xp+yp*4800; } else { u = x/7200; j = 27+u; xp = x-u*7200; yp = y-18000; ip = xp+yp*7200; } fseek(gfd[j], 2*ip, SEEK_SET); if (feof(gfd[j])) return NOVALUE; c1 = fgetc(gfd[j]); if (feof(gfd[j])) return NOVALUE; c2 = fgetc(gfd[j]); n = (c1<<8) | c2; if (n&0x8000) n |= 0xFFFF0000; if (nmax_alt) max_alt = n; /* This corrects a bug of GTOPO30 */ if (y==21599) { n = read_input(x+(x==0)+(y-1)*43200); return n; } else if (x==0 && y>=18000) { n = read_input(1+y*43200); return n; } /* end of GTOPO30 bug fix */ in_ocean = (n==-9999); if (in_ocean && input==MIXED) { /* We start reading in ETOPO2 for bathymetry */ int n1, n2, n3, n4, xpp, ypp; double fx, fy; input = ALT; xp = x/4; fx = 0.25*(x%4); xpp = xp+1; if (xpp==10800) xpp=0; yp = y/4; fy = 0.25*(y%4); ypp = yp+1; if (ypp==5400) ypp=5399; n1 = read_input(xp+yp*10800); n2 = read_input(xpp+yp*10800); n3 = read_input(xp+ypp*10800); n4 = read_input(xpp+ypp*10800); n = (int)((1.0-fy)*((1.0-fx)*n1+fx*n2)+fy*((1.0-fx)*n3+fx*n4)-0.5); input = MIXED; } return n; } if (input==ALT) { gzseek(gzd, 2*i+header_data, SEEK_SET); if (gzeof(gzd)) return NOVALUE; if (endian_data) { c2 = gzgetc(gzd); if (gzeof(gzd)) return NOVALUE; c1 = gzgetc(gzd); } else { c1 = gzgetc(gzd); if (gzeof(gzd)) return NOVALUE; c2 = gzgetc(gzd); } n = (c1<<8) | c2; /* high bit might be "ocean bit"; next bit is, in any case, sign bit */ n = n&0x7FFF; if (n&0x4000) n |= 0xFFFF8000; if (nmax_alt) max_alt = n; in_ocean = c1>>7; return n; } if (input==POP) { gzseek(gzd, 3*i+header_data, SEEK_SET); if (gzeof(gzd)) return NOVALUE; if (endian_data) { c3 = gzgetc(gzd); if (gzeof(gzd)) return NOVALUE; c2 = gzgetc(gzd); if (gzeof(gzd)) return NOVALUE; c1 = gzgetc(gzd); } else { c1 = gzgetc(gzd); if (gzeof(gzd)) return NOVALUE; c2 = gzgetc(gzd); if (gzeof(gzd)) return NOVALUE; c3 = gzgetc(gzd); } k = (int)((c1<<16) | (c2<<8) | c3); if (output<=PACK) return k; if (c1==255) return NOVALUE; den = ((double)k)*invcosphi; if (denmax_den) max_den = den; n = (int) (913.036*(log(den+40)-3.6888)); if (n>10240) n=10240; } return n; } void do_output(int n, int x, int y) { char c1, c2, c3; int l; if (output==XWIN) { XSetForeground(dpy, gc, pix[n+12000]); XDrawPoint(dpy, win, gc, x, y); XDrawPoint(dpy, pixmap, gc, x, y); } else if (output==PPM) { if (n<-12000 || n>12000) { fprintf(stderr, "Strange value %d\n!!!", n); printf("%c%c%c", 0, 0, 0); } else { l = n+12000; printf("%c%c%c", red[l], green[l], blue[l]); } } else if (output==RAW && endian_out==0) { if (input==POP || input==PZ2) { if (n<0) n = 0xFF0000; c1 = (n & 0xFF0000)>>16; c2 = (n & 0xFF00)>>8; c3 = n & 0xFF; printf("%c%c%c", c1, c2, c3); } else { c1 = (n & 0xFF00)>>8; if (ocean_bit) { if (in_ocean) c1 |= 0x80; else c1 &= 0x7F; } c2 = n & 0xFF; printf("%c%c", c1, c2); } } else if (output==RAW && endian_out==1) { if (input==POP || input==PZ2) { if (n<0) n = 0xFF0000; c1 = (n & 0xFF0000)>>16; c2 = (n & 0xFF00)>>8; c3 = n & 0xFF; printf("%c%c%c", c3, c2, c1); } else { c1 = (n & 0xFF00)>>8; if (ocean_bit) { if (in_ocean) c1 |= 0x80; else c1 &= 0x7F; } c2 = n & 0xFF; printf("%c%c", c2, c1); } } } void init_colors(char *range) { int i, j, k, boo; char *ptr1, *ptr2; unsigned int col; unsigned char c1, c2, c3, u, v; double f; if (!range) { if (input==POP || input==PZ2) { if (num_scheme>max_scheme_pop) num_scheme = max_scheme_pop; range = strdup(color_scheme_pop[num_scheme-1]); } else { if (num_scheme>max_scheme_alt) num_scheme = max_scheme_alt; range = strdup(color_scheme_alt[num_scheme-1]); } } if (verbose) fprintf(stderr, "Computing color range (scheme %s%d)...\n", ((input==POP||input==PZ2)?"POP":"ALT"), num_scheme); ptr1 = ptr2 = range; if (!red) red = (unsigned char *)malloc(24002*sizeof(unsigned char)); if (!green) green = (unsigned char *)malloc(24002*sizeof(unsigned char)); if (!blue) blue = (unsigned char *)malloc(24002*sizeof(unsigned char)); i = -1; boo = 1; begrange: while (*ptr2 && *ptr2!=',') ++ptr2; if (*ptr2==',') { *ptr2 = '\0'; j = atoi(ptr1)+12000; } else j = -1; if (j<0 || j>24000) { fprintf(stderr, "Erroneous color range !!\n\n"); exit(-1); } ++ptr2; ptr1 = ptr2; while (*ptr2 && *ptr2!=',') ++ptr2; if (!*ptr2) boo=0; *ptr2 = '\0'; sscanf(ptr1, "%x", &col); red[j] = col>>16; green[j] = (col>>8)&255; blue[j] = col&255; if (i==-1) { c1 = red[j]; c2 = green[j]; c3 = blue[j]; } else { c1 = red[i]; c2 = green[i]; c3 = blue[i]; } for (k=i+1; k1.0) { gamma_f = gamma_f - 1.0; for (k=0; k<=24000; k++) { red[k] = (unsigned char) ((1.0-gamma_f)*red[k]+gamma_f*255.0+0.5); green[k] = (unsigned char) ((1.0-gamma_f)*green[k]+gamma_f*255.0+0.5); blue[k] = (unsigned char) ((1.0-gamma_f)*blue[k]+gamma_f*255.0+0.5); } gamma_f = gamma_f + 1.0; } if (verbose) fprintf(stderr, "colors[-12000...12000] written to palette.\n\n"); if (output==XWIN) { if (!pix) pix = (Pixel *)malloc(24002*sizeof(Pixel)); if (verbose) fprintf(stderr, "Indexing colors for the X Window system\n"); for (k=0; k<=24000; k++) { if (verbose && k%500==0) { fprintf(stderr, "[%d]", k); if ((k%500)%10==9) fprintf(stderr, "\n"); else fprintf(stderr, " "); } if (depth>=24) pix[k] = (red[k]<<16) | (green[k]<<8) | blue[k]; else if (depth==16) { u = (blue[k]&248)>>3 | (green[k]&28)<<3; v = (green[k]&224)>>5 | (red[k]&248); pix[k] = (v<<8)|u; } else if (depth==15) { u = (blue[k]&248)>>3 | (green[k]&56)<<2; v = (green[k]&192)>>6 | (red[k]&248)>>1; pix[k] = (v<<8)|u; } } if (verbose) fprintf(stderr, "\n\n"); } new_colors = 0; } void correct_aspect() { double ratio, center_w, center_h, fw, fh; if (!aspect) return; ratio = sqrt(((double)width)*(lat2-lat1)/(((double)height)*(lon2-lon1))/ cos(M_PI*(lat1+lat2)/360.0)); center_w = 0.5*(lon1+lon2); center_h = 0.5*(lat1+lat2); fw = 0.5*(lon2-lon1)*ratio; fh = 0.5*(lat2-lat1)/ratio; lon1 = center_w-fw; lon2 = center_w+fw; lat1 = center_h-fh; lat2 = center_h+fh; while (lon1>180.0) { lon1 -= 360.00; lon2 -= 360.00; } while (lon1<-180.0) { lon1 += 360.00; lon2 += 360.00; } } Bool evpred(d, e, a) Display * d; XEvent * e; XPointer a; { return (True); } void save_latlon() { lonbak1 = lon1; lonbak2 = lon2; latbak1 = lat1; latbak2 = lat2; } int manage_event(XEvent event) { double f, cor; int i; if (event.type == VisibilityNotify || event.type == Expose) { XSetWindowBackgroundPixmap(dpy, win, pixmap); XClearWindow(dpy, win); XSync(dpy, True); return 0; } if ((event.xclient.message_type == wm_protocols && event.xclient.format == 32 && event.xclient.data.l[0] == wm_delete_window)) return 2; if (event.type == ConfigureNotify) { Window root; int i, j, x, y, w, h; unsigned int b, d; XGetGeometry(dpy, win, &root, &x, &y, &w, &h, &b, &d); if (w!=width && h!=height) { width = w; height = h; XFreePixmap(dpy, pixmap); pixmap = XCreatePixmap(dpy, win, width, height, depth); XSetForeground(dpy, gc, black); for (j=0; jwidth) return 0; if (event.xbutton.y<0 || event.xbutton.y>height) return 0; if (event.xbutton.x>x_orig) x=x_orig; else x=event.xbutton.x; if (event.xbutton.y>y_orig) y=y_orig; else y=event.xbutton.y; w = abs(event.xbutton.x-x_orig); h = abs(event.xbutton.y-y_orig); rectangle = 0; XClearWindow(dpy, win); center_x = lon1+(lon2-lon1)*((double)(x+w/2))/((double)width); center_y = lat2-(lat2-lat1)*((double)(y+h/2))/((double)height); if (w<=2 && h<=2) { if (event.xbutton.button!=3) return 0; /* click almost same point --> translate view rectangle */ fw = 0.5*(lon2-lon1); fh = 0.5*(lat2-lat1); } else { /* click other point --> zoom scene */ fw = 0.5*(lon2-lon1)*((double)w)/((double)width); fh = 0.5*(lat2-lat1)*((double)h)/((double)height); } save_latlon(); lon1 = center_x-fw; lon2 = center_x+fw; lat1 = center_y-fh; lat2 = center_y+fh; correct_aspect(); return 1; } if (event.type == MotionNotify && rectangle) { int x, y, w, h; XClearWindow(dpy, win); if (event.xbutton.x>x_orig) x=x_orig; else x=event.xbutton.x; if (event.xbutton.y>y_orig) y=y_orig; else y=event.xbutton.y; w = abs(event.xbutton.x-x_orig); h = abs(event.xbutton.y-y_orig); XSetForeground(dpy, gc, white); XDrawRectangle(dpy, win, gc, x, y, w, h); return 0; } if (event.type == KeyPress) { KeySym keysym; char buffer[1]; XLookupString((XKeyEvent *) &event, buffer, 1, &keysym, NULL); if (keysym==XK_BackSpace || keysym==XK_Delete) { if (latbak1>100.0) return 0; lon1 = lonbak1; lon2 = lonbak2; lat1 = latbak1; lat2 = latbak2; return 1; } if (((i=(int)(keysym-XK_0))>=1 && i<=9) || ((i=(int)(keysym-XK_KP_0))>=1 && i<=9)) { if (i==num_scheme) return 0; num_scheme = i; if (verbose) { fprintf(stderr, "Changing to color scheme %d...\n", num_scheme); } free(range); range = NULL; new_colors = 1; return 1; } if (keysym==XK_equal) { save_latlon(); lon1 = londata1; lon2 = londata2; lat1 = latdata1; lat2 = latdata2; return 1; } if (keysym==XK_Page_Up) { speed = speed*speed; return 0; } if (keysym==XK_Page_Down) { speed = sqrt(speed); return 0; } if (keysym==XK_c || keysym==XK_C) { if (cps && cps_file==default_alt_file) { data_file = default_pop_file; for (i=0; i2.0) gamma_f = 2.0; } else if (i= GTOPO30) { char *ptr1, *ptr2; w_data = 43200; h_data = 21600; ptr1 = strdup(data_file); ptr2 = index(ptr1, ':'); if (ptr2) { *ptr2 = '\0'; ++ptr2; } endian_data = 0; for (i=0; i<33; i++) { char fname[512]; sprintf(fname, "%s/%s", ptr1, gtopo30_blocks[i]); gfd[i] = fopen(fname, "r"); if (!gfd[i]) { fprintf(stderr, "Directory '%s' does not exist or\n" "File '%s' cannot be read !!\n\n", ptr1, fname); exit(-1); } } if (input==MIXED) { if (!ptr2) { fprintf(stderr, "etopo2 data missing!!\n"); exit(-1); } gzd = gzopen(ptr2, "r"); if (!gzd) { fprintf(stderr, "File '%s' cannot be read !!\n\n", ptr2); exit(-1); } header_data = 0; gzgets(gzd, buf_read, 255); if (!strncmp(buf_read, "@#!ALT", 6)) { i = 0; j = 1; do { gzgets(gzd, buf_read, 255); ++i; } while (i<=20 && !gzeof(gzd) && (j=strncmp(buf_read, "size:", 5))); if (j) { fprintf(stderr, "\nCouldn't find start of data section in '%s' !!\n", ptr2); exit(-1); } else { header_data = gztell(gzd); if (verbose) fprintf(stderr, "\nFound start of data section in '%s'\n" "after header of length %d ...\n", ptr2, header_data); } } } free(ptr1); goto processdata; } if (verbose) fprintf(stderr, "Opening file '%s' ...\n", data_file); gzd = gzopen(data_file, "r"); if (!gzd) { fprintf(stderr, "File '%s' cannot be read !!\n\n", data_file); exit(-1); } gzgets(gzd, buf_read, 255); i = UNDEF; if (!strncmp(buf_read, "@#!ALT", 6)) i = ALT; else if (!strncmp(buf_read, "@#!POP", 6)) i = POP; else if (!strncmp(buf_read, "@#!AZ2", 6)) i = AZ2; else if (!strncmp(buf_read, "@#!PZ2", 6)) i = PZ2; else if (!strncmp(buf_read, "@#!CPS", 6)) i = CPS; if (i!=UNDEF) { header_data = 1; if (input==UNDEF) input = i; else if (input!=i) { fprintf(stderr, "The specified data type doesn't match the actual data.\n" "Aborting!!\n"); exit(-1); } } if (input==UNDEF) { fprintf(stderr, "Cannot determine the data type: file %s has no legible header.\n" "You may try to set it manually with the option -data XXX\n" "Aborting!!\n", data_file); exit(-1); } if (input==AZ2 || input==PZ2) header_data = 1; if (input==CPS && !cps) { char data[10], name[220]; char *ptr; struct stat buf; /* composite data */ header_data = 0; cps_file = data_file; ptr = rindex(cps_file, '/'); if (ptr) { i = ptr-cps_file+1; cps_dir = (char *)malloc((i+1)*sizeof(char)); strncpy(cps_dir, cps_file, i); cps_dir[i] = '\0'; } else cps_dir = NULL; num_cps = 0; while (!gzeof(gzd)) { gzgets(gzd, buf_read, 255); if (!strncmp(buf_read, "%end", 4)) break; if (*buf_read=='%' || isspace(*buf_read)) continue; cps = realloc(cps, (num_cps+1)*sizeof(record)); i = sscanf(buf_read, "%s %d %d %s %lg %lg %lg %lg", data, &cps[num_cps].w_data, &cps[num_cps].h_data, name, &cps[num_cps].lon1, &cps[num_cps].lon2, &cps[num_cps].lat1, &cps[num_cps].lat2); if (i<8) { fprintf(stderr, "Incorrect syntax in %s :\n%s\n", data_file, buf_read); continue; } i = UNDEF; if (!strcasecmp(data, "ALT")) i = ALT; else if (!strcasecmp(data, "POP")) i = POP; else if (!strcasecmp(data, "AZ2")) i = AZ2; else if (!strcasecmp(data, "PZ2")) i = PZ2; else if (!strcasecmp(data, "GTOPO30")) i = GTOPO30; else if (!strcasecmp(data, "GTOPO30+")) i = MIXED; if (i==UNDEF) { fprintf(stderr, "Wrong data type definition in %s :\n%s\n", data_file, buf_read); continue; } if (*name=='/' || !cps_dir) /* path is absolute path or current directory is that of .cps file */ cps[num_cps].name = strdup(name); else { /* relative path */ cps[num_cps].name = malloc((strlen(name)+strlen(cps_dir)+1)*sizeof(char)); sprintf(cps[num_cps].name, "%s%s", cps_dir, name); } j = stat(cps[num_cps].name, &buf); if (j!=0 || !S_ISREG(buf.st_mode)) { if (verbose) fprintf(stderr, "!!cancelled: %s\n", cps[num_cps].name); free(cps[num_cps].name); continue; } if (verbose) fprintf(stderr, "%s", buf_read); cps[num_cps].data = i; ++num_cps; } if (num_cps==0) { fprintf(stderr, "Composite file %s contains no valid record.\n" "Aborting!!\n", data_file); exit(-1); } londata1 = cps[0].lon1; londata2 = cps[0].lon2; latdata1 = cps[0].lat1; latdata2 = cps[0].lat2; w_data = cps[0].w_data; h_data = cps[0].h_data; if (gzd) { gzclose(gzd); gzd = NULL; } } if (header_data) { if (verbose) fprintf(stderr, "\nReading header data from '%s'\n\n", data_file); if (verbose) fprintf(stderr, buf_read); /* print magic string */ gzgets(gzd, buf_read, 255); /* source (just for info) */ if (verbose) fprintf(stderr, buf_read); gzgets(gzd, buf_read, 255); /* reading lon/lat of data */ i = sscanf(buf_read, "lon/lat: %lg %lg %lg %lg", &londata1, &londata2, &latdata1, &latdata2); if (i<4) { fprintf(stderr, "Header of input data %s has incorrect lon/lat values:\n %s\n", data_file, buf_read); exit(-1); } if (verbose) fprintf(stderr, "lon/lat: %.4f %.4f %.4f %.4f\n", londata1, londata2, latdata1, latdata2); gzgets(gzd, buf_read, 255); /* reading w_data h_data */ i = sscanf(buf_read, "size: %d %d", &w_data, &h_data); if (i<2) { fprintf(stderr, "Header of input data %s has incorrect size:\n %s\n", data_file, buf_read); exit(-1); } if (verbose) fprintf(stderr, "size: %d %d\n", w_data, h_data); if (input == AZ2 || input == PZ2) { gzgets(gzd, buf_read, 255); /* reading im_data jm_data */ i = sscanf(buf_read, "pack: %d %d", &im_data, &jm_data); if (i<2) { fprintf(stderr, "Header of input data %s has incorrect pack values:\n %s\n", data_file, buf_read); exit(-1); } if (verbose) fprintf(stderr, "pack: %d %d\n", im_data, jm_data); header_data = gztell(gzd); gzclose(gzd); gzd = NULL; fd = fopen(data_file, "r"); xm_data = w_data/im_data; ym_data = h_data/jm_data; buf_out = (char **)realloc(buf_out, im_data*jm_data*sizeof(char *)); memset(buf_out, 0, im_data*jm_data*sizeof(char *)); } else header_data = gztell(gzd); } if (verbose && header_data) fprintf(stderr, "header length: %d\n\n", header_data); if (listheader) { if (fd) fclose(fd); if (gzd) gzclose(gzd); exit(0); } processdata: if (w_data==-1 || h_data==-1) { fprintf(stderr, "Dimensions (w=%d,h=%d) of input incorrectly specified !!\n", w_data, h_data); exit(-1); } if (w_data<=10 || h_data<=5) { fprintf(stderr, "data_file file '%s' seems to be corrupted !!\n", data_file); exit(-1); } if (londata1==londata2 || latdata1==latdata2) { fprintf(stderr, "Specified data region empty !!\n"); exit(-1); } if (lon1==lon2 || lat1==lat2) { fprintf(stderr, "Specified output region empty !!\n"); exit(-1); } if (londata1>londata2) { fcopy = londata1; londata1 = londata2; londata2 = fcopy; } if (latdata1>latdata2) { fcopy = latdata1; latdata1 = latdata2; latdata2 = fcopy; } if (lon1>lon2) { fcopy = lon1; lon1 = lon2; lon2 = fcopy; } if (lat1>lat2) { fcopy = lat1; lat1 = lat2; lat2 = fcopy; } if (lat1latdata2) lat2 = latdata2; while (lon1>180.0) { lon1 -= 360.00; lon2 -= 360.00; } while (lon1<-180.0) { lon1 += 360.00; lon2 += 360.00; } if (fabs(londata2-londata1-360.0)>1E-5) { if (lon1londata2) lon2 = londata2; } if (width==0 || height==0) { fcopy = (lon2-lon1)/(lat2-lat1); if (aspect) fcopy *= cos(M_PI*(lat1+lat2)/360.0); if (width==0 && height==0) { width = (int)(720 * sqrt(fcopy)+0.5); height = (int)(720 / sqrt(fcopy)+0.5); } else if (width!=0) height = (int) (width/fcopy+0.5); else if (height!=0) width = (int) (height*fcopy+0.5); } cpsinit: if (input==CPS && cps) { j = 0; for (i=0; i0 && i>0) --i; data_file = cps[i].name; input = cps[i].data; londata1 = cps[i].lon1; londata2 = cps[i].lon2; latdata1 = cps[i].lat1; latdata2 = cps[i].lat2; w_data = cps[i].w_data; h_data = cps[i].h_data; goto initialize; } dil_x = 0; dil_y = 0; alon = (lon2-lon1)*((double)w_data)/((double)width*(londata2-londata1)); blon = (lon1-londata1)*((double)w_data)/(londata2-londata1) + 0.0001; alat = (lat2-lat1)*((double)h_data)/((double)height*(latdata2-latdata1)); blat = (lat1-latdata1)*((double)h_data)/(latdata2-latdata1) - 0.0001; if (interp) { if (alon<0.99999) dil_x = 1; if (alat<0.99999) dil_y = 1; } if (output==XWIN && dpy==NULL) { dpy = XOpenDisplay(NULL); scr = DefaultScreen(dpy); visual = DefaultVisual(dpy, scr); root = DefaultRootWindow(dpy); black = BlackPixel(dpy, scr); white = WhitePixel(dpy, scr); gcv.foreground = black; gc = XCreateGC(dpy, root, GCForeground, &gcv); depth = DefaultDepth(dpy, scr); if (depth<=8) { fprintf(stderr, "Can't use X Window output in depth <= 8. Aborting!!\n"); exit(1); } else cmap = DefaultColormap(dpy, scr); win = XCreateSimpleWindow(dpy, root, 10, 10, width, height, 0, white, black); pixmap = XCreatePixmap(dpy, win, width, height, depth); for (j=0; jgreen_mask==992) depth = 15; wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); XSetWMProtocols(dpy, win, &wm_delete_window, 1); XSelectInput(dpy, win, KeyPressMask|VisibilityChangeMask|ExposureMask|PointerMotionMask| StructureNotifyMask|ButtonPressMask|ButtonReleaseMask); XMapWindow(dpy, win); XFlush(dpy); usleep(10000); } if (output==XWIN && dpy!=NULL) { XResizeWindow(dpy, win, width, height); XSync(dpy, True); } if (output==XWIN) { sprintf(title, "%s (lon %.2f %.2f / lat %.2f %.2f) scheme %d [%dx%d%s]", ((input==POP||input==PZ2)?"Population":"Topography"), lon1, lon2, lat1, lat2, num_scheme, w_data, h_data, ((dil_x || dil_y)?",i":"")); XStoreName(dpy, win, title); } if (new_colors) init_colors(range); if (verbose) { if (input==POP||input==PZ2) fprintf(stderr, "Reading population densities from '%s':\n", data_file); else fprintf(stderr, "Reading elevation values from '%s':\n", data_file); fprintf(stderr, " scanning %dx%d grid at resolution %dx%d (%s)\n", w_data, h_data, width, height, ((output==STAT)? "statistics only":"image output")); if (output!=STAT) fprintf(stderr, "Output image %dx%d : %.3f <= lon <= %.3f, " "%.3f <= lat <= %.3f\n", width, height, lon1, lon2, lat1, lat2); } max_alt = -12000; min_alt = 10000; min_den = 1E9; max_den = -12000.0; if (output==PACK) { int total, mode; FILE *fo; char *source, *dest; xm_out = width/im_out; ym_out = height/jm_out; if (xm_out*im_out!=width || ym_out*jm_out!=height) { fprintf(stderr, "Output size %dx%d not compatible with (%d,%d) packing\n" "Aborting!!\n", width, height, im_out, jm_out); exit(-1); } /* create all necessary buffers for the .bz2 chunks */ mode = (input==POP||input==PZ2); source = (unsigned char *) malloc((2+mode)*xm_out*ym_out*sizeof(unsigned char)); dest = (unsigned char *) malloc(((2+mode)*xm_out*ym_out+100)*sizeof(unsigned char)); if (!source || !dest) { fprintf(stderr, "Memory allocation failed!!\n"); exit(-1); } /* create output file */ sprintf(buf_read, "%dx%d-%dx%d.%s", width, height, im_out, jm_out, ((mode)? "pz2":"az2")); fo = fopen(buf_read, "w"); if (!fo) { fprintf(stderr, "File '%s' cannot be created\n", buf_read); exit(-1); } fprintf(stderr, "Writing file '%s' ...\n", buf_read); /* 8 char identification string for new formats "packed BZ2" */ if (mode) sprintf(buf_read, "%s", "@#!PZ2\n"); else sprintf(buf_read, "%s", "@#!AZ2\n"); fprintf(fo,"%s", buf_read); header_out = strlen(buf_read); sprintf(buf_read, "source: %dx%d, %s\n", w_data, h_data, data_file); fprintf(fo,"%s", buf_read); header_out += strlen(buf_read); sprintf(buf_read, "lon/lat: %.6f %.6f %.6f %.6f\n", lon1, lon2, lat1, lat2); fprintf(fo,"%s", buf_read); header_out += strlen(buf_read); sprintf(buf_read, "size: %d %d\n", width, height); fprintf(fo,"%s", buf_read); header_out += strlen(buf_read); sprintf(buf_read, "pack: %d %d\n", im_out, jm_out); fprintf(fo,"%s", buf_read); header_out += strlen(buf_read); /* this finishes the header of AZ2/PZ2 format */ /* just fill the addresses with zeroes as they are still unknown */ for (i=0; i<=im_out*jm_out; i++) nprintf(fo, total); if (verbose) fprintf(stderr, "Starting to pack %dx%d chunks of size %dx%d\n", im_out, jm_out, xm_out, ym_out); total = 0; for (j=0; j>16; ++l; source[l] = (alt & 0xFF00)>>8; ++l; source[l] = alt & 0xFF; ++l; } else for (x=0; x>8; if (ocean_bit) { if (in_ocean) source[l] |= 0x80; else source[l] &= 0x7F; } ++l; source[l] = alt & 0xFF; ++l; } } l = (2+mode)*xm_out*ym_out+100; k = BZ2_bzBuffToBuffCompress(dest, &l, source, (2+mode)*xm_out*ym_out, 9, 0, 30); if (k==BZ_OUTBUFF_FULL) { fprintf(stderr, "Bzip2 compression failed!! Bailing out...\n"); exit(-1); } /* write addresses of bz2 chunks immediately after header */ fseek(fo, header_out+4*(i+im_out*j), SEEK_SET); nprintf(fo, total); nprintf(fo, total+l); /* write .bz2 compressed buffer */ fseek(fo, header_out+4*(im_out*jm_out+1)+total, SEEK_SET); for (k=0; k " "%02x_%02x.bz2, size = %d, total = %d\n", i, j, i, j, l, total); } } fclose(fo); free(source); free(dest); exit(0); } /* write header output if required */ if (output==PPM) { printf("P6\n%d %d\n255\n", width, height); } else if (output==RAW && header_out) { if (input==POP || input==PZ2) printf("%s", "@#!POP\n"); else printf("%s", "@#!ALT\n"); printf("source: %dx%d, %s\n", w_data, h_data, data_file); printf("lon/lat: %.6f %.6f %.6f %.6f\n", lon1, lon2, lat1, lat2); printf("size: %d %d\n", width, height); } n_mem_alt = (int *)realloc(n_mem_alt, width*sizeof(int)); if (dil_y) o_mem_alt = (int *)realloc(o_mem_alt, width*sizeof(int)); i = 0; yp = -1; for (y=-dil_y; y=h_data) yp = h_data-1; } else { fyp = (double)(h_data-1)-(double)(height-1-y)*alat-blat; n_yp = (int)fyp; fyp = fyp-(double)n_yp; n_yp = n_yp+dil_y; if (n_yp<0) n_yp=0; if (n_yp>=h_data) n_yp = h_data-1; if (dil_y) { if (n_yp==yp) { for (x=0; x