2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/ngspice.h"
|
|
|
|
|
#include "ngspice/bool.h"
|
2019-12-11 01:47:00 +01:00
|
|
|
#include "ngspice/dstring.h"
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/wordlist.h"
|
|
|
|
|
#include "ngspice/graph.h"
|
|
|
|
|
#include "ngspice/cpdefs.h"
|
|
|
|
|
#include "ngspice/pnode.h"
|
|
|
|
|
#include "ngspice/sim.h"
|
|
|
|
|
#include "ngspice/fteext.h"
|
2000-05-13 19:28:16 +02:00
|
|
|
|
2000-06-27 18:09:02 +02:00
|
|
|
#include <circuits.h>
|
|
|
|
|
|
2000-06-16 21:04:15 +02:00
|
|
|
#include "plotit.h"
|
2019-12-11 01:47:00 +01:00
|
|
|
#include "points.h"
|
2000-06-16 21:04:15 +02:00
|
|
|
#include "agraf.h"
|
2008-03-22 14:10:46 +01:00
|
|
|
#include "gnuplot.h"
|
2000-06-16 21:04:15 +02:00
|
|
|
#include "graf.h"
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
static bool sameflag;
|
2020-01-11 11:25:14 +01:00
|
|
|
/* All these things are static so that "samep" will work.
|
|
|
|
|
They are outside of plotit() to allow deleting */
|
|
|
|
|
static double *xcompress = NULL, *xindices = NULL;
|
|
|
|
|
static double *xlim = NULL, *ylim = NULL;
|
|
|
|
|
static double *xdelta = NULL, *ydelta = NULL;
|
|
|
|
|
static char *xlabel = NULL, *ylabel = NULL, *title = NULL;
|
2008-08-27 15:39:05 +02:00
|
|
|
#ifdef TCL_MODULE
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/tclspice.h"
|
2008-08-27 15:39:05 +02:00
|
|
|
#endif
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2020-01-11 11:25:14 +01:00
|
|
|
/* remove the malloced parameters upon ngspice quit */
|
|
|
|
|
void pl_rempar(void)
|
|
|
|
|
{
|
|
|
|
|
txfree(xcompress);
|
|
|
|
|
txfree(xindices);
|
|
|
|
|
txfree(xlim);
|
|
|
|
|
txfree(ylim);
|
|
|
|
|
txfree(xdelta);
|
|
|
|
|
txfree(ydelta);
|
|
|
|
|
txfree(xlabel);
|
|
|
|
|
txfree(ylabel);
|
|
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
static struct dvec *vec_self(struct dvec *v);
|
|
|
|
|
static struct dvec *vec_scale(struct dvec *v);
|
|
|
|
|
static void find_axis_limits(double *lim, bool oneval, bool f_real,
|
|
|
|
|
struct dvec *vecs,
|
|
|
|
|
struct dvec *(*p_get_axis_dvec)(struct dvec *dvec),
|
|
|
|
|
double *lims);
|
|
|
|
|
|
|
|
|
|
|
2000-06-16 21:04:15 +02:00
|
|
|
/* This routine gets parameters from the command line, which are of
|
|
|
|
|
* the form "name number ..." It returns a pointer to the parameter
|
2019-12-11 01:47:00 +01:00
|
|
|
* values.
|
|
|
|
|
*
|
|
|
|
|
* Parameters
|
|
|
|
|
* wl: Wordlist prefixed with dummy node from which the parameter value or
|
|
|
|
|
* values is to be extracted. On return, the nodes corresponding to the
|
|
|
|
|
* name of the parameter and the following value nodes are removed.
|
|
|
|
|
* name: Name of parameter
|
|
|
|
|
* number: number of values for the parameter
|
|
|
|
|
*
|
|
|
|
|
* Return values
|
|
|
|
|
* Allocated list of values extracted from the wordlist
|
|
|
|
|
*
|
|
|
|
|
* Remarks
|
|
|
|
|
* The dummy node at the front of wl guarantees that removing the nodes
|
|
|
|
|
* for this parameter will not change the first node of the wordlist.
|
|
|
|
|
*/
|
|
|
|
|
static double *getlims(wordlist *wl, const char *name, int number)
|
2000-06-16 21:04:15 +02:00
|
|
|
{
|
2019-12-11 01:47:00 +01:00
|
|
|
wordlist *wk;
|
2000-06-16 21:04:15 +02:00
|
|
|
int n;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (number < 1) { /* Parameter takes no argument */
|
|
|
|
|
return (double *) NULL;
|
|
|
|
|
}
|
2011-07-24 22:30:44 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Locate parameter name in the wordlist */
|
|
|
|
|
wordlist * const beg = wl_find(name, wl->wl_next);
|
|
|
|
|
if (!beg) { /* not foumd */
|
|
|
|
|
return (double *) NULL;
|
|
|
|
|
}
|
2011-07-24 22:30:44 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
wk = beg->wl_next; /* Start of values for parameter */
|
2011-07-24 22:30:44 +02:00
|
|
|
|
2019-12-06 22:04:45 +01:00
|
|
|
double * const d = TMALLOC(double, number); /* alloc for returned vals */
|
2011-07-24 22:30:44 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
for (n = 0; n < number; n++) { /* loop over values */
|
2011-07-24 22:30:44 +02:00
|
|
|
char *ss;
|
|
|
|
|
|
|
|
|
|
if (!wk) {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Syntax error: not enough parameters for \"%s\".\n", name);
|
|
|
|
|
txfree(d);
|
2019-12-06 22:04:45 +01:00
|
|
|
return (double *) NULL;
|
2000-06-16 21:04:15 +02:00
|
|
|
}
|
2011-07-24 22:30:44 +02:00
|
|
|
|
|
|
|
|
ss = wk->wl_word;
|
2019-12-06 22:04:45 +01:00
|
|
|
if (ft_numparse(&ss, FALSE, d + n) < 0) { /* put val in d[n] */
|
2011-07-24 22:30:44 +02:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Syntax error: bad parameters for \"%s\".\n", name);
|
|
|
|
|
txfree(d);
|
2019-12-06 22:04:45 +01:00
|
|
|
return (double *) NULL;
|
2011-07-24 22:30:44 +02:00
|
|
|
}
|
|
|
|
|
|
2012-07-29 12:40:00 +02:00
|
|
|
wk = wk->wl_next;
|
2019-12-06 22:04:45 +01:00
|
|
|
} /* end of loop over numbers */
|
2011-07-24 22:30:44 +02:00
|
|
|
|
2019-12-06 22:04:45 +01:00
|
|
|
wl_delete_slice(beg, wk); /* remove param name and its value nodes */
|
2011-07-24 22:30:44 +02:00
|
|
|
|
|
|
|
|
return d;
|
2019-12-06 22:04:45 +01:00
|
|
|
} /* end of function getlims */
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
|
2000-06-16 21:04:15 +02:00
|
|
|
/* Extend a data vector to length by replicating the last element, or
|
2019-12-11 01:47:00 +01:00
|
|
|
* truncate it if it is too long. If the vector is empty, it is
|
|
|
|
|
* extended with NAN */
|
|
|
|
|
static void xtend(struct dvec *v, int length)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
2000-06-16 21:04:15 +02:00
|
|
|
int i;
|
|
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (v->v_length == length) { /* no change required */
|
2000-06-16 21:04:15 +02:00
|
|
|
return;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (v->v_length > length) { /* too long */
|
2015-12-28 20:28:39 +01:00
|
|
|
dvec_trunc(v, length);
|
2000-06-16 21:04:15 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Else must be extended */
|
2015-12-26 19:43:54 +01:00
|
|
|
i = v->v_length;
|
|
|
|
|
|
2015-12-28 20:27:52 +01:00
|
|
|
dvec_realloc(v, length, NULL);
|
2015-12-28 20:24:11 +01:00
|
|
|
|
|
|
|
|
if (isreal(v)) {
|
|
|
|
|
double d = NAN;
|
2019-12-11 01:47:00 +01:00
|
|
|
if (i > 0) { /* At least one value */
|
2015-12-26 19:43:18 +01:00
|
|
|
d = v->v_realdata[i - 1];
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
while (i < length) { /* Fill new elements at end */
|
2000-06-16 21:04:15 +02:00
|
|
|
v->v_realdata[i++] = d;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2015-12-26 19:44:41 +01:00
|
|
|
ngcomplex_t c = {NAN, NAN};
|
2019-12-11 01:47:00 +01:00
|
|
|
if (i > 0) { /* At least one value */
|
2015-12-26 19:43:18 +01:00
|
|
|
c = v->v_compdata[i - 1];
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
while (i < length) { /* Fill new elements at end */
|
2015-12-26 19:44:33 +01:00
|
|
|
v->v_compdata[i++] = c;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-06-16 21:04:15 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
} /* end of function xtend */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2000-06-16 21:04:15 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Collapse every *xcomp elements into one, and use only the elements
|
|
|
|
|
* between xind[0] and xind[1]. Decimate would be a better description
|
|
|
|
|
* than compress */
|
|
|
|
|
static void compress(struct dvec *d, double *xcomp, double *xind)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
2000-06-16 21:04:15 +02:00
|
|
|
if (xind) {
|
2019-12-11 01:47:00 +01:00
|
|
|
int newlen;
|
|
|
|
|
const int ilo = (int) xind[0];
|
|
|
|
|
const int ihi = (int) xind[1];
|
2010-11-06 19:08:27 +01:00
|
|
|
if ((ihi >= ilo) && (ilo > 0) && (ilo < d->v_length) &&
|
2012-07-23 19:17:25 +02:00
|
|
|
(ihi > 1) && (ihi <= d->v_length)) {
|
2000-06-16 21:04:15 +02:00
|
|
|
newlen = ihi - ilo;
|
|
|
|
|
if (isreal(d)) {
|
2010-11-06 19:08:27 +01:00
|
|
|
double *dd = TMALLOC(double, newlen);
|
2016-07-23 09:13:55 +02:00
|
|
|
memcpy(dd, d->v_realdata + ilo, (size_t) newlen * sizeof(double));
|
2015-12-28 20:27:52 +01:00
|
|
|
dvec_realloc(d, newlen, dd);
|
2000-06-16 21:04:15 +02:00
|
|
|
} else {
|
2010-11-06 19:08:27 +01:00
|
|
|
ngcomplex_t *cc = TMALLOC(ngcomplex_t, newlen);
|
2016-07-23 09:13:55 +02:00
|
|
|
memcpy(cc, d->v_compdata + ilo, (size_t) newlen * sizeof(ngcomplex_t));
|
2015-12-28 20:27:52 +01:00
|
|
|
dvec_realloc(d, newlen, cc);
|
2000-06-16 21:04:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2000-06-16 21:04:15 +02:00
|
|
|
if (xcomp) {
|
2019-12-11 01:47:00 +01:00
|
|
|
const int cfac = (int) *xcomp;
|
2000-06-16 21:04:15 +02:00
|
|
|
if ((cfac > 1) && (cfac < d->v_length)) {
|
2019-12-11 01:47:00 +01:00
|
|
|
int i, j;
|
|
|
|
|
const int n = d->v_length;
|
|
|
|
|
for (i = 0, j = 0; j < n; i++, j += cfac) {
|
|
|
|
|
if (isreal(d)) {
|
|
|
|
|
d->v_realdata[i] = d->v_realdata[j];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
d->v_compdata[i] = d->v_compdata[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-28 20:28:39 +01:00
|
|
|
dvec_trunc(d, i);
|
2000-06-16 21:04:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
} /* end of function compress */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Check for and remove a one-word keyword (without an argument). */
|
|
|
|
|
static bool getflag(wordlist *wl, const char *name)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
2012-07-28 19:55:09 +02:00
|
|
|
wl = wl_find(name, wl->wl_next);
|
2012-07-28 12:29:19 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!wl) {
|
2012-07-28 12:29:19 +02:00
|
|
|
return FALSE;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-28 12:29:19 +02:00
|
|
|
|
2012-07-29 12:40:00 +02:00
|
|
|
wl_delete_slice(wl, wl->wl_next);
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2012-07-28 12:29:19 +02:00
|
|
|
return TRUE;
|
2019-12-11 01:47:00 +01:00
|
|
|
} /* end of function getflag */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a copy of the value of parameter and deletes the keyword and
|
|
|
|
|
* value nodes in the wordlist. The search for the keyword begins after
|
|
|
|
|
* the node wl. (This behavior is due to a dummy node being added
|
|
|
|
|
* to the front of the wordlist.)
|
|
|
|
|
*
|
|
|
|
|
* Parameters
|
|
|
|
|
* wl: wordlist to process
|
|
|
|
|
* sz_keyword: keyword to locate
|
|
|
|
|
*
|
|
|
|
|
* Return values
|
|
|
|
|
* NULL: The keyword was not found or its value was missing
|
|
|
|
|
* allocation consisting of the value node as a string.
|
|
|
|
|
*
|
|
|
|
|
* Example
|
|
|
|
|
* wl= "a" <-> "xlabel" <-> "voltage" <-> "b"
|
|
|
|
|
* sz_keyword = "xlabel"
|
|
|
|
|
* On return,
|
|
|
|
|
* wl= "a" <-> "b"
|
|
|
|
|
* return value = "voltage"
|
|
|
|
|
*/
|
|
|
|
|
static char *getword(wordlist *wl, const char *sz_keyword)
|
2000-06-16 21:04:15 +02:00
|
|
|
{
|
2019-12-11 01:47:00 +01:00
|
|
|
wordlist *kw = wl_find(sz_keyword, wl->wl_next);
|
2012-07-28 12:29:19 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (kw == (wordlist *) NULL) { /* not found */
|
|
|
|
|
return (char *) NULL;
|
|
|
|
|
}
|
2012-07-28 12:29:19 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
wordlist *value = kw->wl_next; /* value follows keyword */
|
|
|
|
|
if (value == (wordlist *) NULL) { /* no value for keyword */
|
2012-07-28 12:29:19 +02:00
|
|
|
fprintf(cp_err,
|
2019-12-11 01:47:00 +01:00
|
|
|
"Syntax error: missing value for plot keyword \"%s\".\n",
|
|
|
|
|
sz_keyword);
|
|
|
|
|
return (char *) NULL;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
char *sz_ret = copy(value->wl_word); /* save value */
|
|
|
|
|
wl_delete_slice(kw, value->wl_next); /* remove kw and val nodes */
|
2012-07-28 12:29:19 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
return sz_ret;
|
|
|
|
|
} /* end of funtion getword */
|
2012-07-28 12:29:19 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The common routine for all plotting commands. This does hardcopy
|
2019-12-11 01:47:00 +01:00
|
|
|
* and graphics plotting.
|
|
|
|
|
*
|
|
|
|
|
* Parameters
|
|
|
|
|
* wl: plotting command
|
|
|
|
|
* hcopy: File used for plotting
|
|
|
|
|
* devname: "Device" for plotting, e.g. Gnuplot
|
|
|
|
|
*/
|
|
|
|
|
bool plotit(wordlist *wl, const char *hcopy, const char *devname)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!wl) { /* no wordlist -> cannot plot */
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-16 11:52:59 +01:00
|
|
|
static double *xprevgraph = NULL;
|
2020-02-10 17:21:46 +01:00
|
|
|
int prevgraph = 0;
|
2020-02-16 11:52:59 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
static bool nointerp = FALSE;
|
|
|
|
|
static GRIDTYPE gtype = GRID_LIN;
|
|
|
|
|
static PLOTTYPE ptype = PLOT_LIN;
|
|
|
|
|
|
|
|
|
|
bool gfound = FALSE, pfound = FALSE, oneval = FALSE;
|
2019-12-11 01:47:00 +01:00
|
|
|
double ylims[2], xlims[2];
|
2012-10-01 17:59:40 +02:00
|
|
|
struct pnode *pn, *names;
|
2015-08-15 21:04:58 +02:00
|
|
|
struct dvec *d = NULL, *vecs = NULL, *lv, *lastvs = NULL;
|
2000-04-27 22:03:57 +02:00
|
|
|
char *xn;
|
2015-12-15 19:58:11 +01:00
|
|
|
int i, y_type, xt;
|
2019-12-11 01:47:00 +01:00
|
|
|
wordlist *wwl;
|
2009-03-08 13:10:15 +01:00
|
|
|
char *nxlabel = NULL, *nylabel = NULL, *ntitle = NULL;
|
2000-04-27 22:03:57 +02:00
|
|
|
double tstep, tstart, tstop, ttime;
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Save start of vectors on entry for cleaning up junk left behind
|
|
|
|
|
* by ft_getpnames() */
|
|
|
|
|
struct dvec *dv_head_orig =
|
|
|
|
|
plot_cur ? plot_cur->pl_dvecs : (struct dvec *) NULL;
|
|
|
|
|
|
|
|
|
|
/* Dstring for building plot command */
|
|
|
|
|
DS_CREATE(ds_cline, 200);
|
|
|
|
|
int rc_ds = 0; /* return code from dstring operations */
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/* return value, error by default */
|
|
|
|
|
bool rtn = FALSE;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Create a copy of the input wordlist with a dummy node at the
|
|
|
|
|
* beginning of the list. The dummy node is used to ensure that
|
|
|
|
|
* the keyword and value nodes and the labels and title nodes
|
|
|
|
|
* that are removed are not at the beginning of the list.
|
|
|
|
|
* As a result, the head of the list remains unchanged while
|
|
|
|
|
* the undesired nodes are being removed. */
|
2012-07-28 19:55:09 +02:00
|
|
|
wl = wl_cons(NULL, wl_copy(wl));
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2012-07-23 19:17:25 +02:00
|
|
|
/* First get the command line, without the limits.
|
2019-12-11 01:47:00 +01:00
|
|
|
Wii be used for zoomed windows. Besides returning the values,
|
|
|
|
|
which are not wanted here, the getlims calls remove the
|
|
|
|
|
nodes for the keyword and its value from wwl. */
|
2000-04-27 22:03:57 +02:00
|
|
|
wwl = wl_copy(wl);
|
2019-12-11 01:47:00 +01:00
|
|
|
txfree(getlims(wwl, "xl", 2));
|
|
|
|
|
txfree(getlims(wwl, "xlimit", 2));
|
|
|
|
|
txfree(getlims(wwl, "yl", 2));
|
|
|
|
|
txfree(getlims(wwl, "ylimit", 2));
|
|
|
|
|
|
|
|
|
|
/* Save title, xlabel and ylabel for use later and remove the
|
|
|
|
|
* corresponding nodes from the wordlist */
|
2009-03-08 13:10:15 +01:00
|
|
|
nxlabel = getword(wwl, "xlabel");
|
|
|
|
|
nylabel = getword(wwl, "ylabel");
|
|
|
|
|
ntitle = getword(wwl, "title");
|
2020-02-10 17:21:46 +01:00
|
|
|
/* remove sgraphid */
|
2020-02-16 11:52:59 +01:00
|
|
|
txfree(getlims(wwl, "sgraphid", 1));
|
2019-12-11 01:47:00 +01:00
|
|
|
|
|
|
|
|
/* Build the plot command. This construction had been done with wordlists
|
|
|
|
|
* and reversing, and flattening, but it is clearer as well as much more
|
|
|
|
|
* efficient to use a dstring. */
|
2020-01-11 11:25:14 +01:00
|
|
|
char *flatstr = wl_flatten(wwl->wl_next);
|
|
|
|
|
rc_ds |= ds_cat_printf(&ds_cline, "plot %s", flatstr);
|
2000-04-27 22:03:57 +02:00
|
|
|
wl_free(wwl);
|
2020-01-11 11:25:14 +01:00
|
|
|
tfree(flatstr);
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Add title, xlabel or ylabel, if available, with quotes ''. */
|
2009-03-08 13:10:15 +01:00
|
|
|
if (nxlabel) {
|
2019-12-11 01:47:00 +01:00
|
|
|
rc_ds |= ds_cat_printf(&ds_cline, " xlabel '%s'", nxlabel);
|
2012-09-20 20:30:53 +02:00
|
|
|
tfree(nxlabel);
|
2009-03-08 13:10:15 +01:00
|
|
|
}
|
|
|
|
|
if (nylabel) {
|
2019-12-11 01:47:00 +01:00
|
|
|
rc_ds |= ds_cat_printf(&ds_cline, " ylabel '%s'", nylabel);
|
|
|
|
|
tfree(nxlabel);
|
2009-03-08 13:10:15 +01:00
|
|
|
}
|
|
|
|
|
if (ntitle) {
|
2019-12-11 01:47:00 +01:00
|
|
|
rc_ds |= ds_cat_printf(&ds_cline, " title '%s'", ntitle);
|
2012-09-20 20:30:53 +02:00
|
|
|
tfree(ntitle);
|
2009-03-08 13:10:15 +01:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
if (rc_ds != 0) {
|
|
|
|
|
fprintf(cp_err, "Unable to build plot command line.\n");
|
|
|
|
|
goto quit1;
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2014-11-30 22:15:37 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Now extract all the parameters. */
|
|
|
|
|
sameflag = getflag(wl, "samep");
|
|
|
|
|
|
|
|
|
|
if (!sameflag || !xlim) {
|
2020-01-11 11:25:14 +01:00
|
|
|
txfree(xlim);
|
2000-04-27 22:03:57 +02:00
|
|
|
xlim = getlims(wl, "xl", 2);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!xlim) {
|
2000-04-27 22:03:57 +02:00
|
|
|
xlim = getlims(wl, "xlimit", 2);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getlims(wl, "xl", 2));
|
|
|
|
|
txfree(getlims(wl, "xlimit", 2));
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sameflag || !ylim) {
|
2020-01-11 11:25:14 +01:00
|
|
|
txfree(ylim);
|
2000-04-27 22:03:57 +02:00
|
|
|
ylim = getlims(wl, "yl", 2);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!ylim) {
|
2000-04-27 22:03:57 +02:00
|
|
|
ylim = getlims(wl, "ylimit", 2);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getlims(wl, "yl", 2));
|
|
|
|
|
txfree(getlims(wl, "ylimit", 2));
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sameflag || !xcompress) {
|
2020-01-11 11:25:14 +01:00
|
|
|
txfree(xcompress);
|
2000-04-27 22:03:57 +02:00
|
|
|
xcompress = getlims(wl, "xcompress", 1);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!xcompress) {
|
2000-04-27 22:03:57 +02:00
|
|
|
xcompress = getlims(wl, "xcomp", 1);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getlims(wl, "xcompress", 1));
|
|
|
|
|
txfree(getlims(wl, "xcomp", 1));
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sameflag || !xindices) {
|
2020-01-11 11:25:14 +01:00
|
|
|
txfree(xindices);
|
2000-04-27 22:03:57 +02:00
|
|
|
xindices = getlims(wl, "xindices", 2);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!xindices) {
|
2000-04-27 22:03:57 +02:00
|
|
|
xindices = getlims(wl, "xind", 2);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getlims(wl, "xindices", 2));
|
|
|
|
|
txfree(getlims(wl, "xind", 2));
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sameflag || !xdelta) {
|
2020-01-11 11:25:14 +01:00
|
|
|
txfree(xdelta);
|
2000-04-27 22:03:57 +02:00
|
|
|
xdelta = getlims(wl, "xdelta", 1);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!xdelta) {
|
2000-04-27 22:03:57 +02:00
|
|
|
xdelta = getlims(wl, "xdel", 1);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
} else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getlims(wl, "xdelta", 1));
|
|
|
|
|
txfree(getlims(wl, "xdel", 1));
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!sameflag || !ydelta) {
|
2020-01-11 11:25:14 +01:00
|
|
|
txfree(ydelta);
|
2000-04-27 22:03:57 +02:00
|
|
|
ydelta = getlims(wl, "ydelta", 1);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!ydelta) {
|
2000-04-27 22:03:57 +02:00
|
|
|
ydelta = getlims(wl, "ydel", 1);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getlims(wl, "ydelta", 1));
|
|
|
|
|
txfree(getlims(wl, "ydel", 1));
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2020-02-10 17:21:46 +01:00
|
|
|
if (!sameflag || !xprevgraph) {
|
|
|
|
|
xprevgraph = getlims(wl, "sgraphid", 1);
|
|
|
|
|
if(xprevgraph)
|
|
|
|
|
prevgraph = (int)(*xprevgraph);
|
|
|
|
|
} else {
|
|
|
|
|
txfree(getlims(wl, "sgraphid", 1));
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Get the grid type and the point type. Note we can't do if-else
|
|
|
|
|
* here because we want to catch all the grid types.
|
|
|
|
|
*/
|
|
|
|
|
if (getflag(wl, "lingrid")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"lingrid\" is ignored.\n");
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LIN;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "loglog")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"loglog\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LOGLOG;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "nogrid")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"nogrid\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_NONE;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "linear")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"linear\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LIN;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "xlog")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2015-05-14 15:56:24 +02:00
|
|
|
if (gtype == GRID_YLOG)
|
|
|
|
|
gtype = GRID_LOGLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
else {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"xlog\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_XLOG;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "ylog")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
if (gtype == GRID_XLOG) {
|
2015-05-14 15:56:24 +02:00
|
|
|
gtype = GRID_LOGLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"xlog\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_YLOG;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "polar")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"polar\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_POLAR;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "smith")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"smith\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_SMITH;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "smithgrid")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many grid types given. "
|
|
|
|
|
"\"smithgrid\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_SMITHGRID;
|
|
|
|
|
gfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sameflag && !gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
char buf[BSIZE_SP];
|
2018-07-21 18:22:18 +02:00
|
|
|
if (cp_getvar("gridstyle", CP_STRING, buf, sizeof(buf))) {
|
2019-12-11 01:47:00 +01:00
|
|
|
if (eq(buf, "lingrid")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LIN;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "loglog")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LOGLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "xlog")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_XLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "ylog")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_YLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "smith")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_SMITH;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "smithgrid")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_SMITHGRID;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "polar")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_POLAR;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "nogrid")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_NONE;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
else {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: unknown grid type \"%s\" is ignored. "
|
|
|
|
|
"The grid type will default to linear.\n", buf);
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LIN;
|
|
|
|
|
}
|
|
|
|
|
gfound = TRUE;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LIN;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now get the point type. */
|
|
|
|
|
if (getflag(wl, "linplot")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (pfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many plot types given. "
|
|
|
|
|
"\"linplot\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_LIN;
|
|
|
|
|
pfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-23 14:27:14 +01:00
|
|
|
if (getflag(wl, "retraceplot")) {
|
2016-09-09 22:04:00 +02:00
|
|
|
if (pfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many plot types given. "
|
2020-02-23 14:27:14 +01:00
|
|
|
"\"retraceplot\" is ignored.\n");
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2020-02-23 14:27:14 +01:00
|
|
|
ptype = PLOT_RETLIN;
|
2016-09-09 22:04:00 +02:00
|
|
|
pfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
if (getflag(wl, "combplot")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (pfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many plot types given. "
|
|
|
|
|
"\"combplot\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_COMB;
|
|
|
|
|
pfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (getflag(wl, "pointplot")) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (pfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: too many plot types given. "
|
|
|
|
|
"\"pointplot\" is ignored.\n");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_POINT;
|
|
|
|
|
pfound = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sameflag && !pfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
char buf[BSIZE_SP];
|
2018-07-21 18:22:18 +02:00
|
|
|
if (cp_getvar("plotstyle", CP_STRING, buf, sizeof(buf))) {
|
2019-12-11 01:47:00 +01:00
|
|
|
if (eq(buf, "linplot")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_LIN;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2020-02-23 14:27:14 +01:00
|
|
|
else if (eq(buf, "retraceplot")) {
|
|
|
|
|
ptype = PLOT_RETLIN;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "combplot")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_COMB;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (eq(buf, "pointplot")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_POINT;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
else {
|
2019-12-11 01:47:00 +01:00
|
|
|
fprintf(cp_err,
|
|
|
|
|
"Warning: strange plot type \"%s\" is ignored. "
|
|
|
|
|
"The plot type will default to linear.\n", buf);
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_LIN;
|
|
|
|
|
}
|
|
|
|
|
pfound = TRUE;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
ptype = PLOT_LIN;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!sameflag || !xlabel) {
|
2000-04-27 22:03:57 +02:00
|
|
|
xlabel = getword(wl, "xlabel");
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getword(wl, "xlabel"));
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!sameflag || !ylabel) {
|
2000-04-27 22:03:57 +02:00
|
|
|
ylabel = getword(wl, "ylabel");
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getword(wl, "ylabel"));
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!sameflag || !title) {
|
2000-04-27 22:03:57 +02:00
|
|
|
title = getword(wl, "title");
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2012-12-15 22:59:47 +01:00
|
|
|
txfree(getword(wl, "title"));
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!sameflag) {
|
2000-04-27 22:03:57 +02:00
|
|
|
nointerp = getflag(wl, "nointerp");
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if (getflag(wl, "nointerp")) {
|
2000-04-27 22:03:57 +02:00
|
|
|
nointerp = TRUE;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2012-07-28 19:55:09 +02:00
|
|
|
if (!wl->wl_next) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err, "Error: no vectors given\n");
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit1;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now parse the vectors. We have a list of the form
|
|
|
|
|
* "a b vs c d e vs f g h". Since it's a bit of a hassle for
|
|
|
|
|
* us to parse the vector boundaries here, we do this -- call
|
|
|
|
|
* ft_getpnames() without the check flag, and then look for 0-length
|
|
|
|
|
* vectors with the name "vs"... This is a sort of a gross hack,
|
|
|
|
|
* since we have to check for 0-length vectors ourselves after
|
|
|
|
|
* evaulating the pnodes...
|
2019-12-11 01:47:00 +01:00
|
|
|
*
|
|
|
|
|
* Note: Evaluating the wordlist starting at wl->wl_next since the first
|
|
|
|
|
* node is a dummy node.
|
2000-04-27 22:03:57 +02:00
|
|
|
*/
|
|
|
|
|
|
2012-07-28 19:55:09 +02:00
|
|
|
names = ft_getpnames(wl->wl_next, FALSE);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (names == (struct pnode *) NULL) {
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit1;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* Now evaluate the names. */
|
2019-12-11 01:47:00 +01:00
|
|
|
for (pn = names, lv = NULL; pn; pn = pn->pn_next) {
|
|
|
|
|
struct dvec *pn_value = pn->pn_value;
|
|
|
|
|
|
|
|
|
|
/* Test for a vs b construct */
|
|
|
|
|
if (pn_value && (pn_value->v_length == 0) &&
|
|
|
|
|
eq(pn_value->v_name, "vs")) {
|
2015-08-15 21:04:58 +02:00
|
|
|
struct dvec *dv;
|
|
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!lv) { /* e.g. "plot vs b" */
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err, "Error: misplaced vs arg\n");
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit;
|
2012-08-04 16:04:21 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
if ((pn = pn->pn_next) == NULL) { /* "plot a vs" */
|
2012-08-04 16:04:42 +02:00
|
|
|
fprintf(cp_err, "Error: missing vs arg\n");
|
|
|
|
|
goto quit;
|
|
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2012-10-01 17:59:40 +02:00
|
|
|
dv = ft_evaluate(pn);
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!dv) {
|
2012-08-04 16:04:42 +02:00
|
|
|
goto quit;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (lastvs) {
|
2012-08-04 16:04:42 +02:00
|
|
|
lv = lastvs->v_link2;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2012-08-04 16:04:42 +02:00
|
|
|
lv = vecs;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-08-04 16:05:05 +02:00
|
|
|
|
2012-08-04 16:04:42 +02:00
|
|
|
while (lv) {
|
|
|
|
|
lv->v_scale = dv;
|
|
|
|
|
lastvs = lv;
|
|
|
|
|
lv = lv->v_link2;
|
|
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else { /* An explicit scale vector is not given ("plot a") */
|
|
|
|
|
struct dvec * const dv = ft_evaluate(pn);
|
|
|
|
|
if (!dv) {
|
2012-08-04 16:04:42 +02:00
|
|
|
goto quit;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (!d) {
|
2012-08-04 16:04:42 +02:00
|
|
|
vecs = dv;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2012-08-04 16:04:42 +02:00
|
|
|
d->v_link2 = dv;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = dv; d->v_link2; d = d->v_link2) {
|
2012-08-04 16:04:42 +02:00
|
|
|
;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2012-08-04 16:04:42 +02:00
|
|
|
lv = dv;
|
2012-08-04 16:05:05 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
} /* end of loop evaluating the names */
|
|
|
|
|
d->v_link2 = NULL; /* terminate list */
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* Now check for 0-length vectors. */
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!d->v_length) {
|
2007-10-08 17:36:56 +02:00
|
|
|
fprintf(cp_err, "Error(plotit.c--plotit): %s: no such vector\n",
|
2000-04-27 22:03:57 +02:00
|
|
|
d->v_name);
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* If there are higher dimensional vectors, transform them into a
|
|
|
|
|
* family of vectors.
|
|
|
|
|
*/
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs, lv = NULL; d; d = d->v_link2) {
|
|
|
|
|
/* Link the family of vectors that is created through the v_link2 link.
|
|
|
|
|
* Note that vec_mkfamily links all of the vector that are created
|
|
|
|
|
* through v_link2 also, so the family of vectors can be added to
|
|
|
|
|
* the plot list by stepping to the end and linking to the next
|
|
|
|
|
* vector */
|
|
|
|
|
if (d->v_numdims > 1) { /* multi-dim vector */
|
|
|
|
|
if (lv) {
|
2012-07-23 19:17:25 +02:00
|
|
|
lv->v_link2 = vec_mkfamily(d);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2012-07-23 19:17:25 +02:00
|
|
|
vecs = lv = vec_mkfamily(d);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Step to end of the family of vectors */
|
|
|
|
|
while (lv->v_link2) {
|
2000-04-27 22:03:57 +02:00
|
|
|
lv = lv->v_link2;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* And link last vector in family to next vector to plot */
|
2000-04-27 22:03:57 +02:00
|
|
|
lv->v_link2 = d->v_link2;
|
|
|
|
|
d = lv;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Ordinary 1-dim vector, so set prev vector to this one in
|
|
|
|
|
* preparation for next increment in loop */
|
2000-04-27 22:03:57 +02:00
|
|
|
lv = d;
|
2012-07-23 19:17:25 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
} /* end of loop over vectors being plotted */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* Now fill in the scales for vectors who aren't already fixed up. */
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!d->v_scale) {
|
2019-12-11 01:47:00 +01:00
|
|
|
if (d->v_plot->pl_scale) {
|
2000-04-27 22:03:57 +02:00
|
|
|
d->v_scale = d->v_plot->pl_scale;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
d->v_scale = d;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2012-07-23 19:17:25 +02:00
|
|
|
/* The following line displays the unit at the time of
|
2018-10-27 12:28:01 +02:00
|
|
|
temp-sweep, res-sweep, and i-sweep. This may not be a so good solution. by H.T */
|
2019-12-11 01:47:00 +01:00
|
|
|
if (strcmp(vecs->v_scale->v_name, "temp-sweep") == 0) {
|
2012-08-04 16:03:52 +02:00
|
|
|
vecs->v_scale->v_type = SV_TEMP;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
if (strcmp(vecs->v_scale->v_name, "res-sweep") == 0) {
|
2012-08-04 16:03:52 +02:00
|
|
|
vecs->v_scale->v_type = SV_RES;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
if (strcmp(vecs->v_scale->v_name, "i-sweep") == 0) {
|
2018-10-27 12:28:01 +02:00
|
|
|
vecs->v_scale->v_type = SV_CURRENT;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* See if the log flag is set anywhere... */
|
|
|
|
|
if (!gfound) {
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
|
|
|
|
if (d->v_scale && (d->v_scale->v_gridtype == GRID_XLOG)) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_XLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
2000-04-27 22:03:57 +02:00
|
|
|
if (d->v_gridtype == GRID_YLOG) {
|
2019-12-11 01:47:00 +01:00
|
|
|
if ((gtype == GRID_XLOG) || (gtype == GRID_LOGLOG)) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_LOGLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = GRID_YLOG;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
2012-09-20 20:30:53 +02:00
|
|
|
if (d->v_gridtype == GRID_SMITH ||
|
2019-12-11 01:47:00 +01:00
|
|
|
d->v_gridtype == GRID_SMITHGRID ||
|
|
|
|
|
d->v_gridtype == GRID_POLAR) {
|
2000-04-27 22:03:57 +02:00
|
|
|
gtype = d->v_gridtype;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if there are any default plot types... Here, like above, we
|
|
|
|
|
* don't do entirely the best thing when there is a mixed set of
|
|
|
|
|
* default plot types...
|
|
|
|
|
*/
|
|
|
|
|
if (!sameflag && !pfound) {
|
|
|
|
|
ptype = PLOT_LIN;
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
2000-04-27 22:03:57 +02:00
|
|
|
if (d->v_plottype != PLOT_LIN) {
|
|
|
|
|
ptype = d->v_plottype;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check and see if this is pole zero stuff. */
|
2019-12-11 01:47:00 +01:00
|
|
|
if ((vecs->v_type == SV_POLE) || (vecs->v_type == SV_ZERO)) {
|
2000-04-27 22:03:57 +02:00
|
|
|
oneval = TRUE;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
2000-04-27 22:03:57 +02:00
|
|
|
if (((d->v_type == SV_POLE) || (d->v_type == SV_ZERO)) !=
|
2019-12-11 01:47:00 +01:00
|
|
|
oneval ? 1 : 0) {
|
2000-04-27 22:03:57 +02:00
|
|
|
fprintf(cp_err,
|
2019-12-11 01:47:00 +01:00
|
|
|
"Error: plot must be either all pole-zero "
|
|
|
|
|
"or contain no poles or zeros\n");
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (gtype == GRID_POLAR || gtype == GRID_SMITH ||
|
|
|
|
|
gtype == GRID_SMITHGRID) {
|
2000-04-27 22:03:57 +02:00
|
|
|
oneval = TRUE;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* If a vector contains a single point, copy the point so that there are
|
|
|
|
|
* as many copies as the scale vector has elements. */
|
|
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
|
|
|
|
if (d->v_length == 1) { /* single value */
|
2000-04-27 22:03:57 +02:00
|
|
|
xtend(d, d->v_scale->v_length);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Now patch up each vector with the compression (decimation) and
|
|
|
|
|
* the strchr selection. */
|
|
|
|
|
if (xcompress || xindices) {
|
2000-04-27 22:03:57 +02:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
|
|
|
|
compress(d, xcompress, xindices);
|
|
|
|
|
d->v_scale = vec_copy(d->v_scale);
|
|
|
|
|
compress(d->v_scale, xcompress, xindices);
|
|
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Transform for smith plots */
|
|
|
|
|
if (gtype == GRID_SMITH) {
|
2019-12-11 01:47:00 +01:00
|
|
|
struct dvec **prevvp = &vecs;
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Loop over vectors being plotted */
|
2012-07-23 19:17:25 +02:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
|
|
|
|
if (d->v_flags & VF_PERMANENT) {
|
2019-12-11 01:47:00 +01:00
|
|
|
struct dvec * const n = vec_copy(d);
|
2012-07-23 19:17:25 +02:00
|
|
|
n->v_flags &= ~VF_PERMANENT;
|
|
|
|
|
n->v_link2 = d->v_link2;
|
|
|
|
|
d = n;
|
|
|
|
|
*prevvp = d;
|
|
|
|
|
}
|
|
|
|
|
prevvp = &d->v_link2;
|
|
|
|
|
|
|
|
|
|
if (isreal(d)) {
|
|
|
|
|
fprintf(cp_err,
|
2019-12-11 01:47:00 +01:00
|
|
|
"Warning: plotting real data \"%s\" on a Smith grid\n",
|
2012-07-23 19:17:25 +02:00
|
|
|
d->v_name);
|
|
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
const int n_elem = d->v_length;
|
|
|
|
|
int j;
|
|
|
|
|
for (j = 0; j < n_elem; j++) {
|
|
|
|
|
const double r = d->v_realdata[j];
|
2012-07-23 19:17:25 +02:00
|
|
|
d->v_realdata[j] = (r - 1) / (r + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
else {
|
|
|
|
|
ngcomplex_t * const v0 = d->v_compdata;
|
|
|
|
|
const int n_elem = d->v_length;
|
|
|
|
|
int j;
|
|
|
|
|
for (j = 0; j < n_elem; j++) {
|
|
|
|
|
ngcomplex_t * const p_cur = v0 + j;
|
|
|
|
|
(void) SMITH_tfm(realpart(*p_cur), imagpart(*p_cur),
|
|
|
|
|
&realpart(*p_cur), &imagpart(*p_cur));
|
|
|
|
|
} /* end of loop over elements in vector */
|
|
|
|
|
} /* complex data */
|
|
|
|
|
} /* end of loop over vectors being plotted */
|
|
|
|
|
} /* end of case of Smith grid */
|
|
|
|
|
|
|
|
|
|
/* Figure out the proper x-axis and y-axis limits. */
|
|
|
|
|
find_axis_limits(ylim, oneval, FALSE, vecs, &vec_self, ylims);
|
|
|
|
|
find_axis_limits(xlim, oneval, TRUE, vecs, &vec_scale, xlims);
|
|
|
|
|
|
|
|
|
|
if ((xlims[0] <= 0.0) &&
|
|
|
|
|
((gtype == GRID_XLOG) || (gtype == GRID_LOGLOG))) {
|
2012-08-03 20:42:37 +02:00
|
|
|
fprintf(cp_err, "Error: X values must be > 0 for log scale\n");
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
if ((ylims[0] <= 0.0) &&
|
|
|
|
|
((gtype == GRID_YLOG) || (gtype == GRID_LOGLOG))) {
|
2012-08-03 20:42:37 +02:00
|
|
|
fprintf(cp_err, "Error: Y values must be > 0 for log scale\n");
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fix the plot limits for smith and polar grids. */
|
|
|
|
|
if ((!xlim || !ylim) && (gtype == GRID_POLAR)) {
|
2012-08-04 16:04:00 +02:00
|
|
|
double mx, my, rad;
|
2000-04-27 22:03:57 +02:00
|
|
|
/* (0,0) must be in the center of the screen. */
|
2012-08-04 16:03:52 +02:00
|
|
|
mx = (fabs(xlims[0]) > fabs(xlims[1])) ? fabs(xlims[0]) : fabs(xlims[1]);
|
|
|
|
|
my = (fabs(ylims[0]) > fabs(ylims[1])) ? fabs(ylims[0]) : fabs(ylims[1]);
|
2012-07-23 19:17:25 +02:00
|
|
|
/* rad = (mx > my) ? mx : my; */
|
|
|
|
|
/* AM.Roldán
|
|
|
|
|
* Change this reason that this was discussed, as in the case of 1 + i want to plot point
|
|
|
|
|
* is outside the drawing area so I'll stay as the maximum size of the hypotenuse of
|
|
|
|
|
* the complex value
|
|
|
|
|
*/
|
2014-12-05 20:08:02 +01:00
|
|
|
rad = hypot(mx, my);
|
2019-12-11 01:47:00 +01:00
|
|
|
xlims[0] = -rad;
|
2000-04-27 22:03:57 +02:00
|
|
|
xlims[1] = rad;
|
2019-12-11 01:47:00 +01:00
|
|
|
ylims[0] = -rad;
|
2000-04-27 22:03:57 +02:00
|
|
|
ylims[1] = rad;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
else if ((!xlim || !ylim) &&
|
|
|
|
|
(gtype == GRID_SMITH || gtype == GRID_SMITHGRID)) {
|
2000-04-27 22:03:57 +02:00
|
|
|
xlims[0] = -1.0;
|
|
|
|
|
xlims[1] = 1.0;
|
|
|
|
|
ylims[0] = -1.0;
|
|
|
|
|
ylims[1] = 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
if (xlim) {
|
2012-08-04 19:09:13 +02:00
|
|
|
tfree(xlim);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
if (ylim) {
|
2012-08-04 19:09:13 +02:00
|
|
|
tfree(ylim);
|
2019-05-01 18:49:34 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* We don't want to try to deal with Smith plots for asciiplot. */
|
2000-04-27 22:03:57 +02:00
|
|
|
if (devname && eq(devname, "lpr")) {
|
|
|
|
|
/* check if we should (can) linearize */
|
2012-08-04 16:02:49 +02:00
|
|
|
if (ft_curckt && ft_curckt->ci_ckt &&
|
2019-12-11 01:47:00 +01:00
|
|
|
(strcmp(ft_curckt->ci_name, plot_cur->pl_title) == 0) &&
|
|
|
|
|
if_tranparams(ft_curckt, &tstart, &tstop, &tstep) &&
|
|
|
|
|
((tstop - tstart) * tstep > 0.0) &&
|
|
|
|
|
((tstop - tstart) >= tstep) &&
|
|
|
|
|
plot_cur && plot_cur->pl_dvecs &&
|
|
|
|
|
plot_cur->pl_scale &&
|
|
|
|
|
isreal(plot_cur->pl_scale) &&
|
|
|
|
|
ciprefix("tran", plot_cur->pl_typename)) {
|
2012-08-04 16:04:00 +02:00
|
|
|
int newlen = (int)((tstop - tstart) / tstep + 1.5);
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2015-12-28 20:24:11 +01:00
|
|
|
double *newscale;
|
2012-08-04 16:04:00 +02:00
|
|
|
|
2015-12-28 20:26:58 +01:00
|
|
|
struct dvec *v, *newv_scale =
|
|
|
|
|
dvec_alloc(copy(vecs->v_scale->v_name),
|
|
|
|
|
vecs->v_scale->v_type,
|
|
|
|
|
vecs->v_scale->v_flags,
|
|
|
|
|
newlen, NULL);
|
2012-07-23 19:17:25 +02:00
|
|
|
|
|
|
|
|
newv_scale->v_gridtype = vecs->v_scale->v_gridtype;
|
|
|
|
|
|
2015-12-28 20:24:11 +01:00
|
|
|
newscale = newv_scale->v_realdata;
|
2019-12-11 01:47:00 +01:00
|
|
|
for (i = 0, ttime = tstart; i < newlen; i++, ttime += tstep) {
|
2012-07-23 19:17:25 +02:00
|
|
|
newscale[i] = ttime;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2012-07-23 19:17:25 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
for (v = vecs; v; v = v->v_link2) {
|
2012-08-04 16:04:00 +02:00
|
|
|
double *newdata = TMALLOC(double, newlen);
|
2012-07-23 19:17:25 +02:00
|
|
|
|
|
|
|
|
if (!ft_interpolate(v->v_realdata, newdata,
|
2019-12-11 01:47:00 +01:00
|
|
|
v->v_scale->v_realdata, v->v_scale->v_length,
|
|
|
|
|
newscale, newlen, 1)) {
|
2012-08-03 20:42:37 +02:00
|
|
|
fprintf(cp_err, "Error: can't interpolate %s\n", v->v_name);
|
2012-07-23 19:17:25 +02:00
|
|
|
goto quit;
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2015-12-28 20:27:52 +01:00
|
|
|
dvec_realloc(v, newlen, newdata);
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2012-07-23 19:17:25 +02:00
|
|
|
/* Why go to all this trouble if agraf ignores it? */
|
|
|
|
|
nointerp = TRUE;
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2012-07-23 19:17:25 +02:00
|
|
|
vecs->v_scale = newv_scale;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2012-08-04 16:04:42 +02:00
|
|
|
|
2012-08-04 16:03:52 +02:00
|
|
|
ft_agraf(xlims, ylims,
|
|
|
|
|
vecs->v_scale, vecs->v_plot, vecs,
|
|
|
|
|
xdelta ? *xdelta : 0.0,
|
|
|
|
|
ydelta ? *ydelta : 0.0,
|
2012-07-23 19:17:25 +02:00
|
|
|
((gtype == GRID_XLOG) || (gtype == GRID_LOGLOG)),
|
|
|
|
|
((gtype == GRID_YLOG) || (gtype == GRID_LOGLOG)),
|
|
|
|
|
nointerp);
|
2003-07-23 21:36:39 +02:00
|
|
|
rtn = TRUE;
|
2012-07-23 19:17:25 +02:00
|
|
|
goto quit;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-15 19:48:28 +01:00
|
|
|
/* See if there is one common v_type we can give for the y scale... */
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs->v_link2; d; d = d->v_link2) {
|
|
|
|
|
if (d->v_type != vecs->v_type) {
|
2000-04-27 22:03:57 +02:00
|
|
|
break;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
2015-12-15 19:48:28 +01:00
|
|
|
|
2015-12-15 19:58:11 +01:00
|
|
|
y_type = d ? SV_NOTYPE : vecs->v_type;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2012-07-23 19:17:25 +02:00
|
|
|
if (devname && eq(devname, "gnuplot")) {
|
|
|
|
|
/* Interface to Gnuplot Plot Program */
|
|
|
|
|
ft_gnuplot(xlims, ylims, hcopy,
|
|
|
|
|
title ? title : vecs->v_plot->pl_title,
|
|
|
|
|
xlabel ? xlabel : ft_typabbrev(vecs->v_scale->v_type),
|
2015-12-15 19:58:11 +01:00
|
|
|
ylabel ? ylabel : ft_typabbrev(y_type),
|
2012-07-23 19:17:25 +02:00
|
|
|
gtype, ptype, vecs);
|
|
|
|
|
rtn = TRUE;
|
|
|
|
|
goto quit;
|
2010-02-27 22:11:30 +01:00
|
|
|
}
|
|
|
|
|
|
2012-07-23 19:17:25 +02:00
|
|
|
if (devname && eq(devname, "writesimple")) {
|
|
|
|
|
/* Interface to simple write output */
|
|
|
|
|
ft_writesimple(xlims, ylims, hcopy,
|
|
|
|
|
title ? title : vecs->v_plot->pl_title,
|
|
|
|
|
xlabel ? xlabel : ft_typabbrev(vecs->v_scale->v_type),
|
2015-12-15 19:58:11 +01:00
|
|
|
ylabel ? ylabel : ft_typabbrev(y_type),
|
2012-07-23 19:17:25 +02:00
|
|
|
gtype, ptype, vecs);
|
|
|
|
|
rtn = TRUE;
|
|
|
|
|
goto quit;
|
2008-03-22 14:10:46 +01:00
|
|
|
}
|
|
|
|
|
|
2008-08-27 15:39:05 +02:00
|
|
|
#ifdef TCL_MODULE
|
|
|
|
|
if (devname && eq(devname, "blt")) {
|
2012-07-23 19:17:25 +02:00
|
|
|
/* Just send the pairs to Tcl/Tk */
|
2012-08-04 16:04:32 +02:00
|
|
|
for (d = vecs; d; d = d->v_link2)
|
2012-07-23 19:17:25 +02:00
|
|
|
blt_plot(d, oneval ? NULL : d->v_scale, (d == vecs) ? 1 : 0);
|
|
|
|
|
rtn = TRUE;
|
|
|
|
|
goto quit;
|
2008-08-27 15:39:05 +02:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Find the number of vectors being plotted */
|
|
|
|
|
for (d = vecs, i = 0; d; d = d->v_link2) {
|
2000-04-27 22:03:57 +02:00
|
|
|
i++;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* Figure out the X name and the X type. This is sort of bad... */
|
|
|
|
|
xn = vecs->v_scale->v_name;
|
|
|
|
|
xt = vecs->v_scale->v_type;
|
|
|
|
|
|
|
|
|
|
|
2011-04-28 17:59:36 +02:00
|
|
|
if (!gr_init(xlims, ylims, (oneval ? NULL : xn),
|
2019-12-11 01:47:00 +01:00
|
|
|
title ? title : vecs->v_plot->pl_title,
|
|
|
|
|
hcopy, i,
|
|
|
|
|
xdelta ? *xdelta : 0.0,
|
|
|
|
|
ydelta ? *ydelta : 0.0,
|
|
|
|
|
gtype, ptype, xlabel, ylabel, xt, y_type,
|
2020-02-10 17:21:46 +01:00
|
|
|
plot_cur->pl_typename, ds_get_buf(&ds_cline), prevgraph)) {
|
2003-07-23 21:36:39 +02:00
|
|
|
goto quit;
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
/* Now plot all the graphs. */
|
2019-12-11 01:47:00 +01:00
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
2011-04-28 17:59:36 +02:00
|
|
|
ft_graf(d, oneval ? NULL : d->v_scale, FALSE);
|
2019-12-11 01:47:00 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
gr_clean();
|
2019-12-11 01:47:00 +01:00
|
|
|
rtn = TRUE; /* Indicate success */
|
2012-08-04 16:04:42 +02:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
quit:
|
2019-12-11 01:47:00 +01:00
|
|
|
ds_free(&ds_cline); /* free dstring resources, if any */
|
2003-07-23 21:36:39 +02:00
|
|
|
free_pnode(names);
|
2012-12-15 22:59:47 +01:00
|
|
|
FREE(title);
|
2019-12-11 01:47:00 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
quit1:
|
2019-12-11 01:47:00 +01:00
|
|
|
/* Free any vectors left behing while parsing the plot arguments. These
|
|
|
|
|
* are vectors created by ft_evaluate() */
|
|
|
|
|
if (plot_cur != (struct plot *) NULL) {
|
|
|
|
|
struct dvec *dv = plot_cur->pl_dvecs;
|
|
|
|
|
while(dv != dv_head_orig) {
|
|
|
|
|
struct dvec *dv_next = dv->v_next;
|
|
|
|
|
vec_free(dv);
|
|
|
|
|
dv = dv_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-28 19:55:09 +02:00
|
|
|
wl_free(wl);
|
2003-07-23 21:36:39 +02:00
|
|
|
return rtn;
|
2019-12-11 01:47:00 +01:00
|
|
|
} /* end of function plotit */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return itself */
|
|
|
|
|
static struct dvec *vec_self(struct dvec *v)
|
|
|
|
|
{
|
|
|
|
|
return v;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2019-12-11 01:47:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return scale vector */
|
|
|
|
|
static struct dvec *vec_scale(struct dvec *v)
|
|
|
|
|
{
|
|
|
|
|
return v->v_scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function finds the range limits for an x-axis or y-axis.
|
|
|
|
|
*
|
|
|
|
|
* Parameters
|
|
|
|
|
* lim: Existing limits
|
|
|
|
|
* oneval: Flag that there is no scale vector
|
|
|
|
|
* f_real: Flag that the real component of a complex value should be used
|
|
|
|
|
* when finding the range if true and the imaginary part if false
|
|
|
|
|
* vecs: Vectors being used to determine the range. It is related to athe
|
|
|
|
|
* oneval flag in that it determines
|
|
|
|
|
* p_get_axis_dvec: Address of function used to get range information
|
|
|
|
|
* from a vector. It should be either the address of vec_self to use
|
|
|
|
|
* the vector itself (for y range with scale value) or the address of
|
|
|
|
|
* vec_scale for its scale vector (for x range of scale).
|
|
|
|
|
* lims: Address of an array of 2 double values to receive the limits.
|
|
|
|
|
**/
|
|
|
|
|
static void find_axis_limits(double lim[2], bool oneval, bool f_real,
|
|
|
|
|
struct dvec *vecs,
|
|
|
|
|
struct dvec *(*p_get_axis_dvec)(struct dvec *dvec),
|
|
|
|
|
double lims[2])
|
|
|
|
|
{
|
|
|
|
|
if (lim != (double *) NULL) {
|
|
|
|
|
lims[0] = lim[0];
|
|
|
|
|
lims[1] = lim[1];
|
|
|
|
|
}
|
|
|
|
|
else if (oneval) {
|
|
|
|
|
struct dvec *d;
|
|
|
|
|
lims[0] = HUGE;
|
|
|
|
|
lims[1] = -lims[0];
|
|
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
|
|
|
|
/* dd = ft_minmax(d, FALSE); */
|
|
|
|
|
/* With this we seek the maximum and minimum of imaginary part
|
|
|
|
|
* that will go to Y axis
|
|
|
|
|
*/
|
|
|
|
|
const double * const dd = ft_minmax(d, f_real);
|
|
|
|
|
|
|
|
|
|
if (lims[0] > dd[0]) {
|
|
|
|
|
lims[0] = dd[0];
|
|
|
|
|
}
|
|
|
|
|
if (lims[1] < dd[1]) {
|
|
|
|
|
lims[1] = dd[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else { /* have scale vector */
|
|
|
|
|
struct dvec *d;
|
|
|
|
|
lims[0] = HUGE;
|
|
|
|
|
lims[1] = -lims[0];
|
|
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
|
|
|
|
const double * const dd = ft_minmax((*p_get_axis_dvec)(d), TRUE);
|
|
|
|
|
if (lims[0] > dd[0]) {
|
|
|
|
|
lims[0] = dd[0];
|
|
|
|
|
}
|
|
|
|
|
if (lims[1] < dd[1]) {
|
|
|
|
|
lims[1] = dd[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (d = vecs; d; d = d->v_link2) {
|
|
|
|
|
struct dvec *d2 = (*p_get_axis_dvec)(d);
|
|
|
|
|
short v_flags = d2->v_flags;
|
|
|
|
|
if (v_flags & VF_MINGIVEN) {
|
|
|
|
|
double v_minsignal = d2->v_minsignal;
|
|
|
|
|
if (lims[0] < v_minsignal) {
|
|
|
|
|
lims[0] = v_minsignal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (v_flags & VF_MAXGIVEN) {
|
|
|
|
|
double v_maxsignal = d2->v_maxsignal;
|
|
|
|
|
if (lims[1] > v_maxsignal) {
|
|
|
|
|
lims[1] = v_maxsignal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} /* end of loop over vectors being plotted */
|
|
|
|
|
} /* end of case of vector with scale vector */
|
|
|
|
|
|
|
|
|
|
/* Do some coercion of the limits to make them reasonable. */
|
|
|
|
|
if ((lims[0] == 0.0) && (lims[1] == 0.0)) {
|
|
|
|
|
lims[0] = -1.0;
|
|
|
|
|
lims[1] = 1.0;
|
|
|
|
|
}
|
|
|
|
|
if (lims[0] > lims[1]) {
|
|
|
|
|
SWAP(double, lims[0], lims[1]);
|
|
|
|
|
}
|
|
|
|
|
if (AlmostEqualUlps(lims[0], lims[1], 10)) {
|
|
|
|
|
lims[0] *= (lims[0] > 0) ? 0.9 : 1.1;
|
|
|
|
|
lims[1] *= (lims[1] > 0) ? 1.1 : 0.9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} /* end of function find_axis_limits */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|