/* "VIEW", a data viewing program, Copyright (C) 1987, 1990 California Institute of Technology. Original authors: Dave Gillespie, port by Rick Koshi Unix Port Maintainer: John Lazzaro Maintainers's address: lazzaro@hobiecat.cs.caltech.edu; CB 425/ CU Boulder/Boulder CO 91125. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation (Version 1, Feb 1989). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Output from p2c, the Pascal-to-C translator */ /* From input file "viewcurves.text" */ /* The View program by Dave Gillespie */ /*caged_date='I{ Last edit by $U on $X $]'*/ /* Last edit by dave on Mar 12, 1989 7:19 am */ /* Last edit by dave on Mar 12, 1989 7:12 am */ /* Last edit by dave on Mar 12, 1989 6:06 am */ /* Last edit by dave on Mar 12, 1989 6:03 am */ /* Last edit by dave on Mar 12, 1989 6:01 am */ /* Last edit by dave on Mar 12, 1989 4:56 am */ /* Last edit by dave on Mar 9, 1989 5:51 pm */ /* Last edit by dave on Mar 9, 1989 5:25 pm */ /* Last edit by dave on Mar 9, 1989 4:31 pm */ /* Last edit by dave on Jun 7, 1988 3:17 am */ /* Last edit by dave on Jun 6, 1988 8:16 pm */ /* Last edit by dave on Mar 26, 1988 4:38 pm */ /* Last edit by dave on Mar 3, 1988 6:10 pm */ /* Last edit by dave on Feb 29, 1988 6:01 pm */ /* Last edit by dave on Feb 15, 1988 6:32 pm */ /* Last edit by dave on Feb 12, 1988 6:07 pm */ /* Last edit by dave on Feb 4, 1988 8:46 pm */ /* Last edit by dave on Jan 26, 1988 3:15 am */ /* Last edit by dave on Jan 24, 1988 6:30 am */ /* Last edit by dave on Jan 23, 1988 11:23 pm */ /* Last edit by dave on Jan 20, 1988 11:21 pm */ /* Last edit by dave on Jan 19, 1988 8:36 pm */ /* Last edit by dave on Jan 14, 1988 7:45 am */ /* Last edit by dave on Nov 30, 1987 6:01 pm */ char unixCommand[256]; /*$ debug ${*/ #include "global.h" #define VIEWCURVES_G #include "viewcurves.h" #ifndef NUMEX_H #include #endif #ifndef REGEX_H #include #endif #ifndef NEWASM_H #include #endif #ifndef SYSGLOBALS_H #include #endif #ifndef PLOT_ROUTINES_H #include #endif #ifndef PLOT_H #include #endif /*homeless orphans*/ #ifndef MISC_H #include #endif #ifndef SYSDEVS_H #include #endif #ifndef FILEPACK_H #include #endif #ifndef MATH_H #include #endif #ifndef MYLIB_H #include #endif #ifndef NEWCRT_H #include #endif #ifndef NEWKBD_H #include #endif #ifndef NEWCI_H #include #endif #ifndef NEWTABLET_H #include #endif #ifndef VIEWMOD_H #include "viewmod.h" #endif #define excp_line 0 Static long v_aticks[3]; Static double v_ainterval[3]; Static v_paramrec *p_tex, *p_datestamp; Static double penvel; Static m_tablet_info intpen; Static boolean wasdepr, wasnear; Static double penx, peny, oldpenx, oldpeny, penxmin, penxmax, penymin, penymax; Static Void doedit(buf_) Char *buf_; { Char buf[256], tempfn[256]; v_curverec *cp; Char STR1[256], STR2[256]; strcpy(buf, buf_); strcpy(tempfn, buf); v_ncurvelist(tempfn, &cp, v_clsome); cp = v_findcurve(buf); if (cp != NULL && cp->expr != NULL) { /*editing a single computed curve*/ strcpy(tempfn, cp->name); sprintf(STR1, "%s == ", tempfn); v_readkbddef(buf, STR1, cp->expr, ""); strcpy(STR1, strltrim(strrtrim(strcpy(STR2, buf)))); strcpy(buf, STR1); if (*buf != '\0') v_addcurveexpr(buf, tempfn); return; } sprintf(tempfn, "/tmp/vtmp_%ld.dat", newci_fullseconds() % 1000); /* p2c: viewcurves.text, line 109: * Note: Using % for possibly-negative arguments [317] */ /* p2c: viewcurves.text, line 110: * Note: Null character at end of sprintf control string [148] */ v_savecurves(strcpy(STR1, tempfn), buf); /*#0 forces 'nice' formatting*/ v_closelog(); newci_fulleditescape(tempfn, "S", 8L, 1L); switch (v_loadfile(tempfn)) { case 0: /* blank case */ break; case 1: v_failmsg("File was deleted!"); break; case 2: v_failmsg("File format was trashed!"); break; } unlink(tempfn); do { v_strword(buf, tempfn); if (*tempfn != '\0') { cp = v_findcurve(tempfn); if (cp != NULL) v_change(cp); } } while (*tempfn != '\0'); } Static Void dorange(buf_) Char *buf_; { Char buf[256], wrd[256]; v_curverec *cp; v_baserec *bp; double minv, maxv; long i, j; Char STR3[256]; strcpy(buf, buf_); if (*buf == '[') cp = NULL; else v_desteqsrc(buf, &cp, v_clsome); v_needsep(buf, '['); v_exstrword(buf, wrd); v_needsep(buf, ':'); if (!v_parsereal(wrd, &minv)) v_fail(); v_exstrword(buf, wrd); v_needsep(buf, ']'); if (cp == NULL) v_desteqsrc(buf, &cp, v_clsome); v_checktoomany(buf); if (!v_parsereal(wrd, &maxv)) v_fail(); ma_rsort2(&minv, &maxv); if (minv == maxv) v_failmsg("Error: = "); while (cp != NULL) { bp = cp->base; v_checksorted(bp); if (bp == NULL) v_notvector(); i = 1; while (i <= bp->len && bp->vec[i - 1] < minv) i++; j = bp->len; while (j >= 1 && bp->vec[j - 1] > maxv) j--; if (i > j) v_failmsg("No relevant data points"); if (v_p_trace->val.U1.i1 >= 1) { sprintf(STR3, "%ld data point(s) used out of %ld", j - i + 1, bp->len); v_logwriteln(STR3); } v_addcurve(j - i + 1, &bp->vec[i - 1], &cp->vec[i - 1], bp->units, cp->units, cp->dest); cp = cp->next2; } } /*dorange*/ #define defnumpts 15 #define fudge 1e-2 Static Void dobasis(buf_) Char *buf_; { Char buf[256], wrd[256], dest[256], units[256]; double val, oval, minv, maxv, incr, mult; long i, j, len; Char STR2[256]; strcpy(buf, buf_); *units = '\0'; v_strword(buf, dest); if (*dest == '\0') v_needcurvename(); v_needsep(buf, '='); v_exstrword(buf, wrd); if (!v_parsereal(wrd, &minv)) v_fail(); v_needsep(buf, ':'); v_exstrword(buf, wrd); if (!v_parsereal(wrd, &maxv)) v_fail(); if (maxv <= minv) v_failmsg("Error: max <= min"); incr = 0.0; if (*buf == ':') { strcpy(buf, buf + 1); v_exstrword(buf, wrd); if (*wrd != '\0') { if (!v_parsereal(wrd, &incr)) v_fail(); } } if (*buf == ':') { strcpy(buf, buf + 1); v_strword(buf, units); } v_checktoomany(buf); if (incr < 0) v_failmsg("Negative increment"); if (incr == 0) { incr = (maxv - minv) * 100; /*something large*/ i = 0; while (incr >= 10) { i++; incr /= 10; } while (incr < 1) { i--; incr *= 10; } incr = 1.0; for (j = 1; j <= i; j++) incr *= 10; for (j = -1; j >= i; j--) incr /= 10; mult = 0.5; while ((maxv - minv) / (incr * mult) < defnumpts) { if (mult == 0.5) { mult = 0.25; continue; } if (mult == 0.25) mult = 0.1; else if (mult == 0.1) { incr /= 10; mult = 0.5; } } incr *= mult; } len = 0; do { val = minv + len * incr; if (val <= maxv) { len++; v_stretchtempvecs(len); v_tempxvec[len - 1] = val; v_tempyvec[len - 1] = val; oval = val; } } while (val <= maxv); if (maxv - oval > fudge * incr || len == 1) len++; v_stretchtempvecs(len); v_tempxvec[len - 1] = maxv; v_tempyvec[len - 1] = maxv; if (v_p_trace->val.U1.i1 >= 1) { sprintf(STR2, "%ld data points made", len); v_logwriteln(STR2); } v_addcurve(len, v_tempxvec, v_tempyvec, units, units, dest); } /*dobasis*/ #undef defnumpts #undef fudge Static Void domap(buf_) Char *buf_; { Char buf[256], wrd[256], dest[256]; v_curverec *cp, *cp2; v_baserec *bp; double *vec; long i; v_interpolator int_; long FORLIM; strcpy(buf, buf_); int_ = v_parseinterp(buf); v_strword(buf, dest); if (*dest == '\0') v_needcurvename(); v_needsep(buf, '='); v_strword(buf, wrd); cp2 = v_findcurve(wrd); if (cp2 == NULL) v_nosuchcurve(wrd); v_needcurve(cp2); bp = cp2->base; if (bp == NULL) v_notvector(); v_needsep(buf, ':'); v_strword(buf, wrd); v_desteqsrc2(dest, wrd, &cp); v_checktoomany(buf); while (cp != NULL) { v_newvector(&vec, bp->len); if (cp->base == bp) { FORLIM = bp->len; for (i = 0; i < FORLIM; i++) vec[i] = cp->vec[i]; } else { FORLIM = bp->len; for (i = 0; i < FORLIM; i++) vec[i] = v_interp(&int_, cp, bp->vec[i]); } v_makecurve(&cp2, bp, vec, cp->units, cp->dest); cp = cp->next2; } v_disposeinterp(&int_); } /*domap*/ typedef boolean boolarr[1000000L]; Static Void dopermute(buf_) Char *buf_; { Char buf[256], wrd[256], dest[256]; v_curverec *cpo, *cpi; v_baserec *bp; long i, j, len; double val; boolean *flags; boolean fullflag, cleanflag; strcpy(buf, buf_); fullflag = false; cleanflag = false; while (*buf == '[') { strcpy(buf, buf + 1); v_exstrword(buf, wrd); if (strcicmp(wrd, "full") == 0) fullflag = true; else if (strcicmp(wrd, "clean") == 0) cleanflag = true; else v_unrecognizedoption(); v_needsep(buf, ']'); } v_strword(buf, dest); if (*dest == '\0') v_needcurvename(); if (*buf == '=') { strcpy(buf, buf + 1); v_strword(buf, wrd); } else strcpy(wrd, dest); cpo = v_findcurve(wrd); if (cpo == NULL) v_nosuchcurve(wrd); v_needcurve(cpo); bp = cpo->base; if (bp == NULL) v_notvector(); len = bp->len; v_needsep(buf, ':'); v_strword(buf, wrd); cpi = v_findcurve(wrd); if (cpi == NULL) v_nosuchcurve(wrd); v_needcurve(cpi); if (cpi->base == NULL) v_notvector(); if (cpi->base->len != len) v_cantcombine(); v_checktoomany(buf); v_stretchtempvecs(len); na_alloc((Anyptr)&flags, len); for (i = 0; i < len; i++) flags[i] = false; for (i = 0; i < len; i++) { val = cpi->vec[i]; if (val >= 1 && val <= len) { j = (long)val; val = cpo->vec[i]; if (val == v_badvalue || !flags[j - 1]) v_tempyvec[j - 1] = val; else { if (val != 0 && v_tempyvec[j - 1] != v_badvalue) { /*optimization*/ TRY(try1); v_tempyvec[j - 1] += val; RECOVER(try1); if (P_escapecode == -20) _Escape(P_escapecode); v_tempyvec[j - 1] = v_badvalue; v_writeerrmsg("Arithmetic error (probably overflow)"); ENDTRY(try1); } } flags[j - 1] = true; } v_tempxvec[i] = bp->vec[i]; } if (cleanflag) { for (i = 0; i < len; i++) { if (flags[i] && v_tempyvec[i] == v_badvalue) flags[i] = false; } } if (fullflag) { j = len; for (i = 0; i < len; i++) { if (!flags[i]) v_tempyvec[i] = 0.0; } } else { j = 0; for (i = 0; i < len; i++) { if (flags[i]) { j++; if (j != i + 1) { v_tempxvec[j - 1] = v_tempxvec[i]; v_tempyvec[j - 1] = v_tempyvec[i]; } } } } if (j == 0) v_failmsg("Result curve is empty"); v_addcurve(j, v_tempxvec, v_tempyvec, bp->units, cpo->units, dest); na_free((Anyptr)&flags); } /*domap*/ Static Void safeappend(str, buf, max) Char *str; Char *buf; long max; { Char STR2[256]; if (strlen(str) + strlen(buf) > max) { sprintf(STR2, "%s%.*s", str, (int)(max - strlen(str)), buf); strcpy(str, STR2); } else strcat(str, buf); } Static Void dostyle(buf_) Char *buf_; { Char buf[256], wrd[256]; long st, lst, pst; strcpy(buf, buf_); if (*buf == '\0') { for (st = 0; st <= v_maxstyle; st++) { sprintf(wrd, "Style %ld:", st); switch (v_lstyle[st]) { case 0: strcat(wrd, " line"); break; case 1: strcat(wrd, " dots"); break; case 2: strcat(wrd, " dash"); break; case 3: strcat(wrd, " longdash"); break; case 4: strcat(wrd, " dashdot"); break; case 6: strcat(wrd, " dashdot2"); break; } switch (v_pstyle[st]) { case 0: strcat(wrd, " stars"); break; case 1: strcat(wrd, " box"); break; case 2: strcat(wrd, " circ"); break; case 3: strcat(wrd, " tri"); break; case 4: strcat(wrd, " fbox"); break; case 5: strcat(wrd, " fcirc"); break; case 6: strcat(wrd, " ftri"); break; } v_logwriteln(wrd); } return; } if (*buf == '@') strcpy(buf, buf + 1); v_exstrword(buf, wrd); if (*buf == '=') strcpy(buf, buf + 1); if (v_parseinteger(wrd, &st)) { if ((unsigned long)st > v_maxstyle) v_failmsg("Style number out of range"); v_exstrword(buf, wrd); } else st = 0; lst = -1; pst = -1; do { if (*wrd == '\0') v_checktoomany(buf); else { strlower(wrd, wrd); if (!strcmp(wrd, "line")) lst = 0; else if (!strcmp(wrd, "dots")) lst = 1; else if (!strcmp(wrd, "dash")) lst = 2; else if (!strcmp(wrd, "longdash")) lst = 3; else if (!strcmp(wrd, "dashdot")) lst = 4; else if (!strcmp(wrd, "dashdot2")) lst = 6; else if (!strcmp(wrd, "stars")) pst = 0; else if (!strcmp(wrd, "box")) pst = 1; else if (!strcmp(wrd, "circ")) pst = 2; else if (!strcmp(wrd, "tri")) pst = 3; else if (!strcmp(wrd, "fbox")) pst = 4; else if (!strcmp(wrd, "fcirc")) pst = 5; else if (!strcmp(wrd, "ftri")) pst = 6; else v_failmsg("Bad style name (do '? style' for help)"); } v_exstrword(buf, wrd); } while (*buf != '\0' || *wrd != '\0'); v_lstyle[st] = lst; v_pstyle[st] = pst; if (v_lstyle[st] < 0 && v_pstyle[st] < 0) v_lstyle[st] = 0; } Static Void showlimits(axis, anotation, aticks, amin, amax, ainterval, alog) long axis, anotation, aticks; double amin, amax, ainterval; boolean alog; { Char buf[256]; switch (axis) { case 1: strcpy(buf, "Horizontal "); break; case 2: strcpy(buf, "Left vertical "); break; case 3: strcpy(buf, "Right vertical "); break; } strcat(buf, "axis:"); if (amin != ma_maxreal_ || amax != ma_minreal) { strcat(buf, " ["); if (amin != ma_maxreal_) sprintf(buf + strlen(buf), "%g", amin); strcat(buf, ":"); if (amax != ma_minreal) sprintf(buf + strlen(buf), "%g", amax); if (ainterval != 0.0) sprintf(buf + strlen(buf), ":%g", ainterval); strcat(buf, "]"); } else strcat(buf, " (no limits)"); if (alog) strcat(buf, " [log]"); else strcat(buf, " [linear]"); switch (anotation) { case 0: strcat(buf, " [flt]"); break; case 1: strcat(buf, " [int]"); break; case 2: strcat(buf, " [eng]"); break; case 3: strcat(buf, " [sci]"); break; case 4: strcat(buf, " [fix]"); break; } switch (aticks) { case 0: /* blank case */ break; case 1: strcat(buf, " [grid]"); break; case 2: strcat(buf, " [border]"); break; } v_logwriteln(buf); } Static Void helplimits() { v_logwriteln("Options for PLOT, FPLOT, and LIMITS commands:"); v_logwriteln(" [:] Scale axis automatically (default)"); v_logwriteln(" [a:b] Range axis between a and b"); v_logwriteln(" [a:b:c] Range axis from a to b in steps of c"); v_logwriteln(""); v_logwriteln(" [flt] Choose best notation for labels (default)"); v_logwriteln(" [fix] Decimal notation"); v_logwriteln(" [sci] Scientific notation"); v_logwriteln(" [int] Integer (or decimal) notation"); v_logwriteln(" [eng] Engineering notation"); v_logwriteln(""); v_logwriteln(" [lin] Linear axis (default)"); v_logwriteln(" [log] Logarithmic axis"); v_logwriteln(""); v_logwriteln(" [ticks] Small tick marks on axes (default)"); v_logwriteln(" [grid] Large grid lines on axes"); v_logwriteln(" [border] Small ticks on both sides of plot"); } Static boolean trackpollkbd(pen) m_tablet_info *pen; { boolean Result; double vel; Char TEMP; if (nk_keybufsize() > 0) { Result = true; while ((TEMP = nk_testkey(0), (uchar)TEMP < 32 && ((1L << TEMP) & 0x90002508L) != 0)) { penvel += 0.1; vel = (ma_tanh(penvel - 2) + 1.1) * 6; pen->near_ = true; switch (nk_getkey()) { case '\034': penx = P_rmin(penx + vel, penxmax); break; case '\b': penx = P_rmax(penx - vel, penxmin); break; case '\037': peny = P_rmin(peny + vel, penymax); break; case '\n': peny = P_rmax(peny - vel, penymin); break; case '\015': pen->depressed = !pen->depressed; break; case '\003': pen->near_ = false; break; } Result = (nk_keybufsize() > 0); } return Result; } Result = false; if (penvel >= 0.02) penvel *= 0.5; else penvel = 0.0; return Result; } Static Void inittrackpen(pen, minx, miny, maxx, maxy) m_tablet_info *pen; double minx, miny, maxx, maxy; { m_init_pen(0L); m_trackpen(&intpen); if (nc_text_in_window) printf("Use the mouse, press space to exit."); else printf("Use the mouse, press space to exit.\n"); pen->depressed = false; pen->near_ = false; penx = m_across / 2; peny = m_down / 2; penxmin = minx; penxmax = maxx; penymin = miny; penymax = maxy; wasdepr = false; wasnear = false; oldpenx = penx; oldpeny = peny; } Static Void mytrackpen(pen) m_tablet_info *pen; { pen->x = (long)floor(penx + 0.5); pen->y = (long)floor(peny + 0.5); m_readpen(&intpen); if (intpen.moving) { *pen = intpen; penx = pen->x; peny = pen->y; } if (pen->near_) m_cursor(pen->x, pen->y); else m_nocursor(); pen->dn = (pen->depressed && !wasdepr); pen->up = (!pen->depressed && wasdepr); pen->moving = (pen->depressed != wasdepr || pen->near_ != wasnear || penx != oldpenx || peny != oldpeny); wasdepr = pen->depressed; wasnear = pen->near_; oldpenx = penx; oldpeny = peny; } #define numcolors 6 #define maxtweak 10 typedef long colorvalsarr[numcolors]; typedef Char colornamesarr[numcolors][11]; Const colorvalsarr colorvals = { m_white, m_green, m_red, m_cyan, m_purple, m_yellow }; /*cyan really*/ Const colornamesarr colornames = { "White", "Green", "Red", "Blue", "Purple", "Yellow" }; #define wid 25 #define margin 20 /* Local variables for genplot: */ struct LOC_genplot { v_curverec *cbase, *vs, *highcp; Char title[256]; v_curverec *tweakcp[maxtweak]; long numtweak; boolean alog[3], alimited[3], afixed[3], ufixed[3], lfixed[3]; long limitmode[2]; Char units[3][256], alabel[3][256], logness[3][256]; long anotation[3], aticks[3]; double amin[3], amax[3], ainterval[3]; long i, vaxis, numcurves, numaxes; boolean dateflag, isscreen, hascolors, hasvs, hasplot, redraw, rescale, firstdraw; } ; Local Void reevalunits(LINK) struct LOC_genplot *LINK; { long i, axis; v_curverec *cp, *cp2; Char STR2[256]; for (i = 1; i <= 2; i++) { if (!LINK->ufixed[i]) *LINK->units[i] = '\0'; } cp = LINK->cbase; while (cp != NULL) { if (cp->flag) axis = 3; else axis = 2; if (!LINK->ufixed[axis - 1] && *cp->units != '\0') { cp2 = LINK->cbase; while (cp2 != cp && strcmp(cp2->units, cp->units)) cp2 = cp2->next2; if (cp2 == cp) { if (*LINK->units[axis - 1] == '\0') strcpy(LINK->units[axis - 1], cp->units); else { sprintf(STR2, "%s,%s", LINK->units[axis - 1], cp->units); strcpy(LINK->units[axis - 1], STR2); } } } cp = cp->next2; } } /* Local variables for plotpass: */ struct LOC_plotpass { struct LOC_genplot *LINK; double *bvec, *cvec; boolean doplot, dosplot; Char splotch; } ; Local boolean plotvalid(n, LINK) long n; struct LOC_plotpass *LINK; { return (LINK->bvec[n - 1] != v_badvalue && LINK->cvec[n - 1] != v_badvalue && (!LINK->LINK->alog[0] || LINK->bvec[n - 1] != 0) && (!LINK->LINK->alog[LINK->LINK->vaxis - 1] || LINK->cvec[n - 1] != 0)); } Local Void setstyle(st, defsplotch, LINK) long st; Char defsplotch; struct LOC_plotpass *LINK; { if (v_lstyle[st] >= 0) { mam_datastyle(v_lstyle[st]); LINK->doplot = true; } else LINK->doplot = false; if (v_pstyle[st] >= 0) { switch (v_pstyle[st]) { case 0: /*stars*/ LINK->splotch = 'E'; break; /*... don't work!*/ case 1: /*box*/ LINK->splotch = 'A'; break; case 2: /*circ*/ LINK->splotch = 'C'; break; case 3: /*tri*/ LINK->splotch = 'E'; break; case 4: /*fbox*/ LINK->splotch = 'B'; break; case 5: /*fcirc*/ LINK->splotch = 'D'; break; case 6: /*ftri*/ LINK->splotch = 'F'; break; } LINK->dosplot = true; } else { LINK->dosplot = false; LINK->splotch = defsplotch; } if (isupper(LINK->splotch)) { mam_symboloffset(0.0, 0.0); mam_symbolfont(14L); } else { mam_symboloffset(mam_defsymbolxoff, mam_defsymbolyoff); mam_symbolfont(2L); } } /* mode 1: scale curves */ /* mode 2: draw curves */ /* mode 3: erase highlighted curve */ /* mode 4: draw highlighted curve */ /* mode 5: erase curves */ Local Void plotpass(mode, LINK) long mode; struct LOC_genplot *LINK; { struct LOC_plotpass V; long i, j, k, num, fidx, vidx; v_curverec *cp; v_baserec *bp; double *xvec, *yvec, *fvec, *vvec; boolean xneg, yneg; long inflag, inflag2; double val, val2, ival, fval, fval2, fmax, fmin; V.LINK = LINK; cp = LINK->cbase; num = 0; while (cp != NULL) { num++; if (cp->next3 == NULL) { bp = cp->base; V.bvec = bp->vec; } else { bp = cp->next3->base; V.bvec = cp->next3->vec; } V.cvec = cp->vec; if (cp->flag) LINK->vaxis = 3; else LINK->vaxis = 2; V.doplot = true; V.dosplot = false; if ((unsigned long)mode < 32 && ((1L << mode) & 0x18) != 0 && cp != LINK->highcp) i = bp->len + 1; else i = 1; do { while (i <= bp->len && !plotvalid(i, &V)) i++; if (i <= bp->len) { j = i; xneg = (V.bvec[i - 1] < 0); yneg = (V.cvec[i - 1] < 0); while (i <= bp->len && plotvalid(i, &V) && (!LINK->alog[0] || (V.bvec[i - 1] < 0) == xneg) && (!LINK->alog[LINK->vaxis - 1] || (V.cvec[i - 1] < 0) == yneg)) /*will happen >= once*/ i++; xvec = &V.bvec[j - 1]; yvec = &V.cvec[j - 1]; switch (mode) { case 1: switch (LINK->limitmode[LINK->vaxis - 2]) { case 0: for (k = j - 1; k <= i - 2; k++) { val = V.cvec[k]; if (LINK->alog[LINK->vaxis - 1]) val = fabs(val); val2 = V.bvec[k]; if (LINK->alog[0]) val2 = fabs(val2); if (val < LINK->amin[LINK->vaxis - 1]) LINK->amin[LINK->vaxis - 1] = val; if (val > LINK->amax[LINK->vaxis - 1]) LINK->amax[LINK->vaxis - 1] = val; if (val2 < LINK->amin[0]) LINK->amin[0] = val2; if (val2 > LINK->amax[0]) LINK->amax[0] = val2; } break; case 1: case 2: if (LINK->limitmode[LINK->vaxis - 2] == 1) { fidx = 1; fvec = V.bvec; vidx = LINK->vaxis; vvec = V.cvec; } else { vidx = 1; vvec = V.bvec; fidx = LINK->vaxis; fvec = V.cvec; } fmin = LINK->amin[fidx - 1]; fmax = LINK->amax[fidx - 1]; fval = fvec[j - 1]; if (LINK->alog[fidx - 1]) fval = fabs(fval); val = vvec[j - 1]; if (LINK->alog[vidx - 1]) val = fabs(val); inflag = (fval > fmax) - (fval < fmin); if (inflag == 0) { LINK->amin[vidx - 1] = P_rmin(LINK->amin[vidx - 1], val); LINK->amax[vidx - 1] = P_rmax(LINK->amax[vidx - 1], val); } for (k = j; k <= i - 2; k++) { fval2 = fval; fval = fvec[k]; if (LINK->alog[fidx - 1]) fval = fabs(fval); val2 = val; val = vvec[k]; if (LINK->alog[vidx - 1]) val = fabs(val); inflag2 = inflag; inflag = (fval > fmax) - (fval < fmin); if (inflag == 0) { if (val < LINK->amin[vidx - 1]) LINK->amin[vidx - 1] = val; if (val > LINK->amax[vidx - 1]) LINK->amax[vidx - 1] = val; } if (inflag != inflag2 && !isequal(fval, fval2)) { /*crossing an edge*/ if (inflag < 0 || inflag2 < 0) { ival = val2 + (val - val2) * (fmin - fval2) / (fval - fval2); LINK->amin[vidx - 1] = P_rmin(LINK->amin[vidx - 1], ival); LINK->amax[vidx - 1] = P_rmax(LINK->amax[vidx - 1], ival); } if (inflag > 0 || inflag2 > 0) { ival = val2 + (val - val2) * (fmax - fval2) / (fval - fval2); LINK->amin[vidx - 1] = P_rmin(LINK->amin[vidx - 1], ival); LINK->amax[vidx - 1] = P_rmax(LINK->amax[vidx - 1], ival); } } } break; case 3: /* blank case */ break; } break; case 2: case 3: case 4: case 5: if ((xneg && LINK->alog[0]) != (yneg && LINK->alog[LINK->vaxis - 1])) setstyle(cp->astyle, 'E', &V); else setstyle(cp->style, 'C', &V); if (i - j == 1) { V.doplot = false; V.dosplot = true; } if (mode == 3 || mode == 5) mam_color(0L); else if (LINK->hascolors) { if (num > numcolors) mam_color(7L); else mam_color(colorvals[num - 1]); } else if (mode == 4) mam_color(1L); if (LINK->vaxis == 2) { if (V.doplot) mam_plot(&xvec, &yvec, i - j); if (V.dosplot) mam_splot(&xvec, &yvec, i - j, V.splotch); } else { if (V.doplot) mam_plot3(&xvec, &yvec, i - j); if (V.dosplot) mam_splot3(&xvec, &yvec, i - j, V.splotch); } break; } } } while (i <= bp->len); cp = cp->next2; } if (LINK->hascolors && mode >= 2) mam_color((long)m_white); } /*plotpass*/ Local Void plotcurves(fn_, LINK) Char *fn_; struct LOC_genplot *LINK; { Char fn[256]; long i; boolean erasing; double defcharsize; long FORLIM; strcpy(fn, fn_); mam_setup_generic(); LINK->isscreen = false; LINK->hascolors = false; if (!strcmp(fn, "erase")) { strcpy(fn, "screen"); erasing = true; } else erasing = false; if (!strcmp(fn, "screen")) { plot_initscreen(0L, 0L, 0L, 0L); LINK->isscreen = true; LINK->hascolors = (m_maxcolor > 1 && !erasing); } else if (!strcmp(fn, "plotter")) plot_init(0L, 'X'); else { plot_initgen(fn); if (strciends(fn, ".ff")) LINK->hascolors = true; } plot_selfont(2L); mam_init_generic(); if (LINK->isscreen) { defcharsize = mam_defcharsize; /*this is really to get around*/ mam_charsize(defcharsize * 1.5); /* the Bobcat-330 compiler bug*/ if (erasing) mam_color(0L); else mam_color((long)m_white); mam_font(1L); } FORLIM = LINK->numaxes; for (i = 1; i <= FORLIM; i++) { if (LINK->amin[i - 1] > LINK->amax[i - 1]) { switch (i) { case 1: v_failmsg("Bad limits on X axis"); break; case 2: v_failmsg("Bad limits on Y axis"); break; case 3: v_failmsg("Bad limits on righthand Y axis"); break; } } else if (LINK->amin[i - 1] == LINK->amax[i - 1]) { if (LINK->amin[i - 1] == 0) { LINK->amin[i - 1] = -1.0; LINK->amax[i - 1] = 1.0; } else { LINK->amin[i - 1] *= 0.5; LINK->amax[i - 1] *= 1.5; } } if (LINK->ainterval[i - 1] != 0) mam_fullrange(i, LINK->amin[i - 1], LINK->amax[i - 1], LINK->ainterval[i - 1]); else if (LINK->alog[i - 1] || LINK->afixed[i - 1]) mam_range(i, LINK->amin[i - 1], LINK->amax[i - 1]); else if (i > 2 || LINK->aticks[2 - i] == 2 || i >= 2 && LINK->numaxes > 2) mam_range(i, LINK->amin[i - 1] - (LINK->amax[i - 1] - LINK->amin[i - 1]) * 0.05, LINK->amax[i - 1] + (LINK->amax[i - 1] - LINK->amin[i - 1]) * 0.05); else mam_range(i, LINK->amin[i - 1] - (LINK->amax[i - 1] - LINK->amin[i - 1]) * 0.05, LINK->amax[i - 1]); switch (LINK->anotation[i - 1]) { case 0: mam_fltlabel(i); break; case 1: mam_intlabel(i); break; case 2: mam_englabel(i); break; case 3: /* blank case */ break; case 4: mam_fixlabel(i); break; } switch (LINK->aticks[i - 1]) { case 0: /* blank case */ break; case 1: mam_gridaxis(i); break; case 2: mam_mirroraxis(i); break; } } if (strciends(fn, ".ff") && v_getboolparam(p_tex)) mam_tex(); if (LINK->numaxes > 2) mam_axis3(LINK->alabel[0], LINK->units[0], LINK->logness[0], LINK->alabel[1], LINK->units[1], LINK->logness[1], LINK->alabel[2], LINK->units[2], LINK->logness[2]); else mam_axis(LINK->alabel[0], LINK->units[0], LINK->logness[0], LINK->alabel[1], LINK->units[1], LINK->logness[1]); if (LINK->hascolors) { mam_bordercolor(8L); mam_tickcolor(15L); mam_labelcolor(15L); } mam_drawborder(); plotpass(2L, LINK); if (*LINK->title != '\0') mam_title(LINK->title); mam_close_generic(); if (LINK->dateflag) mam_date(); plot_view(); plot_finish(); /*keep data out of axes*/ } /*plotcurves*/ Local Void parseminmax(buf, idx, needbrack, LINK) Char *buf; long idx; boolean needbrack; struct LOC_genplot *LINK; { double minval, maxval, intval; long i, first, last; boolean brack; Char wrd[256]; if (idx == 0) { first = 1; last = 3; } else { first = idx; last = idx; } while (*buf == '[' || !needbrack && *buf != '\0') { brack = (*buf == '['); if (brack) v_needsep(buf, '['); v_exstrword(buf, wrd); if (*buf == ':') { v_needsep(buf, ':'); for (i = first - 1; i < last; i++) { LINK->alimited[i] = true; LINK->afixed[i] = (*wrd != '\0' || *buf != '\0' && *buf != ']'); } if (*wrd != '\0') { if (v_parsereal(wrd, &minval)) { for (i = first - 1; i < last; i++) LINK->amin[i] = minval; } else v_fail(); } v_exstrword(buf, wrd); if (*wrd != '\0') { if (v_parsereal(wrd, &maxval)) { for (i = first - 1; i < last; i++) LINK->amax[i] = maxval; } else v_fail(); } if (*buf == ':') { v_needsep(buf, ':'); v_exstrword(buf, wrd); if (*wrd != '\0') { if (v_parsereal(wrd, &intval)) { for (i = first - 1; i < last; i++) LINK->ainterval[i] = intval; } else v_fail(); } } else { for (i = first - 1; i < last; i++) LINK->ainterval[i] = 0.0; } } else if (strcicmp(wrd, "flt") == 0) { for (i = first - 1; i < last; i++) LINK->anotation[i] = 0; } else if (strcicmp(wrd, "int") == 0) { for (i = first - 1; i < last; i++) LINK->anotation[i] = 1; } else if (strcicmp(wrd, "eng") == 0) { for (i = first - 1; i < last; i++) LINK->anotation[i] = 2; } else if (strcicmp(wrd, "sci") == 0) { for (i = first - 1; i < last; i++) LINK->anotation[i] = 3; } else if (strcicmp(wrd, "fix") == 0) { for (i = first - 1; i < last; i++) LINK->anotation[i] = 4; } else if (strcicmp(wrd, "lin") == 0 || strcicmp(wrd, "linear") == 0) { for (i = first - 1; i < last; i++) LINK->alog[i] = false; } else if (strcicmp(wrd, "log") == 0) { for (i = first - 1; i < last; i++) LINK->alog[i] = true; } else if (strcicmp(wrd, "ticks") == 0) { for (i = first - 1; i < last; i++) LINK->aticks[i] = 0; } else if (strcicmp(wrd, "grid") == 0) { for (i = first - 1; i < last; i++) LINK->aticks[i] = 1; } else if (strcicmp(wrd, "border") == 0) { for (i = first - 1; i < last; i++) LINK->aticks[i] = 2; } else if (strcicmp(wrd, "none") == 0) { for (i = first - 1; i < last; i++) { LINK->alimited[i] = true; LINK->afixed[i] = false; LINK->amin[i] = ma_maxreal_; LINK->amax[i] = ma_minreal; LINK->ainterval[i] = 0.0; } } else v_unrecognizedoption(); if (brack) v_needsep(buf, ']'); } } /* Local variables for zoom: */ struct LOC_zoom { struct LOC_genplot *LINK; long axis; double minrx, minry, maxrx, maxry, x1, y1, x2, y2; } ; Local Void drawzoom(LINK) struct LOC_zoom *LINK; { long ix1, iy1, ix2, iy2; /* if (x2 >= minrx) and (x2 <= maxrx) and (y2 >= minry) and (y2 <= maxry) then */ ix1 = (long)floor(LINK->x1 + 0.5); iy1 = (long)floor(LINK->y1 + 0.5); ix2 = (long)floor(LINK->x2 + 0.5); iy2 = (long)floor(LINK->y2 + 0.5); m_color(15L); m_colormode((long)m_xor); switch (LINK->axis) { case 0: m_drawrect(ix1, iy1, ix2, iy2); break; case 1: m_drawline(ix1, (long)floor(LINK->minry + 0.5), ix1, (long)floor(LINK->maxry + 0.5)); if (ix1 != ix2) m_drawline(ix2, (long)floor(LINK->minry + 0.5), ix2, (long)floor(LINK->maxry + 0.5)); break; case 2: case 3: m_drawline((long)floor(LINK->minrx + 0.5), iy1, (long)floor(LINK->maxrx + 0.5), iy1); if (iy1 != iy2) m_drawline((long)floor(LINK->minrx + 0.5), iy2, (long)floor(LINK->maxrx + 0.5), iy2); break; } m_colormode((long)m_normal); } Local Void zoom(axis_, LINK) long axis_; struct LOC_genplot *LINK; { struct LOC_zoom V; m_tablet_info pen; Char ch; long yaxis; double rx1, ry1, rx2, ry2, rint; V.LINK = LINK; V.axis = axis_; if (V.axis == 3) yaxis = 3; else yaxis = 2; if (!LINK->hasplot) { printf("No plot on screen"); return; } if (yaxis > LINK->numaxes) { printf("That axis is not active"); return; } mam_getrange(1L, &rx1, &rx2, &rint); mam_getrange(2L, &ry1, &ry2, &rint); mam_transform(rx1, ry1, yaxis, &V.minrx, &V.minry); mam_transform(rx2, ry2, yaxis, &V.maxrx, &V.maxry); inittrackpen(&pen, V.minrx, V.minry, V.maxrx, V.maxry); do { mytrackpen(&pen); } while (!(pen.dn || trackpollkbd(&pen) || v_peektakeover())); if (pen.dn && !trackpollkbd(&pen) && !v_peektakeover()) { /* (penx >= minrx) and (penx <= maxrx) and (peny >= minry) and (peny <= maxry) and */ V.x1 = penx; V.y1 = peny; do { V.x2 = penx; V.y2 = peny; drawzoom(&V); do { mytrackpen(&pen); } while (!(pen.moving || trackpollkbd(&pen) || v_peektakeover())); drawzoom(&V); } while (!(!pen.depressed || trackpollkbd(&pen) || v_peektakeover())); /* (penx >= minrx) and (penx <= maxrx) and (peny >= minry) and (peny <= maxry) and */ if (!trackpollkbd(&pen) && !v_peektakeover()) { if (V.x1 > V.x2) { rint = V.x1; V.x1 = V.x2; V.x2 = rint; } if (V.y1 > V.y2) { rint = V.y1; V.y1 = V.y2; V.y2 = rint; } mam_untransform(V.x1, V.y1, 2L, &rx1, &ry1); mam_untransform(V.x2, V.y2, 2L, &rx2, &ry2); if ((V.axis == 1 || V.axis == 0) && rx1 != rx2) { LINK->amin[0] = rx1; LINK->amax[0] = rx2; LINK->afixed[0] = true; } if ((V.axis == 2 || V.axis == 0) && ry1 != ry2) { LINK->amin[1] = ry1; LINK->amax[1] = ry2; LINK->afixed[1] = true; } if (V.axis == 3 || V.axis == 0 && LINK->numaxes >= 3) { mam_untransform(V.x1, V.y1, 3L, &rx1, &ry1); mam_untransform(V.x2, V.y2, 3L, &rx2, &ry2); if (ry1 != ry2) { LINK->amin[2] = ry1; LINK->amax[2] = ry2; LINK->afixed[2] = true; } } LINK->redraw = true; LINK->rescale = true; } } if (trackpollkbd(&pen)) ch = m_inkey(); } Local long saferound(x, LINK) double x; struct LOC_genplot *LINK; { if (x <= LONG_MIN) return LONG_MIN; else if (x >= LONG_MAX) return LONG_MAX; else return ((long)floor(x + 0.5)); } /* Local variables for measure: */ struct LOC_measure { struct LOC_genplot *LINK; long xx, yy, ox, oy, xpos; double minrx, minry, maxrx, maxry; } ; Local Void myputstr(y, s_, LINK) long y; Char *s_; struct LOC_measure *LINK; { Char s[256]; strcpy(s, s_); if (nc_text_in_window) nc_putStr((int)LINK->xpos, (int)y, s); else printf("%s\n",s); } Local Void drawmeasure(LINK) struct LOC_measure *LINK; { m_color(15L); m_colormode((long)m_xor); if (LINK->xx != -1) { if (LINK->xx >= LINK->minrx && LINK->xx <= LINK->maxrx) m_drawline(LINK->xx, (long)floor(LINK->minry + 0.5), LINK->xx, (long)floor(LINK->maxry + 0.5)); if (LINK->ox != -1 && LINK->ox != LINK->xx && LINK->ox >= LINK->minrx && LINK->ox <= LINK->maxrx) m_drawline(LINK->ox, (long)floor(LINK->minry + 0.5), LINK->ox, (long)floor(LINK->maxry + 0.5)); } if (LINK->yy != -1) { if (LINK->yy >= LINK->minry && LINK->yy <= LINK->maxry) m_drawline((long)floor(LINK->minrx + 0.5), LINK->yy, (long)floor(LINK->maxrx + 0.5), LINK->yy); if (LINK->oy != -1 && LINK->oy != LINK->yy && LINK->oy >= LINK->minry && LINK->oy <= LINK->maxry) m_drawline((long)floor(LINK->minrx + 0.5), LINK->oy, (long)floor(LINK->maxrx + 0.5), LINK->oy); } m_colormode((long)m_normal); } Local Void measure(axis, LINK) long axis; struct LOC_genplot *LINK; { struct LOC_measure V; m_tablet_info pen; boolean wasvisible; Char buf[256]; long i; double alpha, closest, oox, ooy, rx1, ry1, rx2, ry2, rx3, ry3, rx4, ry4, rint, base1, base2, basev, basenv, other1, other2, otherv, othernv; double *vec1, *vec2; v_curverec *cp, *nearcp; Char ch; Char STR1[256]; long FORLIM; Char STR2[256]; V.LINK = LINK; if (!LINK->hasplot) { printf("No plot on screen"); return; } V.xpos = nc_curWindow->width - wid; mam_getrange(1L, &rx1, &rx2, &rint); mam_getrange(2L, &ry1, &ry2, &rint); mam_transform(rx1, ry1, 2L, &V.minrx, &V.minry); mam_transform(rx2, ry2, 2L, &V.maxrx, &V.maxry); inittrackpen(&pen, V.minrx, V.minry, V.maxrx, V.maxry); m_alpha_on(); m_graphics_on(); V.ox = -1; V.oy = -1; V.xx = -1; V.yy = -1; nearcp = NULL; if (nc_text_in_window) myputstr(3L, "Press any key to stop.", &V); do { wasvisible = (V.xx != -1 || V.yy != -1); if (pen.near_ && V.minrx <= penx && penx <= V.maxrx && V.minry <= peny && peny <= V.maxry) { V.xx = pen.x; V.yy = pen.y; if (pen.dn && axis == 0) { V.ox = V.xx; V.oy = V.yy; oox = penx; ooy = peny; } else if (!pen.depressed) { V.ox = -1; V.oy = -1; } mam_untransform(penx, peny, 2L, &rx1, &ry1); if (LINK->numaxes > 2) mam_untransform(penx, peny, 3L, &rx2, &ry2); nc_clearXY((int)V.xpos, 0, wid, (int)LINK->numaxes); if (axis > 0) { cp = LINK->cbase; nearcp = NULL; while (cp != NULL) { if (cp->flag) { basev = rx2; otherv = ry2; } else { basev = rx1; otherv = ry1; } if (axis == 1) { if (cp->next3 == NULL) vec1 = cp->base->vec; else vec1 = cp->next3->vec; vec2 = cp->vec; } else if (!cp->flag == (axis == 2)) { vec1 = cp->vec; if (cp->next3 == NULL) vec2 = cp->base->vec; else vec2 = cp->next3->vec; rint = basev; basev = otherv; otherv = rint; } else vec1 = NULL; if (vec1 != NULL) { base1 = vec1[0]; other1 = vec2[0]; FORLIM = cp->base->len; for (i = 1; i < FORLIM; i++) { base2 = vec1[i]; other2 = vec2[i]; if (base1 != v_badvalue && base2 != v_badvalue && other1 != v_badvalue && other2 != v_badvalue && (base1 <= basev && basev <= base2 || base2 <= basev && basev <= base1)) { alpha = (basev - base1) / (base2 - base1); rint = other1 + alpha * (other2 - other1); if (nearcp == NULL || fabs(otherv - rint) < closest) { nearcp = cp; basenv = basev; othernv = rint; closest = fabs(otherv - rint); } } base1 = base2; other1 = other2; } } cp = cp->next2; } if (nearcp == NULL) { switch (axis) { case 1: basenv = rx1; break; case 2: basenv = ry1; break; case 3: basenv = ry2; break; } } switch (axis) { case 1: sprintf(STR2, "x: %g", basenv); myputstr(0L, STR2, &V); break; case 2: sprintf(STR1, "y: %g", basenv); myputstr(0L, STR1, &V); break; case 3: sprintf(STR2, "y2: %g", basenv); myputstr(0L, STR2, &V); break; } if (nearcp != NULL) { if (axis > 1) strcpy(buf, "x: "); else if (nearcp->flag) strcpy(buf, "y2: "); else strcpy(buf, "y: "); sprintf(STR2, "%s%g (%s)", buf, othernv, nearcp->name); myputstr(1L, STR2, &V); if (axis == 1) mam_transform(basenv, othernv, nearcp->flag + 2L, &rx3, &ry3); else mam_transform(othernv, basenv, nearcp->flag + 2L, &rx3, &ry3); if (axis == 1) V.yy = saferound(ry3, LINK); else V.xx = saferound(rx3, LINK); } else { if (axis == 1) V.yy = -1; else V.xx = -1; } } else { if (V.ox == -1) { sprintf(STR1, "x: %g", rx1); myputstr(0L, STR1, &V); sprintf(STR2, "y: %g", ry1); myputstr(1L, STR2, &V); if (LINK->numaxes > 2) { sprintf(STR1, "y2: %g", ry2); myputstr(2L, STR1, &V); } } else { if (pen.dn) { sprintf(STR2, "Measured: x = %g", rx1); v_logwrite(STR2); sprintf(STR1, " y = %g", ry1); v_logwrite(STR1); if (LINK->numaxes > 2) { sprintf(STR2, " y2 = %g", ry2); v_logwrite(STR2); } } mam_untransform(oox, ooy, 2L, &rx3, &ry3); if (LINK->numaxes > 2) mam_untransform(oox, ooy, 3L, &rx4, &ry4); if (LINK->alog[0]) { sprintf(STR1, "rx: %g", rx1 / rx3); myputstr(0L, STR1, &V); } else { sprintf(STR2, "dx: %g", rx1 - rx3); myputstr(0L, STR2, &V); } if (LINK->alog[1]) { sprintf(STR1, "ry: %g", ry1 / ry3); myputstr(1L, STR1, &V); } else { sprintf(STR2, "dy: %g", ry1 - ry3); myputstr(1L, STR2, &V); } if (LINK->numaxes > 2) { if (LINK->alog[2]) { sprintf(STR1, "ry2: %g", ry2 / ry4); myputstr(2L, STR1, &V); } else { sprintf(STR2, "dy2: %g", ry2 - ry4); myputstr(2L, STR2, &V); } } } } } else { V.xx = -1; V.yy = -1; } if (wasvisible && V.xx == -1 && V.yy == -1) nc_clearXY((int)V.xpos, 0, wid, (int)LINK->numaxes); drawmeasure(&V); do { mytrackpen(&pen); } while (!(pen.moving || trackpollkbd(&pen) || v_peektakeover())); drawmeasure(&V); } while (!(trackpollkbd(&pen) || v_peektakeover())); if (!trackpollkbd(&pen)) return; ch = m_inkey(); if (nc_alphashared()) LINK->redraw = true; else printf("\f"); } #undef wid Local Void redrawplot(LINK) struct LOC_genplot *LINK; { long i, j; v_curverec *cp; long FORLIM; if (LINK->rescale) { FORLIM = LINK->numaxes; for (i = 0; i < FORLIM; i++) { if (LINK->alog[i]) strcpy(LINK->logness[i], "log"); else strcpy(LINK->logness[i], "linear"); if (!LINK->afixed[i]) { LINK->amin[i] = ma_maxreal_; LINK->amax[i] = ma_minreal; LINK->ainterval[i] = 0.0; } } FORLIM = LINK->numaxes; for (i = 2; i <= FORLIM; i++) LINK->limitmode[i - 2] = (LINK->amin[i - 1] < LINK->amax[i - 1]) * 2 + (LINK->amin[0] < LINK->amax[0]); } LINK->hasplot = false; if (LINK->firstdraw) { if (LINK->rescale) plotpass(1L, LINK); plotcurves("screen", LINK); LINK->hasplot = true; } else { TRY(try2); if (LINK->rescale) plotpass(1L, LINK); plotcurves("screen", LINK); LINK->hasplot = true; RECOVER(try2); if (P_escapecode != -1) _Escape(P_escapecode); nc_gotoXY(0, nc_curWindow->height - 1); v_writeerror(); ENDTRY(try2); } i = nc_curWindow->height - P_imin2(LINK->numcurves, (long)numcolors) - 2; nc_gotoXY(0, (int)i); if (LINK->numcurves > 1 && v_p_quiet->val.U1.i1 == 0) { printf("%s: %s", colornames[0], LINK->cbase->name); j = strlen(colornames[0]) + strlen(LINK->cbase->name) + 2; if (LINK->numcurves > numcolors) { cp = LINK->cbase; for (i = 1; i <= numcolors; i++) cp = cp->next2; while (cp != NULL && j <= LONG_MAX) { if (j + P_imax2((long)strlen(cp->name), 3L) + 2 >= nc_curWindow->width) { j = LONG_MAX; printf(", ..."); } else printf(", %s", cp->name); cp = cp->next2; } } putchar('\n'); cp = LINK->cbase->next2; FORLIM = P_imin2(LINK->numcurves, (long)numcolors); for (i = 1; i < FORLIM; i++) { printf("%s: %s\n", colornames[i], cp->name); cp = cp->next2; } } LINK->redraw = false; LINK->rescale = false; } /* Local variables for tweak: */ struct LOC_tweak { struct LOC_genplot *LINK; Char vals[maxtweak][margin + 6]; long signs[maxtweak]; long i, curnum, curpos; boolean changed, pchanged; } ; Local Void cleanzero(val, LINK) Char *val; struct LOC_tweak *LINK; { LINK->i = 1; while ((val[LINK->i - 1] == ' ' || val[LINK->i - 1] == '0') && (LINK->i == 1 || val[LINK->i - 2] == ' ') && LINK->i < strlen(val) && (val[LINK->i] == ' ' || isdigit(val[LINK->i]))) { val[LINK->i - 1] = ' '; LINK->i++; } } Local Void storevalue(wrd, LINK) Char *wrd; struct LOC_tweak *LINK; { TRY(try3); LINK->LINK->tweakcp[LINK->curnum - 1]->yval = atof(wrd) * LINK->signs[LINK->curnum - 1]; if (LINK->LINK->tweakcp[LINK->curnum - 1]->yval == 0) /*fix -0's*/ LINK->signs[LINK->curnum - 1] = 1; v_change(LINK->LINK->tweakcp[LINK->curnum - 1]); strcpy(LINK->vals[LINK->curnum - 1], wrd); LINK->changed = true; LINK->pchanged = true; RECOVER(try3); if (P_escapecode == -20) _Escape(P_escapecode); /* reescape rhkoshi */ BEEP(); ENDTRY(try3); } Local Void adjust(dir, LINK) long dir; struct LOC_tweak *LINK; { long i, epos, ppos; Char val[256]; boolean doneadj, abortadj; Char STR1[256]; long FORLIM; strcpy(val, LINK->vals[LINK->curnum - 1]); epos = strposc(val, 'e', 1L); ppos = strposc(val, '.', 1L); if (epos == 0) epos = margin + 1; doneadj = false; abortadj = false; if (LINK->curpos < epos) { if (val[LINK->curpos - 1] == ' ' || isdigit(val[LINK->curpos - 1])) { dir *= LINK->signs[LINK->curnum - 1]; i = LINK->curpos; while (i <= margin && val[i - 1] == ' ') { val[i - 1] = '0'; i++; } i = LINK->curpos; do { val[i - 1] = (Char)(val[i - 1] + dir); if (val[i - 1] > '9' || val[i - 1] < '0') { if (val[i - 1] < '0') val[i - 1] = '9'; else val[i - 1] = '0'; i--; if (i >= 1 && val[i - 1] == '.') i--; if (i == 0 || val[i - 1] == ' ') { if (dir > 0) { if (i == 0) { if (ppos > 0 && ppos < epos - 1) { strcpy(val + epos - 2, val + epos - 1); sprintf(val, "1%s", strcpy(STR1, val)); LINK->curpos++; } else abortadj = true; } else val[i - 1] = '1'; } else { LINK->signs[LINK->curnum - 1] = -LINK->signs[LINK->curnum - 1]; val[LINK->curpos - 1] = '1'; /*used to be '0'*/ FORLIM = LINK->curpos - 2; for (i = 0; i <= FORLIM; i++) { if (val[i] == '9') val[i] = '0'; } } doneadj = true; } } else doneadj = true; } while (!doneadj); cleanzero(val, LINK); } } else { if (LINK->curpos > epos) { i = strtol(strcpy(STR1, val + epos), NULL, 0) + dir; val[epos] = '\0'; /* p2c: viewcurves.text, line 1853: * Note: Modification of string length may translate incorrectly [146] */ sprintf(val + strlen(val), "%ld", i); while (strlen(val) < margin) sprintf(val, " %s", strcpy(STR1, val)); while (strlen(val) > margin && !abortadj) { if (val[0] == ' ') strcpy(val, val + 1); else abortadj = true; } } } if (!abortadj) storevalue(val, LINK); /* ignore */ } Local Void adddigit(LINK) struct LOC_tweak *LINK; { Char val[256]; long epos, ppos; Char STR1[256]; strcpy(val, LINK->vals[LINK->curnum - 1]); epos = strposc(val, 'e', 1L); if (epos == 0) epos = strlen(val) + 1; ppos = strposc(val, '.', 1L); if (ppos == 0) { if (val[0] != ' ' || val[1] != ' ') { BEEP(); return; } sprintf(STR1, ".0%s", val + epos - 1); strcpy(val + epos - 1, STR1); strcpy(val, val + 2); storevalue(val, LINK); return; } if (val[0] != ' ') { BEEP(); return; } sprintf(STR1, "0%s", val + epos - 1); strcpy(val + epos - 1, STR1); strcpy(val, val + 1); storevalue(val, LINK); } Local Void deldigit(LINK) struct LOC_tweak *LINK; { Char val[256]; long i, epos, ppos; Char STR2[256]; strcpy(val, LINK->vals[LINK->curnum - 1]); epos = strposc(val, 'e', 1L); if (epos == 0) epos = strlen(val) + 1; ppos = strposc(val, '.', 1L); if (ppos <= 0) { BEEP(); return; } if (ppos == epos - 2) i = 2; else i = 1; strcpy(val + epos - i - 1, val + epos - 1); sprintf(val, "%*s%s", (int)i, "", strcpy(STR2, val)); storevalue(val, LINK); } Local Void getvalue(i, r, LINK) long i; double r; struct LOC_tweak *LINK; { Char wrd[256]; if (r < 0) LINK->signs[i - 1] = -1; else LINK->signs[i - 1] = 1; ma_strfmtreal(wrd, fabs(r), (long)margin, -1L); if (strlen(wrd) > margin) wrd[margin] = '\0'; strcpy(LINK->vals[i - 1], wrd); } Local Void tweak(buf_, LINK) Char *buf_; struct LOC_genplot *LINK; { struct LOC_tweak V; Char buf[256]; Char shbuf[margin]; v_curverec *cp; Char wrd[256], wrd2[256]; long j, xpos; double r; boolean redo, done, isfirst; Char ch, nextch, prevch; long FORLIM; Char STR1[256]; V.LINK = LINK; strcpy(buf, buf_); V.changed = true; V.pchanged = false; redo = false; nextch = '\0'; if (*buf == '\0') { FORLIM = LINK->numtweak; for (V.i = 1; V.i <= FORLIM; V.i++) { cp = LINK->tweakcp[V.i - 1]; getvalue(V.i, cp->yval, &V); } } else { LINK->numtweak = 0; nextch = ' '; do { v_strword(buf, wrd); if (*wrd != '\0') { cp = v_findcurve(wrd); if (cp == NULL || cp->kind != v_ck_num) { sprintf(STR1, "No such constant as %s", wrd); v_failmsg(STR1); } if (LINK->numtweak == maxtweak) { sprintf(STR1, "Can't adjust more than %ld curves", (long)maxtweak); v_failmsg(STR1); } LINK->numtweak++; LINK->tweakcp[LINK->numtweak - 1] = cp; if (*buf == '=') { v_needsep(buf, '='); v_strword(buf, wrd); if (!v_parseureal(wrd, &r, wrd2)) v_fail(); if (*wrd2 != '\0') v_addcurveconst(r, wrd2, cp->name); else v_assigncurveconst(r, cp->name); V.changed = true; V.pchanged = true; redo = true; } else nextch = '\0'; getvalue(LINK->numtweak, cp->yval, &V); } } while (*wrd != '\0'); } if (LINK->numtweak == 0) v_failmsg("Need a curve name"); xpos = nc_curWindow->width - margin; V.curnum = 1; V.curpos = margin; isfirst = true; done = false; prevch = ' '; ch = ' '; do { if (redo) { if (ch == prevch && ch == ' ') { cp = LINK->cbase; while (cp != NULL) { v_needcurve(cp); cp = cp->next2; } LINK->redraw = true; LINK->rescale = true; printf("\f"); redrawplot(LINK); V.pchanged = false; } else { /*fast redraw without rescaling*/ plotpass(5L, LINK); cp = LINK->cbase; while (cp != NULL) { v_needcurve(cp); cp = cp->next2; } plotpass(2L, LINK); V.pchanged = false; } } if (redo || isfirst) { FORLIM = LINK->numtweak; for (V.i = 1; V.i <= FORLIM; V.i++) { cp = LINK->tweakcp[V.i - 1]; sprintf(wrd, "%s:", cp->name); nc_putStr((int)(xpos - strlen(cp->name) - 2), (int)V.i, wrd); } strcpy(wrd, "Use knob/arrows to select, +/- to adjust digit, space to redraw, \"q\" to exit."); nc_putStr(0, nc_curWindow->height - 2, wrd); isfirst = false; } if (redo || V.changed) { FORLIM = LINK->numtweak; for (V.i = 1; V.i <= FORLIM; V.i++) { sprintf(wrd, " %s", V.vals[V.i - 1]); if (V.signs[V.i - 1] < 0) { j = 1; while (wrd[j - 1] == ' ') j++; wrd[j - 2] = '-'; } nc_putStr((int)(xpos - 1), (int)V.i, wrd); } } redo = false; V.changed = false; prevch = ch; if (nextch != '\0') { ch = nextch; nextch = '\0'; } else { nc_gotoXY((int)(xpos + V.curpos - 1), (int)V.curnum); ch = tolower(nk_getkey()); nc_gotoXY(0, nc_curWindow->height - 2); } switch (ch) { case '\034': if (V.curpos < margin) V.curpos++; break; case '\b': if (V.curpos > 1) V.curpos--; break; case '\n': case '\015': if (V.curnum < LINK->numtweak) V.curnum++; break; case '\037': if (V.curnum > 1) V.curnum--; break; case '+': adjust(1L, &V); break; case '-': adjust(-1L, &V); break; case '<': adddigit(&V); break; case '>': deldigit(&V); break; case '=': nc_gotoXY((int)xpos, (int)V.curnum); nc_clearXY((int)xpos, (int)V.curnum, margin, 1); strcpy(shbuf, strltrim(V.vals[V.curnum - 1])); if (V.signs[V.curnum - 1] < 0) { if (strlen(shbuf) == margin) *shbuf = '\0'; else sprintf(shbuf, "-%s", strcpy(STR1, shbuf)); } newci_inputstring(shbuf, im_default, "\003\015\034\n ", &nextch, false, &V.i); if (nextch == '\015') nextch = '\0'; if (*shbuf != '\0') { if (v_parsereal(shbuf, &r)) { v_assigncurveconst(r, LINK->tweakcp[V.curnum - 1]->name); getvalue(V.curnum, r, &V); V.changed = true; V.pchanged = true; } else { v_clearerror(); BEEP(); } } V.changed = true; break; case '.': strcpy(wrd, V.vals[V.curnum - 1]); V.i = strposc(wrd, 'e', 1L); if (V.curpos <= strlen(wrd) && (V.i == 0 || V.curpos < V.i) && wrd[V.curpos - 1] != '.') { V.i = strposc(wrd, '.', 1L); if (V.i != 0) wrd[V.i - 1] = '0'; if (wrd[V.curpos - 1] == ' ' && V.curpos > 1) wrd[V.curpos - 1] = '0'; wrd[V.curpos - 1] = '.'; V.i = V.curpos + 1; while (V.i <= strlen(wrd) && wrd[V.i - 1] == ' ') { wrd[V.i - 1] = '0'; V.i++; } cleanzero(wrd, &V); if (V.curpos < strlen(wrd) && isdigit(wrd[V.curpos])) V.curpos++; storevalue(wrd, &V); } break; case ' ': redo = true; break; case '\003': case '\004': case 'q': if (V.pchanged) { nextch = ch; redo = true; } else done = true; break; default: if (isdigit(ch)) { strcpy(wrd, V.vals[V.curnum - 1]); if (V.curpos <= strlen(wrd) && (wrd[V.curpos - 1] == ' ' || wrd[V.curpos - 1] == '.' || isdigit(wrd[V.curpos - 1]))) { wrd[V.curpos - 1] = ch; V.i = V.curpos + 1; while (V.i <= strlen(wrd) && wrd[V.i - 1] == ' ') { wrd[V.i - 1] = '0'; V.i++; } cleanzero(wrd, &V); if (V.curpos < strlen(wrd) && (wrd[V.curpos] == ' ' || wrd[V.curpos] == '.' || isdigit(wrd[V.curpos]))) V.curpos++; storevalue(wrd, &V); } } break; } } while (!done); } #undef margin Local Char *defaxislabel(Result, axis, LINK) Char *Result; long axis; struct LOC_genplot *LINK; { Char buf[256]; v_curverec *cp; Char STR1[256]; *buf = '\0'; if (axis == 1) { if (LINK->hasvs && LINK->vs != NULL) strcpy(buf, LINK->vs->name); return strcpy(Result, buf); } cp = LINK->cbase; while (cp != NULL) { if (!cp->flag == (axis == 2)) { if (*buf == '\0') strcpy(buf, cp->name); else { sprintf(STR1, ", %s", cp->name); safeappend(buf, STR1, 200L); } } cp = cp->next2; } return strcpy(Result, buf); } Local Void askaxislabel(axis, LINK) long axis; struct LOC_genplot *LINK; { Char buf[256], wrd[256]; Char STR1[256]; switch (axis) { case 1: strcpy(wrd, "Horizontal"); break; case 2: strcpy(wrd, "Vertical"); break; case 3: strcpy(wrd, "Right vertical"); break; } if (*LINK->alabel[LINK->i - 1] == '\0') defaxislabel(buf, axis, LINK); else strcpy(buf, LINK->alabel[LINK->i - 1]); sprintf(STR1, "%s axis label: ", wrd); v_readkbddef(LINK->alabel[LINK->i - 1], STR1, buf, ""); LINK->lfixed[LINK->i - 1] = (strcmp(LINK->alabel[LINK->i - 1], buf) == 0); } Local Void tryclear(LINK) struct LOC_genplot *LINK; { if (nc_alphashared()) nc_gotoXY(0, 0); else printf("\f"); } Local long getaxis(buf, LINK) Char *buf; struct LOC_genplot *LINK; { if (strcicmp(buf, "x") == 0) return 1; else if (strcicmp(buf, "y") == 0) return 2; else if (strcicmp(buf, "y2") == 0) return 3; else return 0; } /* Remove non-curves from the list */ Local Void cleancurvelist(cbase, LINK) v_curverec **cbase; struct LOC_genplot *LINK; { v_curverec *cp, *prev; cp = *cbase; prev = NULL; while (cp != NULL) { if (cp->kind != v_ck_curve) { if (prev == NULL) *cbase = cp->next2; else prev->next2 = cp->next2; } else prev = cp; cp = cp->next2; } if (*cbase == NULL) v_notvector(); } Static Void genplot(buf, isfast) Char *buf; boolean isfast; { struct LOC_genplot V; static colorvalsarr colorvals_ = { m_white, m_green, m_red, m_cyan, m_purple, m_yellow }; static colornamesarr colornames_ = { "White", "Green", "Red", "Blue", "Purple", "Yellow" }; Char wrd[256]; v_curverec *cfirst, *cgroup, *clast, *cp, *cp2; v_baserec *bp; long j; boolean flag, flag2; long FORLIM; Char STR1[256]; Char STR2[256], STR3[256]; for (V.i = 1; V.i <= 3; V.i++) { *V.units[V.i - 1] = '\0'; V.ufixed[V.i - 1] = false; *V.alabel[V.i - 1] = '\0'; V.lfixed[V.i - 1] = false; *V.logness[V.i - 1] = '\0'; V.afixed[V.i - 1] = v_alimited[V.i - 1]; V.alimited[V.i - 1] = false; V.anotation[V.i - 1] = v_anotation[V.i - 1]; V.alog[V.i - 1] = v_alog[V.i - 1]; V.aticks[V.i - 1] = v_aticks[V.i - 1]; V.amin[V.i - 1] = ma_maxreal_; V.amax[V.i - 1] = ma_minreal; V.ainterval[V.i - 1] = 0.0; } V.dateflag = (!isfast && v_getboolparam(p_datestamp)); V.hasplot = false; *V.title = '\0'; V.numtweak = 0; V.numcurves = 0; V.numaxes = 2; V.hasvs = false; clast = NULL; V.cbase = NULL; cgroup = NULL; parseminmax(buf, 0L, true, &V); /*global options*/ do { v_ncurvelist(buf, &cfirst, v_clsome); cleancurvelist(&cfirst, &V); if (cgroup == NULL) cgroup = cfirst; if (clast != NULL) clast->next2 = cfirst; else V.cbase = cfirst; cp = cfirst; while (cp != NULL) { clast = cp; V.numcurves++; if (*cp->units == '\0') flag2 = false; else if (*V.units[1] == '\0' || !strcmp(V.units[1], cp->units)) { strcpy(V.units[1], cp->units); flag2 = false; } else if (*V.units[2] == '\0' || !strcmp(V.units[2], cp->units)) { strcpy(V.units[2], cp->units); flag2 = true; V.numaxes = 3; } else { v_logwriteln("Warning: more than two types of y-units present"); flag2 = false; /*arbitrary*/ } cp->flag = flag2; cp = cp->next2; } if (flag2) parseminmax(buf, 3L, true, &V); else parseminmax(buf, 2L, true, &V); if (*buf == ':') { v_needsep(buf, ':'); v_strword(buf, wrd); parseminmax(buf, 1L, true, &V); if (*wrd == '\0') { cp = cgroup; while (cp != NULL) { bp = cp->base; if (*V.units[0] == '\0') strcpy(V.units[0], bp->units); else if (*bp->units != '\0' && strcmp(V.units[0], bp->units)) v_logwriteln("Warning: bases have inconsistent units"); cp->next3 = NULL; cp = cp->next2; } cgroup = NULL; } else { cp = v_findcurve(wrd); if (cp == NULL) v_nosuchcurve(wrd); v_needcurve(cp); bp = cp->base; if (bp == NULL) v_notvector(); cp2 = cfirst; while (cp2 != NULL) { if (cp2->base != bp) v_cantcombine(); cp2->next3 = cp; cp2 = cp2->next2; } if (V.hasvs) V.vs = NULL; else V.vs = cp; V.hasvs = true; if (*V.units[0] == '\0') strcpy(V.units[0], cp->units); else if (*cp->units != '\0' && strcmp(V.units[0], cp->units)) v_logwriteln("Warning: bases have inconsistent units"); cgroup = NULL; } } } while (*buf != '\0'); cp = cgroup; while (cp != NULL) { bp = cp->base; if (*V.units[0] == '\0') strcpy(V.units[0], bp->units); else if (*bp->units != '\0' && strcmp(V.units[0], bp->units)) v_logwriteln("Warning: bases have inconsistent units"); cp->next3 = NULL; cp = cp->next2; } reevalunits(&V); *V.title = '\0'; FORLIM = V.numaxes; for (V.i = 1; V.i <= FORLIM; V.i++) { strcpy(V.alabel[V.i - 1], defaxislabel(STR1, V.i, &V)); if (V.numaxes > 2 && V.i > 1 && v_p_quiet->val.U1.i1 == 0) { switch (V.i) { case 2: nc_gotoXY(0, 0); printf("Curves on left axis:%s\n", V.alabel[V.i - 1]); break; case 3: printf("Curves on right axis:%s\n", V.alabel[V.i - 1]); break; } } if (!V.alimited[V.i - 1]) { if (v_alimited[V.i - 1]) { V.amin[V.i - 1] = v_amin[V.i - 1]; V.amax[V.i - 1] = v_amax[V.i - 1]; V.ainterval[V.i - 1] = v_ainterval[V.i - 1]; } } } V.firstdraw = true; V.redraw = true; V.rescale = true; do { if (V.redraw) { if (v_p_quiet->val.U1.i1 == 0 || !isfast) { if (nc_gType() == nc_g300 || !V.firstdraw) printf("\f"); else { FORLIM = nc_curWindow->height; for (V.i = 1; V.i <= FORLIM; V.i++) putchar('\n'); } } V.hasplot = false; redrawplot(&V); } m_alpha_on(); XFlush(m_display); if (isfast) { if (!nc_alphashared() && v_p_quiet->val.U1.i1 == 0) printf("Press the ALPHA key to clear the graph\n"); v_halt(); } nc_gotoXY(0, nc_curWindow->height - 2); if (V.firstdraw) { V.firstdraw = false; v_readkbd(buf, "Plot mode [h for help]> \t", ""); /* if v_readkbd(buf, 'Want to plot this curve [h for help]? '#9, '') then ; */ } else v_readkbd(buf, "Plot mode> \t", ""); TRY(try4); v_strword(buf, wrd); strlower(wrd, wrd); if (*wrd == 'n' || *wrd == 'q' || *wrd == '\0' && *buf == '\0') { m_graphics_off(); v_halt(); } else if (*wrd == 'r') { V.rescale = true; V.redraw = true; } else if (!strncmp(buf, "[?]", 3L)) { tryclear(&V); helplimits(); } else if (*wrd == 'x') { parseminmax(buf, 1L, false, &V); V.rescale = true; V.redraw = true; } else if (!strncmp(wrd, "y2", 2L)) { parseminmax(buf, 3L, false, &V); V.rescale = true; V.redraw = true; } else if (*wrd == 'y') { parseminmax(buf, 2L, false, &V); V.rescale = true; V.redraw = true; } else if (*wrd == '\0' && *buf == '[') { parseminmax(buf, 0L, false, &V); V.rescale = true; V.redraw = true; } else if (*wrd == 'u') { V.i = getaxis(strcpy(STR1, wrd + 1), &V); if (V.i == 0) { /*unzoom*/ strcpy(buf, "[:]"); parseminmax(buf, 0L, false, &V); V.rescale = true; V.redraw = true; } else { /*set units*/ strcpy(V.units[V.i - 1], buf); V.ufixed[V.i - 1] = true; V.redraw = true; } } else if (*wrd == 'i') { cp = v_findcurve(buf); V.highcp = V.cbase; while (V.highcp != cp && V.highcp != NULL) V.highcp = V.highcp->next2; if (V.highcp == NULL) printf("No curve \"%s\" on the plot", buf); else { do { plotpass(3L, &V); plotpass(4L, &V); } while (!m_pollkbd()); m_inkey(); } } else if (*wrd == '<' || *wrd == '>') { flag2 = (*wrd == '>'); strcpy(wrd, wrd + 1); if (*wrd == '\0') v_strword(buf, wrd); while (*wrd != '\0') { cp = v_findcurve(wrd); if (cp != NULL) { cp->flag = flag2; v_strword(buf, wrd); } } V.i = 2; cp = V.cbase; while (cp != NULL) { if (cp->flag) V.i = 3; cp = cp->next2; } V.numaxes = V.i; reevalunits(&V); FORLIM = V.numaxes; for (V.i = 2; V.i <= FORLIM; V.i++) { if (!V.lfixed[V.i - 1]) strcpy(V.alabel[V.i - 1], defaxislabel(STR1, V.i, &V)); } V.redraw = true; V.rescale = true; } else if (*wrd == 'z') zoom(getaxis(strcpy(STR1, wrd + 1), &V), &V); else if (*wrd == 'm') measure(getaxis(strcpy(STR1, wrd + 1), &V), &V); else if (*wrd == 'c') tweak(buf, &V); else if (*wrd == 's') { if (*buf == '\0') { /*show limits*/ tryclear(&V); for (V.i = 1; V.i <= 3; V.i++) showlimits(V.i, V.anotation[V.i - 1], V.aticks[V.i - 1], V.amin[V.i - 1], V.amax[V.i - 1], V.ainterval[V.i - 1], V.alog[V.i - 1]); } else { /*change style*/ dostyle(buf); V.redraw = true; } } else if (*buf == '@' && *wrd == '\0') { while (*buf == '@') { flag = false; flag2 = false; while (*buf == '@') { strcpy(buf, buf + 1); if (*buf == '@') { strcpy(buf, buf + 1); v_exstrword(buf, wrd); if (v_parseinteger(wrd, &j)) flag2 = true; } else { v_exstrword(buf, wrd); if (v_parseinteger(wrd, &V.i)) flag = true; } } v_strword(buf, wrd); while (*wrd != '\0') { cp = v_findcurve(wrd); if (cp != NULL) { if (flag) cp->style = V.i; if (flag2) cp->astyle = j; V.redraw = true; } v_strword(buf, wrd); } } } else if (*wrd == 'd') { V.dateflag = !V.dateflag; V.redraw = true; } else if (*wrd == 't') { if (*buf != '\0') strcpy(V.title, buf); else v_readkbddef(V.title, "Plot title: ", V.title, ""); V.redraw = true; } else if (*wrd == 'l') { V.i = getaxis(strcpy(STR1, wrd + 1), &V); if (V.i == 0) { FORLIM = V.numaxes; for (V.i = 1; V.i <= FORLIM; V.i++) askaxislabel(V.i, &V); } else { if (*buf != '\0') { strcpy(V.alabel[V.i - 1], buf); V.lfixed[V.i - 1] = true; } else askaxislabel(V.i, &V); } V.redraw = true; } else if (*wrd == 'p') { plotcurves("plotter", &V); V.redraw = true; /* m_graphics_off; v_halt; */ } else if (*wrd == 'a') { if (*buf != '\0') newci_fixfname(buf, "ps", ""); else { sprintf(buf, "/tmp/plot%ld.ps", newci_fullseconds() % 1000); /* p2c: viewcurves.text, line 2661: * Note: Using % for possibly-negative arguments [317] */ } plotcurves(buf, &V); /* * print to unix postscript printer, then delete file */ strcpy (unixCommand, "lpr -h "); strcat (unixCommand, buf); system (unixCommand); strcpy (unixCommand, "rm -f "); strcat (unixCommand, buf); system (unixCommand); V.redraw = true; /* m_graphics_off; v_halt; */ } else if (*wrd == 'f') { if (*buf == '\0') v_readkbd(buf, "Enter file name: ", ""); strlower(buf, strcpy(STR2, strltrim(strrtrim(strcpy(STR3, buf))))); if (*buf != '\0') { do { flag = false; if (strends(buf, ".ff")) v_logwriteln("Writing a .ff file"); else if (strends(buf, ".ps")) v_logwriteln("Writing a PostScript file"); else if (strends(buf, ".hpgl")) v_logwriteln("Writing an HPGL file"); else if (strposc(buf, '.', 1L) != 0) { v_failmsg("Don't understand file type"); *buf = '\0'; } else { v_readkbddef(wrd, "Which format (ff, ps, hpgl)? ", "ff", ""); strlower(wrd, wrd); if (*wrd == '.') strcpy(wrd, wrd + 1); if (!strcmp(wrd, "f")) strcpy(wrd, "ff"); else if (!strcmp(wrd, "h")) strcpy(wrd, "hpgl"); else if (*wrd == '\0' || !strcmp(wrd, "p")) strcpy(wrd, "ps"); newci_fixfname(buf, wrd, ""); flag = true; } } while (flag); } if (*buf != '\0') { plotcurves(buf, &V); V.redraw = true; /* m_graphics_off; v_halt; */ } } else { tryclear(&V); /* writeln('Plot mode commands:'); */ printf(" n (or blank line) Return to \"view>\" prompt\n"); printf(" r Refresh the screen\n"); printf(" s Show current plotting parameters\n"); printf(" x [...] Set x-axis options (like XLIMITS)\n"); printf(" y [...] Set y-axis options (or y2 for right axis)\n"); printf(" [...] Set options on all axes\n"); printf(" [?] Show list of plotting options\n"); printf(" z Zoom using pen (also zx, zy, zy2)\n"); printf(" u Unzoom, i.e., set all axes auto-ranging\n"); printf(" m Measure data using pen (also mx, my, my2)\n"); printf(" c ... Change constants and recompute plot\n"); printf(" t ... Set the title string\n"); printf(" l ... Set the axis labels (also lx, ly, ly2)\n"); printf(" < ... Move curve(s) to the left axis (also >)\n"); printf(" @n ... Set curve(s) to style n (also @@n, s@n=)\n"); printf(" ux ... Set units on the x-axis (also uy, uy2)\n"); printf(" i ... Identify (flash) specified curve\n"); printf(" d Turn date-stamp on and off\n"); printf(" p Plot on a pen plotter (unsupported)\n"); printf(" a Plot on a Postscript printer (via lpr)\n"); printf(" f Plot into a file\n"); } RECOVER(try4); if (P_escapecode != -1) _Escape(P_escapecode); ENDTRY(try4); if (*v_lasterrormsg != '\0') { fputs(v_lasterrormsg, stdout); v_clearerror(); } } while (true); } /*genplot*/ #undef numcolors #undef maxtweak Static Void initplotting() { long i; for (i = 0; i <= 2; i++) { v_aticks[i] = 0; v_amin[i] = ma_maxreal_; v_amax[i] = ma_minreal; v_ainterval[i] = 0.0; } } Static Void doplot(buf_) Char *buf_; { Char buf[256]; strcpy(buf, buf_); genplot(buf, false); } Static Void dofplot(buf_) Char *buf_; { Char buf[256]; strcpy(buf, buf_); genplot(buf, true); } Static Void dolimitstuff(which, buf_) long which; Char *buf_; { Char buf[256], wrd[256]; long i, first, last; double min, max, interv; boolean brack; strcpy(buf, buf_); if (which == 0) { first = 1; last = 3; } else { first = which; last = which; } if (!strcmp(buf, "?") || !strcmp(buf, "[?]")) { helplimits(); return; } if (*buf == '\0') { for (i = first - 1; i < last; i++) showlimits(i + 1, v_anotation[i], v_aticks[i], v_amin[i], v_amax[i], v_ainterval[i], v_alog[i]); return; } while (*buf != '\0') { brack = (*buf == '['); if (brack) v_needsep(buf, '['); v_exstrword(buf, wrd); if (*buf == ':') { v_needsep(buf, ':'); if (*wrd == '\0' && (*buf == '\0' || *buf == ']')) { for (i = first - 1; i < last; i++) { v_alimited[i] = false; v_amin[i] = ma_maxreal_; v_amax[i] = ma_minreal; v_ainterval[i] = 0.0; } } else { if (*wrd == '\0') min = ma_maxreal_; else if (!v_parsereal(wrd, &min)) v_fail(); v_exstrword(buf, wrd); if (*wrd == '\0') max = ma_minreal; else if (!v_parsereal(wrd, &max)) v_fail(); interv = 0.0; if (*buf == ':') { v_needsep(buf, ':'); v_exstrword(buf, wrd); if (*wrd != '\0') { if (!v_parsereal(wrd, &interv)) v_fail(); } } for (i = first - 1; i < last; i++) { v_amin[i] = min; v_amax[i] = max; v_ainterval[i] = interv; v_alimited[i] = true; } } } else if (strcicmp(wrd, "flt") == 0) { for (i = first - 1; i < last; i++) v_anotation[i] = 0; } else if (strcicmp(wrd, "int") == 0) { for (i = first - 1; i < last; i++) v_anotation[i] = 1; } else if (strcicmp(wrd, "eng") == 0) { for (i = first - 1; i < last; i++) v_anotation[i] = 2; } else if (strcicmp(wrd, "log") == 0) { for (i = first - 1; i < last; i++) v_alog[i] = true; } else if (strcicmp(wrd, "sci") == 0) { for (i = first - 1; i < last; i++) v_anotation[i] = 3; } else if (strcicmp(wrd, "fix") == 0) { for (i = first - 1; i < last; i++) v_anotation[i] = 4; } else if (strcicmp(wrd, "lin") == 0 || strcicmp(wrd, "linear") == 0) { for (i = first - 1; i < last; i++) v_alog[i] = false; } else if (strcicmp(wrd, "ticks") == 0) { for (i = first - 1; i < last; i++) v_aticks[i] = 0; } else if (strcicmp(wrd, "grid") == 0) { for (i = first - 1; i < last; i++) v_aticks[i] = 1; } else if (strcicmp(wrd, "border") == 0) { for (i = first - 1; i < last; i++) v_aticks[i] = 2; } else if (strcicmp(wrd, "none") == 0) { for (i = first - 1; i < last; i++) { v_alimited[i] = false; v_amin[i] = ma_maxreal_; v_amax[i] = ma_minreal; v_ainterval[i] = 0.0; } } else v_unrecognizedoption(); if (brack) v_needsep(buf, ']'); } } /*dolimitstuff*/ Static Void dolimits(buf) Char *buf; { dolimitstuff(0L, buf); } Static Void doxlimits(buf) Char *buf; { dolimitstuff(1L, buf); } Static Void doylimits(buf) Char *buf; { dolimitstuff(2L, buf); } Static Void doy2limits(buf) Char *buf; { dolimitstuff(3L, buf); } /* Local variables for doregress: */ struct LOC_doregress { Char buf[256], wrd[256]; long kind; boolean fullrange; double minv, maxv; } ; Local Void regropts(LINK) struct LOC_doregress *LINK; { while (*LINK->buf == '[') { v_needsep(LINK->buf, '['); v_exstrword(LINK->buf, LINK->wrd); if (strcicmp(LINK->wrd, "lin") == 0) LINK->kind = 0; else if (strcicmp(LINK->wrd, "exp") == 0) LINK->kind = 1; else if (strcicmp(LINK->wrd, "pow") == 0) LINK->kind = 2; else if (*LINK->buf == ':') { v_needsep(LINK->buf, ':'); if (!v_parsereal(LINK->wrd, &LINK->minv)) v_fail(); v_exstrword(LINK->buf, LINK->wrd); if (!v_parsereal(LINK->wrd, &LINK->maxv)) v_fail(); ma_rsort2(&LINK->minv, &LINK->maxv); if (LINK->minv == LINK->maxv) v_failmsg("Error: = "); LINK->fullrange = false; } else v_unrecognizedoption(); v_needsep(LINK->buf, ']'); } } Static Void doregress(buf_) Char *buf_; { struct LOC_doregress V; v_curverec *cp, *cp2; long i; v_baserec *bp; double *vec; double xval, yval, sigy, sigy2, sigx, sigx2, sigxy, n, x0, sigmax0, phi, a, b, c, m, sigmam, sigmab; boolean good, xpos, xneg, ypos, yneg, haserr; long FORLIM; Char STR1[256], STR2[256], STR3[256]; strcpy(V.buf, buf_); V.fullrange = true; V.kind = 0; regropts(&V); v_desteqsrc(V.buf, &cp, v_clopt); regropts(&V); /*allow options before or after*/ v_checktoomany(V.buf); while (cp != NULL) { bp = cp->base; if (bp == NULL) v_notvector(); sigx = 0.0; sigy = 0.0; sigx2 = 0.0; sigy2 = 0.0; sigxy = 0.0; xpos = false; xneg = false; ypos = false; yneg = false; n = 0.0; FORLIM = bp->len; for (i = 0; i < FORLIM; i++) { xval = bp->vec[i]; yval = cp->vec[i]; if (yval != v_badvalue && xval != v_badvalue && (V.fullrange || V.minv <= xval && xval <= V.maxv)) { good = true; switch (V.kind) { case 0: /*fit to line*/ break; /*just leave 'em alone*/ case 1: /*fit to exponential*/ if (yval > 0) { ypos = true; yval = log(yval); } else if (yval < 0) { yneg = true; yval = log(-yval); } else good = false; break; case 2: /*fit to power function*/ if (xval > 0) { xpos = true; xval = log(xval); } else if (xval < 0) { xneg = true; xval = log(-xval); } else good = false; if (yval > 0) { ypos = true; yval = log(yval); } else if (yval < 0) { yneg = true; yval = log(-yval); } else good = false; break; } if (good) { sigy += yval; sigy2 += yval * yval; sigx += xval; sigx2 += xval * xval; sigxy += xval * yval; n++; } } } if (v_p_debug->val.U1.i1 > 0) { sprintf(STR2, "REGRESSION: n = %g", n); v_logwriteln(STR2); sprintf(STR3, "sigma_x = %g sigma_x^2 = %g", sigx, sigx2); v_logwriteln(STR3); sprintf(STR1, "sigma_y = %g sigma_y^2 = %g", sigy, sigy2); v_logwriteln(STR1); sprintf(STR2, "sigma_xy = %g", sigxy); v_logwriteln(STR2); } if (n < 2) v_failmsg("Need at least 2 good points for regression"); /* now calculate everything*/ switch (V.kind) { case 0: /*fit to line*/ m = (sigxy - sigx * sigy / n) / (sigx2 - sigx * sigx / n); b = (sigy - m * sigx) / n; haserr = false; TRY(try5); if (n > 2) phi = (sigy2 - b * sigy - m * sigxy) / (n - 2); else phi = 0.0; sigmab = sqrt((double)(phi * sigx2 / (n * sigx2 - sigx * sigx))); sigmam = sqrt((double)(phi * n / (n * sigx2 - sigx * sigx))); haserr = true; RECOVER(try5); newci_nullrecover(); ENDTRY(try5); sprintf(STR1, "Linear regression for %s = m*x + b", cp->name); v_logwriteln(STR1); if (haserr) { sprintf(STR3, " m = %g +/- %g", m, sigmam); v_logwriteln(STR3); sprintf(STR1, " b = %g +/- %g", b, sigmab); v_logwriteln(STR1); } else { sprintf(STR2, " m = %g", m); v_logwriteln(STR2); sprintf(STR1, " b = %g", b); v_logwriteln(STR1); } sprintf(STR1, "%s_m", cp->name); v_assigncurveconst(m, STR1); sprintf(STR1, "%s_b", cp->name); v_assigncurveconst(b, STR1); strcpy(V.wrd, " x0 = "); TRY(try6); x0 = -(b / m); if (haserr) { sprintf(V.wrd + strlen(V.wrd), "%g +/- ", x0); sigmax0 = fabs( x0 * sqrt((double)(sigmab * sigmab / (b * b) + sigmam * sigmam / (m * m)))); sprintf(V.wrd + strlen(V.wrd), "%g", sigmax0); } sprintf(STR2, "%s_x0", cp->name); v_assigncurveconst(x0, STR2); RECOVER(try6); strcat(V.wrd, "(error)"); ENDTRY(try6); v_logwriteln(V.wrd); break; case 1: /*fit to exponential*/ m = (sigxy - sigx * sigy / n) / (sigx2 - sigx * sigx / n); a = exp((sigy - m * sigx) / n); if (yneg) { if (ypos) v_failmsg("Curve contains both positive and negative Y values"); else a = -a; } b = exp(m); c = m; sprintf(STR1, "Exponential fit for %s = a*b^x = a*exp(c*x)", cp->name); v_logwriteln(STR1); sprintf(STR2, " a = %g", a); v_logwriteln(STR2); sprintf(STR1, " b = %g", b); v_logwriteln(STR1); sprintf(STR2, " c = %g", c); v_logwriteln(STR2); sprintf(STR2, "%s_a", cp->name); v_assigncurveconst(a, STR2); sprintf(STR2, "%s_b", cp->name); v_assigncurveconst(b, STR2); sprintf(STR2, "%s_c", cp->name); v_assigncurveconst(c, STR2); break; case 2: /*fit to power function*/ m = (sigxy - sigx * sigy / n) / (sigx2 - sigx * sigx / n); a = exp((sigy - m * sigx) / n); if (yneg) { if (ypos) v_failmsg("Curve contains both positive and negative Y values"); else a = -a; } if (xneg && xpos) v_failmsg("Curve contains both positive and negative X values"); b = m; sprintf(STR1, "Power function fit for %s = a * x^b", cp->name); v_logwriteln(STR1); sprintf(STR2, " a = %g", a); v_logwriteln(STR2); sprintf(STR1, " b = %g", b); v_logwriteln(STR1); sprintf(STR1, "%s_a", cp->name); v_assigncurveconst(a, STR1); sprintf(STR1, "%s_b", cp->name); v_assigncurveconst(b, STR1); if (xneg) v_logwriteln("(X values are negative)"); break; } if (cp->dest != NULL) { v_newvector(&vec, bp->len); switch (V.kind) { case 0: /*fit to line*/ FORLIM = bp->len; for (i = 0; i < FORLIM; i++) vec[i] = m * bp->vec[i] + b; break; case 1: /*fit to exponential*/ FORLIM = bp->len; for (i = 0; i < FORLIM; i++) vec[i] = a * exp(c * bp->vec[i]); break; case 2: /*fit to power function*/ FORLIM = bp->len; for (i = 0; i < FORLIM; i++) { if (bp->vec[i] == 0) vec[i] = 0.0; else vec[i] = a * ma_mytox(fabs(bp->vec[i]), b); } break; } v_makecurve(&cp2, bp, vec, cp->units, cp->dest); } cp = cp->next2; } } Static Void doderiv(buf_) Char *buf_; { Char buf[256], wrd[256]; v_curverec *cp, *cp2, *cp3; v_baserec *bp; double *vec, *v1, *v2; long i, FORLIM; Char STR2[256]; strcpy(buf, buf_); v_desteqsrc(buf, &cp, v_clsome); if (*buf == ':') { strcpy(buf, buf + 1); v_strword(buf, wrd); cp2 = v_findcurve(wrd); if (cp2 == NULL) v_nosuchcurve(wrd); v_needcurve(cp2); } else cp2 = NULL; v_checktoomany(buf); while (cp != NULL) { bp = cp->base; if (bp == NULL) v_notvector(); v1 = cp->vec; if (cp2 != NULL) { if (cp2->base != bp) v_cantcombine(); v2 = cp2->vec; strcpy(wrd, cp2->units); } else { v_checksorted(bp); v2 = bp->vec; strcpy(wrd, bp->units); } v_newvector(&vec, bp->len); vec[0] = v_badvalue; FORLIM = bp->len; for (i = 2; i <= FORLIM; i++) { if (v1[i - 1] == v_badvalue || v1[i - 2] == v_badvalue || v2[i - 1] == v_badvalue || v2[i - 2] == v_badvalue) vec[i - 1] = v_badvalue; else vec[i - 1] = (v1[i - 1] - v1[i - 2]) / (v2[i - 1] - v2[i - 2]); } if (*wrd == '\0') strcpy(wrd, cp->units); else sprintf(wrd, "%s/%s", cp->units, strcpy(STR2, wrd)); v_makecurve(&cp3, bp, vec, wrd, cp->dest); cp = cp->next2; } } /*doderiv*/ Static Void dosplice(buf_) Char *buf_; { Char buf[256], wrd[256], dest[256]; v_curverec *cp, *cp2; v_baserec *bp; strcpy(buf, buf_); v_strword(buf, dest); if (*dest == '\0') v_needcurvename(); v_needsep(buf, '='); v_strword(buf, wrd); cp = v_findcurve(wrd); if (cp == NULL) v_nosuchcurve(wrd); v_needcurve(cp); bp = cp->base; if (bp == NULL) v_notvector(); v_needsep(buf, ':'); v_strword(buf, wrd); v_desteqsrc2(dest, wrd, &cp2); v_checktoomany(buf); while (cp2 != NULL) { if (cp2->base == NULL) v_notvector(); if (cp2->base != bp) { if (cp2->base->len != bp->len) v_failmsg("Curves have different numbers of points"); else { if (v_p_quiet->val.U1.i1 == 0) printf("Warning: curves have different bases\n"); } } v_addcurve(bp->len, cp->vec, cp2->vec, cp->units, cp2->units, cp2->dest); cp2 = cp2->next2; } } /*dosplice*/ Static Void dosort(buf_) Char *buf_; { Char buf[256]; v_curverec *cp, *cbase; strcpy(buf, buf_); v_curvelist(buf, &cbase, v_clopt); v_checktoomany(buf); cp = cbase; while (cp != NULL) { v_sortcurve(cp); cp = cp->next2; } } Static Void dopoke(buf_) Char *buf_; { Char buf[256], wrd[256]; long i; v_curverec *cp, *cbase; double val; strcpy(buf, buf_); v_curvelist(buf, &cbase, v_clopt); v_needsep(buf, '@'); v_exstrword(buf, wrd); if (!v_parseinteger(wrd, &i)) v_fail(); v_needsep(buf, '='); v_exstrword(buf, wrd); if (!v_parsereal(wrd, &val)) v_fail(); v_checktoomany(buf); cp = cbase; while (cp != NULL) { if (cp->expr != NULL) v_failmsg("Can't assign to part of a computed curve"); if (cp->base != NULL && i >= 1 && i <= cp->base->len) cp->vec[i - 1] = val; cp = cp->next2; } } /* Functions */ Static Void cvlenproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); if (cp == NULL || cp->kind != v_ck_curve) *res = 0.0; else *res = cp->base->len; } /* syntax: cvsum('curvename') */ Static Void cvsumproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; double *vec; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); if (cp == NULL || cp->kind != v_ck_curve) _Escape(ne_badescape); *res = 0.0; i = cp->base->len; if (mode == 'x') vec = cp->base->vec; else vec = cp->vec; while (i >= 1) { if (vec[i - 1] != v_badvalue) *res += vec[i - 1]; i--; } } /* syntax: cvsubsum('curvename', v1, v2) */ Static Void cvsubsumproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; double *vec, *bvec; double v1, v2; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); if (cp == NULL || cp->kind != v_ck_curve) _Escape(ne_badescape); *res = 0.0; i = cp->base->len; if (mode == 'x') vec = cp->base->vec; else vec = cp->vec; bvec = cp->base->vec; v1 = ne_reval(nex->UU.U10.p2); v2 = ne_reval(nex->UU.U10.p3); while (i >= 1) { if (vec[i - 1] != v_badvalue && v1 <= bvec[i - 1] && bvec[i - 1] <= v2) *res += vec[i - 1]; i--; } } /* syntax: cvprod('curvename') */ Static Void cvprodproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; double *vec; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); if (cp == NULL || cp->kind != v_ck_curve) _Escape(ne_badescape); *res = 1.0; i = cp->base->len; if (mode == 'x') vec = cp->base->vec; else vec = cp->vec; while (i >= 1) { if (vec[i - 1] != v_badvalue) *res *= vec[i - 1]; i--; } } #define aname "__A__" #define bname "__B__" /* syntax: cvapply('curvename', 'funcname') */ Static Void cvapplyproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; ne_nexrec *nex2; Char mode; double *vec; long i; boolean hada, hadb; v_curverec *acp, *bcp; double aval, bval; Char STR1[256]; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); if (cp == NULL || cp->kind != v_ck_curve) _Escape(ne_badescape); if (mode == 'x') vec = cp->base->vec; else vec = cp->vec; acp = v_findcurve(aname); if (acp != NULL && acp->kind == v_ck_num) { aval = acp->yval; hada = true; } else { v_assigncurveconst(0.0, aname); acp = v_findcurve(aname); if (acp == NULL || acp->kind != v_ck_num) _Escape(ne_badescape); hada = false; } bcp = v_findcurve(bname); if (bcp != NULL && bcp->kind == v_ck_num) { bval = bcp->yval; hadb = true; } else { v_assigncurveconst(0.0, bname); bcp = v_findcurve(bname); if (bcp == NULL || bcp->kind != v_ck_num) _Escape(ne_badescape); hadb = false; } sprintf(buf, "%s(%s,%s)", ne_seval(STR1, nex->UU.U10.p2), aname, bname); v_buildsymtab(0L); ne_compile(buf, &nex2, &v_nedesc); if ((ne_opkind)nex2->op == ne_error) _Escape(ne_badescape); i = 1; while (i <= cp->base->len && vec[i - 1] == v_badvalue) i++; *res = vec[i - 1]; i++; while (i <= cp->base->len && *res != v_badvalue) { if (vec[i - 1] != v_badvalue) { acp->yval = *res; bcp->yval = vec[i - 1]; *res = ne_revaluate(nex2, &v_nedesc); } i++; } if (hada) acp->yval = aval; else v_deletecurve(&acp); if (hadb) bcp->yval = bval; else v_deletecurve(&bcp); ne_dispose(&nex2); } #undef aname #undef bname /* syntax: cvidx('curvename', idx) */ Static Void cvidxproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); i = (long)floor(ne_reval(nex->UU.U10.p2) + 0.5); if (cp == NULL || cp->kind != v_ck_curve || i < 1 || i > cp->base->len) _Escape(ne_badescape); if (mode == 'x') *res = cp->base->vec[i - 1]; else *res = cp->vec[i - 1]; if (*res == v_badvalue) _Escape(ne_badescape); } /* syntax: cvrelidx('curvename', delta_idx) */ Static Void cvrelidxproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); i = v_arithidx + (long)floor(ne_reval(nex->UU.U10.p2) + 0.5); if (cp == NULL || cp->kind != v_ck_curve || i < 1 || i > cp->base->len) _Escape(ne_badescape); if (mode == 'x') *res = cp->base->vec[i - 1]; else *res = cp->vec[i - 1]; if (*res == v_badvalue) _Escape(ne_badescape); } /* syntax: cvvalid('curvename', idx) */ Static Void cvvalidproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); i = (long)floor(ne_reval(nex->UU.U10.p2) + 0.5); if (cp == NULL || cp->kind != v_ck_curve || (unsigned long)i > cp->base->len) { *res = 0.0; return; } if (i == 0) { *res = 1.0; i = cp->base->len; while (i >= 1 && cp->vec[i - 1] != v_badvalue && cp->base->vec[i - 1] != v_badvalue) i--; *res = (i < 1); return; } if (cp->vec[i - 1] == v_badvalue || cp->base->vec[i - 1] == v_badvalue) *res = 0.0; else *res = 1.0; } /* syntax: cvrelvalid('curvename', delta_idx) */ Static Void cvrelvalidproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); i = v_arithidx + (long)floor(ne_reval(nex->UU.U10.p2) + 0.5); if (cp == NULL || cp->kind != v_ck_curve || i < 1 || i > cp->base->len || cp->vec[i - 1] == v_badvalue || cp->base->vec[i - 1] == v_badvalue) *res = 0.0; else *res = 1.0; } /* syntax: cvsearch('curvename', idx) */ Static Void cvsearchproc(nex, res) ne_nexrec *nex; double *res; { Char buf[256]; v_curverec *cp; Char mode; long i; mode = 'y'; ne_seval(buf, nex->UU.U10.p1); v_checkcurvename(buf, &cp, &mode); i = (long)floor(ne_reval(nex->UU.U10.p2) + 0.5); if (cp == NULL || cp->kind != v_ck_curve) _Escape(ne_badescape); if (i == 0) { *res = 0.0; return; } if (i > 0) { while (i <= cp->base->len && (cp->vec[i - 1] == v_badvalue || cp->base->vec[i - 1] == v_badvalue || cp->vec[i - 1] <= 0)) i++; if (i <= cp->base->len) *res = i; else *res = 0.0; return; } i = -i; if (i > cp->base->len) i = cp->base->len; while (i >= 1 && (cp->vec[i - 1] == v_badvalue || cp->base->vec[i - 1] == v_badvalue || cp->vec[i - 1] <= 0)) i--; if (i >= 1) *res = i; else *res = 0.0; } /* Interpolators */ Static Void lextrinterp(cp, x, user, val) v_curverec *cp; double x; na_long user; double *val; { v_baserec *bp; double *vec, *bvec; double diff; long i, len; bp = cp->base; if (!bp->sorted) v_checksorted(bp); bvec = bp->vec; len = bp->len; i = 1; while (i <= len && bvec[i - 1] <= x) /*this should be a binary search*/ i++; vec = cp->vec; if (len < 2) { *val = v_badvalue; return; } if (i == 1) { *val = vec[0] + (x - bvec[0]) * (vec[1] - vec[0]) / (bvec[1] - bvec[0]); return; } diff = x - bvec[i - 2]; if (diff == 0) { *val = vec[i - 2]; return; } if (i > len) *val = vec[i - 2] + diff * (vec[i - 2] - vec[i - 3]) / (bvec[i - 2] - bvec[i - 3]); else *val = vec[i - 2] + diff * (vec[i - 1] - vec[i - 2]) / (bvec[i - 1] - bvec[i - 2]); } Static Void dofit(buf_) Char *buf_; { fit (buf_); } /* Initialization */ Void curves_viewinit() { _PROCEDURE TEMP; TEMP.proc = (Anyptr)dofit; TEMP.link = (Anyptr)NULL; v_addcmd("fit", TEMP, "fit ...", "Fit a function with parameters to data"); v_addhelp("fit ..."); v_addhelp(" Fit a computed function to a data curve with the same"); v_addhelp(" basis. This is done via simplex minimization of chi^2"); v_addhelp(" over the specified parameters of the function. The"); v_addhelp(" constant \"fit_tol\" is used to specify the goodness"); v_addhelp(" of fit, and is created with a default value of 0.001"); v_addhelp(" if not previously set. Output can be redirected to a"); v_addhelp(" specified file if the \" > file_name\" convention is"); v_addhelp(" appended to the command line."); TEMP.proc = (Anyptr)doedit; TEMP.link = (Anyptr)NULL; v_addcmd("edit", TEMP, "edit ", "Run the editor on a curve"); v_addhelp("edit ..."); v_addhelp(" Write the curve(s) to a temporary file, run Caged on"); v_addhelp(" that file, then reload the curves when Caged exits."); TEMP.proc = (Anyptr)dorange; TEMP.link = (Anyptr)NULL; v_addcmd("range", TEMP, "*", ""); v_addhelp("range = [ : ]"); v_addhelp(" Make a curve from another by taking those points"); v_addhelp(" with <= X <= ."); TEMP.proc = (Anyptr)doregress; TEMP.link = (Anyptr)NULL; v_addcmd("regress", TEMP, "regress ", "Compute linear regression"); v_addhelp("regress "); v_addhelp("regress [ : ]"); v_addhelp("regress = "); v_addhelp("regress = [ : ]"); v_addhelp(" Compute linear regression coefficients for a curve."); v_addhelp(" If is given, create a new curve which is the fitted line."); v_addhelp(" If a range is given, examine only points with <= X <= ."); v_addhelp(" Also stores the coefficients as View variables."); v_addhelp(" The [exp] option fits an exponential instead of a line,"); v_addhelp(" and [pow] fits a power function (a*x^b)."); TEMP.proc = (Anyptr)doderiv; TEMP.link = (Anyptr)NULL; v_addcmd("deriv", TEMP, "deriv =", "Compute deriv wrt base"); v_addhelp("deriv = "); v_addhelp("deriv = : "); v_addhelp(" Compute the derivative of a curve with respect to its"); v_addhelp(" basis, or with respect to another curve."); TEMP.proc = (Anyptr)dosplice; TEMP.link = (Anyptr)NULL; v_addcmd("splice", TEMP, "*", ""); v_addhelp("splice = : "); v_addhelp(" Make a curve with x-axis = and y-axis = ."); TEMP.proc = (Anyptr)doplot; TEMP.link = (Anyptr)NULL; v_addcmd("plot", TEMP, "plot ", "Plot curves against basis"); v_addhelp("plot "); v_addhelp("plot : "); v_addhelp(" Plot one or more curves against their bases or"); v_addhelp(" against another curve. The plot is previewed on"); v_addhelp(" the screen, then you may choose to plot it again on"); v_addhelp(" a pen plotter, laser printer, or file."); v_addhelp(" Curve names may be followed by @