Jspice3
newgraf.c
Go to the documentation of this file.
1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: 1992 Stephen R. Whiteley
5 ****************************************************************************/
6 
7 /*
8  * NEWGRAF.C Copyright (c) S. Whiteley 1989 All Rights Reserved
9  * Added iplot routines 4/17/91 SRW
10  * Added 'a' option. 8/14/90 SRW
11  * Added routines for plotting margin analysis results 8/15/90.
12  * This file contains all the routines needed for the "graf" command
13  * in spice or nutmeg. A line for graf should be added to the command
14  * table definition file (spcmdtab.c and nucmdtab.c in 3e2).
15  * A declaration for com_graf should be added to FTEextern.h .
16  * The following options are accepted after each plot, or on command
17  * line following '-':
18  *
19  * 'a' Append the current plot to file "plotdt".
20  * 'b' Plot the data in X-Y mode, taking 2 traces at a time.
21  * 'c' Bring up the marker. The marker prints the trace coordinates
22  * when control-ENTER is struck, and is retired when ENTER is depressed.
23  * The marker is associated with a particular trace (indicated by color)
24  * and is retired when ENTER is depressed. Point to left of graph to
25  * change active trace in x-y mode.
26  * 'h' Print the help message.
27  * 'n' Use similar scales for three classes of traces: those with names
28  * beginning with V, I, and otherwise (case insensitive).
29  * 'N' Plot all traces on the same vertical scale.
30  * 'p' Plot the data as points.
31  * 'P' Print the screen on HP laserjet, generate plotfile "hpplot".
32  * 'q' Exit the program.
33  * 's' Interpolate as steps, hold value until next point (cmd line only).
34  * 't' Display each trace on a separate axis so as to not overlap.
35  * 'x' Change the horizontal scale, thus plot a portion of the graph.
36  * 'X' Same as 'x' but use the whole curve to generate the vertical
37  * scales. For x,X the new horiz. scale max and min are prompted for.
38  * 'y' Use separate scales for each trace (undo n or N).
39  *
40  * Options p, t toggle, y,n,N remain in effect until changed (y is the
41  * default). When using the x,X options, ENTER as response to the scale
42  * min max prompt will reset to full scale, and space followed by ENTER
43  * will leave the values unchanged.
44  * If no command line args, previous options, if any, are used.
45  */
46 
47 #include "spice.h"
48 #include "ftedefs.h"
49 #include "newgraf.h"
50 #include "plotdev.h"
51 #include "plotext.h"
52 
53 GRAPH* EchoGraph; /* set to the GRAPH during iplot (iplot.c) */
54 
55 /* Plot on log scale if max/min > LOGTST and min != 0 */
56 #define LOGTST 50
57 
58 /* NUMOUTPTS number points plotted */
59 #define NUMOUTPTS 1001
60 
61 static bool Running; /* used to terminate if not using X */
62 
63 static char INBUF[128]; /* INBUF general purpose buffer */
64 
65 #ifdef __STDC__
66 static bool is_monotonic(struct dvec*);
67 static void free_graf(GRDATA);
68 static GRDATA copygraf(GRDATA);
69 static void init_viewport(struct screen*);
70 static void graf_display(GRAPH*);
71 static int alpha_only(char*);
72 static void what_now(char*);
73 static int interval(struct gplot*,int,int,double*,double*);
74 static void interpolateX(struct gplot*,struct dvec*);
75 static void interpolateY(struct gplot*,int,struct dvec*);
76 static void proc_option(struct gplot*,char*);
77 static void displ(struct gplot*);
78 static int newscale(struct gplot*);
79 static void displxy(struct gplot*);
80 static void minmax(struct gplot*,int*);
81 static void draw(struct gplot*,int,double,double);
82 static void axes(struct gplot*,int,int);
83 static void set_scale(double,double,double*,double*,int*);
84 static void set_scale_4(double,double,double*,double*);
85 static void writef(double,int,int);
86 static void writeg(double,int,int,char);
87 static char *ecvt12(double);
88 static void help(struct gplot*);
89 static void fpick(GRAPH*);
90 static void graf_setmark(struct gplot*,int);
91 static void ghost_mark(int,int,int,int);
92 static int ymap(struct gplot*,double*,int,int,int,int);
93 static void xy_pick(struct gplot*);
94 static int set_cursor(struct gplot*,int);
95 static void addplot(struct gplot*);
96 static void extpts(FILE*,struct chkpts**);
97 static void combin(struct chkpts*);
98 static void plpts(struct mdata*);
99 static void mp_display(GRAPH*);
100 static void mp_free(GRDATA);
101 static void chkpts_free(struct chkpts*);
102 static GRDATA mp_copy(GRDATA);
103 static void init(struct mdata*);
104 static void addit(struct chkpts*,int,int,int);
105 static void ebox(int,int,int,int);
106 static void xbox(int,int,int,int);
107 static void pbox(int,int,int,int);
108 #else
109 static bool is_monotonic();
110 static void free_graf();
111 static GRDATA copygraf();
112 static void init_viewport();
113 static void graf_display();
114 static int alpha_only();
115 static void what_now();
116 static int interval();
117 static void interpolateX();
118 static void interpolateY();
119 static void proc_option();
120 static void displ();
121 static int newscale();
122 static void displxy();
123 static void minmax();
124 static void draw();
125 static void axes();
126 static void set_scale();
127 static void set_scale_4();
128 static void writef();
129 static void writeg();
130 static char *ecvt12();
131 static void help();
132 static void fpick();
133 static void graf_setmark();
134 static void ghost_mark();
135 static int ymap();
136 static void xy_pick();
137 static int set_cursor();
138 static void addplot();
139 static void extpts();
140 static void combin();
141 static void plpts();
142 static void mp_display();
143 static void mp_free();
144 static void chkpts_free();
145 static GRDATA mp_copy();
146 static void init();
147 static void addit();
148 static void ebox();
149 static void xbox();
150 static void pbox();
151 #endif
152 
153 /* common error messages */
154 static char *errmsg_scale = "Error: scale not monotonically increasing\n";
155 static char *errmsg_gralloc = "Error: can't allocate new graph\n";
156 static char *errmsg_newvp = "Error: can't open viewport for graphics\n";
157 
158 void
160 
161 /* Main routine for graf command. */
162 wordlist *wl;
163 {
164  struct pnode *names;
165  struct dvec *d, *lv, *scale;
166  struct dvlist *dl0, *dl;
167  char *s, q[8];
168  int i, numtr;
169  static wordlist *oldwl;
170  static char oldq[8];
171  struct gplot *graf;
172  GRAPH *graph;
173 
174  *q = '\0';
175  if (wl) {
176  s = wl->wl_word;
177  if (*s == '-' && alpha_only(s+1)) {
178  strncpy(q,s+1,7);
179  q[7] = '\0';
180  strcpy(oldq,q);
181  wl = wl->wl_next;
182  }
183  }
184  if (!wl && !oldwl) {
185  fprintf(cp_err, "Error: no vectors given\n");
186  return;
187  }
188  if (wl) {
189  if (oldwl) wl_free(oldwl);
190  oldwl = wl_copy(wl);
191  }
192  else {
193  wl = oldwl;
194  strcpy(q,oldq);
195  }
196  wl->wl_prev = NULL;
197  if ((names = ft_getpnames(wl, false)) == NULL)
198  return;
199  if ((dl0 = ft_dvlist(names)) == NULL)
200  return;
201 
202  /* Now check for vectors we can't handle. */
203  for (dl = dl0; dl; dl = dl->dl_next) {
204  if (dl->dl_dvec->v_length < 2) {
205  fprintf(cp_err, "Error: %s: too few points to plot\n",
206  dl->dl_dvec->v_name);
207  vec_dlfree(dl0);
208  return;
209  }
210  }
211 
212  scale = dl0->dl_dvec->v_plot->pl_scale;
213  if (!scale)
214  scale = dl0->dl_dvec->v_scale;
215  if (!scale)
216  scale = dl0->dl_dvec;
217 
218  if (!is_monotonic(scale)) {
219  fprintf(cp_err,errmsg_scale);
220  vec_dlfree(dl0);
221  return;
222  }
223 
224  /* If we are plotting scalars, make sure there is enough
225  * data to fit on the screen.
226  * Fill in the scales for vectors who aren't already fixed up.
227  */
228  numtr = 0;
229  for (dl = dl0; dl; dl = dl->dl_next) {
230  d = dl->dl_dvec;
231  numtr++;
232  d->v_scale = scale;
233  if (d->v_length != d->v_scale->v_length)
234  plot_extend(d, d->v_scale->v_length);
235  }
236 
237  if (numtr > PNUM) {
238  fprintf(cp_err,"Error: more than %d traces\n",PNUM);
239  vec_dlfree(dl0);
240  return;
241  }
242 
243  graf = (struct gplot *) tmalloc(sizeof(struct gplot));
244  graf->scale = (struct gscale *) tmalloc(sizeof(struct gscale));
245  graf->plot = dl0->dl_dvec->v_plot;
246  graf->plot->pl_active++;
247  graf->numtr = numtr;
248  graf->numpt = NUMOUTPTS;
249 
250  for (dl = dl0, i = 0; dl; dl = dl->dl_next) {
251  d = dl->dl_dvec;
252  strncpy(graf->tdata[i].name,d->v_name,FIELD+1);
253  graf->tdata[i].name[FIELD+1] = '\0';
254 
255  if (ciprefix("i",graf->tdata[i].name) ||
256  strchr(graf->tdata[i].name,'#'))
257  graf->tdata[i].type = GRAF_I;
258  else if (ciprefix("v",graf->tdata[i].name))
259  graf->tdata[i].type = GRAF_V;
260  else
261  graf->tdata[i].type = GRAF_O;
262  interpolateY(graf,i,d);
263  i++;
264  }
265  interpolateX(graf,dl0->dl_dvec);
266 
267  vec_dlfree(dl0);
268 
269  Running = true;
270  graf->iniplot = false;
271  proc_option(graf,q);
272 
273  if (!(graph = NewGraph())) {
274  fprintf(cp_err, errmsg_gralloc);
275  free_graf((GRDATA)graf);
276  return;
277  }
278 
279  graph->graphtype = GR_GRAF;
280  graph->plotdata = (GRDATA)graf;
281  graph->destroy = free_graf;
282  graph->copydata = copygraf;
283  graph->redraw = graf_display;
284 
285  if (graf->opt & OPT_hcpy) {
286  graf->opt &= ~OPT_hcpy;
287  graf->opt &= ~OPT_help;
288  graf->opt &= ~OPT_add;
289  graf->opt &= ~OPT_mark;
290  graf->opt &= ~OPT_Xx;
291  graf->opt &= ~OPT_X;
292  graf->opt &= ~OPT_x;
293  ft_hardcopy(NULL,graph,false,NULL,false);
294  return;
295  }
296 
297  if (DevNewViewport(graph)) {
298  fprintf(cp_err, errmsg_newvp);
299  DestroyGraph(graph->graphid);
300  return;
301  }
302 
303  if (!dispdev->windows) {
304 
305  PushGraphContext(graph);
306  while (Running) {
307  graf_display(graph);
308  if (dispdev->hardcopy)
309  break;
310  what_now(q);
311  proc_option(graf,q);
312  }
313  DevHalt();
314  PopGraphContext();
315  DestroyGraph(graph->graphid);
316  }
317 }
318 
319 
320 static bool
322 
323 struct dvec *v;
324 {
325  bool inc;
326  int i, len;
327 
328  if (v->v_numdims > 1)
329  len = v->v_dims[v->v_numdims - 1];
330  else
331  len = v->v_length;
332 
333  if (isreal(v)) {
334  inc = v->v_realdata[0] < v->v_realdata[1];
335  if (!inc)
336  return (false);
337  for (i = 2; i < len; i++) {
338  if (inc != (v->v_realdata[i-1] < v->v_realdata[i]))
339  return (false);
340  }
341  }
342  else {
343  inc = realpart(&v->v_compdata[0]) < realpart(&v->v_compdata[1]);
344  if (!inc)
345  return (false);
346  for (i = 2; i < len; i++) {
347  if (inc != (realpart(&v->v_compdata[i-1]) <
348  realpart(&v->v_compdata[i])))
349  return (false);
350  }
351  }
352  return (true);
353 }
354 
355 
356 static void
357 free_graf(grafp)
358 
359 GRDATA grafp;
360 {
361  struct gplot *graf = (struct gplot *)grafp;
362  struct dvlist *dl;
363 
364  tfree(graf->scale);
365  while (graf->numtr--)
366  tfree(graf->tdata[graf->numtr].data);
367  tfree(graf->xdata);
368 
369  /* This is non-null only if we killed an iplot
370  * before it finished.
371  */
372  for (dl = graf->dlist; dl; dl = graf->dlist) {
373  graf->dlist = dl->dl_next;
374  txfree((char*)dl);
375  }
376  if (graf->plot)
377  graf->plot->pl_active--;
378 
379  tfree(graf);
380 }
381 
382 
383 static GRDATA
384 copygraf(grafp)
385 
386 /* copy a gplot structure */
387 GRDATA grafp;
388 {
389  struct gplot *graf = (struct gplot *)grafp;
390  struct gplot *newgraf;
391  int i, size, size1;
392 
393  newgraf = (struct gplot *) tmalloc(sizeof(struct gplot));
394  newgraf->numtr = graf->numtr;
395  newgraf->numpt = graf->numpt;
396  newgraf->opt = graf->opt;
397  newgraf->scale = (struct gscale *) tmalloc(sizeof(struct gscale));
398  *newgraf->scale = *graf->scale;
399  newgraf->plot = graf->plot;
400  newgraf->plot->pl_active++;
401  size = graf->numpt*sizeof(float);
402  newgraf->xdata = (float *) tmalloc(size);
403  memcpy(newgraf->xdata,graf->xdata,size);
404 
405  for (i = 0; i < graf->numtr; i++) {
406  newgraf->tdata[i] = graf->tdata[i];
407  size1 = size * graf->tdata[i].cycles;
408  newgraf->tdata[i].data = (float *) tmalloc(size1);
409  memcpy(newgraf->tdata[i].data,graf->tdata[i].data,size1);
410  }
411 
412  return ((GRDATA)newgraf);
413 }
414 
415 
416 static void
418 
419 struct screen *scr;
420 {
421  int fwidth, fheight, edge;
422  int oldXL, oldYL, oldX, oldY;
423  struct _keyed *k;
424 
425  oldXL = scr->XL;
426  oldYL = scr->YL;
427  oldX = scr->X;
428  oldY = scr->Y;
429 
430  fheight = currentgraph->fontheight;
431  fwidth = currentgraph->fontwidth;
432 #ifdef HAVE_X11
433  edge = 2*fwidth;
434 #else
435  edge = 0;
436 #endif
437  scr->W = fwidth;
438  scr->H = fheight;
439  scr->W2 = fwidth/2;
440  scr->H2 = fheight/2;
441  scr->H3 = scr->H + scr->H2;
442  scr->XL = 14*fwidth + edge;
443  scr->YL = 3*fheight + edge;
444  scr->XS = currentgraph->absolute.width;
445  scr->YS = currentgraph->absolute.height;
446  scr->X = scr->XS - scr->XL - 2*fwidth - edge;
447  scr->Y = scr->YS - scr->YL - 3*fheight - edge;
448  scr->XC = scr->XL + scr->X/2;
449  scr->YC = scr->YL + scr->Y/2;
450  scr->XU = scr->XL + scr->X;
451  scr->YU = scr->YL + scr->Y;
452 
453  if (oldX && oldY) {
454  for (k = currentgraph->keyed; k; k = k->next) {
455  k->x = (k->x - oldXL)*((double)scr->X)/oldX + scr->XL;
456  k->y = (k->y - oldYL)*((double)scr->Y)/oldY + scr->YL;
457  }
458  }
459 }
460 
461 
462 static void
464 
465 GRAPH *graph;
466 {
467  struct gplot *graf = (struct gplot *)graph->plotdata;
468  struct _keyed *k;
469 
470  if (graf == NULL || graph->graphtype != GR_GRAF)
471  return;
472  PushGraphContext(graph);
473  init_viewport(&graf->scr);
474 
475  if (!(graf->opt & OPT_mark)) {
476  DevSetGhost(NULL,0,0);
477  }
478  graf->ref.set = false;
479 
480  if (graf->opt & OPT_help) {
481  help(graf);
482  if (!dispdev->windows)
483  graf->opt &= ~OPT_help;
484  goto quit;
485  }
486 
487  if (graf->opt & OPT_add) {
488  addplot(graf);
489  graf->opt &= ~OPT_add;
490  goto quit;
491  }
492 
493  if (graf->opt & OPT_hcpy) {
494  graf->opt &= ~OPT_hcpy;
495  ft_hardcopy(NULL,graph,true,NULL,false);
496  goto quit;
497  }
498 
499  if (graf->opt & OPT_Xx) {
500  /* never used in X */
501  if (newscale(graf))
502  goto quit;
503  graf->opt &= ~OPT_Xx;
504  }
505  displ(graf);
506  for (k = graph->keyed; k; k = k->next) {
507  DevSetColor(k->colorindex);
508  DevText(k->text, k->x, k->y);
509  }
510 
511  if (graf->opt & OPT_mark) {
512  fpick(graph);
513  }
514 
515 quit:
516  PopGraphContext();
517  return;
518 }
519 
520 
521 static int
523 char *s;
524 {
525  while (*s) {
526  if (!isalpha(*s)) return 0;
527  s++;
528  }
529  return 1;
530 }
531 
532 int
533 iplot_begin(dl0,pl)
534 
535 /* Initiate an interactive plot, return the graphid. */
536 struct dvlist *dl0;
537 struct plot *pl;
538 {
539  int i;
540  struct gplot *graf;
541  struct dvlist *dl;
542  GRAPH *graph;
543 
544  graf = (struct gplot *) tmalloc(sizeof(struct gplot));
545  graf->scale = (struct gscale *) tmalloc(sizeof(struct gscale));
546 
547  graf->iniplot = false; /* for initial draw */
548  graf->plot = pl;
549  pl->pl_active++;
550  graf->dlist = dl0;
551  graf->numpt = NUMOUTPTS;
552 
553  if (is_monotonic(pl->pl_scale)) {
554  for (dl = dl0, i = 0; dl; dl = dl->dl_next, i++) {
555  strncpy(graf->tdata[i].name,dl->dl_dvec->v_name,FIELD+1);
556  graf->tdata[i].name[FIELD+1] = '\0';
557  interpolateY(graf,i,dl->dl_dvec);
558  }
559  graf->numtr = i;
560  interpolateX(graf,pl->pl_scale);
561  }
562 
563  /* set option t */
564  graf->opt |= OPT_t;
565 
566  if (!(graph = NewGraph())) {
567  fprintf(cp_err,errmsg_gralloc);
568  free_graf((GRDATA)graf);
569  return (0);
570  }
571 
572  graph->graphtype = GR_GRAF;
573  graph->plotdata = (GRDATA)graf;
574  graph->destroy = free_graf;
575  graph->copydata = copygraf;
576  graph->redraw = graf_display;
577 
578  /* can call DestroyGraph() here without messing up debug list */
579  if (!is_monotonic(pl->pl_scale)) {
580  fprintf(cp_err,errmsg_scale);
581  DestroyGraph(graph->graphid);
582  return (0);
583  }
584  if (DevNewViewport(graph)) {
585  fprintf(cp_err,errmsg_newvp);
586  DestroyGraph(graph->graphid);
587  return (0);
588  }
589 
590  if (!dispdev->windows) {
591  PushGraphContext(graph);
592  init_viewport(&graf->scr);
593  displ(graf);
594  PopGraphContext();
595  }
596 
597  return (graph->graphid);
598 }
599 
600 
601 bool
603 
604 /* Update the interactive plot. */
605 {
606  struct dvlist *dl0, *dl;
607  struct dvec *d, *xs;
608  int i, k, l, n;
609  bool newdim;
610  double *ah, *al, xx, xl, yy, dy, amx, amn;
611  struct gplot *graf = (struct gplot *)currentgraph->plotdata;
612 
613  if (graf == NULL || currentgraph->graphtype != GR_GRAF)
614  return (true);
615 
616  xs = graf->plot->pl_scale;
617  if (isreal(xs)) {
618  xx = xs->v_realdata[xs->v_length-1];
619  xl = xs->v_realdata[xs->v_length-2];
620  }
621  else {
622  xx = realpart(&xs->v_compdata[xs->v_length-1]);
623  xl = realpart(&xs->v_compdata[xs->v_length-2]);
624  }
625  if (xx < xl)
626  newdim = true;
627  else
628  newdim = false;
629 
630  if (xs->v_numdims <= 1 && newdim) {
631  /* error, free the dvlist, not the dvecs! */
632  for (dl = graf->dlist; dl; dl = dl0) {
633  dl0 = dl->dl_next;
634  txfree((char*)dl);
635  }
636  graf->dlist = NULL;
637  graf->iniplot = false;
638  DevSetColor(8);
639  DevText("Monotonicity error, partial plot",graf->scr.XU,
640  graf->scr.YL - 3*graf->scr.H);
641  return (true);
642  }
643  if (graf->scale->lflg)
644  xx = log10(xx);
645 
646  init_viewport(&graf->scr);
647  dl0 = graf->dlist;
648  if (xx > graf->scale->xcurr.max +
649  .001*(graf->scale->xcurr.max - graf->scale->xcurr.min)) goto redraw;
650 
651  for (dl = dl0, i = 0; dl; dl = dl->dl_next, i++) {
652 
653  d = dl->dl_dvec;
654  if (isreal(d))
655  yy = d->v_realdata[d->v_length-1];
656  else
657  yy = realpart(&d->v_compdata[d->v_length-1]);
658 
659  dy = .001*(graf->tdata[i].scale[1] - graf->tdata[i].scale[0]);
660  if (yy > graf->tdata[i].scale[1] + dy ||
661  yy < graf->tdata[i].scale[0] - dy) goto redraw;
662  }
663 
664  ah = graf->scale->ymax;
665  al = graf->scale->ymin;
666  n = graf->numtr;
667 
668  k = graf->scr.X*(xx - graf->scale->xcurr.min) /
669  (graf->scale->xcurr.max - graf->scale->xcurr.min);
670 
671  for (dl = dl0, i = 0; dl; dl = dl->dl_next, i++) {
672 
673  d = dl->dl_dvec;
674  amx = ((ah[i]+al[i])+(ah[i]-al[i])*(2*i+1))/2;
675  amn = ((ah[i]+al[i])-(ah[i]-al[i])*(2*(n-i)-1))/2;
676  if (amx == amn)
677  continue;
678 
679  if (isreal(d))
680  yy = d->v_realdata[d->v_length-1];
681  else
682  yy = realpart(&d->v_compdata[d->v_length-1]);
683 
684  l = (int) (.5 + graf->scr.Y*(yy - amn)/(amx - amn));
685  if (!newdim) {
686  DevSetColor(i+2);
687  DevLine(graf->lastx,graf->tdata[i].lasty,
688  graf->scr.XL + k,graf->scr.YL + l);
689  }
690  graf->tdata[i].lasty = graf->scr.YL + l;
691  }
692  graf->lastx = graf->scr.XL + k;
693  return (false);
694 
695 redraw:
696  graf->iniplot = true;
697  for (dl = dl0, i = 0; dl; dl = dl->dl_next, i++) {
698  interpolateY(graf,i,dl->dl_dvec);
699  }
700  interpolateX(graf,xs);
701  DevSetColor(0);
702  DevBox(0,0,graf->scr.XU,graf->scr.YU);
703  displ(graf);
704  return (false);
705 }
706 
707 
708 void
710 
711 /* Terminate interactive plot. */
712 {
713  int i;
714  char q[8];
715  struct gplot *graf = (struct gplot *)currentgraph->plotdata;
716  struct dvlist *dl, *dl0;
717  struct dvec *scale;
718 
719  if (graf == NULL || currentgraph->graphtype != GR_GRAF)
720  return;
721 
722  dl0 = graf->dlist;
723  if (dl0) {
724  scale = graf->plot->pl_scale;
725 
726  for (dl = dl0, i = 0; dl; dl = dl->dl_next, i++) {
727  interpolateY(graf,i,dl->dl_dvec);
728  }
729  interpolateX(graf,graf->plot->pl_scale);
730 
731  /* free the dvlist, not the dvecs! */
732  for (dl = dl0; dl; dl = dl0) {
733  dl0 = dl->dl_next;
734  txfree((char*)dl);
735  }
736  graf->dlist = NULL;
737  }
738 
739  DevClear();
740  Running = true;
741  graf->iniplot = false;
742 
743  for (i = 0; Running; ) {
745  if (dispdev->windows || dispdev->hardcopy)
746  break;
747  what_now(q);
748  if (i == 0 && *q == '\0') break;
749  i = 1;
750  proc_option(graf,q);
751  }
752 }
753 
754 
755 static void
757 
758 char *q;
759 {
760  int x0,y0,x1,y1,xr0,xr1;
761  struct gplot *graf = (struct gplot *)currentgraph->plotdata;
762  char *qq;
763 
764  /* box to erase */
765  x0 = graf->scr.XU - 33*graf->scr.W;
766  y0 = graf->scr.YL - 3*graf->scr.H;
767  x1 = graf->scr.XS;
768  y1 = graf->scr.YL - 2*graf->scr.H;
769 
770  /* response box */
771  xr0 = graf->scr.XU - 8*graf->scr.W;
772  xr1 = graf->scr.XU;
773 
774  DevSetColor(0);
775  DevBox(x0,y0,x1,y1);
776 
777  DevSetColor(11);
778  DevBox(xr0,y0,xr1,y1);
779 
780  DevSetColor(8);
781  DevText("What now? (h for help) :",x0,y0);
782  qq = KbEdit(NULL,xr0,y0,11,1,13);
783  if (qq) {
784  strncpy(q,qq,7);
785  q[7] = '\0';
786  }
787  else {
788  /* quit if ESC entered */
789  q[0] = 'q';
790  q[1] = '\0';
791  }
792  DevSetColor(0);
793  DevBox(x0,y0,x1,y1);
794 }
795 
796 
797 #ifdef HAVE_X11
798 
799 /* These are called from X handlers */
800 
801 void
802 graf_newdisplay(graph,xl,xh)
803 
804 /* launch a new graf window with magnified scale */
805 GRAPH *graph;
806 int xl, xh; /* scale endpoints (screen coords) */
807 {
808  struct gplot *graf, *oldgraf;
809  double dxl, dxh, dxt;
810  GRAPH *newgraph;
811 
812  if (graph->graphtype != GR_GRAF)
813  return;
814 
815  oldgraf = (struct gplot *)graph->plotdata;
816 
817  if (interval(oldgraf,xl,xh,&dxl,&dxh))
818  return;
819 
820  if (dxh < dxl) {
821  dxt = dxh;
822  dxh = dxl;
823  dxl = dxt;
824  }
825 
826  if (dxl < oldgraf->scale->xfull.beg)
827  dxl = oldgraf->scale->xfull.beg;
828  else if (dxl >= oldgraf->scale->xfull.end)
829  return;
830 
831  if (dxh > oldgraf->scale->xfull.end)
832  dxh = oldgraf->scale->xfull.end;
833  else if (dxh <= oldgraf->scale->xfull.beg)
834  return;
835 
836  graf = (struct gplot*)copygraf((GRDATA)oldgraf);
837  graf->opt |= OPT_x;
838 
839  graf->scale->xcurr.beg = dxl;
840  graf->scale->xcurr.end = dxh;
841  if (graf->scale->lflg) {
842  graf->scale->xcurr.min = floor(graf->scale->xcurr.beg);
843  graf->scale->xcurr.max = ceil(graf->scale->xcurr.end);
844  graf->scale->ncells = graf->scale->xcurr.max -
845  graf->scale->xcurr.min;
846  }
847  else
848  set_scale(graf->scale->xcurr.beg,graf->scale->xcurr.end,
849  &graf->scale->xcurr.min,&graf->scale->xcurr.max,
850  &graf->scale->ncells);
851 
852  if (!(newgraph = NewGraph())) {
853  fprintf(cp_err, errmsg_gralloc);
854  free_graf((GRDATA)graf);
855  return;
856  }
857 
858  newgraph->graphtype = GR_GRAF;
859  newgraph->plotdata = (GRDATA)graf;
860  newgraph->destroy = free_graf;
861  newgraph->copydata = copygraf;
862  newgraph->redraw = graf_display;
863 
864  if (DevNewViewport(newgraph)) {
865  fprintf(cp_err, errmsg_newvp);
866  DestroyGraph(newgraph->graphid);
867  }
868 }
869 
870 
871 /* ARGSUSED */
872 void
873 graf_slopelocation(graph,x0,y0,x1,y1)
874 
875 /* print out the selected (on screen) scale points */
876 GRAPH *graph;
877 int x0, y0, x1, y1;
878 {
879  double dxl, dxh;
880 
881  if (graph->graphtype != GR_GRAF)
882  return;
884  graf_setmark((struct gplot *)graph->plotdata,x0);
885  PopGraphContext();
886 }
887 
888 
889 static int
890 interval(graf,xl,xh,dxl,dxh)
891 
892 /* convert the screen interval endpoints to scale data values */
893 struct gplot *graf;
894 int xl, xh;
895 double *dxl, *dxh;
896 {
897  int xt, swap = false;
898  double d0, d1;
899 
900  if (xh < xl) {
901  xt = xh;
902  xh = xl;
903  xl = xt;
904  swap = true;
905  }
906  if (xh <= graf->scr.XL || xl >= graf->scr.XU)
907  return (1);
908  if (xl < graf->scr.XL)
909  xl = graf->scr.XL;
910  if (xh > graf->scr.XU)
911  xh = graf->scr.XU;
912 
913  d0 = graf->scale->xcurr.min +
914  (xl - graf->scr.XL)*
915  (graf->scale->xcurr.max - graf->scale->xcurr.min)/graf->scr.X;
916 
917  d1 = graf->scale->xcurr.min +
918  (xh - graf->scr.XL)*
919  (graf->scale->xcurr.max - graf->scale->xcurr.min)/graf->scr.X;
920 
921  if (swap) {
922  *dxl = d1;
923  *dxh = d0;
924  }
925  else {
926  *dxl = d0;
927  *dxh = d1;
928  }
929  return (0);
930 }
931 
932 #endif
933 
934 
935 static void
937 
938 /* Linearize scale. */
939 struct gplot *graf;
940 struct dvec *d;
941 {
942  double xl, xu, dx;
943  float *v;
944  int i, len;
945  struct dvec *xs = graf->plot->pl_scale;
946 
947  if (xs->v_numdims > 1)
948  len = xs->v_dims[xs->v_numdims-1];
949  else
950  len = xs->v_length;
951 
952  if (isreal(xs)) {
953  xl = *(xs->v_realdata);
954  xu = *(xs->v_realdata + len - 1);
955  dx = (xu - xl)/(graf->numpt-1);
956  }
957  else {
958  xl = realpart(&xs->v_compdata[0]);
959  xu = realpart(&xs->v_compdata[len - 1]);
960  dx = (xu - xl)/(graf->numpt-1);
961  }
962  txfree((char*)graf->xdata);
963  graf->xdata = (float *) tmalloc(graf->numpt*sizeof(float));
964  v = graf->xdata;
965  for (i = 0; i < graf->numpt; i++) {
966  *(v++) = (float) xl;
967  xl += dx;
968  }
969  graf->scale->xfull.beg = *graf->xdata;
970  graf->scale->xfull.end = *(graf->xdata + graf->numpt - 1);
971  if (graf->scale->lflg) {
972  graf->scale->xfull.beg = log10(graf->scale->xfull.beg);
973  graf->scale->xfull.end = log10(graf->scale->xfull.end);
974  graf->scale->xfull.min = floor(graf->scale->xfull.beg);
975  graf->scale->xfull.max = ceil(graf->scale->xfull.end);
976  graf->scale->ncells = graf->scale->xfull.max -
977  graf->scale->xfull.min;
978  }
979  else {
980  set_scale(graf->scale->xfull.beg,graf->scale->xfull.end,
981  &graf->scale->xfull.min,&graf->scale->xfull.max,
982  &graf->scale->ncells);
983  }
984  graf->scale->xcurr = graf->scale->xfull;
985 }
986 
987 
988 static void
989 interpolateY(graf,ind,d)
990 
991 /* Linearize data. */
992 struct gplot *graf;
993 int ind;
994 struct dvec *d;
995 {
996  double xl, xu, ymax, ymin, dx, xi, xj, yi, yj, xl0;
997  double *xd, *yd;
998  complex *xc, *yc;
999  float *v;
1000  int i, j, len, cy, extra, ird, irs;
1001  struct dvec *xs = graf->plot->pl_scale;
1002 
1003  if (xs->v_numdims > 1)
1004  len = xs->v_dims[xs->v_numdims-1];
1005  else
1006  len = xs->v_length;
1007 
1008  if (isreal(xs)) {
1009  xl = *(xs->v_realdata);
1010  xu = *(xs->v_realdata + len - 1);
1011  dx = (xu - xl)/(graf->numpt-1);
1012  }
1013  else {
1014  xl = realpart(&xs->v_compdata[0]);
1015  xu = realpart(&xs->v_compdata[len - 1]);
1016  dx = (xu - xl)/(graf->numpt-1);
1017  }
1018  if (ciprefix("freq",xs->v_name)
1019  && xl > 0 && fabs(xu/xl) > LOGTST) {
1020  xu = log10(xu); /* rescale x factors */
1021  xl = log10(xl); /* for log plot */
1022  dx = (xu - xl)/(graf->numpt-1);
1023  graf->scale->lflg = 1;
1024  }
1025 
1026  if (xs->v_numdims > 1) {
1027 
1028  /* how many dimensions hath d? (length = scale) */
1029  for (j = 1, i = 0; i < d->v_numdims - 1; i++)
1030  j *= d->v_dims[i];
1031 
1032  graf->tdata[ind].cycles = j;
1033  extra = xs->v_length % len;
1034  if (extra)
1035  (graf->tdata[ind].cycles)++;
1036  else
1037  graf->tdata[ind].extra = 0;
1038  }
1039  else {
1040  graf->tdata[ind].cycles = 1;
1041  extra = 0;
1042  graf->tdata[ind].extra = 0;
1043  }
1044 
1045  txfree((char*)graf->tdata[ind].data);
1046  graf->tdata[ind].data =
1047  (float *) tmalloc(graf->numpt*graf->tdata[ind].cycles*sizeof(float));
1048  v = graf->tdata[ind].data;
1049 
1050  ird = isreal(d);
1051  irs = isreal(xs);
1052  xl0 = xl;
1053  xd = xs->v_realdata;
1054  xc = xs->v_compdata;
1055  yd = d->v_realdata;
1056  yc = d->v_compdata;
1057  ymin = ymax = ird ? *yd : realpart(&yc[0]);
1058  cy = graf->tdata[ind].cycles;
1059  while (cy--) {
1060  xi = xl = xl0;
1061  yi = ird ? *yd : realpart(&yc[0]);
1062 
1063  if (!cy && extra)
1064  len = extra;
1065 
1066  j = 0;
1067  for (i = 1; i < len; i++) {
1068  xj = irs ? *(xd + i) : realpart(&xc[i]);
1069  if (graf->scale->lflg) {
1070  xj = log10(xj);
1071  }
1072 
1073  yj = ird ? *(yd + i) : realpart(&yc[i]);
1074  if (yj > ymax) ymax = yj;
1075  if (yj < ymin) ymin = yj;
1076 
1077  if (graf->opt & OPT_step) {
1078  while (xl < xj && j < graf->numpt) {
1079  *(v++) = yi;
1080  xl += dx;
1081  j++;
1082  }
1083  }
1084  else {
1085  while (xl < xj && j < graf->numpt) {
1086  *(v++) =
1087  (float) (yi + (yj - yi)*(xl - xi)/(xj - xi));
1088  xl += dx;
1089  j++;
1090  }
1091  }
1092  xi = xj;
1093  yi = yj;
1094  }
1095  if (!cy && extra) {
1096  graf->tdata[ind].extra = j;
1097  break;
1098  }
1099  while (j < graf->numpt) {
1100  *(v++) = (float) yj;
1101  j++;
1102  }
1103  if (irs)
1104  xd += len;
1105  else
1106  xc += len;
1107  if (ird)
1108  yd += len;
1109  else
1110  yc += len;
1111  }
1112 
1113  set_scale_4(ymin,ymax,graf->tdata[ind].scale,
1114  graf->tdata[ind].scale+1);
1115 }
1116 
1117 
1118 static void
1120 
1121 /* Set option flags. */
1122 struct gplot *graf;
1123 char *q;
1124 {
1125 #ifndef HAVE_X11
1126  if (strchr(q,'h')) graf->opt |= OPT_help;
1127  if (strchr(q,'q')) {
1128  /* does nothing in X */
1129  Running = false;
1130  }
1131  if (strchr(q,'P')) graf->opt |= OPT_hcpy;
1132  if (strchr(q,'a')) graf->opt |= OPT_add;
1133  if (strchr(q,'c')) graf->opt |= OPT_mark;
1134 #endif
1135  if (strchr(q,'n')) {
1136  graf->opt |= OPT_n;
1137  graf->opt &= ~OPT_N;
1138  }
1139  if (strchr(q,'N')) {
1140  graf->opt |= OPT_N;
1141  graf->opt &= ~OPT_n;
1142  }
1143  if (strchr(q,'y')) graf->opt &= ~(OPT_n|OPT_N);
1144 
1145  if (!dispdev->windows) {
1146  if (strchr(q,'x')) {
1147  graf->opt |= OPT_x;
1148  graf->opt &= ~OPT_X;
1149  graf->opt |= OPT_Xx;
1150  }
1151  if (strchr(q,'X')) {
1152  graf->opt |= OPT_X;
1153  graf->opt &= ~OPT_x;
1154  graf->opt |= OPT_Xx;
1155  }
1156  }
1157 
1158  if (graf->numtr > 1) {
1159  if (strchr(q,'b')) graf->opt ^= OPT_b;
1160  if (strchr(q,'t')) graf->opt ^= OPT_t;
1161  }
1162  if (strchr(q,'p')) graf->opt ^= OPT_p;
1163  if (strchr(q,'s')) graf->opt ^= OPT_step;
1164 }
1165 
1166 
1167 static void
1168 displ(graf)
1169 
1170 /* Display the data. */
1171 struct gplot *graf;
1172 {
1173  double fl, fh, *al, *ah, full_scale[2];
1174  int ny = 4;
1175  int i, n, m;
1176  int cflgs[3]; /* existence flags, v,i,other */
1177  int spa, dely;
1178 
1179  m = graf->numpt;
1180  n = graf->numtr;
1181  al = graf->scale->ymin;
1182  ah = graf->scale->ymax;
1183 
1184  graf->scale->numpts =
1185  (int) (m*(graf->scale->xcurr.end - graf->scale->xcurr.beg)/
1186  (graf->scale->xfull.end - graf->scale->xfull.beg) + .5);
1187  graf->scale->strtpt =
1188  (int) (m*(graf->scale->xcurr.beg - graf->scale->xfull.beg)/
1189  (graf->scale->xfull.end - graf->scale->xfull.beg) + .5);
1190 
1191  if (graf->opt & OPT_x) {
1192  minmax(graf,cflgs);
1193  for (i = 0; i < n; i++)
1194  set_scale_4(al[i],ah[i],al+i,ah+i);
1195  }
1196  else {
1197  cflgs[0] = cflgs[1] = cflgs[2] = 0;
1198  al[n] = al[n+1] = al[n+2] = al[n+3] = 1;
1199  ah[n] = ah[n+1] = ah[n+2] = ah[n+3] = -1;
1200  for (i = 0; i < n; i++) {
1201  al[i] = fl = *graf->tdata[i].scale;
1202  ah[i] = fh = *(graf->tdata[i].scale + 1);
1203  if (al[n] > ah[n]) {
1204  al[n] = fl;
1205  ah[n] = fh;
1206  }
1207  else {
1208  if (fl < al[n]) al[n] = fl;
1209  if (fh > ah[n]) ah[n] = fh;
1210  }
1211  switch (graf->tdata[i].type) {
1212  case GRAF_V:
1213  if (al[n+1] > ah[n+1]) {
1214  al[n+1] = fl;
1215  ah[n+1] = fh;
1216  }
1217  else {
1218  if (fl < al[n+1]) al[n+1] = fl;
1219  if (fh > ah[n+1]) ah[n+1] = fh;
1220  }
1221  cflgs[0] = 1;
1222  break;
1223  case GRAF_I:
1224  if (al[n+2] > ah[n+2]) {
1225  al[n+2] = fl;
1226  ah[n+2] = fh;
1227  }
1228  else {
1229  if (fl < al[n+2]) al[n+2] = fl;
1230  if (fh > ah[n+2]) ah[n+2] = fh;
1231  }
1232  cflgs[1] = 1;
1233  break;
1234  default:
1235  if (al[n+3] > ah[n+3]) {
1236  al[n+3] = fl;
1237  ah[n+3] = fh;
1238  }
1239  else {
1240  if (fl < al[n+3]) al[n+3] = fl;
1241  if (fh > ah[n+3]) ah[n+3] = fh;
1242  }
1243  cflgs[2] = 1;
1244  }
1245  }
1246  }
1247 
1248  if (graf->opt & OPT_b) {
1249  displxy(graf);
1250  return;
1251  }
1252 
1253  if (cflgs[0]) { set_scale_4(al[n+1],ah[n+1],al+n+1,ah+n+1); }
1254  if (cflgs[1]) { set_scale_4(al[n+2],ah[n+2],al+n+2,ah+n+2); }
1255  if (cflgs[2]) { set_scale_4(al[n+3],ah[n+3],al+n+3,ah+n+3); }
1256  if (graf->opt & OPT_N) set_scale(al[n],ah[n],al+n,ah+n,&ny);
1257 
1258  axes(graf,graf->scale->ncells, ((graf->opt & OPT_t) && n > 1) ? n : ny);
1259  dely = 3*graf->scr.H + graf->scr.H2;
1260  if (graf->opt & OPT_t) {
1261  if (n)
1262  spa = graf->scr.Y/n;
1263  else
1264  spa = graf->scr.Y;
1265  if (spa < dely)
1266  spa = dely;
1267  }
1268  else
1269  spa = dely;
1270  dely -= graf->scr.H2/2;
1271  for (i = 0; i < n; i++) {
1272  int ix;
1273  double amx, amn;
1274  int scrx = graf->scr.XL - 13*graf->scr.W - graf->scr.W2;
1275 
1276  DevSetColor(1);
1277  DevText(graf->tdata[i].name,scrx,
1278  graf->scr.YU - i*spa - graf->scr.H - 2);
1279  if (graf->opt & OPT_N)
1280  ix = n;
1281  else if (graf->opt & OPT_n) {
1282  if (graf->tdata[i].type == GRAF_V)
1283  ix = n+1;
1284  else if (graf->tdata[i].type == GRAF_I)
1285  ix = n+2;
1286  else
1287  ix = n+3;
1288  }
1289  else
1290  ix = i;
1291  if (!(graf->opt & OPT_mark)) {
1292  if (!(graf->opt & OPT_N) || i == 0) {
1293  writef(ah[ix], scrx,
1294  graf->scr.YU - i*spa - 2*graf->scr.H - 2);
1295  writef(al[ix], scrx,
1296  graf->scr.YU - i*spa - 3*graf->scr.H - 2);
1297  }
1298  }
1299  amx = ((graf->opt & OPT_t) && n > 1) ?
1300  ((ah[ix]+al[ix])+(ah[ix]-al[ix])*(2*i+1))/2 : ah[ix];
1301  amn = ((graf->opt & OPT_t) && n > 1) ?
1302  ((ah[ix]+al[ix])-(ah[ix]-al[ix])*(2*(n-i)-1))/2 : al[ix];
1303  DevSetColor(i+2);
1304  if (dispdev->numcolors == 2 && !(graf->opt & OPT_p) &&
1305  !(graf->opt & OPT_t))
1306  DevSetLinestyle(i);
1307  ebox(scrx - graf->scr.W2, graf->scr.YU - i*spa - dely,
1308  scrx - graf->scr.W2 + 13*graf->scr.W, graf->scr.YU - i*spa);
1309  draw(graf,i,amn,amx);
1310  if (dispdev->numcolors == 2 && !(graf->opt & OPT_p) &&
1311  !(graf->opt & OPT_t))
1312  DevSetLinestyle(0);
1313  }
1314  DevSetColor(1);
1315  if (!graf->iniplot)
1316  DevText(graf->plot->pl_title,
1317  graf->scr.XL,graf->scr.YU + graf->scr.H3);
1318  strcpy(INBUF,graf->plot->pl_scale->v_name);
1319  if (graf->scale->lflg) strcat(INBUF," (log)");
1320  DevText(INBUF,graf->scr.XC - ((int)strlen(INBUF)*graf->scr.W)/2,
1321  graf->scr.YL - graf->scr.H3);
1322  writeg(graf->scale->xcurr.min,
1323  graf->scr.XL,graf->scr.YL - graf->scr.H - 1,'l');
1324  writeg(graf->scale->xcurr.max,
1325  graf->scr.XU,graf->scr.YL - graf->scr.H - 1,'r');
1326  DevSetColor(8);
1327  if (!graf->iniplot) {
1328  DevText(graf->plot->pl_name,graf->scr.XL,graf->scr.YU + graf->scr.H2);
1329  if (graf->scr.X > ((int)strlen(graf->plot->pl_name) +
1330  (int)strlen(graf->plot->pl_date))*graf->scr.W)
1331  DevText(graf->plot->pl_date,
1332  graf->scr.XU - (int)strlen(graf->plot->pl_date)*graf->scr.W,
1333  graf->scr.YU + graf->scr.H2);
1334  }
1335 }
1336 
1337 
1338 static int
1340 
1341 struct gplot *graf;
1342 {
1343  char s[128], *c;
1344  int j;
1345 
1346  DevClear();
1347  DevSetColor(8);
1348  strcpy(s,graf->plot->pl_scale->v_name);
1349  if (graf->scale->lflg) strcat(s," (log)");
1350  DevSetColor(2);
1351  sprintf(INBUF,"Scale type: %s",s);
1352  DevText(INBUF,0,graf->scr.Y);
1353  DevSetColor(8);
1354  sprintf(INBUF,"The full range of x is: %s %s",
1355  ecvt12(graf->scale->xfull.beg),ecvt12(graf->scale->xfull.end));
1356  DevText(INBUF,0,graf->scr.Y - 2*graf->scr.H);
1357  sprintf(INBUF,"Currently, the range is: %s %s",
1358  ecvt12(graf->scale->xcurr.beg),ecvt12(graf->scale->xcurr.end));
1359  DevText(INBUF,0,graf->scr.Y - 3*graf->scr.H);
1360  DevSetColor(1);
1361  sprintf(INBUF,"Enter new range min max or <CR> for full scale : ");
1362  DevText(INBUF,0,graf->scr.Y - 5*graf->scr.H);
1363  for (;;) {
1364  char *c;
1365  DevSetColor(11);
1366  DevBox((int)strlen(INBUF)*graf->scr.W,
1367  graf->scr.Y - 5*graf->scr.H,graf->scr.XU,
1368  graf->scr.Y - 4*graf->scr.H);
1369  c = KbEdit(NULL,(int)strlen(INBUF)*graf->scr.W,
1370  graf->scr.Y - 5*graf->scr.H,11,1,13);
1371  if (!c) break; /* ESC entered */
1372  j = strlen(c);
1373  if (!j) {
1374  graf->scale->xcurr.end = graf->scale->xfull.end;
1375  graf->scale->xcurr.beg = graf->scale->xfull.beg;
1376  graf->opt &= ~(OPT_x|OPT_X);
1377  break;
1378  }
1379  if (strchr(c,'q'))
1380  return 1;
1381  if ((j == 1) && (*c == ' ')) break;
1382  if (sscanf(c,"%le %le",
1383  &graf->scale->xcurr.beg,&graf->scale->xcurr.end) == 1) {
1384  graf->scale->xcurr.end = graf->scale->xcurr.beg;
1385  graf->scale->xcurr.beg = graf->scale->xfull.beg;
1386  }
1387  if (graf->scale->xcurr.end > graf->scale->xfull.end)
1388  graf->scale->xcurr.end = graf->scale->xfull.end;
1389  if (graf->scale->xcurr.beg < graf->scale->xfull.beg)
1390  graf->scale->xcurr.beg = graf->scale->xfull.beg;
1391  if (graf->scale->xcurr.beg >= graf->scale->xfull.beg &&
1392  graf->scale->xcurr.end <= graf->scale->xfull.end &&
1393  graf->scale->xcurr.beg < graf->scale->xcurr.end) break;
1394  DevSetColor(0);
1395  DevBox(0,graf->scr.Y - 5*graf->scr.H,graf->scr.XU,
1396  graf->scr.Y - 4*graf->scr.H);
1397  sprintf(INBUF,"Error: Please reenter the new range min max : ");
1398  DevSetColor(1);
1399  DevText(INBUF,0,graf->scr.Y - 5*graf->scr.H);
1400  }
1401  if (graf->scale->lflg) {
1402  graf->scale->xcurr.min = floor(graf->scale->xcurr.beg);
1403  graf->scale->xcurr.max = ceil(graf->scale->xcurr.end);
1404  graf->scale->ncells = graf->scale->xcurr.max - graf->scale->xcurr.min;
1405  }
1406  else {
1407  set_scale(graf->scale->xcurr.beg,graf->scale->xcurr.end,
1408  &graf->scale->xcurr.min,&graf->scale->xcurr.max,
1409  &graf->scale->ncells);
1410  }
1411  DevUpdate();
1412  return 0;
1413 }
1414 
1415 
1416 static void
1417 displxy(graf)
1418 
1419 /* Display in x-y mode. */
1420 struct gplot *graf;
1421 {
1422  double xi, xx, yi, yx;
1423  int i, j, k, num, spa, scrx, cy;
1424  int ix, iy, ixo, iyo, len, extra;
1425  float *px, *py;
1426 
1427  if (graf->numtr < 2) return;
1428  axes(graf,2,2);
1429  scrx = graf->scr.XL - 13*graf->scr.W - graf->scr.W2;
1430  num = (graf->numtr >> 1) << 1;
1431  spa = (num*graf->scr.H) >> 1;
1432  DevSetColor(8);
1433  DevText("X",scrx,graf->scr.YC + spa);
1434  DevText("Y",scrx,graf->scr.YC + spa - graf->scr.H);
1435  for (i = 0; i < num; i += 2) {
1436  DevSetColor(i/2 + 2);
1437  xi = graf->scale->ymin[i];
1438  xx = graf->scale->ymax[i];
1439  yi = graf->scale->ymin[i+1];
1440  yx = graf->scale->ymax[i+1];
1441  DevText(graf->tdata[i].name,
1442  scrx,graf->scr.YC + spa - (i+2)*graf->scr.H);
1443  DevText(graf->tdata[i+1].name,
1444  scrx,graf->scr.YC + spa - (i+3)*graf->scr.H);
1445  if (!(graf->opt & OPT_mark)) {
1446  writef(yx,scrx,graf->scr.YU - graf->scr.H*(i/2+1));
1447  writef(yi,scrx,graf->scr.YL + spa - graf->scr.H*(i/2 + 1));
1448  if (num <= 4) {
1449  writef(xi,graf->scr.XL,graf->scr.YL - graf->scr.H*(i/2+1));
1450  writef(xx,graf->scr.XU - FIELD*graf->scr.W,
1451  graf->scr.YL - graf->scr.H*(i/2+1));
1452  }
1453  else if (i >= 4) {
1454  writef(xi,graf->scr.XL + (FIELD+1)*graf->scr.W,
1455  graf->scr.YL - graf->scr.H*(i/2-1));
1456  writef(xx,graf->scr.XU - FIELD*graf->scr.W,
1457  graf->scr.YL - graf->scr.H*(i/2-1));
1458  }
1459  else {
1460  writef(xi,graf->scr.XL,graf->scr.YL - graf->scr.H*(i/2+1));
1461  writef(xx,graf->scr.XU - (2*FIELD+1)*graf->scr.W,
1462  graf->scr.YL - graf->scr.H*(i/2+1));
1463  }
1464  }
1465  if (dispdev->numcolors == 2 && !(graf->opt & OPT_p))
1466  DevSetLinestyle(i);
1467 
1468  cy = graf->tdata[i].cycles;
1469  if (cy > graf->tdata[i+1].cycles)
1470  cy = graf->tdata[i+1].cycles;
1471  extra = graf->tdata[i].extra;
1472  if (extra > graf->tdata[i+1].extra)
1473  extra = graf->tdata[i+1].extra;
1474 
1475  px = graf->tdata[i].data + graf->scale->strtpt;
1476  py = graf->tdata[i+1].data + graf->scale->strtpt;
1477  len = graf->scale->numpts;
1478  while (cy--) {
1479  if (!cy && extra) {
1480  if (graf->scale->strtpt > extra)
1481  break;
1482  if (len + graf->scale->strtpt > extra)
1483  len = extra - graf->scale->strtpt;
1484  }
1485  for (j = 0; j < len; j++) {
1486  ix = graf->scr.XL +
1487  (.5 + graf->scr.X*(*(px+j) - xi)/(xx - xi));
1488  iy = graf->scr.YL +
1489  (.5 + graf->scr.Y*(*(py+j) - yi)/(yx - yi));
1490  if (graf->opt & OPT_p)
1491  DevPixel(ix,iy);
1492  else if (j)
1493  DevLine(ix,iy,ixo,iyo);
1494  ixo = ix;
1495  iyo = iy;
1496  }
1497  py += graf->numpt;
1498  }
1499  if (dispdev->numcolors == 2 && !(graf->opt & OPT_p))
1500  DevSetLinestyle(0);
1501  }
1502  DevSetColor(1);
1503  DevText(graf->plot->pl_title,graf->scr.XL,graf->scr.YU + graf->scr.H3);
1504  DevSetColor(8);
1505  DevText(graf->plot->pl_name,graf->scr.XL,graf->scr.YU + graf->scr.H2);
1506  if (graf->scr.X > ((int)strlen(graf->plot->pl_name) +
1507  (int)strlen(graf->plot->pl_date))*graf->scr.W)
1508  DevText(graf->plot->pl_date,
1509  graf->scr.XU - (int)strlen(graf->plot->pl_date)*graf->scr.W,
1510  graf->scr.YU + graf->scr.H2);
1511  DevUpdate();
1512  return;
1513 }
1514 
1515 
1516 static void
1517 minmax(graf,c)
1518 
1519 /* Find MIN MAX of trace over interval. */
1520 struct gplot *graf;
1521 int *c;
1522 {
1523 
1524  float *dp;
1525  int i, j, n, cy, numpts;
1526  double f, atof(), *al, *ah;
1527 
1528  c[0] = c[1] = c[2] = 0;
1529  al = graf->scale->ymin;
1530  ah = graf->scale->ymax;
1531  n = graf->numtr;
1532  al[n] = al[n+1] = al[n+2] = al[n+3] = 1;
1533  ah[n] = ah[n+1] = ah[n+2] = ah[n+3] = -1;
1534  for (i = 0; i < n; i++) {
1535  al[i] = 1;
1536  ah[i] = -1;
1537  cy = graf->tdata[i].cycles;
1538  dp = graf->tdata[i].data + graf->scale->strtpt;
1539  numpts = graf->scale->numpts;
1540  while (cy--) {
1541  if (!cy && graf->tdata[i].extra) {
1542  if (graf->scale->strtpt > graf->tdata[i].extra)
1543  break;
1544  if (numpts + graf->scale->strtpt > graf->tdata[i].extra)
1545  numpts = graf->tdata[i].extra - graf->scale->strtpt;
1546  }
1547 
1548  for (j = 0; j < numpts; j++) {
1549 
1550  f = (double) *(dp + j);
1551  if (al[i] > ah[i]) {
1552  al[i] = f;
1553  ah[i] = f;
1554  }
1555  else {
1556  if (f < al[i]) al[i] = f;
1557  if (f > ah[i]) ah[i] = f;
1558  }
1559  switch (graf->tdata[i].type) {
1560  case GRAF_V:
1561  if (al[n+1] > ah[n+1]) {
1562  al[n+1] = f;
1563  ah[n+1] = f;
1564  }
1565  else {
1566  if (f < al[n+1]) al[n+1] = f;
1567  if (f > ah[n+1]) ah[n+1] = f;
1568  }
1569  c[0] = 1;
1570  break;
1571  case GRAF_I:
1572  if (al[n+2] > ah[n+2]) {
1573  al[n+2] = f;
1574  ah[n+2] = f;
1575  }
1576  else {
1577  if (f < al[n+2]) al[n+2] = f;
1578  if (f > ah[n+2]) ah[n+2] = f;
1579  }
1580  c[1] = 1;
1581  break;
1582  default:
1583  if (al[n+3] > ah[n+3]) {
1584  al[n+3] = f;
1585  ah[n+3] = f;
1586  }
1587  else {
1588  if (f < al[n+3]) al[n+3] = f;
1589  if (f > ah[n+3]) ah[n+3] = f;
1590  }
1591  c[2] = 1;
1592  break;
1593  }
1594  }
1595  dp += graf->numpt;
1596  }
1597  if (al[n] > ah[n]) {
1598  al[n] = al[i];
1599  ah[n] = ah[i];
1600  }
1601  else {
1602  if (al[i] < al[n]) al[n] = al[i];
1603  if (ah[i] > ah[n]) ah[n] = ah[i];
1604  }
1605  }
1606 }
1607 
1608 
1609 static void
1610 draw(graf,trace,fl,fh)
1611 
1612 /* Plot cm pixels scaled between
1613  * fl - fh to 0 - Y.
1614  */
1615 struct gplot *graf;
1616 int trace;
1617 double fl, fh;
1618 {
1619  float *dp;
1620  int i, k, l, ok, ol, cy, numpts;
1621  double atof(), s, o;
1622 
1623  if (fl == fh)
1624  return;
1625  s = (graf->scale->xcurr.end - graf->scale->xcurr.beg) /
1626  (graf->scale->xcurr.max - graf->scale->xcurr.min);
1627  o = (graf->scale->xcurr.beg - graf->scale->xcurr.min) /
1628  (graf->scale->xcurr.max - graf->scale->xcurr.min);
1629 
1630  cy = graf->tdata[trace].cycles;
1631  dp = graf->tdata[trace].data + graf->scale->strtpt;
1632  numpts = graf->scale->numpts;
1633 
1634  while (cy--) {
1635  if (!cy && graf->tdata[trace].extra) {
1636  if (graf->scale->strtpt > graf->tdata[trace].extra)
1637  break;
1638  if (numpts + graf->scale->strtpt > graf->tdata[trace].extra)
1639  numpts = graf->tdata[trace].extra - graf->scale->strtpt;
1640  }
1641  k = graf->scr.XL + (int) (.5 + o*graf->scr.X);
1642  l = graf->scr.YL + (int) (.5 + graf->scr.Y*(*dp - fl)/(fh - fl));
1643  if (graf->opt & OPT_p)
1644  DevPixel(k,l);
1645  ok = k;
1646  ol = l;
1647  for (i = 1; i < numpts; i++) {
1648  k = graf->scr.XL +
1649  (int) (.5 + o*graf->scr.X +
1650  s*graf->scr.X*i/(graf->scale->numpts - 1));
1651  l = graf->scr.YL +
1652  (int) (.5 + graf->scr.Y*(*(dp + i) - fl)/(fh - fl));
1653  if (graf->opt & OPT_p)
1654  DevPixel(k,l);
1655  else
1656  DevLine(ok,ol,k,l);
1657  ok = k;
1658  ol = l;
1659  }
1660  dp += graf->numpt;
1661  }
1662  /* have to keep track of the last point plotted for iplot */
1663  graf->lastx = k;
1664  graf->tdata[trace].lasty = l;
1665  return;
1666 }
1667 
1668 
1669 static void
1670 axes(graf,nx,ny)
1671 
1672 /* Draw axes, ny X nx grid. */
1673 struct gplot *graf;
1674 int nx, ny;
1675 {
1676  int x, y;
1677 
1678  graf->scr.X = (graf->scr.X/nx)*nx;
1679  graf->scr.Y = (graf->scr.Y/ny)*ny;
1680  graf->scr.XC = graf->scr.XL + graf->scr.X/2;
1681  graf->scr.YC = graf->scr.YL + graf->scr.Y/2;
1682  graf->scr.XU = graf->scr.XL + graf->scr.X;
1683  graf->scr.YU = graf->scr.YL + graf->scr.Y;
1684  if (!graf->iniplot)
1685  DevClear();
1686  DevSetLinestyle(0);
1687  DevSetColor(8);
1688  ebox(graf->scr.XL,graf->scr.YL,graf->scr.XU,graf->scr.YU);
1689  DevDefineLinestyle(1,0xcc);
1690  DevSetLinestyle(1);
1691  for (x = graf->scr.X/nx; x <= graf->scr.X - graf->scr.X/nx;
1692  x += graf->scr.X/nx)
1693  DevLine(x + graf->scr.XL,graf->scr.YL,x + graf->scr.XL,graf->scr.YU);
1694  for (y = graf->scr.Y/ny; y <= graf->scr.Y - graf->scr.Y/ny;
1695  y += graf->scr.Y/ny)
1696  DevLine(graf->scr.XL,y + graf->scr.YL,graf->scr.XU,y + graf->scr.YL);
1697  DevSetLinestyle(0);
1698 }
1699 
1700 
1701 static void
1702 set_scale(l,u,lnew,unew,n)
1703 
1704 /* Find nice 1-2-5 scale for data. */
1705 double l, u, *lnew, *unew;
1706 int *n;
1707 {
1708  double x, e, m, del, s;
1709  double fabs(), log10(), pow(), floor();
1710  int j = 0;
1711  *n = 4;
1712  if (u < l) { x = l; l = u; u = x; }
1713  if (u == l) { l -= 0.1*fabs(l); u += 0.1*fabs(u); }
1714  if (u == l) { *lnew = -0.5; *unew = 0.5; return; }
1715  x = u - l;
1716  l += x*.001;
1717  u -= x*.001;
1718  x = u - l;
1719  e = floor(log10(x));
1720  m = x / pow(10.0,e);
1721 
1722  if (m <= 2) j = 1;
1723  else if (m <= 4) j = 2;
1724  else if (m <= 8) j = 4;
1725  else j = 8;
1726 
1727  if (m > j*1.75) *n = 8;
1728  else if (m > j*1.5) *n = 7;
1729  else if (m > j*1.25) *n = 6;
1730  else if (m > j*1.0) *n = 5;
1731  else *n = 4;
1732 
1733  s = *n * j * pow(10.0, e) / 4.0;
1734  if (*n == 8) *n = 4;
1735  del = s / *n;
1736  x = l / del;
1737  while (s + del*floor(x) < u) {
1738  s += del;
1739  *n += 1;
1740  if (*n == 8) *n = 4;
1741  del = s / *n;
1742  x = l / del;
1743  }
1744  *lnew = del * floor(x);
1745  *unew = *lnew + s;
1746 }
1747 
1748 
1749 static void
1750 set_scale_4(l,u,lnew,unew)
1751 
1752 /* Find 4 segment scale for data. */
1753 double l, u, *lnew, *unew;
1754 {
1755  double x, e, m, del, s;
1756  double fabs(), log10(), pow(), floor();
1757  int n, j = 0;
1758  if (u < l) { x = l; l = u; u = x; }
1759  if (u == l) { l -= 0.1*fabs(l); u += 0.1*fabs(u); }
1760  if (u == l) { *lnew = -0.5; *unew = 0.5; return; }
1761  x = u - l;
1762  l += x*.001;
1763  u -= x*.001;
1764  x = u - l;
1765  e = floor(log10(x));
1766  m = x / pow(10.0,e);
1767 
1768  if (m <= 2) j = 1;
1769  else if (m <= 4) j = 2;
1770  else if (m <= 8) j = 4;
1771  else j = 8;
1772 
1773  if (m > j*1.75) n = 8;
1774  else if (m > j*1.5) n = 7;
1775  else if (m > j*1.25) n = 6;
1776  else if (m > j*1.0) n = 5;
1777  else n = 4;
1778 
1779  s = n * j * pow(10.0, e) / 4.0;
1780  if (n == 8) n = 4;
1781  del = s / n;
1782  x = l / del;
1783  while (n != 4 || s + del*floor(x) < u) {
1784  s += del;
1785  n += 1;
1786  if (n == 8) n = 4;
1787  del = s / n;
1788  x = l / del;
1789  }
1790  *lnew = del * floor(x);
1791  *unew = *lnew + s;
1792 }
1793 
1794 
1795 static void
1796 writef(d,x,y)
1797 
1798 /* Write floating point number on screen. */
1799 double d;
1800 int x, y;
1801 {
1802  DevText(ecvt12(d),x,y);
1803 }
1804 
1805 
1806 static void
1807 writeg(d,x,y,j)
1808 
1809 /* Write floating point number on screen. */
1810 double d;
1811 int x, y;
1812 char j; /* 'r' right justify, else left justify */
1813 {
1814  char t[20], *tt;
1815  int xp, sn;
1816 
1817  sprintf(t,"%g",d);
1818  if ((tt = strchr(t,'e')) != NULL) {
1819  tt += 1;
1820  if (*tt == '-')
1821  sn = -1;
1822  else
1823  sn = 1;
1824  tt++;
1825  xp = atoi(tt);
1826  if (xp > 99) {
1827  if (sn > 0)
1828  xp = 99;
1829  else {
1830  if (j == 'r')
1831  DevText("0",x - 2*currentgraph->fontwidth,y);
1832  else
1833  DevText("0",x,y);
1834  return;
1835  }
1836  }
1837  sprintf(tt,"%02d",xp);
1838  }
1839  if (j == 'r')
1840  DevText(t,x - (int)strlen(t)*currentgraph->fontwidth,y);
1841  else
1842  DevText(t,x,y);
1843 }
1844 
1845 
1846 static char *
1848 
1849 /* Format: space or +, x.xxxxx, e, + or -, xx
1850  * keeps track of 10 calls for use in printf.
1851  */
1852 double d;
1853 {
1854  static char s[10][20];
1855  static int num;
1856  int xp, sn;
1857  char *ss;
1858 
1859  num++;
1860  if (num > 9)
1861  num = 0;
1862  sprintf(s[num],"%+.5e",d);
1863  ss = strchr(s[num],'e');
1864  if (ss[1] == '-')
1865  sn = -1;
1866  else
1867  sn = 1;
1868  xp = atoi(ss+2);
1869 
1870  if (xp > 99) {
1871  if (sn > 0)
1872  xp = 99;
1873  else {
1874  strcpy(s[num]," 0.00000e+00");
1875  return (s[num]);
1876  }
1877  }
1878 
1879  /* make sure we print . and trailing 0's */
1880  if (ss - s[num] == 2)
1881  *ss++ = '.';
1882  while (ss - s[num] < 8)
1883  *ss++ = '0';
1884  *ss++ = 'e';
1885  if (sn < 0)
1886  *ss++ = '-';
1887  else
1888  *ss++ = '+';
1889  *ss++ = '0' + (xp/10);
1890  *ss++ = '0' + (xp%10);
1891  *ss++ = '\0';
1892  if (*s[num] == '+')
1893  *s[num] = ' ';
1894  return (s[num]);
1895 }
1896 
1897 
1898 static void
1899 help(graf)
1900 
1901 struct gplot *graf;
1902 {
1903  int x, y, h;
1904  int maxline = 0;
1905 
1906  DevClear();
1907  x = graf->scr.XL - 10*graf->scr.W;
1908  y = graf->scr.YS - 2*graf->scr.H;
1909  h = graf->scr.H;
1910  DevSetColor(8);
1911 
1912  DevText("Display mode options are as follows :",x,y);
1913 
1914  DevText("a Append current plot to file \"plotdt\".",
1915  x,y-=(3*h)/2);
1916  DevText("b Plot data in X-Y mode, taking 2 traces at a time.",
1917  x,y-=h);
1918  DevText("c Enable the marker. The marker prints the trace",
1919  x,y-=h);
1920  DevText(" coordinates, and is retired when ENTER is struck.",
1921  x,y-=h);
1922  DevText("n Use similar scales for three classes of traces: those",
1923  x,y-=h);
1924  DevText(" with names beginning with V,I, and otherwise.",
1925  x,y-=h);
1926  DevText("N Plot all traces on the same vertical scale",
1927  x,y-=h);
1928  DevText("p Plot data as points.",
1929  x,y-=h);
1930  DevText("P Generate a hardcopy.",
1931  x,y-=h);
1932  DevText("q Quit.",
1933  x,y-=h);
1934  DevText("t Display each trace on a separate axis, no overlap.",
1935  x,y-=h);
1936  DevText("x Change the horizontal scale, thus display a portion of the graph.",
1937  x,y-=h);
1938  DevText("X Same as \"x\" but use the whole curve to generate the y scales.",
1939  x,y-=h);
1940  DevText("y Use separate scales for each trace.",
1941  x,y-=h);
1942  DevText("Options p and t toggle, therefore enter a second time to return to the",
1943  x,y-=(3*h)/2);
1944  DevText("original display mode. Options can also be input from the command line.",
1945  x,y-=h);
1946  DevText("When using the x option, ENTER as response to the scale min max prompt",
1947  x,y-=(3*h)/2);
1948  DevText("will reset to full scale values, and a space followed by ENTER will leave",
1949  x,y-=h);
1950  DevText("the previous values unchanged.",
1951  x,y-=h);
1952  DevText("Options may be entered after each plot is displayed.",
1953  x,y-=h);
1954  y -= (3*h)/2;
1955  maxline = 74;
1956 
1957  DevSetColor(2);
1958  ebox(x - graf->scr.W,y - graf->scr.H2,
1959  x + maxline*graf->scr.W,graf->scr.YS - graf->scr.H2);
1960 
1961  DevUpdate();
1962 }
1963 
1964 
1965 static void
1967 
1968 /* Driver for marker. */
1969 GRAPH *graph;
1970 {
1971  struct gplot *graf = (struct gplot *)graph->plotdata;
1972  int i, spa, dely, scrx;
1973  int num, fw, fy;
1974  REQUEST request;
1976 
1977  if (dispdev->hardcopy) return;
1978 
1979  scrx = graf->scr.XL - 13*graf->scr.W - graf->scr.W2;
1980  fw = FIELD*graf->scr.W;
1981 
1982  DevSetColor(0);
1983 
1984  if (graf->opt & OPT_b) {
1985 
1986  num = (graf->numtr >> 1);
1987  spa = num*graf->scr.H;
1988 
1989  DevBox(scrx,graf->scr.YU - graf->scr.H*num,
1990  scrx + fw,graf->scr.YU);
1991  DevBox(scrx,graf->scr.YL + spa - graf->scr.H*num,
1992  scrx + fw,graf->scr.YL + spa);
1993 
1994  for (i = 0; i < num; i++) {
1995 
1996  fy = graf->scr.H*i;
1997 
1998  if (num <= 2) {
1999 
2000  DevBox(graf->scr.XL,graf->scr.YL - fy - graf->scr.H,
2001  graf->scr.XL + fw,graf->scr.YL - fy - 1);
2002  DevBox(graf->scr.XU - fw,graf->scr.YL - fy - graf->scr.H,
2003  graf->scr.XU, graf->scr.YL - fy - 1);
2004  }
2005  else if (i >= 2) {
2006  DevBox(graf->scr.XL + fw + graf->scr.W,
2007  graf->scr.YL - fy + graf->scr.H,
2008  graf->scr.XL + 2*fw + graf->scr.W,
2009  graf->scr.YL - fy + 2*graf->scr.H - 1);
2010  DevBox(graf->scr.XU - fw,graf->scr.YL - fy + graf->scr.H,
2011  graf->scr.XU, graf->scr.YL - fy + 2*graf->scr.H - 1);
2012  }
2013  else {
2014  DevBox(graf->scr.XL,graf->scr.YL - fy - graf->scr.H,
2015  graf->scr.XL + fw, graf->scr.YL - fy - 1);
2016  DevBox(graf->scr.XU - 2*fw - graf->scr.W,
2017  graf->scr.YL - fy - graf->scr.H,
2018  graf->scr.XU - fw - graf->scr.H, graf->scr.YL - fy - 1);
2019  }
2020  }
2021  }
2022  else {
2023  dely = 3*graf->scr.H + graf->scr.H2;
2024  if (graf->opt & OPT_t) {
2025  if (graf->numtr)
2026  spa = graf->scr.Y/graf->numtr;
2027  else
2028  spa = graf->scr.Y;
2029  if (spa < dely)
2030  spa = dely;
2031  }
2032  else
2033  spa = dely;
2034  for (i = 0; i < graf->numtr; i++) {
2035  DevBox(scrx,graf->scr.YU - i*spa - 3*graf->scr.H - 2,
2036  scrx + fw, graf->scr.YU - i*spa - graf->scr.H - 1);
2037  }
2038  }
2039 
2040  DevSetColor(1);
2041  DevSetGhost(ghost_mark,0,0);
2042  if (!dispdev->windows) {
2045  DevSetGhost(NULL,0,0);
2046  graf->opt &= ~OPT_mark;
2047  displ(graf);
2048  }
2049 }
2050 
2051 
2052 static void
2054 
2055 struct gplot *graf;
2056 int x;
2057 {
2058  int nmin, nmax;
2059  int i, spa, dely, scrx, fw;
2060 
2061  if (graf->opt & (OPT_help | OPT_b))
2062  return;
2063  nmin = graf->scr.XL + (int)
2064  ((graf->scale->xcurr.beg - graf->scale->xcurr.min)*graf->scr.X/
2065  (graf->scale->xcurr.max - graf->scale->xcurr.min)+.5);
2066  nmax = graf->scr.XL + (int)
2067  ((graf->scale->xcurr.end - graf->scale->xcurr.min)*graf->scr.X/
2068  (graf->scale->xcurr.max - graf->scale->xcurr.min)+.5);
2069  if (x < nmin || x > nmax)
2070  return;
2071  DevSetGhost(NULL,0,0);
2072  DevSetColor(0);
2073  scrx = graf->scr.XL - 13*graf->scr.W - graf->scr.W2;
2074  fw = FIELD*graf->scr.W;
2075  dely = 3*graf->scr.H + graf->scr.H2;
2076  if (graf->opt & OPT_t) {
2077  if (graf->numtr)
2078  spa = graf->scr.Y/graf->numtr;
2079  else
2080  spa = graf->scr.Y;
2081  if (spa < dely)
2082  spa = dely;
2083  }
2084  else
2085  spa = dely;
2086  for (i = 0; i < graf->numtr; i++) {
2087  DevBox(scrx,graf->scr.YU - i*spa - 3*graf->scr.H - 2,
2088  scrx + fw, graf->scr.YU - i*spa - graf->scr.H - 1);
2089  }
2090  DevBox(graf->scr.XL, graf->scr.YL - 3*graf->scr.H,
2091  graf->scr.XS-1, graf->scr.YL - 2*graf->scr.H);
2092 
2093  graf->ref.set = true;
2094  graf->ref.x = x;
2095  DevSetGhost(ghost_mark,0,0);
2096 }
2097 
2098 
2099 /* ARGSUSED */
2100 static void
2101 ghost_mark(x,y,refx,refy)
2102 
2103 int x, y, refx, refy;
2104 {
2105  struct gplot *graf = (struct gplot *)currentgraph->plotdata;
2106  int i, num, scrx, spa, dely;
2107  int nmin, nmax;
2108  int fw, fy;
2109  double xx, x0, yy, y0;
2110 
2111  fw = FIELD*graf->scr.W;
2112  scrx = graf->scr.XL - fw - graf->scr.W - graf->scr.W2;
2113 
2114  if (graf->opt & OPT_b) {
2115 
2116  if (x < graf->scr.XL || x > graf->scr.XU)
2117  return;
2118  if (y < graf->scr.YL || y > graf->scr.YU)
2119  return;
2120 
2121  DevLine(x,graf->scr.YL,x,graf->scr.YU);
2122  DevLine(graf->scr.XL,y,graf->scr.XU,y);
2123 
2124  num = (graf->numtr >> 1) << 1;
2125  for (i = 0; i < num; i += 2) {
2126 
2127  fy = graf->scr.H*i/2;
2128 
2129  xx = graf->scale->ymin[i] +
2130  ((graf->scale->ymax[i]-graf->scale->ymin[i])*
2131  (x-graf->scr.XL))/graf->scr.X;
2132  yy = graf->scale->ymin[i+1] +
2133  ((graf->scale->ymax[i+1]-graf->scale->ymin[i+1])*
2134  (y-graf->scr.YL))/graf->scr.Y;
2135 
2136  writef(yy,scrx,graf->scr.YU - fy - graf->scr.H);
2137 
2138  if (num <= 4) {
2139  writef(xx,graf->scr.XU - fw,
2140  graf->scr.YL - fy - graf->scr.H);
2141  }
2142  else if (i >= 4) {
2143  writef(xx,graf->scr.XU - fw,
2144  graf->scr.YL - fy + graf->scr.H);
2145  }
2146  else {
2147  writef(xx,graf->scr.XU - 2*fw - graf->scr.W,
2148  graf->scr.YL - fy - graf->scr.H);
2149  }
2150  }
2151  return;
2152  }
2153 
2154  nmin = graf->scr.XL + (int)
2155  ((graf->scale->xcurr.beg - graf->scale->xcurr.min)*graf->scr.X/
2156  (graf->scale->xcurr.max - graf->scale->xcurr.min)+.5);
2157  nmax = graf->scr.XL + (int)
2158  ((graf->scale->xcurr.end - graf->scale->xcurr.min)*graf->scr.X/
2159  (graf->scale->xcurr.max - graf->scale->xcurr.min)+.5);
2160 
2161  if (x < nmin || x > nmax)
2162  return;
2163 
2164  DevLine(x,graf->scr.YL,x,graf->scr.YU);
2165 
2166  dely = 3*graf->scr.H + graf->scr.H2;
2167  if (graf->opt & OPT_t) {
2168  if (graf->numtr)
2169  spa = graf->scr.Y/graf->numtr;
2170  else
2171  spa = graf->scr.Y;
2172  if (spa < dely)
2173  spa = dely;
2174  }
2175  else
2176  spa = dely;
2177 
2178  for (i = 0; i < graf->numtr; i++) {
2179  ymap(graf,&yy,x,nmin,nmax,i);
2180  if (graf->ref.set) {
2181  ymap(graf,&y0,graf->ref.x,nmin,nmax,i);
2182  yy -= y0;
2183  }
2184  writef(yy, scrx, graf->scr.YU - i*spa - 2*graf->scr.H - 2);
2185  }
2186  xx = graf->scale->xcurr.beg + (x - nmin)*
2187  (graf->scale->xcurr.end - graf->scale->xcurr.beg)/(nmax-nmin);
2188  if (graf->ref.set) {
2189  x0 = graf->scale->xcurr.beg + (graf->ref.x - nmin)*
2190  (graf->scale->xcurr.end - graf->scale->xcurr.beg)/(nmax-nmin);
2191  xx -= x0;
2192  sprintf(INBUF,"dX = %s",ecvt12(xx));
2193  }
2194  else
2195  sprintf(INBUF,"X = %s",ecvt12(xx));
2196  DevText(INBUF,graf->scr.XU - strlen(INBUF)*graf->scr.W,
2197  graf->scr.YL - 3*graf->scr.H);
2198 }
2199 
2200 
2201 static int
2202 ymap(graf,y,m,nmin,nmax,j)
2203 
2204 /* Return y screen coordinate, given x screen coordinate m.
2205  * Also give interpolated y value y, given range
2206  * (screen coords) nmin, nmax, j is trace.
2207  */
2208 struct gplot *graf;
2209 double *y;
2210 int m, nmin, nmax, j;
2211 {
2212  double mm, mf, maxy, miny;
2213  int mi, yo, ys;
2214 
2215  mm = m - nmin;
2216  mm *= (graf->scale->numpts-1);
2217  mm /= (nmax - nmin);
2218  mm += graf->scale->strtpt;
2219  mi = (int) mm;
2220  mf = mm - mi;
2221  *y = graf->tdata[j].data[mi] +
2222  mf*(graf->tdata[j].data[mi+1]-graf->tdata[j].data[mi]);
2223  if (graf->opt & OPT_t) {
2224  ys = graf->scr.Y/graf->numtr;
2225  yo = graf->scr.YL + (graf->numtr-j-1)*ys;
2226  }
2227  else {
2228  ys = graf->scr.Y;
2229  yo = graf->scr.YL;
2230  }
2231  if (graf->opt & OPT_N) {
2232  miny = graf->scale->ymin[graf->numtr];
2233  maxy = graf->scale->ymax[graf->numtr];
2234  }
2235  else if (graf->opt & OPT_n) {
2236  switch (graf->tdata[j].type) {
2237  case GRAF_V:
2238  miny = graf->scale->ymin[graf->numtr+1];
2239  maxy = graf->scale->ymax[graf->numtr+1];
2240  break;
2241  case GRAF_I:
2242  miny = graf->scale->ymin[graf->numtr+2];
2243  maxy = graf->scale->ymax[graf->numtr+2];
2244  break;
2245  default:
2246  miny = graf->scale->ymin[graf->numtr+3];
2247  maxy = graf->scale->ymax[graf->numtr+3];
2248  }
2249  }
2250  else {
2251  miny = graf->scale->ymin[j];
2252  maxy = graf->scale->ymax[j];
2253  }
2254  return yo + (int) ((*y-miny)*ys/(maxy-miny)+.5);
2255 }
2256 
2257 
2258 static void
2259 addplot(graf)
2260 
2261 /* Write a plotfile to stream *fptr. */
2262 struct gplot *graf;
2263 {
2264  float *dp;
2265  int i, j, m, n, rem;
2266  FILE *fptr;
2267 
2268  fptr = fopen("plotdt","a");
2269  if (!fptr) return;
2270  n = graf->numtr;
2271  m = graf->numpt;
2272  fprintf(fptr,"%s\n%d %s %s\n",graf->plot->pl_title,n,"27.0",
2273  graf->plot->pl_date);
2274  for (i = 0; i < n; i++)
2275  fprintf(fptr,"%d\n%s\n",1,graf->tdata[i].name);
2276  fprintf(fptr,"%s\n%d\n",graf->plot->pl_scale->v_name,m);
2277  rem = m % 10;
2278  m /= 10;
2279  for (i = 0; i < n; i++) {
2280  fprintf(fptr,"%s%s\n",ecvt12(*graf->tdata[i].scale),
2281  ecvt12(*(graf->tdata[i].scale + 1)));
2282  fflush(fptr);
2283  dp = graf->tdata[i].data;
2284  for (j = 0; j < m; j++, dp += 10)
2285 
2286 fprintf(fptr,"%s%s%s%s%s%s%s%s%s%s\n",
2287 ecvt12(*dp),ecvt12(*(dp+1)),ecvt12(*(dp+2)),ecvt12(*(dp+3)),ecvt12(*(dp+4)),
2288 ecvt12(*(dp+5)),ecvt12(*(dp+6)),ecvt12(*(dp+7)),ecvt12(*(dp+8)),
2289 ecvt12(*(dp+9)));
2290 
2291  for (j = 0; j < rem; j++, dp++)
2292  fprintf(fptr,"%s",ecvt12(*dp));
2293  if (rem)
2294  fprintf(fptr,"\n");
2295  }
2296  dp = graf->xdata;
2297  for (j = 0; j < m; j++, dp += 10)
2298 
2299 fprintf(fptr,"%s%s%s%s%s%s%s%s%s%s\n",
2300 ecvt12(*dp),ecvt12(*(dp+1)),ecvt12(*(dp+2)),ecvt12(*(dp+3)),ecvt12(*(dp+4)),
2301 ecvt12(*(dp+5)),ecvt12(*(dp+6)),ecvt12(*(dp+7)),ecvt12(*(dp+8)),
2302 ecvt12(*(dp+9)));
2303 
2304  for (j = 0; j < rem; j++, dp++)
2305  fprintf(fptr,"%s",ecvt12(*dp));
2306  if (rem)
2307  fprintf(fptr,"\n");
2308 
2309  fclose(fptr);
2310 }
2311 
2312 
2313 /*********************************************************************
2314  *
2315  * Operating range analysis plotting.
2316  *
2317  *********************************************************************/
2318 
2319 
2320 static bool DOIPLOT; /* true => show iplot during run */
2321 
2322 void
2324 
2325 /* Operating range analysis plotting command. */
2326 wordlist *wl;
2327 {
2328  FILE *fp;
2329  wordlist *ww;
2330  struct chkpts *p, *p0 = NULL;
2331  struct mdata *md;
2332  char c = 0, d = 0;
2333  char buf[BSIZE_SP];
2334  GRAPH *graph;
2335  extern char *kw_mplot_cur;
2336 
2337  if (!wl) {
2338  if (cp_getvar(kw_mplot_cur,VT_STRING,buf))
2339  fp = fopen(buf,"r");
2340  else
2341  fp = fopen("check.dat","r");
2342  if (!fp) {
2343  fprintf(cp_err,"Error: No margin analysis data file found\n");
2344  return;
2345  }
2346  extpts(fp,&p0);
2347  fclose(fp);
2348  }
2349  for (ww = wl; ww; ww = ww->wl_next) {
2350  if (*ww->wl_word == '-' && *(ww->wl_word+1) == 'c') {
2351  c = 1;
2352  continue;
2353  }
2354  if (*ww->wl_word == '-' && *(ww->wl_word+1) == 'o' &&
2355  *(ww->wl_word+2) == 'n') {
2356  DOIPLOT = true;
2357  fprintf(cp_out,"Will display plot during margin analysis.\n");
2358  continue;
2359  }
2360  if (*ww->wl_word == '-' && *(ww->wl_word+1) == 'o' &&
2361  *(ww->wl_word+2) == 'f') {
2362  DOIPLOT = false;
2363  fprintf(cp_out,"Will not display plot during margin analysis.\n");
2364  continue;
2365  }
2366  fp = fopen(ww->wl_word,"r");
2367  if (!fp) {
2368  fprintf(cp_err,
2369  "Error: Margin analysis data file \"%s\" not found\n",
2370  ww->wl_word);
2371  continue;
2372  }
2373  d = 1;
2374  extpts(fp,&p0);
2375  fclose(fp);
2376  }
2377  if (!p0) {
2378  if (d)
2379  fprintf(cp_err,"Error: Nothing in file to plot.\n");
2380  return;
2381  }
2382  if (c) combin(p0);
2383 
2384  for (p = p0; p; p = p0) {
2385  p0 = p->next;
2386 
2387  if (!(graph = NewGraph())) {
2388  fprintf(cp_err, errmsg_gralloc);
2389  for (; p; p = p0) {
2390  p0 = p->next;
2391  chkpts_free(p);
2392  }
2393  return;
2394  }
2395  md = alloc(struct mdata);
2396  md->pts = p;
2397 
2398  graph->graphtype = GR_MPLT;
2399  graph->plotdata = (GRDATA)md;
2400  graph->copydata = mp_copy;
2401  graph->redraw = mp_display;
2402  graph->destroy = mp_free;
2403 
2404  if (DevNewViewport(graph)) {
2405  fprintf(cp_err, errmsg_newvp);
2406  DestroyGraph(graph->graphid);
2407  continue;
2408  }
2409 
2410  if (!dispdev->windows) {
2411  mp_display(graph);
2412  PushGraphContext(graph);
2413  if (!dispdev->hardcopy) {
2414  DevSetColor(0);
2415  DevBox(0,0,md->scr.XS,md->scr.H);
2416  DevSetColor(8);
2417  DevText("Hit any key to continue, 'p' for hardcopy",
2418  p->xc + p->d/2 - 20*md->scr.W - md->scr.W2,0);
2419  DevUpdate();
2420  if (DevGetchar(NULL) == 'p') {
2421  DevSetColor(0);
2422  DevBox(0,0,md->scr.XS,md->scr.H);
2423  ft_hardcopy(NULL,graph,true,NULL,false);
2424  }
2425  }
2426  DevHalt();
2427  PopGraphContext();
2428  DestroyGraph(graph->graphid);
2429  }
2430  }
2431 }
2432 
2433 
2434 static void
2435 extpts(fp,p0)
2436 
2437 /* Extract points from file. */
2438 FILE *fp;
2439 struct chkpts **p0;
2440 {
2441  int i, j, x, y, d1, d2;
2442  double v1, v2, maxv1, minv1, maxv2, minv2;
2443  struct chkpts *p, *q;
2444  char buf[80];
2445 
2446  i = 0;
2447  while (fgets(buf,80,fp)) {
2448  if (strchr(buf,'p') || strchr(buf,'f')) i++;
2449  }
2450  rewind(fp);
2451 
2452  p = alloc(struct chkpts);
2453  p->v1 = (char *) tmalloc(i);
2454  p->v2 = (char *) tmalloc(i);
2455  p->pf = (char *) tmalloc(i);
2456  p->size = i;
2457  p->next = NULL;
2458 
2459  i = 0;
2460  fgets(buf,80,fp);
2461  sscanf(buf,"%d %d %le %le",&d1,&d2,&v1,&v2);
2462  maxv1 = minv1 = v1;
2463  maxv2 = minv2 = v2;
2464  p->delta1 = -2*d1 + 1;
2465  p->delta2 = -2*d2 + 1;
2466 
2467  while (fgets(buf,80,fp)) {
2468  if (*buf != '\t') {
2469  sscanf(buf,"%d %d %le %le",&d1,&d2,&v1,&v2);
2470 
2471  if (v1 > maxv1) maxv1 = v1;
2472  if (v1 < minv1) minv1 = v1;
2473  if (v2 > maxv2) maxv2 = v2;
2474  if (v2 < minv2) minv2 = v2;
2475  }
2476 
2477  else if (strchr(buf,'p')) {
2478  (p->v1)[i] = d1;
2479  (p->v2)[i] = d2;
2480  (p->pf)[i] = 1;
2481  i++;
2482  }
2483  else if (strchr(buf,'f')) {
2484  (p->v1)[i] = d1;
2485  (p->v2)[i] = d2;
2486  (p->pf)[i] = 0;
2487  i++;
2488  }
2489  }
2490  p->minv1 = minv1;
2491  p->maxv1 = maxv1;
2492  p->minv2 = minv2;
2493  p->maxv2 = maxv2;
2494  if (!*p0)
2495  *p0 = p;
2496  else {
2497  for (q = *p0; q->next; q = q->next) ;
2498  q->next = p;
2499  }
2500 }
2501 
2502 
2503 static void
2505 
2506 /* Combine sets of data points into a single plot. */
2507 struct chkpts *p0;
2508 {
2509  struct chkpts *p, *q;
2510  double maxv1, minv1, maxv2, minv2, d1, d2, temp;
2511  int i, o1, o2, o3, o4;
2512  char *p1, *p2, *p3;
2513 
2514  d1 = (p0->maxv1 - p0->minv1)/(p0->delta1 - 1);
2515  d2 = (p0->maxv2 - p0->minv2)/(p0->delta2 - 1);
2516  for (p = p0->next; p; p = q) {
2517  maxv1 = (p->maxv1 - p->minv1)/(p->delta1 - 1);
2518  maxv2 = (p->maxv2 - p->minv2)/(p->delta2 - 1);
2519  if (fabs((d1-maxv1)/(d1+maxv1)) + fabs((d2-maxv2)/(d2+maxv2)) > 1e-6) {
2520  fprintf(cp_err,"Error: can't combine, incompatible data.\n");
2521  getchar();
2522  q = p->next;
2523  chkpts_free(p);
2524  continue;
2525  }
2526  maxv1 = (p0->maxv1 > p->maxv1 ? p0->maxv1 : p->maxv1);
2527  minv1 = (p0->minv1 < p->minv1 ? p0->minv1 : p->minv1);
2528  maxv2 = (p0->maxv2 > p->maxv2 ? p0->maxv2 : p->maxv2);
2529  minv2 = (p0->minv2 < p->minv2 ? p0->minv2 : p->minv2);
2530  temp = -(maxv1 + minv1)/d1 + 2*p->minv1/d1 + p->delta1 - 1;
2531  if (temp > 0) temp += .5;
2532  else temp -= .5;
2533  o1 = temp;
2534  if (o1 & 1) o1--;
2535  o1 >>= 1;
2536  temp = -(maxv2 + minv2)/d2 + 2*p->minv2/d2 + p->delta2 - 1;
2537  if (temp > 0) temp += .5;
2538  else temp -= .5;
2539  o2 = temp;
2540  if (o2 & 1) o2--;
2541  o2 >>= 1;
2542  temp = -(maxv1 + minv1)/d1 + 2*p0->minv1/d1 + p0->delta1 - 1;
2543  if (temp > 0) temp += .5;
2544  else temp -= .5;
2545  o3 = temp;
2546  if (o3 & 1) o3--;
2547  o3 >>= 1;
2548  temp = -(maxv2 + minv2)/d2 + 2*p0->minv2/d2 + p0->delta2 - 1;
2549  if (temp > 0) temp += .5;
2550  else temp -= .5;
2551  o4 = temp;
2552  if (o4 & 1) o4--;
2553  o4 >>= 1;
2554  p0->delta1 = (maxv1 - minv1)/d1 + 1.5;
2555  p0->delta2 = (maxv2 - minv2)/d2 + 1.5;
2556  for (i = 0; i < p0->size; i++) {
2557  p0->v1[i] += o3;
2558  p0->v2[i] += o4;
2559  }
2560  p0->v1 = (char *) trealloc(p0->v1,p0->size + p->size);
2561  p0->v2 = (char *) trealloc(p0->v2,p0->size + p->size);
2562  p0->pf = (char *) trealloc(p0->pf,p0->size + p->size);
2563  p1 = p0->v1 + p0->size;
2564  p2 = p0->v2 + p0->size;
2565  p3 = p0->pf + p0->size;
2566  p0->size += p->size;
2567  for (i = 0; i < p->size; i++) {
2568  *p1++ = p->v1[i] + o1;
2569  *p2++ = p->v2[i] + o2;
2570  *p3++ = p->pf[i];
2571  }
2572  p0->minv1 = minv1;
2573  p0->maxv1 = maxv1;
2574  p0->minv2 = minv2;
2575  p0->maxv2 = maxv2;
2576  q = p->next;
2577  chkpts_free(p);
2578  }
2579  p0->next = NULL;
2580 }
2581 
2582 
2583 static void
2585 
2586 /* Plot the list of data points. */
2587 struct mdata *md;
2588 {
2589  struct chkpts *p = md->pts;
2590  int j, x, y;
2591  void (*box)();
2592 
2593  init(md);
2594  for (j = 0; j < p->size; j++) {
2595  if (p->pf[j]) {
2596  DevSetColor(3);
2597  box = pbox;
2598  }
2599  else {
2600  DevSetColor(2);
2601  box = xbox;
2602  }
2603  x = p->xc + p->v1[j]*p->d;
2604  y = p->yc + p->v2[j]*p->d;
2605  box(x+1,y+1,x+p->d-1,y+p->d-1);
2606  }
2607 }
2608 
2609 
2610 static void
2612 
2613 /* redraw procedure */
2614 GRAPH *graph;
2615 {
2616  struct mdata *md = (struct mdata *)graph->plotdata;
2617  struct _keyed *k;
2618 
2619  PushGraphContext(graph);
2620  init_viewport(&md->scr);
2621  plpts(md);
2622  for (k = graph->keyed; k; k = k->next) {
2623  DevSetColor(k->colorindex);
2624  DevText(k->text, k->x, k->y);
2625  }
2626  PopGraphContext();
2627 }
2628 
2629 
2630 static void
2632 
2633 /* free data procedure */
2634 GRDATA mdp;
2635 {
2636  struct mdata *md = (struct mdata *)mdp;
2637  struct chkpts *p = md->pts;
2638 
2639  chkpts_free(p);
2640  txfree((char*)md);
2641 }
2642 
2643 
2644 static void
2646 
2647 struct chkpts *p;
2648 {
2649  txfree(p->v1);
2650  txfree(p->v2);
2651  txfree(p->pf);
2652  txfree((char*)p);
2653 }
2654 
2655 static GRDATA
2657 
2658 GRDATA mdp;
2659 {
2660  struct mdata *md = (struct mdata *)mdp;
2661  struct mdata *new;
2662 
2663  new = alloc(struct mdata);
2664  *new = *md;
2665  new->pts = alloc(struct chkpts);
2666  *new->pts = *md->pts;
2667  new->pts->v1 = tmalloc(new->pts->size);
2668  new->pts->v2 = tmalloc(new->pts->size);
2669  new->pts->pf = tmalloc(new->pts->size);
2670  memcpy(new->pts->v1,md->pts->v1,new->pts->size);
2671  memcpy(new->pts->v2,md->pts->v2,new->pts->size);
2672  memcpy(new->pts->pf,md->pts->pf,new->pts->size);
2673  return (GRDATA) new;
2674 }
2675 
2676 
2677 /* The next four routines are called from the margin analysis driver. */
2678 
2679 
2680 int
2681 mp_init(delta1,delta2, v1min, v1max, v2min, v2max)
2682 
2683 /* Initialize the operating range analysis plotting routines.
2684  * Return the graphid.
2685  */
2686 int delta1, delta2;
2687 double v1min, v1max, v2min, v2max;
2688 {
2689  int d, dd1, dd2, xc, yc, x1, y1;
2690  char s[64];
2691  char *msg = "Operating Range Analysis";
2692  GRAPH *graph;
2693  struct chkpts *p0;
2694  struct mdata *md;
2695 
2696  if (!DOIPLOT) return (0);
2697  if (!(graph = NewGraph())) {
2698  fprintf(cp_err, errmsg_gralloc);
2699  return (0);
2700  }
2701  p0 = alloc(struct chkpts);
2702  p0->delta1 = delta1;
2703  p0->delta2 = delta2;
2704  p0->minv1 = v1min;
2705  p0->maxv1 = v1max;
2706  p0->minv2 = v2min;
2707  p0->maxv2 = v2max;
2708 
2709  md = alloc(struct mdata);
2710  md->pts = p0;
2711 
2712  graph->graphtype = GR_MPLT;
2713  graph->plotdata = (GRDATA)md;
2714  graph->destroy = mp_free;
2715  graph->copydata = mp_copy;
2716  graph->redraw = mp_display;
2717 
2718  if (DevNewViewport(graph)) {
2719  fprintf(cp_err, errmsg_newvp);
2720  DestroyGraph(graph->graphid);
2721  return (0);
2722  }
2723 
2724  if (!dispdev->windows) {
2725  PushGraphContext(graph);
2726  init_viewport(&md->scr);
2727  init(md);
2728  PopGraphContext();
2729  }
2730  EchoGraph = graph;
2731 
2732  return (graph->graphid);
2733 }
2734 
2735 
2736 int
2737 mp_where(id,d1,d2)
2738 
2739 /* Define the lower left corner of the marker array. */
2740 int id, d1, d2;
2741 {
2742  struct mdata *md;
2743  struct chkpts *p;
2744 
2745  if (!DOIPLOT || !id) return (1);
2746 
2748  md = (struct mdata *)currentgraph->plotdata;
2749  p = md->pts;
2750  p->d1 = d1;
2751  p->d2 = d2;
2752  PopGraphContext();
2753  return (0);
2754 }
2755 
2756 
2757 int
2758 mp_mark(id,pf)
2759 
2760 /* Plot a data point. */
2761 int id;
2762 char pf;
2763 {
2764  int x, y;
2765  void (*box)();
2766  struct chkpts *p;
2767  struct mdata *md;
2768 
2769  if (!DOIPLOT || !id) return (1);
2770 
2772  md = (struct mdata *)currentgraph->plotdata;
2773  p = md->pts;
2774  addit(p,p->d1,p->d2,pf);
2775  if (pf) {
2776  DevSetColor(3);
2777  box = pbox;
2778  }
2779  else {
2780  DevSetColor(2);
2781  box = xbox;
2782  }
2783  x = p->xc + p->d1*p->d;
2784  y = p->yc + p->d2*p->d;
2785  box(x+1,y+1,x+p->d-1,y+p->d-1);
2786  DevUpdate();
2787  PopGraphContext();
2788  return (0);
2789 }
2790 
2791 
2792 int
2794 
2795 /* Called after all data points have been output. */
2796 int id;
2797 {
2798  struct mdata *md;
2799  struct chkpts *p;
2800  struct gpoint *graf;
2801 
2802  EchoGraph = NULL;
2803  if (!DOIPLOT || !id) return (1);
2804  if (dispdev->windows) return (0);
2805 
2807  md = (struct mdata *)currentgraph->plotdata;
2808  p = md->pts;
2809 
2810  if (!dispdev->hardcopy) {
2811  DevSetColor(0);
2812  DevBox(0,0,md->scr.XS,md->scr.H);
2813  DevSetColor(8);
2814  DevText("Hit any key to continue, 'p' for hardcopy",
2815  p->xc + p->d/2 - 20*md->scr.W - md->scr.W2,0);
2816  DevUpdate();
2817  if (DevGetchar(NULL) == 'p') {
2818  DevSetColor(0);
2819  DevBox(0,0,md->scr.XS,md->scr.H);
2820  ft_hardcopy(NULL,currentgraph,true,NULL,false);
2821  }
2822  }
2823  DevHalt();
2824  PopGraphContext();
2825  DestroyGraph(id);
2826 
2827  return (0);
2828 }
2829 
2830 
2831 static void
2832 init(md)
2833 
2834 struct mdata *md;
2835 {
2836  struct chkpts *p = md->pts;
2837  int d, dd1, dd2, xc, yc, x1, y1;
2838  int xx, yy, spa;
2839  char s[64];
2840  char *msg = "Operating Range Analysis";
2841  double dx;
2842  double dy;
2843 
2844  xx = md->scr.XS - 10*md->scr.W;
2845  yy = md->scr.YS - 9*md->scr.H;
2846  dx = (1.0 + (double)p->delta1)/xx;
2847  dy = (1.0 + (double)p->delta2)/yy;
2848 
2849  if (dx > dy)
2850  d = 1/dx;
2851  else
2852  d = 1/dy;
2853 
2854  dd1 = ((p->delta1-1)*d) >> 1;
2855  dd2 = ((p->delta2-1)*d) >> 1;
2856  p->d = d;
2857  p->xc = xc = 8*md->scr.W + xx/2;
2858  p->yc = yc = 6*md->scr.H + yy/2;
2859  if (!(p->delta1 & 1)) p->xc += d/2;
2860  if (!(p->delta2 & 1)) p->yc += d/2;
2861  spa = md->scr.H2/2;
2862  x1 = xc-dd1-spa;
2863  y1 = yc-dd2-spa;
2864 
2865  DevSetLinestyle(0);
2866  DevSetColor(4);
2867  ebox(x1,y1,xc+dd1+d+spa,yc+dd2+d+spa);
2868 
2869  yy = y1 - md->scr.H3;
2870  xx = x1;
2871 
2872  DevSetColor(1);
2873  DevText(msg,xx,yy);
2874 
2875  yy = y1 - 3*md->scr.H;
2876 
2877  DevSetColor(3);
2878  pbox(xx,yy,xx + md->scr.H,yy + md->scr.H);
2879  DevSetColor(8);
2880  DevText("pass",xx + md->scr.H3,yy);
2881 
2882  xx += md->scr.H3 + 7*md->scr.W;
2883 
2884  DevSetColor(2);
2885  xbox(xx,yy,xx + md->scr.H,yy + md->scr.H);
2886  DevSetColor(8);
2887  DevText("fail",xx + md->scr.H3,yy);
2888 
2889  yy = y1 - 3*md->scr.H - md->scr.H3;
2890 
2891  *s = '\0';
2892  if (dd1 && !dd2)
2893  sprintf(s,"Incr1 = %g",(p->maxv1-p->minv1)/(p->delta1-1));
2894  if (!dd1 && dd2)
2895  sprintf(s,"Incr2 = %g",(p->maxv2-p->minv2)/(p->delta2-1));
2896  if (dd1 && dd2)
2897  sprintf(s,"Incr1 = %g, Incr2 = %g",(p->maxv1-p->minv1)/
2898  (p->delta1-1),(p->maxv2-p->minv2)/(p->delta2-1));
2899 
2900  if (*s) {
2901  /* don't print if just 1 point */
2902  DevSetColor(1);
2903  DevText(s,x1,yy);
2904  }
2905 
2906  DevSetColor(8);
2907  writeg(p->maxv2,x1-md->scr.W,yc+dd2+d/2-md->scr.H2,'r');
2908  if (dd2)
2909  writeg(p->minv2,x1-md->scr.W,yc-dd2+d/2-md->scr.H2,'r');
2910 
2911  writeg(p->minv1,x1,yc+dd2+d+md->scr.H2,'l');
2912  if (dd1)
2913  if (dd1 < 2)
2914  writeg(p->maxv1,xc+dd1+d,yc+dd2+d+md->scr.H2,'l');
2915  else
2916  writeg(p->maxv1,xc+dd1+d,yc+dd2+d+md->scr.H2,'r');
2917 
2918  DevSetColor(1);
2919  DevText("Param 2",
2920  x1-8*md->scr.W-md->scr.W2,yc+d/2-(dd2 ? md->scr.H2 : md->scr.H3));
2921  DevText("Param 1",xc+d/2-3*md->scr.W-md->scr.W2,yc+dd2+d+md->scr.H3);
2922  DevUpdate();
2923 }
2924 
2925 
2926 static void
2928 
2929 /* save points for redraw during interactive plot */
2930 struct chkpts *p;
2931 int v1,v2;
2932 char pf;
2933 {
2934  if (p->size == 0) {
2935  p->rsize = 100;
2936  p->v1 = tmalloc(p->rsize);
2937  p->v2 = tmalloc(p->rsize);
2938  p->pf = tmalloc(p->rsize);
2939  }
2940  if (p->size > p->rsize) {
2941  p->rsize += 100;
2942  p->v1 = trealloc(p->v1,p->rsize);
2943  p->v2 = trealloc(p->v2,p->rsize);
2944  p->pf = trealloc(p->pf,p->rsize);
2945  }
2946  p->v1[p->size] = (char) v1;
2947  p->v2[p->size] = (char) v2;
2948  p->pf[p->size] = pf;
2949  p->size++;
2950 }
2951 
2952 
2953 static void
2954 ebox(xl,yl,xu,yu)
2955 
2956 int xl, yl, xu, yu;
2957 {
2958  DevLine(xl,yl,xu,yl);
2959  DevLine(xu,yl,xu,yu);
2960  DevLine(xu,yu,xl,yu);
2961  DevLine(xl,yu,xl,yl);
2962 }
2963 
2964 
2965 static void
2966 xbox(xl,yl,xu,yu)
2967 
2968 int xl, yl, xu, yu;
2969 {
2970  ebox(xl,yl,xu,yu);
2971  DevLine(xl,yl,xu,yu);
2972  DevLine(xl,yu,xu,yl);
2973 }
2974 
2975 
2976 static void
2977 pbox(xl,yl,xu,yu)
2978 
2979 int xl, yl, xu, yu;
2980 {
2981  ebox(xl,yl,xu,yu);
2982  DevLine(xl+(xu-xl)/4,yl+(yu-yl)/2,xu-(xu-xl)/4,yl+(yu-yl)/2);
2983  DevLine(xl+(xu-xl)/2,yl+(yu-yl)/4,xl+(xu-xl)/2,yu-(yu-yl)/4);
2984 }
2985 
2986 
2987 /*********************************************************************
2988  *
2989  * An echo command that puts text to the graphics window when needed.
2990  *
2991  *********************************************************************/
2992 
2993 
2994 void
2995 com_echo(wlist)
2996 
2997 /* Put the text on the screen, supports graphics mode. */
2998 wordlist *wlist;
2999 {
3000  char *s, *ss, buf[BSIZE_SP];
3001  bool nl = true;
3002  int i = 0;
3003 
3004  if (wlist && eq(wlist->wl_word, "-n")) {
3005  wlist = wlist->wl_next;
3006  nl = false;
3007  }
3008 
3009  while (wlist) {
3010  ss = s = copy(wlist->wl_word);
3011  cp_unquote(s);
3012  while (*s && (i < BSIZE_SP-1))
3013  buf[i++] = *s++;
3014  tfree(ss);
3015  if (wlist->wl_next && (i < BSIZE_SP-3))
3016  buf[i++] = ' ';
3017  wlist = wlist->wl_next;
3018  }
3019  buf[i] = '\0';
3020 
3021  if (dispdev) {
3022  /* a little tricky */
3023  if (!dispdev->windows) {
3024  if (EchoGraph) {
3025  /* doing iplot, covers full screen
3026  * send text to it
3027  */
3028  goto tograf;
3029  }
3030  else if (SCEDactive()) {
3031  ShowPrompt(buf);
3032  return;
3033  }
3034  }
3035  else {
3036  if (SCEDactive()) {
3037  ShowPrompt(buf);
3038  return;
3039  }
3040  if (DOIPLOT && EchoGraph != NULL) {
3041  /* send text to interactive mplot only */
3042  goto tograf;
3043  }
3044  }
3045  }
3046  fputs(buf, cp_out);
3047  if (nl)
3048  fputs("\n", cp_out);
3049  return;
3050 
3051 tograf:
3052  buf[64] = '\0';
3053  PushGraphContext(EchoGraph);
3054  DevSetColor(0);
3055  DevBox(0,0,EchoGraph->fontwidth*64,EchoGraph->fontheight);
3056  DevSetColor(5);
3057  DevText(buf,0,0);
3058  DevUpdate();
3059  PopGraphContext();
3060  return;
3061 }
3062 
3063 
3064 void
3066 
3067 /* handle messages during analysis */
3068 char *msg;
3069 {
3070  wordlist wl;
3071 
3072  wl.wl_next = NULL;
3073  wl.wl_prev = NULL;
3074  wl.wl_word = msg;
3075  com_echo(&wl);
3076 }
static void addplot()
float * xdata
Definition: newgraf.h:109
struct gframe xcurr
Definition: newgraf.h:63
int x
Definition: newgraf.h:98
static char buf[MAXPROMPT]
Definition: arg.c:18
static void free_graf()
int mp_done(int id)
Definition: newgraf.c:2793
#define BSIZE_SP
Definition: misc.h:19
#define eq(a, b)
Definition: misc.h:29
int ciprefix()
static int set_cursor()
struct gtrace tdata[PNUM]
Definition: newgraf.h:113
static char * errmsg_gralloc
Definition: newgraf.c:155
bool cp_getvar(char *n, int t, char *r)
Definition: help.c:184
static int newscale()
static int interval()
static void interpolateX()
double maxv2
Definition: newgraf.h:138
void plot_extend()
double end
Definition: newgraf.h:41
char * GRDATA
Definition: ftegraph.h:26
bool set
Definition: newgraf.h:99
struct graph::@2 absolute
void WARNmsg(char *msg)
Definition: newgraf.c:3065
char * strcpy()
struct screen scr
Definition: newgraf.h:114
static void interpolateY()
Definition: cddefs.h:119
void graf_slopelocation()
OPTION option
Definition: ftegraph.h:187
double minv2
Definition: newgraf.h:137
int mp_init(int delta1, int delta2, double v1min, double v1max, double v2min, double v2max)
Definition: newgraf.c:2681
#define FIELD
Definition: newgraf.h:15
struct dvlist * ft_dvlist()
double minv1
Definition: newgraf.h:135
void DevSetColor()
if(TDesc==NULL)
Definition: cd.c:1326
Definition: ftedata.h:49
Definition: xforms.c:16
#define PNUM
Definition: newgraf.h:12
void DevText()
struct pnode * ft_getpnames()
DISPDEVICE * dispdev
Definition: display.c:112
bool iplot_point()
Definition: newgraf.c:602
static void mp_display()
int type
Definition: newgraf.h:71
float * data
Definition: newgraf.h:74
static void combin()
Definition: cpstd.h:29
static double e
Definition: vectors.c:17
struct gframe xfull
Definition: newgraf.h:62
static void writeg()
FILE * p
Definition: proc2mod.c:48
struct _keyed * next
Definition: ftegraph.h:129
double ymin[PNUM+4]
Definition: newgraf.h:60
double max
Definition: newgraf.h:43
Definition: ftedata.h:61
char * v1
Definition: newgraf.h:123
int height
Definition: ftegraph.h:45
bool hardcopy
Definition: plotdev.h:64
int iplot_begin(struct dvlist *dl0, struct plot *pl)
Definition: newgraf.c:533
void DevSetLinestyle()
void DevDefineLinestyle()
static void xbox()
Definition: library.c:18
Definition: cddefs.h:312
int numtr
Definition: newgraf.h:104
GRDATA(* copydata)()
Definition: ftegraph.h:72
static char * errmsg_newvp
Definition: newgraf.c:156
int v_dims[MAXDIMS]
Definition: ftedata.h:41
void com_mplot(wordlist *wl)
Definition: newgraf.c:2323
Definition: newgraf.h:103
int size
Definition: newgraf.h:128
int DevNewViewport()
int lflg
Definition: newgraf.h:51
Definition: cddefs.h:215
static GRDATA copygraf()
void DevClear()
Definition: display.c:234
int mp_mark(int id, char pf)
Definition: newgraf.c:2758
#define alloc(type)
Definition: cdmacs.h:21
#define OPT_help
Definition: newgraf.h:26
FILE * m
Definition: proc2mod.c:47
complex * v_compdata
Definition: ftedata.h:29
void cp_unquote()
char * copy()
double scale[2]
Definition: newgraf.h:72
#define GRAF_V
Definition: newgraf.h:34
int mp_where(int id, int d1, int d2)
Definition: newgraf.c:2737
#define LOGTST
Definition: newgraf.c:56
struct dvlist * dl_next
Definition: ftedata.h:51
struct gref ref
Definition: newgraf.h:115
#define OPT_b
Definition: newgraf.h:22
void wl_free()
char name[FIELD+2]
Definition: newgraf.h:70
FILE * cp_err
Definition: help.c:101
bool windows
Definition: plotdev.h:61
char * tmalloc()
int cycles
Definition: newgraf.h:68
#define NUMOUTPTS
Definition: newgraf.c:59
int numpt
Definition: newgraf.h:105
struct wordlist * wl_prev
Definition: cpstd.h:24
void DevBox()
int fontwidth
Definition: ftegraph.h:82
static void redraw()
static bool Running
Definition: newgraf.c:61
struct dvlist * dlist
Definition: newgraf.h:112
static void set_scale()
#define OPT_hcpy
Definition: newgraf.h:30
Definition: cddefs.h:237
void DevHalt()
Definition: display.c:226
#define tfree(x)
Definition: cdmacs.h:22
static void fpick()
static void extpts()
void txfree()
int pl_active
Definition: ftedata.h:75
struct dvec * pl_scale
Definition: ftedata.h:68
void PushGraphContext()
#define NULL
Definition: spdefs.h:121
int graphtype
Definition: ftegraph.h:31
int opt
Definition: newgraf.h:106
int graphid
Definition: ftegraph.h:30
int XU
Definition: newgraf.h:87
struct gscale * scale
Definition: newgraf.h:110
GRDATA plotdata
Definition: ftegraph.h:33
void com_graf(wordlist *wl)
Definition: newgraf.c:159
#define OPT_add
Definition: newgraf.h:29
static bool is_monotonic()
static void init()
FILE * cp_out
Definition: help.c:101
struct plot * v_plot
Definition: ftedata.h:42
#define OPT_step
Definition: newgraf.h:31
static void draw()
struct dvec * v_scale
Definition: ftedata.h:45
static GRDATA mp_copy()
Definition: newgraf.h:142
int W
Definition: newgraf.h:81
Definition: ftegraph.h:29
struct plot * plot
Definition: newgraf.h:111
void DevPixel()
void DevLine()
int ncells
Definition: newgraf.h:48
static void ebox()
bool iniplot
Definition: newgraf.h:108
int fontheight
Definition: ftegraph.h:82
static double c
Definition: vectors.c:16
#define VT_STRING
Definition: cpstd.h:63
struct chkpts * next
Definition: newgraf.h:139
char * KbEdit(char *s, int x, int y, int bg, int fg, int cc)
Definition: main.c:280
int yc
Definition: newgraf.h:131
#define isreal(v)
Definition: ftedata.h:54
void DevSetGhost()
Definition: ftedata.h:24
struct dvec * dl_dvec
Definition: ftedata.h:50
static void proc_option()
#define GRAF_I
Definition: newgraf.h:35
GRAPH * FindGraph()
int H
Definition: newgraf.h:82
static bool DOIPLOT
Definition: newgraf.c:2320
double ymax[PNUM+4]
Definition: newgraf.h:61
static int ymap()
GRAPH * EchoGraph
Definition: newgraf.c:53
char * v_name
Definition: ftedata.h:25
int YU
Definition: newgraf.h:89
static void what_now()
static void xy_pick()
Definition: cddefs.h:142
void DevUpdate()
Definition: display.c:359
int X
Definition: newgraf.h:79
struct graph::_keyed * keyed
int lasty
Definition: newgraf.h:73
void(* destroy)()
Definition: ftegraph.h:71
Definition: cpstd.h:21
static void displxy()
char * pf
Definition: newgraf.h:125
static void ghost_mark()
static void writef()
static char * ecvt12()
void PopGraphContext()
Definition: graphdb.c:270
char * kw_mplot_cur
Definition: options.c:376
int DestroyGraph()
Definition: cddefs.h:177
int DevGetchar()
int YL
Definition: newgraf.h:88
static void set_scale_4()
void DevInput()
#define swap(a, b)
Definition: hplaser.c:34
char * v2
Definition: newgraf.h:124
void vec_dlfree()
int lastx
Definition: newgraf.h:107
int XL
Definition: newgraf.h:86
int numcolors
Definition: plotdev.h:67
static char * errmsg_scale
Definition: newgraf.c:154
#define OPT_n
Definition: newgraf.h:18
#define OPT_x
Definition: newgraf.h:20
double maxv1
Definition: newgraf.h:136
static void plpts()
double min
Definition: newgraf.h:42
void com_echo(wordlist *wlist)
Definition: newgraf.c:2995
Definition: netlist.c:477
#define OPT_t
Definition: newgraf.h:23
static void graf_setmark()
static int alpha_only()
#define OPT_p
Definition: newgraf.h:24
static void pbox()
struct screen scr
Definition: newgraf.h:144
#define GRAF_O
Definition: newgraf.h:36
#define GR_MPLT
Definition: ftegraph.h:22
int d1
Definition: newgraf.h:133
struct wordlist * wl_next
Definition: cpstd.h:23
char delta1
Definition: newgraf.h:126
#define OPT_mark
Definition: newgraf.h:28
int v_numdims
Definition: ftedata.h:40
GRAPH * currentgraph
Definition: graphdb.c:21
int d
Definition: newgraf.h:132
int width
Definition: ftegraph.h:45
static void displ()
struct chkpts * pts
Definition: newgraf.h:143
static void addit()
char * wl_word
Definition: cpstd.h:22
void(* redraw)()
Definition: ftegraph.h:70
Definition: newgraf.h:47
static void help()
void graf_newdisplay()
int v_length
Definition: ftedata.h:34
int W2
Definition: newgraf.h:83
enum Active SCEDactive()
Definition: scedstub.c:63
double * v_realdata
Definition: ftedata.h:28
static void mp_free()
static void init_viewport()
#define OPT_X
Definition: newgraf.h:21
char delta2
Definition: newgraf.h:127
static void minmax()
Definition: cddefs.h:192
int H2
Definition: newgraf.h:84
#define OPT_N
Definition: newgraf.h:19
int Y
Definition: newgraf.h:80
void iplot_end()
Definition: newgraf.c:709
static void axes()
void ShowPrompt(char *str)
Definition: scedstub.c:71
Definition: cddefs.h:109
double beg
Definition: newgraf.h:40
static void graf_display()
int d2
Definition: newgraf.h:134
char * trealloc()
static char INBUF[128]
Definition: newgraf.c:63
int xc
Definition: newgraf.h:130
#define GR_GRAF
Definition: ftegraph.h:21
static void chkpts_free()
void ft_hardcopy()
GRAPH * NewGraph()
Definition: graphdb.c:59
Definition: newgraf.h:78
#define realpart(cval)
Definition: cpstd.h:35
#define OPT_Xx
Definition: newgraf.h:25
int XS
Definition: newgraf.h:90
Definition: fteparse.h:16
wordlist * wl_copy()