1 /*
2  * @(#)gremlinlib.c	1.1  11/30/84
3  *
4  * Programmer's interface to Gremlin file creation routines.
5  *
6  * Mark Opperman (opcode@monet.BERKELEY)
7  *
8  */
9 
10 #include <stdio.h>
11 #include <math.h>
12 #include "gremlin.h"
13 
14 #define SQRT2 0.707107		/* sqrt(2) / 2.0 */
15 #define TWOPI 6.283185
16 
17 #define NFONTS 4
18 #define NBRUSHES 6
19 #define NSIZES 4
20 #define NSTIPPLES 8
21 
22 static version;			/* AED_GREMLIN or SUN_GREMLIN */
23 
24 static char *justify_names[] = { "BOTLEFT", "BOTRIGHT", "CENTCENT",
25 				 "", "", "", "", "", "", "",
26 				 "TOPLEFT", "TOPCENT", "TOPRIGHT",
27 				 "CENTLEFT", "CENTRIGHT", "BOTCENT" };
28 
29 
30 /*
31  * Return file pointer for open gremlin file.
32  * Return NULL if bad arguments passed or unable to open file.
33  * Write gremlin file header info to file.
34  * Because there is only one global indicator of the device (version),
35  * elements written to gremlinfile will be of the type of the device
36  * in the most recent call to gr_open().
37  */
38 FILE *
gr_open(gremlinfile,device,orientation,x,y)39 gr_open(gremlinfile, device, orientation, x, y)
40 char *gremlinfile;		/* file path name */
41 int device;			/* SUN_GREMLIN or AED_GREMLIN */
42 int orientation;		/* meaningful for AED only */
43 float x, y;			/* picture reference point */
44 {
45     FILE *fp, *fopen();
46 
47     if ((device != SUN_GREMLIN) && (device != AED_GREMLIN)) {
48 	fprintf(stderr, "gr_open: bad device %d\n", device);
49 	return((FILE *) NULL);
50     }
51     else if ((orientation != VERT_ORIENT) && (orientation != HORZ_ORIENT)) {
52 	fprintf(stderr, "gr_open: bad orientation %d\n", orientation);
53 	return((FILE *) NULL);
54     }
55 
56     if ((fp = fopen(gremlinfile, "w")) != NULL) {
57 	if ((version = device) == SUN_GREMLIN)
58 	    fprintf(fp, "sungremlinfile\n");
59 	else
60 	    fprintf(fp, "gremlinfile\n");
61 
62 	fprintf(fp, "%d %3.2f %3.2f\n", orientation, x, y);
63     }
64 
65     return(fp);
66 }
67 
68 
69 /*
70  * Write terminator element to gremlin file and close the file.
71  */
gr_close(fp)72 gr_close(fp)
73 FILE *fp;
74 {
75     if (fp == (FILE *) NULL) {
76 	fprintf(stderr, "gr_close: NULL file pointer\n");
77 	return(GR_ERROR);
78     }
79     fprintf(fp, "-1\n");
80     return(fclose(fp));
81 }
82 
83 
84 /*
85  * Write vector element to gremlin file.
86  */
gr_vector(fp,npoints,list,brush)87 gr_vector(fp, npoints, list, brush)
88 FILE *fp;			/* gremlin file pointer */
89 int npoints;			/* number of points */
90 float list[][2];		/* coordinate point list */
91 int brush;			/* line style */
92 {
93     register i;
94 
95     if (fp == (FILE *) NULL) {
96 	fprintf(stderr, "gr_vector: NULL file pointer\n");
97 	return(GR_ERROR);
98     }
99     else if (npoints < 2) {
100 	fprintf(stderr, "gr_vector: too few points %d\n", npoints);
101 	return(GR_ERROR);
102     }
103     else if ((brush < 1) || (brush > NBRUSHES)) {
104 	fprintf(stderr, "gr_vector: bad brush %d\n", brush);
105 	return(GR_ERROR);
106     }
107 
108     if (version == SUN_GREMLIN)
109 	fprintf(fp, "VECTOR\n");
110     else
111 	fprintf(fp, "%d\n", VECTOR);
112 
113     for (i=0; i<npoints; i++)
114 	fprintf(fp, "%3.2f %3.2f\n", list[i][0], list[i][1]);
115 
116     fprintf(fp, (version == SUN_GREMLIN) ? "*\n" : "-1.00 -1.00\n");
117 
118     fprintf(fp, "%d 0\n0\n", brush);
119     return(GR_OK);
120 }
121 
122 
123 /*
124  * Write curve element to gremlin file.
125  */
gr_curve(fp,npoints,list,brush)126 gr_curve(fp, npoints, list, brush)
127 FILE *fp;			/* gremlin file pointer */
128 int npoints;			/* number of points */
129 float list[][2];		/* coordinate point list */
130 int brush;			/* line style */
131 {
132     register i;
133 
134     if (fp == (FILE *) NULL) {
135 	fprintf(stderr, "gr_curve: NULL file pointer\n");
136 	return(GR_ERROR);
137     }
138     else if (npoints < 2) {
139 	fprintf(stderr, "gr_curve: too few points %d\n", npoints);
140 	return(GR_ERROR);
141     }
142     else if ((brush < 1) || (brush > NBRUSHES)) {
143 	fprintf(stderr, "gr_curve: bad brush %d\n", brush);
144 	return(GR_ERROR);
145     }
146 
147     if (version == SUN_GREMLIN)
148 	fprintf(fp, "CURVE\n");
149     else
150 	fprintf(fp, "%d\n", CURVE);
151 
152     for (i=0; i<npoints; i++)
153 	fprintf(fp, "%3.2f %3.2f\n", list[i][0], list[i][1]);
154 
155     fprintf(fp, (version == SUN_GREMLIN) ? "*\n" : "-1.00 -1.00\n");
156 
157     fprintf(fp, "%d 0\n0\n", brush);
158     return(GR_OK);
159 }
160 
161 
162 /*
163  * Write circle element (360 degree arc) to gremlin file.
164  */
gr_circle(fp,cx,cy,radius,brush)165 gr_circle(fp, cx, cy, radius, brush)
166 FILE *fp;			/* gremlin file pointer */
167 float cx, cy;			/* center of the circle */
168 float radius;			/* circle radius */
169 int brush;			/* line style */
170 {
171     if (fp == (FILE *) NULL) {
172 	fprintf(stderr, "gr_circle: NULL file pointer\n");
173 	return(GR_ERROR);
174     }
175     else if (radius <= 0.0) {
176 	fprintf(stderr, "gr_circle: non-positive radius %f\n", radius);
177 	return(GR_ERROR);
178     }
179     else if ((brush < 1) || (brush > NBRUSHES)) {
180 	fprintf(stderr, "gr_circle: bad brush %d\n", brush);
181 	return(GR_ERROR);
182     }
183 
184     if (version == SUN_GREMLIN)
185 	fprintf(fp, "ARC\n");
186     else
187 	fprintf(fp, "%d\n", ARC);
188 
189     fprintf(fp, "%3.2f %3.2f\n", cx, cy);
190     fprintf(fp, "%3.2f %3.2f\n", cx + (SQRT2 * radius),
191 				 cy + (SQRT2 * radius));
192     fprintf(fp, "%3.2f %3.2f\n", cx, cy + radius);
193     fprintf(fp, "%3.2f %3.2f\n", cx, cy - radius);
194     fprintf(fp, "%3.2f %3.2f\n", cx + radius, cy);
195     fprintf(fp, "%3.2f %3.2f\n", cx - radius, cy);
196 
197     fprintf(fp, (version == SUN_GREMLIN) ? "*\n" : "-1.00 -1.00\n");
198 
199     fprintf(fp, "%d 0\n0\n", brush);
200     return(GR_OK);
201 }
202 
203 
204 /*
205  * Write arc element to gremlin file.
206  */
gr_arc(fp,cx,cy,sx,sy,angle,brush)207 gr_arc(fp, cx, cy, sx, sy, angle, brush)
208 FILE *fp;			/* gremlin file pointer */
209 float cx, cy;			/* center of the circle */
210 float sx, sy;			/* point at start of arc */
211 float angle;			/* counter-clockwise angle of arc (degrees) */
212 int brush;			/* line style */
213 {
214     float radius;		/* radius of arc */
215     float start_angle;		/* angle of starting point (radians) */
216     float stop_angle;		/* angle stopping point (radians) */
217     double dx, dy;		/* delta x and y (center to start) */
218 
219     if (fp == (FILE *) NULL) {
220 	fprintf(stderr, "gr_arc: NULL file pointer\n");
221 	return(GR_ERROR);
222     }
223     else if ((angle <= 0.0) || (angle > 360.0)) {
224 	fprintf(stderr, "gr_arc: bad angle %f\n", angle);
225 	return(GR_ERROR);
226     }
227     else if ((brush < 1) || (brush > NBRUSHES)) {
228 	fprintf(stderr, "gr_arc: bad brush %d\n", brush);
229 	return(GR_ERROR);
230     }
231 
232     dx = (double) (sx - cx);
233     dy = (double) (sy - cy);
234 
235     if ((radius = (float) sqrt(dx * dx + dy * dy)) == 0.0) {
236 	fprintf(stderr, "gr_arc: zero radius\n");
237 	return(GR_ERROR);
238     }
239 
240     start_angle = (float) atan2(dx, dy);
241     stop_angle = start_angle + (angle * (TWOPI / 360.0));
242 
243     if (version == SUN_GREMLIN)
244 	fprintf(fp, "ARC\n");
245     else
246 	fprintf(fp, "%d\n", ARC);
247 
248     fprintf(fp, "%3.2f %3.2f\n", cx, cy);
249     fprintf(fp, "%3.2f %3.2f\n", sx, sy);
250     fprintf(fp, "%3.2f %3.2f\n", cx + (radius * sin(stop_angle)),
251 				 cy + (radius * cos(stop_angle)));
252 
253     fprintf(fp, (version == SUN_GREMLIN) ? "*\n" : "-1.00 -1.00\n");
254 
255     fprintf(fp, "%d %d\n0\n", brush, (int) (angle + 0.5));
256     return(GR_OK);
257 }
258 
259 
260 /*
261  * Write polygon element to gremlin file.
262  */
gr_polygon(fp,npoints,list,border,stipple)263 gr_polygon(fp, npoints, list, border, stipple)
264 FILE *fp;			/* gremlin file pointer */
265 int npoints;			/* number of points */
266 float list[][2];		/* coordinate point list */
267 int border;			/* border style (0 is unbordered) */
268 int stipple;			/* stipple pattern */
269 {
270     register i;
271 
272     if (fp == (FILE *) NULL) {
273 	fprintf(stderr, "gr_polygon: NULL file pointer\n");
274 	return(GR_ERROR);
275     }
276     else if (npoints < 3) {
277 	fprintf(stderr, "gr_polygon: too few points %d\n", npoints);
278 	return(GR_ERROR);
279     }
280     else if ((border < 0) || (border > NBRUSHES)) {
281 	fprintf(stderr, "gr_polygon: bad border %d\n", border);
282 	return(GR_ERROR);
283     }
284     else if ((stipple < 1) || (stipple > NSTIPPLES)) {
285 	fprintf(stderr, "gr_polygon: bad stipple %d\n", stipple);
286 	return(GR_ERROR);
287     }
288 
289     if (version == SUN_GREMLIN)
290 	fprintf(fp, "POLYGON\n");
291     else
292 	fprintf(fp, "%d\n", POLYGON);
293 
294     for (i=0; i<npoints; i++)
295 	fprintf(fp, "%3.2f %3.2f\n", list[i][0], list[i][1]);
296 
297     fprintf(fp, (version == SUN_GREMLIN) ? "*\n" : "-1.00 -1.00\n");
298 
299     fprintf(fp, "%d %d\n0\n", border, stipple);
300     return(GR_OK);
301 }
302 
303 
304 /*
305  * Write text element to gremlin file.
306  * The SUN version of Gremlin recalculates the lower left coordinate
307  * text position each time a file is read.  Therefore, coordinates
308  * are computed as if the text were being displayed on the AED.
309  */
gr_text(fp,text,x,y,font,size,justification)310 gr_text(fp, text, x, y, font, size, justification)
311 FILE *fp;			/* gremlin file pointer */
312 char *text;			/* text string */
313 float x, y;			/* justification relative to this point */
314 int font, size;			/* text font, text size */
315 int justification;		/* type of justification */
316 {
317     int nchars;			/* number of characters in text string */
318     int length;			/* (AED) length based on size */
319     int charxsize;		/* (AED) character width */
320     int charysize;		/* (AED) character height */
321     int descenders;		/* (AED) character descender height */
322     float pos_x, pos_y;		/* lower left coordinate position of text */
323 
324     if (fp == (FILE *) NULL) {
325 	fprintf(stderr, "gr_text: NULL file pointer\n");
326 	return(GR_ERROR);
327     }
328     else if ((nchars = strlen(text)) == 0) {
329 	fprintf(stderr, "gr_text: null text string\n");
330 	return(GR_ERROR);
331     }
332     else if ((font < 1) || (font > NFONTS)) {
333 	fprintf(stderr, "gr_text: bad font %d\n", font);
334 	return(GR_ERROR);
335     }
336     else if ((size < 1) || (size > NSIZES)) {
337 	fprintf(stderr, "gr_text: bad size %d\n", size);
338 	return(GR_ERROR);
339     }
340     else if ((justification < BOTLEFT) || (justification > BOTCENT) ||
341 	    ((justification > CENTCENT) && (justification < TOPLEFT))) {
342 	fprintf(stderr, "gr_text: bad justification %d\n", justification);
343 	return(GR_ERROR);
344     }
345 
346     switch (size) {		/* set lower left position a la AED */
347 	case 1:
348 	    charxsize = 6;
349 	    charysize = 7;
350 	    descenders = 1;
351 	    break;
352 	case 2:
353 	    charxsize = 8;
354 	    charysize = 12;
355 	    descenders = 3;
356 	    break;
357 	case 3:
358 	    charxsize = 10;
359 	    charysize = 14;
360 	    descenders = 2;
361 	    break;
362 	case 4:
363 	    charxsize = 15;
364 	    charysize = 24;
365 	    descenders = 6;
366 	    break;
367     }
368 
369     length = nchars * charxsize;
370 
371     switch (justification) {
372 	case BOTLEFT:
373 	    pos_x = x;
374 	    pos_y = y;
375 	case BOTCENT:
376 	    pos_x = x - (length >> 1);
377 	    pos_y = y;
378 	    break;
379 	case BOTRIGHT:
380 	    pos_x = x - length;
381 	    pos_y = y;
382 	    break;
383 	case CENTLEFT:
384 	    pos_x = x;
385 	    pos_y = y - (charysize >> 1);
386 	    break;
387 	case CENTCENT:
388 	    pos_x = x - (length >> 1);
389 	    pos_y = y - (charysize >> 1);
390 	    break;
391 	case CENTRIGHT:
392 	    pos_x = x - length;
393 	    pos_y = y - (charysize >> 1);
394 	    break;
395 	case TOPLEFT:
396 	    pos_x = x;
397 	    pos_y = y + descenders - charysize;
398 	    break;
399 	case TOPCENT:
400 	    pos_x = x - (length >> 1);
401 	    pos_y = y + descenders - charysize;
402 	    break;
403 	case TOPRIGHT:
404 	    pos_x = x - length;
405 	    pos_y = y + descenders - charysize;
406 	    break;
407     }
408 
409     if (version == SUN_GREMLIN)
410 	fprintf(fp, "%s\n", justify_names[justification]);
411     else
412 	fprintf(fp, "%d\n", justification);
413 
414     fprintf(fp, "%3.2f %3.2f\n", x, y);
415     fprintf(fp, "%3.2f %3.2f\n", pos_x, pos_y);
416     fprintf(fp, "%3.2f %3.2f\n", pos_x + (length >> 1), pos_y);
417     fprintf(fp, "%3.2f %3.2f\n", pos_x + length, pos_y);
418 
419     fprintf(fp, (version == SUN_GREMLIN) ? "*\n" : "-1.00 -1.00\n");
420 
421     fprintf(fp, "%d %d\n", font, size);
422     fprintf(fp, "%d %s\n", nchars, text);
423     return(GR_OK);
424 }
425