1 /*  Copyright (C) 1988-2005 by Brian Doty and the Institute
2                   of Global Environment and Society (IGES).
3 
4     See file COPYRIGHT for more information.   */
5 
6 /* Authored by B. Doty */
7 
8 /*  Low level graphics interface, providing scaling, line styles,
9     clipping, character drawing, metafile output, etc.         */
10 
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 
14 /* If autoconfed, only include malloc.h when it's presen */
15 #ifdef HAVE_MALLOC_H
16 #include <malloc.h>
17 #endif
18 
19 #else /* undef HAVE_CONFIG_H */
20 
21 #include <malloc.h>
22 
23 #endif /* HAVE_CONFIG_H */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <math.h>
28 #include "gx.h"
29 
30 #ifdef XLIBEMU
31 #include "pcx11e.h"
32 #endif
33 
34 
35 /* The following variables are local to this file, and are used by
36    all the routines in the file.    */
37 
38 static float  xsize, ysize;               /* Virtual size       */
39 static float rxsize, rysize;              /* Real size          */
40 static int lwflg;                         /* Reduce lw due vpage*/
41 static float clminx,clmaxx,clminy,clmaxy; /* Clipping region    */
42 static int cflag;                         /* Clipping flag      */
43 static int mflag;                         /* mask flag          */
44 static float dash[8];                     /* Linestyle pattern  */
45 static int dnum,lstyle;                   /* Current linestyle  */
46 static int color;                         /* Current color      */
47 static int lwide;                         /* Current linewidth  */
48 static float oldx,oldy;                   /* Previous position  */
49 
50 static int bufmod;                        /* Buffering mode     */
51 static float xsave,ysave,alen,slen;       /* Linestyle constants*/
52 static int jpen,dpnt;
53 
54 static int bcol;                          /* Background color   */
55 static int intflg;                        /* Batch flag */
56 
57 static int reds[100],grns[100],blus[100]; /* Save defined color info */
58 
59 static void (*fconv) (float, float, float *, float *);
60                                           /* fconv points to proj rnt  */
61 static void (*gconv) (float, float, float *, float *);
62                                           /* gconv points to grid rnt  */
63 static void (*bconv) (float, float, float *, float *);
64                                           /* gconv points to grid rnt  */
65 static char *mask;     /* pointer to mask array */
66 static int maskflg;  /* mask flag; -999 no mask yet,
67                  0 no mask used, 1 mask values set, -888 error  */
68 static int masksize;   /* Size of mask array */
69 static int maskx;      /* Size of a row in the array */
70 
71 
72 /* Initialize graphics output  */
73 /* batch flag = 1, batch mode only (no graphics output) */
74 
gxstrt(float xmx,float ymx,int batch,int hbufsz)75 void gxstrt (float xmx, float ymx, int batch, int hbufsz) {
76 int iii,jjj;
77 
78   printf ("GX Package Initialization: Size = %g %g \n",xmx,ymx);
79   if (batch) printf ("Running in Batch mode\n");
80   intflg = !batch;
81   if (intflg) {
82     gxdbgn (xmx, ymx);
83     gxdcol (1);                          /* Initial device color    */
84     gxdwid (1);                          /* Initial line width      */
85   } else {
86     gxdbat ();
87   }
88   rxsize = xmx;  rysize = ymx;
89   clminx=0; clmaxx=xmx;                  /* Set clipping area       */
90   clminy=0; clmaxy=ymx;
91   xsave=0.0; ysave=0.0; lstyle=0; lwide = 1;
92   oldx=0.0; oldy=0.0;
93   fconv=NULL;                            /* No projection set up    */
94   gconv=NULL;                            /* No grid scaling set up  */
95   bconv=NULL;                            /* No back transform       */
96   gxscal (0.0,xmx,0.0,ymx,0.0,xmx,0.0,ymx); /* Linear scaling=inches*/
97   gxvpag (xmx,ymx,0.0,xmx,0.0,ymx);      /* Virtual page scaling */
98   gxchii();                              /* Init character plotting */
99   bufmod=0;
100   bcol = 0;                              /* Background is black     */
101   for (iii=0; iii<100; iii++) reds[iii]=-999;
102   gxhnew(rxsize,rysize,hbufsz);                 /* Init hardcopy buffering */
103   color = 1;
104   mask = NULL; maskflg = -999;         /* Don't allocate mask until first use */
105 }
106 
107 /* Terminate graphics output */
108 
gxend(void)109 void gxend (void){                     /* Return screen to normal */
110   gxhend();
111   if (mask) free(mask);
112   if (intflg) gxdend();
113   printf ("GX package terminated \n");
114 }
115 
116 /* Frame action.  Values for action are:
117       0 -- new frame (clear display), wait before clearing.
118       1 -- new frame, no wait.
119       2 -- New frame in double buffer mode.  If not supported
120            has same result as action=1.  Usage involves multiple
121            calls with action=2 to obtain an animation effect.
122       7 -- new frame, but just clear graphics.  Do not clear
123            event queue; redraw buttons.
124       8 -- clear only the event queue.
125       9 -- clear only the X request buffer */
126 
gxfrme(int action)127 void gxfrme (int action) {
128 int scol,i;
129 
130   if (action>7) {
131     if (intflg) gxdfrm(action);
132     return;
133   }
134   gxmaskclear();
135   if (intflg) {
136 #ifdef XLIBEMU
137     if (action==0) {
138         { char cmd[512];
139           gets(cmd);
140         }
141     }
142 #else
143     if (action==0) getchar();              /* Wait if requested    */
144 #endif
145     if (action!=2&&bufmod) {
146       gxdsgl ();
147       bufmod=0;
148     }
149     if (action==2&&(!bufmod)) {
150       gxddbl ();
151       bufmod=1;
152     }
153     if (bufmod) gxdswp ();
154     gxdfrm (action);
155   }
156 
157   gxhfrm (action);                         /* Reset meta buffer */
158 
159   for (i=16; i<100; i++) {
160     if (reds[i]>-1) hout4i(-5,i,reds[i],grns[i],blus[i]);
161   }
162   if (bcol>0) {
163     scol = color;
164     gxcolr(bcol);
165     color = scol;
166     gxrecf (0.0, rxsize, 0.0, rysize);
167     if (intflg) gxdfrm (9);
168   }
169 
170 }
171 
172 /* Perform new frame stuff for redraw.  This primarily involves
173    the background color. */
174 
gxsfrm(void)175 void gxsfrm (void) {
176   if (bcol>0) {
177     gxdcol(bcol);
178     gxdrec (0.0, rxsize, 0.0, rysize);
179     gxdcol(color);
180   }
181 }
182 
183 /* Set color.  Colors are: 0 - black;  1 - white
184                            2 - red;    3 - green;   4 - blue
185                            5 - cyan;   6 - magenta; 7 - yellow
186                            8 - orange; 9 - purple; 10 - lt. blue
187                           11 - pink;  12 - grey;
188    Other colors may be available but are defined by the device
189    driver.   */
190 
gxcolr(int clr)191 void gxcolr (int clr){                 /* Set color     */
192   if (clr<0) clr=0;
193   if (clr>99) clr=99;
194   hout1(-3,clr);
195   if (intflg) gxdcol (clr);
196   color = clr;
197 }
198 
199 /* Set and query background color */
200 
gxbckg(int col)201 void gxbckg (int col) {
202   bcol = col;
203 }
204 
gxqbck(void)205 int gxqbck (void) {
206   return(bcol);
207 }
208 
gxacol(int clr,int red,int green,int blue)209 int gxacol (int clr, int red, int green, int blue ) {
210 int rtn;
211   rtn=1;
212   hout4i(-5,clr,red,green,blue);
213   if (intflg) rtn = gxdacl (clr, red, green, blue);
214   if (clr>15 && clr<100) {
215     reds[clr] = red;
216     grns[clr] = green;
217     blus[clr] = blue;
218   }
219   return rtn;
220 }
221 
222 
223 /* Set line weight */
224 
gxwide(int wid)225 void gxwide (int wid){                 /* Set width     */
226 int hwid;
227   hwid = wid;
228   if (lwflg) hwid = (wid+1)/2;
229   hout2i(-4,hwid,wid);
230   if (intflg) gxdwid (wid);
231   lwide = wid;
232 }
233 
234 
235 /* Move to x, y with 'clipping'.  Clipping is implmented
236    corsely, where any move or draw point that is outside the
237    clip region is not plotted.                          */
238 
gxmove(float x,float y)239 void gxmove (float x, float y){        /* Move to x,y   */
240   mflag = 0;
241   oldx = x;
242   oldy = y;
243   if ( x<clminx || x>clmaxx || y<clminy || y>clmaxy ) {
244     cflag=1;
245     return;
246   }
247   cflag=0;
248   gxvcon(x,y,&x,&y);
249   hout2(-10,x,y);
250   if (intflg) gxdmov (x,y);
251 }
252 
253 /* Draw to x, y with clipping */
254 
gxdraw(float x,float y)255 void gxdraw (float x, float y){        /* Draw to x,y   */
256 float xnew,ynew;
257 int pos;
258   if ( x<clminx || x>clmaxx || y<clminy || y>clmaxy ) {
259     if (!cflag) {
260       bdterp (oldx,oldy,x,y,&xnew,&ynew);
261       gxvcon(xnew,ynew,&xnew,&ynew);
262       hout2(-11,xnew,ynew);
263       if (intflg) gxddrw (xnew,ynew);
264       cflag=1;
265     }
266     oldx = x; oldy = y;
267     return;
268   }
269   if (cflag) {
270     bdterp (oldx,oldy,x,y,&xnew,&ynew);
271     cflag=0;
272     gxvcon(xnew,ynew,&xnew,&ynew);
273     hout2(-10,xnew,ynew);
274     if (intflg) gxdmov (xnew,ynew);
275   }
276   oldx = x; oldy = y;
277   gxvcon(x,y,&x,&y);
278   if (maskflg>0) pos = ((int)(y*100.0))*maskx + (int)(x*100.0);
279   if (maskflg>0 && pos>0 && pos<masksize && *(mask+pos)=='1') {
280     hout2(-10,x,y);
281     if (intflg) gxdmov (x,y);
282     mflag = 1;
283     return;
284   }
285   if (mflag) {
286     hout2(-10,x,y);
287     if (intflg) gxdmov (x,y);
288     mflag = 0;
289     return;
290   }
291   hout2(-11,x,y);
292   if (intflg) gxddrw (x, y);
293 }
294 
295 /* Set software linestyle */
296 
gxstyl(int style)297 void gxstyl (int style) {              /* Set line style  */
298   if (style==-9) style=1;
299   lstyle=style;
300   if (style==2) {
301     dnum=1;
302     dash[0]=0.25;
303     dash[1]=0.1;  }
304   else if (style==3) {
305     dnum=1;
306     dash[0]=0.03;
307     dash[1]=0.03;   }
308   else if (style==4) {
309     dnum=3;
310     dash[0]=0.25;
311     dash[1]=0.1;
312     dash[2]=0.1;
313     dash[3]=0.1;   }
314   else if (style==5) {
315     dnum=1;
316     dash[0]=0.01;
317     dash[1]=0.08;  }
318   else if (style==6) {
319     dnum=3;
320     dash[0]=0.15;
321     dash[1]=0.08;
322     dash[2]=0.01; ;
323     dash[3]=0.08;   }
324   else if (style==7) {
325     dnum=5;
326     dash[0]=0.15;
327     dash[1]=0.08;
328     dash[2]=0.01;
329     dash[3]=0.08;
330     dash[4]=0.01;
331     dash[5]=0.08;  }
332   else lstyle=0;
333   slen=dash[0]; jpen=2; dpnt=0;
334 }
335 
336 /* Move and draw with linestyles and clipping */
337 
gxplot(float x,float y,int ipen)338 void gxplot (float x, float y, int ipen ) {    /* Move or draw  */
339 float x1,y1;
340 
341   if (lstyle<2) {
342      if (ipen==2) gxdraw (x,y);
343      else gxmove (x,y);
344      xsave=x; ysave=y;
345      return;
346   }
347   if (ipen==3) {
348     slen=dash[0];
349     dpnt=0;
350     jpen=2;
351     xsave=x;
352     ysave=y;
353     gxmove (x,y);
354     return;
355   }
356   alen=hypot ((x-xsave),(y-ysave));
357   if (alen<0.001) return;
358   while (alen>slen) {
359     x1=xsave+(x-xsave)*(slen/alen);
360     y1=ysave+(y-ysave)*(slen/alen);
361     if (jpen==2) gxdraw (x1,y1);
362             else gxmove (x1,y1);
363     dpnt+=1;
364     if (dpnt>dnum) dpnt=0;
365     slen=slen+dash[dpnt];
366     jpen+=1;
367     if (jpen>3) jpen=2;
368   }
369   slen=slen-alen;
370   xsave=x;
371   ysave=y;
372   if (jpen==2) gxdraw (x,y);
373           else gxmove (x,y);
374   if (slen<0.001) {
375     dpnt+=1;
376     if (dpnt>dnum) dpnt=0;
377     slen=dash[dpnt];
378     jpen+=1;
379     if (jpen>3) jpen=2;
380   }
381 }
382 
383 /* Specify software clip region.  */
384 
gxclip(float xmin,float xmax,float ymin,float ymax)385 void gxclip (float xmin, float xmax, float ymin, float ymax) {
386   clminx = xmin;
387   clmaxx = xmax;
388   clminy = ymin;
389   clmaxy = ymax;
390   if (clminx<0.0) clminx = 0.0;
391   if (clmaxx>xsize) clmaxx = xsize;
392   if (clminy<0.0) clminy = 0.0;
393   if (clmaxy>ysize) clmaxy = ysize;
394 }
395 
396 /* Constants for linear scaling */
397 
398 static float xm,xb,ym,yb;
399 
400 /* Specify low level linear scaling (scaling level 1) */
401 
gxscal(float xmin,float xmax,float ymin,float ymax,float smin,float smax,float tmin,float tmax)402 void gxscal (float xmin, float xmax, float ymin, float ymax,
403              float smin, float smax, float tmin, float tmax){
404   xm=(xmax-xmin)/(smax-smin);
405   xb=xmin-(xm*smin);
406   ym=(ymax-ymin)/(tmax-tmin);
407   yb=ymin-(ym*tmin);
408 }
409 
410 /* Constants for virtual page scaling */
411 
412 static float vxm,vxb,vym,vyb;
413 
414 /* Specify virtual page scaling */
415 
gxvpag(float xmax,float ymax,float smin,float smax,float tmin,float tmax)416 void gxvpag (float xmax, float ymax,
417              float smin, float smax, float tmin, float tmax){
418 float xmin, ymin;
419   xmin = 0.0;
420   ymin = 0.0;
421   xsize = xmax;
422   ysize = ymax;
423   if (smin<0.0) smin=0.0;
424   if (smax>rxsize) smax = rxsize;
425   if (tmin<0.0) tmin=0.0;
426   if (tmax>rysize) tmax = rysize;
427   clminx = 0.0;
428   clmaxx = xmax;
429   clminy = 0.0;
430   clmaxy = ymax;
431   if ((smax-smin)/rxsize < 0.6 || (tmax-tmin)/rysize < 0.6) lwflg = 1;
432   else lwflg = 0;
433   vxm=(smax-smin)/(xmax-xmin);
434   vxb=smin-(vxm*xmin);
435   vym=(tmax-tmin)/(ymax-ymin);
436   vyb=tmin-(vym*ymin);
437 }
438 
439 /* Do virtual page scaling conversion */
440 
gxvcon(float s,float t,float * x,float * y)441 void gxvcon (float s, float t, float *x, float *y) {
442   *x = s*vxm+vxb;
443   *y = t*vym+vyb;
444 }
445 
gxppvp(float x,float y,float * s,float * t)446 void gxppvp (float x, float y, float *s, float *t) {
447   *s = (x-vxb)/vxm;
448   *t = (y-vyb)/vym;
449 }
450 
451 
452 /* Specify projection-level scaling, typically used for map
453    projections.  The address of the routine to perform the scaling
454    is provided.  This is scaling level 2, and is the level that
455    mapping is done. */
456 
gxproj(void (* fproj)(float s,float t,float * x,float * y))457 void gxproj ( void (*fproj) (float s, float t, float *x, float *y)){
458 
459   fconv=fproj;
460 }
461 
462 /* Specify grid level scaling, typically used to convert a grid
463    to lat-lon values that can be input to the projection or linear
464    level scaling.  The address of a routine is provided to perform
465    the possibly non-linear scaling.  This is scaling level 3, and
466    is the level that contouring is done.  */
467 
gxgrid(void (* fproj)(float s,float t,float * x,float * y))468 void gxgrid ( void (*fproj) (float s, float t, float *x, float *y)){
469 
470   gconv=fproj;
471 }
472 
473 /* Convert coordinates at a particular level to level 0 coordinates
474    (hardware coords, 'inches').  The level of the input coordinates
475    is provided.  User projection and grid scaling routines are called
476    as needed.  */
477 
gxconv(float s,float t,float * x,float * y,int level)478 void gxconv (float s, float t, float *x, float *y, int level) {
479 
480   if (level>2 && gconv!=NULL) (*gconv)(s,t,&s,&t);
481   if (level>1 && fconv!=0) (*fconv)(s,t,&s,&t);
482 
483   if (level>0) {
484     s=s*xm+xb;
485     t=t*ym+yb;
486   }
487   *x=s;
488   *y=t;
489 }
490 
491 /* Convert from level 0 coordinates (inches) to level 2 world
492    coordinates.  The back transform is done via conversion
493    linearly from level 0 to level 1, then calling the back
494    transform map routine, if available, to do level 1 to level
495    2 transform.  */
496 
gxxy2w(float x,float y,float * s,float * t)497 void gxxy2w (float x, float y, float *s, float *t) {
498 
499   /* Do level 0 to level 1 */
500 
501   if (xm==0.0 || ym==0.0) {
502     *s = -999.9;
503     *t = -999.9;
504     return;
505   }
506   *s = (x-xb)/xm;
507   *t = (y-yb)/ym;
508 
509   /* Do level 1 to level 2 */
510 
511   if (bconv!=NULL) (*bconv)(*s,*t,s,t);
512 }
513 
514 /* Allow caller to specify a routine to do the back transform from
515    level 1 to level 2 coordinates. */
516 
gxback(void (* fproj)(float s,float t,float * x,float * y))517 void gxback ( void (*fproj) (float s, float t, float *x, float *y)){
518 
519   bconv=fproj;
520 }
521 
522 
523 /* Convert from grid coordinates to map coordinates (level 3 to
524    level 2) */
525 
gxgrmp(float s,float t,float * x,float * y)526 void gxgrmp (float s, float t, float *x, float *y) {
527 
528   if (gconv!=NULL) (*gconv)(s,t,&s,&t);
529   *x = s;
530   *y = t;
531 }
532 
533 /* Convert an array of higher level coordinates to level 0 coordinates.
534    The conversion is done 'in place' and the input coordinates are
535    lost.  This routine performs the same function as coord except is
536    somewhat more efficient for many coordinate transforms.         */
537 
gxcord(float * coords,int num,int level)538 void gxcord (float * coords, int num, int level) {
539 int i;
540 float * xy;
541 
542   if (level>2 && gconv!=NULL) {
543     xy=coords;
544     for (i=0; i<num; i++) {
545       (*gconv) (*xy,*(xy+1),xy,xy+1);
546       xy+=2;
547     }
548   }
549 
550   if (level>1 && fconv!=NULL) {
551     xy=coords;
552     for (i=0; i<num; i++) {
553       (*fconv) (*xy,*(xy+1),xy,xy+1);
554       xy+=2;
555     }
556   }
557 
558   if (level>0) {
559     xy=coords;
560     for (i=0; i<num; i++) {
561       *xy = *xy*xm+xb;
562       xy++;
563       *xy = *xy*ym+yb;
564       xy++;
565     }
566   }
567 }
568 
569 /* Delete level 3 or level 2 and level 3 scaling.  Level 1 scaling
570    cannot be deleted.  */
571 
gxrset(int level)572 void gxrset (int level) {
573 
574   if (level > 2) gconv=NULL;
575   if (level > 1) {fconv=NULL; bconv=NULL;}
576 }
577 
578 /* Plot a color filled rectangle.  */
579 
gxrecf(float xlo,float xhi,float ylo,float yhi)580 void gxrecf (float xlo, float xhi, float ylo, float yhi) {
581 float x;
582 
583   if (xlo>xhi) {
584     x = xlo;
585     xlo = xhi;
586     xhi = x;
587   }
588   if (ylo>yhi) {
589     x = ylo;
590     ylo = yhi;
591     yhi = x;
592   }
593   if (xhi<=clminx || xlo>=clmaxx || yhi<=clminy || ylo>=clmaxy) return;
594   if (xlo<clminx) xlo = clminx;
595   if (xhi>clmaxx) xhi = clmaxx;
596   if (ylo<clminy) ylo = clminy;
597   if (yhi>clmaxy) yhi = clmaxy;
598   gxvcon (xlo,ylo,&xlo,&ylo);
599   gxvcon (xhi,yhi,&xhi,&yhi);
600   hout4(-6,xlo,xhi,ylo,yhi);
601   if (intflg) gxdrec (xlo, xhi, ylo, yhi);
602 }
603 
604 /* Define fill pattern for rectangles and polygons. */
605 
gxptrn(int typ,int den,int ang)606 void gxptrn (int typ, int den, int ang) {
607   hout3i(-12,typ,den,ang);
608   if (intflg) gxdptn (typ, den, ang);
609 }
610 
611 /* query color */
612 
gxqclr(void)613 int gxqclr (void) {
614   return (color);
615 }
616 
617 /* query style */
618 
gxqstl(void)619 int gxqstl (void) {
620   return (lstyle);
621 }
622 
623 /* Draw markers 1-5. */
624 
gxmark(int mtype,float x,float y,float siz)625 void gxmark (int mtype, float x, float y, float siz ) {
626 float x1,y1,t,t1,siz2,xy[80];
627 int i,ii,lsave,cnt;
628 
629   siz2 = siz/2.0;
630   if (mtype==1) {                      /* cross hair */
631     gxmove (x,y-siz2);
632     gxdraw (x,y+siz2);
633     gxmove (x-siz2,y);
634     gxdraw (x+siz2,y);
635     return;
636   }
637   if (mtype==2 || mtype==3 || mtype==10 || mtype==11) { /* circles */
638     if (siz<0.1) ii = 30;
639     else if (siz<0.3) ii = 15;
640     else ii = 10;
641     if (mtype>3) ii = 15;
642     cnt = 0;
643     for (i=60; i<415; i+=ii) {
644       xy[cnt*2] = x + siz2*cos((float)(i)*3.14159/180.0);
645       xy[cnt*2+1] = y + siz2*sin((float)(i)*3.14159/180.0);
646       cnt++;
647     }
648     xy[cnt*2] = xy[0];
649     xy[cnt*2+1] = xy[1];
650     cnt++;
651     if (mtype==2) {                  /* Open circle */
652       gxmove(xy[0],xy[1]);
653       for (i=1; i<cnt; i++) gxdraw (xy[i*2],xy[i*2+1]);
654     } else if (mtype==3) {           /* Filled circle */
655       gxfill (xy,cnt);
656     } else if (mtype==10) {          /* Scattered fill */
657       gxmove(xy[6],xy[7]);
658       for (i=4; i<14; i++) gxdraw (xy[i*2],xy[i*2+1]);
659       gxmove(xy[30],xy[31]);
660       for (i=16; i<25; i++) gxdraw (xy[i*2],xy[i*2+1]);
661       gxdraw (xy[0],xy[1]);
662       for (i=8; i<14; i++) xy[i] = xy[i+18];
663       xy[14] = xy[2]; xy[15] = xy[3];
664       gxfill (xy+2,7);
665     } else if (mtype==11) {          /* Broken fill */
666       xy[0] = x + siz2*cos(68.0*3.14159/180.0);
667       xy[1] = y + siz2*sin(68.0*3.14159/180.0);
668       xy[8] = x + siz2*cos(112.0*3.14159/180.0);
669       xy[9] = y + siz2*sin(112.0*3.14159/180.0);
670       xy[24] = x + siz2*cos(248.0*3.14159/180.0);
671       xy[25] = y + siz2*sin(248.0*3.14159/180.0);
672       xy[32] = x + siz2*cos(292.0*3.14159/180.0);
673       xy[33] = y + siz2*sin(292.0*3.14159/180.0);
674       gxmove(xy[0],xy[1]);
675       for (i=1; i<5; i++) gxdraw (xy[i*2],xy[i*2+1]);
676       gxmove(xy[24],xy[25]);
677       for (i=13; i<17; i++) gxdraw (xy[i*2],xy[i*2+1]);
678       xy[26] = xy[8]; xy[27] = xy[9];
679       gxfill (xy+8,10);
680       xy[50] = xy[0]; xy[51] = xy[1];
681       gxfill (xy+32,10);
682     }
683     return;
684   }
685   if (mtype==4 || mtype==5) {          /* Draw sqaures */
686     xy[0] = x-siz2; xy[1] = y+siz2;
687     xy[2] = x+siz2; xy[3] = y+siz2;
688     xy[4] = x+siz2; xy[5] = y-siz2;
689     xy[6] = x-siz2; xy[7] = y-siz2;
690     xy[8] = xy[0]; xy[9] = xy[1];
691     if (mtype==4) {
692       gxmove (xy[0],xy[1]);
693       for (i=1; i<5; i++) gxdraw (xy[i*2],xy[i*2+1]);
694     } else {
695       gxfill (xy,5);
696     }
697     return;
698   }
699   if (mtype==6) {                      /* ex marks the spot */
700     gxmove (x-siz2*0.71,y-siz2*0.71);
701     gxdraw (x+siz2*0.71,y+siz2*0.71);
702     gxmove (x-siz2*0.71,y+siz2*0.71);
703     gxdraw (x+siz2*0.71,y-siz2*0.71);
704     return;
705   }
706   if (mtype==7) {                      /* Open diamond */
707     gxmove (x-siz2*0.75,y);
708     gxdraw (x,y+siz2*1.1);
709     gxdraw (x+siz2*0.75,y);
710     gxdraw (x,y-siz2*1.1);
711     gxdraw (x-siz2*0.75,y);
712     return;
713   }
714   if (mtype==8 || mtype==9) {          /* Triangles */
715     xy[0] = x; xy[1] = y+siz2;
716     xy[2] = x+siz2*0.88; xy[3] = y-siz2*0.6;
717     xy[4] = x-siz2*0.88; xy[5] = y-siz2*0.6;
718     xy[6] = x; xy[7] = y+siz2;
719     if (mtype==8) {
720       gxmove (xy[0],xy[1]);
721       for (i=1; i<4; i++) gxdraw (xy[i*2],xy[i*2+1]);
722     } else {
723       gxfill (xy,4);
724     }
725     return;
726   }
727 }
728 
729 /* Plot centered title.  Only supports angle of 0 and 90 */
730 
gxtitl(char * chrs,float x,float y,float height,float width,float angle)731 void gxtitl (char * chrs, float x, float y, float height,
732              float width, float angle) {
733 float xx,yy;
734 int len,i;
735 
736   i = 0;
737   len = 0;
738   while (*(chrs+i)) {
739     if (*(chrs+i)!=' ') len=i+1;
740     i++;
741   }
742   if (len==0) return;
743 
744   xx = x; yy = y;
745   if (angle > 45.0) {
746     yy = y - 0.5*width*(float)len;
747   } else {
748     xx = x - 0.5*width*(float)len;
749   }
750   gxchpl (chrs, len, xx, yy, height, width, angle);
751 }
752 
753 /* Do polygon fill.  It is assumed the bulk of the work will be done
754    in hardware.  We do perform clipping at this level, and
755    actually do the work to clip at the clipping boundry.       */
756 
gxfill(float * xy,int num)757 void gxfill (float *xy, int num) {
758 int i,flag,onum,aflag;
759 float *r, *out, *buff;
760 float xold,yold,x,y;
761 float xybuff[40];
762 
763   if (num<3) return;
764 
765   /* Do clipping.    */
766 
767   aflag = 0;
768   if (num<10) buff = xybuff;
769   else {
770     buff = (float *)malloc(sizeof(float)*num*4);
771     if (buff==NULL) {
772       printf("Memory allocation error in gxfill.  Can't fill contour\n");
773       return;
774     }
775     aflag = 1;
776   }
777 
778   r = xy;
779   out = buff;
780   onum = 0;
781   flag = 0;
782   if (*r<clminx || *r>clmaxx || *(r+1)<clminy || *(r+1)>clmaxy) flag=1;
783   for (i=0; i<num; i++) {
784     if (*r<clminx || *r>clmaxx || *(r+1)<clminy || *(r+1)>clmaxy) {
785       if (!flag) {
786         bdterp (*(r-2), *(r-1), *r, *(r+1), &x, &y);
787         *out = x;
788         *(out+1) = y;
789         onum++;
790         out+=2;
791       }
792       *out = *r;
793       *(out+1) = *(r+1);
794       if (*r<clminx) *out = clminx;
795       if (*r>clmaxx) *out = clmaxx;
796       if (*(r+1)<clminy) *(out+1) = clminy;
797       if (*(r+1)>clmaxy) *(out+1) = clmaxy;
798       onum++;
799       out+=2;
800       flag = 1;
801     } else {
802       if (flag) {
803         bdterp (*(r-2), *(r-1), *r, *(r+1), &x, &y);
804         *out = x;
805         *(out+1) = y;
806         onum++;
807         out+=2;
808       }
809       *out = *r;
810       *(out+1) = *(r+1);
811       onum++;
812       out+=2;
813       flag = 0;
814     }
815     r+=2;
816   }
817 
818   r = buff;
819   for (i=0; i<onum; i++) {
820     gxvcon (*r,*(r+1),r,r+1);
821     r+=2;
822   }
823 
824   /* Output to meta buffer if requested.   */
825 
826   hout1(-7,onum);
827   r = buff;
828   hout2(-10,*r,*(r+1));
829   r+=2;
830   for (i=1; i<onum; i++) {
831     hout2(-11,*r,*(r+1));
832     r+=2;
833   }
834   hout0(-8);
835 
836   /* Output to hardware */
837 
838   if (intflg) gxdfil (buff, onum);
839   if (aflag) free(buff);
840 }
841 
842 /* Perform edge interpolation for clipping  */
843 
bdterp(float x1,float y1,float x2,float y2,float * x,float * y)844 void bdterp (float x1, float y1, float x2, float y2,
845              float *x, float *y) {
846 
847   sidev:
848 
849   if (x1<clminx || x2<clminx || x1>clmaxx || x2>clmaxx) {
850     *x = clminx;
851     if (x1>clmaxx || x2>clmaxx) *x = clmaxx;
852     *y = y1 - ((y1-y2)*(x1-*x)/(x1-x2));
853     if (*y<clminy || *y>clmaxy) goto sideh;
854     return;
855   }
856 
857   sideh:
858 
859   if (y1<clminy || y2<clminy || y1>clmaxy || y2>clmaxy) {
860     *y = clminy;
861     if (y1>clmaxy || y2>clmaxy) *y = clmaxy;
862     *x = x1 - ((x1-x2)*(y1-*y)/(y1-y2));
863     return;
864   }
865 }
866 
867 /* Query env symbol */
868 
gxgsym(char * ch)869 char *gxgsym(char *ch) {
870   return (getenv(ch));
871 }
872 
873 /* Construct full file path name from env symbol or default */
874 
gxgnam(char * ch)875 char *gxgnam(char *ch) {
876 char *fname, *ddir;
877 int len,i,j;
878 
879   /* calc partial length of output string */
880 
881   len = 0;
882   i = 0;
883   while (*(ch+i)) { i++; len++;}
884 
885   /* Query the env symbol */
886 
887   ddir = gxgsym("GADDIR");
888 
889   /* calc the total length of the output string */
890 
891   if (ddir==NULL) {
892     i = 0;
893     while (*(datad+i)) { i++; len++;}
894   } else {
895     i = 0;
896     while (*(ddir+i)) { i++; len++;}
897   }
898 
899   /* Allocate memory for the output */
900 
901   fname = (char *)malloc(len+5);
902   if (fname==NULL) {
903     printf ("Memory allocation error in data set open\n");
904     return (NULL);
905   }
906 
907   /* fill in the directory depending on the value of the env var */
908 
909   if (ddir==NULL) {
910     i = 0;
911     while (*(datad+i)) {
912       *(fname+i) = *(datad+i);
913       i++;
914     }
915   } else if (*ddir=='.') {
916     i = 0;
917   } else {
918     i = 0;
919     while (*(ddir+i)) {
920       *(fname+i) = *(ddir+i);
921       i++;
922     }
923   }
924 
925   /* Insure a slash between dir name and file name */
926 
927   if (i!=0 && *(fname+i-1)!='/') {
928     *(fname+i) = '/';
929     i++;
930   }
931 
932   /* fill in the file name */
933 
934   j = 0;
935   while (*(ch+j)) {
936     *(fname+i) = *(ch+j);
937     i++; j++;
938   }
939   *(fname+i) = '\0';
940 
941   return (fname);
942 }
943 
gxbutn(int bnum,struct gbtn * pbn)944 void gxbutn (int bnum, struct gbtn *pbn) {
945   hout1(-20,bnum);
946   gxdpbn(bnum, pbn, 0, 0, -1);
947 }
948 
949 /* Set mask for a rectangular area */
950 
gxmaskrec(float xlo,float xhi,float ylo,float yhi)951 void gxmaskrec (float xlo, float xhi, float ylo, float yhi) {
952 int siz,i,j,pos,ilo,ihi,jlo,jhi,jj;
953 
954   if (maskflg == -888) return;
955 
956   if (mask==NULL) {                     /* If not allocated yet, now's the time */
957     siz = (int)(rxsize*rysize*10000.0);
958     mask = (char *)malloc(siz);
959     if (mask==NULL) {
960       printf ("Error allocating mask array memory\n");
961       printf ("Execution continues with no mask\n");
962       maskflg = -888;
963       return;
964     }
965     masksize = siz;
966     maskx = (int)(rxsize*100.0);
967     gxmaskclear();
968   }
969 
970   ilo = (int)(xlo*100.0);
971   ihi = (int)(xhi*100.0);
972   jlo = (int)(ylo*100.0);
973   jhi = (int)(yhi*100.0);
974   if (ilo<0) ilo = 0;
975   if (ihi<0) ihi = 0;
976   if (ilo>maskx) ilo = maskx;
977   if (ihi>maskx) ihi = maskx;
978   for (j=jlo; j<=jhi; j++) {
979     jj = j*maskx;
980     for (i=ilo; i<=ihi; i++) {
981       pos = jj+i;
982       if (pos>=0 || pos<masksize) *(mask+pos) = '1';
983     }
984   }
985   maskflg = 1;
986 }
987 
988 /* Set mask to unset state */
989 
gxmaskclear(void)990 void gxmaskclear(void) {
991 int i;
992   if (maskflg > 0)  {
993     for (i=0; i<masksize; i++) *(mask+i) = '0';
994     maskflg = 0;
995   }
996 }
997