Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!rutgers!super.upenn.edu!dsl.cis.upenn.edu!bradley From: bradley@dsl.cis.upenn.edu (John Bradley) Newsgroups: comp.windows.x Subject: xsplot - a SPICE plotting program for X V10.4 (part 2 of 4) Message-ID: <1842@super.upenn.edu> Date: Mon, 24-Aug-87 19:07:07 EDT Article-I.D.: super.1842 Posted: Mon Aug 24 19:07:07 1987 Date-Received: Tue, 25-Aug-87 06:49:40 EDT References: <1841@super.upenn.edu> Sender: news@super.upenn.edu Reply-To: bradley@dsl.cis.upenn.edu.UUCP (John Bradley) Distribution: na Organization: University of Pennsylvania Lines: 2032 xsplot is an X program (10.4) for viewing, plotting, and analyzing SPICE output. It will drive an HP-GL plotter for hardcopy. It can be used to look at non-SPICE data, also. Why, it could be the Neatest Thing Ever. Probably not, though. Runs just dandy on Berkeley 4.2 Unix variants (on the IBM RT under 4.2 and 4.3, and on random Vaxen under Ultrix 1.2 and 2.0) --John Bradley - University of Pennsylvania - bradley@cis.upenn.edu Part 2 of 4 -------------------------cut here---------------------- #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -d ./xsplot` then mkdir ./xsplot echo "mkdir ./xsplot" fi if `test ! -s ./xsplot/xsplotctl.c` then echo "writing ./xsplot/xsplotctl.c" cat > ./xsplot/xsplotctl.c << '\Rogue\Monster\' /************************************************************************/ /* XSPLOTCTL.C */ /*----------------------------------------------------------------------*/ /* Library of routines to handle controls (push buttons) */ /*----------------------------------------------------------------------*/ /* void R2Str (num); */ /* void O2Str (num); */ /* void ModifyBut (bnum,ctrl); */ /* void SetXButs (); */ /* void DrawXButs (); */ /* void FpToEng (str,num); */ /************************************************************************/ #include "xsplot.h" /************************************************************************/ R2Str(num) int num; /* takes the power and multiplier values and fills in the str and val fields */ { Range *rp = &ranges[num]; strcpy(rp->str,multstr[rp->multiplier]); strcat(rp->str,prefix[rp->power]); strcat(rp->str,units[num]); rp->val=mult[rp->multiplier] * pow(10.0,(double) ((rp->power-4)*3) ); } /************************************************************************/ O2Str(num) int num; /* takes the val field and fills in the str field */ { Offset *op = &offsets[num]; char tmp[20]; int i,e; FpToEng(tmp,op->val); /* tmp = 'x.xxxExx' */ /* find the 'E' part, truncate tmp at that point, and set 'e' = the exponent */ for (i=4; (tmp[i]!='E') && tmp[i]; i++); if (!tmp[i]) e=0; /* was no 'E' */ else { tmp[i]='\0'; e=atoi(tmp+i+1); } /* do a quick range check */ if (e<-12) { op->val=0.0; strcpy(tmp,"0.000"); e=0; } if (e>12 && op->val>0.0) { op->val= 999.9e12; strcpy(tmp,"999.9"); e=12; } if (e>12 && op->val<0.0) { op->val= -999.9e12; strcpy(tmp,"-999.9"); e=12; } /* tack units onto end of string */ strcat(tmp,prefix[(e/3)+4]); strcat(tmp,units[num]); strcpy(op->str,tmp); } /************************************************************************/ ModifyBut(bnum,ctrl) int bnum; { if (ctrl==12) Norm(bnum); else if (ctrl==13) Neg(bnum,1); else if (ctrl==14) Pos(bnum,1); else if (ctrl==15) Neg(bnum,2); else if (ctrl==16) Pos(bnum,2); else if (ctrl==17) Neg(bnum,3); else if (ctrl==18) Pos(bnum,3); } /************************************************************************/ static Neg(bnum,amount) int bnum,amount; { int rnum,i; Range *rp; Offset *op; /* if it's one of the X controls, and we're non-linear, then deal */ if ((bnum==2 || bnum==3) && xscal!=LINEAR) ModXCtrl(bnum,-1*amount); /* see if it's one of the range controls */ else if ((bnum==3) || (bnum==5) || (bnum==7) || (bnum==9) || (bnum==11)) { rnum=(bnum-3)/2; rp= &ranges[rnum]; switch (amount) { case 1: rp->multiplier--; break; case 2: rp->multiplier-=3; break; case 3: rp->power--; break; } /* adjust things */ if (rp->multiplier<0) { rp->multiplier+=9; rp->power--; } if (rp->power<0) { rp->power = rp->multiplier = 0; } R2Str(rnum); butts[bnum].st = rp->str; RedrawBut(&butts[bnum]); } /* see if it's one of the offset controls */ else if ((bnum==2) || (bnum==4) || (bnum==6) || (bnum==8) || (bnum==10)) { if (ylock && bnum!=2) { for (i=1; i<=numy; i++) ModOffset(i,-1*amount); } else { rnum=(bnum-2)/2; ModOffset(rnum,-1*amount); } } /* see if it's the X Grid Control */ else if (bnum==0) { xscal=(xscal+2) % 3; butts[bnum].st=scals[xscal]; RedrawBut(&butts[bnum]); DrawXButs(); } } /************************************************************************/ static Pos(bnum,amount) int bnum,amount; { int rnum,i; Range *rp; Offset *op; /* if it's one of the X controls, and we're non-linear, then deal */ if ((bnum==2 || bnum==3) && xscal!=LINEAR) ModXCtrl(bnum,amount); /* see if it's one of the range controls */ else if ((bnum==3) || (bnum==5) || (bnum==7) || (bnum==9) || (bnum==11)) { rnum=(bnum-3)/2; rp= &ranges[rnum]; switch (amount) { case 1: rp->multiplier++; break; case 2: rp->multiplier+=3; break; case 3: rp->power++; break; } /* adjust things */ if (rp->multiplier>8) { rp->multiplier-=9; rp->power++; } if (rp->power>8) { rp->power = rp->multiplier = 8; } R2Str(rnum); butts[bnum].st = rp->str; RedrawBut(&butts[bnum]); } /* see if it's one of the offset controls */ else if ((bnum==2) || (bnum==4) || (bnum==6) || (bnum==8) || (bnum==10)) { if (ylock && bnum!=2) { for (i=1; i<=numy; i++) ModOffset(i,amount); } else { rnum=(bnum-2)/2; ModOffset(rnum,amount); } } /* see if it's the X Grid Control */ else if (bnum==0) { xscal=(xscal+1) % 3; butts[bnum].st=scals[xscal]; RedrawBut(&butts[bnum]); DrawXButs(); } } /************************************************************************/ static Norm(bnum) int bnum; { int rnum,i; Range *rp; Offset *op; if ((bnum==2 || bnum==3) && xscal!=LINEAR) ModXCtrl(bnum,0); else if ((bnum==3) || (bnum==5) || (bnum==7) || (bnum==9) || (bnum==11)) { rnum=(bnum-3)/2; rp = &ranges[rnum]; rp->power =4; rp->multiplier=0; rp->val=1.0; R2Str(rnum); butts[bnum].st=rp->str; RedrawBut(&butts[bnum]); } else if ((bnum==2) || (bnum==4) || (bnum==6) || (bnum==8) || (bnum==10)) { if (ylock && bnum!=2) { for (i=1; i<=numy; i++) { offsets[i].val=0.0; O2Str(i); butts[2+i*2].st=offsets[i].str; RedrawBut(&butts[2+i*2]); } } else { rnum=(bnum-2)/2; offsets[rnum].val=0.0; O2Str(rnum); butts[bnum].st=offsets[rnum].str; RedrawBut(&butts[bnum]); } } else if (bnum==0) { xscal=LINEAR; butts[bnum].st=scals[xscal]; RedrawBut(&butts[bnum]); DrawXButs(); } } /************************************************************************/ static ModOffset(num,amt) int num,amt; { double rng; int i,bnum; bnum = num*2+2; rng = ranges[num].val; if (amt== 3) offsets[num].val += (rng*10.0); else if (amt== 2) offsets[num].val += (rng); else if (amt== 1) offsets[num].val += (rng/10.0); else if (amt== -1) offsets[num].val -= (rng/10.0); else if (amt== -2) offsets[num].val -= (rng); else if (amt== -3) offsets[num].val -= (rng*10.0); O2Str(num); butts[bnum].st=offsets[num].str; RedrawBut(&butts[bnum]); } /************************************************************************/ static ModXCtrl(bnum,amt) int bnum,amt; { int *offs, *rang; if (xscal==LOG10) { offs = &L10Offset; rang = &L10Range;} else { offs = &OctOffset; rang = &OctRange;} if (bnum==2) { /* offset */ if (amt) { *offs += amt; if (*offs<-19) *offs = -19; if (*offs>19) *offs = 19; } else *offs=0; SetXButs(); RedrawBut(&butts[bnum]); } else { /* range */ if (amt>0) { *rang+=1; *rang%=3; } else if (amt<0) { *rang+=2; *rang%=3; } else *rang=0; SetXButs(); RedrawBut(&butts[bnum]); } } /************************************************************************/ SetXButs() /* sets top two buttons (2,3) to appropriate strings */ { static char oStr[20]; static char rStrs[3][8]={"1 div","3 divs","10 divs"}; switch (xscal) { case LINEAR: butts[2].st=offsets[0].str; butts[3].st=ranges[0].str; break; case LOG10: sprintf(oStr,"1E%d %s",L10Offset,units[0]); butts[2].st=oStr; butts[3].st=rStrs[L10Range]; break; case OCTAVE: sprintf(oStr,"2^%d %s",OctOffset,units[0]); butts[2].st=oStr; butts[3].st=rStrs[OctRange]; break; } if (butts[0].st != scals[xscal]) { butts[0].st = scals[xscal]; } } /************************************************************************/ DrawXButs() /* sets top two buttons (2,3) to appropriate strings and draws them */ { SetXButs(); RedrawBut(&butts[2]); RedrawBut(&butts[3]); } /******************/ FpToEng(st,aval) char *st; double aval; /* * converts a floating point number to a string in the form 'x.xxx Exx', * where the Exx is divisible by 3. (engineering notation) */ { int e,ei,i,j; char tmp[20]; sprintf(st,"%e",fabs(aval)); /* generate the 'std' E-notation */ *(st+5)='\0'; /* take the first five chars */ /* 'x.xxx' */ for (i=6; *(st+i)!='e'; i++); /* find the beginning of the 'E' part */ i++; e=atoi(st+i); /* exponent value (an integer) */ i=(e+99) % 3; /* number of places to shift dec. point (0-2) */ ei = e-i; /* new/improved exp. value (divisible by 3) */ for (j=1; j<=i; j++) /* shift the decimal point right 0-2 times */ *(st+j) = *(st+j+1); *(st+i+1) = '.'; if (aval<0.0) { /* if negative, add a '-' sign at the front */ for (i=4; i>0; i--) *(st+i) = *(st+i-1); *st = '-'; } if (ei) { /* tack on the exponent part */ sprintf(tmp,"E%-3d",ei); strcat(st,tmp); } } \Rogue\Monster\ else echo "will not over write ./xsplot/xsplotctl.c" fi if `test ! -s ./xsplot/xsplotdiv.c` then echo "writing ./xsplot/xsplotdiv.c" cat > ./xsplot/xsplotdiv.c << '\Rogue\Monster\' /************************************************************************/ /* XSPLOTDIV.C - routines for manipulating the 'diversion' */ /*----------------------------------------------------------------------*/ /* InitDivers(); - called once at start of program to init it */ /* OpenDivers(); - open up the diversion and execute it */ /* RedrawDivers(); - called by 'HandleEvent' to redraw the thing */ /************************************************************************/ #include "xsplot.h" /* size of interesting part of diversion window */ #define DW 200 #define DH 290 #define BRWIDE 16 #define BRHIGH 8 #define BRWIDE2 8 #define BRHIGH2 4 #define BX(j) (20*j + 10) #define BY(i) (14*i + 24) static int invplanes,score,fast,small,grace,ballnum,numbricks; static short bx,by,bdx,bdy,px,py; static int pwidth, bwidth=6, pwidth2, bwidth2; static Cursor noncurs; static short brick[6][10]; /* hint, hint */ static short bscore[6] = {5,5,3,3,1,1}; /************************************************************************/ InitDivers() { static short non_bits[8] = {0,0,0,0,0,0,0,0}; /* an inviso-cursor */ invplanes = dlgFcol ^ dlgBcol; px = -1; /* a very unlikely number */ py = 272; bwidth2 = bwidth/2; NewGame(); noncurs = XCreateCursor(8,8,non_bits,non_bits,0,0,1,0,GXcopy); XDefineCursor(diversW,noncurs); } /************************************************************************/ static NewGame() { score = ballnum = 0; NewBall(); NewBricks(); } /************************************************************************/ static NewBall() { char *tmp = "Game Over"; char *tmp1 = "Click mouse to continue"; XEvent event; ballnum++; if (ballnum==4) { /* game over */ XText(diversW,(DW-XStringWidth(tmp,butfinfo,0,0))/2, 150,tmp,strlen(tmp),butfont,dlgFcol,dlgBcol); XText(diversW,(DW-XStringWidth(tmp1,butfinfo,0,0))/2, 162,tmp1,strlen(tmp1),butfont,dlgFcol,dlgBcol); } bx = (abs(rand())%20)*10 + 5; by = 141; bdx = (abs(rand())%21)-10; bdy = 6; InvertPad(); pwidth=32; pwidth2 = pwidth/2; InvertPad(); fast=small=0; grace=40; } /************************************************************************/ static NewBricks() { int i,j; numbricks=60; for (i=0; i<6; i++) for (j=0; j<10; j++) brick[i][j]=1; } /************************************************************************/ OpenDivers() { XEvent event; Window subw; int mx,my,ox,oy,gameover; int i,w,h,sc; sc=selCB; selCB=3; /* to force the inverted frame to be color '3' */ for (i=1; i<=201; i+=8) { Frame(gridW,i-10,i-15,i+10,i+15,1,dlgFcol,GXinvert); XFlush(); Timer(15000L); } for (i=1; i<201; i+=8) { Frame(gridW,i-10,i-15,i+10,i+15,1,dlgFcol,GXinvert); XFlush(); Timer(15000L); } selCB=sc; for (w=20,h=30; w<200; w+=10,h+=15) { /* Zoom! */ int x,y; x=201-w/2; y=201-h/2; Frame(gridW,x,y,x+w,y+h,1,dlgFcol,GXcopy); XFlush(); Timer(25000L); } XMapWindow(diversW); gameover=0; grace=40; /* handle events until the next mouse event */ while (1) { Timer(30000L); if (XPending()) { XNextEvent(&event); if (event.type != ButtonPressed) HandleEvent(&event); else if (event.type == ButtonPressed && gameover) { gameover=0; NewGame(); RedrawDivers(); } else break; } if (gameover) continue; /* advance diversion by one frame */ XQueryMouse(diversW,&mx,&my,&subw); if (mx>DW) mx=DW; if (mx<0) mx=0; if (mx != px) { /* move player thing */ InvertPad(); px = mx; InvertPad(); } if (grace) { /* give the player a grace period before moving ball */ grace--; continue; } /* move non-player thing */ ox = bx; oy = by; bx += bdx; by += bdy; if ( (bx-bwidth2 < 0) || (bx+bwidth2 > DW) ) { /* hit left or right */ bdx = -bdx; bx += 2*bdx; } if (by-bwidth2 < 0) { /* hit back */ bdy = - bdy; by += 2*bdy; if (!small) { /* make paddle smaller */ small=1; InvertPad(); pwidth=18; pwidth2=pwidth/2; InvertPad(); } } else if (by+bwidth > DH) { /* hit bottom */ XFeep(0); NewBall(); if (ballnum==4) { /* game over */ gameover=1; continue; } else DrawBC(); } else if ( (by+bwidth2) >= py && (by-bwidth2) <= (py+8) && (bx+bwidth2) > (px-pwidth2) && (bx-bwidth2) < (px+pwidth2) ) { /* hit paddle */ bdy = -bdy; bdx = (bx-px)/2; if (small) bdx=2*bdx; /* more english on smaller paddle */ } else { /* check to see if it hit a brick */ int i,j,k; for (i=0; i<6; i++) { /* find row */ k=BY(i); if ( (k-BRHIGH2) < (by+bwidth2) && (k+BRHIGH2) > (by-bwidth2) ) break; } if (i<6) { /* it's on a row, now check individual bricks */ for (j=0; j<10; j++) { k=BX(j); if ( brick[i][j] && (k-BRWIDE2) < (bx+bwidth2) && (k+BRWIDE2) > (bx-bwidth2) ) break; } if (j<10) { /* hit brick[i][j] */ brick[i][j]=0; numbricks--; InvBrick(i,j); bdy = -bdy; score += bscore[i]; DrawScore(); if (!fast && i<2) { /* hit a rear brick. speedup */ fast=1; bdy = bdy * 2; } if (!numbricks) { /* completed the thing. Wowzo! */ XText(diversW, (DW-XStringWidth("Wowzo!",dlogfinfo,0,0))/2, 150,"Wowzo!",6,dlogfont,dlgFcol,dlgBcol); score+=200; DrawScore(); XFeep(0); XFeep(0); XFeep(0); XFlush(); Timer(2000000L); ballnum--; NewBall(); NewBricks(); RedrawDivers(); ox=bx; oy=by; } } } } InvertBall(ox,oy); InvertBall(bx,by); } XUnmapWindow(diversW); } /************************************************************************/ static InvertBall(x,y) int x,y; { XPixFill(diversW,x-bwidth2,y-bwidth2,bwidth,bwidth,1,0,GXinvert,invplanes); } /************************************************************************/ static InvBrick(i,j) int i,j; { XPixFill(diversW,BX(j)-BRWIDE2,BY(i)-BRHIGH2,BRWIDE,BRHIGH, 1,0,GXinvert,invplanes); } /************************************************************************/ static InvertPad() { XPixFill(diversW,px-pwidth2,py,pwidth,8,1,0,GXinvert,invplanes); } /************************************************************************/ static DrawBC() { char tmp[24]; sprintf(tmp,"Ball %d",ballnum); XText(diversW,20,DH+1,tmp,strlen(tmp),butfont,dlgBcol,dlgFcol); } /************************************************************************/ static DrawScore() { char tmp[24]; sprintf(tmp,"Score=%d",score); XText(diversW,DW-20-XStringWidth(tmp,butfinfo,0,0), DH+1,tmp,strlen(tmp),butfont,dlgBcol,dlgFcol); } /************************************************************************/ RedrawDivers() { int i,j; XClear(diversW); InvertPad(); InvertBall(bx,by); for (i=0; i<6; i++) for (j=0; j<10; j++) if (brick[i][j]) InvBrick(i,j); XPixSet(diversW,0,DH,DW,10,dlgFcol); DrawBC(); DrawScore(); } \Rogue\Monster\ else echo "will not over write ./xsplot/xsplotdiv.c" fi if `test ! -s ./xsplot/xsplotdlg.c` then echo "writing ./xsplot/xsplotdlg.c" cat > ./xsplot/xsplotdlg.c << '\Rogue\Monster\' /************************************************************************/ /* XSPLOTDLG.C - routines for manipulating dialog boxes */ /*----------------------------------------------------------------------*/ /* OpenDlog(w); - open a dialog window */ /* CloseDlog(); - close the current dialog window */ /* RedrawDlog(); - got an 'ExposeWindow'. Redraw the dlog */ /* DlogKey(st,len); - got a 'KeyPress' during dialog. Deal with it */ /* ClickDlog(x,y); - got a mouse click at x,y. Do something. */ /************************************************************************/ #include "xsplot.h" static int selanal; /**********************/ OpenDlog(w) Window w; { int i; dlogW = w; if (dlogW == LoadDlog) { /* 380x100 */ MakeButton(&dbutts[0],dlogW,30, 60,80,30,"Ok",dlogfinfo); /* MakeButton(&dbutts[1],dlogW,150,60,80,30,"No Parse",dlogfinfo); */ MakeButton(&dbutts[1],dlogW,270,60,80,30,"Cancel",dlogfinfo); for (i=0; i<2; i++) XSelectInput(dbutts[i].win,ExposeWindow); XMapSubwindows(dlogW); dlogstr[0]='\0'; dlscnt=0; } else if (dlogW == SwitchDlog) { XChangeWindow(dlogW,200,40+20*numanals); selanal = curanal; } else if (dlogW == CurvDlog) { /* 200x300 */ MakeButton(&curvbutts[0],dlogW,10, 50, 80,40,theAnal->labels[1],dlogfinfo); MakeButton(&curvbutts[1],dlogW,110,50, 80,40,theAnal->labels[2],dlogfinfo); MakeButton(&curvbutts[2],dlogW,10, 100,80,40,theAnal->labels[3],dlogfinfo); MakeButton(&curvbutts[3],dlogW,110,100,80,40,theAnal->labels[4],dlogfinfo); MakeButton(&curvbutts[4],dlogW,10, 150,80,40,theAnal->labels[5],dlogfinfo); MakeButton(&curvbutts[5],dlogW,110,150,80,40,theAnal->labels[6],dlogfinfo); MakeButton(&curvbutts[6],dlogW,10, 200,80,40,theAnal->labels[7],dlogfinfo); MakeButton(&curvbutts[7],dlogW,110,200,80,40,theAnal->labels[8],dlogfinfo); MakeButton(&dbutts[0],dlogW,10, 265,80,25,"Ok",dlogfinfo); MakeButton(&dbutts[1],dlogW,110,265,80,25,"Cancel",dlogfinfo); for (i=0; inumys; i++) { XMapWindow(curvbutts[i].win); XSelectInput(curvbutts[i].win,ExposeWindow); } } else if (dlogW == PlotDlog) { /* 380x70 */ MakeButton(&dbutts[0],dlogW,30, 30,80,30,"File", dlogfinfo); MakeButton(&dbutts[1],dlogW,150,30,80,30,"Plotter",dlogfinfo); MakeButton(&dbutts[2],dlogW,270,30,80,30,"Cancel", dlogfinfo); for (i=0; i<3; i++) XSelectInput(dbutts[i].win,ExposeWindow); XMapSubwindows(dlogW); } else if (dlogW == PlotNDlog) { /* 380x100 */ MakeButton(&dbutts[0],dlogW,30, 60,80,30,"Ok",dlogfinfo); MakeButton(&dbutts[1],dlogW,270,60,80,30,"Cancel",dlogfinfo); dbutts[2].win=0; for (i=0; i<2; i++) XSelectInput(dbutts[i].win,ExposeWindow); XMapSubwindows(dlogW); dlogstr[0]='\0'; dlscnt=0; } else if (dlogW == HelpDlog) {} XMapWindow(dlogW); } /**********************/ CloseDlog() { int i; if (dlogW == LoadDlog) { InvertBut(&butts[25]); XDestroySubwindows(dlogW); } else if (dlogW == SwitchDlog) { InvertBut(&butts[24]); } else if (dlogW == CurvDlog) { InvertBut(&butts[26]); XDestroySubwindows(dlogW); } else if (dlogW == PlotDlog) { InvertBut(&butts[38]); XDestroySubwindows(dlogW); } else if (dlogW == PlotNDlog) { InvertBut(&butts[38]); XDestroySubwindows(dlogW); } else if (dlogW == HelpDlog) { InvertBut(&butts[39]); } XUnmapWindow(dlogW); dlogW = 0; } /***********************/ RedrawDlog() { int i; if (dlogW == LoadDlog) { /* 380x100 */ XText(dlogW,10,10, "Load data from:",15, dlogfont,dlgFcol,dlgBcol); Frame(dlogW,10,30, 370,50, 2, dlgFcol,GXcopy); XText(dlogW,14,36,dlogstr,dlscnt,butfont,dlgFcol,dlgBcol); XPixSet(dlogW, 14+dlscnt*butfinfo->width, 36, /* text cursor */ butfinfo->width, butfinfo->height, dlgFcol); } else if (dlogW == SwitchDlog) { /* 200x(40 + 20*numanal) */ XText(dlogW, 10,10, "Choose an analysis:",19, dlogfont,dlgFcol,dlgBcol); XLine(dlogW, 0,30, 200,30, 1,1,dlgFcol,GXcopy,AllPlanes); for (i=0; iheight)/2, anals[i].title, strlen(anals[i].title), dlogfont, dlgFcol, dlgBcol); XPixFill(dlogW,0,40+20*curanal,200,20,ForeColor,0,GXinvert, dlgFcol ^ dlgBcol); } else if (dlogW == CurvDlog) { /* 200x300 */ XPixSet(dlogW,0,0,200,30,dlgBcol); XLine(dlogW,0,30,200,30,1,1,dlgFcol,GXcopy,AllPlanes); XText(dlogW,35,8, "Choose 1-4 curves",17,dlogfont,dlgFcol,dlgBcol); } else if (dlogW == HelpDlog) { /* 380x200 */ XText(dlogW, 40, 65, "Sorry, no on-line help available...",35, dlogfont,dlgFcol,dlgBcol); } else if (dlogW == PlotDlog) { /* 380x70 */ XText(dlogW,10,10, "Send plot data to:",18,dlogfont,dlgFcol,dlgBcol); } else if (dlogW == PlotNDlog) { /* 380x100 */ XText(dlogW,10,10, "Write plot data to:",19, dlogfont,dlgFcol,dlgBcol); Frame(dlogW,10,30, 370,50, 2, dlgFcol, GXcopy); XText(dlogW,14,36,dlogstr,dlscnt,butfont,dlgFcol,dlgBcol); XPixSet(dlogW, 14+dlscnt*butfinfo->width, 36, /* text cursor */ butfinfo->width, butfinfo->height, dlgFcol); } } /***********************/ DlogKey(st,cnt) char *st; int cnt; { int i; if (dlogW == LoadDlog || dlogW == PlotNDlog) { for (i=0; iwidth, 36, butfinfo->width, butfinfo->height, dlgBcol); if (dlscnt) dlscnt--; XPixSet(dlogW, 14+dlscnt*butfinfo->width, 36, butfinfo->width, butfinfo->height, dlgFcol); } else if (st[i]=='\0') {} /* toss nulls away */ else if (st[i]=='\n' || st[i]=='\r') { /* return. choose default */ if (dlscnt==0) /* didn't enter a name. Cancel */ ClickDlog(dbutts[1].x+1, dbutts[1].y+1); else /* choose 'Ok' */ ClickDlog(dbutts[0].x+1, dbutts[0].y+1); } else { /* normal character */ dlogstr[dlscnt]=st[i]; XText(dlogW,14+dlscnt*butfinfo->width,36,&st[i],1, butfont,dlgFcol,dlgBcol); if (dlscntwidth, 36, butfinfo->width, butfinfo->height, dlgFcol); } } } } /***********************/ ClickDlog(x,y) short x,y; { int i; char tmpfname[64]; dlogstr[dlscnt]='\0'; if (dlogW == LoadDlog) { for (i=0; i<2; i++) { if (x>=dbutts[i].x && x<=(dbutts[i].x+dbutts[i].w) && y>=dbutts[i].y && y<=(dbutts[i].y+dbutts[i].h)) break; } if (i<2) { InvertBut(&dbutts[i]); XFlush(); Timer(200000L); } else return; if (i==0) { NOPARSE=0; strcpy(tmpfname,basfname); strcpy(basfname,dlogstr); if (OpenSpice()) { /* couldn't load it. or something */ NOPARSE=1; if (strcmp(FixName(tmpfname),FixName(basfname))==0) { /* the very odd case that the previous SPICE and the asked-for SPICE have the same filename, but the asked-for SPICE was unable to be loaded. In this case, it's possible that the previous SPICE's tmp files have been overwritten. Better regenerate them, to be on the safe side... */ NOPARSE=0; } strcpy(basfname,tmpfname); OpenSpice(); LoadAnal(curanal); } else { LoadNewAnal(0); ChangedAnal(); XFlush(); RedrawSettings(); } } CloseDlog(); } else if (dlogW == SwitchDlog) { int tmpanal; tmpanal = (y/20)-2; if (tmpanal<0 || tmpanal>numanals) return; else if (tmpanal==selanal) { if (selanal==curanal) { CloseDlog(); return; } else { LoadNewAnal(selanal); CloseDlog(); ChangedAnal(); XFlush(); RedrawSettings(); } } else { XPixFill(dlogW,0,40+20*selanal,200,20,ForeColor,0,GXinvert, dlgFcol ^ dlgBcol); selanal=tmpanal; XPixFill(dlogW,0,40+20*selanal,200,20,ForeColor,0,GXinvert, dlgFcol ^ dlgBcol); } } else if (dlogW == CurvDlog) { int j,numsel,tmpind[4]; for (i=0; i<2; i++) { if (x>=dbutts[i].x && x<=(dbutts[i].x+dbutts[i].w) && y>=dbutts[i].y && y<=(dbutts[i].y+dbutts[i].h)) break; } if (i<2) { InvertBut(&dbutts[i]); XFlush(); Timer(200000L); } if (i==0) { /* Ok */ for (j=0,numsel=0; jnumys; j++) if (curvbutts[j].invert) { if (numsel<4) tmpind[numsel]=j; numsel++; } if (numsel==0) { ErrBox("Choose at least one curve.",1); InvertBut(&dbutts[0]); } else if (numsel>4) { ErrBox("Choose no more than four curves.",1); InvertBut(&dbutts[0]); } else { /* selected curves are okay, load 'em */ for (j=0; jnumys; i++) { if (x>=curvbutts[i].x && x<=(curvbutts[i].x+curvbutts[i].w) && y>=curvbutts[i].y && y<=(curvbutts[i].y+curvbutts[i].h)) break; } if (inumys) InvertBut(&curvbutts[i]); } } else if (dlogW == PlotDlog) { for (i=0; i<3; i++) { if (x>=dbutts[i].x && x<=(dbutts[i].x+dbutts[i].w) && y>=dbutts[i].y && y<=(dbutts[i].y+dbutts[i].h)) break; } if (i<3) { InvertBut(&dbutts[i]); XFlush(); Timer(200000L); } else return; if (i==0) { /* File */ XMapWindow(PlotNDlog); CloseDlog(); InvertBut(&butts[38]); OpenDlog(PlotNDlog); } else if (i==1) { /* Plotter */ Splotter(); CloseDlog(); } else CloseDlog(); /* Cancel */ } else if (dlogW == PlotNDlog) { for (i=0; i<2; i++) { if (x>=dbutts[i].x && x<=(dbutts[i].x+dbutts[i].w) && y>=dbutts[i].y && y<=(dbutts[i].y+dbutts[i].h)) break; } if (i<2) { InvertBut(&dbutts[i]); XFlush(); Timer(200000L); } else return; if (i==0) { /* Ok */ if (!PlotFile(dlogstr)) ErrBox("Plot file written.",-1); } CloseDlog(); } else CloseDlog(); } \Rogue\Monster\ else echo "will not over write ./xsplot/xsplotdlg.c" fi if `test ! -s ./xsplot/xsplotgr.c` then echo "writing ./xsplot/xsplotgr.c" cat > ./xsplot/xsplotgr.c << '\Rogue\Monster\' /************************************************************************/ /* XSPLOTGR.C */ /*----------------------------------------------------------------------*/ /* Library of routines to handle data plotting, Big Picture, etc. */ /*----------------------------------------------------------------------*/ /* void DrawGwin (); */ /* void PlotData (); */ /* void ClearArrs (); */ /* void DrawGrid (); */ /* void BigPicture(); */ /* float CalcX(); */ /* float CalcY(); */ /* void BestFit(); */ /* int CalcSRect(x,y,x1,y1); */ /* void DigitalPresets(); /************************************************************************/ #include "xsplot.h" #define SPLOTTER "/usr/local/splotter" #define XUNIT 40 #define YUNIT 40 #define LOG2 0.69314718055994530941 #define NEGLOG -19.0 /* value returned when attempting log(-n) */ #define BPBottomFP 396.0 /* Big Picture size/position info */ #define BPHighFP 390.0 /* the Big Picture is a 390x390 rect centered */ #define BPLeftFP 6.0 /* in the 400x400 grid window */ #define BPWideFP 390.0 #define BPLeft 6 #define BPBottom 396 static int oldxscal = -1, oldyscal = -1; static int BPonscrn = 0; #define log10a(x) ((x<0.0) ? NEGLOG : log10(x)) #define log2a(x) ((x<0.0) ? NEGLOG : log(x)/LOG2) #define inrange(y) (y>=GTop && y<=GBottom) static float xmin,xmax,ymin,ymax; /* min/max values of DATA, unscaled */ static float sxmin,symin,sxmax,symax; /* min/max values of screen grid */ /* note: sx/sy vals are ALWAYS linear */ static float dx,dy; /* xmax-xmin, ymax-ymin */ static float sdx,sdy; /* sxmax-sxmin, symax-symin */ /************************************************************************/ DrawGwin() /* redraws whatever was in the grid window */ { if (BPonscrn) BigPicture(); else PlotData(); } /************************************************************************/ static float Coord2S(coord,scale) float coord; int scale; { switch (scale) { case LINEAR: return(coord); case LOG10: return(log10a(coord)); default: return(log2a(coord)); } } /************************************************************************/ static int xconv(x) float x; { /* given an x value (from xlist.dat[]), convert it to an integer (+-4K) suitable for plotting */ float xtmp; static float divsize[3]={400.0,133.333333,40.0}; /* size of a division on one, three, and ten division grid, respectively */ switch (xscal) { case LINEAR: xtmp = GLRmidFP+((x-offsets[0].val)/ranges[0].val)*XUNIT; break; case LOG10: x = Coord2S(x,xscal); xtmp = GLeftFP + (x-L10Offset)*divsize[L10Range]; break; case OCTAVE: x = Coord2S(x,xscal); xtmp = GLeftFP + (x-OctOffset)*divsize[OctRange]; break; } if (xtmp<-4000.0) xtmp = -4000.0; else if (xtmp> 4000.0) xtmp = 4000.0; return( (int) xtmp); } /************************************************************************/ static int yconv(i,y) int i; float y; { /* given a y value from ylist[i].dat[], convert it to an integer (+-4K) suitable for plotting */ float ytmp; y = Coord2S(y,yscal); ytmp = GTBmidFP - ((y-offsets[i+1].val) / ranges[i+1].val) * YUNIT; if (ytmp> 4000.0) ytmp = 4000.0; if (ytmp<-4000.0) ytmp = -4000.0; return( (int) ytmp); } /************************************************************************/ PlotData() { /* draws the data in the gridW using the current settings */ int x,y,i,j,numplot; Vertex *vp; ClearArrs(); BPonscrn = Vis159 = 0; DrawGrid(); /* clear and redraw the grid */ if (numpts<2) return; /* no points (per se) to draw */ for (i=0; iGRight) RightArr=1; if (yGBottom) DownArr[i]=1; /* keep track of the number of points plotted */ if (x>=GLeft && x<=GRight && y>=GTop && y<=GBottom) numplot++; SetVertex(curve+j,x,y,0); } if (mono) XDrawDashed(gridW,curve,numpts,1,1,ForeColor,linepats[i],GXcopy,AllPlanes); else XDraw(gridW,curve,numpts,1,1,trcol[i],GXcopy,AllPlanes); /* if 30 or less points plotted, plot the actual data points, too. */ if (numplot<31) for (j=0,vp=curve; jx; y = vp->y; if (x>=GLeft && x<=GRight && y>=GTop && y<=GBottom) XPixFill(gridW,x-1,y-1,3,3,trcol[i],0,GXcopy,AllPlanes); } } DrawArrs(); } /************************************************************************/ ClearArrs() { int i; LeftArr = RightArr = 0; for (i=0; i<4; i++) UpArr[i] = DownArr[i] = 0; } /************************************************************************/ static Calcminmax() /* calculates xmin,ymin,xmax,ymax,dx,dy */ { int i,j; /* find xmin, xmax, ymin, ymax */ xmin = xmax = xlist.dat[0]; ymin = ymax = ylist[0].dat[0]; for (i=0; ixmax) xmax=xlist.dat[i]; for (j=0; jymax) ymax=ylist[j].dat[i]; } } dx=xmax-xmin; dy=ymax-ymin; } /************************************************************************/ static CalcSdat() { /* calculate sxmin, sxmax, symin, symax, sdx, sdy */ sxmin=Coord2S(xmin,xscal); sxmax=Coord2S(xmax,xscal); symin=Coord2S(ymin,yscal); symax=Coord2S(ymax,yscal); sdx=sxmax-sxmin; sdy=symax-symin; } /************************************************************************/ static int BPxconv(x) float x; { /* converts a data x-value to it's bigpicture x-value */ float xtmp; x=Coord2S(x,xscal); xtmp = BPLeftFP + ((x-sxmin) * BPWideFP) / sdx; return( (int) xtmp); } /************************************************************************/ static int BPyconv(y) float y; { /* converts a data y-value to it's bigpicture y-value */ float ytmp; Coord2S(y,yscal); ytmp=BPBottomFP - ((y-symin) * BPHighFP) / sdy; return( (int) ytmp); } /************************************************************************/ BigPicture() { /* erases grid, redraws the Big Picture */ int x,y,i,j; char vals[100],vals1[16],vals2[16],vals3[16],vals4[16]; BPonscrn=1; Vis159=0; XClear(gridW); Calcminmax(); CalcSdat(); ClearArrs(); DrawArrs(); if (numpts<2) return; /* no points (per se) to draw */ for (i=0; iGRightFP) return(GRight); else if (xGBottomFP) return(GBottom); else if (y 20) L10Offset = 20; tmp = x2/x1; if (tmp>1000.0) L10Range=2; else if (tmp> 10.0) L10Range=1; else L10Range=0; } else /* (xscal==OCTAVE) */ { double tmp; OctOffset=(int) floor(log(x1)/log(2.0)); if (OctOffset<-20) OctOffset = -20; if (OctOffset> 20) OctOffset = 20; tmp = x2/x1; if (tmp>8.0) OctRange=2; else if (tmp>2.0) OctRange=1; else OctRange=0; } } /****************/ static CalcNearRange(d,mul,exp,mid) double d; int *mul,*exp; double *mid; { /* given a delta, and a midpoint, returns 'best fit' mul,exp, and mid values. Only works on linear settings */ /* takes a desired range 'd', and converts it to a valid range setting */ /* rounding rules: 1 x=2.0 2 x=5.0 5 x=10.0 (where x=first digit) */ /* also takes the center of the range (offset) and rounds it to the next lower half-division (ie: if the resultant range is 5V per division, the offset will be rounded to some multiple of 2.5V. In theory, at least */ double mant,newmant,rpdiv,rpdiv2,z,md; int powr,m,e,e1; powr = (int) floor(log10(d)); /* powr(125.0) = 2 */ mant = d/pow(10.0,(double) powr); /* mant(125.0) = 1.25 */ /* mant * 10^powr = d : 1 <= mant < 10 */ /* round up range */ if (mant>5.0) { newmant=1.0; m=0; powr++;} else if (mant>2.0) { newmant=5.0; m=2; } else if (mant>1.0) { newmant=2.0; m=1; } else { newmant=1.0; m=0; } powr--; /* divide by 10 to get range/div */ e = (powr/3) + 4; /* convert powr -> exp */ if (e>8) e=8; /* truncate at ends of valid range */ if (e<0) e=0; e1=abs(powr)%3; if (powr<0 && e1!=0) { e--; e1=3-e1; } if (e>=0) m=m+e1*3; /* calculate mul */ else { e=0; m=0; } *mul=m; *exp=e; /* calculate the nice, rounded-off midpt */ rpdiv = newmant * pow(10.0,(double) powr); /* range per div */ rpdiv2 = rpdiv/2; /* range per half-div */ md = *mid; /* vaguely-evil kludge. Basically, if mid/rpdiv2 is something like 5.99999, this hopefully pushes it above 6.0, so that floor returns 6 */ *mid = *mid * 1.00001; z = floor(*mid/rpdiv2); /* integer # of half-divs in m */ *mid = z * rpdiv2; /* rounded down version of m */ /* printf("rpdiv:=%e rpdiv2=%e\n",rpdiv,rpdiv2); printf("mid=%e mid/rpdiv=%e z=%e z*rpdiv2=%e\n\n",md,md/rpdiv2,z,*mid); */ } /************************************************************************/ /* Routines to handle data plotting. (Hard Copy! Wowzo!) */ /*----------------------------------------------------------------------*/ /* PlotFile(fnam); - writes data points to the named SPIF file. */ /* Splotter(); - writes a tmp SPIF file, and execs splotter */ /************************************************************************/ /* * The SPIF Format: * (all numbers are in ascii format (printf)) * * Field 1: The name of the spice file * 2: The name of the analysis * 3: The Grid Type * (0 = Linear, 10 divs per axis, with axes at center) * (1 = Log10, 1 div) * (2 = Log10, 3 divs) * (3 = Log10, 10 divs) * (4 = Log 2, 1 div) * (5 = Log 2, 3 divs) * (6 = Log 2, 10 divs) * (consult Splot to see what grids should look like) * 4: The number of traces in the plot (1-4) * 5: The names of the traces (2-5 words, each up to 8 chars long) * 6: The x-axis offset/range information * (if gridtype=0, will be in the form * x.xxxxexx x.xxxxexx * where the first number is the offset at the center line, * and the second is the amount of change per division) * * (if gridtype=1-3, will be in the form * 10^x y * where 'x' will be an integer in range +/- 19. * this refers to the value at the left edge of the plot. * 'y' will be an integer, either 1,3, or 10. This is * actually redundant, but what the hell.) * * (if gridtype=4-6, will be in the form * 2^x y * where 'x' will be an integer in range +/- 19. * this refers to the value at the left edge of the plot. * 'y' will be an integer, either 1,3, or 10. This is * actually redundant, but what the hell.) * * 7: The y-axis offset/range information * This will be 1-4 lines, each containing a pair of * numbers of the format used for the x-axis when gridtype=0 * * 8: The actual data * This will be an indeterminant number of lines, each with * an x coordinate and 1-4 y coordinates separated by * spaces. The coordinates will be in the range +/- 32K. * The plotting program should clip these coordinates to the * range 0-400 on both axes. 0,0 refers to the bottom left * corner of the grid. * The end of the data will be signalled by the end of the * SPIF file, so needless to say, this field HAS to be the * last field in the SPIF file, should anyone get the urge * to add things to the SPIF format. * */ /****************/ int PlotFile(name) char *name; /****************/ { /* writes the named SPIF file */ int x,y,i,j,gridtype; FILE *spiffile; char tmp[128]; if (expfname(name)) { sprintf(tmp,"Unable to create file '%s'",name); ErrBox(tmp,3); return 1; } spiffile = fopen(name,"w"); if (spiffile == 0) { sprintf(tmp,"Unable to create file '%s'",name); ErrBox(tmp,3); return 1; } /* write header information */ fprintf(spiffile,"%s\n",FixName(basfname)); fprintf(spiffile,"%s\n",theAnal->title); if (xscal==LINEAR) gridtype=0; else if (xscal==LOG10) gridtype=1+L10Range; else /* (xscal==OCTAVE)*/ gridtype=4+OctRange; fprintf(spiffile,"%d\n",gridtype); fprintf(spiffile,"%d\n",numy); fprintf(spiffile,"%s",xlist.label); for (i=0; i32000) y=32000; fprintf(spiffile," %d",y); } fprintf(spiffile,"\n"); } fclose(spiffile); return 0; } /***************/ int Splotter() /***************/ { /* generates a unique file name (/tmp/spifXXXXXX), writes the SPIF file using that name, and then runs SPLOTTER to plot it (and delete it) */ char name[32]; int pid; strcpy(name,"/tmp/spifXXXXXX"); mktemp(name); if (PlotFile(name)) return 1; pid = vfork(); if (pid==0) { /* we're in the child's context. fire up splotter */ char tmp[128]; sprintf(tmp,"Executing %s.",SPLOTTER); ErrBox(tmp,-1); if (execl(SPLOTTER,SPLOTTER,"-i",name,"-u",0) == -1) { sprintf(tmp,"Couldn't execute %s.",SPLOTTER); ErrBox(tmp,4); _exit(); /* exit the child process */ } } } /*************************************************************/ DigitalPresets() /*************************************************************/ { /* sets range/offsets to 'best' values for viewing several curves that range from 0.0 to 5.0. 'Stacks' them, or some such nonsense. */ int i,m,p; double zx1,zx2,zdx,zxm; /* do a best fit on the X-axis */ Calcminmax(); CalcSdat(); zx1 = xmin; zx2 = xmax; zdx = zx2 - zx1; zxm = zx1 + zdx/2.0; CalcXRange(zx1,zx2,zdx,zxm); /* set up the y-axis values */ switch (numy) { case 1: m=0; p=4; /* 1V per div */ offsets[1].val= 2.5; break; case 2: m=1; p=4; /* 2V per div */ offsets[1].val= -2.0; offsets[2].val= 6.0; break; case 3: m=1; p=4; /* 2V per div */ offsets[1].val= -4.0; offsets[2].val= 2.0; offsets[3].val= 8.0; break; case 4: m=2; p=4; /* 5V per div */ offsets[1].val= -15.0; offsets[2].val= -5.0; offsets[3].val= 5.0; offsets[4].val= 15.0; break; } for (i=1; i<=numy; i++) { ranges[i].multiplier=m; ranges[i].power=p; } xscal=LINEAR; } \Rogue\Monster\ else echo "will not over write ./xsplot/xsplotgr.c" fi echo "Finished archive 2 of ompXB di