1 /*
2  * Grace - GRaphing, Advanced Computation and Exploration of data
3  *
4  * Home page: http://plasma-gate.weizmann.ac.il/Grace/
5  *
6  * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7  * Copyright (c) 1996-2000 Grace Development Team
8  *
9  * Maintained by Evgeny Stambulchik
10  *
11  *
12  *                           All Rights Reserved
13  *
14  *    This program is free software; you can redistribute it and/or modify
15  *    it under the terms of the GNU General Public License as published by
16  *    the Free Software Foundation; either version 2 of the License, or
17  *    (at your option) any later version.
18  *
19  *    This program is distributed in the hope that it will be useful,
20  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *    GNU General Public License for more details.
23  *
24  *    You should have received a copy of the GNU General Public License
25  *    along with this program; if not, write to the Free Software
26  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  */
28 
29 /*
30  *
31  * routines to allocate, manipulate, and return
32  * information about sets.
33  *
34  */
35 
36 #include <config.h>
37 #include <cmath.h>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include "globals.h"
44 #include "utils.h"
45 #include "files.h"
46 #include "graphs.h"
47 #include "protos.h"
48 
49 extern graph *g;
50 
51 /*
52  * return the string version of the set type
53  */
set_types(int it)54 char *set_types(int it)
55 {
56     char *s = "xy";
57 
58     switch (it) {
59     case SET_XY:
60 	s = "xy";
61 	break;
62     case SET_BAR:
63 	s = "bar";
64 	break;
65     case SET_BARDY:
66 	s = "bardy";
67 	break;
68     case SET_BARDYDY:
69 	s = "bardydy";
70 	break;
71     case SET_XYZ:
72 	s = "xyz";
73 	break;
74     case SET_XYDX:
75 	s = "xydx";
76 	break;
77     case SET_XYDY:
78 	s = "xydy";
79 	break;
80     case SET_XYDXDX:
81 	s = "xydxdx";
82 	break;
83     case SET_XYDYDY:
84 	s = "xydydy";
85 	break;
86     case SET_XYDXDY:
87 	s = "xydxdy";
88 	break;
89     case SET_XYDXDXDYDY:
90 	s = "xydxdxdydy";
91 	break;
92     case SET_XYHILO:
93 	s = "xyhilo";
94 	break;
95     case SET_XYR:
96 	s = "xyr";
97 	break;
98     case SET_XYCOLOR:
99 	s = "xycolor";
100 	break;
101     case SET_XYCOLPAT:
102 	s = "xycolpat";
103 	break;
104     case SET_XYVMAP:
105 	s = "xyvmap";
106 	break;
107     case SET_BOXPLOT:
108 	s = "xyboxplot";
109 	break;
110     case SET_XYSIZE:
111 	s = "xysize";
112 	break;
113     }
114     return s;
115 }
116 
get_settype_by_name(char * s)117 int get_settype_by_name(char *s)
118 {
119     int i;
120 
121     for (i = 0; i < NUMBER_OF_SETTYPES; i++) {
122         if (strcmp(set_types(i), s) == 0) {
123             return i;
124         }
125     }
126     return SET_BAD;
127 }
128 
settype_cols(int type)129 int settype_cols(int type)
130 {
131     int ncols;
132 
133     switch (type) {
134     case SET_XY:
135     case SET_BAR:
136 	ncols = 2;
137 	break;
138     case SET_XYDX:
139     case SET_XYDY:
140     case SET_XYZ:
141     case SET_BARDY:
142     case SET_XYR:
143     case SET_XYCOLOR:
144     case SET_XYSIZE:
145 	ncols = 3;
146 	break;
147     case SET_XYDXDX:
148     case SET_XYDYDY:
149     case SET_XYDXDY:
150     case SET_BARDYDY:
151     case SET_XYCOLPAT:
152     case SET_XYVMAP:
153 	ncols = 4;
154 	break;
155     case SET_XYHILO:
156 	ncols = 5;
157 	break;
158     case SET_XYDXDXDYDY:
159     case SET_BOXPLOT:
160 	ncols = 6;
161 	break;
162     default:
163         ncols = 0;
164         break;
165     }
166 
167     return ncols;
168 }
169 
170 /*
171  * return the string version of the dataset column
172  */
dataset_colname(int col)173 char *dataset_colname(int col)
174 {
175     char *s;
176 
177     switch (col) {
178     case 0:
179 	s = "X";
180 	break;
181     case 1:
182 	s = "Y";
183 	break;
184     case 2:
185 	s = "Y1";
186 	break;
187     case 3:
188 	s = "Y2";
189 	break;
190     case 4:
191 	s = "Y3";
192 	break;
193     case 5:
194 	s = "Y4";
195 	break;
196     default:
197 	s = "?";
198 	errmsg("Internal error in dataset_colname()");
199         break;
200     }
201     return s;
202 }
203 
zero_set_data(Dataset * dsp)204 int zero_set_data(Dataset *dsp)
205 {
206     int k;
207 
208     if (dsp) {
209         dsp->len = 0;
210         for (k = 0; k < MAX_SET_COLS; k++) {
211 	    dsp->ex[k] = NULL;
212         }
213         dsp->s = NULL;
214         return RETURN_SUCCESS;
215     } else {
216         return RETURN_FAILURE;
217     }
218 }
219 
220 /*
221  * free set data
222  */
free_set_data(Dataset * dsp)223 int free_set_data(Dataset *dsp)
224 {
225     int k;
226 
227     if (dsp) {
228         if (dsp->len) {
229             for (k = 0; k < MAX_SET_COLS; k++) {
230 	        XCFREE(dsp->ex[k]);
231             }
232             if (dsp->s) {
233 	        for (k = 0; k < dsp->len; k++) {
234 		    XCFREE(dsp->s[k]);
235 	        }
236                 XCFREE(dsp->s);
237             }
238             dsp->len = 0;
239 	    set_dirtystate();
240         }
241         return RETURN_SUCCESS;
242     } else {
243         return RETURN_FAILURE;
244     }
245 }
246 
247 /*
248  * free set data, but preserve the parameter settings
249  */
killsetdata(int gno,int setno)250 void killsetdata(int gno, int setno)
251 {
252     if (is_valid_setno(gno, setno)) {
253         free_set_data(&g[gno].p[setno].data);
254     }
255 }
256 
257 /*
258  * (re)allocate data arrays for a set of length len.
259  */
setlength(int gno,int setno,int len)260 int setlength(int gno, int setno, int len)
261 {
262     plotarr *p;
263     int i, j, ncols, oldlen;
264 
265     if (is_valid_setno(gno, setno) != TRUE) {
266         return RETURN_FAILURE;
267     }
268 
269     p = &g[gno].p[setno];
270 
271     oldlen = p->data.len;
272     if (len == oldlen) {
273 	return RETURN_SUCCESS;
274     }
275     if (len < 0) {
276 	return RETURN_FAILURE;
277     }
278 
279     ncols = settype_cols(p->type);
280 
281     if (ncols == 0) {
282 	errmsg("Set type not found in setlength()!");
283 	return RETURN_FAILURE;
284     }
285 
286     for (i = 0; i < ncols; i++) {
287 	if ((p->data.ex[i] = xrealloc(p->data.ex[i], len*SIZEOF_DOUBLE)) == NULL
288             && len != 0) {
289 	    return RETURN_FAILURE;
290 	}
291         for (j = oldlen; j < len; j++) {
292             p->data.ex[i][j] = 0.0;
293         }
294     }
295 
296     if (p->data.s != NULL) {
297         for (i = len; i < oldlen; i++) {
298             xfree(p->data.s[i]);
299         }
300         p->data.s = xrealloc(p->data.s, len*sizeof(char *));
301         for (j = oldlen; j < len; j++) {
302             p->data.s[j] = copy_string(NULL, "");
303         }
304     }
305 
306     p->data.len = len;
307 
308     set_dirtystate();
309 
310     return RETURN_SUCCESS;
311 }
312 
313 /*
314  * moveset
315  */
moveset(int gnofrom,int setfrom,int gnoto,int setto)316 int moveset(int gnofrom, int setfrom, int gnoto, int setto)
317 {
318     if (gnoto == gnofrom && setfrom == setto) {
319 	return RETURN_FAILURE;
320     }
321 
322     if (is_valid_setno(gnofrom, setfrom) != TRUE) {
323         return RETURN_FAILURE;
324     }
325 
326     if (is_set_active(gnoto, setto)) {
327 	killset(gnoto, setto);
328     }
329     activateset(gnoto, setto);
330 
331     memcpy(&g[gnoto].p[setto], &g[gnofrom].p[setfrom], sizeof(plotarr));
332 
333     zero_set_data(&g[gnofrom].p[setfrom].data);
334 
335     g[gnofrom].p[setfrom].hidden = TRUE;
336 
337     set_dirtystate();
338     return RETURN_SUCCESS;
339 }
340 
341 
342 /*
343  * copy a set to another set, if the to set doesn't exist allocate it
344  */
copyset(int gfrom,int setfrom,int gto,int setto)345 int copyset(int gfrom, int setfrom, int gto, int setto)
346 {
347     int i, k, len, ncols;
348     double *savec[MAX_SET_COLS];
349     char **saves;
350     char buf[256];
351 
352     if (!is_set_active(gfrom, setfrom)) {
353 	return RETURN_FAILURE;
354     }
355     if (!is_valid_gno(gto)) {
356 	return RETURN_FAILURE;
357     }
358     if (setfrom == setto && gfrom == gto) {
359 	return RETURN_FAILURE;
360     }
361     if (is_set_active(gto, setto)) {
362 	killset(gto, setto);
363     }
364     len = getsetlength(gfrom, setfrom);
365     ncols = dataset_cols(gfrom, setfrom);
366     activateset(gto, setto);
367     set_dataset_type(gto, setto, dataset_type(gfrom, setfrom));
368     if (setlength(gto, setto, len) != RETURN_SUCCESS) {
369 	return RETURN_FAILURE;
370     }
371     if (g[gfrom].p[setfrom].data.s != NULL) {
372         if ((g[gto].p[setto].data.s = xmalloc(len*sizeof(char *))) == NULL) {
373 	    return RETURN_FAILURE;
374         }
375     }
376 
377     for (k = 0; k < MAX_SET_COLS; k++) {
378 	savec[k] = getcol(gto, setto, k);
379     }
380     saves = get_set_strings(gto, setto);
381     memcpy(&g[gto].p[setto], &g[gfrom].p[setfrom], sizeof(plotarr));
382     for (k = 0; k < ncols; k++) {
383 	g[gto].p[setto].data.ex[k] = savec[k];
384 	memcpy(g[gto].p[setto].data.ex[k],
385                g[gfrom].p[setfrom].data.ex[k],
386                len*SIZEOF_DOUBLE);
387     }
388     g[gto].p[setto].data.s = saves;
389     if (g[gfrom].p[setfrom].data.s != NULL) {
390         for (i = 0; i < len; i++) {
391 	     g[gto].p[setto].data.s[i] =
392                 copy_string(NULL, g[gfrom].p[setfrom].data.s[i]);
393         }
394     }
395 
396     sprintf(buf, "copy of set G%d.S%d", gfrom, setfrom);
397     setcomment(gto, setto, buf);
398 
399     set_dirtystate();
400 
401     return RETURN_SUCCESS;
402 }
403 
404 /*
405  * same as copyset(), but doesn't alter the to set appearance
406  */
copysetdata(int gfrom,int setfrom,int gto,int setto)407 int copysetdata(int gfrom, int setfrom, int gto, int setto)
408 {
409     int i, k, len, ncols;
410     char buf[256];
411 
412     if (!is_set_active(gfrom, setfrom)) {
413 	return RETURN_FAILURE;
414     }
415     if (!is_valid_gno(gto)) {
416 	return RETURN_FAILURE;
417     }
418     if (setfrom == setto && gfrom == gto) {
419 	return RETURN_FAILURE;
420     }
421     if (is_set_active(gto, setto)) {
422 	killsetdata(gto, setto);
423     }
424     len = getsetlength(gfrom, setfrom);
425     ncols = dataset_cols(gfrom, setfrom);
426     activateset(gto, setto);
427     if (dataset_cols(gto, setto) != ncols) {
428         set_dataset_type(gto, setto, dataset_type(gfrom, setfrom));
429     }
430     if (setlength(gto, setto, len) != RETURN_SUCCESS) {
431         return RETURN_FAILURE;
432     }
433     if (g[gfrom].p[setfrom].data.s != NULL) {
434         if ((g[gto].p[setto].data.s = xmalloc(len*sizeof(char *))) == NULL) {
435 	    return RETURN_FAILURE;
436         }
437     }
438 
439     for (k = 0; k < ncols; k++) {
440 	memcpy(g[gto].p[setto].data.ex[k],
441                g[gfrom].p[setfrom].data.ex[k],
442                len*SIZEOF_DOUBLE);
443     }
444     if (g[gfrom].p[setfrom].data.s != NULL) {
445         for (i = 0; i < len; i++) {
446 	     g[gto].p[setto].data.s[i] =
447                 copy_string(NULL, g[gfrom].p[setfrom].data.s[i]);
448         }
449     }
450 
451     sprintf(buf, "copy of setdata G%d.S%d", gfrom, setfrom);
452     setcomment(gto, setto, buf);
453 
454     set_dirtystate();
455 
456     return RETURN_SUCCESS;
457 }
458 
459 /*
460  * swap a set with another set
461  */
swapset(int gno1,int setno1,int gno2,int setno2)462 int swapset(int gno1, int setno1, int gno2, int setno2)
463 {
464     plotarr p;
465 
466     if (is_valid_setno(gno1, setno1) == FALSE ||
467         is_valid_setno(gno2, setno2) == FALSE) {
468 	return RETURN_FAILURE;
469     }
470     if (setno1 == setno2 && gno1 == gno2) {
471 	return RETURN_FAILURE;
472     }
473 
474     memcpy(&p, &g[gno2].p[setno2], sizeof(plotarr));
475     memcpy(&g[gno2].p[setno2], &g[gno1].p[setno1], sizeof(plotarr));
476     memcpy(&g[gno1].p[setno1], &p, sizeof(plotarr));
477 
478     set_dirtystate();
479 
480     return RETURN_SUCCESS;
481 }
482 
483 /*
484  * kill a set
485  */
killset(int gno,int setno)486 void killset(int gno, int setno)
487 {
488     if (is_valid_setno(gno, setno)) {
489 	killsetdata(gno, setno);
490 	set_default_plotarr(&g[gno].p[setno]);
491     }
492 }
493 
getcol(int gno,int setno,int col)494 double *getcol(int gno, int setno, int col)
495 {
496     if (is_valid_setno(gno, setno)) {
497         return g[gno].p[setno].data.ex[col];
498     } else {
499         return NULL;
500     }
501 }
502 
setcol(int gno,int setno,int col,double * x,int len)503 void setcol(int gno, int setno, int col, double *x, int len)
504 {
505     if (is_valid_setno(gno, setno) != TRUE) {
506         return;
507     }
508     g[gno].p[setno].data.ex[col] = x;
509     g[gno].p[setno].data.len = len;
510     set_dirtystate();
511 }
512 
get_set_strings(int gno,int setno)513 char **get_set_strings(int gno, int setno)
514 {
515     if (is_valid_setno(gno, setno)) {
516         return g[gno].p[setno].data.s;
517     } else {
518         return NULL;
519     }
520 }
521 
set_set_strings(int gno,int setno,int len,char ** s)522 int set_set_strings(int gno, int setno, int len, char **s)
523 {
524     if (is_valid_setno(gno, setno) && len > 0 && s!= NULL) {
525         g[gno].p[setno].data.s = s;
526         g[gno].p[setno].data.len = len;
527         set_dirtystate();
528         return RETURN_SUCCESS;
529     } else {
530         return RETURN_FAILURE;
531     }
532 }
533 
getsetlength(int gno,int setno)534 int getsetlength(int gno, int setno)
535 {
536     if (is_valid_setno(gno, setno)) {
537         return g[gno].p[setno].data.len;
538     } else {
539         return -1;
540     }
541 }
542 
setcomment(int gno,int setno,char * s)543 int setcomment(int gno, int setno, char *s)
544 {
545     if (is_valid_setno(gno, setno) && s != NULL) {
546         strncpy(g[gno].p[setno].comments, s, MAX_STRING_LENGTH - 1);
547         set_dirtystate();
548         return RETURN_SUCCESS;
549     } else {
550         return RETURN_FAILURE;
551     }
552 }
553 
getcomment(int gno,int setno)554 char *getcomment(int gno, int setno)
555 {
556     if (is_valid_setno(gno, setno)) {
557         return g[gno].p[setno].comments;
558     } else {
559         return NULL;
560     }
561 }
562 
set_legend_string(int gno,int setno,char * s)563 int set_legend_string(int gno, int setno, char *s)
564 {
565     if (is_valid_setno(gno, setno) && s != NULL) {
566         strncpy(g[gno].p[setno].lstr, s, MAX_STRING_LENGTH - 1);
567         return RETURN_SUCCESS;
568     } else {
569         return RETURN_FAILURE;
570     }
571 }
572 
get_legend_string(int gno,int setno)573 char *get_legend_string(int gno, int setno)
574 {
575     if (is_valid_setno(gno, setno)) {
576         return g[gno].p[setno].lstr;
577     } else {
578         return NULL;
579     }
580 }
581 
set_dataset_type(int gno,int setno,int type)582 int set_dataset_type(int gno, int setno, int type)
583 {
584     int old_type = dataset_type(gno, setno);
585 
586     if (old_type < 0) {
587         /* wrong gno/setno */
588         return RETURN_FAILURE;
589     } else if (old_type == type) {
590         /* nothing changed */
591         return RETURN_SUCCESS;
592     } else {
593         int i, len, ncols_old, ncols_new;
594 
595         len = getsetlength(gno, setno);
596         ncols_old = dataset_cols(gno, setno);
597         ncols_new = settype_cols(type);
598         for (i = ncols_old; i < ncols_new; i++) {
599             g[gno].p[setno].data.ex[i] = xcalloc(len, SIZEOF_DOUBLE);
600         }
601         for (i = ncols_new; i < ncols_old; i++) {
602             XCFREE(g[gno].p[setno].data.ex[i]);
603         }
604 
605         g[gno].p[setno].type = type;
606 
607         set_dirtystate();
608         return RETURN_SUCCESS;
609     }
610 }
611 
dataset_type(int gno,int setno)612 int dataset_type(int gno, int setno)
613 {
614     if (is_valid_setno(gno, setno)) {
615         return g[gno].p[setno].type;
616     } else {
617         return -1;
618     }
619 }
620 
621 
622 
set_hotlink(int gno,int setno,int onoroff,char * fname,int src)623 void set_hotlink(int gno, int setno, int onoroff, char *fname, int src)
624 {
625     if (is_valid_setno(gno, setno) != TRUE) {
626         return;
627     }
628 
629     g[gno].p[setno].hotlink = onoroff;
630     if (onoroff && fname != NULL) {
631 	strcpy(g[gno].p[setno].hotfile, fname);
632 	g[gno].p[setno].hotsrc = src;
633     }
634     set_dirtystate();
635 }
636 
is_hotlinked(int gno,int setno)637 int is_hotlinked(int gno, int setno)
638 {
639     if (is_valid_setno(gno, setno) != TRUE) {
640         return FALSE;
641     }
642 
643     if (g[gno].p[setno].hotlink && strlen(g[gno].p[setno].hotfile)) {
644         return g[gno].p[setno].hotlink;
645     } else {
646         return FALSE;
647     }
648 }
649 
get_hotlink_file(int gno,int setno)650 char *get_hotlink_file(int gno, int setno)
651 {
652     if (is_valid_setno(gno, setno) != TRUE) {
653         return NULL;
654     } else {
655         return g[gno].p[setno].hotfile;
656     }
657 }
658 
get_hotlink_src(int gno,int setno)659 int get_hotlink_src(int gno, int setno)
660 {
661     if (is_valid_setno(gno, setno) != TRUE) {
662         return -1;
663     } else {
664         return g[gno].p[setno].hotsrc;
665     }
666 }
667 
do_update_hotlink(int gno,int setno)668 void do_update_hotlink(int gno, int setno)
669 {
670     if (is_hotlinked(gno, setno) != TRUE) {
671         return;
672     } else {
673         plotarr *p;
674         p = &g[gno].p[setno];
675         update_set_from_file(gno, setno, p->hotfile, p->hotsrc);
676     }
677 }
678 
679 
680 /*
681  * get the min/max fields of a set
682  */
getsetminmax(int gno,int setno,double * xmin,double * xmax,double * ymin,double * ymax)683 int getsetminmax(int gno, int setno,
684                     double *xmin, double *xmax, double *ymin, double *ymax)
685 {
686     double *x, *y;
687     int len;
688     double x1, x2, y1, y2;
689     int i, first = TRUE;
690     int imin, imax; /* dummy */
691 
692     if (setno == ALL_SETS) {
693         for (i = 0; i < number_of_sets(gno); i++) {
694             if (is_set_drawable(gno, i)) {
695                 x = getcol(gno, i, 0);
696                 y = getcol(gno, i, 1);
697                 len = getsetlength(gno, i);
698                 minmax(x, len, &x1, &x2, &imin, &imax);
699                 minmax(y, len, &y1, &y2, &imin, &imax);
700                 if (first) {
701                     *xmin = x1;
702                     *xmax = x2;
703                     *ymin = y1;
704                     *ymax = y2;
705                     first = FALSE;
706                 } else {
707                     *xmin = (x1 < *xmin) ? x1 : *xmin;
708                     *xmax = (x2 > *xmax) ? x2 : *xmax;
709                     *ymin = (y1 < *ymin) ? y1 : *ymin;
710                     *ymax = (y2 > *ymax) ? y2 : *ymax;
711                 }
712             }
713         }
714     } else if (is_valid_setno(gno, setno)) {
715         x = getcol(gno, setno, 0);
716         y = getcol(gno, setno, 1);
717         len = getsetlength(gno, setno);
718         minmax(x, len, xmin, xmax, &imin, &imax);
719         minmax(y, len, ymin, ymax, &imin, &imax);
720         first = FALSE;
721     }
722 
723     if (first == FALSE) {
724         return RETURN_SUCCESS;
725     } else {
726         return RETURN_FAILURE;
727     }
728 }
729 
730 /*
731  * get the min/max fields of a set with fixed x/y range
732  */
getsetminmax_c(int gno,int setno,double * xmin,double * xmax,double * ymin,double * ymax,int ivec)733 int getsetminmax_c(int gno, int setno,
734             double *xmin, double *xmax, double *ymin, double *ymax, int ivec)
735 {
736     double vmin_t, vmax_t, *vmin, *vmax, bvmin, bvmax, *vec, *bvec;
737     int i, start, stop, n;
738     int first = TRUE, hits;
739 
740     if (ivec == 1) {
741         bvmin = *xmin;
742         bvmax = *xmax;
743         vmin  = ymin;
744         vmax  = ymax;
745     } else {
746         bvmin = *ymin;
747         bvmax = *ymax;
748         vmin  = xmin;
749         vmax  = xmax;
750     }
751     if (setno == ALL_SETS) {
752         start = 0;
753         stop  = number_of_sets(gno) - 1;
754     } else if (is_valid_setno(gno, setno)) {
755         start = setno;
756         stop  = setno;
757     } else {
758         return RETURN_FAILURE;
759     }
760 
761     for (i = start; i <= stop; i++) {
762         if (is_set_drawable(gno, i)) {
763 
764             if (ivec == 1) {
765                 bvec = getx(gno, i);
766                 vec  = gety(gno, i);
767             } else {
768                 bvec = gety(gno, i);
769                 vec  = getx(gno, i);
770             }
771 
772             n = getsetlength(gno, i);
773             hits = minmaxrange(bvec, vec, n, bvmin, bvmax, &vmin_t, &vmax_t);
774             if (hits == RETURN_SUCCESS) {
775                 if (first) {
776                     *vmin = vmin_t;
777                     *vmax = vmax_t;
778                     first = FALSE;
779                 } else {
780                     *vmin = MIN2(vmin_t, *vmin);
781                     *vmax = MAX2(vmax_t, *vmax);
782                 }
783             }
784         }
785     }
786 
787     if (first == FALSE) {
788         return RETURN_SUCCESS;
789     } else {
790         return RETURN_FAILURE;
791     }
792 }
793 
794 
795 /*
796  * compute the mins and maxes of a vector x
797  */
minmax(double * x,int n,double * xmin,double * xmax,int * imin,int * imax)798 void minmax(double *x, int n, double *xmin, double *xmax, int *imin, int *imax)
799 {
800     int i;
801 
802     *imin = 0;
803     *imax = 0;
804 
805     if (x == NULL) {
806         *xmin = 0.0;
807         *xmax = 0.0;
808         return;
809     }
810 
811     *xmin = x[0];
812     *xmax = x[0];
813 
814     for (i = 1; i < n; i++) {
815 	if (x[i] < *xmin) {
816 	    *xmin = x[i];
817 	    *imin = i;
818 	}
819 	if (x[i] > *xmax) {
820 	    *xmax = x[i];
821 	    *imax = i;
822 	}
823     }
824 }
825 
826 
827 /*
828  * compute the min and max of vector vec calculated for indices such that
829  * bvec values lie within [bmin, bmax] range
830  * returns RETURN_FAILURE if none found
831  */
minmaxrange(double * bvec,double * vec,int n,double bvmin,double bvmax,double * vmin,double * vmax)832 int minmaxrange(double *bvec, double *vec, int n, double bvmin, double bvmax,
833               	   double *vmin, double *vmax)
834 {
835     int i, first = TRUE;
836 
837     if ((vec == NULL) || (bvec == NULL)) {
838         return RETURN_FAILURE;
839     }
840 
841     for (i = 0; i < n; i++) {
842         if ((bvec[i] >= bvmin) && (bvec[i] <= bvmax)) {
843 	    if (first == TRUE) {
844                 *vmin = vec[i];
845                 *vmax = vec[i];
846                 first = FALSE;
847             } else {
848                 if (vec[i] < *vmin) {
849                     *vmin = vec[i];
850   	        } else if (vec[i] > *vmax) {
851                     *vmax = vec[i];
852        	        }
853             }
854         }
855     }
856 
857     if (first == FALSE) {
858         return RETURN_SUCCESS;
859     } else {
860         return RETURN_FAILURE;
861     }
862 }
863 
864 
865 /*
866  * compute the mins and maxes of a vector x
867  */
vmin(double * x,int n)868 double vmin(double *x, int n)
869 {
870     int i;
871     double xmin;
872     if (n <= 0) {
873 	return 0.0;
874     }
875     xmin = x[0];
876     for (i = 1; i < n; i++) {
877 	if (x[i] < xmin) {
878 	    xmin = x[i];
879 	}
880     }
881     return xmin;
882 }
883 
vmax(double * x,int n)884 double vmax(double *x, int n)
885 {
886     int i;
887     double xmax;
888     if (n <= 0) {
889 	return 0.0;
890     }
891     xmax = x[0];
892     for (i = 1; i < n; i++) {
893 	if (x[i] > xmax) {
894 	    xmax = x[i];
895 	}
896     }
897     return xmax;
898 }
899 
set_point(int gno,int setno,int seti,WPoint wp)900 int set_point(int gno, int setno, int seti, WPoint wp)
901 {
902     if (is_valid_setno(gno, setno) != TRUE) {
903         return RETURN_FAILURE;
904     }
905     if (seti >= getsetlength(gno, setno) || seti < 0) {
906         return RETURN_FAILURE;
907     }
908     (getcol(gno, setno, DATA_X))[seti] = wp.x;
909     (getcol(gno, setno, DATA_Y))[seti] = wp.y;
910     set_dirtystate();
911     return RETURN_SUCCESS;
912 }
913 
get_point(int gno,int setno,int seti,WPoint * wp)914 int get_point(int gno, int setno, int seti, WPoint *wp)
915 {
916     if (is_valid_setno(gno, setno) != TRUE) {
917         return RETURN_FAILURE;
918     }
919     if (seti >= getsetlength(gno, setno) || seti < 0) {
920         return RETURN_FAILURE;
921     }
922     wp->x = (getcol(gno, setno, DATA_X))[seti];
923     wp->y = (getcol(gno, setno, DATA_Y))[seti];
924     return RETURN_SUCCESS;
925 }
926 
copycol2(int gfrom,int setfrom,int gto,int setto,int col)927 void copycol2(int gfrom, int setfrom, int gto, int setto, int col)
928 {
929     int i, n1, n2;
930     double *x1, *x2;
931 
932     if (is_valid_setno(gfrom, setfrom) != TRUE ||
933         is_valid_setno(gto, setto) != TRUE) {
934         return;
935     }
936     n1 = getsetlength(gfrom, setfrom);
937     n2 = getsetlength(gto, setto);
938     if (n1 != n2) {
939         return;
940     }
941     x1 = getcol(gfrom, setfrom, col);
942     x2 = getcol(gto, setto, col);
943     for (i = 0; i < n1; i++) {
944 	x2[i] = x1[i];
945     }
946     set_dirtystate();
947 }
948 
949 
pushset(int gno,int setno,int push_type)950 int pushset(int gno, int setno, int push_type)
951 {
952     int i, newsetno;
953 
954     if (is_valid_setno(gno, setno) != TRUE) {
955         return RETURN_FAILURE;
956     } else {
957         switch (push_type) {
958         case PUSH_SET_TOFRONT:
959             newsetno = number_of_sets(gno) - 1;
960             for (i = setno; i < newsetno; i++) {
961                 if (swapset(gno, i, gno, i + 1) != RETURN_SUCCESS) {
962                     return RETURN_FAILURE;
963                 }
964             }
965             break;
966         case PUSH_SET_TOBACK:
967             newsetno = 0;
968             for (i = setno; i > newsetno; i--) {
969                 if (swapset(gno, i, gno, i - 1) != RETURN_SUCCESS) {
970                     return RETURN_FAILURE;
971                 }
972             }
973             break;
974         default:
975             return RETURN_FAILURE;
976             break;
977         }
978         return RETURN_SUCCESS;
979     }
980 }
981 
982 
983 /*
984  * pack all sets leaving no gaps in the set structure
985  */
packsets(int gno)986 void packsets(int gno)
987 {
988     int i, j;
989 
990     for (i = 0; i < number_of_sets(gno); i++) {
991 	if (is_set_active(gno, i)) {
992 	    for (j = 0; j < i; j++) {
993 		if (is_set_active(gno, j) != TRUE) {
994 		    moveset(gno, i, gno, j);
995 		}
996 	    }
997 	}
998     }
999 }
1000 
allocate_set(int gno,int setno)1001 int allocate_set(int gno, int setno)
1002 {
1003     if (is_valid_setno(gno, setno)) {
1004         return RETURN_SUCCESS;
1005     } else
1006     if (setno >= 0) {
1007         return realloc_graph_plots(gno, setno + 1);
1008     } else {
1009         return RETURN_FAILURE;
1010     }
1011 }
1012 
activateset(int gno,int setno)1013 int activateset(int gno, int setno)
1014 {
1015     int retval;
1016 
1017     if (is_valid_gno(gno) != TRUE) {
1018         return RETURN_FAILURE;
1019     } else {
1020         retval = allocate_set(gno, setno);
1021         if (retval == RETURN_SUCCESS) {
1022             set_set_hidden(gno, setno, FALSE);
1023         }
1024         return retval;
1025     }
1026 }
1027 
1028 static target recent_target = {-1, -1};
1029 
get_recent_setno(void)1030 int get_recent_setno(void)
1031 {
1032     return recent_target.setno;
1033 }
1034 
get_recent_gno(void)1035 int get_recent_gno(void)
1036 {
1037     return recent_target.gno;
1038 }
1039 
1040 /*
1041  * return the next available set in graph gno
1042  * If target is allocated but with no data, choose it (used for loading sets
1043  * from project files when sets aren't packed)
1044  */
nextset(int gno)1045 int nextset(int gno)
1046 {
1047     int setno;
1048     int maxplot;
1049 
1050     if (is_valid_gno(gno) != TRUE) {
1051         return (-1);
1052     }
1053 
1054     if ( (target_set.gno == gno) &&
1055          is_valid_setno(target_set.gno, target_set.setno) &&
1056          !is_set_active(gno, target_set.setno)) {
1057 	setno = target_set.setno;
1058 	target_set.gno = -1;
1059 	target_set.setno = -1;
1060     } else {
1061         maxplot = number_of_sets(gno);
1062         for (setno = 0; setno < maxplot; setno++) {
1063             if (!is_set_active(gno, setno)) {
1064                 break;
1065             }
1066         }
1067         /* if no sets found, try allocating new one */
1068         if (setno == maxplot && allocate_set(gno, setno) != RETURN_SUCCESS) {
1069             return (-1);
1070         }
1071     }
1072     recent_target.gno = gno;
1073     recent_target.setno = setno;
1074     return (setno);
1075 }
1076 
is_set_active(int gno,int setno)1077 int is_set_active(int gno, int setno)
1078 {
1079     if (is_valid_setno(gno, setno) && getsetlength(gno, setno) > 0) {
1080         return TRUE;
1081     } else {
1082         return FALSE;
1083     }
1084 }
1085 
1086 /*
1087  * return number of active set(s) in gno
1088  */
number_of_active_sets(int gno)1089 int number_of_active_sets(int gno)
1090 {
1091     int setno, na;
1092 
1093     if (is_valid_gno(gno) != TRUE) {
1094         return -1;
1095     }
1096 
1097     na = 0;
1098     for (setno = 0; setno < number_of_sets(gno); setno++) {
1099 	if (is_set_active(gno, setno) == TRUE) {
1100 	    na++;
1101 	}
1102     }
1103     return na;
1104 }
1105 
1106 /*
1107  * drop points from a set
1108  */
droppoints(int gno,int setno,int startno,int endno)1109 void droppoints(int gno, int setno, int startno, int endno)
1110 {
1111     double *x;
1112     char **s;
1113     int i, j, len, ncols, dist;
1114 
1115     if (is_valid_setno(gno, setno) != TRUE) {
1116         return;
1117     }
1118 
1119     dist = endno - startno + 1;
1120     if (dist <= 0) {
1121         return;
1122     }
1123 
1124     len = getsetlength(gno, setno);
1125 
1126     if (dist == len) {
1127         killsetdata(gno, setno);
1128         return;
1129     }
1130 
1131     ncols = dataset_cols(gno, setno);
1132     for (j = 0; j < ncols; j++) {
1133 	x = getcol(gno, setno, j);
1134 	for (i = endno + 1; i < len; i++) {
1135 	    x[i - dist] = x[i];
1136 	}
1137     }
1138     if ((s = get_set_strings(gno, setno)) != NULL) {
1139 	for (i = endno + 1; i < len; i++) {
1140 	    s[i - dist] = copy_string(s[i - dist], s[i]);
1141 	}
1142     }
1143     setlength(gno, setno, len - dist);
1144 }
1145 
1146 /*
1147  * join several sets together; all but the first set in the list will be killed
1148  */
join_sets(int gno,int * sets,int nsets)1149 int join_sets(int gno, int *sets, int nsets)
1150 {
1151     int i, j, n, setno, setno_final, ncols, old_length, new_length;
1152     double *x1, *x2;
1153     char **s1, **s2;
1154 
1155     if (nsets < 2) {
1156         errmsg("nsets < 2");
1157         return RETURN_FAILURE;
1158     }
1159 
1160     setno_final = sets[0];
1161     ncols = dataset_cols(gno, setno_final);
1162     for (i = 0; i < nsets; i++) {
1163         setno = sets[i];
1164         if (is_valid_setno(gno, setno) != TRUE) {
1165             errmsg("Invalid setno in the list");
1166             return RETURN_FAILURE;
1167         }
1168         if (dataset_cols(gno, setno) != ncols) {
1169             errmsg("Can't join datasets with different number of cols");
1170             return RETURN_FAILURE;
1171         }
1172     }
1173 
1174     new_length = getsetlength(gno, setno_final);
1175     for (i = 1; i < nsets; i++) {
1176         setno = sets[i];
1177         old_length = new_length;
1178         new_length += getsetlength(gno, setno);
1179         if (setlength(gno, setno_final, new_length) != RETURN_SUCCESS) {
1180             return RETURN_FAILURE;
1181         }
1182         for (j = 0; j < ncols; j++) {
1183             x1 = getcol(gno, setno_final, j);
1184             x2 = getcol(gno, setno, j);
1185             for (n = old_length; n < new_length; n++) {
1186                 x1[n] = x2[n - old_length];
1187             }
1188         }
1189         s1 = get_set_strings(gno, setno_final);
1190         s2 = get_set_strings(gno, setno);
1191         if (s1 != NULL && s2 != NULL) {
1192             for (n = old_length; n < new_length; n++) {
1193                 s1[n] = copy_string(s1[n], s2[n - old_length]);
1194             }
1195         }
1196         killset(gno, setno);
1197     }
1198 
1199     return RETURN_SUCCESS;
1200 }
1201 
reverse_set(int gno,int setno)1202 void reverse_set(int gno, int setno)
1203 {
1204     int n, i, j, k, ncols;
1205     double *x;
1206     char **s;
1207 
1208     if (!is_valid_setno(gno, setno)) {
1209 	return;
1210     }
1211     n = getsetlength(gno, setno);
1212     ncols = dataset_cols(gno, setno);
1213     for (k = 0; k < ncols; k++) {
1214 	x = getcol(gno, setno, k);
1215 	for (i = 0; i < n / 2; i++) {
1216 	    j = (n - 1) - i;
1217 	    fswap(&x[i], &x[j]);
1218 	}
1219     }
1220     if ((s = get_set_strings(gno, setno)) != NULL) {
1221 	char *stmp;
1222         for (i = 0; i < n / 2; i++) {
1223 	    j = (n - 1) - i;
1224 	    stmp = s[i];
1225             s[i] = s[j];
1226             s[j] = stmp;
1227 	}
1228     }
1229     set_dirtystate();
1230 }
1231 /*
1232  * sort a set
1233  */
1234 static double *vptr;
1235 
1236 /*
1237  * for ascending and descending sorts
1238  */
1239 
compare_points1(const void * p1,const void * p2)1240 static int compare_points1(const void *p1, const void *p2)
1241 {
1242     const int *i1, *i2;
1243     double a, b;
1244     i1 = (const int *)p1;
1245     i2 = (const int *)p2;
1246     a = vptr[*i1];
1247     b = vptr[*i2];
1248     if (a < b) {
1249 	return -1;
1250     }
1251     if (a > b) {
1252 	return 1;
1253     }
1254     return 0;
1255 }
1256 
compare_points2(const void * p1,const void * p2)1257 static int compare_points2(const void *p1, const void *p2)
1258 {
1259     const int *i1, *i2;
1260     double a, b;
1261     i1 = (const int *)p1;
1262     i2 = (const int *)p2;
1263     a = vptr[*i1];
1264     b = vptr[*i2];
1265     if (a > b) {
1266 	return -1;
1267     }
1268     if (a < b) {
1269 	return 1;
1270     }
1271     return 0;
1272 }
1273 
sortset(int gno,int setno,int sorton,int stype)1274 void sortset(int gno, int setno, int sorton, int stype)
1275 {
1276     int i, j, nc, len, *ind;
1277     double *x, *xtmp;
1278     char **s, **stmp;
1279 
1280     /* get the vector to sort on */
1281     vptr = getcol(gno, setno, sorton);
1282     if (vptr == NULL) {
1283 	errmsg("NULL vector in sort, operation cancelled, check set type");
1284 	return;
1285     }
1286 
1287     len = getsetlength(gno, setno);
1288     if (len <= 1) {
1289 	return;
1290     }
1291 
1292     /* allocate memory for permuted indices */
1293     ind = xmalloc(len*SIZEOF_INT);
1294     if (ind == NULL) {
1295 	return;
1296     }
1297     /* allocate memory for temporary array */
1298     xtmp = xmalloc(len*SIZEOF_DOUBLE);
1299     if (xtmp == NULL) {
1300 	xfree(ind);
1301 	return;
1302     }
1303 
1304     s = get_set_strings(gno, setno);
1305     if (s != NULL) {
1306         stmp = xmalloc(len*sizeof(char *));
1307         if (stmp == NULL) {
1308 	    xfree(xtmp);
1309 	    xfree(ind);
1310         }
1311     } else {
1312         stmp = NULL;
1313     }
1314 
1315     /* initialize indices */
1316     for (i = 0; i < len; i++) {
1317 	ind[i] = i;
1318     }
1319 
1320     /* sort */
1321     qsort(ind, len, SIZEOF_INT, stype ? compare_points2 : compare_points1);
1322 
1323     /* straighten things out - done one vector at a time for storage */
1324 
1325     nc = dataset_cols(gno, setno);
1326     /* loop over the number of columns */
1327     for (j = 0; j < nc; j++) {
1328         /* get this vector and put into the temporary vector in the right order */
1329 	x = getcol(gno, setno, j);
1330 	for (i = 0; i < len; i++) {
1331 	    xtmp[i] = x[ind[i]];
1332 	}
1333 
1334         /* load it back to the set */
1335 	for (i = 0; i < len; i++) {
1336 	    x[i] = xtmp[i];
1337 	}
1338     }
1339 
1340     /* same with strings, if any */
1341     if (s != NULL) {
1342 	for (i = 0; i < len; i++) {
1343 	    stmp[i] = s[ind[i]];
1344 	}
1345 
1346 	for (i = 0; i < len; i++) {
1347 	    s[i] = stmp[i];
1348 	}
1349     }
1350 
1351     /* free allocated temporary arrays */
1352     xfree(stmp);
1353     xfree(xtmp);
1354     xfree(ind);
1355 
1356     set_dirtystate();
1357 }
1358 
1359 /*
1360  * sort two arrays
1361  */
sort_xy(double * tmp1,double * tmp2,int up,int sorton,int stype)1362 void sort_xy(double *tmp1, double *tmp2, int up, int sorton, int stype)
1363 {
1364 
1365     int d, i, j;
1366     int lo = 0;
1367     double t1, t2;
1368 
1369     if (sorton == 1) {
1370 	double *ttmp;
1371 
1372 	ttmp = tmp1;
1373 	tmp1 = tmp2;
1374 	tmp2 = ttmp;
1375     }
1376     up--;
1377 
1378     for (d = up - lo + 1; d > 1;) {
1379 	if (d < 5)
1380 	    d = 1;
1381 	else
1382 	    d = (5 * d - 1) / 11;
1383 	for (i = up - d; i >= lo; i--) {
1384 	    t1 = tmp1[i];
1385 	    t2 = tmp2[i];
1386 	    if (!stype) {
1387 		for (j = i + d; j <= up && (t1 > tmp1[j]); j += d) {
1388 		    tmp1[j - d] = tmp1[j];
1389 		    tmp2[j - d] = tmp2[j];
1390 		}
1391 		tmp1[j - d] = t1;
1392 		tmp2[j - d] = t2;
1393 	    } else {
1394 		for (j = i + d; j <= up && (t1 < tmp1[j]); j += d) {
1395 		    tmp1[j - d] = tmp1[j];
1396 		    tmp2[j - d] = tmp2[j];
1397 		}
1398 		tmp1[j - d] = t1;
1399 		tmp2[j - d] = t2;
1400 	    }
1401 	}
1402     }
1403     set_dirtystate();
1404 }
1405 
1406 /*
1407  * delete the point pt in setno
1408  */
del_point(int gno,int setno,int pt)1409 void del_point(int gno, int setno, int pt)
1410 {
1411     droppoints(gno, setno, pt, pt);
1412 }
1413 
1414 /*
1415  * add a point to setno
1416  */
add_point(int gno,int setno,double px,double py)1417 void add_point(int gno, int setno, double px, double py)
1418 {
1419     int len;
1420     double *x, *y;
1421 
1422     if (is_valid_setno(gno, setno)) {
1423 	 len = getsetlength(gno, setno);
1424 	 setlength(gno, setno, len + 1);
1425 	 x = getx(gno, setno);
1426 	 y = gety(gno, setno);
1427 	 x[len] = px;
1428 	 y[len] = py;
1429     }
1430 }
1431 
zero_datapoint(Datapoint * dpoint)1432 void zero_datapoint(Datapoint *dpoint)
1433 {
1434     int k;
1435 
1436     for (k = 0; k < MAX_SET_COLS; k++) {
1437         dpoint->ex[k] = 0.0;
1438     }
1439     dpoint->s = NULL;
1440 }
1441 
1442 /*
1443  * add a point to setno at ind
1444  */
add_point_at(int gno,int setno,int ind,const Datapoint * dpoint)1445 int add_point_at(int gno, int setno, int ind, const Datapoint *dpoint)
1446 {
1447     int len, col, ncols;
1448     double *ex;
1449     char **s;
1450 
1451     if (is_valid_setno(gno, setno)) {
1452         len = getsetlength(gno, setno);
1453         if (ind < 0 || ind > len) {
1454             return RETURN_FAILURE;
1455         }
1456         len++;
1457         setlength(gno, setno, len);
1458         ncols = dataset_cols(gno, setno);
1459         for (col = 0; col < ncols; col++) {
1460             ex = getcol(gno, setno, col);
1461             if (ind < len - 1) {
1462                 memmove(ex + ind + 1, ex + ind, (len - ind - 1)*SIZEOF_DOUBLE);
1463             }
1464             ex[ind] = dpoint->ex[col];
1465         }
1466         s = get_set_strings(gno, setno);
1467         if (s != NULL) {
1468             if (ind < len - 1) {
1469                 memmove(s + ind + 1, s + ind, (len - ind - 1)*sizeof(char *));
1470             }
1471             s[ind] = copy_string(NULL, dpoint->s);
1472         }
1473         set_dirtystate();
1474         return RETURN_SUCCESS;
1475     } else {
1476         return RETURN_FAILURE;
1477     }
1478 }
1479 
get_datapoint(int gno,int setno,int ind,int * ncols,Datapoint * dpoint)1480 int get_datapoint(int gno, int setno, int ind, int *ncols, Datapoint *dpoint)
1481 {
1482     int n, col;
1483     double *ex;
1484     char **s;
1485 
1486     n = getsetlength(gno, setno);
1487     if (ind < 0 || ind >= n) {
1488         return RETURN_FAILURE;
1489     } else {
1490         *ncols = dataset_cols(gno, setno);
1491         for (col = 0; col < *ncols; col++) {
1492             ex = getcol(gno, setno, col);
1493             dpoint->ex[col] = ex[ind];
1494         }
1495         s = get_set_strings(gno, setno);
1496         if (s != NULL) {
1497             dpoint->s = s[ind];
1498         } else {
1499             dpoint->s = NULL;
1500         }
1501         return RETURN_SUCCESS;
1502     }
1503 }
1504 
delete_byindex(int gno,int setno,int * ind)1505 void delete_byindex(int gno, int setno, int *ind)
1506 {
1507     int i, j, cnt = 0;
1508     int ncols = dataset_cols(gno, setno);
1509 
1510     if (is_valid_setno(gno, setno) != TRUE) {
1511         return;
1512     }
1513 
1514     for (i = 0; i < getsetlength(gno, setno); i++) {
1515 	if (ind[i]) {
1516 	    cnt++;
1517 	}
1518     }
1519     if (cnt == getsetlength(gno, setno)) {
1520 	killset(gno, setno);
1521 	return;
1522     }
1523     cnt = 0;
1524     for (i = 0; i < getsetlength(gno, setno); i++) {
1525 	if (ind[i] == 0) {
1526 	    for (j = 0; j < ncols; j++) {
1527                 (getcol(gno, setno, j))[cnt] = (getcol(gno, setno, j))[i];
1528 	    }
1529 	    cnt++;
1530 	}
1531     }
1532     setlength(gno, setno, cnt);
1533 }
1534 
1535 
1536 /*
1537  * move a set to another set, in possibly another graph
1538  */
do_moveset(int gfrom,int setfrom,int gto,int setto)1539 int do_moveset(int gfrom, int setfrom, int gto, int setto)
1540 {
1541     int retval;
1542     char buf[64];
1543 
1544     retval = moveset(gfrom, setfrom, gto, setto);
1545     if (retval != RETURN_SUCCESS) {
1546         sprintf(buf,
1547             "Error moving G%d.S%d to G%d.S%d",
1548             gfrom, setfrom, gto, setto);
1549         errmsg(buf);
1550     }
1551     return retval;
1552 }
1553 
1554 /*
1555  * do_copyset
1556  */
do_copyset(int gfrom,int setfrom,int gto,int setto)1557 int do_copyset(int gfrom, int setfrom, int gto, int setto)
1558 {
1559     int retval;
1560     char buf[64];
1561 
1562     retval = copyset(gfrom, setfrom, gto, setto);
1563     if (retval != RETURN_SUCCESS) {
1564         sprintf(buf,
1565             "Error copying G%d.S%d to G%d.S%d",
1566             gfrom, setfrom, gto, setto);
1567         errmsg(buf);
1568     }
1569     return retval;
1570 }
1571 
1572 /*
1573  * do_swapset
1574  */
do_swapset(int gfrom,int setfrom,int gto,int setto)1575 int do_swapset(int gfrom, int setfrom, int gto, int setto)
1576 {
1577     int retval;
1578     char buf[64];
1579 
1580     retval = swapset(gfrom, setfrom, gto, setto);
1581     if (retval != RETURN_SUCCESS) {
1582         sprintf(buf,
1583             "Error swapping G%d.S%d with G%d.S%d",
1584             gfrom, setfrom, gto, setto);
1585         errmsg(buf);
1586     }
1587     return retval;
1588 }
1589 
1590 /*
1591  * split a set into lpart length sets
1592  */
do_splitsets(int gno,int setno,int lpart)1593 void do_splitsets(int gno, int setno, int lpart)
1594 {
1595     int i, j, k, ncols, len, plen, tmpset, npsets;
1596     double *x;
1597     char s[256];
1598     plotarr p;
1599     Dataset ds, dstmp;
1600 
1601     if ((len = getsetlength(gno, setno)) < 2) {
1602 	errmsg("Set length < 2");
1603 	return;
1604     }
1605     if (lpart >= len) {
1606 	errmsg("Split length >= set length");
1607 	return;
1608     }
1609     if (lpart <= 0) {
1610 	errmsg("Split length <= 0");
1611 	return;
1612     }
1613 
1614     npsets = (len - 1)/lpart + 1;
1615 
1616     /* get number of columns in this set */
1617     ncols = dataset_cols(gno, setno);
1618 
1619     p = g[gno].p[setno];
1620 
1621     /* save the contents to a temporary buffer */
1622     memcpy(&ds, &p.data, sizeof(Dataset));
1623 
1624     /* zero data contents of the original set */
1625     zero_set_data(&g[gno].p[setno].data);
1626 
1627     /* now load each set */
1628     for (i = 0; i < npsets; i++) {
1629 	plen = MIN2(lpart, len - i*lpart);
1630         tmpset = nextset(gno);
1631         if (!is_valid_setno(gno, tmpset)) {
1632             errmsg("Can't create new set");
1633             return;
1634         }
1635 
1636         /* set the plot parameters */
1637 	dstmp = g[gno].p[tmpset].data;
1638         g[gno].p[tmpset] = p;
1639 	g[gno].p[tmpset].data = dstmp;
1640 
1641 	set_set_hidden(gno, tmpset, FALSE);
1642 	if (setlength(gno, tmpset, plen) != RETURN_SUCCESS) {
1643             /* should not happen */
1644             return;
1645         }
1646         if (ds.s) {
1647             g[gno].p[tmpset].data.s = xmalloc(plen*sizeof(char *));
1648         }
1649 
1650         /* load the data into each column */
1651 	for (k = 0; k < ncols; k++) {
1652 	    x = getcol(gno, tmpset, k);
1653 	    for (j = 0; j < plen; j++) {
1654 		x[j] = ds.ex[k][i*lpart + j];
1655 	    }
1656 	}
1657         if (ds.s) {
1658 	    for (j = 0; j < plen; j++) {
1659 		g[gno].p[tmpset].data.s[j] =
1660                     copy_string(NULL, ds.s[i*lpart + j]);
1661 	    }
1662         }
1663 
1664         sprintf(s, "partition %d of set G%d.S%d", i + 1, gno, setno);
1665 	setcomment(gno, tmpset, s);
1666     }
1667 
1668     free_set_data(&ds);
1669 }
1670 
1671 /*
1672  * drop points from an active set
1673  */
do_drop_points(int gno,int setno,int startno,int endno)1674 void do_drop_points(int gno, int setno, int startno, int endno)
1675 {
1676     int setlength;
1677     char buf[256];
1678 
1679     if (!is_set_active(gno, setno)) {
1680 	sprintf(buf, "Set %d not active", setno);
1681 	errmsg(buf);
1682 	return;
1683     }
1684 
1685     setlength = getsetlength(gno, setno);
1686     if (startno < 0) {
1687         startno = setlength + 1 + startno;
1688     }
1689     if (endno < 0) {
1690         endno = setlength + 1 + endno;
1691     }
1692 
1693     if (startno > endno) {
1694         iswap(&startno, &endno);
1695     }
1696 
1697     if (startno < 0) {
1698 	errmsg("Start # < 0");
1699 	return;
1700     }
1701     if (endno >= setlength) {
1702 	errmsg("Ending # >= set length");
1703 	return;
1704     }
1705 
1706     droppoints(gno, setno, startno, endno);
1707 }
1708 
1709 
1710 /*
1711  * sort sets, only works on sets of type XY
1712  */
do_sort(int setno,int sorton,int stype)1713 void do_sort(int setno, int sorton, int stype)
1714 {
1715     int i, gno = get_cg();
1716     char buf[256];
1717 
1718     if (setno == -1) {
1719 	for (i = 0; i < number_of_sets(gno); i++) {
1720 	    if (is_set_active(gno, i)) {
1721 		sortset(gno, i, sorton, stype);
1722 	    }
1723 	}
1724     } else {
1725 	if (!is_set_active(gno, setno)) {
1726 	    sprintf(buf, "Set %d not active", setno);
1727 	    errmsg(buf);
1728 	    return;
1729 	} else {
1730 	    sortset(gno, setno, sorton, stype);
1731 	}
1732     }
1733 }
1734 
1735 
setybase(int gno,int setno)1736 double setybase(int gno, int setno)
1737 {
1738     double dummy, *y, ybase = 0.0;
1739     int len;
1740 
1741     if (is_valid_setno(gno, setno) != TRUE) {
1742         return 0.0;
1743     }
1744 
1745     y = getcol(gno, setno, DATA_Y);
1746     len = getsetlength(gno, setno);
1747 
1748     switch (g[gno].p[setno].baseline_type) {
1749     case BASELINE_TYPE_0:
1750         ybase = 0.0;
1751         break;
1752     case BASELINE_TYPE_SMIN:
1753         ybase = vmin(y, len);
1754         break;
1755     case BASELINE_TYPE_SAVG:
1756         stasum(y, len, &ybase, &dummy);
1757         break;
1758     case BASELINE_TYPE_SMAX:
1759         ybase = vmax(y, len);
1760         break;
1761     case BASELINE_TYPE_GMIN:
1762         ybase = g[gno].w.yg1;
1763         break;
1764     case BASELINE_TYPE_GMAX:
1765         ybase = g[gno].w.yg2;
1766         break;
1767     default:
1768         errmsg("Wrong type of baseline");
1769     }
1770 
1771     return(ybase);
1772 }
1773 
1774 
dataset_cols(int gno,int setno)1775 int dataset_cols(int gno, int setno)
1776 {
1777     return settype_cols(dataset_type(gno, setno));
1778 }
1779 
load_comments_to_legend(int gno,int setno)1780 int load_comments_to_legend(int gno, int setno)
1781 {
1782     return set_legend_string(gno, setno, getcomment(gno, setno));
1783 }
1784 
filter_set(int gno,int setno,char * rarray)1785 int filter_set(int gno, int setno, char *rarray)
1786 {
1787     int i, ip, j, ncols;
1788     Dataset *dsp;
1789 
1790     if (is_valid_setno(gno, setno) != TRUE) {
1791         return RETURN_FAILURE;
1792     }
1793     if (rarray == NULL) {
1794         return RETURN_SUCCESS;
1795     }
1796     ncols = dataset_cols(gno, setno);
1797     dsp = &(g[gno].p[setno].data);
1798     ip = 0;
1799     for (i = 0; i < dsp->len; i++) {
1800         if (rarray[i]) {
1801             for (j = 0; j < ncols; j++) {
1802                 dsp->ex[j][ip] = dsp->ex[j][i];
1803             }
1804             if (dsp->s != NULL) {
1805                 dsp->s[ip] = copy_string(dsp->s[ip], dsp->s[i]);
1806             }
1807             ip++;
1808         }
1809     }
1810     setlength(gno, setno, ip);
1811     return RETURN_SUCCESS;
1812 }
1813