static char rcsid[] = "$Header: /usr/jjc/dvitops/RCS/tpic.c,v 1.4 90/08/14 13:03:50 jjc Rel $"; #include "dvitops.h" #ifdef TPIC_SUPPORT /* Dotted lines look a bit anaemic; so we add this many milli-inches to the pen size of a dotted line. */ #define DOTTED_LINE_WIDTH_ADDITION 3 /* flags in tpic_object is or'ed from these */ #define ARC 1 #define SPLINE 2 #define SHADED 4 #define INVISIBLE 8 #define DOTTED 16 #define DASHED 32 struct point { integer x; integer y; }; struct tpic_object { struct tpic_object *next; integer h, v; int region; unsigned flags; integer pen_size; float shade; union { struct { float dash_width; int npoints; struct point point_vector[2]; /* may be bigger than this */ } p; struct { integer cx; integer cy; integer rx; integer ry; float s; float e; } a; } u; }; #ifdef PROTO static void draw_path(FILE *psfp, double sc, integer h, integer v, struct point *pv, int np, int closed); static void draw_spline(FILE *psfp, double sc, integer h, integer v, struct point *pv, int np); static void draw_ellipse(FILE *psfp, double sc, integer h, integer v, integer cx, integer cy, integer rx, integer ry); static void draw_arc(FILE *psfp, double sc, integer h, integer v, integer cx, integer cy, integer r, double s, double e); #else static void draw_path(); static void draw_spline(); static void draw_ellipse(); static void draw_arc(); #endif struct tpic_object *tpic_object_list = NULL; #define TPIC_CODE(c1, c2) (((unsigned char)(c1) << 8) + (unsigned char)(c2)) /* return 1 if it was a tpic_special, 0 otherwise */ int tpic_special(pass, arg, x, y) int pass; char *arg; integer x, y; { static integer current_pen_size = 8; static unsigned tpic_flags = 0; static float shade = 0.0; static int npoints = 0; static int maxpoints = 0; static struct point *point_vector = 0; double dash_width; int complete = 0; while (*arg == ' ') arg++; if (arg[0] == '\0' || arg[1] == '\0' || (arg[2] != ' ' && arg[2] != '\0')) return 0; if (pass != PASS2) { switch (TPIC_CODE(arg[0], arg[1])) { case TPIC_CODE('p', 'n'): case TPIC_CODE('p', 'a'): case TPIC_CODE('s', 'p'): case TPIC_CODE('d', 'a'): case TPIC_CODE('d', 't'): case TPIC_CODE('i', 'p'): case TPIC_CODE('f', 'p'): case TPIC_CODE('i', 'a'): case TPIC_CODE('a', 'r'): case TPIC_CODE('s', 'h'): case TPIC_CODE('w', 'h'): case TPIC_CODE('b', 'k'): return 1; default: /* it's not a tpic special */ return 0; } } switch (TPIC_CODE(arg[0], arg[1])) { case TPIC_CODE('p', 'n'): { long n; if (sscanf(arg + 2, "%ld", &n) != 1) { message(ERROR, "bad argument to pn special"); return 1; } current_pen_size = n; break; } case TPIC_CODE('p', 'a'): { long x, y; if (sscanf(arg + 2, "%ld %ld", &x, &y) != 2) { message(ERROR, "bad arguments to pa special"); return 1; } if (npoints >= maxpoints) { if (maxpoints == 0) { point_vector = (struct point *) malloc((maxpoints = 5)*sizeof(struct point)); if (point_vector == NULL) out_of_memory(); } else { point_vector = (struct point *) realloc((char *)point_vector, sizeof(struct point)*(maxpoints *= 2)); if (point_vector == NULL) out_of_memory(); } } point_vector[npoints].x = x; point_vector[npoints].y = y; npoints++; break; } case TPIC_CODE('s', 'p'): { float f; if (sscanf(arg + 2, "%f", &f) == 1 && f != 0.0) { if (f > 0.0) { tpic_flags |= DASHED; dash_width = f; } else { tpic_flags |= DOTTED; dash_width = -f; } } tpic_flags |= SPLINE; goto path; } case TPIC_CODE('d', 'a'): { float f; if (sscanf(arg + 2, "%f", &f) != 1) { message(ERROR, "bad argument to da special"); return 1; } tpic_flags |= DASHED; dash_width = f; goto path; } case TPIC_CODE('d', 't'): { float f; if (sscanf(arg + 2, "%f", &f) != 1) { message(ERROR, "bad argument to dt special"); return 1; } tpic_flags |= DOTTED; dash_width = f; goto path; } case TPIC_CODE('i', 'p'): tpic_flags |= INVISIBLE; /* fall through */ case TPIC_CODE('f', 'p'): path: { struct tpic_object *p; size_t sz = sizeof(struct tpic_object); if (npoints > 2) sz += sizeof(struct point)*(npoints - 2); p = (struct tpic_object *)malloc(sz); if (p == NULL) out_of_memory(); p->flags = tpic_flags; if (tpic_flags & (DOTTED|DASHED)) p->u.p.dash_width = dash_width; tpic_flags = 0; memcpy((char *)p->u.p.point_vector, (char *)point_vector, npoints*sizeof(struct point)); p->u.p.npoints = npoints; npoints = 0; p->next = tpic_object_list; tpic_object_list = p; complete = 1; break; } case TPIC_CODE('i', 'a'): tpic_flags |= INVISIBLE; /* fall through */ case TPIC_CODE('a', 'r'): { struct tpic_object *p; long x, y; long rx, ry; float s, e; if (sscanf(arg + 2, "%ld %ld %ld %ld %f %f", &x, &y, &rx, &ry, &s, &e) != 6) { if (arg[0] == 'i') message(ERROR, "bad argument to ia special"); else message(ERROR, "bad argument to ar special"); return 1; } p = (struct tpic_object *)malloc(sizeof(struct tpic_object)); if (p == NULL) out_of_memory(); p->flags = ARC|tpic_flags; tpic_flags = 0; p->u.a.cx = x; p->u.a.cy = y; p->u.a.rx = rx; p->u.a.ry = ry; p->u.a.s = s; p->u.a.e = e; p->next = tpic_object_list; tpic_object_list = p; complete = 1; break; } case TPIC_CODE('s', 'h'): { float f; if (sscanf(arg + 2, "%f", &f) != 1) f = 0.5; tpic_flags |= SHADED; shade = f; break; } case TPIC_CODE('w', 'h'): tpic_flags |= SHADED; shade = 0.0; break; case TPIC_CODE('b', 'k'): tpic_flags |= SHADED; shade = 1.0; break; default: /* it's not a tpic special */ return 0; } if (complete) { /* we just completed an object, so fill in some details */ tpic_object_list->h = x; tpic_object_list->v = y; tpic_object_list->region = current_region; tpic_object_list->pen_size = current_pen_size; if (tpic_object_list->flags & DOTTED) tpic_object_list->pen_size += DOTTED_LINE_WIDTH_ADDITION; if (tpic_object_list->flags & SHADED) tpic_object_list->shade = shade; } return 1; } #define round(d) ((long)((d) + 0.5)) void p_tpic_list(psfp, page) FILE *psfp; struct page_info *page; { int r = NO_REGION; integer ox = 0, oy = 0; integer ps = -1; double sc = (254.0*page->den)/page->num; struct tpic_object *p = tpic_object_list; if (p == NULL) return; /* reverse tpic_object_list */ tpic_object_list = NULL; while (p != NULL) { struct tpic_object *tem = p; p = p->next; tem->next = tpic_object_list; tpic_object_list = tem; } fputs("BO TP\n", psfp); while (tpic_object_list != NULL) { p = tpic_object_list; if (p->region != r) { if (r != NO_REGION) fputs("GR\n", psfp); if (p->region != NO_REGION) { fputs("GS\n", psfp); do_transform(p->region, &ox, &oy, psfp); } else ox = oy = 0; r = p->region; } p->h -= ox; p->v -= oy; if (p->pen_size != ps) { ps = p->pen_size; put_dim(round(ps*sc), psfp); fputs(" LW\n", psfp); } if (p->flags & ARC) { integer cx, cy, rx, ry; double s, e; cx = p->u.a.cx; cy = p->u.a.cy; rx = p->u.a.rx; ry = p->u.a.ry; s = p->u.a.s; e = p->u.a.e; if (e - s >= M_PI*2.0) { if (p->flags & SHADED) { if (p->shade != 1.0) fprintf(psfp, "%g SG\n", 1 - p->shade); draw_ellipse(psfp, sc, p->h, p->v, cx, cy, rx, ry); fputs("FI\n", psfp); if (p->shade != 1.0) fputs("0 SG\n", psfp); } if (!(p->flags & INVISIBLE)) { draw_ellipse(psfp, sc, p->h, p->v, cx, cy, rx, ry); fputs("ST\n", psfp); } } else { if (rx != ry) message(WARNING, "open arc with rx != ry"); draw_arc(psfp, sc, p->h, p->v, cx, cy, rx, s, e); fputs("ST\n", psfp); } } else { int np = p->u.p.npoints; struct point *pv = p->u.p.point_vector; double dw = p->u.p.dash_width*1000.0; if (p->flags & SPLINE) { if (p->flags & DASHED) { put_dim(round(sc*dw), psfp); putc(' ', psfp); put_dim(round(sc*dw), psfp); fputs(" DH\n", psfp); } else if (p->flags & DOTTED) { fputs("0 ", psfp); put_dim(round(sc*dw), psfp); fputs(" DH\n", psfp); } draw_spline(psfp, sc, p->h, p->v, pv, np); fputs("ST\n", psfp); if (p->flags & (DOTTED|DASHED)) fputs("SO\n", psfp); } else { int closed = (np >= 2 && pv[0].x == pv[np - 1].x && pv[0].y == pv[np - 1].y); if (p->flags & SHADED) { if (p->shade != 1.0) fprintf(psfp, "%g SG\n", 1 - p->shade); draw_path(psfp, sc, p->h, p->v, pv, np - (closed != 0), 1); fputs("FI\n", psfp); if (p->shade != 1.0) fputs("0 SG\n", psfp); } if (!(p->flags & INVISIBLE)) { if (p->flags & DOTTED) { int i; for (i = 0; i < np - 1; i++) { double x = pv[i+1].x - pv[i].x; double y = pv[i+1].y - pv[i].y; double dist = sqrt(x*x + y*y); double adw; if (dist <= dw) adw = dist; else adw = dist/round(dist/dw); fputs("0 ", psfp); put_dim(round(sc*adw), psfp); fputs(" DH\n", psfp); draw_path(psfp, sc, p->h, p->v, pv + i, 2, 0); fputs("ST\n", psfp); } fputs("SO\n", psfp); } else if (p->flags & DASHED) { int i; for (i = 0; i < np - 1; i++) { double x = pv[i+1].x - pv[i].x; double y = pv[i+1].y - pv[i].y; double dist = sqrt(x*x + y*y); double adw, gw; if (dist <= dw*2.0) { adw = dist; gw = 0.0; } else { int ndashes = (int)(ceil((dist - dw)/(dw*2.0))); gw = (dist - dw)/ndashes - dw; adw = dw; } put_dim(round(sc*adw), psfp); putc(' ', psfp); put_dim(round(sc*gw), psfp); fputs(" DH\n", psfp); draw_path(psfp, sc, p->h, p->v, pv + i, 2, 0); fputs("ST\n", psfp); } fputs("SO\n", psfp); } else { draw_path(psfp, sc, p->h, p->v, pv, np - (closed != 0), closed); fputs("ST\n", psfp); } } } } tpic_object_list = tpic_object_list->next; free((char *)p); } if (r != NO_REGION) fputs("GR\n", psfp); fputs("EO\n", psfp); } static void draw_path(psfp, sc, ox, oy, pv, np, closed) FILE *psfp; double sc; integer ox, oy; struct point *pv; int np; int closed; { int i; put_dim(ox + round(pv[0].x*sc), psfp); putc(' ', psfp); put_dim(oy + round(pv[0].y*sc), psfp); fputs(" MT\n", psfp); for (i = 1; i < np; i++) { put_dim(ox + round(pv[i].x*sc), psfp); putc(' ', psfp); put_dim(oy + round(pv[i].y*sc), psfp); fputs(" LT\n", psfp); } if (closed) fputs("CP\n", psfp); } static void draw_spline(psfp, sc, ox, oy, pv, np) FILE *psfp; double sc; integer ox, oy; struct point *pv; int np; { int i; put_dim(ox + round(pv[0].x*sc), psfp); putc(' ', psfp); put_dim(oy + round(pv[0].y*sc), psfp); fputs(" MT\n", psfp); put_dim(ox + round((pv[0].x+pv[1].x)*sc/2.0), psfp); putc(' ', psfp); put_dim(oy + round((pv[0].y+pv[1].y)*sc/2.0), psfp); fputs(" LT\n", psfp); for (i = 1; i < np - 1; i++) { put_dim(ox + round((pv[i-1].x + 5*pv[i].x)*sc/6.0), psfp); putc(' ', psfp); put_dim(oy + round((pv[i-1].y + 5*pv[i].y)*sc/6.0), psfp); putc(' ', psfp); put_dim(ox + round((5*pv[i].x + pv[i+1].x)*sc/6.0), psfp); putc(' ', psfp); put_dim(oy + round((5*pv[i].y + pv[i+1].y)*sc/6.0), psfp); putc(' ', psfp); put_dim(ox + round((pv[i].x+pv[i+1].x)*sc/2.0), psfp); putc(' ', psfp); put_dim(oy + round((pv[i].y+pv[i+1].y)*sc/2.0), psfp); fputs(" CT\n", psfp); } put_dim(ox + round(pv[np - 1].x*sc), psfp); putc(' ', psfp); put_dim(oy + round(pv[np - 1].y*sc), psfp); fputs(" LT\n", psfp); } static void draw_ellipse(psfp, sc, ox, oy, cx, cy, rx, ry) FILE *psfp; double sc; integer ox, oy; integer cx, cy, rx, ry; { put_dim(round(rx*sc), psfp); putc(' ', psfp); put_dim(round(ry*sc), psfp); putc(' ', psfp); put_dim(ox + round(sc*cx), psfp); putc(' ', psfp); put_dim(oy + round(sc*cy), psfp); fputs(" EL\n", psfp); } static void draw_arc(psfp, sc, ox, oy, cx, cy, r, s, e) FILE *psfp; double sc; integer ox, oy; integer cx, cy, r; double s, e; { put_dim(ox + round(sc*cx), psfp); putc(' ', psfp); put_dim(oy + round(sc*cy), psfp); putc(' ', psfp); put_dim(round(sc*r), psfp); fprintf(psfp, " %g %g AR\n", s*180.0/M_PI, e*180.0/M_PI); } #endif /* Local Variables: c-indent-level: 4 c-continued-statement-offset: 4 c-brace-offset: -4 c-argdecl-indent: 0 c-label-offset: -4 tab-width: 4 End: */