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(>mp, &g[from], sizeof(graph));
246 memcpy(&g[from], &g[to], sizeof(graph));
247 memcpy(&g[to], >mp, 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