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 * 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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