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