/* * Grace - GRaphing, Advanced Computation and Exploration of data * * Home page: http://plasma-gate.weizmann.ac.il/Grace/ * * Copyright (c) 1991-1995 Paul J Turner, Portland, OR * Copyright (c) 1996-2000 Grace Development Team * * Maintained by Evgeny Stambulchik * * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * * routines to allocate, manipulate, and return * information about sets. * */ #include #include #include #include #include #include "globals.h" #include "utils.h" #include "files.h" #include "graphs.h" #include "protos.h" extern graph *g; /* * return the string version of the set type */ char *set_types(int it) { char *s = "xy"; switch (it) { case SET_XY: s = "xy"; break; case SET_BAR: s = "bar"; break; case SET_BARDY: s = "bardy"; break; case SET_BARDYDY: s = "bardydy"; break; case SET_XYZ: s = "xyz"; break; case SET_XYDX: s = "xydx"; break; case SET_XYDY: s = "xydy"; break; case SET_XYDXDX: s = "xydxdx"; break; case SET_XYDYDY: s = "xydydy"; break; case SET_XYDXDY: s = "xydxdy"; break; case SET_XYDXDXDYDY: s = "xydxdxdydy"; break; case SET_XYHILO: s = "xyhilo"; break; case SET_XYR: s = "xyr"; break; case SET_XYCOLOR: s = "xycolor"; break; case SET_XYCOLPAT: s = "xycolpat"; break; case SET_XYVMAP: s = "xyvmap"; break; case SET_BOXPLOT: s = "xyboxplot"; break; case SET_XYSIZE: s = "xysize"; break; } return s; } int get_settype_by_name(char *s) { int i; for (i = 0; i < NUMBER_OF_SETTYPES; i++) { if (strcmp(set_types(i), s) == 0) { return i; } } return SET_BAD; } int settype_cols(int type) { int ncols; switch (type) { case SET_XY: case SET_BAR: ncols = 2; break; case SET_XYDX: case SET_XYDY: case SET_XYZ: case SET_BARDY: case SET_XYR: case SET_XYCOLOR: case SET_XYSIZE: ncols = 3; break; case SET_XYDXDX: case SET_XYDYDY: case SET_XYDXDY: case SET_BARDYDY: case SET_XYCOLPAT: case SET_XYVMAP: ncols = 4; break; case SET_XYHILO: ncols = 5; break; case SET_XYDXDXDYDY: case SET_BOXPLOT: ncols = 6; break; default: ncols = 0; break; } return ncols; } /* * return the string version of the dataset column */ char *dataset_colname(int col) { char *s; switch (col) { case 0: s = "X"; break; case 1: s = "Y"; break; case 2: s = "Y1"; break; case 3: s = "Y2"; break; case 4: s = "Y3"; break; case 5: s = "Y4"; break; default: s = "?"; errmsg("Internal error in dataset_colname()"); break; } return s; } int zero_set_data(Dataset *dsp) { int k; if (dsp) { dsp->len = 0; for (k = 0; k < MAX_SET_COLS; k++) { dsp->ex[k] = NULL; } dsp->s = NULL; return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } /* * free set data */ int free_set_data(Dataset *dsp) { int k; if (dsp) { if (dsp->len) { for (k = 0; k < MAX_SET_COLS; k++) { XCFREE(dsp->ex[k]); } if (dsp->s) { for (k = 0; k < dsp->len; k++) { XCFREE(dsp->s[k]); } XCFREE(dsp->s); } dsp->len = 0; set_dirtystate(); } return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } /* * free set data, but preserve the parameter settings */ void killsetdata(int gno, int setno) { if (is_valid_setno(gno, setno)) { free_set_data(&g[gno].p[setno].data); } } /* * (re)allocate data arrays for a set of length len. */ int setlength(int gno, int setno, int len) { plotarr *p; int i, j, ncols, oldlen; if (is_valid_setno(gno, setno) != TRUE) { return RETURN_FAILURE; } p = &g[gno].p[setno]; oldlen = p->data.len; if (len == oldlen) { return RETURN_SUCCESS; } if (len < 0) { return RETURN_FAILURE; } ncols = settype_cols(p->type); if (ncols == 0) { errmsg("Set type not found in setlength()!"); return RETURN_FAILURE; } for (i = 0; i < ncols; i++) { if ((p->data.ex[i] = xrealloc(p->data.ex[i], len*SIZEOF_DOUBLE)) == NULL && len != 0) { return RETURN_FAILURE; } for (j = oldlen; j < len; j++) { p->data.ex[i][j] = 0.0; } } if (p->data.s != NULL) { for (i = len; i < oldlen; i++) { xfree(p->data.s[i]); } p->data.s = xrealloc(p->data.s, len*sizeof(char *)); for (j = oldlen; j < len; j++) { p->data.s[j] = copy_string(NULL, ""); } } p->data.len = len; set_dirtystate(); return RETURN_SUCCESS; } /* * moveset */ int moveset(int gnofrom, int setfrom, int gnoto, int setto) { if (gnoto == gnofrom && setfrom == setto) { return RETURN_FAILURE; } if (is_valid_setno(gnofrom, setfrom) != TRUE) { return RETURN_FAILURE; } if (is_set_active(gnoto, setto)) { killset(gnoto, setto); } activateset(gnoto, setto); memcpy(&g[gnoto].p[setto], &g[gnofrom].p[setfrom], sizeof(plotarr)); zero_set_data(&g[gnofrom].p[setfrom].data); g[gnofrom].p[setfrom].hidden = TRUE; set_dirtystate(); return RETURN_SUCCESS; } /* * copy a set to another set, if the to set doesn't exist allocate it */ int copyset(int gfrom, int setfrom, int gto, int setto) { int i, k, len, ncols; double *savec[MAX_SET_COLS]; char **saves; char buf[256]; if (!is_set_active(gfrom, setfrom)) { return RETURN_FAILURE; } if (!is_valid_gno(gto)) { return RETURN_FAILURE; } if (setfrom == setto && gfrom == gto) { return RETURN_FAILURE; } if (is_set_active(gto, setto)) { killset(gto, setto); } len = getsetlength(gfrom, setfrom); ncols = dataset_cols(gfrom, setfrom); activateset(gto, setto); set_dataset_type(gto, setto, dataset_type(gfrom, setfrom)); if (setlength(gto, setto, len) != RETURN_SUCCESS) { return RETURN_FAILURE; } if (g[gfrom].p[setfrom].data.s != NULL) { if ((g[gto].p[setto].data.s = xmalloc(len*sizeof(char *))) == NULL) { return RETURN_FAILURE; } } for (k = 0; k < MAX_SET_COLS; k++) { savec[k] = getcol(gto, setto, k); } saves = get_set_strings(gto, setto); memcpy(&g[gto].p[setto], &g[gfrom].p[setfrom], sizeof(plotarr)); for (k = 0; k < ncols; k++) { g[gto].p[setto].data.ex[k] = savec[k]; memcpy(g[gto].p[setto].data.ex[k], g[gfrom].p[setfrom].data.ex[k], len*SIZEOF_DOUBLE); } g[gto].p[setto].data.s = saves; if (g[gfrom].p[setfrom].data.s != NULL) { for (i = 0; i < len; i++) { g[gto].p[setto].data.s[i] = copy_string(NULL, g[gfrom].p[setfrom].data.s[i]); } } sprintf(buf, "copy of set G%d.S%d", gfrom, setfrom); setcomment(gto, setto, buf); set_dirtystate(); return RETURN_SUCCESS; } /* * same as copyset(), but doesn't alter the to set appearance */ int copysetdata(int gfrom, int setfrom, int gto, int setto) { int i, k, len, ncols; char buf[256]; if (!is_set_active(gfrom, setfrom)) { return RETURN_FAILURE; } if (!is_valid_gno(gto)) { return RETURN_FAILURE; } if (setfrom == setto && gfrom == gto) { return RETURN_FAILURE; } if (is_set_active(gto, setto)) { killsetdata(gto, setto); } len = getsetlength(gfrom, setfrom); ncols = dataset_cols(gfrom, setfrom); activateset(gto, setto); if (dataset_cols(gto, setto) != ncols) { set_dataset_type(gto, setto, dataset_type(gfrom, setfrom)); } if (setlength(gto, setto, len) != RETURN_SUCCESS) { return RETURN_FAILURE; } if (g[gfrom].p[setfrom].data.s != NULL) { if ((g[gto].p[setto].data.s = xmalloc(len*sizeof(char *))) == NULL) { return RETURN_FAILURE; } } for (k = 0; k < ncols; k++) { memcpy(g[gto].p[setto].data.ex[k], g[gfrom].p[setfrom].data.ex[k], len*SIZEOF_DOUBLE); } if (g[gfrom].p[setfrom].data.s != NULL) { for (i = 0; i < len; i++) { g[gto].p[setto].data.s[i] = copy_string(NULL, g[gfrom].p[setfrom].data.s[i]); } } sprintf(buf, "copy of setdata G%d.S%d", gfrom, setfrom); setcomment(gto, setto, buf); set_dirtystate(); return RETURN_SUCCESS; } /* * swap a set with another set */ int swapset(int gno1, int setno1, int gno2, int setno2) { plotarr p; if (is_valid_setno(gno1, setno1) == FALSE || is_valid_setno(gno2, setno2) == FALSE) { return RETURN_FAILURE; } if (setno1 == setno2 && gno1 == gno2) { return RETURN_FAILURE; } memcpy(&p, &g[gno2].p[setno2], sizeof(plotarr)); memcpy(&g[gno2].p[setno2], &g[gno1].p[setno1], sizeof(plotarr)); memcpy(&g[gno1].p[setno1], &p, sizeof(plotarr)); set_dirtystate(); return RETURN_SUCCESS; } /* * kill a set */ void killset(int gno, int setno) { if (is_valid_setno(gno, setno)) { killsetdata(gno, setno); set_default_plotarr(&g[gno].p[setno]); } } double *getcol(int gno, int setno, int col) { if (is_valid_setno(gno, setno)) { return g[gno].p[setno].data.ex[col]; } else { return NULL; } } void setcol(int gno, int setno, int col, double *x, int len) { if (is_valid_setno(gno, setno) != TRUE) { return; } g[gno].p[setno].data.ex[col] = x; g[gno].p[setno].data.len = len; set_dirtystate(); } char **get_set_strings(int gno, int setno) { if (is_valid_setno(gno, setno)) { return g[gno].p[setno].data.s; } else { return NULL; } } int set_set_strings(int gno, int setno, int len, char **s) { if (is_valid_setno(gno, setno) && len > 0 && s!= NULL) { g[gno].p[setno].data.s = s; g[gno].p[setno].data.len = len; set_dirtystate(); return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } int getsetlength(int gno, int setno) { if (is_valid_setno(gno, setno)) { return g[gno].p[setno].data.len; } else { return -1; } } int setcomment(int gno, int setno, char *s) { if (is_valid_setno(gno, setno) && s != NULL) { strncpy(g[gno].p[setno].comments, s, MAX_STRING_LENGTH - 1); set_dirtystate(); return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } char *getcomment(int gno, int setno) { if (is_valid_setno(gno, setno)) { return g[gno].p[setno].comments; } else { return NULL; } } int set_legend_string(int gno, int setno, char *s) { if (is_valid_setno(gno, setno) && s != NULL) { strncpy(g[gno].p[setno].lstr, s, MAX_STRING_LENGTH - 1); return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } char *get_legend_string(int gno, int setno) { if (is_valid_setno(gno, setno)) { return g[gno].p[setno].lstr; } else { return NULL; } } int set_dataset_type(int gno, int setno, int type) { int old_type = dataset_type(gno, setno); if (old_type < 0) { /* wrong gno/setno */ return RETURN_FAILURE; } else if (old_type == type) { /* nothing changed */ return RETURN_SUCCESS; } else { int i, len, ncols_old, ncols_new; len = getsetlength(gno, setno); ncols_old = dataset_cols(gno, setno); ncols_new = settype_cols(type); for (i = ncols_old; i < ncols_new; i++) { g[gno].p[setno].data.ex[i] = xcalloc(len, SIZEOF_DOUBLE); } for (i = ncols_new; i < ncols_old; i++) { XCFREE(g[gno].p[setno].data.ex[i]); } g[gno].p[setno].type = type; set_dirtystate(); return RETURN_SUCCESS; } } int dataset_type(int gno, int setno) { if (is_valid_setno(gno, setno)) { return g[gno].p[setno].type; } else { return -1; } } void set_hotlink(int gno, int setno, int onoroff, char *fname, int src) { if (is_valid_setno(gno, setno) != TRUE) { return; } g[gno].p[setno].hotlink = onoroff; if (onoroff && fname != NULL) { strcpy(g[gno].p[setno].hotfile, fname); g[gno].p[setno].hotsrc = src; } set_dirtystate(); } int is_hotlinked(int gno, int setno) { if (is_valid_setno(gno, setno) != TRUE) { return FALSE; } if (g[gno].p[setno].hotlink && strlen(g[gno].p[setno].hotfile)) { return g[gno].p[setno].hotlink; } else { return FALSE; } } char *get_hotlink_file(int gno, int setno) { if (is_valid_setno(gno, setno) != TRUE) { return NULL; } else { return g[gno].p[setno].hotfile; } } int get_hotlink_src(int gno, int setno) { if (is_valid_setno(gno, setno) != TRUE) { return -1; } else { return g[gno].p[setno].hotsrc; } } void do_update_hotlink(int gno, int setno) { if (is_hotlinked(gno, setno) != TRUE) { return; } else { plotarr *p; p = &g[gno].p[setno]; update_set_from_file(gno, setno, p->hotfile, p->hotsrc); } } /* * get the min/max fields of a set */ int getsetminmax(int gno, int setno, double *xmin, double *xmax, double *ymin, double *ymax) { double *x, *y; int len; double x1, x2, y1, y2; int i, first = TRUE; int imin, imax; /* dummy */ if (setno == ALL_SETS) { for (i = 0; i < number_of_sets(gno); i++) { if (is_set_drawable(gno, i)) { x = getcol(gno, i, 0); y = getcol(gno, i, 1); len = getsetlength(gno, i); minmax(x, len, &x1, &x2, &imin, &imax); minmax(y, len, &y1, &y2, &imin, &imax); if (first) { *xmin = x1; *xmax = x2; *ymin = y1; *ymax = y2; first = FALSE; } else { *xmin = (x1 < *xmin) ? x1 : *xmin; *xmax = (x2 > *xmax) ? x2 : *xmax; *ymin = (y1 < *ymin) ? y1 : *ymin; *ymax = (y2 > *ymax) ? y2 : *ymax; } } } } else if (is_valid_setno(gno, setno)) { x = getcol(gno, setno, 0); y = getcol(gno, setno, 1); len = getsetlength(gno, setno); minmax(x, len, xmin, xmax, &imin, &imax); minmax(y, len, ymin, ymax, &imin, &imax); first = FALSE; } if (first == FALSE) { return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } /* * get the min/max fields of a set with fixed x/y range */ int getsetminmax_c(int gno, int setno, double *xmin, double *xmax, double *ymin, double *ymax, int ivec) { double vmin_t, vmax_t, *vmin, *vmax, bvmin, bvmax, *vec, *bvec; int i, start, stop, n; int first = TRUE, hits; if (ivec == 1) { bvmin = *xmin; bvmax = *xmax; vmin = ymin; vmax = ymax; } else { bvmin = *ymin; bvmax = *ymax; vmin = xmin; vmax = xmax; } if (setno == ALL_SETS) { start = 0; stop = number_of_sets(gno) - 1; } else if (is_valid_setno(gno, setno)) { start = setno; stop = setno; } else { return RETURN_FAILURE; } for (i = start; i <= stop; i++) { if (is_set_drawable(gno, i)) { if (ivec == 1) { bvec = getx(gno, i); vec = gety(gno, i); } else { bvec = gety(gno, i); vec = getx(gno, i); } n = getsetlength(gno, i); hits = minmaxrange(bvec, vec, n, bvmin, bvmax, &vmin_t, &vmax_t); if (hits == RETURN_SUCCESS) { if (first) { *vmin = vmin_t; *vmax = vmax_t; first = FALSE; } else { *vmin = MIN2(vmin_t, *vmin); *vmax = MAX2(vmax_t, *vmax); } } } } if (first == FALSE) { return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } /* * compute the mins and maxes of a vector x */ void minmax(double *x, int n, double *xmin, double *xmax, int *imin, int *imax) { int i; *imin = 0; *imax = 0; if (x == NULL) { *xmin = 0.0; *xmax = 0.0; return; } *xmin = x[0]; *xmax = x[0]; for (i = 1; i < n; i++) { if (x[i] < *xmin) { *xmin = x[i]; *imin = i; } if (x[i] > *xmax) { *xmax = x[i]; *imax = i; } } } /* * compute the min and max of vector vec calculated for indices such that * bvec values lie within [bmin, bmax] range * returns RETURN_FAILURE if none found */ int minmaxrange(double *bvec, double *vec, int n, double bvmin, double bvmax, double *vmin, double *vmax) { int i, first = TRUE; if ((vec == NULL) || (bvec == NULL)) { return RETURN_FAILURE; } for (i = 0; i < n; i++) { if ((bvec[i] >= bvmin) && (bvec[i] <= bvmax)) { if (first == TRUE) { *vmin = vec[i]; *vmax = vec[i]; first = FALSE; } else { if (vec[i] < *vmin) { *vmin = vec[i]; } else if (vec[i] > *vmax) { *vmax = vec[i]; } } } } if (first == FALSE) { return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } /* * compute the mins and maxes of a vector x */ double vmin(double *x, int n) { int i; double xmin; if (n <= 0) { return 0.0; } xmin = x[0]; for (i = 1; i < n; i++) { if (x[i] < xmin) { xmin = x[i]; } } return xmin; } double vmax(double *x, int n) { int i; double xmax; if (n <= 0) { return 0.0; } xmax = x[0]; for (i = 1; i < n; i++) { if (x[i] > xmax) { xmax = x[i]; } } return xmax; } int set_point(int gno, int setno, int seti, WPoint wp) { if (is_valid_setno(gno, setno) != TRUE) { return RETURN_FAILURE; } if (seti >= getsetlength(gno, setno) || seti < 0) { return RETURN_FAILURE; } (getcol(gno, setno, DATA_X))[seti] = wp.x; (getcol(gno, setno, DATA_Y))[seti] = wp.y; set_dirtystate(); return RETURN_SUCCESS; } int get_point(int gno, int setno, int seti, WPoint *wp) { if (is_valid_setno(gno, setno) != TRUE) { return RETURN_FAILURE; } if (seti >= getsetlength(gno, setno) || seti < 0) { return RETURN_FAILURE; } wp->x = (getcol(gno, setno, DATA_X))[seti]; wp->y = (getcol(gno, setno, DATA_Y))[seti]; return RETURN_SUCCESS; } void copycol2(int gfrom, int setfrom, int gto, int setto, int col) { int i, n1, n2; double *x1, *x2; if (is_valid_setno(gfrom, setfrom) != TRUE || is_valid_setno(gto, setto) != TRUE) { return; } n1 = getsetlength(gfrom, setfrom); n2 = getsetlength(gto, setto); if (n1 != n2) { return; } x1 = getcol(gfrom, setfrom, col); x2 = getcol(gto, setto, col); for (i = 0; i < n1; i++) { x2[i] = x1[i]; } set_dirtystate(); } int pushset(int gno, int setno, int push_type) { int i, newsetno; if (is_valid_setno(gno, setno) != TRUE) { return RETURN_FAILURE; } else { switch (push_type) { case PUSH_SET_TOFRONT: newsetno = number_of_sets(gno) - 1; for (i = setno; i < newsetno; i++) { if (swapset(gno, i, gno, i + 1) != RETURN_SUCCESS) { return RETURN_FAILURE; } } break; case PUSH_SET_TOBACK: newsetno = 0; for (i = setno; i > newsetno; i--) { if (swapset(gno, i, gno, i - 1) != RETURN_SUCCESS) { return RETURN_FAILURE; } } break; default: return RETURN_FAILURE; break; } return RETURN_SUCCESS; } } /* * pack all sets leaving no gaps in the set structure */ void packsets(int gno) { int i, j; for (i = 0; i < number_of_sets(gno); i++) { if (is_set_active(gno, i)) { for (j = 0; j < i; j++) { if (is_set_active(gno, j) != TRUE) { moveset(gno, i, gno, j); } } } } } int allocate_set(int gno, int setno) { if (is_valid_setno(gno, setno)) { return RETURN_SUCCESS; } else if (setno >= 0) { return realloc_graph_plots(gno, setno + 1); } else { return RETURN_FAILURE; } } int activateset(int gno, int setno) { int retval; if (is_valid_gno(gno) != TRUE) { return RETURN_FAILURE; } else { retval = allocate_set(gno, setno); if (retval == RETURN_SUCCESS) { set_set_hidden(gno, setno, FALSE); } return retval; } } static target recent_target = {-1, -1}; int get_recent_setno(void) { return recent_target.setno; } int get_recent_gno(void) { return recent_target.gno; } /* * return the next available set in graph gno * If target is allocated but with no data, choose it (used for loading sets * from project files when sets aren't packed) */ int nextset(int gno) { int setno; int maxplot; if (is_valid_gno(gno) != TRUE) { return (-1); } if ( (target_set.gno == gno) && is_valid_setno(target_set.gno, target_set.setno) && !is_set_active(gno, target_set.setno)) { setno = target_set.setno; target_set.gno = -1; target_set.setno = -1; } else { maxplot = number_of_sets(gno); for (setno = 0; setno < maxplot; setno++) { if (!is_set_active(gno, setno)) { break; } } /* if no sets found, try allocating new one */ if (setno == maxplot && allocate_set(gno, setno) != RETURN_SUCCESS) { return (-1); } } recent_target.gno = gno; recent_target.setno = setno; return (setno); } int is_set_active(int gno, int setno) { if (is_valid_setno(gno, setno) && getsetlength(gno, setno) > 0) { return TRUE; } else { return FALSE; } } /* * return number of active set(s) in gno */ int number_of_active_sets(int gno) { int setno, na; if (is_valid_gno(gno) != TRUE) { return -1; } na = 0; for (setno = 0; setno < number_of_sets(gno); setno++) { if (is_set_active(gno, setno) == TRUE) { na++; } } return na; } /* * drop points from a set */ void droppoints(int gno, int setno, int startno, int endno) { double *x; char **s; int i, j, len, ncols, dist; if (is_valid_setno(gno, setno) != TRUE) { return; } dist = endno - startno + 1; if (dist <= 0) { return; } len = getsetlength(gno, setno); if (dist == len) { killsetdata(gno, setno); return; } ncols = dataset_cols(gno, setno); for (j = 0; j < ncols; j++) { x = getcol(gno, setno, j); for (i = endno + 1; i < len; i++) { x[i - dist] = x[i]; } } if ((s = get_set_strings(gno, setno)) != NULL) { for (i = endno + 1; i < len; i++) { s[i - dist] = copy_string(s[i - dist], s[i]); } } setlength(gno, setno, len - dist); } /* * join several sets together; all but the first set in the list will be killed */ int join_sets(int gno, int *sets, int nsets) { int i, j, n, setno, setno_final, ncols, old_length, new_length; double *x1, *x2; char **s1, **s2; if (nsets < 2) { errmsg("nsets < 2"); return RETURN_FAILURE; } setno_final = sets[0]; ncols = dataset_cols(gno, setno_final); for (i = 0; i < nsets; i++) { setno = sets[i]; if (is_valid_setno(gno, setno) != TRUE) { errmsg("Invalid setno in the list"); return RETURN_FAILURE; } if (dataset_cols(gno, setno) != ncols) { errmsg("Can't join datasets with different number of cols"); return RETURN_FAILURE; } } new_length = getsetlength(gno, setno_final); for (i = 1; i < nsets; i++) { setno = sets[i]; old_length = new_length; new_length += getsetlength(gno, setno); if (setlength(gno, setno_final, new_length) != RETURN_SUCCESS) { return RETURN_FAILURE; } for (j = 0; j < ncols; j++) { x1 = getcol(gno, setno_final, j); x2 = getcol(gno, setno, j); for (n = old_length; n < new_length; n++) { x1[n] = x2[n - old_length]; } } s1 = get_set_strings(gno, setno_final); s2 = get_set_strings(gno, setno); if (s1 != NULL && s2 != NULL) { for (n = old_length; n < new_length; n++) { s1[n] = copy_string(s1[n], s2[n - old_length]); } } killset(gno, setno); } return RETURN_SUCCESS; } void reverse_set(int gno, int setno) { int n, i, j, k, ncols; double *x; char **s; if (!is_valid_setno(gno, setno)) { return; } n = getsetlength(gno, setno); ncols = dataset_cols(gno, setno); for (k = 0; k < ncols; k++) { x = getcol(gno, setno, k); for (i = 0; i < n / 2; i++) { j = (n - 1) - i; fswap(&x[i], &x[j]); } } if ((s = get_set_strings(gno, setno)) != NULL) { char *stmp; for (i = 0; i < n / 2; i++) { j = (n - 1) - i; stmp = s[i]; s[i] = s[j]; s[j] = stmp; } } set_dirtystate(); } /* * sort a set */ static double *vptr; /* * for ascending and descending sorts */ static int compare_points1(const void *p1, const void *p2) { const int *i1, *i2; double a, b; i1 = (const int *)p1; i2 = (const int *)p2; a = vptr[*i1]; b = vptr[*i2]; if (a < b) { return -1; } if (a > b) { return 1; } return 0; } static int compare_points2(const void *p1, const void *p2) { const int *i1, *i2; double a, b; i1 = (const int *)p1; i2 = (const int *)p2; a = vptr[*i1]; b = vptr[*i2]; if (a > b) { return -1; } if (a < b) { return 1; } return 0; } void sortset(int gno, int setno, int sorton, int stype) { int i, j, nc, len, *ind; double *x, *xtmp; char **s, **stmp; /* get the vector to sort on */ vptr = getcol(gno, setno, sorton); if (vptr == NULL) { errmsg("NULL vector in sort, operation cancelled, check set type"); return; } len = getsetlength(gno, setno); if (len <= 1) { return; } /* allocate memory for permuted indices */ ind = xmalloc(len*SIZEOF_INT); if (ind == NULL) { return; } /* allocate memory for temporary array */ xtmp = xmalloc(len*SIZEOF_DOUBLE); if (xtmp == NULL) { xfree(ind); return; } s = get_set_strings(gno, setno); if (s != NULL) { stmp = xmalloc(len*sizeof(char *)); if (stmp == NULL) { xfree(xtmp); xfree(ind); } } else { stmp = NULL; } /* initialize indices */ for (i = 0; i < len; i++) { ind[i] = i; } /* sort */ qsort(ind, len, SIZEOF_INT, stype ? compare_points2 : compare_points1); /* straighten things out - done one vector at a time for storage */ nc = dataset_cols(gno, setno); /* loop over the number of columns */ for (j = 0; j < nc; j++) { /* get this vector and put into the temporary vector in the right order */ x = getcol(gno, setno, j); for (i = 0; i < len; i++) { xtmp[i] = x[ind[i]]; } /* load it back to the set */ for (i = 0; i < len; i++) { x[i] = xtmp[i]; } } /* same with strings, if any */ if (s != NULL) { for (i = 0; i < len; i++) { stmp[i] = s[ind[i]]; } for (i = 0; i < len; i++) { s[i] = stmp[i]; } } /* free allocated temporary arrays */ xfree(stmp); xfree(xtmp); xfree(ind); set_dirtystate(); } /* * sort two arrays */ void sort_xy(double *tmp1, double *tmp2, int up, int sorton, int stype) { int d, i, j; int lo = 0; double t1, t2; if (sorton == 1) { double *ttmp; ttmp = tmp1; tmp1 = tmp2; tmp2 = ttmp; } up--; for (d = up - lo + 1; d > 1;) { if (d < 5) d = 1; else d = (5 * d - 1) / 11; for (i = up - d; i >= lo; i--) { t1 = tmp1[i]; t2 = tmp2[i]; if (!stype) { for (j = i + d; j <= up && (t1 > tmp1[j]); j += d) { tmp1[j - d] = tmp1[j]; tmp2[j - d] = tmp2[j]; } tmp1[j - d] = t1; tmp2[j - d] = t2; } else { for (j = i + d; j <= up && (t1 < tmp1[j]); j += d) { tmp1[j - d] = tmp1[j]; tmp2[j - d] = tmp2[j]; } tmp1[j - d] = t1; tmp2[j - d] = t2; } } } set_dirtystate(); } /* * delete the point pt in setno */ void del_point(int gno, int setno, int pt) { droppoints(gno, setno, pt, pt); } /* * add a point to setno */ void add_point(int gno, int setno, double px, double py) { int len; double *x, *y; if (is_valid_setno(gno, setno)) { len = getsetlength(gno, setno); setlength(gno, setno, len + 1); x = getx(gno, setno); y = gety(gno, setno); x[len] = px; y[len] = py; } } void zero_datapoint(Datapoint *dpoint) { int k; for (k = 0; k < MAX_SET_COLS; k++) { dpoint->ex[k] = 0.0; } dpoint->s = NULL; } /* * add a point to setno at ind */ int add_point_at(int gno, int setno, int ind, const Datapoint *dpoint) { int len, col, ncols; double *ex; char **s; if (is_valid_setno(gno, setno)) { len = getsetlength(gno, setno); if (ind < 0 || ind > len) { return RETURN_FAILURE; } len++; setlength(gno, setno, len); ncols = dataset_cols(gno, setno); for (col = 0; col < ncols; col++) { ex = getcol(gno, setno, col); if (ind < len - 1) { memmove(ex + ind + 1, ex + ind, (len - ind - 1)*SIZEOF_DOUBLE); } ex[ind] = dpoint->ex[col]; } s = get_set_strings(gno, setno); if (s != NULL) { if (ind < len - 1) { memmove(s + ind + 1, s + ind, (len - ind - 1)*sizeof(char *)); } s[ind] = copy_string(NULL, dpoint->s); } set_dirtystate(); return RETURN_SUCCESS; } else { return RETURN_FAILURE; } } int get_datapoint(int gno, int setno, int ind, int *ncols, Datapoint *dpoint) { int n, col; double *ex; char **s; n = getsetlength(gno, setno); if (ind < 0 || ind >= n) { return RETURN_FAILURE; } else { *ncols = dataset_cols(gno, setno); for (col = 0; col < *ncols; col++) { ex = getcol(gno, setno, col); dpoint->ex[col] = ex[ind]; } s = get_set_strings(gno, setno); if (s != NULL) { dpoint->s = s[ind]; } else { dpoint->s = NULL; } return RETURN_SUCCESS; } } void delete_byindex(int gno, int setno, int *ind) { int i, j, cnt = 0; int ncols = dataset_cols(gno, setno); if (is_valid_setno(gno, setno) != TRUE) { return; } for (i = 0; i < getsetlength(gno, setno); i++) { if (ind[i]) { cnt++; } } if (cnt == getsetlength(gno, setno)) { killset(gno, setno); return; } cnt = 0; for (i = 0; i < getsetlength(gno, setno); i++) { if (ind[i] == 0) { for (j = 0; j < ncols; j++) { (getcol(gno, setno, j))[cnt] = (getcol(gno, setno, j))[i]; } cnt++; } } setlength(gno, setno, cnt); } /* * move a set to another set, in possibly another graph */ int do_moveset(int gfrom, int setfrom, int gto, int setto) { int retval; char buf[64]; retval = moveset(gfrom, setfrom, gto, setto); if (retval != RETURN_SUCCESS) { sprintf(buf, "Error moving G%d.S%d to G%d.S%d", gfrom, setfrom, gto, setto); errmsg(buf); } return retval; } /* * do_copyset */ int do_copyset(int gfrom, int setfrom, int gto, int setto) { int retval; char buf[64]; retval = copyset(gfrom, setfrom, gto, setto); if (retval != RETURN_SUCCESS) { sprintf(buf, "Error copying G%d.S%d to G%d.S%d", gfrom, setfrom, gto, setto); errmsg(buf); } return retval; } /* * do_swapset */ int do_swapset(int gfrom, int setfrom, int gto, int setto) { int retval; char buf[64]; retval = swapset(gfrom, setfrom, gto, setto); if (retval != RETURN_SUCCESS) { sprintf(buf, "Error swapping G%d.S%d with G%d.S%d", gfrom, setfrom, gto, setto); errmsg(buf); } return retval; } /* * split a set into lpart length sets */ void do_splitsets(int gno, int setno, int lpart) { int i, j, k, ncols, len, plen, tmpset, npsets; double *x; char s[256]; plotarr p; Dataset ds, dstmp; if ((len = getsetlength(gno, setno)) < 2) { errmsg("Set length < 2"); return; } if (lpart >= len) { errmsg("Split length >= set length"); return; } if (lpart <= 0) { errmsg("Split length <= 0"); return; } npsets = (len - 1)/lpart + 1; /* get number of columns in this set */ ncols = dataset_cols(gno, setno); p = g[gno].p[setno]; /* save the contents to a temporary buffer */ memcpy(&ds, &p.data, sizeof(Dataset)); /* zero data contents of the original set */ zero_set_data(&g[gno].p[setno].data); /* now load each set */ for (i = 0; i < npsets; i++) { plen = MIN2(lpart, len - i*lpart); tmpset = nextset(gno); if (!is_valid_setno(gno, tmpset)) { errmsg("Can't create new set"); return; } /* set the plot parameters */ dstmp = g[gno].p[tmpset].data; g[gno].p[tmpset] = p; g[gno].p[tmpset].data = dstmp; set_set_hidden(gno, tmpset, FALSE); if (setlength(gno, tmpset, plen) != RETURN_SUCCESS) { /* should not happen */ return; } if (ds.s) { g[gno].p[tmpset].data.s = xmalloc(plen*sizeof(char *)); } /* load the data into each column */ for (k = 0; k < ncols; k++) { x = getcol(gno, tmpset, k); for (j = 0; j < plen; j++) { x[j] = ds.ex[k][i*lpart + j]; } } if (ds.s) { for (j = 0; j < plen; j++) { g[gno].p[tmpset].data.s[j] = copy_string(NULL, ds.s[i*lpart + j]); } } sprintf(s, "partition %d of set G%d.S%d", i + 1, gno, setno); setcomment(gno, tmpset, s); } free_set_data(&ds); } /* * drop points from an active set */ void do_drop_points(int gno, int setno, int startno, int endno) { int setlength; char buf[256]; if (!is_set_active(gno, setno)) { sprintf(buf, "Set %d not active", setno); errmsg(buf); return; } setlength = getsetlength(gno, setno); if (startno < 0) { startno = setlength + 1 + startno; } if (endno < 0) { endno = setlength + 1 + endno; } if (startno > endno) { iswap(&startno, &endno); } if (startno < 0) { errmsg("Start # < 0"); return; } if (endno >= setlength) { errmsg("Ending # >= set length"); return; } droppoints(gno, setno, startno, endno); } /* * sort sets, only works on sets of type XY */ void do_sort(int setno, int sorton, int stype) { int i, gno = get_cg(); char buf[256]; if (setno == -1) { for (i = 0; i < number_of_sets(gno); i++) { if (is_set_active(gno, i)) { sortset(gno, i, sorton, stype); } } } else { if (!is_set_active(gno, setno)) { sprintf(buf, "Set %d not active", setno); errmsg(buf); return; } else { sortset(gno, setno, sorton, stype); } } } double setybase(int gno, int setno) { double dummy, *y, ybase = 0.0; int len; if (is_valid_setno(gno, setno) != TRUE) { return 0.0; } y = getcol(gno, setno, DATA_Y); len = getsetlength(gno, setno); switch (g[gno].p[setno].baseline_type) { case BASELINE_TYPE_0: ybase = 0.0; break; case BASELINE_TYPE_SMIN: ybase = vmin(y, len); break; case BASELINE_TYPE_SAVG: stasum(y, len, &ybase, &dummy); break; case BASELINE_TYPE_SMAX: ybase = vmax(y, len); break; case BASELINE_TYPE_GMIN: ybase = g[gno].w.yg1; break; case BASELINE_TYPE_GMAX: ybase = g[gno].w.yg2; break; default: errmsg("Wrong type of baseline"); } return(ybase); } int dataset_cols(int gno, int setno) { return settype_cols(dataset_type(gno, setno)); } int load_comments_to_legend(int gno, int setno) { return set_legend_string(gno, setno, getcomment(gno, setno)); } int filter_set(int gno, int setno, char *rarray) { int i, ip, j, ncols; Dataset *dsp; if (is_valid_setno(gno, setno) != TRUE) { return RETURN_FAILURE; } if (rarray == NULL) { return RETURN_SUCCESS; } ncols = dataset_cols(gno, setno); dsp = &(g[gno].p[setno].data); ip = 0; for (i = 0; i < dsp->len; i++) { if (rarray[i]) { for (j = 0; j < ncols; j++) { dsp->ex[j][ip] = dsp->ex[j][i]; } if (dsp->s != NULL) { dsp->s[ip] = copy_string(dsp->s[ip], dsp->s[i]); } ip++; } } setlength(gno, setno, ip); return RETURN_SUCCESS; }