This is xvgraf.c in view mode; [Download] [Up]
/* * xvgraf.c - GRAF window handling functions * * callable functions: * * CreateGraf() - creates a GRAF window * InitGraf() - inits GRAF handles to reasonable defaults * RedrawGraf() - called by 'expose' events * ClickGraf() - called when B1 clicked in GRAF window * GrafKey() - called when keypress in GRAF window * Graf2Str() - copies current GRAF settings to a string * Str2Graf() - parses an xrdb string into GRAF settings * GetGrafState() - copies GRAF data into GRAF_STATE structure * SetGrafState() - sets GRAF data based on GRAF_STATE * InitSpline() - called to generate y' table for EvalSpline * EvalSpline() - evalutes spline function at given point */ /* Copyright Notice * ================ * Copyright 1989, 1990, 1991, 1992, 1993 by John Bradley * * Permission to use, copy, and distribute XV in its entirety, for * non-commercial purposes, is hereby granted without fee, provided that * this license information and copyright notice appear in all copies. * * Note that distributing XV 'bundled' in with ANY product is considered * to be a 'commercial purpose'. * * Also note that any copies of XV that are distributed MUST be built * and/or configured to be in their 'unregistered copy' mode, so that it * is made obvious to the user that XV is shareware, and that they should * consider donating, or at least reading this License Info. * * The software may be modified for your own purposes, but modified * versions may NOT be distributed without prior consent of the author. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author be held liable for any damages * arising from the use of this software. * * If you would like to do something with XV that this copyright * prohibits (such as distributing it with a commercial product, * using portions of the source in some other program, etc.), please * contact the author (preferably via email). Arrangements can * probably be worked out. * * XV is shareware for PERSONAL USE only. You may use XV for your own * amusement, and if you find it nifty, useful, generally cool, or of * some value to you, your non-deductable donation would be greatly * appreciated. $25 is the suggested donation, though, of course, * larger donations are quite welcome. Folks who donate $25 or more * can receive a Real Nice bound copy of the XV manual for no extra * charge. * * Commercial, government, and institutional users MUST register their * copies of XV, for the exceedingly REASONABLE price of just $25 per * workstation/X terminal. Site licenses are available for those who * wish to run XV on a large number of machines. Contact the author * for more details. * * The author may be contacted via: * US Mail: John Bradley * 1053 Floyd Terrace * Bryn Mawr, PA 19010 * * Phone: (215) 898-8813 * EMail: bradley@cis.upenn.edu */ #include "xv.h" #include "bitmaps.h" #define GHIGH 147 #define GBHIGH 23 #define GBWIDE 30 #define GWIDE (128 + 3 + 4 + GBWIDE) #define PW gf1_addh_width #define PH gf1_addh_height static int pixmaps_built = 0; static Pixmap gfbpix[N_GFB]; /* local functions */ #ifdef __STDC__ static void drawGraf(GRAF *, int); static void drawHandPos(GRAF *, int); #else static void drawGraf(), drawHandPos(); #endif /***************************************************/ void CreateGraf(gp, parent, x, y, fg, bg, title) GRAF *gp; Window parent; int x,y; unsigned long fg,bg; char *title; { /* NOTE: CreateGraf does not initialize hands[], nhands, or spline, as these could be initialized by X resources (or whatever), which takes place long before we can create the windows. InitGraf() sets those fields of a GRAF to likely enough values */ int i; if (!pixmaps_built) { gfbpix[GFB_ADDH] = XCreatePixmapFromBitmapData(theDisp, parent, gf1_addh_bits, PW, PH, 1, 0, 1); gfbpix[GFB_DELH] = XCreatePixmapFromBitmapData(theDisp, parent, gf1_delh_bits, PW, PH, 1, 0, 1); gfbpix[GFB_LINE] = XCreatePixmapFromBitmapData(theDisp, parent, gf1_line_bits, PW, PH, 1, 0, 1); gfbpix[GFB_SPLINE] = XCreatePixmapFromBitmapData(theDisp, parent, gf1_spln_bits, PW, PH, 1, 0, 1); gfbpix[GFB_RESET] = XCreatePixmapFromBitmapData(theDisp, parent, gf1_rst_bits, PW, PH, 1, 0, 1); gfbpix[GFB_GAMMA] = XCreatePixmapFromBitmapData(theDisp, parent, gf1_gamma_bits, gf1_gamma_width, gf1_gamma_height, 1, 0, 1); for (i=0; i<N_GFB && gfbpix[i] != (Pixmap) NULL; i++); if (i<N_GFB) FatalError("can't create graph pixmaps"); pixmaps_built = 1; } gp->fg = fg; gp->bg = bg; gp->str = title; gp->entergamma = 0; gp->drawobj = NULL; sprintf(gp->gvstr, "%.5g", gp->gamma); gp->win = XCreateSimpleWindow(theDisp, parent, x,y, GWIDE, GHIGH, 1, fg,bg); if (!gp->win) FatalError("can't create graph (main) window"); gp->gwin = XCreateSimpleWindow(theDisp, gp->win, 2, GHIGH-132, 128, 128, 1, fg,bg); if (!gp->gwin) FatalError("can't create graph (sub) window"); for (i=0; i<N_GFB; i++) { BTCreate(&gp->butts[i], gp->win, GWIDE-GBWIDE-2, 1+i * (GBHIGH + 1), GBWIDE, GBHIGH, (char *) NULL, fg, bg, hicol, locol); gp->butts[i].pix = gfbpix[i]; gp->butts[i].pw = PW; gp->butts[i].ph = PH; } gp->butts[GFB_SPLINE].toggle = 1; gp->butts[GFB_LINE ].toggle = 1; gp->butts[GFB_SPLINE].lit = gp->spline; gp->butts[GFB_LINE ].lit = !gp->spline; if (gp->nhands == 2) gp->butts[GFB_DELH].active = 0; if (gp->nhands == MAX_GHANDS) gp->butts[GFB_ADDH].active = 0; GenerateGrafFunc(gp,0); XSelectInput(theDisp, gp->win, ExposureMask | ButtonPressMask | KeyPressMask); XSelectInput(theDisp, gp->gwin, ExposureMask); XMapSubwindows(theDisp, gp->win); } /***************************************************/ void InitGraf(gp) GRAF *gp; { gp->nhands = 4; gp->spline = 1; gp->hands[0].x = 0; gp->hands[0].y = 0; gp->hands[1].x = 64; gp->hands[1].y = 64; gp->hands[2].x = 192; gp->hands[2].y = 192; gp->hands[3].x = 255; gp->hands[3].y = 255; gp->gammamode = 0; gp->gamma = 1.0; } /***************************************************/ void RedrawGraf(gp, gwin) GRAF *gp; int gwin; { int i; /* if gwin, only redraw the graf window, otherwise, only redraw the title and buttons */ if (gwin) drawGraf(gp,0); else { Draw3dRect(gp->win, 0,0, GWIDE-1, GHIGH-1, R3D_OUT, 1, hicol, locol, gp->bg); XSetForeground(theDisp, theGC, gp->fg); XSetBackground(theDisp, theGC, gp->bg); XDrawString(theDisp, gp->win, theGC, 2, 1+ASCENT,gp->str,strlen(gp->str)); for (i=0; i<N_GFB; i++) BTRedraw(&gp->butts[i]); } } /***************************************************/ static void drawGraf(gp,erase) GRAF *gp; int erase; { int i,x,y; XPoint pts[129], *pt; if (gp->entergamma) { char *str1 = "Enter gamma"; char *str2 = "value: "; XSetForeground(theDisp, theGC, gp->fg); XSetBackground(theDisp, theGC, gp->bg); XClearWindow(theDisp,gp->gwin); XDrawString(theDisp,gp->gwin, theGC, 10,30+ASCENT, str1, strlen(str1)); XDrawString(theDisp,gp->gwin, theGC, 10,30+ASCENT+CHIGH+3, str2, strlen(str2)); x = 10 + StringWidth(str2) + 8; y = 30 + ASCENT + CHIGH + 3; i = StringWidth(gp->gvstr); if (gp->entergamma < 0 && strlen(gp->gvstr)) { /* show string highlited */ XFillRectangle(theDisp, gp->gwin, theGC, x-1,y-ASCENT-1,i+2,CHIGH+2); XSetForeground(theDisp, theGC, gp->bg); } else XDrawLine(theDisp, gp->gwin, theGC, x+i, y-ASCENT, x+i, y+DESCENT); XDrawString(theDisp, gp->gwin, theGC, x,y, gp->gvstr, strlen(gp->gvstr)); return; } if (erase) XSetForeground(theDisp, theGC, gp->bg); else XSetForeground(theDisp, theGC, gp->fg); for (i=0, pt=pts; i<256; i+=2,pt++) { pt->x = i/2; pt->y = 127 - (gp->func[i]/2); if (i==0) i = -1; /* kludge to get sequence 0,1,3,5, ... 253,255 */ } XDrawLines(theDisp, gp->gwin, theGC, pts, 129, CoordModeOrigin); if (erase) return; /* don't erase handles */ /* redraw handles */ XSetForeground(theDisp, theGC, gp->bg); for (i=0; i<gp->nhands; i++) { /* clear inside rectangles */ x = gp->hands[i].x/2; y = 127 - gp->hands[i].y/2; XFillRectangle(theDisp, gp->gwin, theGC, x-2, y-2, 5,5); } XSetForeground(theDisp,theGC,gp->fg); for (i=0; i<gp->nhands; i++) { /* draw center dots */ x = gp->hands[i].x/2; y = 127 - gp->hands[i].y/2; XDrawPoint(theDisp, gp->gwin, theGC, x, y); } for (i=0; i<gp->nhands; i++) { /* draw rectangles */ x = gp->hands[i].x/2; y = 127 - gp->hands[i].y/2; XDrawRectangle(theDisp, gp->gwin, theGC, x-3, y-3, 6,6); } } /***************************************************/ int ClickGraf(gp,child,mx,my) GRAF *gp; Window child; int mx,my; { /* returns '1' if GrafFunc was changed, '0' otherwise */ int i, j, rv; byte oldfunc[256]; BUTT *bp; Window rW, cW; int x, y, rx, ry, firsttime=1; unsigned int mask; rv = 0; while (1) { /* loop until Button1 up and ShiftKey up */ if (!XQueryPointer(theDisp,gp->win,&rW,&cW,&rx,&ry, &mx,&my,&mask)) continue; if (!firsttime && !(mask & (Button1Mask | ShiftMask))) break; /* if it's not the first time, wait for Button1 to be pressed */ if (!firsttime && !(mask & Button1Mask)) continue; firsttime = 0; for (i=0; i<N_GFB; i++) { bp = &gp->butts[i]; if (PTINRECT(mx, my, bp->x, bp->y, bp->w, bp->h)) break; } if (i<N_GFB) { /* found one */ if (BTTrack(bp)) { /* it was selected */ switch (i) { case GFB_SPLINE: case GFB_LINE: gp->gammamode = 0; if ((i==GFB_SPLINE && !gp->spline) || (i==GFB_LINE && gp->spline)) { gp->spline = !gp->spline; gp->butts[GFB_SPLINE].lit = gp->spline; gp->butts[GFB_LINE].lit = !gp->spline; BTRedraw(&gp->butts[GFB_SPLINE]); BTRedraw(&gp->butts[GFB_LINE]); for (i=0; i<256; i++) oldfunc[i] = gp->func[i]; GenerateGrafFunc(gp,1); for (i=0; i<256 && abs(oldfunc[i] - gp->func[i])<2; i++); if (i<256) rv = 1; } else { gp->butts[i].lit = 1; BTRedraw(&gp->butts[i]); } break; case GFB_RESET: for (j=0; j<gp->nhands; j++) { gp->hands[j].y = gp->hands[j].x; } gp->gammamode = 0; for (i=0; i<256; i++) oldfunc[i] = gp->func[i]; GenerateGrafFunc(gp,1); for (i=0; i<256 && abs(oldfunc[i] - gp->func[i])<2; i++); if (i<256) rv = 1; break; case GFB_GAMMA: gp->entergamma = -1; drawGraf(gp,1); break; case GFB_ADDH: if (gp->nhands < MAX_GHANDS) { /* find largest x-gap in handles, put new handle in mid */ int lgap, lpos, x, y; lgap = gp->hands[1].x - gp->hands[0].x; lpos = 1; for (j=1; j<gp->nhands-1; j++) if ((gp->hands[j+1].x - gp->hands[j].x) > lgap) { lgap = gp->hands[j+1].x - gp->hands[j].x; lpos = j+1; } /* open up position in hands[] array */ xvbcopy((char *) &gp->hands[lpos], (char *) &gp->hands[lpos+1], (gp->nhands - lpos) * sizeof(XPoint)); x = gp->hands[lpos-1].x + lgap/2; y = gp->func[x]; gp->hands[lpos].x = x; gp->hands[lpos].y = y; gp->nhands++; for (i=0; i<256; i++) oldfunc[i] = gp->func[i]; GenerateGrafFunc(gp,1); for (i=0; i<256 && abs(oldfunc[i] - gp->func[i])<2; i++); if (i<256) rv = 1; if (gp->nhands==MAX_GHANDS) /* turn off 'add' button */ BTSetActive(&gp->butts[GFB_ADDH], 0); if (gp->nhands==3) /* turn on 'del' button */ BTSetActive(&gp->butts[GFB_DELH], 1); } break; case GFB_DELH: if (gp->nhands > 2) { /* find (middle) point whose x-distance to previous and next points is minimal. Delete that point */ int dist, mdist, mpos; mdist = (gp->hands[1].x - gp->hands[0].x) + (gp->hands[2].x - gp->hands[1].x); mpos = 1; for (j=2; j<gp->nhands-1; j++) { dist = (gp->hands[j ].x - gp->hands[j-1].x) + (gp->hands[j+1].x - gp->hands[j].x); if (dist < mdist) { mdist = dist; mpos = j; } } /* delete position 'mpos' in hands[] array */ xvbcopy((char *) &gp->hands[mpos+1], (char *) &gp->hands[mpos], (gp->nhands-mpos-1) * sizeof(XPoint)); gp->nhands--; for (i=0; i<256; i++) oldfunc[i] = gp->func[i]; GenerateGrafFunc(gp,1); for (i=0; i<256 && abs(oldfunc[i] - gp->func[i])<2; i++); if (i<256) rv = 1; if (gp->nhands==MAX_GHANDS-1) /* turn on 'add' button */ BTSetActive(&gp->butts[GFB_ADDH], 1); if (gp->nhands==2) /* turn off 'del' button */ BTSetActive(&gp->butts[GFB_DELH], 0); } break; } } } else if (cW == gp->gwin) { /* clicked in graph */ int h, vertonly, offx, offy; XTranslateCoordinates(theDisp, gp->win, gp->gwin,mx,my,&mx,&my,&cW); /* see if x,y is within any of the handles */ for (h=0; h<gp->nhands; h++) { if (PTINRECT(mx*2,(127-my)*2, gp->hands[h].x-5,gp->hands[h].y-5,11,11)) break; } if (h==gp->nhands) { /* not found. wait 'til mouseup */ while (XQueryPointer(theDisp,gp->gwin,&rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button1Mask)) break; /* button released */ } } else { /* track handle */ int origx, origy, orighx, orighy, dx, dy, olddx, olddy, grab; drawHandPos(gp, h); /* keep original mouse position in 'mx,my', and warp mouse to center of screen */ grab = !XGrabPointer(theDisp, gp->gwin, False, 0, GrabModeAsync, GrabModeAsync, None, inviso, CurrentTime); XWarpPointer(theDisp, None, rootW, 0,0,0,0, dispWIDE/2, dispHIGH/2); origx = dispWIDE/2; origy = dispHIGH/2; orighx = gp->hands[h].x; orighy = gp->hands[h].y; gp->gammamode = 0; offx = gp->hands[h].x - origx; offy = gp->hands[h].y - origy; vertonly = (h==0 || h==(gp->nhands-1)); olddx = 0; olddy = 0; while (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x,&y,&mask)) { int newx, newy; if (!(mask & Button1Mask)) break; /* button released */ /* x,y are in screen coordinates */ if (vertonly) x = origx; /* no sidewards motion */ dx = x - origx; dy = origy - y; /* flip y axis */ /* new (virt) position of handle is (desired) orighx + dx, orighy + dy */ if (!vertonly) { /* keep this handle between its neighbors */ if (dx+orighx <= gp->hands[h-1].x) dx=(gp->hands[h-1].x+1)-orighx; if (dx+orighx >= gp->hands[h+1].x) dx=(gp->hands[h+1].x-1)-orighx; } newx = dx + orighx; newy = dy + orighy; RANGE(newy, 0, 255); if (newx != gp->hands[h].x || newy != gp->hands[h].y) { /* this handle has moved... */ XSetForeground(theDisp, theGC, gp->bg); XFillRectangle(theDisp, gp->gwin, theGC, (gp->hands[h].x/2)-3, ((255-gp->hands[h].y)/2)-3, 7,7); gp->hands[h].x = newx; gp->hands[h].y = newy; drawGraf(gp,1); /* erase old trace */ GenerateGrafFunc(gp,0); drawGraf(gp,0); drawHandPos(gp, h); rv = 1; olddx = dx; olddy = dy; if (gp->drawobj) (gp->drawobj)(); } } drawHandPos(gp, -1); XWarpPointer(theDisp, None, gp->gwin, 0,0,0,0, gp->hands[h].x/2, (255-gp->hands[h].y)/2); if (grab) XUngrabPointer(theDisp, CurrentTime); } } } return rv; } static void drawHandPos(gp, hnum) GRAF *gp; int hnum; { int w; char *tstr = "888,888"; /* if hnum < 0, clears the text area */ XSetFont(theDisp, theGC, monofont); w = XTextWidth(monofinfo, tstr, strlen(tstr)); if (hnum >= 0) sprintf(str,"%3d,%3d",gp->hands[hnum].x,gp->hands[hnum].y); else sprintf(str," "); XSetForeground(theDisp, theGC, gp->fg); XSetBackground(theDisp, theGC, gp->bg); XDrawImageString(theDisp, gp->win, theGC, 130-w, 1+ASCENT, str, strlen(str)); XSetFont(theDisp, theGC, mfont); } /***************************************************/ int GrafKey(gp,str) GRAF *gp; char *str; { int len, ok; /* returns '1' if str was 'eaten', '2' if CR was hit, '0' otherwise. */ if (!gp->entergamma) { /* not entering a value yet */ if (*str == 'g') { gp->entergamma = -1; /* special 'show old value highlited' */ drawGraf(gp,1); str++; } else return 0; } while (*str) { if (gp->entergamma == -1 && (*str != '\012' && *str != '\015' && *str != '\033')) { gp->entergamma = 1; gp->gvstr[0] = '\0'; drawGraf(gp,1); } ok = 0; len = strlen(gp->gvstr); if (*str>= '0' && *str <= '9') { if (len < GVMAX) { gp->gvstr[len++] = *str; gp->gvstr[len] = '\0'; ok = 1; } } else if (*str == '.') { if (len < GVMAX && ((char *) strchr(gp->gvstr,'.'))==NULL) { gp->gvstr[len++] = *str; gp->gvstr[len] = '\0'; ok = 1; } } else if (*str == '\010' || *str == '\177') { /* BS or DEL */ if (len > 0) gp->gvstr[--len] = '\0'; ok = 1; } else if (*str == '\025' || *str == '\013') { /* ^U or ^K clear line */ gp->gvstr[0] = '\0'; len = 0; ok = 1; } else if (*str == '\012' || *str == '\015' || *str == '\033') { /* CR, LF or ESC*/ if (len>0 && *str != '\033') { /* 'Ok' processing */ if (sscanf(gp->gvstr, "%lf", &(gp->gamma))==1) { if (gp->gamma == 0.0) gp->gamma = 0.001; if (gp->gamma >= 1000.0) gp->gamma = 1000.0; gp->gammamode = 1; gp->entergamma = 0; GenerateGrafFunc(gp,1); return 2; } } else { gp->entergamma = 0; GenerateGrafFunc(gp,1); } break; /* out of *str loop */ } if (!ok) XBell(theDisp, 0); else { XClearWindow(theDisp,gp->gwin); drawGraf(gp,1); } str++; } return 1; } /*********************/ void GenerateGrafFunc(gp,redraw) GRAF *gp; int redraw; { /* generate new gp->func data (ie, handles have moved, or line/spline setting has changed) and redraw the entire graph area */ int i,j,k; /* do sanity check. (x-coords must be sorted (strictly increasing)) */ for (i=0; i<gp->nhands; i++) { RANGE(gp->hands[i].x, 0, 255); RANGE(gp->hands[i].y, 0, 255); } gp->hands[0].x = 0; gp->hands[gp->nhands-1].x = 255; for (i=1; i<gp->nhands-1; i++) { if (gp->hands[i].x < i) gp->hands[i].x = i; if (gp->hands[i].x > 256-gp->nhands+i) gp->hands[i].x = 256-gp->nhands+i; if (gp->hands[i].x <= gp->hands[i-1].x) gp->hands[i].x = gp->hands[i-1].x + 1; } /* recompute the function */ if (gp->gammamode) { /* do gamma function instead of interpolation */ double y, invgam; invgam = 1.0 / gp->gamma; for (i=0; i<256; i++) { y = pow( ((double) i / 255.0), invgam) * 255.0; j = (int) floor(y + 0.5); RANGE(j,0,255); gp->func[i] = j; } for (i=0; i<gp->nhands; i++) { gp->hands[i].y = gp->func[gp->hands[i].x]; } } else if (!gp->spline) { /* do linear interpolation */ int y,x1,y1,x2,y2; double yd; for (i=0; i<gp->nhands-1; i++) { x1 = gp->hands[ i ].x; y1 = gp->hands[ i ].y; x2 = gp->hands[i+1].x; y2 = gp->hands[i+1].y; for (j=x1,k=0; j<=x2; j++,k++) { /* x2 <= 255 */ yd = ((double) k * (y2 - y1)) / (x2 - x1); y = y1 + (int) floor(yd + 0.5); RANGE(y,0,255); gp->func[j] = y; } } } else { /* splinear interpolation */ static int x[MAX_GHANDS], y[MAX_GHANDS]; double yf[MAX_GHANDS]; double yd; for (i=0; i<gp->nhands; i++) { x[i] = gp->hands[i].x; y[i] = gp->hands[i].y; } InitSpline(x, y, gp->nhands, yf); for (i=0; i<256; i++) { yd = EvalSpline(x, y, yf, gp->nhands, (double) i); j = (int) floor(yd + 0.5); RANGE(j,0,255); gp->func[i] = j; } } if (redraw) { /* redraw graph */ XClearWindow(theDisp, gp->gwin); drawGraf(gp,0); } } /*********************/ void Graf2Str(gp, str) GRAF_STATE *gp; char *str; { /* generates strings of the form: "S 3 : 0,0 : 63,63 : 255,255", (meaning SPLINE, 3 points, and the 3 sets of handle coordinates) This is the string that you'd put in the 'xv.preset1.vgraph:' resource, ferinstance */ /* maximum length of string generated is 164 characters. str better be able to hold it... */ int i; char cstr[16]; if (gp->gammamode) { sprintf(str,"G %g", gp->gamma); } else { sprintf(str, "%c %d", gp->spline ? 'S' : 'L', gp->nhands); for (i=0; i<gp->nhands; i++) { sprintf(cstr," : %d,%d", gp->hands[i].x, gp->hands[i].y); strcat(str, cstr); } } } /*********************/ int Str2Graf(gp, str) GRAF_STATE *gp; char *str; { /* parses strings of the form: "S 3 : 0,0 : 63,63 : 255,255", (meaning SPLINE, 3 points, and the 3 sets of handle coordinates) This is the string that you'd put in the 'xv.preset1.igraf:' resource, ferinstance */ /* returns '1' if unable to parse. Note: does NOT redraw the graf, as it may be called before the graph window has even been created */ /* NOTE: I deliberately avoid using '*dp++ = *sp++', as this sort of thing tends to break optimizers */ char tstr[256], tstr1[256], *sp, *dp; XPoint coords[MAX_GHANDS]; int spline, nhands, i, x, y; if (!str) return 1; /* NULL strings don't parse well! */ /* first, strip all pesky whitespace from str */ for (sp=str, dp=tstr; *sp; sp++) if (*sp > ' ') { *dp = *sp; dp++; } *dp = '\0'; /* check for 'gamma'-style str */ if (*tstr == 'G' || *tstr == 'g') { if (sscanf(tstr+1, "%lf", &(gp->gamma)) == 1 && gp->gamma > 0.0 && gp->gamma <= 1000.0) { gp->gammamode = 1; sprintf(gp->gvstr, "%.5g", gp->gamma); return 0; } else return 1; } /* read Spline, or Line (S/L) character */ sp = tstr; if (*sp == 'S' || *sp == 's') spline = 1; else if (*sp == 'L' || *sp == 'l') spline = 0; else return 1; /* read 'nhands' */ sp++; dp = tstr1; while (*sp && *sp != ':') { *dp = *sp; dp++; sp++; } *dp++ = '\0'; nhands = atoi(tstr1); if (nhands>MAX_GHANDS || nhands<2) return 1; /* read nhands coordinate pairs */ for (i=0; i<nhands && *sp; i++) { sp++; dp = tstr1; while (*sp && *sp != ':') {*dp = *sp; dp++; sp++; } *dp++ = '\0'; if (sscanf(tstr1,"%d,%d",&x, &y) != 2) return 1; if (x < 0 || x > 255 || y < 0 || y > 255) return 1; /* out of range */ coords[i].x = x; coords[i].y = y; } if (i<nhands) return 1; /* string terminated early */ gp->nhands = nhands; gp->spline = spline; for (i=0; i<nhands; i++) { gp->hands[i].x = coords[i].x; gp->hands[i].y = coords[i].y; } return 0; } /*********************/ void GetGrafState(gp, gsp) GRAF *gp; GRAF_STATE *gsp; { int i; gsp->spline = gp->spline; gsp->entergamma= gp->entergamma; gsp->gammamode = gp->gammamode; gsp->gamma = gp->gamma; gsp->nhands = gp->nhands; strcpy(gsp->gvstr, gp->gvstr); for (i=0; i<MAX_GHANDS; i++) { gsp->hands[i].x = gp->hands[i].x; gsp->hands[i].y = gp->hands[i].y; } } /*********************/ int SetGrafState(gp, gsp) GRAF *gp; GRAF_STATE *gsp; { #define IFSET(a,b) if ((a) != (b)) { a = b; rv++; } int i; int rv = 0; IFSET(gp->spline, gsp->spline); IFSET(gp->entergamma, gsp->entergamma); IFSET(gp->gammamode, gsp->gammamode); IFSET(gp->gamma, gsp->gamma); IFSET(gp->nhands, gsp->nhands); if (strcmp(gp->gvstr, gsp->gvstr)) { strcpy(gp->gvstr, gsp->gvstr); rv++; } for (i=0; i<gp->nhands; i++) { IFSET(gp->hands[i].x, gsp->hands[i].x); IFSET(gp->hands[i].y, gsp->hands[i].y); } gp->butts[GFB_DELH].active = (gp->nhands > 2); gp->butts[GFB_ADDH].active = (gp->nhands < MAX_GHANDS); gp->butts[GFB_SPLINE].lit = gp->spline; gp->butts[GFB_LINE].lit = !gp->spline; if (rv) { XClearWindow(theDisp,gp->gwin); GenerateGrafFunc(gp,0); RedrawGraf(gp,0); RedrawGraf(gp,1); } return rv; } /*********************/ void InitSpline(x,y,n,y2) int *x, *y, n; double *y2; { /* given arrays of data points x[0..n-1] and y[0..n-1], computes the values of the second derivative at each of the data points y2[0..n-1] for use in the splint function */ int i,k; double p,qn,sig,un,u[MAX_GHANDS]; y2[0] = u[0] = 0.0; for (i=1; i<n-1; i++) { sig = ((double) x[i]-x[i-1]) / ((double) x[i+1] - x[i-1]); p = sig * y2[i-1] + 2.0; y2[i] = (sig-1.0) / p; u[i] = (((double) y[i+1]-y[i]) / (x[i+1]-x[i])) - (((double) y[i]-y[i-1]) / (x[i]-x[i-1])); u[i] = (6.0 * u[i]/(x[i+1]-x[i-1]) - sig*u[i-1]) / p; } qn = un = 0.0; y2[n-1] = (un-qn*u[n-2]) / (qn*y2[n-2]+1.0); for (k=n-2; k>=0; k--) y2[k] = y2[k]*y2[k+1]+u[k]; } /*********************/ double EvalSpline(xa,ya,y2a,n,x) double y2a[],x; int n,xa[],ya[]; { int klo,khi,k; double h,b,a; klo = 0; khi = n-1; while (khi-klo > 1) { k = (khi+klo) >> 1; if (xa[k] > x) khi = k; else klo = k; } h = xa[khi] - xa[klo]; if (h==0.0) FatalError("bad xvalues in splint\n"); a = (xa[khi]-x)/h; b = (x-xa[klo])/h; return (a*ya[klo] + b*ya[khi] + ((a*a*a-a)*y2a[klo] +(b*b*b-b)*y2a[khi]) * (h*h) / 6.0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.