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-2003 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  * Graph stuff
32  *
33  */
34 
35 #include <config.h>
36 #include <cmath.h>
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "defines.h"
43 #include "utils.h"
44 #include "device.h"
45 #include "draw.h"
46 #include "graphs.h"
47 #include "graphutils.h"
48 #include "parser.h"
49 
50 #include "protos.h"
51 
52 /* graph definition */
53 graph *g = NULL;
54 static int maxgraph = 0;
55 
56 /* the current graph */
57 static int cg = -1;
58 
is_valid_gno(int gno)59 int is_valid_gno(int gno)
60 {
61     if (gno >= 0 && gno < maxgraph) {
62         return TRUE;
63     } else {
64         return FALSE;
65     }
66 }
67 
number_of_graphs(void)68 int number_of_graphs(void)
69 {
70     return maxgraph;
71 }
72 
get_cg(void)73 int get_cg(void)
74 {
75     return cg;
76 }
77 
graph_types(int it)78 char *graph_types(int it)
79 {
80     static char s[16];
81 
82     switch (it) {
83     case GRAPH_XY:
84 	strcpy(s, "XY");
85 	break;
86     case GRAPH_CHART:
87 	strcpy(s, "Chart");
88 	break;
89     case GRAPH_POLAR:
90 	strcpy(s, "Polar");
91 	break;
92     case GRAPH_SMITH:
93 	strcpy(s, "Smith");
94 	break;
95     case GRAPH_FIXED:
96 	strcpy(s, "Fixed");
97 	break;
98     case GRAPH_PIE:
99 	strcpy(s, "Pie");
100 	break;
101     default:
102         strcpy(s, "Unknown");
103 	break;
104    }
105     return s;
106 }
107 
108 /*
109  * kill all sets in a graph
110  */
kill_all_sets(int gno)111 int kill_all_sets(int gno)
112 {
113     int i;
114 
115     if (is_valid_gno(gno) == TRUE) {
116 	for (i = 0; i < g[gno].maxplot; i++) {
117 	    killset(gno, i);
118 	}
119         return RETURN_SUCCESS;
120     } else {
121         return RETURN_FAILURE;
122     }
123 }
124 
kill_graph(int gno)125 int kill_graph(int gno)
126 {
127     int j;
128     if (is_valid_gno(gno) == TRUE) {
129 	kill_all_sets(gno);
130         XCFREE(g[gno].labs.title.s);
131         XCFREE(g[gno].labs.stitle.s);
132         for (j = 0; j < MAXAXES; j++) {
133             free_graph_tickmarks(g[gno].t[j]);
134             g[gno].t[j] = NULL;
135         }
136 
137         if (gno == maxgraph - 1) {
138             maxgraph--;
139             g = xrealloc(g, maxgraph*sizeof(graph));
140             if (cg == gno) {
141                 cg--;
142             }
143         } else {
144             set_graph_hidden(gno, TRUE);
145         }
146 
147         set_dirtystate();
148         return RETURN_SUCCESS;
149     } else {
150         return RETURN_FAILURE;
151     }
152 }
153 
kill_all_graphs(void)154 void kill_all_graphs(void)
155 {
156     int i;
157 
158     for (i = maxgraph - 1; i >= 0; i--) {
159         kill_graph(i);
160     }
161 }
162 
copy_graph(int from,int to)163 int copy_graph(int from, int to)
164 {
165     int i, j;
166 
167     if (is_valid_gno(from) != TRUE || is_valid_gno(to) != TRUE || from == to) {
168         return RETURN_FAILURE;
169     }
170 
171     /* kill target graph */
172     kill_all_sets(to);
173     XCFREE(g[to].labs.title.s);
174     XCFREE(g[to].labs.stitle.s);
175     for (j = 0; j < MAXAXES; j++) {
176         free_graph_tickmarks(g[to].t[j]);
177         g[to].t[j] = NULL;
178     }
179 
180     memcpy(&g[to], &g[from], sizeof(graph));
181 
182     /* zero allocatable storage */
183     g[to].p = NULL;
184     g[to].maxplot = 0;
185     g[to].labs.title.s = NULL;
186     g[to].labs.stitle.s = NULL;
187 
188     /* duplicate allocatable storage */
189     if (realloc_graph_plots(to, g[from].maxplot) != RETURN_SUCCESS) {
190         return RETURN_FAILURE;
191     }
192     for (i = 0; i < g[from].maxplot; i++) {
193         do_copyset(from, i, to, i);
194     }
195     g[to].labs.title.s = copy_string(NULL, g[from].labs.title.s);
196     g[to].labs.stitle.s = copy_string(NULL, g[from].labs.stitle.s);
197     for (j = 0; j < MAXAXES; j++) {
198 	g[to].t[j] = copy_graph_tickmarks(g[from].t[j]);
199     }
200 
201     return RETURN_SUCCESS;
202 }
203 
move_graph(int from,int to)204 int move_graph(int from, int to)
205 {
206     if (is_valid_gno(from) != TRUE || is_valid_gno(to) != TRUE) {
207         return RETURN_FAILURE;
208     }
209 
210     if (copy_graph(from, to) != RETURN_SUCCESS) {
211         return RETURN_FAILURE;
212     } else {
213         kill_graph(from);
214         return RETURN_SUCCESS;
215     }
216 }
217 
duplicate_graph(int gno)218 int duplicate_graph(int gno)
219 {
220     int new_gno = maxgraph;
221 
222     if (is_valid_gno(gno) != TRUE) {
223         return RETURN_FAILURE;
224     }
225 
226     if (set_graph_active(new_gno) != RETURN_SUCCESS) {
227         return RETURN_FAILURE;
228     }
229 
230     if (copy_graph(gno, new_gno) != RETURN_SUCCESS) {
231         return RETURN_FAILURE;
232     } else {
233         return RETURN_SUCCESS;
234     }
235 }
236 
swap_graph(int from,int to)237 int swap_graph(int from, int to)
238 {
239     graph gtmp;
240 
241     if (is_valid_gno(from) != TRUE || is_valid_gno(to) != TRUE) {
242         return RETURN_FAILURE;
243     }
244 
245     memcpy(&gtmp, &g[from], sizeof(graph));
246     memcpy(&g[from], &g[to], sizeof(graph));
247     memcpy(&g[to], &gtmp, sizeof(graph));
248 
249     set_dirtystate();
250 
251     return RETURN_SUCCESS;
252 }
253 
get_graph_framep(int gno,framep * f)254 int get_graph_framep(int gno, framep *f)
255 {
256     if (is_valid_gno(gno) == TRUE) {
257         memcpy(f, &g[gno].f, sizeof(framep));
258         return RETURN_SUCCESS;
259     } else {
260         return RETURN_FAILURE;
261     }
262 }
263 
get_graph_locator(int gno,GLocator * locator)264 int get_graph_locator(int gno, GLocator *locator)
265 {
266     if (is_valid_gno(gno) == TRUE) {
267         memcpy(locator, &g[gno].locator, sizeof(GLocator));
268         return RETURN_SUCCESS;
269     } else {
270         return RETURN_FAILURE;
271     }
272 }
273 
get_graph_world(int gno,world * w)274 int get_graph_world(int gno, world *w)
275 {
276     if (is_valid_gno(gno) == TRUE) {
277         memcpy(w, &g[gno].w, sizeof(world));
278         return RETURN_SUCCESS;
279     } else {
280         return RETURN_FAILURE;
281     }
282 }
283 
get_graph_viewport(int gno,view * v)284 int get_graph_viewport(int gno, view *v)
285 {
286     if (is_valid_gno(gno) == TRUE) {
287         memcpy(v, &g[gno].v, sizeof(view));
288         return RETURN_SUCCESS;
289     } else {
290         return RETURN_FAILURE;
291     }
292 }
293 
get_graph_labels(int gno,labels * labs)294 int get_graph_labels(int gno, labels *labs)
295 {
296     if (is_valid_gno(gno) == TRUE) {
297         memcpy(labs, &g[gno].labs, sizeof(labels));
298         return RETURN_SUCCESS;
299     } else {
300         return RETURN_FAILURE;
301     }
302 }
303 
get_graph_plotarr(int gno,int i,plotarr * p)304 int get_graph_plotarr(int gno, int i, plotarr *p)
305 {
306     if (is_valid_gno(gno) == TRUE) {
307         memcpy(p, &g[gno].p[i], sizeof(plotarr));
308         return RETURN_SUCCESS;
309     } else {
310         return RETURN_FAILURE;
311     }
312 }
313 
314 /* Tickmarks */
315 
is_valid_axis(int gno,int axis)316 int is_valid_axis(int gno, int axis)
317 {
318     if (is_valid_gno(gno) &&
319         axis >= 0 && axis < MAXAXES &&
320         g[gno].t[axis] != NULL) {
321         return TRUE;
322     } else {
323         return FALSE;
324     }
325 }
326 
get_graph_tickmarks(int gno,int a)327 tickmarks *get_graph_tickmarks(int gno, int a)
328 {
329     if (is_valid_axis(gno, a) == TRUE) {
330         return g[gno].t[a];
331     } else {
332         return NULL;
333     }
334 }
335 
new_graph_tickmarks(void)336 tickmarks *new_graph_tickmarks(void)
337 {
338     tickmarks *retval;
339 
340     retval = xmalloc(sizeof(tickmarks));
341     if (retval != NULL) {
342         set_default_ticks(retval);
343     }
344     return retval;
345 }
346 
copy_graph_tickmarks(tickmarks * t)347 tickmarks *copy_graph_tickmarks(tickmarks *t)
348 {
349     tickmarks *retval;
350     int i;
351 
352     if (t == NULL) {
353         return NULL;
354     } else {
355         retval = new_graph_tickmarks();
356         if (retval != NULL) {
357             memcpy(retval, t, sizeof(tickmarks));
358 	    retval->label.s = copy_string(NULL, t->label.s);
359 	    retval->tl_formula = copy_string(NULL, t->tl_formula);
360             for (i = 0; i < MAX_TICKS; i++) {
361                 retval->tloc[i].label = copy_string(NULL, t->tloc[i].label);
362             }
363         }
364         return retval;
365     }
366 }
367 
free_graph_tickmarks(tickmarks * t)368 void free_graph_tickmarks(tickmarks *t)
369 {
370     int i;
371 
372     if (t == NULL) {
373         return;
374     }
375     XCFREE(t->label.s);
376     XCFREE(t->tl_formula);
377     for (i = 0; i < MAX_TICKS; i++) {
378         XCFREE(t->tloc[i].label);
379     }
380     XCFREE(t);
381 }
382 
set_graph_tickmarks(int gno,int a,tickmarks * t)383 int set_graph_tickmarks(int gno, int a, tickmarks *t)
384 {
385     if (is_valid_axis(gno, a) == TRUE) {
386         free_graph_tickmarks(g[gno].t[a]);
387         g[gno].t[a] = copy_graph_tickmarks(t);
388         return RETURN_SUCCESS;
389     } else {
390         return RETURN_FAILURE;
391     }
392 }
393 
394 
get_graph_legend(int gno,legend * leg)395 int get_graph_legend(int gno, legend *leg)
396 {
397     if (is_valid_gno(gno) == TRUE) {
398         memcpy(leg, &g[gno].l, sizeof(legend));
399         return RETURN_SUCCESS;
400     } else {
401         return RETURN_FAILURE;
402     }
403 }
404 
graph_allocate(int gno)405 int graph_allocate(int gno)
406 {
407     int retval;
408 
409     if (is_valid_gno(gno)) {
410         return RETURN_SUCCESS;
411     } else
412     if (gno >= maxgraph) {
413         retval = realloc_graphs(gno + 1);
414         if (retval != RETURN_SUCCESS) {
415             return RETURN_FAILURE;
416         } else {
417             return set_graph_hidden(gno, TRUE);
418         }
419     } else {
420         return RETURN_FAILURE;
421     }
422 }
423 
424 
set_graph_active(int gno)425 int set_graph_active(int gno)
426 {
427     if (graph_allocate(gno) != RETURN_SUCCESS) {
428         return RETURN_FAILURE;
429     } else {
430         return set_graph_hidden(gno, FALSE);
431     }
432 }
433 
set_graph_framep(int gno,framep * f)434 void set_graph_framep(int gno, framep * f)
435 {
436     if (is_valid_gno(gno) != TRUE) {
437         return;
438     }
439 
440     memcpy(&g[gno].f, f, sizeof(framep));
441 
442     set_dirtystate();
443 }
444 
set_graph_locator(int gno,GLocator * locator)445 void set_graph_locator(int gno, GLocator *locator)
446 {
447     if (is_valid_gno(gno) != TRUE) {
448         return;
449     }
450 
451     memcpy(&g[gno].locator, locator, sizeof(GLocator));
452 
453     set_dirtystate();
454 }
455 
set_graph_world(int gno,world w)456 void set_graph_world(int gno, world w)
457 {
458     if (is_valid_gno(gno) != TRUE) {
459         return;
460     }
461 
462     g[gno].w = w;
463 
464     set_dirtystate();
465 }
466 
set_graph_viewport(int gno,view v)467 void set_graph_viewport(int gno, view v)
468 {
469     if (is_valid_gno(gno) != TRUE) {
470         return;
471     }
472 
473     g[gno].v = v;
474 
475     set_dirtystate();
476 }
477 
set_graph_labels(int gno,labels * labs)478 void set_graph_labels(int gno, labels *labs)
479 {
480     if (is_valid_gno(gno) != TRUE) {
481         return;
482     }
483 
484     xfree(g[gno].labs.title.s);
485     xfree(g[gno].labs.stitle.s);
486     memcpy(&g[gno].labs, labs, sizeof(labels));
487     g[gno].labs.title.s = copy_string(NULL, labs->title.s);
488     g[gno].labs.stitle.s = copy_string(NULL, labs->stitle.s);
489 
490     set_dirtystate();
491 }
492 
set_graph_plotarr(int gno,int i,plotarr * p)493 void set_graph_plotarr(int gno, int i, plotarr * p)
494 {
495     if (is_valid_gno(gno) != TRUE) {
496         return;
497     }
498 
499     memcpy(&g[gno].p[i], p, sizeof(plotarr));
500 
501     set_dirtystate();
502 }
503 
set_graph_legend(int gno,legend * leg)504 void set_graph_legend(int gno, legend *leg)
505 {
506     if (is_valid_gno(gno) != TRUE) {
507         return;
508     }
509 
510     memcpy(&g[gno].l, leg, sizeof(legend));
511 
512     set_dirtystate();
513 }
514 
set_graph_legend_active(int gno,int flag)515 void set_graph_legend_active(int gno, int flag)
516 {
517     if (is_valid_gno(gno) != TRUE) {
518         return;
519     }
520 
521     g[gno].l.active = flag;
522 
523     set_dirtystate();
524 }
525 
526 
527 /*
528  * Count the number of active sets in graph gno
529  */
nactive(int gno)530 int nactive(int gno)
531 {
532     int i, cnt = 0;
533 
534     for (i = 0; i < number_of_sets(gno); i++) {
535 	if (is_set_active(gno, i)) {
536 	    cnt++;
537 	}
538     }
539 
540     return cnt;
541 }
542 
543 
544 
select_graph(int gno)545 int select_graph(int gno)
546 {
547     int retval;
548 
549     if (set_parser_gno(gno) == RETURN_SUCCESS) {
550         cg = gno;
551         retval = definewindow(g[gno].w, g[gno].v, g[gno].type,
552                               g[gno].xscale, g[gno].yscale,
553                               g[gno].xinvert, g[gno].yinvert);
554     } else {
555         retval = RETURN_FAILURE;
556     }
557 
558     return retval;
559 }
560 
realloc_graphs(int n)561 int realloc_graphs(int n)
562 {
563     int j;
564     graph *gtmp;
565 
566     if (n <= 0) {
567         return RETURN_FAILURE;
568     }
569     gtmp = xrealloc(g, n*sizeof(graph));
570     if (gtmp == NULL) {
571         return RETURN_FAILURE;
572     } else {
573         g = gtmp;
574         for (j = maxgraph; j < n; j++) {
575             set_default_graph(j);
576         }
577         maxgraph = n;
578         return RETURN_SUCCESS;
579     }
580 }
581 
realloc_graph_plots(int gno,int n)582 int realloc_graph_plots(int gno, int n)
583 {
584     int oldmaxplot, j;
585     plotarr *ptmp;
586     int c, bg;
587 
588     if (is_valid_gno(gno) != TRUE) {
589         return RETURN_FAILURE;
590     }
591     if (n < 0) {
592         return RETURN_FAILURE;
593     }
594     if (n == g[gno].maxplot) {
595         return RETURN_SUCCESS;
596     }
597     ptmp = xrealloc(g[gno].p, n * sizeof(plotarr));
598     if (ptmp == NULL && n != 0) {
599         return RETURN_FAILURE;
600     } else {
601         oldmaxplot = g[gno].maxplot;
602         g[gno].p = ptmp;
603         g[gno].maxplot = n;
604         bg = getbgcolor();
605         c = oldmaxplot + 1;
606         for (j = oldmaxplot; j < n; j++) {
607             set_default_plotarr(&g[gno].p[j]);
608             while (c == bg || get_colortype(c) != COLOR_MAIN) {
609                 c++;
610                 c %= number_of_colors();
611             }
612             set_set_colors(gno, j, c);
613             c++;
614         }
615         return RETURN_SUCCESS;
616     }
617 }
618 
619 
set_graph_type(int gno,int gtype)620 int set_graph_type(int gno, int gtype)
621 {
622     if (is_valid_gno(gno) == TRUE) {
623         if (g[gno].type == gtype) {
624             return RETURN_SUCCESS;
625         }
626 
627         switch (gtype) {
628         case GRAPH_XY:
629         case GRAPH_CHART:
630         case GRAPH_FIXED:
631         case GRAPH_PIE:
632             break;
633         case GRAPH_POLAR:
634 	    g[gno].w.xg1 = 0.0;
635 	    g[gno].w.xg2 = 2*M_PI;
636 	    g[gno].w.yg1 = 0.0;
637 	    g[gno].w.yg2 = 1.0;
638             break;
639         case GRAPH_SMITH:
640 	    g[gno].w.xg1 = -1.0;
641 	    g[gno].w.xg2 =  1.0;
642 	    g[gno].w.yg1 = -1.0;
643 	    g[gno].w.yg2 =  1.0;
644             break;
645         default:
646             errmsg("Internal error in set_graph_type()");
647             return RETURN_FAILURE;
648         }
649         g[gno].type = gtype;
650         return RETURN_SUCCESS;
651     } else {
652         return RETURN_FAILURE;
653     }
654 }
655 
is_graph_hidden(int gno)656 int is_graph_hidden(int gno)
657 {
658     if (is_valid_gno(gno) == TRUE) {
659         return g[gno].hidden;
660     } else {
661         return TRUE;
662     }
663 }
664 
set_graph_hidden(int gno,int flag)665 int set_graph_hidden(int gno, int flag)
666 {
667     if (is_valid_gno(gno) == TRUE) {
668         g[gno].hidden = flag;
669         set_dirtystate();
670         return RETURN_SUCCESS;
671     } else {
672         return RETURN_FAILURE;
673     }
674 }
675 
set_graph_stacked(int gno,int flag)676 int set_graph_stacked(int gno, int flag)
677 {
678     if (is_valid_gno(gno) == TRUE) {
679         g[gno].stacked = flag;
680         set_dirtystate();
681         return RETURN_SUCCESS;
682     } else {
683         return RETURN_FAILURE;
684     }
685 }
686 
is_graph_stacked(int gno)687 int is_graph_stacked(int gno)
688 {
689     if (is_valid_gno(gno) == TRUE) {
690         return g[gno].stacked;
691     } else {
692         return FALSE;
693     }
694 }
695 
get_graph_bargap(int gno)696 double get_graph_bargap(int gno)
697 {
698     if (is_valid_gno(gno) == TRUE) {
699         return g[gno].bargap;
700     } else {
701         return 0.0;
702     }
703 }
704 
set_graph_bargap(int gno,double bargap)705 int set_graph_bargap(int gno, double bargap)
706 {
707     if (is_valid_gno(gno) == TRUE) {
708         g[gno].bargap = bargap;
709         set_dirtystate();
710         return RETURN_SUCCESS;
711     } else {
712         return RETURN_FAILURE;
713     }
714 }
715 
get_graph_type(int gno)716 int get_graph_type(int gno)
717 {
718     if (is_valid_gno(gno) == TRUE) {
719         return g[gno].type;
720     } else {
721         return -1;
722     }
723 }
724 
is_refpoint_active(int gno)725 int is_refpoint_active(int gno)
726 {
727     if (is_valid_gno(gno) == TRUE) {
728         return g[gno].locator.pointset;
729     } else {
730         return FALSE;
731     }
732 }
733 
get_graph_xscale(int gno)734 int get_graph_xscale(int gno)
735 {
736     if (is_valid_gno(gno) == TRUE) {
737         return g[gno].xscale;
738     } else {
739         return -1;
740     }
741 }
742 
get_graph_yscale(int gno)743 int get_graph_yscale(int gno)
744 {
745     if (is_valid_gno(gno) == TRUE) {
746         return g[gno].yscale;
747     } else {
748         return -1;
749     }
750 }
751 
set_graph_xscale(int gno,int scale)752 int set_graph_xscale(int gno, int scale)
753 {
754     if (is_valid_gno(gno) == TRUE) {
755         if (g[gno].xscale != scale) {
756             int naxis;
757             g[gno].xscale = scale;
758             for (naxis = 0; naxis < MAXAXES; naxis++) {
759                 if (is_xaxis(naxis)) {
760                     tickmarks *t;
761                     t = get_graph_tickmarks(gno, naxis);
762                     if (t) {
763                         if (scale == SCALE_LOG) {
764                             if (g[gno].w.xg2 <= 0.0) {
765                                 g[gno].w.xg2 = 10.0;
766                             }
767                             if (g[gno].w.xg1 <= 0.0) {
768                                 g[gno].w.xg1 = g[gno].w.xg2/1.0e3;
769                             }
770                             t->tmajor = 10.0;
771                             t->nminor = 9;
772                         } else {
773                             t->nminor = 1;
774                         }
775                     }
776                 }
777             }
778             set_dirtystate();
779         }
780         return RETURN_SUCCESS;
781     } else {
782         return RETURN_FAILURE;
783     }
784 }
785 
set_graph_yscale(int gno,int scale)786 int set_graph_yscale(int gno, int scale)
787 {
788     if (is_valid_gno(gno) == TRUE) {
789         if (g[gno].yscale != scale) {
790             int naxis;
791             g[gno].yscale = scale;
792             for (naxis = 0; naxis < MAXAXES; naxis++) {
793                 if (is_yaxis(naxis)) {
794                     tickmarks *t;
795                     t = get_graph_tickmarks(gno, naxis);
796                     if (t) {
797                         if (scale == SCALE_LOG) {
798                             if (g[gno].w.yg2 <= 0.0) {
799                                 g[gno].w.yg2 = 10.0;
800                             }
801                             if (g[gno].w.yg1 <= 0.0) {
802                                 g[gno].w.yg1 = g[gno].w.yg2/1.0e3;
803                             }
804                             t->tmajor = 10.0;
805                             t->nminor = 9;
806                         } else {
807                             t->nminor = 1;
808                         }
809                     }
810                 }
811             }
812             set_dirtystate();
813         }
814         return RETURN_SUCCESS;
815     } else {
816         return RETURN_FAILURE;
817     }
818 }
819 
set_graph_znorm(int gno,double norm)820 int set_graph_znorm(int gno, double norm)
821 {
822     if (is_valid_gno(gno) == TRUE) {
823         g[gno].znorm = norm;
824         set_dirtystate();
825         return RETURN_SUCCESS;
826     } else {
827         return RETURN_FAILURE;
828     }
829 }
830 
get_graph_znorm(int gno)831 double get_graph_znorm(int gno)
832 {
833     if (is_valid_gno(gno) == TRUE) {
834         return g[gno].znorm;
835     } else {
836         return 0.0;
837     }
838 }
839 
is_graph_xinvert(int gno)840 int is_graph_xinvert(int gno)
841 {
842     if (is_valid_gno(gno) == TRUE) {
843         return g[gno].xinvert;
844     } else {
845         return FALSE;
846     }
847 }
848 
is_graph_yinvert(int gno)849 int is_graph_yinvert(int gno)
850 {
851     if (is_valid_gno(gno) == TRUE) {
852         return g[gno].yinvert;
853     } else {
854         return FALSE;
855     }
856 }
857 
set_graph_xinvert(int gno,int flag)858 int set_graph_xinvert(int gno, int flag)
859 {
860     if (is_valid_gno(gno) == TRUE) {
861         g[gno].xinvert = flag;
862         set_dirtystate();
863         return RETURN_SUCCESS;
864     } else {
865         return RETURN_FAILURE;
866     }
867 }
868 
set_graph_yinvert(int gno,int flag)869 int set_graph_yinvert(int gno, int flag)
870 {
871     if (is_valid_gno(gno) == TRUE) {
872         g[gno].yinvert = flag;
873         set_dirtystate();
874         return RETURN_SUCCESS;
875     } else {
876         return RETURN_FAILURE;
877     }
878 }
879 
is_axis_active(int gno,int axis)880 int is_axis_active(int gno, int axis)
881 {
882     if (is_valid_axis(gno, axis) == TRUE) {
883         return g[gno].t[axis]->active;
884     } else {
885         return FALSE;
886     }
887 }
888 
is_zero_axis(int gno,int axis)889 int is_zero_axis(int gno, int axis)
890 {
891     if (is_valid_axis(gno, axis) == TRUE) {
892         return g[gno].t[axis]->zero;
893     } else {
894         return FALSE;
895     }
896 }
897 
islogx(int gno)898 int islogx(int gno)
899 {
900     if (is_valid_gno(gno) == TRUE) {
901         return (g[gno].xscale == SCALE_LOG);
902     } else {
903         return FALSE;
904     }
905 }
906 
islogy(int gno)907 int islogy(int gno)
908 {
909     if (is_valid_gno(gno) == TRUE) {
910         return (g[gno].yscale == SCALE_LOG);
911     } else {
912         return FALSE;
913     }
914 }
915 
islogitx(int gno)916 int islogitx(int gno)
917 {
918     if (is_valid_gno(gno) == TRUE) {
919         return (g[gno].xscale == SCALE_LOGIT);
920     } else {
921         return FALSE;
922     }
923 }
924 
islogity(int gno)925 int islogity(int gno)
926 {
927     if (is_valid_gno(gno) == TRUE) {
928         return (g[gno].yscale == SCALE_LOGIT);
929     } else {
930         return FALSE;
931     }
932 }
933 
934 /*
935  * Stack manipulation functions
936  */
937 
clear_world_stack(void)938 void clear_world_stack(void)
939 {
940     if (is_valid_gno(cg) != TRUE) {
941         return;
942     }
943 
944     g[cg].ws_top = 1;
945     g[cg].curw = 0;
946     g[cg].ws[0].w.xg1 = 0.0;
947     g[cg].ws[0].w.xg2 = 0.0;
948     g[cg].ws[0].w.yg1 = 0.0;
949     g[cg].ws[0].w.yg2 = 0.0;
950 }
951 
update_world_stack()952 static void update_world_stack()
953 {
954     if (is_valid_gno(cg) != TRUE) {
955         return;
956     }
957 
958     g[cg].ws[g[cg].curw].w = g[cg].w;
959 }
960 
961 /* Add a world window to the stack
962  * If there are other windows, simply add this one to the bottom of the stack
963  * Otherwise, replace the first window with the new window
964  */
add_world(int gno,double x1,double x2,double y1,double y2)965 void add_world(int gno, double x1, double x2, double y1, double y2)
966 {
967     if (is_valid_gno(gno) != TRUE) {
968         return;
969     }
970 
971     /* see if another entry has been stacked */
972     if( g[gno].ws[0].w.xg1 == 0.0 &&
973 	g[gno].ws[0].w.xg2 == 0.0 &&
974 	g[gno].ws[0].w.yg1 == 0.0 &&
975  	g[gno].ws[0].w.yg2 == 0.0 ) {
976 	    g[gno].ws_top = 0;
977 	}
978 
979     if (g[gno].ws_top < MAX_ZOOM_STACK) {
980 	g[gno].ws[g[gno].ws_top].w.xg1 = x1;
981 	g[gno].ws[g[gno].ws_top].w.xg2 = x2;
982 	g[gno].ws[g[gno].ws_top].w.yg1 = y1;
983 	g[gno].ws[g[gno].ws_top].w.yg2 = y2;
984 
985 	g[gno].ws_top++;
986     } else {
987 	errmsg("World stack full");
988     }
989 }
990 
cycle_world_stack(void)991 void cycle_world_stack(void)
992 {
993     int neww;
994 
995     if (is_valid_gno(cg) != TRUE) {
996         return;
997     }
998 
999     if (g[cg].ws_top < 1) {
1000 	errmsg("World stack empty");
1001     } else {
1002 	update_world_stack();
1003 	neww = (g[cg].curw + 1) % g[cg].ws_top;
1004  	show_world_stack(neww);
1005     }
1006 }
1007 
show_world_stack(int n)1008 void show_world_stack(int n)
1009 {
1010     if (is_valid_gno(cg) != TRUE) {
1011         return;
1012     }
1013 
1014     if (g[cg].ws_top < 1) {
1015 	errmsg("World stack empty");
1016     } else {
1017 	if (n >= g[cg].ws_top) {
1018 	    errmsg("Selected view greater than stack depth");
1019 	} else if (n < 0) {
1020 	    errmsg("Selected view less than zero");
1021 	} else {
1022 	    g[cg].curw = n;
1023 	    g[cg].w = g[cg].ws[n].w;
1024 	}
1025     }
1026 }
1027 
push_world(void)1028 void push_world(void)
1029 {
1030     int i;
1031 
1032     if (is_valid_gno(cg) != TRUE) {
1033         return;
1034     }
1035 
1036     if (g[cg].ws_top < MAX_ZOOM_STACK) {
1037         update_world_stack();
1038         for( i=g[cg].ws_top; i>g[cg].curw; i-- ) {
1039                g[cg].ws[i] = g[cg].ws[i-1];
1040         }
1041 	g[cg].ws_top++;
1042     } else {
1043 	errmsg("World stack full");
1044     }
1045 }
1046 
1047 /* modified to actually pop the current world view off the stack */
pop_world(void)1048 void pop_world(void)
1049 {
1050     int i, neww;
1051 
1052     if (is_valid_gno(cg) != TRUE) {
1053         return;
1054     }
1055 
1056     if (g[cg].ws_top <= 1) {
1057 	errmsg("World stack empty");
1058     } else {
1059     	if (g[cg].curw != g[cg].ws_top - 1) {
1060     	    for (i = g[cg].curw; i < g[cg].ws_top; i++) {
1061                 g[cg].ws[i] = g[cg].ws[i + 1];
1062             }
1063             neww = g[cg].curw;
1064     	} else {
1065             neww = g[cg].curw - 1;
1066         }
1067         g[cg].ws_top--;
1068         show_world_stack(neww);
1069     }
1070 }
1071 
1072 
set_default_graph(int gno)1073 void set_default_graph(int gno)
1074 {
1075     int i;
1076 
1077     g[gno].hidden = TRUE;
1078     g[gno].type = GRAPH_XY;
1079     g[gno].xinvert = FALSE;
1080     g[gno].yinvert = FALSE;
1081     g[gno].xyflip = FALSE;
1082     g[gno].stacked = FALSE;
1083     g[gno].bargap = 0.0;
1084     g[gno].znorm  = 1.0;
1085     g[gno].xscale = SCALE_NORMAL;
1086     g[gno].yscale = SCALE_NORMAL;
1087     g[gno].ws_top = 1;
1088     g[gno].ws[0].w.xg1=g[gno].ws[0].w.xg2=g[gno].ws[0].w.yg1=g[gno].ws[0].w.yg2=0;
1089         g[gno].curw = 0;
1090     g[gno].locator.dsx = g[gno].locator.dsy = 0.0;      /* locator props */
1091     g[gno].locator.pointset = FALSE;
1092     g[gno].locator.pt_type = 0;
1093     g[gno].locator.fx = FORMAT_GENERAL;
1094     g[gno].locator.fy = FORMAT_GENERAL;
1095     g[gno].locator.px = 6;
1096     g[gno].locator.py = 6;
1097     for (i = 0; i < MAXAXES; i++) {
1098         g[gno].t[i] = new_graph_tickmarks();
1099         switch (i) {
1100         case X_AXIS:
1101         case Y_AXIS:
1102             g[gno].t[i]->active = TRUE;
1103             break;
1104         case ZX_AXIS:
1105         case ZY_AXIS:
1106             g[gno].t[i]->active = FALSE;
1107             break;
1108         }
1109     }
1110     set_default_framep(&g[gno].f);
1111     set_default_world(&g[gno].w);
1112     set_default_view(&g[gno].v);
1113     set_default_legend(gno, &g[gno].l);
1114     set_default_string(&g[gno].labs.title);
1115     g[gno].labs.title.charsize = 1.5;
1116     set_default_string(&g[gno].labs.stitle);
1117     g[gno].labs.stitle.charsize = 1.0;
1118     g[gno].maxplot = 0;
1119     g[gno].p = NULL;
1120 }
1121 
is_valid_setno(int gno,int setno)1122 int is_valid_setno(int gno, int setno)
1123 {
1124     if (is_valid_gno(gno) == TRUE && setno >= 0 && setno < g[gno].maxplot) {
1125         return TRUE;
1126     } else {
1127         return FALSE;
1128     }
1129 }
1130 
is_set_hidden(int gno,int setno)1131 int is_set_hidden(int gno, int setno)
1132 {
1133     if (is_valid_setno(gno, setno) == TRUE) {
1134         return g[gno].p[setno].hidden;
1135     } else {
1136         return FALSE;
1137     }
1138 }
1139 
set_set_hidden(int gno,int setno,int flag)1140 int set_set_hidden(int gno, int setno, int flag)
1141 {
1142     if (is_valid_setno(gno, setno) == TRUE) {
1143         g[gno].p[setno].hidden = flag;
1144         set_dirtystate();
1145         return RETURN_SUCCESS;
1146     } else {
1147         return RETURN_FAILURE;
1148     }
1149 }
1150 
number_of_sets(int gno)1151 int number_of_sets(int gno)
1152 {
1153     if (is_valid_gno(gno) == TRUE) {
1154         return g[gno].maxplot;
1155     } else {
1156         return -1;
1157     }
1158 }
1159 
graph_world_stack_size(int gno)1160 int graph_world_stack_size(int gno)
1161 {
1162     if (is_valid_gno(gno) == TRUE) {
1163         return g[gno].ws_top;
1164     } else {
1165         return -1;
1166     }
1167 }
1168 
get_world_stack_current(int gno)1169 int get_world_stack_current(int gno)
1170 {
1171     if (is_valid_gno(gno) == TRUE) {
1172         return g[gno].curw;
1173     } else {
1174         return -1;
1175     }
1176 }
1177 
get_world_stack_entry(int gno,int n,world_stack * ws)1178 int get_world_stack_entry(int gno, int n, world_stack *ws)
1179 {
1180     if (is_valid_gno(gno) == TRUE) {
1181         memcpy(ws, &g[gno].ws[n], sizeof(world_stack));
1182         return RETURN_SUCCESS;
1183     } else {
1184         return RETURN_FAILURE;
1185     }
1186 }
1187 
activate_tick_labels(int gno,int axis,int flag)1188 int activate_tick_labels(int gno, int axis, int flag)
1189 {
1190     if (is_valid_axis(gno, axis) == TRUE) {
1191         g[gno].t[axis]->tl_flag = flag;
1192         set_dirtystate();
1193         return RETURN_SUCCESS;
1194     } else {
1195         return RETURN_FAILURE;
1196     }
1197 }
1198 
set_set_colors(int gno,int setno,int color)1199 int set_set_colors(int gno, int setno, int color)
1200 {
1201     if (is_valid_setno(gno, setno) != TRUE) {
1202         return RETURN_FAILURE;
1203     }
1204     if (color >= number_of_colors() || color < 0) {
1205         return RETURN_FAILURE;
1206     }
1207 
1208     g[gno].p[setno].linepen.color = color;
1209     g[gno].p[setno].sympen.color = color;
1210     g[gno].p[setno].symfillpen.color = color;
1211     g[gno].p[setno].errbar.pen.color = color;
1212 
1213     set_dirtystate();
1214     return RETURN_SUCCESS;
1215 }
1216 
1217 static int project_version;
1218 
get_project_version(void)1219 int get_project_version(void)
1220 {
1221     return project_version;
1222 }
1223 
set_project_version(int version)1224 int set_project_version(int version)
1225 {
1226     if (version  > bi_version_id()) {
1227         project_version = bi_version_id();
1228         return RETURN_FAILURE;
1229     } else {
1230         project_version = version;
1231         return RETURN_SUCCESS;
1232     }
1233 }
1234 
reset_project_version(void)1235 void reset_project_version(void)
1236 {
1237     project_version = bi_version_id();
1238 }
1239 
1240 static char *project_description = NULL;
1241 
set_project_description(char * descr)1242 void set_project_description(char *descr)
1243 {
1244     project_description = copy_string(project_description, descr);
1245     set_dirtystate();
1246 }
1247 
get_project_description(void)1248 char *get_project_description(void)
1249 {
1250     return project_description;
1251 }
1252 
1253 extern plotstr *pstr;
1254 
postprocess_project(int version)1255 void postprocess_project(int version)
1256 {
1257     int gno, setno, naxis, strno;
1258     double ext_x, ext_y;
1259 
1260     if (version >= bi_version_id()) {
1261         return;
1262     }
1263 
1264     if (version < 40005) {
1265         set_page_dimensions(792, 612, FALSE);
1266     }
1267 
1268     if (get_project_version() < 50002) {
1269         setbgfill(TRUE);
1270     }
1271 
1272     if (get_project_version() < 50003) {
1273         allow_two_digits_years(TRUE);
1274         set_wrap_year(1900);
1275     }
1276 
1277     if (version <= 40102) {
1278 #ifndef NONE_GUI
1279         set_pagelayout(PAGE_FIXED);
1280 #endif
1281         get_page_viewport(&ext_x, &ext_y);
1282         rescale_viewport(ext_x, ext_y);
1283     }
1284 
1285     for (gno = 0; gno < number_of_graphs(); gno++) {
1286 	if (version <= 40102) {
1287             g[gno].l.vgap -= 1;
1288         }
1289 	for (setno = 0; setno < number_of_sets(gno); setno++) {
1290             if (version < 50000) {
1291                 switch (g[gno].p[setno].sym) {
1292                 case SYM_NONE:
1293                     break;
1294                 case SYM_DOT_OBS:
1295                     g[gno].p[setno].sym = SYM_CIRCLE;
1296                     g[gno].p[setno].symsize = 0.0;
1297                     g[gno].p[setno].symlines = 0;
1298                     g[gno].p[setno].symfillpen.pattern = 1;
1299                     break;
1300                 default:
1301                     g[gno].p[setno].sym--;
1302                     break;
1303                 }
1304             }
1305             if ((version < 40004 && g[gno].type != GRAPH_CHART) ||
1306                 g[gno].p[setno].sympen.color == -1) {
1307                 g[gno].p[setno].sympen.color = g[gno].p[setno].linepen.color;
1308             }
1309             if (version < 40200 || g[gno].p[setno].symfillpen.color == -1) {
1310                 g[gno].p[setno].symfillpen.color = g[gno].p[setno].sympen.color;
1311             }
1312 
1313 	    if (version <= 40102 && g[gno].type == GRAPH_CHART) {
1314                 set_dataset_type(gno, setno, SET_BAR);
1315                 g[gno].p[setno].sympen = g[gno].p[setno].linepen;
1316                 g[gno].p[setno].symlines = g[gno].p[setno].lines;
1317                 g[gno].p[setno].symlinew = g[gno].p[setno].linew;
1318                 g[gno].p[setno].lines = 0;
1319 
1320                 g[gno].p[setno].symfillpen = g[gno].p[setno].setfillpen;
1321                 g[gno].p[setno].setfillpen.pattern = 0;
1322             }
1323 	    if (version <= 40102 && g[gno].p[setno].type == SET_XYHILO) {
1324                 g[gno].p[setno].symlinew = g[gno].p[setno].linew;
1325             }
1326 	    if (version <= 50112 && g[gno].p[setno].type == SET_XYHILO) {
1327                 g[gno].p[setno].avalue.active = FALSE;
1328             }
1329 	    if (version < 50100 && g[gno].p[setno].type == SET_BOXPLOT) {
1330                 g[gno].p[setno].symlinew = g[gno].p[setno].linew;
1331                 g[gno].p[setno].symlines = g[gno].p[setno].lines;
1332                 g[gno].p[setno].symsize = 2.0;
1333                 g[gno].p[setno].errbar.riser_linew = g[gno].p[setno].linew;
1334                 g[gno].p[setno].errbar.riser_lines = g[gno].p[setno].lines;
1335                 g[gno].p[setno].lines = 0;
1336                 g[gno].p[setno].errbar.barsize = 0.0;
1337             }
1338             if (version < 50003) {
1339                 g[gno].p[setno].errbar.active = TRUE;
1340                 g[gno].p[setno].errbar.pen.color = g[gno].p[setno].sympen.color;
1341                 g[gno].p[setno].errbar.pen.pattern = 1;
1342                 switch (g[gno].p[setno].errbar.ptype) {
1343                 case PLACEMENT_NORMAL:
1344                     g[gno].p[setno].errbar.ptype = PLACEMENT_OPPOSITE;
1345                     break;
1346                 case PLACEMENT_OPPOSITE:
1347                     g[gno].p[setno].errbar.ptype = PLACEMENT_NORMAL;
1348                     break;
1349                 case PLACEMENT_BOTH:
1350                     switch (g[gno].p[setno].type) {
1351                     case SET_XYDXDX:
1352                     case SET_XYDYDY:
1353                     case SET_BARDYDY:
1354                         g[gno].p[setno].errbar.ptype = PLACEMENT_NORMAL;
1355                         break;
1356                     }
1357                     break;
1358                 }
1359             }
1360             if (version < 50002) {
1361                 g[gno].p[setno].errbar.barsize *= 2;
1362             }
1363             if (version < 50105) {
1364                 /* Starting with 5.1.5, X axis min & inverting is honored
1365                    in pie charts */
1366                 if (get_graph_type(gno) == GRAPH_PIE) {
1367                     world w;
1368                     get_graph_world(gno, &w);
1369                     w.xg1 = 0.0;
1370                     w.xg2 = 2*M_PI;
1371                     set_graph_world(gno, w);
1372                     set_graph_xinvert(gno, FALSE);
1373                 }
1374             }
1375             if (version < 50107) {
1376                 /* Starting with 5.1.7, symskip is honored for all set types */
1377                 switch (g[gno].p[setno].type) {
1378                 case SET_BAR:
1379                 case SET_BARDY:
1380                 case SET_BARDYDY:
1381                 case SET_XYHILO:
1382                 case SET_XYR:
1383                 case SET_XYVMAP:
1384                 case SET_BOXPLOT:
1385                     g[gno].p[setno].symskip = 0;
1386                     break;
1387                 }
1388             }
1389         }
1390         for (naxis = 0; naxis < MAXAXES; naxis++) {
1391 	    tickmarks *t = get_graph_tickmarks(gno, naxis);
1392             if (!t) {
1393                 continue;
1394             }
1395 
1396             if (version <= 40102) {
1397                 if ( (is_xaxis(naxis) && g[gno].xscale == SCALE_LOG) ||
1398                      (!is_xaxis(naxis) && g[gno].yscale == SCALE_LOG) ) {
1399                     t->tmajor = pow(10.0, t->tmajor);
1400                 }
1401 
1402                 /* TODO : world/view translation */
1403                 t->offsx = 0.0;
1404                 t->offsy = 0.0;
1405             }
1406 	    if (version < 50000) {
1407 	        /* There was no label_op in Xmgr */
1408                 t->label_op = t->tl_op;
1409 
1410                 /* in xmgr, axis label placement was in x,y coordinates */
1411 	        /* in Grace, it's parallel/perpendicular */
1412 	        if(!is_xaxis(naxis)) {
1413 	            fswap(&t->label.x, &t->label.y);
1414 	        }
1415 	        t->label.y *= -1;
1416 	    }
1417 	    if (version >= 50000 && version < 50103) {
1418 	        /* Autoplacement of axis labels wasn't implemented
1419                    in early versions of Grace */
1420                 if (t->label_place == TYPE_AUTO) {
1421                     t->label.x = 0.0;
1422                     t->label.y = 0.08;
1423                     t->label_place = TYPE_SPEC;
1424                 }
1425             }
1426         }
1427     }
1428 
1429     if (version >= 40200 && version <= 50005) {
1430         /* BBox type justification was erroneously set */
1431         for (strno = 0; strno < number_of_strings(); strno++) {
1432             pstr[strno].just |= JUST_MIDDLE;
1433         }
1434     }
1435 }
1436