#ifndef lint static char *sccsid = "@(#)xmgndisp.c MgnAlt 1.13 (MIT/CSR) 5/13/93"; #endif lint /* Function: Display MIDR or GxDR image in X window System: Magellan Altimetry Data Reduction Phase: UTIL Module: xmgndisp.c Revision: 1.13 Date: 5/13/93 Author: Created: Mon Dec 9 11:44:07 EST 1991 Control: SCCS */ #include #include #include #include #include #include #include #include #define APP_CLASS "/usr/lib/X11/app-defaults/Xmgndisp" #define UNINIT (1.e20) #define OK(d) ((d)<(UNINIT/2)) #define MIN(x,y) ((x)<(y)?(x):(y)) #define MAX(x,y) ((x)>(y)?(x):(y)) #define VENUS_RADIUS 6051000 /* ** Default resource values */ #define DFT_BORDER 2 #define DFT_CMAPDIR "/usr/gips/lib/cmap" #define DFT_EXPAND 1 #define DFT_FONT "fixed" #define DFT_INSERT 0 #define DFT_NZOOM 4 #define DFT_ZOOM 1 #define R_BOOL 0 /* boolean resource value */ #define R_INUM 1 /* int resource value */ #define R_DNUM 2 /* double resource value */ #define R_STR 3 /* string resource value */ /* ** XrmParseCommand stuff */ XrmOptionDescRec opTable[] = { { "-Cmapdir", "*colormapdir", XrmoptionSepArg, (caddr_t) NULL }, { "-borderwidth","*borderwidth",XrmoptionSepArg, (caddr_t) NULL }, { "-browse", "*browse", XrmoptionNoArg, (caddr_t) "True" }, { "-colormap", "*colormap", XrmoptionSepArg, (caddr_t) NULL }, { "-display", "*display", XrmoptionSepArg, (caddr_t) NULL }, { "-expand", "*expand", XrmoptionSepArg, (caddr_t) NULL }, { "-fn", "*font", XrmoptionSepArg, (caddr_t) NULL }, { "-font", "*font", XrmoptionSepArg, (caddr_t) NULL }, { "-geometry", "*geometry", XrmoptionSepArg, (caddr_t) NULL }, { "-help", "*help", XrmoptionNoArg, (caddr_t) "True" }, { "-highvalue", "*highvalue", XrmoptionSepArg, (caddr_t) NULL }, { "-insertloc", "*insertloc", XrmoptionSepArg, (caddr_t) NULL }, { "-lowvalue", "*lowvalue", XrmoptionSepArg, (caddr_t) NULL }, { "-match", "*match", XrmoptionNoArg, (caddr_t) "True" }, { "-nzoom", "*zoomfact", XrmoptionResArg, (caddr_t) NULL }, { "-palette", "*palette", XrmoptionSepArg, (caddr_t) NULL }, { "-shift", "*shift", XrmoptionSepArg, (caddr_t) NULL }, { "-swap", "*swap", XrmoptionNoArg, (caddr_t) "True" }, { "-verbose", "*verbose", XrmoptionNoArg, (caddr_t) "True" }, { "-xrm", NULL, XrmoptionResArg, (caddr_t) NULL }, { "-zoomloc", "*zoomloc", XrmoptionResArg, (caddr_t) NULL }, }; /* ** Command-line parameters */ Usage(cmd) char *cmd; { printf("Usage:\t%s [-browse] [-match] [-verbose]\n", cmd); printf("\t[-borderwidth ] [-colormap ]\n"); printf("\t[-Cmapdir ] [-display ]\n"); printf("\t[-expand ] [-fn ] [-font ]\n"); printf("\t[-geometry ] [-help] [-highvalue ]\n"); printf("\t[-insertloc ] [-lowvalue ]\n"); printf("\t[-nzoom ] [-palette ] [-shift ]\n"); printf("\t[-swap] [-xrm ] [-zoomloc ]\n"); printf("\t[vicar-file]\n"); exit(0); } /* ** Resource values */ char *inFile; /* name of input file */ char *inShortFile; /* short input file name */ char *pCmdName; /* argv[0] value */ int bFlag; /* -browse: browse image */ int nBorder = DFT_BORDER; /* -borderwidth: all borders */ double fExpand = DFT_EXPAND; /* -expand: expansion factor */ double maxValue = UNINIT; /* -highvalue: high DN value */ double minValue = UNINIT; /* -lowvalue: low DN value */ int nFlag; /* -match: exact colors */ int nStrip; /* -shift: pixel shift factor */ int sFlag; /* -swap: swap pixel bytes */ int vFlag; /* -verbose: verbose mode */ int nZoom = DFT_NZOOM; /* zoom insert factor */ int butType = DFT_INSERT; /* button insert location */ int zoomType = DFT_ZOOM; /* zoom insert location */ /* ** General X11 stuff */ Display *theDisp; /* display device */ int theScreen; /* display screen */ Visual *theVisual; /* display visual */ GC theGC; /* graphic object */ Window rootWin; /* root window */ XFontStruct *mfInfo; /* text font */ XrmDatabase resDB; /* merged resources */ /* ** Main image window */ Window imWin; /* xmgndisp image window */ XImage *retImage; /* original image */ char *pRetImage; /* image pixels */ int iWidth; /* retained image width */ int iHeight; /* retained image height */ int inType; /* image type from VICAR */ XImage *expImage; /* displayed image */ int eWidth; /* displayed image width */ int eHeight; /* displayed image height */ int noExpose; /* don't expose after resize */ /* ** Colormap */ unsigned long fColor; /* foreground color */ unsigned long bColor; /* background color */ Colormap theCmap; /* display colormap */ XColor defColor[256]; /* Xcolor entries used */ unsigned long indxColor[256]; /* color lookup table */ char usedColor[256]; /* pixels used */ int nColors; /* displayed colors */ int nCells; /* number of color cells */ unsigned int rgbIndex[3][256]; /* colormap intensities */ /* ** Sub-window parameters */ Window butWin; /* button output window */ int bWidth; /* button text offsets */ int bHeight; /* button text height */ char bText[3][80]; /* button text strings */ int curLoc[2]; /* cursor loc in retImage */ Window zoomWin; /* zoom insert window */ XImage *zoomImage; /* zoom insert image */ char cBuf[4096]; /* conversion buffer */ extern char *getenv(); /* C library */ extern char *malloc(); /* C library */ /* ** Start here */ main(argc, argv) char *argv[]; { XEvent theEvent; parseArgs(argc, argv); readColormap(); openDisplay(); loadVicarFile(&inType); if (nFlag) setExactColors(); else setShiftedColors(); setDisplay(); while (1) { XNextEvent(theDisp, &theEvent); handleEvent(&theEvent); } } /* ** parse command-line arguments */ parseArgs(argc, argv) int argc; char *argv[]; { char *c; XrmDatabase cmdDB; /* parse command arguments */ XrmInitialize(); XrmParseCommand(&resDB, opTable, sizeof(opTable)/sizeof(opTable[0]), pCmdName = argv[0], &argc, argv); /* get input file pathname */ if (argc < 2) inFile = "'stdin'"; else if (argc == 2 && argv[1][0] != '-') inFile = argv[1]; else Usage(pCmdName); /* user asking for help? */ if (getRsrc(&argc, R_BOOL, "xmgndisp.help", "Xmgndisp.Help")) Usage(pCmdName); /* try to open the display */ if (!getRsrc(&c, R_STR, "xmgndisp.display", "Xmgndisp.Display")) c = NULL; if (! (theDisp = XOpenDisplay(c))) error("Can't open display: %s", XDisplayName(c)); /* merge other resources */ cmdDB = resDB; resDB = XrmGetFileDatabase(APP_CLASS); if (c = XResourceManagerString(theDisp)) XrmMergeDatabases(XrmGetStringDatabase(c), &resDB); else { sprintf(cBuf, "%s/%s", getenv("HOME"), "./Xdefaults"); XrmMergeDatabases(XrmGetFileDatabase(cBuf), &resDB); } c = getenv("XENVIRONMENT"); sprintf(cBuf, "%s/.Xdefaults-", c ? c : getenv("HOME")); gethostname(cBuf+strlen(cBuf), sizeof(cBuf)-strlen(cBuf)); XrmMergeDatabases(XrmGetFileDatabase(cBuf), &resDB); XrmMergeDatabases(cmdDB, &resDB); /* get numeric and flag resource values */ (void)getRsrc(&bFlag, R_BOOL, "xmgndisp.browse", "Xmgndisp.Browse"); (void)getRsrc(&fExpand, R_DNUM, "xmgndisp.expand", "Xmgndisp.Expand"); (void)getRsrc(&maxValue, R_DNUM, "xmgndisp.highvalue", "Xmgndisp.HighValue"); (void)getRsrc(&minValue, R_DNUM, "xmgndisp.lowvalue", "Xmgndisp.LowValue"); (void)getRsrc(&nFlag, R_BOOL, "xmgndisp.match", "Xmgndisp.Match"); (void)getRsrc(&nStrip, R_INUM, "xmgndisp.shift", "Xmgndisp.Shift"); (void)getRsrc(&sFlag, R_BOOL, "xmgndisp.swap", "Xmgndisp.Swap"); (void)getRsrc(&vFlag, R_BOOL, "xmgndisp.verbose", "Xmgndisp.Verbose"); (void)getRsrc(&nZoom, R_INUM, "xmgndisp.zoomfact", "Xmgndisp.ZoomFact"); getInsertType(&butType, "xmgndisp.insertloc", "Xmgndisp.Insertloc"); getInsertType(&zoomType, "xmgndisp.zoomloc", "Xmgndisp.Zoomloc"); /* verify numerics */ if (fExpand <= 0 || fExpand > 16) error("bad -expand value", ""); if (nStrip < 0 || nStrip > 7) error("bad -strip value: %d", (char *)nStrip); /* get name of input file */ inShortFile = (c = rindex(inFile, '/')) ? c+1 : inFile; } /* ** Copy colormap file entries to rgbIndex[][] */ readColormap() { char *cFile; /* colormap file */ char *cmapDir; /* colormap directory */ char aName[256]; /* colormap file name */ FILE *pAfile; /* colormap file stream */ int nColor = 0; /* color index */ int pFlag = 0; /* =1 if palette format */ char aFileBuf[256]; /* colormap line buffer */ char *mapFmt = " %d %d %d"; /* file line format */ char *pBuf; /* line buffer pointer */ int i; /* scratch */ /* initialize colors to grey */ for (i = 0; i < 256; i++) rgbIndex[0][i] = rgbIndex[1][i] = rgbIndex[2][i] = i; /* get palette or colormap file name and open it */ if (getRsrc(&cFile, R_STR, "xmgndisp.palette", "Xmgndisp.Palette") && (pAfile = fopen(strcpy(aName, cFile), "r"))) pFlag++; else if (!getRsrc(&cFile, R_STR, "xmgndisp.colormap", "Xmgndisp.Colormap")) return; else if ((pAfile = fopen(strcpy(aName, cFile), "r")) == NULL) { if (!getRsrc(&cmapDir, R_STR, "xmgndisp.colormapdir", "Xmgndisp.Colormapdir")) cmapDir = DFT_CMAPDIR; sprintf(aName, "%s/%s", cmapDir, cFile); pAfile = fopen(aName, "r"); } if (!pAfile) perror(aName), exit(1); /* read colormap file lines */ while (fgets(pBuf = aFileBuf, sizeof(aFileBuf)-1, pAfile)) { while (isspace(*pBuf)) pBuf++; if (! pFlag) { /* ignore comments */ if (! *pBuf || *pBuf == '#') continue; mapFmt = " %d %d %d"; i = nColor; } else if (sscanf(pBuf, " %d", &i) != 1 || i < 0 || i > 255) error("bad palette index: %s", pBuf); else mapFmt = " %*d %d %d %d"; /* line should contail 0 <= red, green, blue <= 255 */ if (sscanf(pBuf, mapFmt, &rgbIndex[0][i], &rgbIndex[1][i], &rgbIndex[2][i]) != 3) error("bad colormap entry: %s", pBuf); nColor++; } (void)fclose(pAfile); if (!pFlag && nColor < 256) error("%s: insufficient colormap entries", aName); } /* ** Save generic display variables */ openDisplay() { theScreen = DefaultScreen(theDisp); theCmap = DefaultColormap(theDisp, theScreen); rootWin = RootWindow(theDisp, theScreen); theGC = DefaultGC(theDisp, theScreen); bColor = WhitePixel(theDisp, theScreen); fColor = BlackPixel(theDisp, theScreen); theVisual = DefaultVisual(theDisp, theScreen); nCells = DisplayCells(theDisp, theScreen); if (nCells <= 2) error("program requires color display", ""); } /* ** Try to allocate all colors used by full-size image. ** If any cannot be allocated, use nearest values. */ setExactColors() { XColor cTable[256]; /* default color table */ int nDefColors; /* colors to find */ int nDist; /* color difference metric */ int minDist; /* minimum color difference */ int minColor; /* closest color index */ int i, j; /* scratch */ if (! (i = defineColors(0xff, 0))) return; if (vFlag) /* failed to pull it off */ fprintf(stderr, "can't allocate %d colors out of %d.\n", i, nColors); nDefColors = MIN(nCells, 256); /* read in the default color table */ for (i = 0; i < nDefColors; i++) cTable[i].pixel = i; XQueryColors(theDisp, theCmap, cTable, nDefColors); for (i = 0; i < 256; i++) { if (! usedColor[i] || indxColor[i] != 0xffff) continue; minDist = 100000; minColor = -1; for (j = 0; j < nDefColors; j++) { nDist = abs(rgbIndex[0][i]-(cTable[j].red >> 8)) + abs(rgbIndex[1][i]-(cTable[j].green >> 8)) + abs(rgbIndex[2][i]-(cTable[j].blue >> 8)); if (nDist < minDist) /* locate nearest color */ minDist = nDist, minColor = j; } if (minColor < 0) error("cannot allocate colors", ""); defColor[i] = defColor[minColor]; indxColor[i] = cTable[minColor].pixel; } } /* ** Try to allocate all colors. If not successful, ** mask least significant bit and try again. */ setShiftedColors() { int i; /* scratch */ int iStrip; /* bit shift index */ for (iStrip = nStrip; iStrip < 8; iStrip++) { /* try to allocate subset of all colors */ if (! (i = defineColors((0xff << iStrip) & 0xff, 1))) break; while (--i >= 0) /* free all colors allocated above */ if (usedColor[i]) XFreeColors(theDisp, theCmap, &indxColor[i], 1, 0L); } if (iStrip == 8) { if (vFlag) /* give up and use default color table */ fprintf(stderr, "can't allocate desired colors.\n"); for (i = 0; i < 256; i++) indxColor[i] = i; } else if (vFlag && iStrip != nStrip) fprintf(stderr, "%s: stripped %d bits\n", inShortFile,iStrip); } /* ** Initialize the main image window */ setDisplay() { XSetWindowAttributes xSwa; /* window attributes */ unsigned int xSwaMask; /* mask for xSwa */ XSizeHints sHints; /* window sizes */ char *geomStr; /* geometry variable */ char *drawFont; /* drawing font */ char iBuf[9]; /* icon title */ char *pChar; /* text pointer */ int geomMask; /* -geometry flags */ int xWin = 0; /* -geometry field */ int yWin = 0; /* -geometry field */ int wWin = 1; /* -geometry field */ int hWin = 1; /* -geometry field */ register char *pPixel; /* image pixel */ register int i; /* scratch */ /* translate retained image pixels to allocated color values */ for (pPixel = pRetImage, i = iHeight * iWidth; --i >= 0; pPixel++) *pPixel = indxColor[*pPixel & 0xff]; /* load up the retained image */ retImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0, pRetImage, iWidth, iHeight, 8, iWidth); if (!retImage) error("unable to create XImage", ""); /* determine dimension of retained and displayed images */ eWidth = iWidth * fExpand; eHeight = iHeight * fExpand; if (eWidth > DisplayWidth(theDisp, theScreen)) eWidth = DisplayWidth(theDisp, theScreen); if (eHeight > DisplayHeight(theDisp, theScreen)) eHeight = DisplayHeight(theDisp, theScreen); /* get a drawing font */ if (!getRsrc(&drawFont, R_STR, "xmgndisp.font", "Xmgndisp.Font")) drawFont = DFT_FONT; if (! (mfInfo = XLoadQueryFont(theDisp, drawFont))) error("couldn't open '%s' font", drawFont); XSetFont(theDisp, theGC, mfInfo->fid); XSetForeground(theDisp, theGC, fColor); XSetBackground(theDisp, theGC, bColor); /* parse the -geometry argument */ if (!getRsrc(&geomStr,R_STR, "xmgndisp.geometry","Xmgndisp.Geometry")) geomMask = 0; else geomMask = XParseGeometry(geomStr, &xWin, &yWin, &wWin, &hWin); if (geomMask & WidthValue) eWidth = wWin; if (geomMask & HeightValue) eHeight = hWin; /* adjust to retain correct aspect ratio */ if (eHeight * iWidth > eWidth * iHeight) eHeight = (eWidth * iHeight + iWidth/2) / iWidth; else if (eHeight * iWidth < eWidth * iHeight) eWidth = (eHeight * iWidth + iHeight/2) / iHeight; /* adjust window origin to keep it within screen area */ if ((geomMask & XValue) && (geomMask & XNegative)) xWin = XDisplayWidth(theDisp, theScreen) - eWidth - abs(xWin); if ((geomMask & YValue) && (geomMask & YNegative)) yWin = XDisplayHeight(theDisp,theScreen) - eHeight - abs(yWin); /* create the image window */ xSwa.background_pixel = bColor; xSwa.border_pixel = fColor; xSwa.bit_gravity = ForgetGravity; xSwaMask = CWBackPixel | CWBorderPixel | CWBitGravity; imWin = XCreateWindow(theDisp, rootWin, xWin, yWin, eWidth, eHeight, 2, 0, CopyFromParent, CopyFromParent, xSwaMask, &xSwa); if (! imWin) error("Can't open main window", ""); /* specify window size hints */ sHints.x = xWin; sHints.y = yWin; sHints.width = eWidth; sHints.height = eHeight; sHints.max_width = DisplayWidth(theDisp, theScreen); sHints.max_height = DisplayHeight(theDisp, theScreen); if ((geomMask & XValue) || (geomMask & YValue)) sHints.flags = USPosition | USSize | PMaxSize; else sHints.flags = PPosition | USSize | PMaxSize; /* construct window and icon titles */ sprintf(cBuf, "File: %s; Type: %s", inFile, inType); strncpy(iBuf, inShortFile, 8); iBuf[8] = 0; if (pChar = index(iBuf, '.')) *pChar = 0; /* send hints to a window manager */ #ifdef X11R3 XSetStandardProperties(theDisp, imWin, cBuf, iBuf, None, &pCmdName, 1, &sHints); #else /* R4 and later */ { XWMHints wHints; /* window manager mode */ XClassHint cHints; /* window class mode */ XTextProperty winName; /* name for window border */ XTextProperty iconName; /* name for window icon */ /* specify window-manager hints */ wHints.initial_state = NormalState; wHints.input = True; wHints.flags = StateHint | InputHint; /* specify window class hints */ cHints.res_name = "xdisp"; cHints.res_class = "Basicwin"; /* construct TextProperty structures for window & icon labels */ pChar = cBuf; XStringListToTextProperty(&pChar, 1, &winName); pChar = iBuf; XStringListToTextProperty(&pChar, 1, &iconName); /* tell the window manager about it */ XSetWMProperties(theDisp, imWin, &winName, &iconName, &pCmdName, 1, &sHints, &wHints, &cHints); } #endif X11R3 /* if necessary, zoom the display image */ reSize(eWidth, eHeight); /* specify which interrupts we want */ XSelectInput(theDisp, imWin, FocusChangeMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | Button1MotionMask | ExposureMask | KeyPressMask | StructureNotifyMask); /* display the image window */ XMapWindow(theDisp, imWin); } /* ** Write message to stderr, then quit */ error(cMsg, cInsert) char *cMsg, *cInsert; { fprintf(stderr, "%s: ", pCmdName); fprintf(stderr, cMsg, cInsert); fprintf(stderr, "\n"); exit(-1); } /* ** Retrieve a resource value from the database */ getRsrc(var, vtype, arg1, arg2) caddr_t var; int vtype; char *arg1, *arg2; { XrmValue val; char *type[20], ch, *c; if (XrmGetResource(resDB, arg1, arg2, type, &val) != True) return 0; ch = *(c = val.addr+val.size); *c = 0; switch(vtype) { case R_BOOL: *(int *)var = strcmp(val.addr, "False") ? 1 : 0; break; case R_INUM: *(int *)var = atoi(val.addr); break; case R_DNUM: *(double *)var = atof(val.addr); break; case R_STR: *(char **)var = strcpy(malloc(val.size+1), val.addr); break; } *c = ch; return 1; } /* ** translate location to index */ getInsertType(val, arg1, arg2) int *val; char *arg1, *arg2; { char *c, *d; if (! getRsrc(&c, R_STR, arg1, arg2)) return; for (d = c; *d; d++) if (isupper(*d)) *d = tolower(*d); if (!strcmp(c, "topleft")) *val = 0; else if (!strcmp(c, "topright")) *val = 1; else if (!strcmp(c, "bottomright")) *val = 2; else if (!strcmp(c, "bottomleft")) *val = 3; else error("bad location: %s", c); } /* ** Try to allocate nColors from rgbIndex[][]. ** If sw==1, immediately XAllocColor fails return ** (1 + the index of the failing rgbIndex[][i]); ** otherwise, keep going and return number allocated. */ defineColors(mask, sw) { int nRetCode = 0; /* return code */ int iColor; /* color index */ for (iColor = 0; iColor < 256; iColor++) { if (! usedColor[iColor]) continue; defColor[iColor].red = (rgbIndex[0][iColor] & mask) << 8; defColor[iColor].green = (rgbIndex[1][iColor] & mask) << 8; defColor[iColor].blue = (rgbIndex[2][iColor] & mask) << 8; defColor[iColor].flags = DoRed | DoGreen | DoBlue; if (! XAllocColor(theDisp, theCmap, &defColor[iColor])) { defColor[iColor].pixel = 0xffff; if (sw) return iColor+1; else nRetCode++; } indxColor[iColor] = defColor[iColor].pixel; } return nRetCode; } /* ** If necessary, resize the image window */ reSize(w, h) { register char *pInImage; /* pointer to input XImage data */ register char *pExpImage; /* pointer to output XImage data */ register char *pLine; /* pointer to output raster */ register int *pIndex, *pIn; /* line expand lookup buffer */ register int x, y; /* scratch */ /* if the size is same as retained image, use that */ if (w == iWidth && h == iHeight) { if (expImage != retImage) { /* remove previous image */ if (expImage) XDestroyImage(expImage); expImage = retImage; eWidth = iWidth; eHeight = iHeight; } return; } /* remove any insert windows (before possible XResizeWindow) */ XUnmapSubwindows(theDisp, imWin); /* preserve aspect ratio */ if (noExpose = (w * iHeight != iWidth * h)) { if (w * iHeight > iWidth * h) w = (iWidth * h + w/2)/iHeight; else h = (w * iHeight + h/2)/iWidth; if (expImage && w == eWidth && h == eHeight) return; XResizeWindow(theDisp, imWin, w, h); } if (w * h > 500 * 500) { /* if large image, tell the user */ pLine = "Resizing Image. Please wait..."; XDrawImageString(theDisp, imWin, theGC, (w - XTextWidth(mfInfo, pLine, strlen(pLine)))/2, (h + mfInfo->ascent - mfInfo->descent)/2, pLine, strlen(pLine)); XFlush(theDisp); } /* kill any old expImage */ if (expImage && expImage != retImage) { free(expImage->data); expImage->data = NULL; XDestroyImage(expImage); } if (vFlag) fprintf(stderr, "resize to %dx%d\n", w, h); /* create new expImage and pixel array */ expImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0, pExpImage = malloc(w * h), eWidth = w, eHeight = h, 8, w); if (!expImage || !pExpImage) error("can't create a %d byte image", eWidth * eHeight); /* create index lookup table to speed line expansion */ pIn = pIndex = (int *)malloc(eWidth*sizeof(int)); for (x = 0; x < eWidth; x++) *pIn++ = (iWidth * x + eWidth/2) / eWidth; /* expand the retained image */ pInImage = (char *)retImage->data; for (y = 0; y < eHeight; y++) { pLine = pInImage + iWidth * ((iHeight * y + eHeight/2) / eHeight); for (pIn = pIndex, x = 0; x < eWidth; x++) *pExpImage++ = *(pLine + *pIn++); } free(pIndex); } /* ** General event handler */ handleEvent(event) XEvent *event; /* generic event */ { XComposeStatus cStatus; /* keyboard status */ XButtonEvent *bEvent; /* button event */ XExposeEvent *eEvent; /* exposure event */ XKeyEvent *kEvent; /* keystroke event */ XConfigureEvent *cEvent; /* configuration event */ XPointerMovedEvent *pEvent; /* pointer motion event */ char kBuf[128]; /* cooked keyboard buffer */ KeySym kSym; /* raw keystroke code */ static char fActive; /* =1 if window is active */ static char fFocus; /* =1 if window has focus */ static char buttonFlag; /* =1 if Button1 is down */ register int x, y; /* scratch */ switch (event->type) { case Expose: eEvent = (XExposeEvent *) event; if (eEvent->window == imWin) if (noExpose && (eEvent->width != eWidth || eEvent->height != eHeight)) ; else XPutImage(theDisp, imWin, theGC, expImage, eEvent->x, eEvent->y, eEvent->x, eEvent->y, eEvent->width, eEvent->height); else if (eEvent->window == butWin) exposeButtonWindow(); else if (eEvent->window == zoomWin) exposeZoomWindow(); noExpose = 0; break; case KeyPress: if (! fActive) break; kEvent = (XKeyEvent *) event; XLookupString(kEvent, kBuf, 128, &kSym, &cStatus); switch (kSym) { case 'q': /* q/Q - quit xmgndisp */ case 'Q': XDestroyWindow(theDisp, imWin); XUnloadFont(theDisp, mfInfo->fid); XCloseDisplay(theDisp); exit(0); case '<': /* < - reduce zoom factor */ if (nZoom <= 2) { XBell(theDisp, 100); break; } nZoom--; showZoomWindow(); break; case '>': /* < - increase zoom factor */ if (nZoom >= 16) { XBell(theDisp, 100); break; } nZoom++; showZoomWindow(); break; case 'v': case 'V': /* v,V - cycle pointer value insert */ butType = (butType + 1) % 4; showButtonWindow(); break; case 'z': case 'Z': /* z,Z - cycle zoom insert */ zoomType = (zoomType + 1) % 4; showButtonWindow(); break; case XK_Return: /* ^M - remove insert windows */ XUnmapSubwindows(theDisp, imWin); break; case XK_Left: /* arrow-keys - move pointer */ case XK_Up: case XK_Right: case XK_Down: case 'h': case 'j': case 'k': case 'l': if (kEvent->window != imWin) break; /* adjust index in retained image */ switch (kSym) { case XK_Left: case 'h': curLoc[0]--; break; case XK_Up: case 'k': curLoc[1]--; break; case XK_Right: case 'l': curLoc[0]++; break; case XK_Down: case 'j': curLoc[1]++; break; } /* change the insert values */ showButtonWindow(); /* translate to offsets in displayed image */ x = (curLoc[0] * eWidth + iWidth/2) / iWidth; y = (curLoc[1] * eHeight + iHeight/2) / iHeight; if (x < 0 || x >= eWidth || y < 0 || y >= eHeight) break; /* if necessary, move the pointer */ if (kEvent->x != x || kEvent->y != y) XWarpPointer(theDisp, None, imWin, 0, 0, 0, 0, x, y); break; } break; case ConfigureNotify: /* resize image window */ cEvent = (XConfigureEvent *) event; if (cEvent->window != imWin) break; noExpose = 0; if (cEvent->width != eWidth || cEvent->height != eHeight) reSize(cEvent->width, cEvent->height); break; case EnterNotify: /* pointer entering image window */ fActive = event->xcrossing.focus; break; case LeaveNotify: /* pointer leaving image window */ fActive = fFocus; break; case FocusIn: /* image window getting the keyboard focus */ fFocus = fActive = 1; break; case FocusOut: /* image window losing the keyboard focus */ fFocus = fActive = 0; break; case ButtonPress: bEvent = (XButtonEvent *) event; if (bEvent->window != imWin) break; if (bEvent->button != Button1) break; /* convert location to retained image */ curLoc[0] = (bEvent->x * iWidth + eWidth/2) / eWidth; curLoc[1] = (bEvent->y * iHeight + eHeight/2) / eHeight; showButtonWindow(); /* remember button pressed */ buttonFlag = 1; break; case ButtonRelease: bEvent = (XButtonEvent *) event; if (bEvent->window != imWin) break; if (bEvent->button != Button1) break; /* remember button released */ buttonFlag = 0; break; case MotionNotify: if (! buttonFlag || !fActive) break; pEvent = (XPointerMovedEvent *) event; if (pEvent->window != imWin) break; /* pointer dragged -- update inserts */ curLoc[0] = (pEvent->x * iWidth + eWidth/2) / eWidth; curLoc[1] = (pEvent->y * iHeight + eHeight/2) / eHeight; showButtonWindow(); break; default: break; } } /* ** Left button draws pixel coordinates and value */ showButtonWindow() { static int wSave, hSave; /* saved subwindow size */ static int xSave, ySave; /* saved subwindow origin */ float lon, lat; /* pointer location */ float fVal; /* pointer data value */ int dn; /* pointer pixel */ int xOrg, yOrg; /* new subwindow origin */ int i, x, y; /* scratch */ char cDelim; /* data value delimiter */ char *fUnits; /* data unit type */ /* clip pointer to retained image */ x = curLoc[0] = MIN(MAX(curLoc[0], 0), iWidth-1); y = curLoc[1] = MIN(MAX(curLoc[1], 0), iHeight-1); /* display the zoomed insert */ showZoomWindow(); /* get map coordinates */ cDelim = getVicarValue(x, y, &i, &lon, &lat, &fVal, &fUnits); /* construct text strings */ sprintf(bText[0], OK(lon) ? "x=%04d PIXEL LONGITUDE = %.3f" : "x=%04d", x, lon); sprintf(bText[1], OK(lat) ? "y=%04d PIXEL LATITUDE = %.3f" : "y=%04d", y, lat); sprintf(bText[2], OK(fVal) ? "d=%04d PIXEL VALUE %c %.7g" : "d=%04d", i, cDelim, fVal); if (fUnits && OK(fVal)) sprintf(bText[2]+strlen(bText[2]), " <%s>", fUnits); /* determine maximum width of strings */ for (bWidth = i = 0; i < 3; i++) bWidth = MAX(bWidth, XTextWidth(mfInfo, bText[i], strlen(bText[i]))); bHeight = mfInfo->ascent + mfInfo->descent; x = bWidth += 2*nBorder; y = 4*nBorder+3*bHeight; /* determine subwindow origin */ switch (butType) { case 0: xOrg = yOrg = 0; break; case 1: xOrg = eWidth - x - 2*nBorder; yOrg = 0; break; case 2: xOrg = eWidth - x - 2*nBorder; yOrg = eHeight - y - 2*nBorder; break; case 3: xOrg = 0; yOrg = eHeight - y - 2*nBorder; break; } if (butWin && (x != wSave || y != hSave || xOrg != xSave || yOrg != ySave)) { /* subwindow size or origin change */ XDestroyWindow(theDisp, butWin); butWin = 0; } if (butWin) { /* same subwindow size and origin */ XClearWindow(theDisp, butWin); exposeButtonWindow(); } else { /* create or recreate the subwindow */ butWin = XCreateSimpleWindow(theDisp, imWin, xSave = xOrg, ySave = yOrg, wSave = x, hSave = y, nBorder, fColor, bColor); XSelectInput(theDisp, butWin, ExposureMask); } XMapWindow(theDisp, butWin); } /* ** redraw the insert subwindow */ exposeButtonWindow() { int i; for (i = 0; i < 3; i++) XDrawImageString(theDisp, butWin, theGC, nBorder, nBorder+bHeight*(i+1), bText[i], strlen(bText[i])); } /* ** Create zoom insert subwindow and zoomed image */ showZoomWindow() { static int xSave, ySave; /* saved subwindow origin */ static int lenSave; /* saved subwindow width/height */ int xOrg, yOrg; /* new subwindow origin */ register char *pIn; /* retained image array */ register char *pOut; /* zoomed image array */ register int lenIn; /* number of pixels to zoom */ register int lenOut; /* new zoomed window width */ register int w, x, y, z; /* scratch */ register int dx, dy; /* scratch */ /* compute unzoomed and zoomed line lengths */ lenIn = MIN(eHeight, eWidth)/(8*nZoom); if (lenIn <= 1) lenIn = 1; lenOut = (2 * lenIn + 1) * nZoom; /* determine subwindow origin */ switch (zoomType) { case 0: xOrg = yOrg = 0; break; case 1: xOrg = eWidth - lenOut - 2*nBorder; yOrg = 0; break; case 2: xOrg = eWidth - lenOut - 2*nBorder; yOrg = eHeight - lenOut - 2*nBorder; break; case 3: xOrg = 0; yOrg = eHeight - lenOut - 2*nBorder; break; } if (zoomWin && (lenSave != lenOut || xOrg != xSave || yOrg != ySave)) { /* remove subwindow on size or origin change */ free(zoomImage->data); XDestroyImage(zoomImage); XDestroyWindow(theDisp, zoomWin); zoomWin = 0; } if (! zoomWin) { /* create or recreate subwindow and zoomed image */ zoomWin = XCreateSimpleWindow(theDisp, imWin, xOrg, yOrg, lenOut, lenOut, nBorder, fColor, bColor); zoomImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0, malloc(lenOut * lenOut), lenOut, lenOut, 8, lenOut); XSelectInput(theDisp, zoomWin, ExposureMask); } pIn = (char *)retImage->data; pOut = (char *)zoomImage->data; /* zoom about curLoc in retained image */ for (y = -lenIn; y <= lenIn; y++) { dy = ((dy = curLoc[1]+y) >= iHeight) ? -1 : dy*iWidth; for (x = -lenIn; x <= lenIn; x++) { w = (dy < 0 || (dx = curLoc[0]+x) < 0 || dx >= iWidth) ? 0 : *(pIn + dy + dx); for (z = nZoom; --z >= 0; *pOut++ = w) ; } /* after zooming a line, replicate it nZoom-1 times */ for (z = nZoom; --z > 0; pOut += lenOut) bcopy(pOut-lenOut, pOut, lenOut); } /* if subwindow size/origin unchanged, it must be exposed */ if (lenSave == lenOut && xOrg == xSave && yOrg == ySave) exposeZoomWindow(); /* save sub-window size and origin */ lenSave = lenOut; xSave = xOrg; ySave = yOrg; XMapWindow(theDisp, zoomWin); } /* ** repaint the zoomed subwindow */ exposeZoomWindow() { register int i; /* scratch */ /* paint the zoomed image */ XPutImage(theDisp, zoomWin, theGC, zoomImage, 0, 0, 0, 0, zoomImage->width, zoomImage->height); /* insert zoom size */ sprintf(cBuf, "x%d", nZoom); XDrawImageString(theDisp, zoomWin, theGC, (zoomImage->width-XTextWidth(mfInfo, cBuf, strlen(cBuf)))/2, nBorder+mfInfo->ascent+mfInfo->descent, cBuf, strlen(cBuf)); /* draw cross-hairs to indicate central pixel */ i = (zoomImage->width - nZoom)/2; XDrawLine(theDisp, zoomWin, theGC, i, i, i-nZoom, i-nZoom); XDrawLine(theDisp, zoomWin, theGC, i+nZoom, i, i+2*nZoom, i-nZoom); i += nZoom; XDrawLine(theDisp, zoomWin, theGC, i, i, i+nZoom, i+nZoom); XDrawLine(theDisp, zoomWin, theGC, i-nZoom, i, i-2*nZoom, i+nZoom); } /* ** Applicable VICAR keywords */ int DIM; /* image dimension */ int EOL; /* end-of-file label flag */ int LBLSIZE; /* label length in bytes */ int NB; /* number of image bands */ int NBB; /* line prefix bytes */ int NL; /* number of lines */ int NLB; /* number of prefix lines */ int NS; /* number of samples per line */ char *DN_UNITS; /* data units */ char *FORMAT; /* pixel format */ char *IMAGE = "unknown"; /* image description */ char *INTFMT; /* integer pixel format */ char *MAP_PROJ; /* map projection type */ char *ORG; /* image structure type */ char *REALFMT; /* float pixel format */ double HI_DN = UNINIT; /* largest assigned pixel value */ double HI_REP = UNINIT; /* real value of HI_DN */ double LAT_LC = UNINIT; /* latitude of lower center */ double LAT_LL = UNINIT; /* latitude of lower left */ double LAT_LR = UNINIT; /* latitude of lower right */ double LAT_UC = UNINIT; /* latitude of upper center */ double LAT_UL = UNINIT; /* latitude of upper left */ double LAT_UR = UNINIT; /* latitude of upper right */ double LON_CL = UNINIT; /* longitude of center left */ double LON_CR = UNINIT; /* longitude of center right */ double LON_LL = UNINIT; /* longitude of lower left */ double LON_LR = UNINIT; /* longitude of lower right */ double LON_UL = UNINIT; /* longitude of upper left */ double LON_UR = UNINIT; /* longitude of upper right */ double LOW_DN = UNINIT; /* smallest assigned pixel value */ double LOW_REP = UNINIT; /* real value of LOW_DN */ double PIXSIZ = UNINIT; /* pixel size in DN_UNITS units */ double PROJSAMP = UNINIT; /* sample index of PROJ_LON */ double PROJ_LON = UNINIT; /* standard projection longitude */ double SPECLINE = UNINIT; /* line index of PROJ_LON */ double SPECSAMP = UNINIT; /* sample index of prime meridian */ #define K_NORTH 01 /* latitude is northern */ #define K_SOUTH 02 /* latitude is southern */ int nsFlag; /* =1,2 if all LATs northern,southern */ /* ** Values of k_flg, below */ #define K_REQD 01 /* keyword must be present */ #define K_FOUND 02 /* keyword is present */ #define K_CHAR 04 /* keyword value is character string */ #define K_INT 010 /* keyword value is integer */ #define K_DOUBLE 020 /* keyword value is integer or double */ #define K_LAT 040 /* keyword value is a latitude */ /* ** Table of VICAR keyword names and attributes ** NOTE: LBLSIZE must be first. */ struct keyTab { char *k_name; /* header keyword */ char *k_ptr; /* where to copy the value */ int k_flg; /* flag fields */ } KeyTable[] = { "LBLSIZE", (char *) &LBLSIZE, K_INT | K_REQD, "DIM", (char *) &DIM, K_INT, "DN_UNITS", (char *) &DN_UNITS, K_CHAR, "EOL", (char *) &EOL, K_INT, "FORMAT", (char *) &FORMAT, K_CHAR | K_REQD, "HI_DN", (char *) &HI_DN, K_DOUBLE, "HI_REP", (char *) &HI_REP, K_DOUBLE, "IMAGE", (char *) &IMAGE, K_CHAR, "INTFMT", (char *) &INTFMT, K_CHAR, "LAT_LC", (char *) &LAT_LC, K_DOUBLE | K_LAT, "LAT_LL", (char *) &LAT_LL, K_DOUBLE | K_LAT, "LAT_LR", (char *) &LAT_LR, K_DOUBLE | K_LAT, "LAT_UC", (char *) &LAT_UC, K_DOUBLE | K_LAT, "LAT_UL", (char *) &LAT_UL, K_DOUBLE | K_LAT, "LAT_UR", (char *) &LAT_UR, K_DOUBLE | K_LAT, "LON_CL", (char *) &LON_CL, K_DOUBLE, "LON_CR", (char *) &LON_CR, K_DOUBLE, "LON_LL", (char *) &LON_LL, K_DOUBLE, "LON_LR", (char *) &LON_LR, K_DOUBLE, "LON_UL", (char *) &LON_UL, K_DOUBLE, "LON_UR", (char *) &LON_UR, K_DOUBLE, "LOW_DN", (char *) &LOW_DN, K_DOUBLE, "LOW_REP", (char *) &LOW_REP, K_DOUBLE, "MAP_PROJ", (char *) &MAP_PROJ, K_CHAR, "NB", (char *) &NB, K_INT, "NBB", (char *) &NBB, K_INT, "NL", (char *) &NL, K_INT | K_REQD, "NLB", (char *) &NLB, K_INT, "NS", (char *) &NS, K_INT | K_REQD, "ORG", (char *) &ORG, K_CHAR, "PIXSIZ", (char *) &PIXSIZ, K_DOUBLE, "PROJSAMP", (char *) &PROJSAMP, K_DOUBLE, "PROJ_LON", (char *) &PROJ_LON, K_DOUBLE, "REALFMT", (char *) &REALFMT, K_CHAR, "SPECLINE", (char *) &SPECLINE, K_DOUBLE, "SPECSAMP", (char *) &SPECSAMP, K_DOUBLE, NULL }; /* ** Read the input VICAR file into an XImage */ loadVicarFile(ppType) char **ppType; /* returned image type */ { float fVal; /* scratch */ double fFact; /* convert from DN to real */ double dFact; /* convert from real to image */ register FILE *pFile; /* input stream pointer */ register char *pPix; /* pointer to pRetImage */ register char dType; /* input byte type */ register char *pixTable; /* input translation table */ register int tabSize; /* size of pixTable */ register int inPix; /* input pixel value */ register int x, y; /* scratch */ register char *c; /* scratch */ /* open the VICAR file */ if (inFile == NULL) inFile = "'stdin'"; if (strcmp(inFile, "'stdin'") == 0) pFile = stdin; else if ((pFile = fopen(inFile, "r")) == NULL) perror(inFile), exit(1); /* scan the header */ readVicarHeader(pFile); /* verify image structure keywords */ if (ORG && strcmp(ORG, "BSQ")) error("unsupported ORG value: %s", ORG); if (DIM && (DIM < 2 || DIM > 3)) error("unsupported DIM value: %d", (char *)DIM); if (!DN_UNITS || ! strcmp(DN_UNITS, "NONE") || ! strcmp(DN_UNITS, "N/A")) DN_UNITS = 0; if (EOL) (void)fprintf(stderr, "%s: EOF labels ignored\n", inFile); /* construct fancy IMAGE string */ for (c = *ppType = IMAGE; *c; c++) if (islower(*c) && (c == IMAGE || c[-1] == ' ')) *c = toupper(*c); else if (isupper(*c) && c != IMAGE && c[-1] != ' ') *c = tolower(*c); /* fix-up bugs in Magellan browse image headers */ if (!strcmp(inShortFile, "browse.img") || !strcmp(inShortFile, "BROWSE.IMG")) bFlag = 1; if (bFlag && OK(PIXSIZ+SPECLINE+PROJSAMP)) { if ((x = PIXSIZ / 75) == 1 || x == 3 || x == 9 || x == 27) { PIXSIZ *= 8; SPECLINE /= 8; PROJSAMP /= 8; } if (vFlag) fprintf(stderr, "%s: %s -> %g,%g,%g\n", inShortFile, "PIXSIZ,SPECLINE,PROJSAMP", PIXSIZ, SPECLINE, PROJSAMP); } /* determine pixel format type */ if (!strcmp(FORMAT, "BYTE")) { dType = 'b'; tabSize = 256; } else if (!strcmp(FORMAT, "HALF")) { dType = ((INTFMT && strcmp(INTFMT, "LOW")) ^ sFlag) ? 'h' : 's'; tabSize = 65536; } else if (!strcmp(FORMAT, "REAL")) { dType = ((REALFMT && strcmp(REALFMT, "VAX")) ^ sFlag) ? 'v' : 'f'; /* float pixels require user-supplied display range */ if (! OK(minValue) || ! OK(maxValue) || minValue >= maxValue) error("%s: missing -lowvalue or -highvalue value", inFile); dFact = 255.0/(maxValue - minValue); tabSize = 0; } else error("unsupported FORMAT value: %s", FORMAT); if (tabSize) { /* for BYTE or HALF pixels, determine image stretch */ if (! OK(LOW_DN)) LOW_DN = 0; if (! OK(LOW_REP)) LOW_REP = LOW_DN; if (! OK(minValue)) minValue = LOW_REP; if (! OK(HI_DN)) HI_DN = tabSize - 1; if (! OK(HI_REP)) HI_REP = HI_DN; if (! OK(maxValue)) maxValue = HI_REP; if (LOW_DN >= HI_DN) error("%s: inconsistent LOW_DN, HI_DN values", inFile); if (minValue >= maxValue) error( "%s: inconsistent -highvalue, -lowvalue values", inFile); fFact = (HI_REP - LOW_REP) / (HI_DN - LOW_DN); dFact = 255.0/(maxValue - minValue); /* construct a lookup table */ pixTable = malloc(tabSize); for (x = 0; x < tabSize; x++) { fVal = LOW_REP + (x - LOW_DN) * fFact; inPix = LOW_DN + (fVal - minValue) * dFact; if (inPix < 0) inPix = 0; else if (inPix > 255) inPix = 255; pixTable[x] = inPix; } } /* allocate the retained image array */ iWidth = NS; iHeight = NL; if ((pRetImage = pPix = malloc(NL * NS)) == NULL) error("%s: insufficient memory", inShortFile); for (y = 0; y < NL+NLB; y++) { for (x = 0; x < NS+NBB; x++) { inPix = getc(pFile) & 0xff; if (x < NBB) /* ignore line-prefix bytes */ continue; /* * NOTE: pixels are loaded one-byte-at-a-time * into inPix so whether the CPU is LSB-first * or MSB-first is unimportant. */ switch (dType) { case 'b': /* byte */ break; case 'h': /* short - HSB first */ inPix = (inPix << 8) | (getc(pFile) & 0xff); break; case 's': /* short - LSB first */ inPix |= (getc(pFile) & 0xff) << 8; break; /* * Conversion into local float format is * CPU-dependent, but note that Sun and * DecStation (mips) obey same rules. */ #ifdef vax case 'f': /* IEEE float -> VAX */ if (inPix && inPix != 0xff) inPix++; inPix = (inPix << 8) | (getc(pFile) & 0xff); inPix |= (getc(pFile) & 0xff) << 24; inPix |= (getc(pFile) & 0xff) << 16; break; case 'v': /* VAX float -> VAX */ inPix |= (getc(pFile) & 0xff) << 8; inPix |= (getc(pFile) & 0xff) << 16; inPix |= (getc(pFile) & 0xff) << 24; break; #else case 'f': /* IEEE float -> IEEE CPU */ inPix = (inPix << 8) | (getc(pFile) & 0xff); inPix = (inPix << 8) | (getc(pFile) & 0xff); inPix = (inPix << 8) | (getc(pFile) & 0xff); break; case 'v': /* VAX float -> IEEE CPU */ inPix |= (getc(pFile) & 0xff) << 8; if (inPix & 0xff00) inPix -= 0x100; inPix = (inPix << 16) | getc(pFile) & 0xff; inPix |= (getc(pFile) & 0xff) << 8; break; #endif vax } if (y < NLB) /* ignore image prefix lines */ continue; if (tabSize) /* translate via lookup table */ inPix = *(pixTable + inPix) & 0xff; else { /* cast long int to float */ *((int *)&fVal) = inPix; /* load as float and normalize */ inPix = (fVal - minValue) * dFact; /* clip */ if (inPix < 0) inPix = 0; else if (inPix > 255) inPix = 255; } /* store retained pixel value */ *pPix++ = inPix; /* count number of discrete pixel values */ if (! usedColor[inPix]) usedColor[inPix] = 1, nColors++; } } (void)fclose(pFile); if (vFlag) fprintf(stderr, "%s: %d colors in %dx%d image\n", inShortFile, nColors, iWidth, iHeight); } /* ** VICAR header state table */ int stateTable[][4] = { /* blank equals quote other state */ { 0, -1, -1, 1 }, /* 0 blank */ { -1, 2, -1, 1 }, /* 1 keyword */ { 7, -1, 3, 6 }, /* 2 assignment */ { 4, 4, 5, 4 }, /* 3 starting quote */ { 4, 4, 5, 4 }, /* 4 string value */ { 0, -1, -1, -1 }, /* 5 ending quote */ { 7, -1, -1, 6 }, /* 6 numeric value */ { 0, -1, -1, 1 } /* 7 end numeric */ }; /* ** Read the VICAR header, fill "KeyTable" structure */ readVicarHeader(pFile) FILE *pFile; /* input file stream */ { struct keyTab *pKey; /* pointer to KeyTable[] */ int nByte = 0; /* input byte count */ int cChar = 0; /* current character */ int cType = 0; /* character type code */ int fNull = 0; /* =1 if NUL read */ int nState = 0; /* state code */ char *pBuf = cBuf; /* pointer to buf */ int ch; /* scratch */ /* ** This code implements a finite-state automaton */ for ( ; cChar != EOF; nByte++) { /* stop if length of label exceded */ if ((KeyTable[0].k_flg & K_FOUND) && nByte >= LBLSIZE) { cType = 0; cChar = EOF; } else if (fNull) { /* gobble after NUL encountered */ (void)getc(pFile); continue; } else switch (cChar = getc(pFile)) { /* get input byte type */ case EOF: error("%s: unexpected EOF", inFile); case 0: fNull++; case '\r': case '\n': continue; case ' ': cType = 0; break; case '=': cType = 1; break; case '\'': cType = 2; break; default: cType = 3; break; } /* branch on new state */ switch (nState = stateTable[nState][cType]) { case -1: /* unexpected state */ error("VICAR label error in byte %d", (char *)nByte); case 0: /* blank before keyword */ break; case 1: /* keyword */ case 4: /* string value */ *pBuf++ = cChar; break; case 2: /* assignment = */ *pBuf = 0; for (pKey = KeyTable; pKey->k_name && strcmp(cBuf, pKey->k_name); pKey++) ; if (! pKey->k_name) pKey = NULL; pBuf = cBuf; break; case 3: /* starting quote */ if (pKey && ! (pKey->k_flg & K_CHAR)) error("non-numeric %s value", pKey->k_name); break; case 6: /* numeric value */ if (pKey && (pKey->k_flg & K_CHAR)) error("non-string %s value", pKey->k_name); *pBuf++ = cChar; break; case 5: /* ending (or doubled) quote */ if ((cChar = getc(pFile)) == '\'') { *pBuf++ = cChar; nState = 4; nByte++; break; } (void)ungetc(cChar, pFile); case 7: /* end numeric */ if (! pKey) { /* skip unimportant keyword */ pBuf = cBuf; break; } *pBuf++ = 0; if (vFlag) fprintf(stderr, "%-8.8s = %s\n", pKey->k_name, cBuf); if (nState == 5) *(char **)(pKey->k_ptr) = strcpy(malloc(pBuf-cBuf), cBuf); else if (sscanf(cBuf[0] ? cBuf : "0", (pKey->k_flg & K_DOUBLE) ? "%lf" : "%d", pKey->k_ptr) != 1) error("bad %s value", pKey->k_name); pKey->k_flg |= K_FOUND; if (pKey->k_flg & K_LAT) nsFlag |= (cBuf[0] == '-') ? K_SOUTH : K_NORTH; pBuf = cBuf; break; } } /* Check for required parameters */ for (pKey = KeyTable; pKey->k_name; pKey++) if ((pKey->k_flg & (K_REQD | K_FOUND)) == K_REQD) error("keyword not in header: %s", pKey->k_name); } getVicarValue(x, y, dn, lon, lat, val, units) float *lon, *lat, *val; /* returned coordinates */ int *dn; /* returned pixel value */ char **units; /* unit type string */ { static float fScale; /* projection scale factor */ static float fConv; /* radians per degree */ float dx, dy; /* scratch */ int i; /* scratch */ /* initialize projection parameters */ if (! fConv && OK(PIXSIZ)) { fConv = 45/atan(1.0); fScale = PIXSIZ/VENUS_RADIUS; } /* if information exists, derive longitude and latitude */ *dn = pRetImage[x + y * iWidth] & 0xff; dx = fScale*(x+0.5-PROJSAMP); dy = fScale*(SPECLINE-0.5-y); if (! MAP_PROJ || !OK(SPECLINE+PROJSAMP+PROJ_LON+PIXSIZ)) *lat = *lon = UNINIT; else if (!strcmp(MAP_PROJ, "SINUSOIDAL")) { *lat = dy*fConv; *lon = dx/cos(dy); } else if (!strcmp(MAP_PROJ, "STEREOGRAPHIC")) { *lon = atan2(dx,(nsFlag == K_SOUTH) ? dy : -dy); *lat = 2*fConv*atan(0.5*hypot(dx,dy)); *lat = (nsFlag == K_SOUTH) ? *lat-90 : 90-*lat; } else if (!strcmp(MAP_PROJ, "MERCATOR")) { *lon = dx; *lat = 2*fConv*atan(exp(dy))-90; } *lon *= fConv; if (fabs(*lon) > 180) *lat = *lon = UNINIT; else if ((*lon = PROJ_LON + *lon) < 0) *lon += 360; *units = DN_UNITS; /* get pixel DN value */ for (i = 0; i < 256 && *dn != indxColor[i]; i++) ; if (i == 256) { *val = UNINIT; return '?'; } else if ((*dn = i) == 0) { *val = minValue; return '<'; } else if (i == 255) { *val = maxValue; return '>'; } else { *val = minValue + (i*(maxValue-minValue))/255.0; return '='; } }