1 /*
2 * $Id: graph.c,v 1.12 2010-04-13 11:34:30 thiebaut Exp $
3 * Define interactive graphics interface using Gist graphics package.
4 */
5 /* Copyright (c) 2005, The Regents of the University of California.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 #include "gist.h"
12 #include "xbasic.h"
13 #include "hlevel.h"
14
15 /* primitive allowance for other non-X windows systems */
16 #ifndef DISPLAY_ENGINE
17 # define DISPLAY_ENGINE GpFXEngine
18 #endif
19 #ifdef NO_XLIB
20 # define NO_MOUSE
21 static int my_rgb_read(Engine *eng, GpColor *rgb, long *nx, long *ny);
22 # define RGB_READER my_rgb_read
23 #else
24 # ifndef NO_MOUSE
25 # ifndef DISPLAY_MOUSE
26 # define DISPLAY_MOUSE GxPointClick
27 # endif
28 # endif
29 # define RGB_READER g_rgb_read
30 extern unsigned long gx_parent;
31 #endif
32 #ifdef NO_MOUSE
33 # ifndef DISPLAY_ZOOM_FACTOR
34 # define DISPLAY_ZOOM_FACTOR myZoomFactor
35 static double myZoomFactor= 1.0;
36 # endif
37 #endif
38 #ifndef DISPLAY_ZOOM_FACTOR
39 # define DISPLAY_ZOOM_FACTOR gxZoomFactor
40 #endif
41
42 /* various X headers included by xfancy.h define True and False */
43 #undef True
44 #undef False
45
46 #include "ydata.h"
47 #include "yio.h"
48 #include "pstdlib.h"
49 #include "play.h"
50 #include <string.h>
51
52 /* Quining operation defined in parse.c */
53 extern void YpQuine(char *name, int nQuined);
54 extern int PutsAsArray(char *s); /* from yio.c */
55 /* in graph0.c */
56 extern long QuickMeshZone(double xx, double yy, double *x, double *y,
57 int *reg, long ix, long ijx, long i,
58 long *bndy, long nbndy);
59 extern long *BuildMeshBndy(double *x, double *y, int *reg,
60 long ix, long ijx, long *nbndy);
61
62 extern BuiltIn Y_plg, Y_plm, Y_plc, Y_plv, Y_plf, Y_pli, Y_plt, Y_pldj;
63 extern BuiltIn Y_plmesh, Y_bytscl, Y_plfp;
64
65 extern BuiltIn Y_limits, Y_logxy, Y_zoom_factor, Y_unzoom;
66 /* Note: range function is interpreted shell for limits */
67
68 extern BuiltIn Y_window, Y_hcp_file, Y_hcp_finish, Y_plsys, Y_palette;
69 extern BuiltIn Y_window_geometry, Y_window_exists, Y_window_select,
70 Y_window_list;
71
72 extern BuiltIn Y_fma, Y_redraw, Y_hcp, Y_hcpon, Y_hcpoff, Y_animate;
73
74 extern BuiltIn Y_plq, Y_pledit, Y_pldefault, Y_gridxy;
75
76 extern BuiltIn Y__pl_init; /* called at initialization by graph.i */
77
78 extern BuiltIn Y_mouse, Y_contour, Y_mesh_loc, Y_pause, Y_current_window;
79 extern BuiltIn Y_keybd_focus, Y_rgb_read;
80 extern BuiltIn Y_current_mouse, Y_set_gpath;
81
82 /*--------------------------------------------------------------------------*/
83
84 static void FreeReference(void *obj);
85 static void Safe_free(void *vptr);
86
87 static char *SetHCPname(int n, char *name);
88 static char *GetHCPname(int n);
89 static char *hcpNames[GH_NDEVS+1];
90 static void SetHCPDefault(void);
91 static void CheckDefaultWindow(void);
92 static void CheckDefaultPalette(void);
93
94 static double *Get1Ddouble(Symbol *stack, long *length);
95 static double *Get2Ddouble(Symbol *stack, long *len1, long *len2);
96 static int *Get2Dint(Symbol *stack, long *len1, long *len2);
97 static short *Get2Dshort(Symbol *stack, long *len1, long *len2);
98 static double *GetDouble(Symbol *stack, long *n);
99 static void LegendAndHide(char *func, char *arg1, char *arg2, char *arg3,
100 char *arg4, Symbol *keySymbols[]);
101 static int GetLineType(Symbol *stack);
102 static int YgetColor(Symbol *stack);
103 static int GetFont(Symbol *stack);
104 static int GetTypeface(char *s);
105 static void GetJustify(Symbol *stack);
106 static long Safe_strlen(const char *s);
107 static void AllocTmpLegend(long len);
108 static void FreeTmpLegend(void);
109 static long escape_count(char *arg);
110 static void escape_cat(char *leg, char *arg);
111 static Symbol *GrabMesh(Symbol *stack, Symbol *triKey, GaQuadMesh *mesh,
112 char **y_name, char **x_name, char **r_name, int tmp);
113 static int *PadRegionArray(Symbol *stack, int *reg, long iMax, long jMax);
114 static void *CopyArray(Symbol *stack, void *xOld,
115 StructDef *base, long iMax, long jMax);
116 static double *CopyLevels(double *levels, long nLevels);
117 static void GetZCrange(double *zmn, double *zmx, double *z, int *reg,
118 int region, long iMax, long jMax, int zCompressed);
119 static void GetPCrange(double *zmn, double *zmx, double *z, int *reg,
120 int region, long iMax, long jMax);
121 static void GrabByteScale(Symbol **keySymbols, double *scale, double *offset,
122 double *zn, double *zx, double *z, int *reg,
123 int region, long iMax, long jMax, int zCompressed);
124 static GpColor *PushColors(double *z, long len, double zmin, double zmax,
125 double scale, double offset);
126
127 static void PrintHideLegend(char *line, int type);
128 static void PrintColor(char *line, int color, int suffix);
129 static void PrintTypeWidth(char *line, int suffix);
130 static void PrintMarks(char *line, int suffix);
131 static void PrintSuffix(int suffix);
132 static void PrintRegion(char *line, int suffix);
133 static double Safe_dbl(double x);
134 static void *MakePropArray(StructDef *base, long size);
135
136 static void CheckPalette(void);
137
138 static int maxColors= 200; /* maximum number of colors for GpReadPalette */
139 static int hcpDump= 1; /* whiners can't figure out how to dump colors */
140 static int hcpPSdefault= 1;
141 static int hcpOnFMA= 0;
142 static int defaultDPI= 75;
143 static int defaultLegends= 1;
144 static char *defaultStyle= 0;
145 static char *defaultPalette= 0;
146
147 /* Pointers to the default mesh set with plmesh are actually
148 Yorick Array pointees. */
149 static long iMesh= 0, jMesh= 0;
150 static double *xMesh= 0, *yMesh= 0;
151 static int *regMesh= 0;
152 static short *triangleMesh= 0;
153
154 static int curElement= -1;
155
156 static void RefMesh(GaQuadMesh *mesh);
157
158 extern int YCurrentPlotter(void); /* for style.c */
159
160 /*--------------------------------------------------------------------------*/
161
162 static long yOrigin;
163
Get1Ddouble(Symbol * stack,long * length)164 static double *Get1Ddouble(Symbol *stack, long *length)
165 {
166 Operand op;
167 long n= *length;
168 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
169 stack->ops->FormOperand(stack, &op);
170 if (op.ops==&voidOps) return 0;
171 if (op.ops->promoteID>T_DOUBLE || (op.type.dims && op.type.dims->next))
172 YError("expecting 1D array convertable to type double as argument");
173 op.ops->ToDouble(&op);
174 if (n>0 && op.type.number!=n)
175 YError("1D double array must be same length as a previous argument");
176 if (op.type.dims) yOrigin= op.type.dims->origin;
177 else yOrigin= 1L;
178 *length= op.type.number;
179 return (double *)op.value;
180 }
181
Get2Ddouble(Symbol * stack,long * len1,long * len2)182 static double *Get2Ddouble(Symbol *stack, long *len1, long *len2)
183 {
184 Operand op;
185 long n1= *len1;
186 long n2= *len2;
187 Dimension *next= 0;
188 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
189 stack->ops->FormOperand(stack, &op);
190 if (op.ops==&voidOps) return 0;
191 if (op.ops->promoteID>T_DOUBLE ||
192 !op.type.dims || !(next= op.type.dims->next) || next->next)
193 YError("expecting 2D array convertable to type double as argument");
194 op.ops->ToDouble(&op);
195 if (n1>0 && (op.type.dims->number!=n1 || next->number!=n2))
196 YError("2D double array must be same shape as a previous argument");
197 *len1= op.type.dims->number;
198 *len2= op.type.dims->next->number;
199 return (double *)op.value;
200 }
201
Get2Dint(Symbol * stack,long * len1,long * len2)202 static int *Get2Dint(Symbol *stack, long *len1, long *len2)
203 {
204 Operand op;
205 long n1= *len1;
206 long n2= *len2;
207 Dimension *next= 0;
208 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
209 stack->ops->FormOperand(stack, &op);
210 if (op.ops==&voidOps) return 0;
211 if (op.ops->promoteID>T_LONG ||
212 !op.type.dims || !(next= op.type.dims->next) || next->next)
213 YError("expecting 2D array convertable to type int as argument");
214 op.ops->ToInt(&op);
215 if (n1>0 && (op.type.dims->number!=n1 || next->number!=n2))
216 YError("2D int array must be same shape as a previous argument");
217 *len1= op.type.dims->number;
218 *len2= op.type.dims->next->number;
219 return (int *)op.value;
220 }
221
Get2Dshort(Symbol * stack,long * len1,long * len2)222 static short *Get2Dshort(Symbol *stack, long *len1, long *len2)
223 {
224 Operand op;
225 long n1= *len1;
226 long n2= *len2;
227 Dimension *next= 0;
228 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
229 stack->ops->FormOperand(stack, &op);
230 if (op.ops==&voidOps) return 0;
231 if (op.ops->promoteID>T_LONG ||
232 !op.type.dims || !(next= op.type.dims->next) || next->next)
233 YError("expecting 2D array convertable to type short as argument");
234 op.ops->ToShort(&op);
235 if (n1>0 && (op.type.dims->number!=n1 || next->number!=n2))
236 YError("2D short array must be same shape as a previous argument");
237 *len1= op.type.dims->number;
238 *len2= op.type.dims->next->number;
239 return (short *)op.value;
240 }
241
Safe_strlen(const char * s)242 static long Safe_strlen(const char *s)
243 {
244 if (s) return strlen(s);
245 else return 0;
246 }
247
248 static char *tmpLegend = 0;
249
250 static void
AllocTmpLegend(long len)251 AllocTmpLegend(long len)
252 {
253 if (tmpLegend) FreeTmpLegend();
254 tmpLegend = p_malloc(len+1);
255 tmpLegend[0] = '\0';
256 }
257
FreeTmpLegend(void)258 static void FreeTmpLegend(void)
259 {
260 if (tmpLegend) {
261 char *legend= tmpLegend;
262 tmpLegend= 0;
263 p_free(legend);
264 }
265 }
266
escape_count(char * arg)267 static long escape_count(char *arg)
268 {
269 long n= 0;
270 if (arg) while (*arg) {
271 if (*arg=='!' || *arg=='_' || *arg=='^') n++;
272 arg++;
273 }
274 return n;
275 }
276
escape_cat(char * leg,char * arg)277 static void escape_cat(char *leg, char *arg)
278 {
279 while (*arg) {
280 if (*arg=='!' || *arg=='_' || *arg=='^') *(leg++)= '!';
281 *(leg++)= *(arg++);
282 }
283 *leg= '\0';
284 }
285
LegendAndHide(char * func,char * arg1,char * arg2,char * arg3,char * arg4,Symbol * keySymbols[])286 static void LegendAndHide(char *func, char *arg1, char *arg2, char *arg3,
287 char *arg4, Symbol *keySymbols[])
288 {
289 /* check for hide= keyword */
290 if (YNotNil(keySymbols[1])) gistD.hidden= (YGetInteger(keySymbols[1])!=0);
291 else gistD.hidden= 0;
292
293 if (tmpLegend) FreeTmpLegend();
294
295 /* check for legend= keyword -- put legend into tmpLegend */
296 if (keySymbols[0]) {
297 /* legend=[] is same as legend=string() */
298 Symbol *stack= keySymbols[0];
299 if (YNotNil(stack)) tmpLegend= p_strcpy(YGetString(stack));
300
301 } else if (func) {
302 /* construct default legend from up to 4 quined arguments */
303 long len0= Safe_strlen(func);
304 long len1= Safe_strlen(arg1)+escape_count(arg1);
305 long len2= Safe_strlen(arg2)+escape_count(arg2);
306 long len3= Safe_strlen(arg3)+escape_count(arg3);
307 long len4= Safe_strlen(arg4)+escape_count(arg4);
308 AllocTmpLegend(len0+len1+len2+len3+len4+6);
309 if (func) strcat(tmpLegend, func);
310 if (arg1) {
311 escape_cat(tmpLegend+len0, arg1);
312 len0+= len1;
313 if (arg2) {
314 strcat(tmpLegend+len0, ", ");
315 escape_cat(tmpLegend+len0+2, arg2);
316 len0+= 2+len2;
317 if (arg3) {
318 strcat(tmpLegend+len0, ", ");
319 escape_cat(tmpLegend+len0+2, arg3);
320 len0+= 2+len3;
321 if (arg4) {
322 strcat(tmpLegend+len0, ", ");
323 escape_cat(tmpLegend+len0+2, arg4);
324 len0+= 2+len4;
325 }
326 }
327 }
328 }
329 }
330
331 /* Put tmpLegend into gistD.legend -- it will be copied out when the
332 element is created. Only danger is pledit, since GdEdit just
333 copies the pointer, not the string -- handle this case specially. */
334 gistD.legend= tmpLegend;
335 }
336
GetLineType(Symbol * stack)337 static int GetLineType(Symbol *stack)
338 {
339 Operand op;
340 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
341 stack->ops->FormOperand(stack, &op);
342 if (op.ops==&stringOps) {
343 char *s= ((char **)op.value)[0];
344 if (op.type.dims) YError("illegal line type -- need scalar string");
345 if (strcmp(s, "none")==0) return L_NONE;
346 else if (strcmp(s, "solid")==0) return L_SOLID;
347 else if (strcmp(s, "dash")==0) return L_DASH;
348 else if (strcmp(s, "dot")==0) return L_DOT;
349 else if (strcmp(s, "dashdot")==0) return L_DASHDOT;
350 else if (strcmp(s, "dashdotdot")==0) return L_DASHDOTDOT;
351 YError("unrecognized line type keyword");
352 return 0;
353 } else {
354 int type= (int)YGetInteger(stack);
355 if (type<0) type= 0;
356 else if (type>5) type= 1 + (type-1)%5;
357 return type;
358 }
359 }
360
361 static int
YgetColor(Symbol * stack)362 YgetColor(Symbol *stack)
363 {
364 Operand op;
365 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
366 stack->ops->FormOperand(stack, &op);
367 if (op.ops==&stringOps) {
368 char *s= ((char **)op.value)[0];
369 if (op.type.dims) YError("illegal color -- need scalar string");
370 if (strcmp(s, "bg")==0) return P_BG;
371 else if (strcmp(s, "fg")==0) return P_FG;
372 else if (strcmp(s, "black")==0) return P_BLACK;
373 else if (strcmp(s, "white")==0) return P_WHITE;
374 else if (strcmp(s, "red")==0) return P_RED;
375 else if (strcmp(s, "green")==0) return P_GREEN;
376 else if (strcmp(s, "blue")==0) return P_BLUE;
377 else if (strcmp(s, "cyan")==0) return P_CYAN;
378 else if (strcmp(s, "magenta")==0) return P_MAGENTA;
379 else if (strcmp(s, "yellow")==0) return P_YELLOW;
380 else if (strcmp(s, "grayd")==0) return P_GRAYD;
381 else if (strcmp(s, "grayc")==0) return P_GRAYC;
382 else if (strcmp(s, "grayb")==0) return P_GRAYB;
383 else if (strcmp(s, "graya")==0) return P_GRAYA;
384 YError("unrecognized color keyword (fg, bg, or 8 primaries only)");
385 return 0;
386 } else {
387 Dimension *dims;
388 int *color = YGet_I(stack, 0, &dims);
389 if (dims && (dims->next || dims->number!=3))
390 YError("color must be integer scalar or triple (rgb)");
391 if (dims) return P_RGB(color[0],color[1],color[2]);
392 if (color[0] < 256) return (color[0]&0xff); /* indexed color */
393 return ((color[0]&0xffffff) | 0x01000000); /* reform packed RGB color */
394 }
395 }
396
GetFont(Symbol * stack)397 static int GetFont(Symbol *stack)
398 {
399 Operand op;
400 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
401 stack->ops->FormOperand(stack, &op);
402 if (op.ops==&stringOps) {
403 char *s= ((char **)op.value)[0];
404 if (op.type.dims) YError("illegal font -- need scalar string");
405 if (strncmp(s, "courier", 7)==0)
406 return T_COURIER | GetTypeface(&s[7]);
407 else if (strncmp(s, "times", 5)==0)
408 return T_TIMES | GetTypeface(&s[5]);
409 else if (strncmp(s, "helvetica", 9)==0)
410 return T_HELVETICA | GetTypeface(&s[9]);
411 else if (strncmp(s, "symbol", 6)==0)
412 return T_SYMBOL | GetTypeface(&s[6]);
413 else if (strncmp(s, "schoolbook", 10)==0)
414 return T_NEWCENTURY | GetTypeface(&s[10]);
415 YError("unrecognized font keyword");
416 return 0;
417 } else {
418 return (int)YGetInteger(stack);
419 }
420 }
421
GetTypeface(char * s)422 static int GetTypeface(char *s)
423 {
424 int face= 0;
425 while (*s) {
426 if (*s=='B' && !(face&T_BOLD)) face|= T_BOLD;
427 else if (*s=='I' && !(face&T_ITALIC)) face|= T_ITALIC;
428 else YError("illegal font keyword suffix -- B is bold, I is italic");
429 s++;
430 }
431 return face;
432 }
433
GetJustify(Symbol * stack)434 static void GetJustify(Symbol *stack)
435 {
436 Operand op;
437 if (!stack->ops) YError("unexpected keyword argument (BUG?)");
438 stack->ops->FormOperand(stack, &op);
439 if (op.ops==&stringOps) {
440 char *s= ((char **)op.value)[0];
441 if (op.type.dims) YError("illegal justify -- need scalar string");
442 if (*s=='N') { gistA.t.alignH= TH_NORMAL; s++; }
443 else if (*s=='L') { gistA.t.alignH= TH_LEFT; s++; }
444 else if (*s=='C') { gistA.t.alignH= TH_CENTER; s++; }
445 else if (*s=='R') { gistA.t.alignH= TH_RIGHT; s++; }
446 else { while (*s) s++; }
447 if (*s=='N') gistA.t.alignV= TV_NORMAL;
448 else if (*s=='T') gistA.t.alignV= TV_TOP;
449 else if (*s=='C') gistA.t.alignV= TV_CAP;
450 else if (*s=='H') gistA.t.alignV= TV_HALF;
451 else if (*s=='A') gistA.t.alignV= TV_BASE;
452 else if (*s=='B') gistA.t.alignV= TV_BOTTOM;
453 else YError("unrecognized justify keyword");
454 } else {
455 int justify= (int)YGetInteger(stack);
456 gistA.t.alignH= justify&3;
457 gistA.t.alignV= justify>>2;
458 }
459 }
460
461 /*--------------------------------------------------------------------------*/
462
463 #undef N_KEYWORDS
464 #define N_KEYWORDS 19
465 static char *plgKeys[N_KEYWORDS+1]= {
466 "legend", "hide", "color", "type", "width",
467 "marks", "mcolor", "marker", "msize", "mspace", "mphase",
468 "rays", "arrowl", "arroww", "rspace", "rphase",
469 "closed", "smooth", "n", 0 };
470
Y_plg(int nArgs)471 void Y_plg(int nArgs)
472 {
473 Symbol *keySymbols[N_KEYWORDS];
474 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, plgKeys, keySymbols);
475 int iPass= 0;
476 double *x= 0, *y= 0;
477 char *x_name= 0, *y_name= 0;
478 long n= 0;
479 long nparts= 0, *np= 0;
480 int defaultX= 0;
481
482 if (!CalledAsSubroutine())
483 YError("plg may not be invoked as a function -- subroutine only");
484
485 while (stack<=sp) {
486 if (!stack->ops) { stack+= 2; continue; }
487
488 if (iPass==0) y= Get1Ddouble(stack, &n);
489 else if (iPass==1) y_name= YGetString(stack);
490 else if (iPass==2) x= Get1Ddouble(stack, &n);
491 else if (iPass==3) x_name= YGetString(stack);
492 else YError("plg takes at most two non-keyword arguments");
493
494 iPass++;
495 stack++;
496 }
497
498 if (!y) YError("plg needs at least one non-keyword argument");
499
500 /* set legend and hide in gistD */
501 CheckDefaultWindow();
502 LegendAndHide("\001: plg, ", y_name, x_name, (char *)0, (char *)0,
503 keySymbols);
504
505 /* set properties, starting from defaults for decorated polylines */
506 GhGetLines();
507
508 if (YNotNil(keySymbols[2]))
509 gistA.l.color= gistA.m.color= YgetColor(keySymbols[2]);
510 if (YNotNil(keySymbols[3]))
511 gistA.l.type= GetLineType(keySymbols[3]);
512 if (YNotNil(keySymbols[4]))
513 gistA.l.width= YGetReal(keySymbols[4]);
514 if (YNotNil(keySymbols[5]))
515 gistA.dl.marks= (YGetInteger(keySymbols[5])!=0);
516 if (YNotNil(keySymbols[6]))
517 gistA.m.color= YgetColor(keySymbols[6]);
518 if (YNotNil(keySymbols[7]))
519 gistA.m.type= (int)YGetInteger(keySymbols[7]);
520 if (YNotNil(keySymbols[8]))
521 gistA.m.size= YGetReal(keySymbols[8]);
522 if (YNotNil(keySymbols[9]))
523 gistA.dl.mSpace= YGetReal(keySymbols[9]);
524 if (YNotNil(keySymbols[10]))
525 gistA.dl.mPhase= YGetReal(keySymbols[10]);
526 if (YNotNil(keySymbols[11]))
527 gistA.dl.rays= (YGetInteger(keySymbols[11])!=0);
528 if (YNotNil(keySymbols[12]))
529 gistA.dl.arrowL= YGetReal(keySymbols[12]);
530 if (YNotNil(keySymbols[13]))
531 gistA.dl.arrowW= YGetReal(keySymbols[13]);
532 if (YNotNil(keySymbols[14]))
533 gistA.dl.rSpace= YGetReal(keySymbols[14]);
534 if (YNotNil(keySymbols[15]))
535 gistA.dl.rPhase= YGetReal(keySymbols[15]);
536 if (YNotNil(keySymbols[16]))
537 gistA.dl.closed= (YGetInteger(keySymbols[16])!=0);
538 if (YNotNil(keySymbols[17]))
539 gistA.dl.smooth= (YGetInteger(keySymbols[17])!=0);
540
541 if (YNotNil(keySymbols[18])) {
542 long i, ntot;
543 Dimension *dims;
544 np= YGet_L(keySymbols[18], 0, &dims);
545 if (!dims || dims->next) YError("n= keyword must be 1D in plg");
546 nparts= dims->number;
547 for (i=ntot=0 ; i<nparts ; i++) ntot+= np[i];
548 if (ntot!=n) YError("n= keyword must sum to numberof(y) in plg");
549 }
550
551 if (!x) {
552 /* default x runs from origin of y dimension in steps of 1 */
553 long i;
554 Array *array=
555 PushDataBlock(NewArray(&doubleStruct,
556 NewDimension(n, 1L, (Dimension *)0)));
557 array->type.dims->references--;
558 x= array->value.d;
559 defaultX= 1;
560 if (!nparts) {
561 for (i=0 ; i<n ; i++) x[i]= yOrigin+(double)i;
562 } else {
563 long j;
564 for (j=0 ; j<nparts ; j++)
565 for (i=0 ; i<np[j] ; i++) x[i]= yOrigin+(double)i;
566 }
567 }
568
569 /* add the graph(s) to the current display list */
570 if (!nparts) {
571 curElement= -1;
572 curElement= GdLines(n, x, y);
573 } else {
574 int ce= 0, cel= 0;
575 curElement= -1;
576 while (nparts--) {
577 cel= GdLines(np[0], x, y);
578 if (cel<0) ce= cel;
579 x+= np[0];
580 y+= np[0];
581 np++;
582 }
583 if (!ce) curElement= cel;
584 }
585 if (curElement<0) YWarning("Gist GdLines plotter failed");
586
587 Drop(nArgs+defaultX);
588 }
589
590 #undef N_KEYWORDS
591 #define N_KEYWORDS 8
592 static char *plmKeys[N_KEYWORDS+1]= {
593 "legend", "hide", "color", "type", "width", "region", "boundary",
594 "inhibit", 0 };
595
Y_plm(int nArgs)596 void Y_plm(int nArgs)
597 {
598 Symbol *keySymbols[N_KEYWORDS];
599 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, plmKeys, keySymbols);
600 char *y_name= 0, *x_name= 0, *r_name= 0;
601 GaQuadMesh mesh;
602
603 if (!CalledAsSubroutine())
604 YError("plm may not be invoked as a function -- subroutine only");
605
606 stack= GrabMesh(stack, (Symbol *)0, &mesh, &y_name, &x_name, &r_name, 0);
607 while (stack<=sp) {
608 if (!stack->ops) stack+= 2;
609 else YError("plm takes at most three non-keyword arguments");
610 }
611
612 /* set legend and hide in gistD */
613 CheckDefaultWindow();
614 LegendAndHide("plm, ", y_name, x_name, r_name, (char *)0, keySymbols);
615
616 /* set properties, starting from defaults for meshes */
617 GhGetMesh();
618 gistD.region= 0;
619 gistD.boundary= 0;
620 gistD.inhibit= 0;
621
622 if (YNotNil(keySymbols[2]))
623 gistA.l.color= YgetColor(keySymbols[2]);
624 if (YNotNil(keySymbols[3]))
625 gistA.l.type= GetLineType(keySymbols[3]);
626 if (YNotNil(keySymbols[4]))
627 gistA.l.width= YGetReal(keySymbols[4]);
628 if (YNotNil(keySymbols[5]))
629 gistD.region= (int)YGetInteger(keySymbols[5]);
630 if (YNotNil(keySymbols[6]))
631 gistD.boundary= (YGetInteger(keySymbols[6])!=0);
632 if (YNotNil(keySymbols[7]))
633 gistD.inhibit= (int)YGetInteger(keySymbols[7]);
634
635 curElement= -1;
636 curElement= GdMesh(NOCOPY_MESH, &mesh, gistD.region, gistD.boundary,
637 gistD.inhibit);
638 if (curElement<0) YWarning("Gist GdMesh plotter failed");
639
640 RefMesh(&mesh);
641 Drop(nArgs);
642 }
643
644 #undef N_KEYWORDS
645 #define N_KEYWORDS 1
646 static char *meshKeys[N_KEYWORDS+1]= { "triangle", 0 };
647
Y_plmesh(int nArgs)648 void Y_plmesh(int nArgs)
649 {
650 Symbol *keySymbols[N_KEYWORDS];
651 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, meshKeys, keySymbols);
652 GaQuadMesh mesh;
653
654 if (nArgs==0) {
655 Safe_free(&xMesh);
656 Safe_free(&yMesh);
657 Safe_free(®Mesh);
658 Safe_free(&triangleMesh);
659 }
660
661 stack= GrabMesh(stack, keySymbols[0], &mesh,
662 (char **)0, (char **)0, (char **)0, 0);
663
664 if (mesh.x!=xMesh) {
665 /* a new default mesh has been defined */
666 Safe_free(&xMesh);
667 Safe_free(&yMesh);
668 Safe_free(®Mesh);
669 Safe_free(&triangleMesh);
670 RefMesh(&mesh);
671 iMesh= mesh.iMax;
672 jMesh= mesh.jMax;
673 xMesh= mesh.x;
674 yMesh= mesh.y;
675 if (mesh.reg) {
676 regMesh= mesh.reg;
677 } else {
678 /* supply a default region array now */
679 long ijMax= iMesh*jMesh;
680 long i= ijMax+iMesh+1;
681 Array *array=
682 PushDataBlock(NewArray(&intStruct,
683 NewDimension(i, 1L, (Dimension *)0)));
684 int *r= array->value.i;
685 array->type.dims->references--;
686
687 for (i=0 ; i<=iMesh ; i++) r[i]= 0;
688 for (i=iMesh+1 ; i<ijMax ; i++) r[i]= 1;
689 for (i=0 ; i<=iMesh ; i++) r[ijMax+i]= 0;
690 for (i=2*iMesh ; i<ijMax ; i+=iMesh) r[i]= 0;
691
692 array->references++; /* preserve across Drop */
693 regMesh= array->value.i;
694 Drop(1);
695 }
696 triangleMesh= mesh.triangle;
697
698 } else {
699 /* perhaps reg or triangle has been updated */
700 if (mesh.x==xMesh) {
701 mesh.x= mesh.y= 0;
702 if (mesh.reg==regMesh) mesh.reg= 0;
703 if (mesh.triangle==triangleMesh) mesh.triangle= 0;
704 }
705 RefMesh(&mesh);
706 if (mesh.reg) {
707 Safe_free(®Mesh);
708 regMesh= mesh.reg;
709 }
710 if (mesh.triangle) {
711 Safe_free(&triangleMesh);
712 triangleMesh= mesh.triangle;
713 }
714 }
715
716 Drop(nArgs);
717 }
718
Safe_free(void * vptr)719 static void Safe_free(void *vptr)
720 {
721 void **ptr= vptr;
722 void *obj= *ptr;
723 *ptr= 0; /* zero reference before freeing object */
724 FreeReference(obj);
725 }
726
GrabMesh(Symbol * stack,Symbol * triKey,GaQuadMesh * mesh,char ** y_name,char ** x_name,char ** r_name,int tmp)727 static Symbol *GrabMesh(Symbol *stack, Symbol *triKey, GaQuadMesh *mesh,
728 char **y_name, char **x_name, char **r_name, int tmp)
729 {
730 Symbol *yStack= 0, *xStack= 0, *rStack= 0;
731 int stackInc= y_name? 1 : 2;
732 int iPass= 0;
733
734 mesh->x= mesh->y= 0;
735 mesh->reg= 0;
736 mesh->iMax= mesh->jMax= 0;
737 mesh->triangle= 0;
738
739 while (stack<=sp) {
740 if (!stack->ops) { stack+= 2; continue; }
741
742 if (iPass==0)
743 mesh->y= Get2Ddouble(yStack= stack, &mesh->jMax, &mesh->iMax);
744 else if (iPass==1) *y_name= YGetString(stack);
745 else if (iPass==2)
746 mesh->x= Get2Ddouble(xStack= stack, &mesh->jMax, &mesh->iMax);
747 else if (iPass==3) *x_name= YGetString(stack);
748 else if (iPass==4)
749 mesh->reg= Get2Dint(rStack= stack, &mesh->jMax, &mesh->iMax);
750 else if (iPass==5) *r_name= YGetString(stack);
751 else break;
752
753 iPass+= stackInc;
754 stack++;
755 }
756
757 if (YNotNil(triKey))
758 mesh->triangle= Get2Dshort(triKey, &mesh->jMax, &mesh->iMax);
759
760 if ((mesh->x!=0)^(mesh->y!=0))
761 YError("both y and x arrays must be specified for a mesh");
762
763 if (!mesh->x) {
764 /* neither y nor x have been specified -- use defaults */
765 if (!xMesh)
766 YError("no default mesh exists to define y and x -- use plmesh");
767 if ((mesh->reg || mesh->triangle) &&
768 (iMesh!=mesh->iMax || jMesh!=mesh->jMax))
769 YError("ireg and triangle must have same dimensions as default mesh");
770 mesh->iMax= iMesh;
771 mesh->jMax= jMesh;
772 mesh->x= xMesh;
773 mesh->y= yMesh;
774
775 } else {
776 /* both y and x have been specified -- copy them for Gist */
777 if (mesh->iMax<2 || mesh->jMax<2)
778 YError("a mesh have dimensions of at least 2-by-2");
779 mesh->x=
780 CopyArray(xStack, mesh->x, &doubleStruct, mesh->iMax, mesh->jMax);
781 mesh->y=
782 CopyArray(yStack, mesh->y, &doubleStruct, mesh->iMax, mesh->jMax);
783 }
784
785 /* the Gist region array requires guard zones beyond iMax*jMax */
786 if (mesh->reg) mesh->reg=
787 PadRegionArray(rStack, mesh->reg, mesh->iMax, mesh->jMax);
788 else if (mesh->x==xMesh)
789 mesh->reg= regMesh;
790
791 if (mesh->triangle) {
792 if (!tmp)
793 mesh->triangle= CopyArray(triKey, mesh->triangle, &shortStruct,
794 mesh->iMax, mesh->jMax);
795 } else if (mesh->x==xMesh && triKey) {
796 mesh->triangle= triangleMesh;
797 }
798
799 return stack;
800 }
801
RefMesh(GaQuadMesh * mesh)802 static void RefMesh(GaQuadMesh *mesh)
803 {
804 if (mesh->x) ((Array *)Pointee(mesh->x))->references++;
805 if (mesh->y) ((Array *)Pointee(mesh->y))->references++;
806 if (mesh->reg) ((Array *)Pointee(mesh->reg))->references++;
807 if (mesh->triangle) ((Array *)Pointee(mesh->triangle))->references++;
808 }
809
PadRegionArray(Symbol * stack,int * reg,long iMax,long jMax)810 static int *PadRegionArray(Symbol *stack, int *reg, long iMax, long jMax)
811 {
812 long ijMax= iMax*jMax;
813 long i= ijMax+iMax+1;
814 Array *array=
815 PushDataBlock(NewArray(&intStruct, NewDimension(i, 1L, (Dimension *)0)));
816 int *r= array->value.i;
817 array->type.dims->references--;
818
819 for (i=0 ; i<=iMax ; i++) r[i]= 0;
820 for (i=iMax+1 ; i<ijMax ; i++) r[i]= reg[i];
821 for (i=0 ; i<=iMax ; i++) r[ijMax+i]= 0;
822 for (i=2*iMax ; i<ijMax ; i+=iMax) r[i]= 0;
823
824 PopTo(stack);
825 return r;
826 }
827
CopyArray(Symbol * stack,void * xOld,StructDef * base,long iMax,long jMax)828 static void *CopyArray(Symbol *stack, void *xOld,
829 StructDef *base, long iMax, long jMax)
830 {
831 if (stack->ops==&dataBlockSym &&
832 (stack->value.db->references || !stack->value.db->ops->isArray)) {
833 long len= iMax*jMax;
834 Array *array=
835 PushDataBlock(NewArray(base, NewDimension(len, 1L, (Dimension *)0)));
836 void *x= array->value.c;
837 array->type.dims->references--;
838 base->Copy(base, x, xOld, len);
839 PopTo(stack);
840 return x;
841 } else {
842 /* no need to copy temporaries */
843 return xOld;
844 }
845 }
846
847 #undef N_KEYWORDS
848 #define N_KEYWORDS 15
849 static char *plcKeys[N_KEYWORDS+1]= {
850 "legend", "hide", "region", "color", "type", "width",
851 "marks", "mcolor", "marker", "msize", "mspace", "mphase",
852 "smooth", "triangle", "levs", 0 };
853
854 static double *tmpLevels= 0;
855
Y_plc(int nArgs)856 void Y_plc(int nArgs)
857 {
858 Symbol *keySymbols[N_KEYWORDS];
859 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, plcKeys, keySymbols);
860 char *z_name= 0, *y_name= 0, *x_name= 0, *r_name= 0;
861 long iMax= 0, jMax= 0, nLevels= 0;
862 double *z= 0, *levels= 0;
863 GaQuadMesh mesh;
864
865 if (!CalledAsSubroutine())
866 YError("plc may not be invoked as a function -- subroutine only");
867
868 if (stack<sp) {
869 z= Get2Ddouble(stack++, &jMax, &iMax);
870 z_name= YGetString(stack++);
871 }
872 if (!z) YError("plc needs at least one non-keyword argument");
873 stack= GrabMesh(stack, keySymbols[13], &mesh, &y_name, &x_name, &r_name, 0);
874 while (stack<=sp) {
875 if (!stack->ops) stack+= 2;
876 else YError("plc takes at most four non-keyword arguments");
877 }
878 if (mesh.iMax!=iMax || mesh.jMax!=jMax)
879 YError("z array must have same dimensions as mesh in plc");
880
881 /* set legend and hide in gistD */
882 CheckDefaultWindow();
883 LegendAndHide("\001: plc, ", z_name, y_name, x_name, r_name, keySymbols);
884
885 /* set properties, starting from defaults for decorated polylines */
886 GhGetLines();
887 gistD.region= 0;
888
889 if (YNotNil(keySymbols[2]))
890 gistD.region= (int)YGetInteger(keySymbols[2]);
891 if (YNotNil(keySymbols[3]))
892 gistA.l.color= gistA.m.color= YgetColor(keySymbols[3]);
893 if (YNotNil(keySymbols[4]))
894 gistA.l.type= GetLineType(keySymbols[4]);
895 if (YNotNil(keySymbols[5]))
896 gistA.l.width= YGetReal(keySymbols[5]);
897 if (YNotNil(keySymbols[6]))
898 gistA.dl.marks= (YGetInteger(keySymbols[6])!=0);
899 if (YNotNil(keySymbols[7]))
900 gistA.m.color= YgetColor(keySymbols[7]);
901 if (YNotNil(keySymbols[8]))
902 gistA.m.type= (int)YGetInteger(keySymbols[8]);
903 if (YNotNil(keySymbols[9]))
904 gistA.m.size= YGetReal(keySymbols[9]);
905 if (YNotNil(keySymbols[10]))
906 gistA.dl.mSpace= YGetReal(keySymbols[10]);
907 if (YNotNil(keySymbols[11]))
908 gistA.dl.mPhase= YGetReal(keySymbols[11]);
909 if (YNotNil(keySymbols[12]))
910 gistA.dl.smooth= (YGetInteger(keySymbols[12])!=0);
911
912 /* set contour levels */
913 if (YNotNil(keySymbols[14])) {
914 levels= Get1Ddouble(keySymbols[14], &nLevels);
915 if (levels)
916 levels= CopyLevels(levels, nLevels);
917 }
918
919 if (!levels) {
920 /* create a default set of contour levels now */
921 int i;
922 double zmin, zmax, step;
923
924 nLevels= 8;
925 levels= CopyLevels((double *)0, nLevels);
926 GetPCrange(&zmin, &zmax, z, mesh.reg, gistD.region, iMax, jMax);
927
928 step= (zmax-zmin)/8.0;
929 levels[0]= zmin+0.5*step;
930 for (i=1 ; i<nLevels ; i++) levels[i]= levels[i-1]+step;
931 }
932
933 curElement= -1;
934 curElement=
935 GdContours(NOCOPY_MESH, &mesh, gistD.region, z, levels, (int)nLevels);
936 if (curElement<0) YWarning("Gist GdContour plotter failed");
937 tmpLevels= 0; /* Gist now owns this pointer */
938
939 RefMesh(&mesh);
940 Drop(nArgs);
941 }
942
CopyLevels(double * levels,long nLevels)943 static double *CopyLevels(double *levels, long nLevels)
944 {
945 long i;
946 double *tmp= tmpLevels;
947 tmpLevels= 0;
948 if (tmp) p_free(tmp);
949 tmpLevels= p_malloc(sizeof(double)*nLevels);
950 for (i=0 ; i<nLevels ; i++) tmpLevels[i]= levels? levels[i] : 0.0;
951 return tmpLevels;
952 }
953
GetZCrange(double * zmn,double * zmx,double * z,int * reg,int region,long iMax,long jMax,int zCompressed)954 static void GetZCrange(double *zmn, double *zmx, double *z, int *reg,
955 int region, long iMax, long jMax, int zCompressed)
956 {
957 double zmin= 0.0, zmax= 0.0;
958 long i, j= iMax-1;
959 long len= (zCompressed? j : iMax)*(jMax-1);
960
961 if (zCompressed) {
962 long len= (iMax-1)*(jMax-1);
963 if (reg) reg+= iMax+1;
964 for (i=0 ; i<len ; i++) { /* first loop finds first z */
965 if (reg? (region? (*reg==region) : (*reg!=0)) : 1) {
966 zmin= zmax= z[i];
967 break;
968 }
969 if (reg) {
970 if (!(--j)) { reg+= 2; j= iMax-1; }
971 else reg++;
972 }
973 }
974 if (reg) {
975 if (!(--j)) { reg+= 2; j= iMax-1; }
976 else reg++;
977 }
978 for (i++ ; i<len ; i++) { /* second loop judges extreme values */
979 if (reg? (region? (*reg==region) : (*reg!=0)) : 1) {
980 if (zmin>z[i]) zmin= z[i];
981 else if (zmax<z[i]) zmax= z[i];
982 }
983 if (reg) {
984 if (!(--j)) { reg+= 2; j= iMax-1; }
985 else reg++;
986 }
987 }
988
989 } else {
990 z+= iMax+1; /* GrabMesh guarantees at least 2-by-2 */
991 if (reg) reg+= iMax+1;
992 for (i=1 ; i<len ; i++) { /* first loop finds first z */
993 if (--j) {
994 if (reg? (region? (*reg==region) : (*reg!=0)) : 1) {
995 zmin= zmax= z[i];
996 break;
997 }
998 } else {
999 j= iMax;
1000 }
1001 }
1002 for (i++ ; i<len ; i++) { /* second loop judges extreme values */
1003 if (--j) {
1004 if (reg? (region? (*reg==region) : (*reg!=0)) : 1) {
1005 if (zmin>z[i]) zmin= z[i];
1006 else if (zmax<z[i]) zmax= z[i];
1007 }
1008 } else {
1009 j= iMax;
1010 }
1011 }
1012 }
1013
1014 *zmn= zmin;
1015 *zmx= zmax;
1016 }
1017
GetPCrange(double * zmn,double * zmx,double * z,int * reg,int region,long iMax,long jMax)1018 static void GetPCrange(double *zmn, double *zmx, double *z, int *reg,
1019 int region, long iMax, long jMax)
1020 {
1021 double zmin= 0.0, zmax= 0.0;
1022 long i, len= iMax*jMax;
1023
1024 for (i=0 ; i<len ; i++) { /* first loop finds first z */
1025 if (reg? (region?
1026 (reg[i]==region || reg[i+1]==region ||
1027 reg[i+iMax]==region || reg[i+iMax+1]==region) :
1028 (reg[i] || reg[i+1] || reg[i+iMax] || reg[i+iMax+1])) : 1) {
1029 zmin= zmax= z[i];
1030 break;
1031 }
1032 }
1033
1034 for ( ; i<len ; i++) { /* second loop judges extreme values */
1035 if (reg? (region?
1036 (reg[i]==region || reg[i+1]==region ||
1037 reg[i+iMax]==region || reg[i+iMax+1]==region) :
1038 (reg[i] || reg[i+1] || reg[i+iMax] || reg[i+iMax+1])) : 1) {
1039 if (zmin>z[i]) zmin= z[i];
1040 else if (zmax<z[i]) zmax= z[i];
1041 }
1042 }
1043
1044 *zmn= zmin;
1045 *zmx= zmax;
1046 }
1047
1048 #undef N_KEYWORDS
1049 #define N_KEYWORDS 8
1050 static char *plvKeys[N_KEYWORDS+1]= {
1051 "legend", "hide", "region",
1052 "color", "hollow", "width", "aspect", "scale", 0 };
1053
Y_plv(int nArgs)1054 void Y_plv(int nArgs)
1055 {
1056 Symbol *keySymbols[N_KEYWORDS];
1057 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, plvKeys, keySymbols);
1058 char *v_name= 0, *u_name= 0, *y_name= 0, *x_name= 0, *r_name= 0;
1059 long iMax= 0, jMax= 0;
1060 double *u= 0, *v= 0, scale;
1061 GaQuadMesh mesh;
1062 int iPass= 0;
1063
1064 if (!CalledAsSubroutine())
1065 YError("plv may not be invoked as a function -- subroutine only");
1066
1067 while (stack<=sp) {
1068 if (!stack->ops) { stack+= 2; continue; }
1069 if (iPass==0) v= Get2Ddouble(stack, &jMax, &iMax);
1070 else if (iPass==1) v_name= YGetString(stack);
1071 else if (iPass==2) u= Get2Ddouble(stack, &jMax, &iMax);
1072 else if (iPass==3) u_name= YGetString(stack);
1073 else break;
1074 iPass++;
1075 stack++;
1076 }
1077 if (!u || !v) YError("plv needs at least two non-keyword arguments");
1078 stack= GrabMesh(stack, (Symbol *)0, &mesh, &y_name, &x_name, &r_name, 0);
1079 while (stack<=sp) {
1080 if (!stack->ops) stack+= 2;
1081 else YError("plv takes at most five non-keyword arguments");
1082 }
1083 if (mesh.iMax!=iMax || mesh.jMax!=jMax)
1084 YError("v and u arrays must have same dimensions as mesh in plv");
1085
1086 /* set legend and hide in gistD */
1087 CheckDefaultWindow();
1088 LegendAndHide("plv, ", v_name, u_name, y_name, x_name, keySymbols);
1089
1090 /* set properties, starting from defaults for vectors */
1091 GhGetVectors();
1092 gistD.region= 0;
1093
1094 if (YNotNil(keySymbols[2]))
1095 gistD.region= (int)YGetInteger(keySymbols[2]);
1096 if (YNotNil(keySymbols[3]))
1097 gistA.l.color= gistA.f.color= YgetColor(keySymbols[3]);
1098 if (YNotNil(keySymbols[4]))
1099 gistA.vect.hollow= (YGetInteger(keySymbols[4])!=0);
1100 if (YNotNil(keySymbols[5]))
1101 gistA.l.width= YGetReal(keySymbols[5]);
1102 if (YNotNil(keySymbols[6]))
1103 gistA.vect.aspect= YGetReal(keySymbols[6]);
1104
1105 /* set vector scale factor */
1106 if (YNotNil(keySymbols[7])) {
1107 scale= YGetReal(keySymbols[7]);
1108
1109 } else {
1110 /* set vector scale factor to make maximum vector length a
1111 "typical" zone dimension */
1112 double umin, umax, vmin, vmax, xmin, xmax, ymin, ymax;
1113
1114 GetPCrange(&xmin, &xmax, mesh.x, mesh.reg, gistD.region, iMax, jMax);
1115 GetPCrange(&ymin, &ymax, mesh.y, mesh.reg, gistD.region, iMax, jMax);
1116 GetPCrange(&umin, &umax, u, mesh.reg, gistD.region, iMax, jMax);
1117 GetPCrange(&vmin, &vmax, v, mesh.reg, gistD.region, iMax, jMax);
1118
1119 umax-= umin;
1120 vmax-= vmin;
1121 if (vmax>umax) umax= vmax;
1122 xmax= (xmax-xmin)+(ymax-ymin);
1123 xmax/= (iMax+jMax);
1124
1125 if (umax>0.0) scale= xmax/umax;
1126 else scale= 1.0;
1127 }
1128
1129 curElement= -1;
1130 curElement= GdVectors(NOCOPY_MESH, &mesh, gistD.region, u, v, scale);
1131 if (curElement<0) YWarning("Gist GdVectors plotter failed");
1132
1133 RefMesh(&mesh);
1134 Drop(nArgs);
1135 }
1136
1137 #undef N_KEYWORDS
1138 #define N_KEYWORDS 9
1139 static char *plfKeys[N_KEYWORDS+1]= {
1140 "legend", "hide", "region", "top", "cmin", "cmax",
1141 "edges", "ecolor", "ewidth", 0 };
1142
Y_plf(int nArgs)1143 void Y_plf(int nArgs)
1144 {
1145 Symbol *keySymbols[N_KEYWORDS];
1146 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, plfKeys, keySymbols);
1147 char *z_name= 0, *y_name= 0, *x_name= 0, *r_name= 0;
1148 long iMax= 0, jMax= 0;
1149 double *z= 0;
1150 GpColor *zc= 0;
1151 GaQuadMesh mesh;
1152 int convertedZ= 0;
1153 int rgb = 0;
1154
1155 if (!CalledAsSubroutine())
1156 YError("plf may not be invoked as a function -- subroutine only");
1157
1158 if (stack<sp) {
1159 Operand op;
1160 if (stack->ops==&referenceSym) ReplaceRef(stack);
1161 stack->ops->FormOperand(stack, &op);
1162 if (op.ops!=&charOps) {
1163 z= Get2Ddouble(stack, &jMax, &iMax);
1164 } else {
1165 Dimension *next= 0;
1166 if (!op.type.dims || !(next= op.type.dims->next) || next->next) {
1167 if (!next || !next->next || next->next->next ||
1168 next->next->number!=3)
1169 YError("expecting NXxNY or 3xNXxNY array as argument to plf");
1170 rgb = 1;
1171 }
1172 iMax= next->number;
1173 jMax= op.type.dims->number;
1174 zc= op.value;
1175 }
1176 stack++;
1177 z_name= YGetString(stack++);
1178 }
1179 stack= GrabMesh(stack, (Symbol *)0, &mesh, &y_name, &x_name, &r_name, 0);
1180 while (stack<=sp) {
1181 if (!stack->ops) stack+= 2;
1182 else YError("plf takes at most four non-keyword arguments");
1183 }
1184 if ((z || zc) && ((mesh.iMax!=iMax || mesh.jMax!=jMax) &&
1185 (mesh.iMax!=iMax+1 || mesh.jMax!=jMax+1)))
1186 YError("z array must have same or 1 smaller dimensions as mesh in plf");
1187
1188 /* set legend and hide in gistD */
1189 CheckDefaultWindow();
1190 CheckDefaultPalette();
1191 LegendAndHide("plf, ", z_name, y_name, x_name, r_name, keySymbols);
1192
1193 gistD.region= 0;
1194 if (YNotNil(keySymbols[2]))
1195 gistD.region= (int)YGetInteger(keySymbols[2]);
1196
1197 if (!zc && z) {
1198 /* need to generate colors array on stack now */
1199 double zmin, zmax, scale, offset;
1200
1201 GrabByteScale(&keySymbols[3], &scale, &offset, &zmin, &zmax,
1202 z, mesh.reg, gistD.region, mesh.iMax, mesh.jMax,
1203 mesh.iMax!=iMax);
1204 zc= PushColors(z, iMax*jMax, zmin, zmax, scale, offset);
1205 convertedZ= 1;
1206 }
1207
1208 GhGetFill();
1209 if (YNotNil(keySymbols[6]))
1210 gistA.e.type= YGetInteger(keySymbols[6])? L_SOLID : L_NONE;
1211 if (YNotNil(keySymbols[7]))
1212 gistA.e.color= YgetColor(keySymbols[7]);
1213 if (YNotNil(keySymbols[8]))
1214 gistA.e.width= YGetReal(keySymbols[8]);
1215 gistA.rgb = rgb;
1216
1217 if (mesh.iMax==iMax) zc += rgb? 3*(iMax+1) : iMax+1;
1218 curElement= -1;
1219 curElement= GdFillMesh(NOCOPY_MESH, &mesh, gistD.region, zc, iMax);
1220 if (curElement<0) YWarning("Gist GdFillMesh plotter failed");
1221
1222 RefMesh(&mesh);
1223 Drop(nArgs+convertedZ);
1224 }
1225
GrabByteScale(Symbol ** keySymbols,double * scale,double * offset,double * zn,double * zx,double * z,int * reg,int region,long iMax,long jMax,int zCompressed)1226 static void GrabByteScale(Symbol **keySymbols, double *scale, double *offset,
1227 double *zn, double *zx, double *z, int *reg,
1228 int region, long iMax, long jMax, int zCompressed)
1229 {
1230 int top;
1231 double zmin= 0.0, zmax= 0.0;
1232 int minGiven, maxGiven;
1233 GpColorCell *palette;
1234
1235 /* get any parameters specified as keywords */
1236 if (YNotNil(keySymbols[0]))
1237 top= (int)YGetInteger(keySymbols[0]);
1238 else
1239 top= GhGetPalette(-1,&palette)-1;
1240 if ((minGiven= YNotNil(keySymbols[1])))
1241 zmin= YGetReal(keySymbols[1]);
1242 if ((maxGiven= YNotNil(keySymbols[2])))
1243 zmax= YGetReal(keySymbols[2]);
1244
1245 /* fill in zmin and zmax from data if not specified */
1246 if (!minGiven || !maxGiven) {
1247 double zmn, zmx;
1248 GetZCrange(&zmn, &zmx, z, reg, region, iMax, jMax, zCompressed);
1249 if (!minGiven) zmin= zmn;
1250 if (!maxGiven) zmax= zmx;
1251 }
1252
1253 /* adjust zmin and zmax to avert numerical catastrophes */
1254 if (zmin>zmax) { double tmp= zmin; zmin= zmax; zmax= tmp; }
1255 else if (zmin==zmax) {
1256 if (zmin>0.0) { zmin= 0.9999*zmin; zmax= 1.0001*zmax; }
1257 if (zmin<0.0) { zmin= 1.0001*zmin; zmax= 0.9999*zmax; }
1258 else { zmin= -0.0001; zmax= 0.0001; }
1259 }
1260 *zn= zmin;
1261 *zx= zmax;
1262
1263 /* adjust top value if it is silly */
1264 if (top<0 || top>255) top= 255;
1265
1266 /* (byte value)= scale*(z cut off at zmin, zmax)+offset
1267 maps from z to interval [0, top] */
1268 *scale= (double)top/(zmax-zmin);
1269 *offset= zmin-(0.4999/(*scale)); /* zmin->0.5, zmax->top+0.5 */
1270 }
1271
PushColors(double * z,long len,double zmin,double zmax,double scale,double offset)1272 static GpColor *PushColors(double *z, long len, double zmin, double zmax,
1273 double scale, double offset)
1274 {
1275 long i;
1276 double zz;
1277 Array *array=
1278 PushDataBlock(NewArray(&charStruct,
1279 NewDimension(len, 1L, (Dimension *)0)));
1280 GpColor *zc= (GpColor *)array->value.c;
1281 array->type.dims->references--;
1282
1283 for (i=0 ; i<len ; i++) {
1284 zz= z[i];
1285 if (zz<zmin) zz= zmin;
1286 else if (zz>zmax) zz= zmax;
1287 zc[i]= (int)((zz-offset)*scale);
1288 }
1289
1290 return zc;
1291 }
1292
1293 #undef N_KEYWORDS
1294 #define N_KEYWORDS 5
1295 static char *pliKeys[N_KEYWORDS+1]= {
1296 "legend", "hide", "top", "cmin", "cmax", 0 };
1297
Y_pli(int nArgs)1298 void Y_pli(int nArgs)
1299 {
1300 Symbol *keySymbols[N_KEYWORDS];
1301 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, pliKeys, keySymbols);
1302 char *z_name= 0;
1303 double *z= 0, x0, y0, x1, y1;
1304 long iMax= 0, jMax= 0;
1305 GpColor *zc= 0;
1306 int convertedZ= 0;
1307 int iPass= 0;
1308 int rgb = 0;
1309
1310 if (!CalledAsSubroutine())
1311 YError("pli may not be invoked as a function -- subroutine only");
1312
1313 x0= y0= x1= y1= 0.0;
1314 while (stack<=sp) {
1315 if (!stack->ops) { stack+= 2; continue; }
1316 if (iPass==0) {
1317 Operand op;
1318 if (stack->ops==&referenceSym) ReplaceRef(stack);
1319 stack->ops->FormOperand(stack, &op);
1320 if (op.ops!=&charOps) {
1321 z= Get2Ddouble(stack, &jMax, &iMax);
1322 } else {
1323 Dimension *next= 0;
1324 if (!op.type.dims || !(next= op.type.dims->next) || next->next) {
1325 if (!next || !next->next || next->next->next ||
1326 next->next->number!=3)
1327 YError("expecting NXxNY or 3xNXxNY array as argument to pli");
1328 rgb = 1;
1329 }
1330 iMax= next->number;
1331 jMax= op.type.dims->number;
1332 zc= op.value;
1333 }
1334 } else if (iPass==1) z_name= YGetString(stack);
1335 else if (iPass==2) x0= YGetReal(stack);
1336 else if (iPass==3) y0= YGetReal(stack);
1337 else if (iPass==4) x1= YGetReal(stack);
1338 else if (iPass==5) y1= YGetReal(stack);
1339 else YError("pli takes at most five non-keyword arguments");
1340 iPass++;
1341 stack++;
1342 }
1343 if (!z && !zc) YError("pli needs at least one non-keyword argument");
1344
1345 /* handle defaulted corner values */
1346 if (iPass!=2 && iPass!=4 && iPass!=6)
1347 YError("pli needs either 0, 1, or 2 corner (x,y) points");
1348 if (iPass==2) {
1349 /* no corners specified */
1350 x0= y0= 0.0;
1351 x1= (double)iMax;
1352 y1= (double)jMax;
1353 } else if (iPass==4) {
1354 /* two corners specified */
1355 x1= x0;
1356 y1= y0;
1357 x0= y0= 0.0;
1358 }
1359
1360 /* set legend and hide in gistD */
1361 CheckDefaultWindow();
1362 CheckDefaultPalette();
1363 LegendAndHide("pli, ", z_name, (char *)0,(char *)0,(char *)0, keySymbols);
1364
1365 if (!zc) {
1366 /* need to generate colors array on stack now */
1367 double zmin, zmax, scale, offset;
1368
1369 GrabByteScale(&keySymbols[2], &scale, &offset, &zmin, &zmax,
1370 z, (int *)0, 0, iMax+1, jMax+1, 1);
1371 zc= PushColors(z, iMax*jMax, zmin, zmax, scale, offset);
1372 convertedZ= 1;
1373 }
1374
1375 gistA.rgb = rgb;
1376
1377 curElement= -1;
1378 curElement= GdCells(x0, y0, x1, y1, iMax, jMax, iMax, zc);
1379 if (curElement<0) YWarning("Gist GdCells plotter failed");
1380
1381 Drop(nArgs+convertedZ);
1382 }
1383
1384 #undef N_KEYWORDS
1385 #define N_KEYWORDS 8
1386 static char *plfpKeys[N_KEYWORDS+1]= {
1387 "legend", "hide", "top", "cmin", "cmax", "edges", "ecolor", "ewidth", 0 };
1388
Y_plfp(int nArgs)1389 void Y_plfp(int nArgs)
1390 {
1391 Symbol *keySymbols[N_KEYWORDS];
1392 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, plfpKeys, keySymbols);
1393 long n= 0, ny= 0, *pn= 0;
1394 double *z= 0, *x= 0, *y= 0;
1395 GpColor *zc= 0;
1396 int convertedZ= 0;
1397 int rgb = 0;
1398
1399 if (!CalledAsSubroutine())
1400 YError("plfp may not be invoked as a function -- subroutine only");
1401
1402 while (stack<=sp) {
1403 Operand op;
1404 if (!stack->ops) {
1405 stack+= 2;
1406 continue;
1407 }
1408 if (stack->ops==&referenceSym) ReplaceRef(stack);
1409 if (!convertedZ) {
1410 stack->ops->FormOperand(stack, &op);
1411 if (op.ops!=&charOps) {
1412 if (op.ops!=&voidOps)
1413 z= Get1Ddouble(stack, &n);
1414 } else {
1415 Dimension *next = op.type.dims? op.type.dims->next : 0;
1416 if (!op.type.dims || next) {
1417 if (next->next || next->number!=3)
1418 YError("expecting 1D or 3xN color array as argument to plfp");
1419 rgb = 1;
1420 }
1421 n= op.type.number;
1422 if (rgb) n /= 3;
1423 zc= op.value;
1424 }
1425 convertedZ= 1;
1426 } else if (!y) {
1427 y= Get1Ddouble(stack, &ny);
1428 if (!y) YError("expecting non-nil argument in plfp");
1429 } else if (!x) {
1430 long nx= 0;
1431 x= Get1Ddouble(stack, &nx);
1432 if (!x) YError("expecting non-nil argument in plfp");
1433 if (nx!=ny) YError("numberof(x)!=numberof(y) in plfp");
1434 } else if (!pn) {
1435 long i, np;
1436 stack->ops->FormOperand(stack, &op);
1437 if (op.ops==&voidOps) YError("expecting non-nil argument in plfp");
1438 if (op.ops->promoteID>T_LONG || (op.type.dims && op.type.dims->next))
1439 YError("expecting 1D array convertable to type long as argument");
1440 op.ops->ToLong(&op);
1441 if ((z||zc) && op.type.number!=n)
1442 YError("numberof(pn)!=numberof(z) in plfp");
1443 else
1444 n= op.type.number;
1445 pn= (long *)op.value;
1446 for (np=i=0 ; i<n ; i++) np+= pn[i];
1447 if (np!=ny) YError("numberof(y)!=sum(pn) in plfp");
1448 } else {
1449 YError("plfp takes at most four non-keyword arguments");
1450 }
1451 stack++;
1452 }
1453 if (!pn) YError("plfp needs four non-keyword arguments");
1454
1455 /* set legend and hide in gistD */
1456 CheckDefaultWindow();
1457 CheckDefaultPalette();
1458 /* would need to add plfp to quine list with YpQuine to get legend
1459 LegendAndHide("plfp, ", z_name, y_name, x_name, r_name, keySymbols); */
1460 LegendAndHide((char *)0, (char *)0, (char *)0,
1461 (char *)0, (char *)0, keySymbols);
1462
1463 if (!zc && z) {
1464 /* need to generate colors array on stack now */
1465 double zmin, zmax, scale, offset;
1466
1467 GrabByteScale(&keySymbols[2], &scale, &offset, &zmin, &zmax,
1468 z, (int *)0, 0, n+1, 2L, 1);
1469 zc= PushColors(z, n, zmin, zmax, scale, offset);
1470 convertedZ= 1;
1471 } else {
1472 convertedZ= 0;
1473 }
1474
1475 GhGetFill();
1476 if (YNotNil(keySymbols[5]))
1477 gistA.e.type= YGetInteger(keySymbols[5])? L_SOLID : L_NONE;
1478 if (YNotNil(keySymbols[6]))
1479 gistA.e.color= YgetColor(keySymbols[6]);
1480 if (YNotNil(keySymbols[7]))
1481 gistA.e.width= YGetReal(keySymbols[7]);
1482 gistA.rgb = rgb;
1483
1484 curElement= -1;
1485 curElement= GdFill(n, zc, x, y, pn);
1486 if (curElement<0) YWarning("Gist GdFill plotter failed");
1487
1488 Drop(nArgs+convertedZ);
1489 }
1490
1491 #undef N_KEYWORDS
1492 #define N_KEYWORDS 9
1493 static char *pltKeys[N_KEYWORDS+1]= {
1494 "legend", "hide",
1495 "color", "font", "height", "orient", "justify", "opaque", "tosys", 0 };
1496
Y_plt(int nArgs)1497 void Y_plt(int nArgs)
1498 {
1499 Symbol *keySymbols[N_KEYWORDS];
1500 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, pltKeys, keySymbols);
1501 char *text= 0;
1502 double x= 0.0, y= 0.0;
1503 int toSys;
1504 int iPass= 0;
1505
1506 while (stack<=sp) {
1507 if (!stack->ops) { stack+= 2; continue; }
1508 if (iPass==0) text= YGetString(stack);
1509 else if (iPass==1) x= YGetReal(stack);
1510 else if (iPass==2) y= YGetReal(stack);
1511 iPass++;
1512 stack++;
1513 }
1514 if (iPass!=3)
1515 YError("plt requires exactly three non-keyword arguments");
1516
1517 /* set legend and hide in gistD */
1518 CheckDefaultWindow();
1519 LegendAndHide((char *)0, (char *)0, (char *)0,
1520 (char *)0, (char *)0, keySymbols);
1521
1522 /* set properties, starting from defaults for vectors */
1523 GhGetText();
1524
1525 if (YNotNil(keySymbols[2]))
1526 gistA.t.color= YgetColor(keySymbols[2]);
1527 if (YNotNil(keySymbols[3]))
1528 gistA.t.font= GetFont(keySymbols[3]);
1529 if (YNotNil(keySymbols[4]))
1530 gistA.t.height= YGetReal(keySymbols[4])*ONE_POINT;
1531 if (YNotNil(keySymbols[5]))
1532 gistA.t.orient= YGetInteger(keySymbols[5]);
1533 if (YNotNil(keySymbols[6]))
1534 GetJustify(keySymbols[6]);
1535 if (YNotNil(keySymbols[7]))
1536 gistA.t.opaque= (YGetInteger(keySymbols[7])!=0);
1537
1538 if (!gistA.t.orient) {
1539 gistA.t.orient= TX_RIGHT;
1540 } else {
1541 if (gistA.t.orient==1) gistA.t.orient= TX_UP;
1542 else if (gistA.t.orient==2) gistA.t.orient= TX_LEFT;
1543 else if (gistA.t.orient==3) gistA.t.orient= TX_DOWN;
1544 else {
1545 gistA.t.orient= TX_RIGHT;
1546 YError("orient= keyword must be 0, 1, 2, or 3");
1547 }
1548 }
1549
1550 toSys= 0;
1551 if (YNotNil(keySymbols[8]))
1552 toSys= (YGetInteger(keySymbols[8])!=0);
1553
1554 if (!text) text= "";
1555 curElement= -1;
1556 curElement= GdText(x, y, text, toSys);
1557 if (curElement<0) YWarning("Gist GdText plotter failed");
1558
1559 Drop(nArgs);
1560 }
1561
1562 #undef N_KEYWORDS
1563 #define N_KEYWORDS 5
1564 static char *pldjKeys[N_KEYWORDS+1]= {
1565 "legend", "hide", "color", "type", "width", 0 };
1566
Y_pldj(int nArgs)1567 void Y_pldj(int nArgs)
1568 {
1569 Symbol *keySymbols[N_KEYWORDS];
1570 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, pldjKeys, keySymbols);
1571 double *x0= 0, *y0= 0, *x1= 0, *y1= 0;
1572 char *x0_name= 0, *y0_name= 0, *x1_name= 0, *y1_name= 0;
1573 long n= 0;
1574 int iPass= 0;
1575
1576 if (!CalledAsSubroutine())
1577 YError("pldj may not be invoked as a function -- subroutine only");
1578
1579 while (stack<=sp) {
1580 if (!stack->ops) { stack+= 2; continue; }
1581 if (iPass==0) x0= GetDouble(stack, &n);
1582 else if (iPass==1) x0_name= YGetString(stack);
1583 else if (iPass==2) y0= GetDouble(stack, &n);
1584 else if (iPass==3) y0_name= YGetString(stack);
1585 else if (iPass==4) x1= GetDouble(stack, &n);
1586 else if (iPass==5) x1_name= YGetString(stack);
1587 else if (iPass==6) y1= GetDouble(stack, &n);
1588 else if (iPass==7) y1_name= YGetString(stack);
1589 iPass++;
1590 stack++;
1591 }
1592 if (iPass!=8)
1593 YError("pldj requires exactly four non-keyword arguments");
1594
1595 /* set legend and hide in gistD */
1596 CheckDefaultWindow();
1597 LegendAndHide("pldj, ", x0_name, y0_name, x1_name, y1_name, keySymbols);
1598
1599 /* set properties, starting from defaults for simple polylines */
1600 GhGetMesh();
1601
1602 if (YNotNil(keySymbols[2]))
1603 gistA.l.color= YgetColor(keySymbols[2]);
1604 if (YNotNil(keySymbols[3]))
1605 gistA.l.type= GetLineType(keySymbols[3]);
1606 if (YNotNil(keySymbols[4]))
1607 gistA.l.width= YGetReal(keySymbols[4]);
1608
1609 curElement= -1;
1610 curElement= GdDisjoint(n, x0, y0, x1, y1);
1611 if (curElement<0) YWarning("Gist GdDisjoint plotter failed");
1612
1613 Drop(nArgs);
1614 }
1615
GetDouble(Symbol * stack,long * n)1616 static double *GetDouble(Symbol *stack, long *n)
1617 {
1618 Operand op;
1619 if (!stack || !stack->ops)
1620 YError("unexpected keyword or missing argument (BUG?)");
1621 stack->ops->FormOperand(stack, &op);
1622 if (op.ops->promoteID>T_DOUBLE)
1623 YError("expecting argument convertable to type double");
1624 op.ops->ToDouble(&op);
1625 *n= op.type.number;
1626 return (double *)op.value;
1627 }
1628
1629 /*--------------------------------------------------------------------------*/
1630
1631 #undef N_KEYWORDS
1632 #define N_KEYWORDS 3
1633 static char *limKeys[N_KEYWORDS+1]= {
1634 "square", "nice", "restrict", 0 };
1635
Y_limits(int nArgs)1636 void Y_limits(int nArgs)
1637 {
1638 /* NB-- If the plot has not been displayed yet, this will not retrieve
1639 the latest extreme values calculated by GdScan. Nevertheless,
1640 it DOES retrieve the precise state of the limits at the time
1641 of this call, and retoring them will work correctly. */
1642 Symbol *keySymbols[N_KEYWORDS];
1643 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, limKeys, keySymbols);
1644 Operand op;
1645 double old_limits[5], *new_limits= 0;
1646 double xmin= 0.0, xmax= 0.0, ymin= 0.0, ymax= 0.0;
1647 char *extreme;
1648 int flags= 0, changed= 0;
1649 int iPass= 0;
1650
1651 while (stack<=sp) {
1652 if (!stack->ops) { stack+= 2; continue; }
1653 if (new_limits)
1654 YError("only one argument allowed when restoring saved limits");
1655
1656 if (YNotNil(stack)) {
1657 stack->ops->FormOperand(stack, &op);
1658 extreme= (op.ops==&stringOps && !op.type.dims)?
1659 ((char **)op.value)[0] : 0;
1660 if (!extreme || (extreme[0]!='e' && extreme[0]!='E') ||
1661 extreme[1]!='\0') {
1662 if (op.ops->promoteID>T_DOUBLE ||
1663 (op.type.dims && (iPass!=0 || op.type.dims->number!=5)))
1664 YError("illegal argument type in limits function");
1665 op.ops->ToDouble(&op);
1666 }
1667 if (iPass==0) {
1668 if (op.type.dims) new_limits= (double *)op.value;
1669 else if (extreme) flags|= D_XMIN;
1670 else xmin= *((double *)op.value);
1671 changed|= 1;
1672 } else if (iPass==1) {
1673 if (extreme) flags|= D_XMAX;
1674 else xmax= *((double *)op.value);
1675 changed|= 2;
1676 } else if (iPass==2) {
1677 if (extreme) flags|= D_YMIN;
1678 else ymin= *((double *)op.value);
1679 changed|= 4;
1680 } else if (iPass==3) {
1681 if (extreme) flags|= D_YMAX;
1682 else ymax= *((double *)op.value);
1683 changed|= 8;
1684 } else {
1685 YError("limits takes at most 4 non-keyword arguments");
1686 }
1687 }
1688
1689 iPass++;
1690 stack++;
1691 }
1692
1693 /* retrieve current limits and flags */
1694 GdGetLimits();
1695 old_limits[0]= gistD.limits.xmin;
1696 old_limits[1]= gistD.limits.xmax;
1697 old_limits[2]= gistD.limits.ymin;
1698 old_limits[3]= gistD.limits.ymax;
1699 old_limits[4]= (double)gistD.flags;
1700
1701 /* process square=, nice=, restrict= keywords */
1702 if (YNotNil(keySymbols[0])) {
1703 if (new_limits) flags= 1;
1704 else if (YGetInteger(keySymbols[0])) gistD.flags|= D_SQUARE;
1705 else gistD.flags&= ~D_SQUARE;
1706 changed|= 16;
1707 }
1708 if (YNotNil(keySymbols[1])) {
1709 if (new_limits) flags= 1;
1710 else if (YGetInteger(keySymbols[1])) gistD.flags|= D_NICE;
1711 else gistD.flags&= ~D_NICE;
1712 changed|= 16;
1713 }
1714 if (YNotNil(keySymbols[2])) {
1715 if (new_limits) flags= 1;
1716 else if (YGetInteger(keySymbols[2])) gistD.flags|= D_RESTRICT;
1717 else gistD.flags&= ~D_RESTRICT;
1718 changed|= 16;
1719 }
1720
1721 if (new_limits) {
1722 /* restore limits saved with previous limits command */
1723 if (flags) YError("no keywords allowed when restoring saved limits");
1724 gistD.limits.xmin= new_limits[0];
1725 gistD.limits.xmax= new_limits[1];
1726 gistD.limits.ymin= new_limits[2];
1727 gistD.limits.ymax= new_limits[3];
1728 gistD.flags= (int)new_limits[4];
1729
1730 } else if (nArgs) {
1731 /* process xmin, xmax, ymin, ymax */
1732 if (changed&1) {
1733 gistD.limits.xmin= xmin;
1734 if (flags&D_XMIN) gistD.flags|= D_XMIN;
1735 else gistD.flags&= ~D_XMIN;
1736 }
1737 if (changed&2) {
1738 gistD.limits.xmax= xmax;
1739 if (flags&D_XMAX) gistD.flags|= D_XMAX;
1740 else gistD.flags&= ~D_XMAX;
1741 }
1742 if (changed&4) {
1743 gistD.limits.ymin= ymin;
1744 if (flags&D_YMIN) gistD.flags|= D_YMIN;
1745 else gistD.flags&= ~D_YMIN;
1746 }
1747 if (changed&8) {
1748 gistD.limits.ymax= ymax;
1749 if (flags&D_YMAX) gistD.flags|= D_YMAX;
1750 else gistD.flags&= ~D_YMAX;
1751 }
1752
1753 } else {
1754 /* just reset to extreme values */
1755 changed= (D_XMIN | D_XMAX | D_YMIN | D_YMAX);
1756 gistD.flags|= changed;
1757 }
1758
1759 /* set new limits in drawing */
1760 if (changed) GdSetLimits();
1761
1762 Drop(nArgs);
1763 if (!CalledAsSubroutine()) {
1764 Array *array=
1765 PushDataBlock(NewArray(&doubleStruct,
1766 NewDimension(5L, 1L, (Dimension *)0)));
1767 double *lims= array->value.d;
1768 int i;
1769 array->type.dims->references--;
1770 for (i=0 ; i<5 ; i++) lims[i]= old_limits[i];
1771 }
1772 }
1773
Y_logxy(int nArgs)1774 void Y_logxy(int nArgs)
1775 {
1776 int xflag= 0, yflag= 0, changed;
1777 int iPass= 0;
1778 Symbol *stack= sp-nArgs+1;
1779
1780 changed= 0;
1781 while (stack<=sp) {
1782 if (!stack->ops) YError("logxy takes no keyword arguments");
1783 if (YNotNil(stack)) {
1784 if (iPass==0) {
1785 xflag= (YGetInteger(stack)!=0);
1786 changed|= 1;
1787 } else if (iPass==1) {
1788 yflag= (YGetInteger(stack)!=0);
1789 changed|= 2;
1790 } else {
1791 YError("logxy takes at most two arguments");
1792 }
1793 }
1794 iPass++;
1795 stack++;
1796 }
1797
1798 if (changed) {
1799 GdGetLimits();
1800 if (changed&1) {
1801 if (xflag) gistD.flags|= D_LOGX;
1802 else gistD.flags&= ~D_LOGX;
1803 }
1804 if (changed&2) {
1805 if (yflag) gistD.flags|= D_LOGY;
1806 else gistD.flags&= ~D_LOGY;
1807 }
1808 GdSetLimits();
1809 }
1810
1811 Drop(nArgs);
1812 }
1813
Y_zoom_factor(int nArgs)1814 void Y_zoom_factor(int nArgs)
1815 {
1816 if (nArgs!=1) YError("zoom_factor takes exactly one argument");
1817 DISPLAY_ZOOM_FACTOR= YGetReal(sp);
1818 /* avert various disasters --
1819 doesn't address DISPLAY_ZOOM_FACTOR==1.0, which would be frustrating... */
1820 if (DISPLAY_ZOOM_FACTOR<0.0) DISPLAY_ZOOM_FACTOR= -DISPLAY_ZOOM_FACTOR;
1821 if (DISPLAY_ZOOM_FACTOR<0.05) DISPLAY_ZOOM_FACTOR= 0.05;
1822 else if (DISPLAY_ZOOM_FACTOR>20.0) DISPLAY_ZOOM_FACTOR= 20.0;
1823 }
1824
Y_unzoom(int nArgs)1825 void Y_unzoom(int nArgs)
1826 {
1827 if (nArgs!=0) YError("unzoom takes exactly zero argument");
1828 GdRevertLimits(1);
1829 }
1830
1831 /*--------------------------------------------------------------------------*/
1832
1833 static char *window_name(int n);
1834 static char *
window_name(int n)1835 window_name(int n)
1836 {
1837 static char buffer[20];
1838 sprintf(buffer, "Yorick %d", n);
1839 return buffer;
1840 }
1841
SetHCPDefault(void)1842 static void SetHCPDefault(void)
1843 {
1844 int i, j;
1845 p_file *f;
1846 char hcpName[16];
1847 if (!hcpPSdefault) strcpy(hcpName, "Aa00.cgm");
1848 else strcpy(hcpName, "Aa00.ps");
1849
1850 for (j='A' ; j<='Z' ; j++) {
1851 hcpName[0]= j;
1852 for (i='a' ; i<='z' ; i++) {
1853 hcpName[1]= i;
1854 if ((f= p_fopen(hcpName, "rb"))) p_fclose(f);
1855 else goto got1;
1856 }
1857 }
1858 YError("you appear to have Aa00 through Zz00 hcp files -- clean up");
1859
1860 got1:
1861 if (!hcpPSdefault)
1862 hcpDefault= GpCGMEngine("Yorick default", 0, hcpDump,
1863 SetHCPname(-1, hcpName));
1864 else
1865 hcpDefault= GpPSEngine("Yorick default", 0, hcpDump,
1866 SetHCPname(-1, hcpName));
1867 if (!hcpDefault) YError("failed to create default hcp file");
1868 }
1869
CheckDefaultWindow(void)1870 static void CheckDefaultWindow(void)
1871 {
1872 int i;
1873 for (i=0 ; i<GH_NDEVS ; i++) if (ghDevices[i].drawing) {
1874 if (!ghDevices[i].display && !ghDevices[i].hcp) {
1875 Drauing *drawing= ghDevices[i].drawing;
1876 ghDevices[i].drawing= 0;
1877 GdKillDrawing(drawing);
1878 curElement= -1;
1879 }
1880 }
1881 if (GhGetPlotter()<0) {
1882 for (i=0 ; i<GH_NDEVS ; i++) if (ghDevices[i].drawing)
1883 YError("graphics window killed -- use window command to re-select");
1884 ghDevices[0].drawing=
1885 GdNewDrawing(defaultStyle? defaultStyle : "work.gs");
1886 curElement= -1;
1887 if (!ghDevices[0].drawing)
1888 YError("failed to create drawing -- Gist work.gs style sheet missing");
1889 ghDevices[0].doLegends= defaultLegends;
1890
1891 #ifndef NO_XLIB
1892 gist_private_map = gist_rgb_hint = 0;
1893 gx_parent = 0;
1894 ghDevices[0].display=
1895 DISPLAY_ENGINE(window_name(0), 0, defaultDPI, (char *)0);
1896 if (!ghDevices[0].display)
1897 YError("failed to open X display or create X window");
1898 #else
1899 ghDevices[0].display= 0;
1900 ghDevices[0].hcp= hcpDefault;
1901 hcpDefault= 0;
1902 #endif
1903
1904 GhSetPlotter(0);
1905 }
1906 }
1907
CheckDefaultPalette(void)1908 static void CheckDefaultPalette(void)
1909 {
1910 GpColorCell *palette;
1911 GhGetPalette(-1, &palette);
1912 if (!palette) GhReadPalette(-1, defaultPalette? defaultPalette : "earth.gp",
1913 &palette, maxColors);
1914 }
1915
CheckPalette(void)1916 static void CheckPalette(void)
1917 {
1918 int n= GhGetPlotter();
1919 if (n>=0 && !ghDevices[n].hcp) {
1920 if (!hcpDefault) SetHCPDefault();
1921 SetHCPPalette();
1922 }
1923 }
1924
SetHCPname(int n,char * name)1925 static char *SetHCPname(int n, char *name)
1926 {
1927 char *now;
1928 if (n<0 || n>GH_NDEVS) n= GH_NDEVS;
1929 now= hcpNames[n];
1930 hcpNames[n]= YExpandName(name);
1931 p_free(now);
1932 return hcpNames[n];
1933 }
1934
GetHCPname(int n)1935 static char *GetHCPname(int n)
1936 {
1937 if (n>=0 && n<GH_NDEVS && ghDevices[n].hcp) return hcpNames[n];
1938 else return hcpNames[GH_NDEVS];
1939 }
1940
1941 #undef N_KEYWORDS
1942 #define N_KEYWORDS 14
1943 static char *windowKeys[N_KEYWORDS+1]= {
1944 "display", "dpi", "private", "hcp", "legends", "dump", "style", "wait",
1945 "width", "height", "rgb", "parent", "xpos", "ypos", 0 };
1946
1947 static Instruction *yg_pc_resume = 0;
1948 extern void yg_got_expose(void);
1949 extern Instruction *ym_suspend(void);
1950 extern void ym_resume(Instruction *);
1951 extern int yg_blocking;
1952 int yg_blocking = 0;
1953
Y_window(int nArgs)1954 void Y_window(int nArgs)
1955 {
1956 int n, nGiven;
1957 Symbol *keySymbols[N_KEYWORDS];
1958 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, windowKeys, keySymbols);
1959 GpColorCell *palette;
1960 int nColors= 0;
1961 int wait_for_expose = 0;
1962 int rgb = 0;
1963 int n0 = GhGetPlotter();
1964
1965 if (stack<=sp && YNotNil(stack++)) {
1966 n= (int)YGetInteger(stack-1);
1967 if (n<0 || n>=GH_NDEVS) YError("bad graphics windows are number");
1968 nGiven= (!ghDevices[n].display && !ghDevices[n].hcp);
1969 } else {
1970 n = n0;
1971 nGiven= (n<0);
1972 if (nGiven) n= 0;
1973 }
1974 while (stack<=sp) {
1975 if (!stack->ops) stack+= 2;
1976 else YError("window function takes at most one non-keyword argument");
1977 }
1978
1979 curElement= -1;
1980
1981 /* get current palette for this graphics window */
1982 nColors= GhGetPalette(n, &palette);
1983
1984 /* check for width and height specs, subwindow hack */
1985 #ifndef NO_XLIB
1986 gx_parent = 0;
1987 if (YNotNil(keySymbols[8])) {
1988 extern int gx75width, gx100width;
1989 int width= (int)YGetInteger(keySymbols[8]);
1990 if (width>30) gx75width= gx100width= width;
1991 else { gx75width= 450; gx100width= 600; }
1992 }
1993 if (YNotNil(keySymbols[9])) {
1994 extern int gx75height, gx100height;
1995 int height= (int)YGetInteger(keySymbols[9]);
1996 if (height>30) gx75height= gx100height= height;
1997 else { gx75height= 450; gx100height= 600; }
1998 }
1999 if (YNotNil(keySymbols[11])) {
2000 extern int gx_xloc, gx_yloc;
2001 gx_parent = (unsigned long)YGetInteger(keySymbols[11]);
2002 gx_xloc = gx_yloc = 0;
2003 if (YNotNil(keySymbols[12]))
2004 gx_xloc = (int)YGetInteger(keySymbols[12]);
2005 if (YNotNil(keySymbols[13]))
2006 gx_yloc = (int)YGetInteger(keySymbols[13]);
2007 }
2008 #endif
2009
2010 if (nGiven || keySymbols[0] || keySymbols[1] || keySymbols[2]) {
2011 /* display= and/or dpi= keywords */
2012 char *display= 0;
2013 int dpi= defaultDPI;
2014 int privmap = 0;
2015 Engine *engine= ghDevices[n].display; /* current display engine */
2016
2017 if (YNotNil(keySymbols[0])) display= YGetString(keySymbols[0]);
2018 if (YNotNil(keySymbols[1])) {
2019 if (engine) YError("cannot change dpi of an existing graphics window");
2020 dpi= (int)YGetInteger(keySymbols[1]);
2021 /*if (dpi!=100 && dpi!=75)
2022 YError("dpi=100 or dpi=75 are only legal values");*/
2023 if (dpi<25) dpi = 25;
2024 else if (dpi>2400) dpi = 2400;
2025 }
2026 if (YNotNil(keySymbols[2])) {
2027 /* private= keyword -- turn on/off private X window colormap */
2028 if (engine)
2029 YError("cannot give existing graphics window private colormap");
2030 if (!(nGiven? (!display || display[0]) : (display && display[0])))
2031 YError("private= keyword not legal without display engine");
2032 privmap = YGetInteger(keySymbols[2])!=0;
2033 }
2034 if (YNotNil(keySymbols[10])) {
2035 /* rgb= keyword -- maybe make this a true color window */
2036 if (engine)
2037 YError("cannot use rgb= on existing graphics window");
2038 if (!(nGiven? (!display || display[0]) : (display && display[0])))
2039 YError("rgb= keyword not legal without display engine");
2040 rgb = YGetInteger(keySymbols[10])!=0;
2041 }
2042
2043 if (engine) GpKillEngine(engine);
2044
2045 if (nGiven? (!display || display[0]) : (display && display[0])) {
2046 #ifndef NO_XLIB
2047 gist_private_map = privmap;
2048 gist_rgb_hint = rgb;
2049 engine= DISPLAY_ENGINE(window_name(n), 0, dpi, display);
2050 if (!engine) YError("failed to open X display or create X window");
2051 else wait_for_expose = 1;
2052 ghDevices[n].display= engine;
2053 if (palette) GhSetPalette(n, palette, nColors);
2054 #else
2055 YError("No interactive graphics in this Yorick -- hcp only");
2056 #endif
2057 }
2058 }
2059
2060 if (keySymbols[3]) {
2061 /* hcp= keyword -- make a new hcp file */
2062 Engine *engine= ghDevices[n].hcp;
2063 char *hcp= 0;
2064 if (YNotNil(keySymbols[3])) hcp= YGetString(keySymbols[3]);
2065
2066 if (engine) {
2067 ghDevices[n].hcp= 0;
2068 GpKillEngine(engine);
2069 SetHCPname(n, (char *)0);
2070 }
2071
2072 if (hcp && hcp[0]) {
2073 long len= strlen(hcp);
2074 if (len>3 && strcmp(&hcp[len-3], ".ps")==0) {
2075 engine= GpPSEngine(window_name(n), 0, hcpDump, SetHCPname(n, hcp));
2076 if (!engine) YError("failed to create PostScript file");
2077 } else {
2078 engine= GpCGMEngine(window_name(n), 0, hcpDump, SetHCPname(n, hcp));
2079 if (!engine) YError("failed to create binary CGM file");
2080 }
2081 ghDevices[n].hcp= engine;
2082 if (palette) GhSetPalette(n, palette, nColors);
2083 }
2084 }
2085
2086 if (keySymbols[4] || keySymbols[3] ||
2087 nGiven || keySymbols[0] || keySymbols[1]) {
2088 if (YNotNil(keySymbols[4]))
2089 /* legends= keyword -- turn on/off legend dumping to hcp file */
2090 ghDevices[n].doLegends= (YGetInteger(keySymbols[4])!=0);
2091 else
2092 ghDevices[n].doLegends= defaultLegends;
2093 }
2094
2095 if (YNotNil(keySymbols[5])) {
2096 /* dump= keyword -- turn on/off colormap dumping to hcp file */
2097 if (!ghDevices[n].hcp)
2098 YError("dump= keyword not legal without hcp engine -- use hcp_file");
2099 GhDumpColors(n, 1, (YGetInteger(keySymbols[5])!=0));
2100 }
2101
2102 if (!ghDevices[n].display && !ghDevices[n].hcp) {
2103 /* shut down this graphics window completely */
2104 Drauing *drawing= ghDevices[n].drawing;
2105 ghDevices[n].drawing= 0;
2106 if (drawing) GdKillDrawing(drawing);
2107 GhDeletePalette(n);
2108 if (n==n0) {
2109 /* highest numbered remaining window becomes current window */
2110 for (n=GH_NDEVS-1 ; n>=0 ; n--)
2111 if (ghDevices[n].display || ghDevices[n].hcp) break;
2112 GhSetPlotter(n);
2113 }
2114
2115 } else {
2116 Drauing *drawing= ghDevices[n].drawing;
2117 if (keySymbols[6]) {
2118 /* style= keyword -- make new drawing */
2119 char *style= YNotNil(keySymbols[6]) ? YGetString(keySymbols[6]) : 0;
2120 if (drawing) {
2121 ghDevices[n].drawing= 0;
2122 GdKillDrawing(drawing);
2123 }
2124 if (!style || !style[0]) style= defaultStyle;
2125 ghDevices[n].drawing= drawing= GdNewDrawing(style? style : "work.gs");
2126
2127 } else if (!drawing) {
2128 /* supply default drawing */
2129 ghDevices[n].drawing= drawing=
2130 GdNewDrawing(defaultStyle? defaultStyle : "work.gs");
2131 }
2132
2133 if (!drawing) {
2134 ghDevices[n].drawing= drawing= GdNewDrawing("work.gs");
2135 if (drawing)
2136 YError("failed to create drawing -- bad style sheet name?");
2137 else
2138 YError("failed to create drawing -- Gist work.gs style sheet missing");
2139 }
2140
2141 /* make this window current */
2142 GhSetPlotter(n);
2143
2144 /* wait= keyword -- pause until X window is exposed */
2145 wait_for_expose = wait_for_expose &&
2146 YNotNil(keySymbols[7]) && YGetInteger(keySymbols[7]);
2147 }
2148
2149 Drop(nArgs);
2150 PushLongValue((long)n);
2151
2152 #ifndef NO_XLIB
2153 if (wait_for_expose) {
2154 Instruction *ipc = yg_pc_resume;
2155 int oops = 0;
2156 if (!ipc) {
2157 oops = gist_expose_wait(ghDevices[n].display, yg_got_expose);
2158 if (!oops) {
2159 yg_blocking = 1;
2160 yg_pc_resume = ym_suspend();
2161 } else if (oops == 2) {
2162 /* window was already exposed */
2163 oops = 0;
2164 }
2165 }
2166 if (ipc || oops) {
2167 yg_got_expose();
2168 YError("window,wait=1 while already waiting for a window");
2169 }
2170 }
2171 #endif
2172 }
2173
2174 static void yg_alarm(void *);
2175
2176 void
yg_got_expose(void)2177 yg_got_expose(void)
2178 {
2179 Instruction *ipc = yg_pc_resume;
2180 yg_pc_resume = 0;
2181 if (yg_blocking==2) p_clr_alarm(yg_alarm, 0);
2182 yg_blocking = 0;
2183 if (ipc) ym_resume(ipc);
2184 }
2185
Y_window_geometry(int argc)2186 void Y_window_geometry(int argc)
2187 {
2188 int win;
2189 double *geom;
2190 Engine *engine;
2191 GpXYMap *map;
2192 long dims[2];
2193
2194 double one_pixel, dpi, xbias, ybias, width, height;
2195
2196 if (argc != 1) {
2197 YError("window_geometry takes exactly one, possibly nil, argument");
2198 }
2199 if (YNotNil(sp)) {
2200 win = (int)YGetInteger(sp);
2201 } else {
2202 win = GhGetPlotter();
2203 }
2204 if (win < 0 || win >= GH_NDEVS || ! ghDevices[win].display) {
2205 PushDataBlock(RefNC(&nilDB));
2206 return;
2207 }
2208
2209 /* NDC -> pixel coordinate transform:
2210 * XPIX = (int)(XSCALE*XNDC + XOFFSET)
2211 * YPIX = (int)(YSCALE*YNDC + YOFFSET)
2212 * with:
2213 * XSCALE = ENGINE->map.x.scale XOFFSET = ENGINE->map.x.offset - margin
2214 * YSCALE = ENGINE->map.y.scale YOFFSET = ENGINE->map.y.offset - margin
2215 * assuming:
2216 * (XSCALE*XNDC + XOFFSET) >= 0
2217 * (YSCALE*YNDC + YOFFSET) >= 0
2218 * the reverse transform is:
2219 * XPIX <= XSCALE*XNDC + XOFFSET < XPIX + 1
2220 * YPIX <= YSCALE*YNDC + YOFFSET < YPIX + 1
2221 * to avoid rounding errors we choose the middle of the interval:
2222 * XNDC = (XPIX - XOFFSET + 0.5)/XSCALE = XBIAS + XPIX*ONE_PIXEL
2223 * YNDC = (YPIX - YOFFSET + 0.5)/YSCALE = YBIAS - YPIX*ONE_PIXEL
2224 * with:
2225 * ONE_PIXEL = 1.0/XSCALE = -1.0/YSCALE
2226 * XBIAS = (0.5 - XOFFSET)*ONE_PIXEL
2227 * XBIAS = (YOFFSET - 0.5)*ONE_PIXEL
2228 */
2229
2230 engine = ghDevices[win].display;
2231 if (engine) {
2232 map= &engine->map;
2233 dpi = ((XEngine *)engine)->dpi;
2234 one_pixel = 2.0/(map->x.scale - map->y.scale);
2235 #define MARGIN(SIDE) (((XEngine *)engine)->SIDE##Margin)
2236 xbias = (MARGIN(left) - map->x.offset + 0.5)/map->x.scale;
2237 ybias = (MARGIN(top) - map->y.offset + 0.5)/map->y.scale;
2238 #undef MARGIN
2239 width = ((XEngine *)engine)->wtop;
2240 height = ((XEngine *)engine)->htop;
2241 } else {
2242 dpi = one_pixel = xbias = ybias = width = height = 0.0;
2243 }
2244
2245 /* Build result array: [DPI, ONE_PIXEL, XBIAS, YBIAS, WIDTH, HEIGHT] */
2246 dims[0] = 1L;
2247 dims[1] = 6L;
2248 geom = ypush_d(dims);
2249 geom[0] = dpi;
2250 geom[1] = one_pixel;
2251 geom[2] = xbias;
2252 geom[3] = ybias;
2253 geom[4] = width;
2254 geom[5] = height;
2255 }
2256
Y_window_exists(int argc)2257 void Y_window_exists(int argc)
2258 {
2259 long n;
2260 if (argc != 1) YError("window_exists takes exactly one argument");
2261 n = YGetInteger(sp);
2262 PushIntValue(((n >= 0 && n < GH_NDEVS && ghDevices[n].display) ? 1 : 0));
2263 }
2264
Y_window_select(int argc)2265 void Y_window_select(int argc)
2266 {
2267 int n;
2268 if (argc != 1) YError("window_select takes exactly one argument");
2269 n = (int)YGetInteger(sp);
2270 if (n >= 0 && n < GH_NDEVS && ghDevices[n].display) {
2271 GhSetPlotter(n);
2272 PushIntValue(1);
2273 } else {
2274 PushIntValue(0);
2275 }
2276 }
2277
Y_window_list(int argc)2278 void Y_window_list(int argc)
2279 {
2280 long *p, i, n, dims[2];
2281
2282 if (argc != 1 || YNotNil(sp)) {
2283 YError("window_list takes exactly one nil argument");
2284 }
2285 for (n=i=0 ; i<GH_NDEVS ; ++i) {
2286 if (ghDevices[i].display) {
2287 ++n;
2288 }
2289 }
2290 if (n >= 1) {
2291 dims[0] = 1;
2292 dims[1] = n;
2293 p = ypush_l(dims);
2294 for (n=i=0 ; i<GH_NDEVS ; ++i) {
2295 if (ghDevices[i].display) {
2296 p[n++] = i;
2297 }
2298 }
2299 } else {
2300 ypush_nil();
2301 }
2302 }
2303
2304 #undef N_KEYWORDS
2305 #define N_KEYWORDS 2
2306 static char *hcpKeys[N_KEYWORDS+1]= { "dump", "ps", 0 };
2307
Y_hcp_file(int nArgs)2308 void Y_hcp_file(int nArgs)
2309 {
2310 Symbol *keySymbols[N_KEYWORDS];
2311 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, hcpKeys, keySymbols);
2312 Engine *engine= hcpDefault;
2313 int gotDump= YNotNil(keySymbols[0]);
2314
2315 if (gotDump) hcpDump= (YGetInteger(keySymbols[0])!=0);
2316
2317 if (YNotNil(keySymbols[1])) hcpPSdefault= (YGetInteger(keySymbols[1])!=0);
2318
2319 if (stack<=sp && YNotNil(stack)) {
2320 char *hcp= YGetString(stack);
2321 long len= Safe_strlen(hcp);
2322
2323 if (engine) {
2324 hcpDefault= 0;
2325 GpKillEngine(engine);
2326 SetHCPname(-1, (char *)0);
2327 engine= 0;
2328 }
2329
2330 if (len>3 && strcmp(&hcp[len-3], ".ps")==0) {
2331 engine= GpPSEngine("Yorick default", 0, hcpDump, SetHCPname(-1, hcp));
2332 if (!engine) YError("failed to create PostScript file");
2333 } else if (len>0) {
2334 engine= GpCGMEngine("Yorick default", 0, hcpDump, SetHCPname(-1, hcp));
2335 if (!engine) YError("failed to create binary CGM file");
2336 }
2337
2338 hcpDefault= engine;
2339 stack++;
2340 } else if (gotDump) {
2341 GhDumpColors(-1, 1, hcpDump);
2342 }
2343 while (stack<=sp) {
2344 if (!stack->ops) stack+= 2;
2345 else YError("hcp_file function takes at most one non-keyword argument");
2346 }
2347
2348 Drop(nArgs);
2349 }
2350
Y_hcp_finish(int nArgs)2351 void Y_hcp_finish(int nArgs)
2352 {
2353 /* just return name of current hcp file */
2354 int n= GhGetPlotter();
2355 Array *array;
2356 Engine *engine;
2357
2358 if (nArgs==1) {
2359 if (YNotNil(sp)) n= YGetInteger(sp);
2360 if (n<-1 || n>=GH_NDEVS)
2361 YError("hcp_finish argument must be -1 or a graphics window number");
2362 } else if (nArgs) {
2363 YError("hcp_finish takes zero or one arguments");
2364 }
2365
2366 array= PushDataBlock(NewArray(&stringStruct, (Dimension *)0));
2367 array->value.q[0]= p_strcpy(GetHCPname(n));
2368
2369 if (n>=0) engine= ghDevices[n].hcp? ghDevices[n].hcp : hcpDefault;
2370 else engine= hcpDefault;
2371 if (engine) {
2372 if (engine==hcpDefault) {
2373 hcpDefault= 0;
2374 } else {
2375 ghDevices[n].hcp= 0;
2376 }
2377 GpKillEngine(engine);
2378 SetHCPname(n, (char *)0);
2379 }
2380 }
2381
Y_plsys(int nArgs)2382 void Y_plsys(int nArgs)
2383 {
2384 int n0;
2385 if (nArgs!=1) YError("plsys takes exactly one argument");
2386
2387 CheckDefaultWindow();
2388 n0= GdGetSystem();
2389
2390 if (YNotNil(sp)) {
2391 int n= (int)YGetInteger(sp);
2392 if (GdSetSystem(n)!=E_SYSTEM && n!=0)
2393 YError("no such coordinate system exists in current graphics window");
2394 }
2395
2396 PushLongValue((long)n0);
2397 }
2398
2399 #undef N_KEYWORDS
2400 #define N_KEYWORDS 2
2401 static char *paletteKeys[N_KEYWORDS+1]= { "ntsc", "query", 0 };
2402
Y_palette(int nArgs)2403 void Y_palette(int nArgs)
2404 {
2405 Symbol *keySymbols[N_KEYWORDS];
2406 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, paletteKeys, keySymbols);
2407 Operand op;
2408 GpColorCell *palette= 0;
2409 unsigned char *red= 0, *green= 0, *blue= 0, *gray= 0;
2410 int i, iPass, nColors, nDevice, query= 0;
2411 Engine *engine;
2412 int sourceDevice= -2;
2413 char **name= 0;
2414
2415 CheckDefaultWindow();
2416 nDevice= GhGetPlotter();
2417 engine= ghDevices[nDevice].display;
2418 if (!engine) engine= ghDevices[nDevice].hcp;
2419
2420 if (YNotNil(keySymbols[1])) {
2421 Dimension *dims= tmpDims;
2422 tmpDims= 0;
2423 FreeDimension(dims);
2424 query= (YGetInteger(keySymbols[1])!=0);
2425 }
2426
2427 iPass= nColors= 0;
2428 while (stack<=sp) {
2429 if (!stack->ops) { stack+= 2; continue; }
2430 if (iPass>3)
2431 YError("palette takes at most red, green, blue, gray arguments");
2432
2433 if (query) {
2434 if (stack->ops!=&referenceSym)
2435 YError("palette query needs simple variable references as arguments");
2436 if (iPass==0) nColors= GpGetPalette(engine, &palette);
2437 if (nColors>0) {
2438 Array *array;
2439 tmpDims= NewDimension((long)nColors, 1L, (Dimension *)0);
2440 array= PushDataBlock(NewArray(&charStruct, tmpDims));
2441 red= (unsigned char *)array->value.c;
2442 if (iPass==0)
2443 for (i=0 ; i<nColors ; i++) red[i]=(unsigned char)(P_R(palette[i]));
2444 else if (iPass==1)
2445 for (i=0 ; i<nColors ; i++) red[i]=(unsigned char)(P_G(palette[i]));
2446 else if (iPass==2)
2447 for (i=0 ; i<nColors ; i++) red[i]=(unsigned char)(P_B(palette[i]));
2448 else if (iPass==3)
2449 for (i=0 ; i<nColors ; i++)
2450 red[i]=(unsigned char)((P_R(palette[i])+P_G(palette[i])+
2451 P_B(palette[i]))/3);
2452 } else {
2453 PushDataBlock(RefNC(&nilDB));
2454 }
2455 PopTo(&globTab[stack->index]);
2456
2457 } else {
2458 stack->ops->FormOperand(stack, &op);
2459 if (iPass==0) {
2460 if (op.ops==&stringOps) {
2461 /* palette, filename */
2462 name= op.value;
2463
2464 } else if (!op.type.dims) {
2465 /* palette, source_window */
2466 if (op.ops->promoteID>T_LONG)
2467 YError("palette source window number must be an integer");
2468 op.ops->ToLong(&op);
2469 sourceDevice= (int)(*((long *)op.value));
2470 if (sourceDevice<0 || sourceDevice>=GH_NDEVS ||
2471 (!(engine= ghDevices[sourceDevice].display) &&
2472 !(engine= ghDevices[sourceDevice].hcp)))
2473 YError("specified palette source window does not exist");
2474 nColors= GpGetPalette(engine, &palette);
2475
2476 } else {
2477 /* palette, red, green, blue */
2478 op.ops->ToChar(&op);
2479 red= op.value;
2480 nColors= (int)op.type.number;
2481 }
2482
2483 if (nColors>256)
2484 YError("Gist palettes can never have more than 256 colors");
2485
2486 } else {
2487 /* palette, red, green, blue */
2488 if (!red) YError("garbled arguments to palette command");
2489 op.ops->ToChar(&op);
2490 if (op.type.number != nColors)
2491 YError("red, green, blue, and gray arguments must be same length");
2492 if (iPass==1) green= op.value;
2493 if (iPass==2) blue= op.value;
2494 if (iPass==3) gray= op.value;
2495 }
2496 }
2497
2498 iPass++;
2499 stack++;
2500 }
2501
2502 if (!query) {
2503 if (sourceDevice!=nDevice) {
2504 /* be sure to preserve dump=1 setting even if hcp palette
2505 is deleted */
2506 int dump;
2507 if (hcpDefault) dump= GhGetColorMode(hcpDefault);
2508 else dump= 0;
2509 GhDeletePalette(nDevice);
2510 if (hcpDefault) GhDumpColors(-1, 1, dump);
2511 }
2512 if (red || palette) {
2513 if (red) {
2514 if (iPass<3)
2515 YError("palette needs at least red, green, and blue components");
2516 /* palette is unprotected against asynchronous interrupts...
2517 fix this someday */
2518 palette = p_malloc(sizeof(GpColorCell)*nColors);
2519 /* palette, red, green, blue malloc'ed like GhReadPalette */
2520 for (i=0 ; i<nColors ; i++) {
2521 palette[i] = P_RGB(red[i], green[i], blue[i]);
2522 /* if (gray) palette[i].gray = gray[i]; */
2523 }
2524 }
2525 if (!gray) {
2526 if (YNotNil(keySymbols[0]) && YGetInteger(keySymbols[0])!=0)
2527 GpPutNTSC(nColors, palette);
2528 else
2529 GpPutGray(nColors, palette);
2530 }
2531 GhSetPalette(nDevice, palette, nColors);
2532
2533 } else if (name) {
2534 nColors= GhReadPalette(nDevice, name[0], &palette, maxColors);
2535 if (nColors<=0)
2536 YError("no such palette -- missing Gist palette file?");
2537
2538 } else {
2539 YError("palette needs at least one non-keyword argument");
2540 }
2541 }
2542 }
2543
2544 /*--------------------------------------------------------------------------*/
2545
Y_fma(int nArgs)2546 void Y_fma(int nArgs)
2547 {
2548 if (nArgs) YError("fma takes exactly zero argument");
2549 CheckDefaultWindow();
2550 if (hcpOnFMA) CheckPalette();
2551 curElement= -1;
2552 GhFMA();
2553 }
2554
Y_redraw(int nArgs)2555 void Y_redraw(int nArgs)
2556 {
2557 if (nArgs) YError("redraw takes exactly zero argument");
2558 CheckDefaultWindow();
2559 GhRedraw();
2560 }
2561
Y_hcp(int nArgs)2562 void Y_hcp(int nArgs)
2563 {
2564 if (nArgs) YError("hcp takes exactly zero argument");
2565 CheckDefaultWindow();
2566 CheckPalette();
2567 GhHCP();
2568 }
2569
Y_hcpon(int nArgs)2570 void Y_hcpon(int nArgs)
2571 {
2572 if (nArgs) YError("hcpon takes exactly zero argument");
2573 CheckDefaultWindow();
2574 hcpOnFMA= 1;
2575 GhFMAMode(1, 2);
2576 }
2577
Y_hcpoff(int nArgs)2578 void Y_hcpoff(int nArgs)
2579 {
2580 if (nArgs) YError("hcpoff takes exactly zero argument");
2581 CheckDefaultWindow();
2582 hcpOnFMA= 0;
2583 GhFMAMode(0, 2);
2584 }
2585
Y_animate(int nArgs)2586 void Y_animate(int nArgs)
2587 {
2588 int i= 3; /* default is to toggle */
2589
2590 if (nArgs==1 && YNotNil(sp)) i= (int)YGetInteger(sp);
2591 else if (nArgs>1) YError("animate takes zero or one argument");
2592
2593 CheckDefaultWindow();
2594
2595 curElement= -1;
2596 GhFMAMode(2, i);
2597 }
2598
2599 /*--------------------------------------------------------------------------*/
2600
2601 static long prop3sizes[10]= {0, 8, 2, 5, 5, 4, 3, 7, 1, 3};
2602 static long prop4sizes[10]= {0, 8, 1, 3, 1, 1, 3, 4, 4, 1};
2603 static long prop5sizes[10]= {0, 3, 5, 2, 5, 6, 7, 9, 3, 5};
2604
2605 static int curIX= -1, curIXc= -1;
2606 static char specialMarkers[5]= ".+*ox";
2607
Y_plq(int nArgs)2608 void Y_plq(int nArgs)
2609 {
2610 int type, n_element= 0, n_contour= 0;
2611
2612 if (nArgs==1) {
2613 if (YNotNil(sp)) n_element= (int)YGetInteger(sp);
2614 } else if (nArgs==2) {
2615 if (YNotNil(sp-1)) n_element= (int)YGetInteger(sp-1);
2616 if (YNotNil(sp)) n_contour= (int)YGetInteger(sp);
2617 } else if (nArgs>2) {
2618 YError("plq function takes no more than two arguments");
2619 }
2620 Drop(nArgs);
2621
2622 /* Yorick uses 1-origin element numbering, Gist uses 0-origin */
2623 n_element--;
2624 n_contour--;
2625
2626 if (n_element>=0) {
2627 /* retrieve specified element */
2628 type= GdSetElement(n_element);
2629 if (n_contour>=0) {
2630 if (type!=E_CONTOURS)
2631 YError("current graphical element is not contours in pledit");
2632 type= GdSetContour(n_contour);
2633 }
2634 curElement= -6666; /* differs from -1 to allow pledit after plq */
2635 curIX= n_element; /* need these, too */
2636 curIXc= n_contour;
2637 if (type==E_LINES) type= 1;
2638 else if (type==E_DISJOINT) type= 2;
2639 else if (type==E_TEXT) type= 3;
2640 else if (type==E_MESH) type= 4;
2641 else if (type==E_FILLED) type= 5;
2642 else if (type==E_VECTORS) type= 6;
2643 else if (type==E_CONTOURS) type= 7;
2644 else if (type==E_CELLS) type= 8;
2645 else if (type==E_POLYS) type= 9;
2646 else type= 0;
2647
2648 if (CalledAsSubroutine()) {
2649 /* return printed summary of keyword values */
2650 char line[120];
2651 PrintInit(YputsOut);
2652
2653 if (type==0) {
2654 sprintf(line, "<no such object> element# %d", n_element+1);
2655 PrintFunc(line);
2656 if (n_contour>=0) {
2657 sprintf(line, " contour# %d", n_contour+1);
2658 PrintFunc(line);
2659 }
2660 ForceNewline();
2661
2662 } else if (type==1) {
2663 sprintf(line, "plg element# %d", n_element+1);
2664 PrintFunc(line);
2665 if (n_contour>=0) {
2666 sprintf(line, " contour# %d", n_contour+1);
2667 PrintFunc(line);
2668 ForceNewline();
2669 sprintf(line, " at level value %g", gistD.levels[n_contour]);
2670 PrintFunc(line);
2671 }
2672 ForceNewline();
2673 PrintHideLegend(line, type);
2674 PrintColor(line, gistA.l.color, 1);
2675 PrintTypeWidth(line, 3);
2676 PrintMarks(line, 3);
2677 sprintf(line, "rays= %d,", gistA.dl.rays);
2678 PrintFunc(line);
2679 ForceNewline();
2680 sprintf(line,
2681 " arrowl= %.2f, arroww= %.2f, rspace= %.5f, rphase= %.5f,",
2682 Safe_dbl(gistA.dl.arrowL), Safe_dbl(gistA.dl.arrowW),
2683 Safe_dbl(gistA.dl.rSpace), Safe_dbl(gistA.dl.rPhase));
2684 PrintFunc(line);
2685 ForceNewline();
2686 sprintf(line, "smooth= %d, closed= %d",
2687 gistA.dl.smooth, gistA.dl.closed);
2688 PrintFunc(line);
2689 ForceNewline();
2690
2691 } else if (type==2) {
2692 sprintf(line, "pldj element# %d", n_element+1);
2693 PrintFunc(line);
2694 ForceNewline();
2695 PrintHideLegend(line, type);
2696 PrintColor(line, gistA.l.color, 1);
2697 PrintTypeWidth(line, 2);
2698
2699 } else if (type==3) {
2700 sprintf(line, "plt element# %d", n_element+1);
2701 PrintFunc(line);
2702 ForceNewline();
2703 PrintHideLegend(line, type);
2704 PrintColor(line, gistA.t.color, 3);
2705 sprintf(line, "text= %.80s", gistD.text);
2706 PrintFunc(line);
2707 ForceNewline();
2708
2709 } else if (type==4) {
2710 sprintf(line, "plm element# %d", n_element+1);
2711 PrintFunc(line);
2712 ForceNewline();
2713 PrintHideLegend(line, type);
2714 PrintColor(line, gistA.l.color, 1);
2715 PrintTypeWidth(line, 2);
2716 PrintRegion(line, 1);
2717 sprintf(line, "boundary= %d, inhibit= %d", gistD.boundary,
2718 gistD.inhibit);
2719 PrintFunc(line);
2720 ForceNewline();
2721
2722 } else if (type==5) {
2723 sprintf(line, "plf element# %d", n_element+1);
2724 PrintFunc(line);
2725 ForceNewline();
2726 PrintHideLegend(line, type);
2727 sprintf(line, "edges= %d, e", gistA.e.type!=L_NONE);
2728 PrintFunc(line);
2729 PrintColor(line, gistA.e.color, 1);
2730 sprintf(line, "ewidth= %.2f", Safe_dbl(gistA.e.width));
2731 PrintFunc(line);
2732 ForceNewline();
2733 PrintRegion(line, 2);
2734
2735 } else if (type==6) {
2736 sprintf(line, "plv element# %d", n_element+1);
2737 PrintFunc(line);
2738 ForceNewline();
2739 PrintHideLegend(line, type);
2740 PrintColor(line, gistA.l.color, 1);
2741 sprintf(line, "width= %.2f,", Safe_dbl(gistA.l.width));
2742 PrintFunc(line);
2743 ForceNewline();
2744 sprintf(line, "hollow= %d, aspect= %.4f,", gistA.vect.hollow,
2745 Safe_dbl(gistA.vect.aspect));
2746 PrintFunc(line);
2747 ForceNewline();
2748 PrintRegion(line, 3);
2749 sprintf(line, "scale= %g", gistD.scale);
2750 PrintFunc(line);
2751 ForceNewline();
2752
2753 } else if (type==7) {
2754 int i;
2755 sprintf(line, "plc element# %d", n_element+1);
2756 PrintFunc(line);
2757 ForceNewline();
2758 PrintHideLegend(line, type);
2759 PrintColor(line, gistA.l.color, 1);
2760 PrintTypeWidth(line, 3);
2761 PrintMarks(line, 3);
2762 sprintf(line, "smooth= %d,", gistA.dl.smooth);
2763 PrintFunc(line);
2764 ForceNewline();
2765 PrintRegion(line, 2);
2766 sprintf(line, "%d contour levels, levs=", gistD.nLevels);
2767 PrintFunc(line);
2768 ForceNewline();
2769 PrintFunc("[");
2770 if (gistD.nLevels>0) {
2771 for (i=0 ; ; i++) {
2772 sprintf(line, "%g", gistD.levels[i]);
2773 PrintFunc(line);
2774 if (i==gistD.nLevels-1) break;
2775 PrintFunc(",");
2776 PermitNewline(0);
2777 }
2778 }
2779 PrintFunc("]");
2780 ForceNewline();
2781
2782 } else if (type==8) {
2783 sprintf(line, "pli element# %d", n_element+1);
2784 PrintFunc(line);
2785 ForceNewline();
2786 PrintHideLegend(line, type);
2787 sprintf(line, "x0= %g, y0= %g, x1= %g, y1= %g",
2788 gistD.px, gistD.py, gistD.qx, gistD.qy);
2789 PrintFunc(line);
2790 ForceNewline();
2791
2792 } else if (type==9) {
2793 sprintf(line, "plfp element# %d", n_element+1);
2794 PrintFunc(line);
2795 ForceNewline();
2796 PrintHideLegend(line, type);
2797 sprintf(line, "%d polygons", gistD.n);
2798 PrintFunc(line);
2799 ForceNewline();
2800 }
2801
2802 } else {
2803 /* return properties array */
2804 Dimension *dims= NewDimension(6L, 1L, (Dimension *)0);
2805 Array *array= PushDataBlock(NewArray(&pointerStruct, dims));
2806 void **p= array->value.p;
2807 char **legend;
2808 int *ival;
2809 double *dval;
2810 long *lval;
2811 dims->references--;
2812
2813 dims= NewDimension(2L, 1L, (Dimension *)0);
2814 p[0]= (NewArray(&intStruct, dims))->value.c;
2815 dims->references--;
2816 p[1]= (NewArray(&stringStruct, (Dimension *)0))->value.c;
2817 p[2]= MakePropArray(&intStruct, prop3sizes[type]);
2818 p[3]= MakePropArray(&doubleStruct, prop4sizes[type]);
2819 p[4]= MakePropArray(&longStruct, prop5sizes[type]);
2820
2821 ival= (int *)p[0];
2822 ival[0]= type;
2823 ival[1]= type? gistD.hidden : 0;
2824
2825 if (type) {
2826 legend= (char **)p[1];
2827 legend[0]= p_strcpy(gistD.legend);
2828 if ((type==1 || type==7) && legend[0] && legend[0][0]=='\001') {
2829 if (gistA.m.type>=' ' && gistA.m.type<'\177')
2830 legend[0][0]= (char)gistA.m.type;
2831 else if (gistA.m.type>=1 && gistA.m.type<=5)
2832 legend[0][0]= specialMarkers[gistA.m.type-1];
2833 else
2834 legend[0][0]= '?';
2835 }
2836 }
2837
2838 ival= (int *)p[2];
2839 dval= (double *)p[3];
2840 lval= (long *)p[4];
2841 if (type==1) { /* plg */
2842 ival[0]= gistA.l.color;
2843 ival[1]= gistA.l.type;
2844 ival[2]= gistA.dl.marks;
2845 ival[3]= gistA.m.color;
2846 ival[4]= gistA.m.type;
2847 ival[5]= gistA.dl.rays;
2848 ival[6]= gistA.dl.closed;
2849 ival[7]= gistA.dl.smooth;
2850 dval[0]= gistA.l.width;
2851 dval[1]= gistA.m.size;
2852 dval[2]= gistA.dl.mSpace;
2853 dval[3]= gistA.dl.mPhase;
2854 dval[4]= gistA.dl.rSpace;
2855 dval[5]= gistA.dl.rPhase;
2856 dval[6]= gistA.dl.arrowL;
2857 dval[7]= gistA.dl.arrowW;
2858 lval[0]= gistD.n;
2859 lval[1]= ((char *)gistD.x)-((char *)0);
2860 lval[2]= ((char *)gistD.y)-((char *)0);
2861 } else if (type==2) { /* pldj */
2862 ival[0]= gistA.l.color;
2863 ival[1]= gistA.l.type;
2864 dval[0]= gistA.l.width;
2865 lval[0]= gistD.n;
2866 lval[1]= ((char *)gistD.x)-((char *)0);
2867 lval[2]= ((char *)gistD.y)-((char *)0);
2868 lval[3]= ((char *)gistD.xq)-((char *)0);
2869 lval[4]= ((char *)gistD.yq)-((char *)0);
2870 } else if (type==3) { /* plt */
2871 ival[0]= gistA.t.color;
2872 ival[1]= gistA.t.font;
2873 ival[2]= gistA.t.orient;
2874 ival[3]= (gistA.t.alignH | (gistA.t.alignV<<2));
2875 ival[4]= gistA.t.opaque;
2876 dval[0]= gistA.t.height/ONE_POINT;
2877 dval[1]= gistD.x0;
2878 dval[2]= gistD.y0;
2879 lval[0]= Safe_strlen(gistD.text);
2880 lval[1]= ((char *)gistD.text)-((char *)0);
2881 } else if (type==4) { /* plm */
2882 ival[0]= gistA.l.color;
2883 ival[1]= gistA.l.type;
2884 ival[2]= gistD.region;
2885 ival[3]= gistD.boundary;
2886 ival[4]= gistD.inhibit;
2887 dval[0]= gistA.l.width;
2888 lval[0]= gistD.mesh.iMax;
2889 lval[1]= gistD.mesh.jMax;
2890 lval[2]= ((char *)gistD.mesh.x)-((char *)0);
2891 lval[3]= ((char *)gistD.mesh.y)-((char *)0);
2892 lval[4]= ((char *)gistD.mesh.reg)-((char *)0);
2893 } else if (type==5) { /* plf */
2894 ival[0]= gistD.region;
2895 ival[1]= gistA.e.type!=L_NONE;
2896 ival[2]= gistA.e.color;
2897 ival[3]= gistA.rgb;
2898 dval[0]= gistA.e.width;
2899 lval[0]= gistD.mesh.iMax;
2900 lval[1]= gistD.mesh.jMax;
2901 lval[2]= ((char *)gistD.mesh.x)-((char *)0);
2902 lval[3]= ((char *)gistD.mesh.y)-((char *)0);
2903 lval[4]= ((char *)gistD.mesh.reg)-((char *)0);
2904 lval[5]= ((char *)gistD.colors)-((char *)0);
2905 } else if (type==6) { /* plv */
2906 ival[0]= gistD.region;
2907 ival[1]= gistA.l.color;
2908 ival[2]= gistA.vect.hollow;
2909 dval[0]= gistA.l.width;
2910 dval[1]= gistA.vect.aspect;
2911 dval[2]= gistD.scale;
2912 lval[0]= gistD.mesh.iMax;
2913 lval[1]= gistD.mesh.jMax;
2914 lval[2]= ((char *)gistD.mesh.x)-((char *)0);
2915 lval[3]= ((char *)gistD.mesh.y)-((char *)0);
2916 lval[4]= ((char *)gistD.mesh.reg)-((char *)0);
2917 lval[5]= ((char *)gistD.u)-((char *)0);
2918 lval[6]= ((char *)gistD.v)-((char *)0);
2919 } else if (type==7) { /* plc */
2920 ival[0]= gistD.region;
2921 ival[1]= gistA.l.color;
2922 ival[2]= gistA.l.type;
2923 ival[3]= gistA.dl.marks;
2924 ival[4]= gistA.m.color;
2925 ival[5]= gistA.m.type;
2926 ival[6]= gistA.dl.smooth;
2927 dval[0]= gistA.l.width;
2928 dval[1]= gistA.m.size;
2929 dval[2]= gistA.dl.mSpace;
2930 dval[3]= gistA.dl.mPhase;
2931 lval[0]= gistD.mesh.iMax;
2932 lval[1]= gistD.mesh.jMax;
2933 lval[2]= ((char *)gistD.mesh.x)-((char *)0);
2934 lval[3]= ((char *)gistD.mesh.y)-((char *)0);
2935 lval[4]= ((char *)gistD.mesh.reg)-((char *)0);
2936 lval[5]= ((char *)gistD.z)-((char *)0);
2937 lval[6]= ((char *)gistD.mesh.triangle)-((char *)0);
2938 lval[7]= gistD.nLevels;
2939 lval[8]= ((char *)gistD.levels)-((char *)0);
2940 } else if (type==8) { /* pli */
2941 ival[0]= gistA.rgb;
2942 dval[0]= gistD.px;
2943 dval[1]= gistD.py;
2944 dval[2]= gistD.qx;
2945 dval[3]= gistD.qy;
2946 lval[0]= gistD.width;
2947 lval[1]= gistD.height;
2948 lval[2]= ((char *)gistD.colors)-((char *)0);
2949 } else if (type==9) { /* plfp */
2950 ival[0]= gistA.e.type;
2951 ival[1]= gistA.e.color;
2952 ival[2]= gistA.rgb;
2953 dval[0]= gistA.e.width;
2954 lval[0]= gistD.n;
2955 lval[1]= ((char *)gistD.x)-((char *)0);
2956 lval[2]= ((char *)gistD.y)-((char *)0);
2957 lval[3]= ((char *)gistD.colors)-((char *)0);
2958 lval[4]= ((char *)gistD.pn)-((char *)0);
2959 }
2960 }
2961
2962 } else if (n_contour>=0) {
2963 YError("contour number cannot be specified without element number");
2964
2965 } else {
2966 char line[16];
2967 int i, offset;
2968 /* print list of legends... */
2969 if (CalledAsSubroutine()) {
2970 /* ...to terminal */
2971 PrintInit(YputsOut);
2972 } else {
2973 /* ...to result string array */
2974 PrintInit(&PutsAsArray);
2975 PushDataBlock(NewArray(&stringStruct, (Dimension *)0));
2976 }
2977
2978 curElement= -1;
2979 for (i=0 ; (type= GdSetElement(i))!=E_NONE ; i++) {
2980 sprintf(line, "%s%2d: ", gistD.hidden?"(H)":"", i+1);
2981 PrintFunc(line);
2982 offset= 0;
2983 if ((type==E_LINES || type==E_CONTOURS) && gistD.legend &&
2984 gistD.legend[0]=='\001') {
2985 char marker[2];
2986 marker[1]= '\0';
2987 if (gistA.m.type>=' ' && gistA.m.type<'\177')
2988 marker[0]= (char)gistA.m.type;
2989 else if (gistA.m.type>=1 && gistA.m.type<=5)
2990 marker[0]= specialMarkers[gistA.m.type-1];
2991 else
2992 marker[0]= '?';
2993 PrintFunc(marker);
2994 offset= 1;
2995 }
2996 if (gistD.legend) PrintFunc(gistD.legend+offset);
2997 ForceNewline();
2998 }
2999 }
3000 }
3001
PrintHideLegend(char * line,int type)3002 static void PrintHideLegend(char *line, int type)
3003 {
3004 int offset= 0;
3005 char marker[5];
3006 marker[0]= '\0';
3007 sprintf(line, "hide= %d,", gistD.hidden);
3008 PrintFunc(line);
3009 ForceNewline();
3010 if ((type==1 || type==7) && gistD.legend && gistD.legend[0]=='\001') {
3011 marker[0]= '\\';
3012 marker[1]= marker[2]= '0';
3013 marker[3]= '1';
3014 marker[4]= '\0';
3015 offset= 1;
3016 }
3017 sprintf(line, "legend= \"%s%.104s\",", marker,
3018 gistD.legend? gistD.legend+offset : "");
3019 PrintFunc(line);
3020 ForceNewline();
3021 }
3022
PrintColor(char * line,int color,int suffix)3023 static void PrintColor(char *line, int color, int suffix)
3024 {
3025 if (color>=0) {
3026 sprintf(line, "color= %d,", color);
3027 PrintFunc(line);
3028 } else if (color==P_FG) PrintFunc("color= \"fg\"");
3029 else if (color==P_BG) PrintFunc("color= \"bg\"");
3030 else if (color==P_RED) PrintFunc("color= \"red\"");
3031 else if (color==P_GREEN) PrintFunc("color= \"green\"");
3032 else if (color==P_BLUE) PrintFunc("color= \"blue\"");
3033 else if (color==P_CYAN) PrintFunc("color= \"cyan\"");
3034 else if (color==P_MAGENTA) PrintFunc("color= \"magenta\"");
3035 else if (color==P_YELLOW) PrintFunc("color= \"yellow\"");
3036 else if (color==P_GRAYD) PrintFunc("color= \"grayd\"");
3037 else if (color==P_GRAYC) PrintFunc("color= \"grayc\"");
3038 else if (color==P_GRAYB) PrintFunc("color= \"grayb\"");
3039 else if (color==P_GRAYA) PrintFunc("color= \"graya\"");
3040 else PrintFunc("color= <unknown>");
3041 PrintSuffix(suffix);
3042 }
3043
PrintTypeWidth(char * line,int suffix)3044 static void PrintTypeWidth(char *line, int suffix)
3045 {
3046 if (gistA.l.type==L_NONE) PrintFunc("type= \"none\"");
3047 else if (gistA.l.type==L_SOLID) PrintFunc("type= \"solid\"");
3048 else if (gistA.l.type==L_DASH) PrintFunc("type= \"dash\"");
3049 else if (gistA.l.type==L_DOT) PrintFunc("type= \"dot\"");
3050 else if (gistA.l.type==L_DASHDOT) PrintFunc("type= \"dashdot\"");
3051 else if (gistA.l.type==L_DASHDOTDOT) PrintFunc("type= \"dashdotdot\"");
3052 else PrintFunc("type= <unknown>");
3053 sprintf(line, ", width= %.2f", Safe_dbl(gistA.l.width));
3054 PrintFunc(line);
3055 PrintSuffix(suffix);
3056 }
3057
PrintMarks(char * line,int suffix)3058 static void PrintMarks(char *line, int suffix)
3059 {
3060 sprintf(line, "marks= %d, mcolor= 0x%02lx, ",
3061 gistA.dl.marks, gistA.m.color);
3062 PrintFunc(line);
3063 if (gistA.m.type<=' ' || gistA.m.type>=0xff)
3064 sprintf(line, "marker= '\\%o',", gistA.m.type);
3065 else
3066 sprintf(line, "marker= '%c',", gistA.m.type);
3067 PrintFunc(line);
3068 ForceNewline();
3069 sprintf(line,
3070 " msize= %.2f, mspace= %.5f, mphase= %.5f",
3071 Safe_dbl(gistA.m.size),
3072 Safe_dbl(gistA.dl.mSpace), Safe_dbl(gistA.dl.mPhase));
3073 PrintFunc(line);
3074 PrintSuffix(suffix);
3075 }
3076
PrintRegion(char * line,int suffix)3077 static void PrintRegion(char *line, int suffix)
3078 {
3079 sprintf(line, "region= %d", gistD.region);
3080 PrintFunc(line);
3081 PrintSuffix(suffix);
3082 }
3083
PrintSuffix(int suffix)3084 static void PrintSuffix(int suffix)
3085 {
3086 if (suffix==1) PrintFunc(", ");
3087 else if (suffix==3) PrintFunc(",");
3088 if (suffix&2) ForceNewline();
3089 }
3090
Safe_dbl(double x)3091 static double Safe_dbl(double x)
3092 {
3093 if (x>1000.0) return 1000.0;
3094 else if (x<-1000.0) return -1000.0;
3095 else return x;
3096 }
3097
MakePropArray(StructDef * base,long size)3098 static void *MakePropArray(StructDef *base, long size)
3099 {
3100 Array *array;
3101 if (!size) return 0;
3102 array= NewArray(base, NewDimension(size, 1L, (Dimension *)0));
3103 array->type.dims->references--;
3104 return array->value.c;
3105 }
3106
3107 /*--------------------------------------------------------------------------*/
3108
3109 #undef N_KEYWORDS
3110 #define N_KEYWORDS 36
3111 static char *editKeys[N_KEYWORDS+1]= {
3112 "legend", "hide",
3113 "color", "type", "width",
3114 "marks", "mcolor", "marker", "msize", "mspace", "mphase",
3115 "rays", "arrowl", "arroww", "rspace", "rphase", "closed", "smooth",
3116 "font", "height", "orient", "justify", "opaque",
3117 "hollow", "aspect", "region", "boundary", "levs", "scale", "scalem",
3118 "dx", "dy", "edges", "ecolor", "ewidth", "inhibit", 0 };
3119
Y_pledit(int nArgs)3120 void Y_pledit(int nArgs)
3121 {
3122 int type= 0, n_element= 0, n_contour= 0;
3123 int changes= 0, resetLevs= 0;
3124 Symbol *keySymbols[N_KEYWORDS];
3125 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, editKeys, keySymbols);
3126 int iPass= 0;
3127 char *legend= 0;
3128
3129 while (stack<=sp) {
3130 if (!stack->ops) { stack+= 2; continue; }
3131
3132 if (iPass==0) {
3133 if (YNotNil(stack)) n_element= (int)YGetInteger(stack);
3134 } else if (iPass==1) {
3135 if (YNotNil(stack)) n_contour= (int)YGetInteger(stack);
3136 } else {
3137 YError("pledit takes at most two non-keyword arguments");
3138 }
3139
3140 iPass++;
3141 stack++;
3142 }
3143
3144 /* Yorick uses 1-origin element numbering, Gist uses 0-origin */
3145 n_element--;
3146 n_contour--;
3147 if (n_element<0) {
3148 if (curElement>=0) {
3149 n_element= GdFindIndex(curElement);
3150 if (n_element<0) {
3151 curElement= -1;
3152 YError("lost current graphical element for pledit (BUG?)");
3153 }
3154 } else if (curElement==-6666) {
3155 n_element= curIX;
3156 n_contour= curIXc;
3157 } else {
3158 YError("no current graphical element for pledit");
3159 }
3160 }
3161 if (n_element>=0 || n_contour>=0) {
3162 /* retrieve specified element */
3163 if (n_element>=0) type= GdSetElement(n_element);
3164 if (n_contour>=0) {
3165 if (type!=E_CONTOURS)
3166 YError("current graphical element is not contours in pledit");
3167 type= GdSetContour(n_contour);
3168 }
3169 curElement= -6666; /* differs from -1 to allow pledit after plq */
3170 curIX= n_element; /* need these, too */
3171 curIXc= n_contour;
3172 if (type==E_LINES) type= 1;
3173 else if (type==E_DISJOINT) type= 2;
3174 else if (type==E_TEXT) type= 3;
3175 else if (type==E_MESH) type= 4;
3176 else if (type==E_FILLED) type= 5;
3177 else if (type==E_VECTORS) type= 6;
3178 else if (type==E_CONTOURS) type= 7;
3179 else if (type==E_CELLS) type= 8;
3180 else type= 0;
3181 if (type==0) YError("no such graphical element for pledit");
3182 }
3183
3184 /* legend and hide */
3185 if (keySymbols[0] && YNotNil(keySymbols[0]))
3186 legend= YGetString(keySymbols[0]);
3187 if (YNotNil(keySymbols[1])) gistD.hidden= (YGetInteger(keySymbols[1])!=0);
3188
3189 /* GdLines properties */
3190 if (YNotNil(keySymbols[2]))
3191 gistA.l.color= gistA.m.color= gistA.f.color=
3192 gistA.t.color= YgetColor(keySymbols[2]);
3193 if (YNotNil(keySymbols[3]))
3194 gistA.l.type= GetLineType(keySymbols[3]);
3195 if (YNotNil(keySymbols[4]))
3196 gistA.l.width= YGetReal(keySymbols[4]);
3197 if (YNotNil(keySymbols[5]))
3198 gistA.dl.marks= (YGetInteger(keySymbols[5])!=0);
3199 if (YNotNil(keySymbols[6]))
3200 gistA.m.color= YgetColor(keySymbols[6]);
3201 if (YNotNil(keySymbols[7]))
3202 gistA.m.type= (int)YGetInteger(keySymbols[7]);
3203 if (YNotNil(keySymbols[8]))
3204 gistA.m.size= YGetReal(keySymbols[8]);
3205 if (YNotNil(keySymbols[9]))
3206 gistA.dl.mSpace= YGetReal(keySymbols[9]);
3207 if (YNotNil(keySymbols[10]))
3208 gistA.dl.mPhase= YGetReal(keySymbols[10]);
3209 if (YNotNil(keySymbols[11]))
3210 gistA.dl.rays= (YGetInteger(keySymbols[11])!=0);
3211 if (YNotNil(keySymbols[12]))
3212 gistA.dl.arrowL= YGetReal(keySymbols[12]);
3213 if (YNotNil(keySymbols[13]))
3214 gistA.dl.arrowW= YGetReal(keySymbols[13]);
3215 if (YNotNil(keySymbols[14]))
3216 gistA.dl.rSpace= YGetReal(keySymbols[14]);
3217 if (YNotNil(keySymbols[15]))
3218 gistA.dl.rPhase= YGetReal(keySymbols[15]);
3219 if (YNotNil(keySymbols[16]))
3220 gistA.dl.closed= (YGetInteger(keySymbols[16])!=0);
3221 if (YNotNil(keySymbols[17]))
3222 gistA.dl.smooth= (YGetInteger(keySymbols[17])!=0);
3223
3224 /* GdText properties */
3225 if (YNotNil(keySymbols[18]))
3226 gistA.t.font= GetFont(keySymbols[18]);
3227 if (YNotNil(keySymbols[19]))
3228 gistA.t.height= YGetReal(keySymbols[19])*ONE_POINT;
3229 if (YNotNil(keySymbols[20]))
3230 gistA.t.orient= YGetInteger(keySymbols[20]);
3231 if (YNotNil(keySymbols[21]))
3232 GetJustify(keySymbols[21]);
3233 if (YNotNil(keySymbols[22]))
3234 gistA.t.opaque= (YGetInteger(keySymbols[22])!=0);
3235
3236 if (!gistA.t.orient) {
3237 gistA.t.orient= TX_RIGHT;
3238 } else {
3239 if (gistA.t.orient==1) gistA.t.orient= TX_UP;
3240 else if (gistA.t.orient==2) gistA.t.orient= TX_LEFT;
3241 else if (gistA.t.orient==3) gistA.t.orient= TX_DOWN;
3242 else {
3243 gistA.t.orient= TX_RIGHT;
3244 YError("orient= keyword must be 0, 1, 2, or 3");
3245 }
3246 }
3247
3248 /* GdVectors properties */
3249 if (YNotNil(keySymbols[23]))
3250 gistA.vect.hollow= (YGetInteger(keySymbols[23])!=0);
3251 if (YNotNil(keySymbols[24]))
3252 gistA.vect.aspect= YGetReal(keySymbols[24]);
3253
3254 if (YNotNil(keySymbols[25])) { /* region */
3255 if (type<4 || type>7)
3256 YError("region= in pledit allowed only for plm, plf, plv, plc");
3257 gistD.region= (int)YGetInteger(keySymbols[25]);
3258 }
3259
3260 if (YNotNil(keySymbols[26])) { /* boundary */
3261 if (type!=4) YError("boundary= in pledit allowed only for plm");
3262 gistD.boundary= (YGetInteger(keySymbols[26])!=0);
3263 }
3264
3265 if (YNotNil(keySymbols[27])) { /* levs */
3266 double *levels;
3267 long nLevels= 0;
3268 if (type!=7) YError("levs= in pledit allowed only for plc");
3269 levels= Get1Ddouble(keySymbols[27], &nLevels);
3270 if (!levels)
3271 YError("pledit cannot recompute default contour levels");
3272 levels= CopyLevels(levels, nLevels);
3273 /* WARNING --
3274 this is a critical code section, since until GdEdit successfully
3275 completes, Gist owns a pointer to the freed levels -- no way to
3276 gracefully avoid this without "knowing" more about guts of Gist's
3277 data structures than seem reasonable here... */
3278 p_free(gistD.levels);
3279 gistD.levels= levels;
3280 gistD.nLevels= nLevels;
3281 changes|= CHANGE_Z;
3282 resetLevs= 1;
3283 }
3284
3285 if (YNotNil(keySymbols[28])) { /* scale */
3286 if (type!=6) YError("scale= in pledit allowed only for plv");
3287 gistD.scale= YGetReal(keySymbols[28]);
3288 }
3289
3290 if (YNotNil(keySymbols[29])) { /* scalem */
3291 if (type!=6) YError("scalem= in pledit allowed only for plv");
3292 gistD.scale*= YGetReal(keySymbols[29]);
3293 }
3294
3295 if (YNotNil(keySymbols[30])) { /* dx */
3296 if (type!=3) YError("dx= in pledit allowed only for plt");
3297 gistD.x0+= YGetReal(keySymbols[30]);
3298 }
3299
3300 if (YNotNil(keySymbols[31])) { /* dy */
3301 if (type!=3) YError("dy= in pledit allowed only for plt");
3302 gistD.y0+= YGetReal(keySymbols[31]);
3303 }
3304
3305 if (YNotNil(keySymbols[32]))
3306 gistA.e.type= YGetInteger(keySymbols[32])? L_SOLID : L_NONE;
3307 if (YNotNil(keySymbols[33]))
3308 gistA.e.color= YgetColor(keySymbols[33]);
3309 if (YNotNil(keySymbols[34]))
3310 gistA.e.width= YGetReal(keySymbols[34]);
3311
3312 if (YNotNil(keySymbols[35])) { /* inhibit */
3313 if (type!=4) YError("inhibit= in pledit allowed only for plm");
3314 gistD.inhibit= (int)YGetInteger(keySymbols[35]);
3315 }
3316
3317 if (legend) {
3318 /* Some giggery-pokery necessary to get the old legend deleted properly,
3319 and the new legend allocated properly, so that Gist will delete it
3320 correctly when the graphical element is deleted. */
3321 char *oldleg= gistD.legend;
3322 gistD.legend= p_malloc(strlen(legend)+1);
3323 strcpy(gistD.legend, legend);
3324 legend= oldleg;
3325 }
3326 GdEdit(changes);
3327 if (legend) p_free(legend);
3328 if (resetLevs) tmpLevels= 0;
3329 Drop(nArgs);
3330 }
3331
3332 #undef N_KEYWORDS
3333 #define N_KEYWORDS 29
3334 static char *dfltKeys[N_KEYWORDS+1]= {
3335 "color", "type", "width",
3336 "marks", "mcolor", "marker", "msize", "mspace", "mphase",
3337 "rays", "arrowl", "arroww", "rspace", "rphase",
3338 "font", "height", "orient", "justify", "opaque",
3339 "hollow", "aspect", "dpi", "style", "legends", "palette", "maxcolors",
3340 "edges", "ecolor", "ewidth", 0 };
3341
Y_pldefault(int nArgs)3342 void Y_pldefault(int nArgs)
3343 {
3344 Symbol *keySymbols[N_KEYWORDS];
3345 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, dfltKeys, keySymbols);
3346
3347 if (stack<=sp) YError("pldefault takes no non-keyword arguments");
3348
3349 /* retrieve all default settings */
3350 GhGetLines();
3351 GhGetMesh();
3352 GhGetVectors();
3353 GhGetText();
3354
3355 if (YNotNil(keySymbols[0]))
3356 gistA.l.color= gistA.m.color= gistA.f.color=
3357 gistA.t.color= gistA.e.color= YgetColor(keySymbols[0]);
3358 if (YNotNil(keySymbols[1]))
3359 gistA.l.type= GetLineType(keySymbols[1]);
3360 if (YNotNil(keySymbols[2]))
3361 gistA.l.width= YGetReal(keySymbols[2]);
3362 if (YNotNil(keySymbols[3]))
3363 gistA.dl.marks= (YGetInteger(keySymbols[3])!=0);
3364 if (YNotNil(keySymbols[4]))
3365 gistA.m.color= YgetColor(keySymbols[4]);
3366 if (YNotNil(keySymbols[5]))
3367 gistA.m.type= (int)YGetInteger(keySymbols[5]);
3368 if (YNotNil(keySymbols[6]))
3369 gistA.m.size= YGetReal(keySymbols[6]);
3370 if (YNotNil(keySymbols[7]))
3371 gistA.dl.mSpace= YGetReal(keySymbols[7]);
3372 if (YNotNil(keySymbols[8]))
3373 gistA.dl.mPhase= YGetReal(keySymbols[8]);
3374 if (YNotNil(keySymbols[9]))
3375 gistA.dl.rays= (YGetInteger(keySymbols[9])!=0);
3376 if (YNotNil(keySymbols[10]))
3377 gistA.dl.arrowL= YGetReal(keySymbols[10]);
3378 if (YNotNil(keySymbols[11]))
3379 gistA.dl.arrowW= YGetReal(keySymbols[11]);
3380 if (YNotNil(keySymbols[12]))
3381 gistA.dl.rSpace= YGetReal(keySymbols[12]);
3382 if (YNotNil(keySymbols[13]))
3383 gistA.dl.rPhase= YGetReal(keySymbols[13]);
3384 if (YNotNil(keySymbols[14]))
3385 gistA.t.font= GetFont(keySymbols[14]);
3386 if (YNotNil(keySymbols[15]))
3387 gistA.t.height= YGetReal(keySymbols[15])*ONE_POINT;
3388 if (YNotNil(keySymbols[16]))
3389 gistA.t.orient= YGetInteger(keySymbols[16]);
3390 if (YNotNil(keySymbols[17]))
3391 GetJustify(keySymbols[17]);
3392 if (YNotNil(keySymbols[18]))
3393 gistA.t.opaque= (YGetInteger(keySymbols[18])!=0);
3394 if (YNotNil(keySymbols[19]))
3395 gistA.vect.hollow= (YGetInteger(keySymbols[19])!=0);
3396 if (YNotNil(keySymbols[20]))
3397 gistA.vect.aspect= YGetReal(keySymbols[20]);
3398
3399 if (!gistA.t.orient) {
3400 gistA.t.orient= TX_RIGHT;
3401 } else {
3402 if (gistA.t.orient==1) gistA.t.orient= TX_UP;
3403 else if (gistA.t.orient==2) gistA.t.orient= TX_LEFT;
3404 else if (gistA.t.orient==3) gistA.t.orient= TX_DOWN;
3405 else {
3406 gistA.t.orient= TX_RIGHT;
3407 YError("orient= keyword must be 0, 1, 2, or 3");
3408 }
3409 }
3410
3411 if (YNotNil(keySymbols[21])) {
3412 int dpi= YGetInteger(keySymbols[21]);
3413 /*if (dpi!=75 && dpi!=100)
3414 YError("dpi=75 or dpi=100 are only legal values");*/
3415 if (dpi<25) dpi = 25;
3416 else if (dpi>2400) dpi = 2400;
3417 defaultDPI= dpi;
3418 }
3419 if (YNotNil(keySymbols[22])) {
3420 char *style= defaultStyle;
3421 defaultStyle= 0;
3422 p_free(style);
3423 style= YGetString(keySymbols[22]);
3424 if (style && style[0]) defaultStyle= p_strcpy(style);
3425 }
3426 if (YNotNil(keySymbols[23]))
3427 /* legends= keyword -- turn on/off legend dumping to hcp file */
3428 defaultLegends= (YGetInteger(keySymbols[23])!=0);
3429 if (keySymbols[24]) {
3430 char *name= defaultPalette;
3431 defaultPalette= 0;
3432 p_free(name);
3433 if (YNotNil(keySymbols[24]))
3434 defaultPalette= p_strcpy(YGetString(keySymbols[24]));
3435 }
3436 if (YNotNil(keySymbols[25]))
3437 maxColors= YGetInteger(keySymbols[25]);
3438
3439 if (YNotNil(keySymbols[26]))
3440 gistA.e.type= YGetInteger(keySymbols[26])? L_SOLID : L_NONE;
3441 if (YNotNil(keySymbols[27]))
3442 gistA.e.color= YgetColor(keySymbols[27]);
3443 if (YNotNil(keySymbols[28]))
3444 gistA.e.width= YGetReal(keySymbols[28]);
3445
3446 /* store all default settings */
3447 GhSetLines();
3448 GhSetMesh();
3449 GhSetVectors();
3450 GhSetText();
3451 GhSetFill();
3452 }
3453
3454 #undef N_KEYWORDS
3455 #define N_KEYWORDS 6
3456 static char *gridKeys[N_KEYWORDS+1]= {
3457 "color", "type", "width", "base60", "degrees", "hhmm", 0 };
3458
Y_gridxy(int nArgs)3459 void Y_gridxy(int nArgs)
3460 {
3461 Symbol *keySymbols[N_KEYWORDS];
3462 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, gridKeys, keySymbols);
3463 int xgrid= 0;
3464 int ygrid= 0;
3465 int iPass= 0;
3466 int ticks = 0;
3467
3468 while (stack<=sp) {
3469 if (!stack->ops) { stack+= 2; continue; }
3470
3471 if (iPass==0) {
3472 if (YNotNil(stack)) xgrid= (int)YGetInteger(stack);
3473 } else if (iPass==1) {
3474 if (YNotNil(stack)) ygrid= (int)YGetInteger(stack);
3475 } else {
3476 YError("gridxy takes at most two non-keyword arguments");
3477 }
3478
3479 iPass++;
3480 stack++;
3481 }
3482
3483 /* If a single argument is given, use it for both xgrid and ygrid */
3484 if (iPass==1) ygrid= xgrid;
3485
3486 CheckDefaultWindow();
3487
3488 if (YNotNil(keySymbols[0]))
3489 gistD.ticks.horiz.gridStyle.color=
3490 gistD.ticks.vert.gridStyle.color= YgetColor(keySymbols[0]);
3491 if (YNotNil(keySymbols[1]))
3492 gistD.ticks.horiz.gridStyle.type=
3493 gistD.ticks.vert.gridStyle.type= GetLineType(keySymbols[1]);
3494 if (YNotNil(keySymbols[2]))
3495 gistD.ticks.horiz.gridStyle.width=
3496 gistD.ticks.vert.gridStyle.width= YGetReal(keySymbols[2]);
3497 if (YNotNil(keySymbols[3]))
3498 ticks |= 1 | ((YGetInteger(keySymbols[3]) & 3) << 1);
3499 if (YNotNil(keySymbols[4]))
3500 ticks |= 1 | ((YGetInteger(keySymbols[4]) & 3) << 3);
3501 if (YNotNil(keySymbols[5]))
3502 ticks |= 1 | ((YGetInteger(keySymbols[5]) & 3) << 5);
3503 if (ticks&1) {
3504 if (ticks&0x2a) {
3505 if (ticks&0x2) GdAltTick(&Base60Ticks,0,0,0);
3506 else if (ticks&0x8) GdAltTick(&Base60Ticks,&DegreeLabels,0,0);
3507 else GdAltTick(&Base60Ticks,&HourLabels,0,0);
3508 gistD.ticks.horiz.flags |= ALT_TICK;
3509 if (ticks&0x2) gistD.ticks.horiz.flags &= ~ALT_LABEL;
3510 else gistD.ticks.horiz.flags |= ALT_LABEL;
3511 } else {
3512 gistD.ticks.horiz.flags &= ~(ALT_TICK|ALT_LABEL);
3513 }
3514 if (ticks&0x54) {
3515 if (ticks&0x4) GdAltTick(0,0,&Base60Ticks,0);
3516 else if (ticks&0x10) GdAltTick(0,0,&Base60Ticks,&DegreeLabels);
3517 else GdAltTick(0,0,&Base60Ticks,&HourLabels);
3518 gistD.ticks.vert.flags |= ALT_TICK;
3519 if (ticks&0x4) gistD.ticks.vert.flags &= ~ALT_LABEL;
3520 else gistD.ticks.vert.flags |= ALT_LABEL;
3521 } else {
3522 gistD.ticks.vert.flags &= ~(ALT_TICK|ALT_LABEL);
3523 }
3524 }
3525
3526 if (iPass>0) {
3527 gistD.ticks.horiz.flags&= ~(GRID_F|GRID_O);
3528 if (xgrid==1)
3529 gistD.ticks.horiz.flags|= GRID_F;
3530 else if (xgrid==2)
3531 gistD.ticks.horiz.flags|= GRID_O;
3532 if (xgrid&0x200) {
3533 gistD.ticks.horiz.flags= (xgrid&0x1ff);
3534 gistD.ticks.frame= (xgrid&0x400)!=0;
3535 }
3536
3537 gistD.ticks.vert.flags&= ~(GRID_F|GRID_O);
3538 if (ygrid&1)
3539 gistD.ticks.vert.flags|= GRID_F;
3540 else if (ygrid&2)
3541 gistD.ticks.vert.flags|= GRID_O;
3542 if (ygrid&0x200) {
3543 gistD.ticks.vert.flags= (ygrid&0x1ff);
3544 gistD.ticks.frame= (ygrid&0x400)!=0;
3545 }
3546 }
3547
3548 GdSetPort();
3549 }
3550
3551 /*--------------------------------------------------------------------------*/
3552
FreeReference(void * obj)3553 static void FreeReference(void *obj)
3554 {
3555 Array *array= obj? Pointee(obj) : 0;
3556 Unref(array);
3557 }
3558
3559 /* defined in task.c */
3560 extern void (*CleanUpForExit)(void);
3561
3562 static void (*OtherCleanUp)(void)= 0;
3563 static void CleanUpGraphics(void);
CleanUpGraphics(void)3564 static void CleanUpGraphics(void)
3565 {
3566 int n;
3567 if (hcpDefault) GpKillEngine(hcpDefault);
3568 for (n=GH_NDEVS-1 ; n>=0 ; n--) {
3569 if (ghDevices[n].display) GpKillEngine(ghDevices[n].display);
3570 if (ghDevices[n].hcp) GpKillEngine(ghDevices[n].hcp);
3571 }
3572 if (OtherCleanUp) OtherCleanUp();
3573 }
3574
3575 extern void yg_before_wait(void);
3576 void
yg_before_wait(void)3577 yg_before_wait(void)
3578 {
3579 GhBeforeWait();
3580 }
3581
3582 void
Y_set_gpath(int argc)3583 Y_set_gpath(int argc)
3584 {
3585 char *p = ((argc==1) && YNotNil(sp))? YGetString(sp) : 0;
3586 if (argc > 1) YError("set_gpath accepts only one argument");
3587 if (!CalledAsSubroutine()) {
3588 Array *a = PushDataBlock(NewArray(&stringStruct, (Dimension *)0));
3589 a->value.q[0] = p_strcpy(g_set_path((char*)0));
3590 }
3591 if (p) g_set_path(p);
3592 }
3593
Y__pl_init(int nArgs)3594 void Y__pl_init(int nArgs)
3595 {
3596 #ifndef NO_XLIB
3597 g_initializer(&ym_argc, ym_argv);
3598 #else
3599 extern char *g_argv0;
3600 g_argv0 = ym_argv? ym_argv[0] : 0;
3601 #endif
3602
3603 /* Install routine to kill graphics engines when Yorick quits. */
3604 OtherCleanUp= CleanUpForExit;
3605 CleanUpForExit= &CleanUpGraphics;
3606
3607 /* Additionally, set up so that Gist Drauing structures actually own
3608 a use of mesh-sized Yorick Arrays. This allows one or more
3609 Drauings to share these potentially large objects. */
3610 GdFree= &FreeReference;
3611
3612 /* Install Yorick's best guess at a GISTPATH. The GISTPATH
3613 environment variable, if present, will be used; otherwise the
3614 argument to this function, if non-nil, will be used; otherwise,
3615 the default compiled into libgist.a will be used. */
3616 if (!p_getenv("GISTPATH") && nArgs==1 && YNotNil(sp))
3617 gistPathDefault= p_strcpy(YGetString(sp));
3618 GhSetXHandler((void (*)(char *))&YError);
3619
3620 /* Set up parser to pass string equivalents of arguments to the
3621 plotting functions for use in the construction of default legends.
3622 NB-- The parser can only quine functions invoked as subroutines,
3623 so all quined functions must check CalledAsSubroutine(). */
3624 YpQuine("plg", 2);
3625 YpQuine("plm", 3);
3626 YpQuine("plc", 4);
3627 YpQuine("plv", 4);
3628 YpQuine("plf", 4);
3629 YpQuine("pli", 1);
3630 /* plt does not use legends */
3631 YpQuine("pldj", 4);
3632
3633 /* Default is to put occasional markers on curves. */
3634 GhGetLines();
3635 gistA.dl.marks= 1;
3636 GhSetLines();
3637
3638 /* Default text is 14 point Helvetica. */
3639 GhGetText();
3640 gistA.t.font= T_HELVETICA;
3641 gistA.t.height= 14.0*ONE_POINT;
3642 GhSetText();
3643 }
3644
Y_keybd_focus(int nArgs)3645 void Y_keybd_focus(int nArgs)
3646 {
3647 /* Set the input hint to false, meaning that Yorick graphics
3648 * windows do not ever want keyboard focus. This is not supposed
3649 * to affect mouse input events, which are wanted. */
3650 #ifndef NO_XLIB
3651 if (nArgs==1) gist_input_hint= YGetInteger(sp);
3652 #endif
3653 }
3654
3655 /*--------------------------------------------------------------------------*/
3656
3657 #undef N_KEYWORDS
3658 #define N_KEYWORDS 3
3659 static char *bsKeys[N_KEYWORDS+1]= { "top", "cmin", "cmax", 0 };
3660
Y_bytscl(int nArgs)3661 void Y_bytscl(int nArgs)
3662 {
3663 Symbol *keySymbols[N_KEYWORDS];
3664 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, bsKeys, keySymbols);
3665 double *z, zmin, zmax, scale, offset, zz;
3666 Operand op;
3667 Array *array;
3668 GpColor *zc;
3669 long i;
3670
3671 z= 0;
3672 while (stack<=sp) {
3673 if (!stack->ops) { stack+=2; continue; }
3674 if (z) { z= 0; break; }
3675 stack->ops->FormOperand(stack, &op);
3676 if (op.ops->promoteID>T_DOUBLE)
3677 YError("bytscl argument must be convertable to type double");
3678 op.ops->ToDouble(&op);
3679 z= op.value;
3680 stack++;
3681 }
3682 if (!z) YError("bytscl takes exactly one non-keyword argument");
3683
3684 GrabByteScale(keySymbols, &scale, &offset, &zmin, &zmax,
3685 z, (int *)0, 0, op.type.number+1, 2L, 1);
3686
3687 array= PushDataBlock(NewArray(&charStruct, op.type.dims));
3688 zc= (GpColor *)array->value.c;
3689
3690 for (i=0 ; i<op.type.number ; i++) {
3691 zz= z[i];
3692 if (zz<zmin) zz= zmin;
3693 else if (zz>zmax) zz= zmax;
3694 zc[i]= (int)((zz-offset)*scale);
3695 }
3696 }
3697
3698 /*--------------------------------------------------------------------------*/
3699
3700 #undef N_KEYWORDS
3701 #define N_KEYWORDS 2
3702 static char *cntrKeys[N_KEYWORDS+1]= { "triangle", "region", 0 };
3703
Y_contour(int nArgs)3704 void Y_contour(int nArgs)
3705 {
3706 Symbol *keySymbols[N_KEYWORDS];
3707 Symbol *stack= YGetKeywords(sp-nArgs+1, nArgs, cntrKeys, keySymbols);
3708 long iMax= 0, jMax= 0;
3709 double *z= 0;
3710 GaQuadMesh mesh;
3711 long xci= 0, yci= 0;
3712 Symbol *xs= 0 , *ys= 0;
3713 double *levs= 0;
3714 int two_levels= 0;
3715 Dimension *dims;
3716 Array *array;
3717 double *xcp, *ycp;
3718 long *np, nparts, ntotal;
3719 int region= 0;
3720 int iPass= 0;
3721
3722 while (stack<=sp && iPass<4) {
3723 if (!stack->ops) { stack+= 2; continue; }
3724
3725 if (iPass==0) {
3726 yci= YGet_Ref(stack);
3727 ys= stack;
3728 } else if (iPass==1) {
3729 xci= YGet_Ref(stack);
3730 xs= stack;
3731 } else if (iPass==2) {
3732 levs= YGet_D(stack, 0, &dims);
3733 if (dims && (dims->number>2 || dims->next))
3734 YError("contour levs must be either single value or value pair");
3735 if (dims && dims->number==2) two_levels= 1;
3736 } else if (iPass==3) {
3737 z= Get2Ddouble(stack, &jMax, &iMax);
3738 }
3739
3740 iPass++;
3741 stack++;
3742 }
3743 if (iPass<4) YError("contour needs at least six arguments");
3744 stack= GrabMesh(stack, keySymbols[0], &mesh,
3745 (char **)0, (char **)0, (char **)0, 1);
3746 while (stack<=sp) {
3747 if (!stack->ops) stack+= 2;
3748 else YError("contour takes at most seven non-keyword arguments");
3749 }
3750 if (mesh.iMax!=iMax || mesh.jMax!=jMax)
3751 YError("z array must have same dimensions as mesh in contour");
3752 if (YNotNil(keySymbols[1]))
3753 region= (int)YGetInteger(keySymbols[1]);
3754
3755 if (!mesh.triangle) {
3756 /* provide a temporary triangle array if none supplied */
3757 short *triangle;
3758 long ijMax= iMax*jMax;
3759 dims= tmpDims;
3760 tmpDims= 0;
3761 FreeDimension(dims);
3762 tmpDims= NewDimension(ijMax, 1L, (Dimension *)0);
3763 triangle= ((Array*)PushDataBlock(NewArray(&shortStruct,
3764 tmpDims)))->value.s;
3765 mesh.triangle= triangle;
3766 while (ijMax--) *(triangle++)= 0;
3767 CheckStack(1);
3768 }
3769
3770 /* initialize trace, counting ntotal and nparts */
3771 ntotal= two_levels? GcInit2(&mesh,region,z,levs,30L,&nparts) :
3772 GcInit1(&mesh,region,z,levs[0],&nparts);
3773
3774 if (!ntotal) {
3775 /* handle case of no points on contour */
3776 PushDataBlock(RefNC(&nilDB));
3777 YPut_Result(sp, yci);
3778 YPut_Result(sp, xci);
3779 return;
3780 }
3781
3782 /* stuff x and y arrays for results onto stack over output symbols */
3783 dims= tmpDims;
3784 tmpDims= 0;
3785 FreeDimension(dims);
3786 tmpDims= dims= NewDimension(ntotal, 1L, (Dimension *)0);
3787 array= NewArray(&doubleStruct, tmpDims);
3788 ys->value.db= (DataBlock *)array;
3789 ys->ops= &dataBlockSym;
3790 ycp= array->value.d;
3791 array= NewArray(&doubleStruct, tmpDims);
3792 xs->value.db= (DataBlock *)array;
3793 xs->ops= &dataBlockSym;
3794 xcp= array->value.d;
3795
3796 /* return list goes on top of stack */
3797 tmpDims= 0;
3798 FreeDimension(dims);
3799 tmpDims= NewDimension(nparts, 1L, (Dimension *)0);
3800 array= PushDataBlock(NewArray(&longStruct, tmpDims));
3801 np= array->value.l;
3802
3803 if (GcTrace(np, xcp, ycp)!=ntotal) YError("GcTrace failed in contour");
3804
3805 /* move results from stack back to output symbols */
3806 YPut_Result(ys, yci);
3807 YPut_Result(xs, xci);
3808 }
3809
Y_mesh_loc(int nArgs)3810 void Y_mesh_loc(int nArgs)
3811 {
3812 Symbol *stack= sp-nArgs+1;
3813 double *x0= 0, *y0= 0;
3814 Operand xop, yop;
3815 Array *result;
3816 long i, n, *zone;
3817 GaQuadMesh mesh;
3818 int iPass= 0;
3819 Dimension *dims;
3820 long ix0, j, ijx, *bndy, nbndy;
3821
3822 mesh.x= mesh.y= 0;
3823 mesh.reg= 0;
3824 mesh.iMax= mesh.jMax= 0;
3825 mesh.triangle= 0;
3826
3827 if (nArgs<2) YError("mesh_loc requires at least two arguments");
3828 while (stack<=sp) {
3829 if (!stack->ops) YError("mesh_loc takes no keyword arguments");
3830
3831 if (iPass==0) {
3832 Dimension *dims;
3833 y0= YGet_D(stack, 0, &dims);
3834 stack->ops->FormOperand(stack, &yop);
3835 } else if (iPass==1) {
3836 Dimension *dims;
3837 x0= YGet_D(stack, 0, &dims);
3838 stack->ops->FormOperand(stack, &xop);
3839 } else if (iPass==2) mesh.y= Get2Ddouble(stack, &mesh.jMax, &mesh.iMax);
3840 else if (iPass==3) mesh.x= Get2Ddouble(stack, &mesh.jMax, &mesh.iMax);
3841 else if (iPass==4) mesh.reg= Get2Dint(stack, &mesh.jMax, &mesh.iMax);
3842 else YError("mesh_loc takes at most five arguments");
3843
3844 iPass++;
3845 stack++;
3846 }
3847
3848 if ((mesh.x!=0)^(mesh.y!=0))
3849 YError("both y and x arrays must be specified for a mesh");
3850
3851 if (!mesh.x) {
3852 /* neither y nor x have been specified -- use defaults */
3853 if (!xMesh)
3854 YError("no default mesh exists to define y and x -- use plmesh");
3855 if (mesh.reg && (iMesh!=mesh.iMax || jMesh!=mesh.jMax))
3856 YError("ireg must have same dimensions as default mesh");
3857 mesh.iMax= iMesh;
3858 mesh.jMax= jMesh;
3859 mesh.x= xMesh;
3860 mesh.y= yMesh;
3861
3862 } else {
3863 /* both y and x have been specified -- copy them for Gist */
3864 if (mesh.iMax<2 || mesh.jMax<2)
3865 YError("a mesh must have dimensions of at least 2-by-2");
3866 }
3867
3868 if (!mesh.reg && mesh.x==xMesh) mesh.reg= regMesh;
3869
3870 if (BinaryConform(&xop, &yop)&4) YError("x0 and y0 not conformable");
3871 n= TotalNumber(tmpDims);
3872 if (n>1) {
3873 result= PushDataBlock(NewArray(&longStruct, tmpDims));
3874 zone= result->value.l;
3875 } else {
3876 PushLongValue(0);
3877 zone= &sp->value.l;
3878 }
3879
3880 /* get fastest varying dimension in (x0,y0) */
3881 dims= tmpDims;
3882 ix0= 1;
3883 while (dims && dims->next) {
3884 dims= dims->next;
3885 if (dims->number>1) ix0= dims->number;
3886 }
3887
3888 ijx= mesh.iMax*mesh.jMax;
3889 if (mesh.reg) {
3890 long i0= 0;
3891 for (j=mesh.iMax+1 ; j<ijx ; j++) {
3892 if ((++i0)==mesh.iMax) { i0= 1; j++; }
3893 if (mesh.reg[j]) break;
3894 }
3895 if (j>=ijx) j= -1;
3896 } else {
3897 j= mesh.iMax+1;
3898 }
3899 bndy= 0;
3900 nbndy= 0;
3901 for (i=0 ; i<n ; i++) {
3902 if (i && !(i%ix0)) j= zone[i-ix0]-1;
3903 j= QuickMeshZone(x0[i], y0[i], mesh.x, mesh.y, mesh.reg,
3904 mesh.iMax, ijx, j, bndy, nbndy);
3905 if (!bndy && j<0) {
3906 bndy= BuildMeshBndy(mesh.x, mesh.y, mesh.reg, mesh.iMax, ijx, &nbndy);
3907 j= QuickMeshZone(x0[i], y0[i], mesh.x, mesh.y, mesh.reg,
3908 mesh.iMax, ijx, j, bndy, nbndy);
3909 }
3910 zone[i]= j+1;
3911 }
3912 if (bndy) Drop(1);
3913 }
3914
3915 /*--------------------------------------------------------------------------*/
3916
3917 #ifndef NO_MOUSE
3918 static int MouseCallBack(Engine *engine, int system,
3919 int release, GpReal x, GpReal y,
3920 int butmod, GpReal xn, GpReal yn);
3921 static char *defaultPrompts[2]= {
3922 "<Click mouse at point>", "<Press, drag, and release mouse>" };
3923 static Array *mouse_array = 0;
3924 #endif
3925
Y_mouse(int nArgs)3926 void Y_mouse(int nArgs)
3927 {
3928 #ifdef DISPLAY_MOUSE
3929 Symbol *stack= sp-nArgs+1;
3930 char *prompt= 0;
3931 int system= -1, style= 0, iPass= 0;
3932 int n= GhGetPlotter();
3933
3934 if (n<0 || !ghDevices[n].display)
3935 YError("no current graphics window for mouse function");
3936
3937 while (stack<=sp) {
3938 if (!stack->ops) YError("mouse function takes no keyword arguments");
3939 if (iPass==0)
3940 system= YNotNil(stack)? YGetInteger(stack) : -1;
3941 else if (iPass==1)
3942 style= YNotNil(stack)? YGetInteger(stack) : 0;
3943 else if (iPass==2)
3944 prompt= YNotNil(stack)? YGetString(stack) : 0;
3945 else
3946 YError("mouse function takes at most three arguments");
3947 iPass++;
3948 stack++;
3949 }
3950
3951 /* GhWaitDisplay(); otherwise can lock up ?? */
3952 GhBeforeWait(); /* be sure display is current */
3953 if (!prompt) YPrompt(defaultPrompts[style!=0]);
3954 else if (prompt[0]) YPrompt(prompt);
3955 if (!prompt || prompt[0]) YPrompt("\n");
3956
3957 if (DISPLAY_MOUSE(ghDevices[n].display, style, system, &MouseCallBack)) {
3958 PushDataBlock(RefNC(&nilDB));
3959 } else {
3960 mouse_array=
3961 PushDataBlock(NewArray(&doubleStruct,
3962 NewDimension(11L, 1L, (Dimension *)0)));
3963 mouse_array->type.dims->references--;
3964 for (n=0 ; n<11 ; n++) mouse_array->value.d[n]= 0.0;
3965 if (yg_pc_resume) {
3966 yg_got_expose();
3967 YError("mouse while already waiting or suspended");
3968 } else {
3969 yg_blocking = 1;
3970 yg_pc_resume = ym_suspend();
3971 }
3972 }
3973 #else
3974 YError("no mouse function in this version of Yorick");
3975 #endif
3976 }
3977
3978 #ifndef NO_MOUSE
MouseCallBack(Engine * engine,int system,int release,GpReal x,GpReal y,int butmod,GpReal xn,GpReal yn)3979 static int MouseCallBack(Engine *engine, int system,
3980 int release, GpReal x, GpReal y,
3981 int butmod, GpReal xn, GpReal yn)
3982 {
3983 int n= GhGetPlotter();
3984 if (n<0 || ghDevices[n].display!=engine) {
3985 mouse_array = 0;
3986 yg_got_expose();
3987 return 1;
3988 } else if (!mouse_array || sp->ops!=&dataBlockSym ||
3989 mouse_array != (Array*)sp->value.db ||
3990 mouse_array->type.base != &doubleStruct ||
3991 mouse_array->type.number != 11) {
3992 mouse_array = 0;
3993 yg_got_expose();
3994 return 1;
3995 } else if (release == -1) {
3996 mouse_array = 0;
3997 yg_got_expose();
3998 return 1;
3999 }
4000 if (!release) {
4001 mouse_array->value.d[8]= (double)system;
4002 mouse_array->value.d[9]= (double)butmod;
4003 mouse_array->value.d[0]= x;
4004 mouse_array->value.d[1]= y;
4005 mouse_array->value.d[4]= xn;
4006 mouse_array->value.d[5]= yn;
4007 } else {
4008 mouse_array->value.d[10]= (double)butmod;
4009 mouse_array->value.d[2]= x;
4010 mouse_array->value.d[3]= y;
4011 mouse_array->value.d[6]= xn;
4012 mouse_array->value.d[7]= yn;
4013 mouse_array = 0;
4014 }
4015 return 0;
4016 }
4017 #endif
4018
4019 /*--------------------------------------------------------------------------*/
4020
YCurrentPlotter(void)4021 int YCurrentPlotter(void)
4022 {
4023 return GhGetPlotter();
4024 }
4025
4026 /*--------------------------------------------------------------------------*/
4027
Y_current_window(int nArgs)4028 void Y_current_window(int nArgs)
4029 {
4030 PushIntValue(GhGetPlotter());
4031 }
4032
4033 void
Y_pause(int nArgs)4034 Y_pause(int nArgs)
4035 {
4036 long timeout;
4037 if (nArgs!=1) YError("pause requires exactly one argument");
4038 timeout = YGetInteger(sp);
4039 if (timeout<0) timeout = 0;
4040 Drop(nArgs);
4041 sp->ops = &intScalar;
4042 sp->value.i = 0;
4043 if (yg_pc_resume) {
4044 yg_got_expose();
4045 YError("pause while already waiting or suspended");
4046 } else {
4047 p_set_alarm(0.001*timeout, yg_alarm, (sp-spBottom)+(char*)0);
4048 yg_blocking = 2;
4049 yg_pc_resume = ym_suspend();
4050 }
4051 }
4052
4053 /* ARGSUSED */
4054 static void
yg_alarm(void * context)4055 yg_alarm(void *context)
4056 {
4057 if (yg_blocking != 2) return;
4058 if (sp-spBottom==((char*)context-(char*)0) &&
4059 sp->ops==&intScalar && sp->value.i==0)
4060 sp->value.i = 1;
4061 yg_got_expose();
4062 }
4063
4064 void
Y_rgb_read(int nArgs)4065 Y_rgb_read(int nArgs)
4066 {
4067 int n = GhGetPlotter();
4068 long nx, ny;
4069 Array *result;
4070 Dimension *dims = tmpDims;
4071 if (nArgs>1) YError("rgb_read takes no more than one argument");
4072 if (nArgs==1 && YNotNil(sp)) n = YGetInteger(sp);
4073 if (n<0 || n>=GH_NDEVS || !ghDevices[n].display ||
4074 RGB_READER(ghDevices[n].display, (GpColor*)0, &nx, &ny))
4075 YError("rgb_read(n_window) with no such n_window");
4076 tmpDims = 0;
4077 FreeDimension(dims);
4078 tmpDims = NewDimension(3L, 1L, (Dimension *)0);
4079 tmpDims = NewDimension(nx, 1L, tmpDims);
4080 tmpDims = NewDimension(ny, 1L, tmpDims);
4081 result = PushDataBlock(NewArray(&charStruct, tmpDims));
4082 RGB_READER(ghDevices[n].display, (GpColor*)result->value.c, &nx, &ny);
4083 }
4084
4085 #ifdef NO_XLIB
4086 /* ARGSUSED */
4087 static int
my_rgb_read(Engine * eng,GpColor * rgb,long * nx,long * ny)4088 my_rgb_read(Engine *eng, GpColor *rgb, long *nx, long *ny)
4089 {
4090 YError("rgb_read impossible - no interactive graphics in this yorick");
4091 return 1;
4092 }
4093 #endif
4094
4095 /*--------------------------------------------------------------------------*/
4096
4097 void
Y_current_mouse(argc)4098 Y_current_mouse(argc)
4099 {
4100 #ifdef NO_XLIB
4101 PushDataBlock(RefNC(&nilDB));
4102 #else
4103 double x, y;
4104 int sys, win, target_win;
4105 Array *array;
4106 double *result;
4107
4108 if (argc != 1) {
4109 YError("current_mouse takes exactly one, possibly nil, argument");
4110 }
4111 win = GhGetMouse(&sys, &x, &y);
4112 if (YNotNil(sp)) {
4113 target_win = (int)YGetInteger(sp);
4114 } else {
4115 target_win = win;
4116 }
4117 if (win < 0 || win != target_win) {
4118 PushDataBlock(RefNC(&nilDB));
4119 } else {
4120 array = PushDataBlock(NewArray(&doubleStruct,
4121 NewDimension(4L, 1L, (Dimension *)0)));
4122 --array->type.dims->references;
4123 result = array->value.d;
4124 result[0] = x;
4125 result[1] = y;
4126 result[2] = sys;
4127 result[3] = win;
4128 }
4129 #endif
4130 }
4131
4132 /*--------------------------------------------------------------------------*/
4133