/* This software may only be used by you under license from AT&T Corp. ("AT&T"). A copy of AT&T's Source Code Agreement is available at AT&T's Internet website having the URL: If you received this software without first entering into a license with AT&T, you have an infringing copy of this software and cannot use it without violating AT&T's intellectual property rights. */ #pragma prototyped /* TODO: * Use encoded form for polyline and polygon */ #include "render.h" #define SOLID 0 #define DOTTED 1 #define DASHED 2 #define INVIS 3 /* Convert point (1/72 inch) to hpgl units (0.025 mm) */ #define PT2UNIT(p) ((p)*(double)14.111) #define PENW 0.0138 #define NPENS 32 #define CX(_x) ((int)(_x)) #define CY(_y) ((int)(_y)) /* Origin of HP plotter from lower left corner, in points * This varies from plotter to plotter. We assume 1/4" and * hope for the best. */ #define HP_OX 18 #define HP_OY 18 static char *raw_prefix = ""; static char *raw_suffix = ""; #ifdef NOTUSED_ERG_MUST_KNOW_WHY static char *clr_prefix = "\033%-12345X@PJL ENTER LANGUAGE = HPGL2\n"; static char *clr_suffix = "\033%-12345X\n"; #endif static char *pcl_prefix = "\033E\n\033%%0B\n"; static char *pcl_suffix = "\033%%0A\n"; static int N_pages; /* static point Pages; */ static double Scale; static point Origin; static box PB; static int CurrentPen; static int ColorsUsed; static char *Sep = ";"; static int PageWidth; /* Width of page, in points. */ static char *prefix; /* Machine-dependent prefix and suffix */ static char *suffix; /* static boolean onetime = TRUE; */ #define MAXLINELEN 80 static int bufcnt; /* Number of characters output on current line */ static char * text_hdr = "LB"; static void output (char* str) { char *ptr = str; int len; while (*ptr != '\0') ptr++; len = ptr-str; if (bufcnt+len > MAXLINELEN) { fputs("\n", Output_file); bufcnt = 0; } fputs(str,Output_file); if ((len > 0) && (*(ptr-1) == '\n')) bufcnt = 0; else bufcnt += len; } static void output_text (char* str) { char *ptr = str; int len; char text_tail[32]; sprintf(text_tail,"\03%s\n",Sep); while (*ptr != '\0') ptr++; len = (ptr-str) + strlen(text_tail) + strlen(text_hdr); if (bufcnt+len > MAXLINELEN) { fputs("\n", Output_file); } fputs(text_hdr,Output_file); fputs(str,Output_file); fputs(text_tail,Output_file); bufcnt = 0; } #ifdef SMILE void doSmile (void) { fprintf(Output_file, "SP1SD1,341,2,1,4,14,5,0,6,0,7,5SSLO7PA%d,0LB\001\003IN\n", (int)PT2UNIT(PageWid-2*HP_OX)); } #endif static void setPen (int p) { char buffer[32]; sprintf(buffer, "SP%d%s", p, Sep); output (buffer); #ifdef HPDEBUG fprintf(stderr, "set pen %d\n", p); #endif CurrentPen = p; } typedef struct { int symbol; int spacing; int face; int bold; int italic; double size; } FontInfo; static FontInfo dfltFont = {277,1,5,0,0,14.0}; static FontInfo coordFont = {277,1,5,0,0,8.0}; static FontInfo nullFont = {0,0,0,0,0,0.0}; /* Font 0 is the stdfont; font 1 is the alt font */ typedef struct { FontInfo fonts[2]; int curfont; } FontState; static FontState fontState; static int eqFontInfo(FontInfo *fi1, FontInfo *fi2) { return ((fi1->face == fi2->face) && (fi1->spacing == fi2->spacing) && (fi1->bold == fi2->bold) && (fi1->italic == fi2->italic) && (fi1->size == fi2->size) && (fi1->symbol == fi2->symbol)); } typedef struct { unsigned char r, g, b; } Color; static int eqColor(Color *c1, Color *c2) { return ((c1->r == c2->r) && (c1->g == c2->g) && (c1->b == c2->b)); } static Color black = {0,0,0}; static Color white = {255,255,255}; static Color *colorlist; typedef struct _gc { int bold; int style; Color color; FontInfo font; struct _gc *prev; } GC; static GC *curGC; static void set_color (Color* cp) { int i; char buffer[32]; if (eqColor(cp,&curGC->color)) return; for(i=0;ir, cp->g, cp->b, Sep); colorlist[i] = *cp; output(buffer); #ifdef HPDEBUG fprintf(stderr, "set pen %d color %d %d %d\n", i, cp->r, cp->g, cp->b); #endif } setPen(i); curGC->color = *cp; } static void initColors (void) { colorlist = N_GNEW(NPENS,Color); colorlist[0] = white; colorlist[1] = black; ColorsUsed = 2; } static void destroyColors (void) { free (colorlist); ColorsUsed = 0; } static void setFont(FontInfo* fi) { int otherfont; char buffer[128]; if (eqFontInfo(fi,&fontState.fonts[fontState.curfont])) return; otherfont = (fontState.curfont?0:1); if (!eqFontInfo(fi,&fontState.fonts[otherfont])) { if (fi->spacing) sprintf(buffer,"%s1,%d,2,1,4,%.1f,5,%d,6,%d,7,%d%s", (otherfont?"AD":"SD"),fi->symbol, Scale*(fi->size),fi->italic,fi->bold,fi->face,Sep); else sprintf(buffer,"%s1,%d,2,0,3,%.1f,5,%d,6,%d,7,%d%s", (otherfont?"AD":"SD"),fi->symbol, (fi->size)/Scale,fi->italic,fi->bold,fi->face,Sep); output(buffer); } sprintf(buffer,"%s%s\n",(otherfont?"SA":"SS"), Sep); output(buffer); fontState.curfont = otherfont; fontState.fonts[otherfont] = *fi; curGC->font = *fi; } static void set_line_bold (int on) { char buffer[32]; if (on) { sprintf(buffer,"PW%.3f%s\n", 2*PENW, Sep); curGC->bold = TRUE; } else { sprintf(buffer,"PW%.3f%s\n", PENW, Sep); curGC->bold = FALSE; } output(buffer); } static void set_line_style(int sty) { char buffer[8]; char *opt = NULL; curGC->style = sty; switch(sty) { case SOLID : opt = "LT"; break; case DOTTED : opt = "LT1"; break; case DASHED : opt = "LT2"; break; case INVIS : default: return; } sprintf(buffer, "%s%s", opt, Sep); output (buffer); } static GC *makeGC(GC* old) { GC *newGC; newGC = GNEW(GC); if (old) *newGC = *old; else { newGC->bold = FALSE, newGC->style = SOLID, newGC->color = black; newGC->font = dfltFont; } newGC->prev = 0; return newGC; } static void initGC(void) { char buffer[32]; curGC = makeGC(0); /* Pick pen 1; set default pen width; set colors */ sprintf(buffer,"SP1%sPW%.3f%s\n", Sep, PENW, Sep); output(buffer); fontState.curfont = 1; setFont(&dfltFont); CurrentPen = 1; initColors(); } static void destroyGC(void) { GC *gc, *gc1; for(gc = curGC;gc;gc=gc1) { gc1 = gc->prev; free(gc); } curGC = 0; fontState.fonts[0] = nullFont; fontState.fonts[1] = nullFont; fontState.curfont = 1; destroyColors(); } static void saveGC(void) { GC *newGC; newGC = makeGC(curGC); newGC->prev = curGC; curGC = newGC; } static void restoreGC(void) { GC *gc, *newGC; gc = curGC; newGC = gc->prev; if (gc->bold != newGC->bold) set_line_bold(newGC->bold); if (gc->style != newGC->style) set_line_style(newGC->style); if (!eqColor(&gc->color, &newGC->color)) { #ifdef HPDEBUG fprintf(stderr, "restore color\n"); #endif set_color(&newGC->color); } if (!eqFontInfo(&gc->font,&newGC->font)) setFont(&newGC->font); free(gc); curGC = newGC; } static int isInvis(void) { return(curGC->style == INVIS); } #if 0 /* not used */ static double _Xalign; #define getTextAlign() (_Xalign) static void initTextAlign (void) { char buffer[20]; _Xalign = -0.5; sprintf(buffer,"LO4%s",Sep); output(buffer); } static int setTextAlign (double al) { char buffer[20]; char opt; if (al == 0.0) opt = '1'; else if (al == -1.0) opt = '7'; else if (al == -0.5) opt = '4'; else return 0; sprintf(buffer,"LO%c%s",opt,Sep); output(buffer); _Xalign = al; return 1; } #endif static void hpgl_reset(void) { /* onetime = TRUE; */ } static void hpgl_begin_job(FILE *ofp, graph_t *g, char **lib, char *user, char *info[], point pages) { /* Pages = pages; */ N_pages = pages.x * pages.y; } static void hpgl_end_job(void) { } static void hpgl_begin_graph(graph_t* g, box bb, point pb) { PB = bb; PageWidth = pb.x; if (Output_lang == PCL) { prefix = pcl_prefix; suffix = pcl_suffix; } else { prefix = raw_prefix; suffix = raw_suffix; } } static void hpgl_end_graph(void) { } static void hpgl_set_scale (double scx,double scy) { char buffer[64]; sprintf(buffer,"SC%.4f,%.4f,%.4f,%.4f,2%s\n", -Origin.x/scx, PT2UNIT(scx), -Origin.y/scy, PT2UNIT(scy), Sep); output(buffer); } static void hpgl_begin_page(graph_t *g, point page, double scale, int rot, point offset) { char buffer[64]; box clipWin; bufcnt = 0; Scale = scale; /* Initialize output */ output(prefix); sprintf(buffer,"BP%sIN%s", Sep, Sep); output(buffer); #ifdef SMILE doSmile(); #endif #if 0 /* not used */ initTextAlign(); #endif initGC(); if (N_pages > 1) { saveGC(); setFont(&coordFont); if (rot == 90) { sprintf(buffer,"RO90IP%s", Sep); output(buffer); } sprintf(buffer,"PA0,0%sLB(%d,%d)\03%s\n", Sep, page.x, page.y, Sep); output(buffer); if (rot == 90) { sprintf(buffer,"ROIP%s", Sep); output(buffer); } restoreGC(); } if (rot == 90) { /* Rotate layout. HPGL/2 automatically shifts * origin to bottom right corner, so we have to * use the page width to set the new origin. */ sprintf(buffer,"RO90IP%s", Sep); output(buffer); clipWin.LL.x = PB.LL.y-HP_OY-1; clipWin.LL.y = PageWidth-PB.UR.x-HP_OX-1; clipWin.UR.x = PB.UR.y-HP_OY+1; clipWin.UR.y = PageWidth-PB.LL.x-HP_OX+1; Origin.x = PB.LL.y + scale*offset.y - HP_OY; Origin.y = PageWidth - PB.LL.x - scale*offset.x - HP_OX; } else { clipWin.LL.x = PB.LL.x-HP_OX-1; clipWin.LL.y = PB.LL.y-HP_OY-1; clipWin.UR.x = PB.UR.x-HP_OX+1; clipWin.UR.y = PB.UR.y-HP_OY+1; Origin.x = PB.LL.x + scale*offset.x - HP_OX; Origin.y = PB.LL.y + scale*offset.y - HP_OY; } /* Set clipping window */ sprintf(buffer,"IW%d,%d,%d,%d%s\n", (int)PT2UNIT(clipWin.LL.x), (int)PT2UNIT(clipWin.LL.y), (int)PT2UNIT(clipWin.UR.x), (int)PT2UNIT(clipWin.UR.y), Sep); /* output(buffer); */ /* Turn off clipping. */ hpgl_set_scale(scale,scale); } static void hpgl_end_page(void) { char buffer[32]; sprintf(buffer,"PU%sSP0%sPG;\n", Sep, Sep); /* pen up; advance page */ output(buffer); output(suffix); destroyGC(); } static void hpgl_begin_cluster(graph_t* g) { } static void hpgl_end_cluster (void) { } static void hpgl_begin_nodes(void) { } static void hpgl_end_nodes(void) { } static void hpgl_begin_edges(void) { } static void hpgl_end_edges(void) { } static void hpgl_begin_node(node_t* n) { } static void hpgl_end_node (void) { } static void hpgl_begin_edge (edge_t* e) { } static void hpgl_end_edge (void) { } static void hpgl_begin_context(void) { saveGC(); } static void hpgl_end_context(void) { restoreGC(); } static void mkFontCanon (char *old, char *new) { char c; while ((c = *old++)) { if (isalnum(c) == FALSE) continue; if (isupper(c)) c = tolower(c); *new++ = c; } *new = c; } /* factors for turning font size, in points, * to pitches, in chars per inch, for fixed pitch fonts. */ static double courierPitch = 110.76923; static double stickPitch = 102.85714; typedef struct { char *name; int symbol; double *spacing; int face; int italic; int bold; } FontIndex; static FontIndex fontIndex[] = { { "timesroman", 277, 0, 5, 0, 0 }, { "timesbold", 277, 0, 5, 0, 3 }, { "timesitalic", 277, 0, 5, 1, 0 }, { "timesbolditalic", 277, 0, 5, 1, 3 }, { "helvetica", 277, 0, 4, 0, 0 }, { "helveticabold", 277, 0, 4, 0, 3 }, { "helveticaoblique", 277, 0, 4, 1, 0 }, { "helveticaboldoblique", 277, 0, 4, 1, 3 }, { "courier", 277, &courierPitch, 3, 0, 0 }, { "courierbold", 277, &courierPitch, 3, 0, 3 }, { "courieroblique", 277, &courierPitch, 3, 1, 0 }, { "courierboldoblique", 277, &courierPitch, 3, 1, 3 }, { "palatinoroman", 277, 0, 15, 0, 0 }, { "palatinobold", 277, 0, 15, 0, 3 }, { "palatinoitalic", 277, 0, 15, 1, 0 }, { "palatinobolditalic", 277, 0, 15, 1, 3 }, { "stickcw", 277, &stickPitch, 48, 0, 0 }, { "stick", 277, 0, 48, 0, 0 }, { "zapfdingbats", 332, 0, 45, 0, 0 }, { "symbol", 173, 0, 5, 0, 0 } }; static void mkFontInfo(char* name, double size, FontInfo* fip) { int i; char buf[128]; FontIndex *fi; mkFontCanon(name,buf); fi = fontIndex; for(i=0;iname)) break; fi++; } fip->symbol = fi->symbol; fip->italic = fi->italic; fip->bold = fi->bold; fip->face = fi->face; if (fi->spacing) { /* fixed spacing */ fip->spacing = 0; fip->size = (*(fi->spacing))/size; } else { /* proportional spacing */ fip->spacing = 1; fip->size = size; } } static void hpgl_set_font(char* name, double size) { static FontInfo fi; mkFontInfo(name,size,&fi); setFont(&fi); } static void hpgl_set_color(char* name) { color_t color; #ifdef HPDEBUG fprintf (stderr, "set color %s\n", name); #endif colorxlate(name,&color,RGBA_BYTE); set_color ((Color *)color.u.rgba); } static void hpgl_set_style(char** s) { char *line; while ((line = *s++)) { if (streq(line,"solid")) set_line_style (SOLID); else if (streq(line,"dashed")) set_line_style (DASHED); else if (streq(line,"dotted")) set_line_style (DOTTED); else if (streq(line,"invis")) set_line_style (INVIS); else if (streq(line,"bold")) set_line_bold (TRUE); else if (streq(line,"filled")) { /* no-op */ } else if (streq(line,"unfilled")) { /* no-op */ } else { agerr(AGERR, "hpgl_set_style: unsupported style %s - ignoring\n", line); } } } static void hpgl_textline(point p, textline_t *line) { char buffer[128]; char *str = line->str; if (isInvis()) return; switch(line->just) { case 'l': break; case 'r': p.x -= line->width; break; default: case 'n': p.x -= line->width / 2; break; } sprintf(buffer,"PA%d,%d%s",CX(p.x),CY(p.y), Sep); output(buffer); output_text(str); #ifdef HPDEBUG fprintf(stderr, "text =%s=\n", str); #endif } static int firstSeg; #define FLATNESS 1.0 static int isFlat (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3) { double sa, ca, y, O = y3 - y0, A = x3 - x0, H = sqrt (O*O + A*A); if (H == 0) return TRUE; sa = O / H, ca = A / H; y = - sa * (x1 - x0) + ca * (y1 - y0); if (y > FLATNESS || y < -FLATNESS) return FALSE; y = - sa * (x2 - x0) + ca * (y2 - y0); return y <= FLATNESS && y >= -FLATNESS; } static void Bzier (double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3) { char buffer[64]; if (isFlat(x0, y0, x1, y1, x2, y2, x3, y3)) { if(firstSeg) { sprintf(buffer,"%d,%d",CX(x3),CY(y3)); firstSeg = 0; } else { sprintf(buffer,",%d,%d",CX(x3),CY(y3)); } output(buffer); return; } Bzier (x0, y0, (x0 + x1) / 2, (y0 + y1) / 2, (x0 + x2) / 4 + x1 / 2, (y0 + y2) / 4 + y1 / 2, (x0 + x3) / 8 + 3 * (x1 + x2) / 8, (y0 + y3) / 8 + 3 * (y1 + y2) / 8); Bzier ((x0 + x3) / 8 + 3 * (x1 + x2) / 8, (y0 + y3) / 8 + 3 * (y1 + y2) / 8, (x1 + x3) / 4 + x2 / 2, (y1 + y3) / 4 + y2 / 2, (x2 + x3) / 2, (y2 + y3) / 2, x3, y3); } static void hpgl_bezier(point *A, int n, int arrow_at_start, int arrow_at_end) { char buffer[32]; int j; if (arrow_at_start || arrow_at_end) agerr(AGERR, "hpgl_bezier illegal arrow args\n"); if (isInvis()) return; sprintf(buffer,"PA%d,%d%sPD",CX(A[0].x),CY(A[0].y), Sep); output(buffer); firstSeg = 1; for (j = 1; j < n; j += 3) Bzier((double)A[j-1].x,(double)A[j-1].y, (double)A[j].x,(double)A[j].y, (double)A[j+1].x,(double)A[j+1].y, (double)A[j+2].x,(double)A[j+2].y); sprintf(buffer,"%sPU%s\n", Sep, Sep); output(buffer); } static void hpgl_polygon(point *A, int n, int filled) { int j; char buffer[64]; if (isInvis()) return; sprintf(buffer,"PA%d,%d%sPM0%sPD",CX(A[0].x),CY(A[0].y),Sep,Sep); output(buffer); for (j = 1; j < n-1; j ++) { sprintf(buffer,"%d,%d,",CX(A[j].x),CY(A[j].y)); output(buffer); } sprintf(buffer,"%d,%d%sPM2%sPU%s",CY(A[n-1].x),CY(A[n-1].y), Sep,Sep,Sep); output(buffer); if (filled) { #ifdef HPDEBUG fprintf(stderr, "fill pen %d\n", CurrentPen); #endif if (CurrentPen == 1) { sprintf(buffer,"FP%sLT%sEP%sLT99%s\n",Sep,Sep,Sep,Sep); } else { sprintf(buffer,"FP%sSP1%sLT%sEP%sSP%d%sLT99%s\n", Sep,Sep,Sep,Sep,CurrentPen,Sep,Sep); } } else { sprintf(buffer, "EP%s\n", Sep); } output(buffer); } /***** Arrowheads now centralized in emit.c static void hpgl_arrowhead(point p,double theta,double scale,int flag) { point sp,ep; double costh, sinth,arroww2,arrowl; char buffer[128]; if (isInvis()) return; costh = cos(RADIANS(theta)); sinth = sin(RADIANS(theta)); arrowl = ARROW_LENGTH * scale; arroww2 = ARROW_WIDTH * scale / 2.0; sp.x = p.x + arrowl*costh + arroww2*sinth; sp.y = p.y + arrowl*sinth - arroww2*costh; ep.x = p.x + arrowl*costh - arroww2*sinth; ep.y = p.y + arrowl*sinth + arroww2*costh; sprintf(buffer,"PA%d,%d%sPM0%sPD%d,%d,%d,%d%sPM2%sPU%sFP%s\n", CX(sp.x),CY(sp.y),Sep,Sep, CX(p.x),CY(p.y),CX(ep.x),CY(ep.y), Sep, Sep, Sep, Sep); output(buffer); } **********/ static void hpgl_ellipse(point p,int rx,int ry,int filled) { char buffer[128]; if (isInvis()) return; sprintf(buffer,"PA%d,%d%s",p.x,p.y,Sep); output(buffer); hpgl_set_scale(Scale*rx,Scale*ry); if (filled) { if (CurrentPen == 1) sprintf(buffer,"WG1,0,360%sLT%sEW1,0,360%sLT99%s",Sep,Sep,Sep,Sep); else sprintf(buffer,"WG1,0,360%sSP1%sLT%sEW1,0,360%sSP%d%sLT99%s", Sep,Sep,Sep,Sep,CurrentPen,Sep,Sep); } else sprintf(buffer,"EW1,0,360%s", Sep); output(buffer); hpgl_set_scale(Scale,Scale); } /* Use encoded form */ static void hpgl_polyline(point* A, int n) { int j; char buffer[64]; if (isInvis()) return; sprintf(buffer,"PA%d,%d%sPD",CX(A[0].x),CY(A[0].y), Sep); output(buffer); for (j = 1; j < n-1; j ++) { sprintf(buffer,"%d,%d,",CX(A[j].x),CY(A[j].y)); output(buffer); } sprintf(buffer,"%d,%d%sPU%s\n",CX(A[n-1].x),CY(A[n-1].y),Sep,Sep); output(buffer); } static void hpgl_user_shape(char *name, point *A, int n, int filled) { static boolean onetime = TRUE; if (onetime) { agerr(AGERR, "custom shapes not available with this driver\n"); onetime = FALSE; } } codegen_t HPGL_CodeGen = { hpgl_reset, hpgl_begin_job, hpgl_end_job, hpgl_begin_graph, hpgl_end_graph, hpgl_begin_page, hpgl_end_page, hpgl_begin_cluster, hpgl_end_cluster, hpgl_begin_nodes, hpgl_end_nodes, hpgl_begin_edges, hpgl_end_edges, hpgl_begin_node, hpgl_end_node, hpgl_begin_edge, hpgl_end_edge, hpgl_begin_context, hpgl_end_context, hpgl_set_font, hpgl_textline, hpgl_set_color, hpgl_set_color, hpgl_set_style, hpgl_ellipse, hpgl_polygon, hpgl_bezier, hpgl_polyline, 0 /* hpgl_arrowhead */, hpgl_user_shape, 0 /* hpgl_comment */, 0 /* hpgl_textsize */ };