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