/* See pswr.h */ /* Last edited on 2004-04-10 22:46:29 by stolfi */ #include #include #include #include #include #include #include #include #include #include /* One millimeter in points: */ #define mm (72.0/25.4) /* STREAM CREATION AND FINALIZATION */ PSStream *pswr_new_stream ( bool eps, /* TRUE for EPS figures, FALSE for PS document. */ char *name, /* File name or prefix. */ FILE *file, /* Optional open file handle. */ char *paperSize, /* Paper size ({letter}, {a3}, etc.). */ double hPageSize, /* Total page/figure width (in pt). */ double vPageSize /* Total page/figure height (in pt). */ ) { PSStream *ps = (PSStream *)notnull(malloc(sizeof(PSStream)), "out of mem"); ps->verbose = FALSE; /* For now. */ ps->eps = eps; ps->name = txtcat(name, ""); ps->file = file; if (eps || (paperSize == NULL) || (strlen(paperSize) == 0)) { /* Ignore the {paperSize} string, use the given page dimensions: */ ps->paperSize = NULL; } else { /* Get page dimensions from the {paperSize} string: */ ps->paperSize = txtcat(paperSize, ""); pswr_get_paper_dimensions(paperSize, &(hPageSize), &(vPageSize)); } if ((hPageSize <= 0) || (vPageSize <= 0)) { fprintf(stderr, "pageSize = %6.1f × %6.1f\n", hPageSize, vPageSize); affirm(FALSE, "invalid pageSize"); } ps->hPageSize = hPageSize; ps->vPageSize = vPageSize; /* Clear font list: */ ps->fonts = NULL; ps->nfonts = 0; if (! eps) { /* Ensure file is open: */ if (ps->file == NULL) { char *fileName = txtcat(ps->name, ".ps"); ps->file = open_write(fileName); free(fileName); } /* Write file preamble: */ pswr_begin_document(ps); } /* Define the stream's state: */ ps->curPage = 0; ps->curSlot = INT_MAX; /* Indicates between-pages state */ /* Default page layout: */ if (eps) { pswr_set_page_layout(ps, 0, 0, TRUE, 4.0, 4.0, 0, 1, 1); } else { pswr_set_page_layout(ps, 0, 0, TRUE, 72.0, 72.0, 5, 1, 1); } return ps; } void pswr_close_stream(PSStream *ps) { if (pswr_within_page(ps)) { pswr_end_page(ps); } if (! ps->eps) { pswr_end_document(ps); } free(ps->paperSize); free(ps->name); free(ps); } /* DEFINING THE PAGE LAYOUT */ void pswr_set_page_size ( PSStream *ps, /* Picture stream. */ double hPageSize, /* Width of each picture (in pt). */ double vPageSize /* Height of each picture (in pt). */ ) { if (ps->eps) { /* If page in progress, flush it: */ if (pswr_within_page(ps)) { pswr_end_page(ps); } ps->hPageSize = hPageSize; ps->vPageSize = vPageSize; pswr_set_page_layout(ps, 0, 0, TRUE, 4.0, 4.0, 0, 1, 1); } else { fprintf(stderr, "pswr_set_page_size ignored (not EPS stream)\n"); } } void pswr_set_page_layout ( PSStream *ps, /* Picture stream. */ double hPicSize, /* Width of each picture (in pt). */ double vPicSize, /* Height of each picture (in pt). */ bool adjustPicSize, /* TRUE to fit {hPicSize,vPicSize} to page size. */ double hPicMargin, /* Left/right margin for each picture (in pt). */ double vPicMargin, /* Top/bottom margin for each picture (in pt). */ int captionLines, /* Number of caption lines below each picture. */ int hCount, /* Number of pictures in each row. */ int vCount /* Number of pictures in each column. */ ) { /* If page in progress, flush it: */ if (pswr_page_dirty(ps)) { pswr_end_page(ps); } /* Get page dimensions: */ double hPageSize = ps->hPageSize; double vPageSize = ps->vPageSize; /* Compute and save requested caption space: */ if (captionLines < 0) { captionLines = 0; } double vCapSize = 10.0*((double)captionLines); /* Caption height (in pt). */ ps->captionLines = captionLines; /* Save picture margins: */ ps->hPicMargin = hPicMargin; ps->vPicMargin = vPicMargin; /* Choose default page margin: */ double hPageMargin, vPageMargin; if (ps->eps) { hPageMargin = vPageMargin = 4.0; } else { hPageMargin = vPageMargin = 72.0; } /* Compute area of page that is available for picture slots, */ /* allowing picture margins and bottom caption to invade page margins: */ double hUsableSize, vUsableSize; { double hXPageMargin = (hPageMargin < hPicMargin ? 0 : hPageMargin - hPicMargin); double tXPageMargin = (vPageMargin < vPicMargin ? 0 : vPageMargin - vPicMargin); double bXPageMargin = (vPageMargin < vPicMargin + vCapSize ? 0 : vPageMargin - vPicMargin - vCapSize); hUsableSize = hPageSize - 2*hXPageMargin; vUsableSize = vPageSize - tXPageMargin - bXPageMargin; } /* (Re)compute slot counts and dimensions, if necessary: */ double hSlotSize, vSlotSize; pswr_fix_slot_size(hUsableSize, hPicMargin, 0.0, &hCount, &hPicSize, &hSlotSize); pswr_fix_slot_size(vUsableSize, vPicMargin, vCapSize, &vCount, &vPicSize, &vSlotSize); /* Adjust sizes to fit page, if so requested: */ if (adjustPicSize) { /* Area that is available for pictures (minus pic margins and captions): */ double hPlottableSize = hUsableSize - hCount*2*hPicMargin; double vPlottableSize = vUsableSize - vCount*(2*vPicMargin + vCapSize); /* Maximum picture magnification factors in each direction: */ double hMag = hPlottableSize / (hCount * hPicSize); double vMag = vPlottableSize / (vCount * vPicSize); /* Picture magnification factor: */ double mag = (hMag < vMag ? hMag : vMag); /* Adjust picture size: */ hPicSize *= mag; vPicSize *= mag; /* Adjust slot size (preserving margins and captions): */ hSlotSize = hPicSize + 2*hPicMargin; vSlotSize = vPicSize + 2*vPicMargin + vCapSize; } if (ps->verbose) { fprintf(stderr, "-- page layout --\n"); fprintf(stderr, " pageSize = %6.1f × %6.1f\n", hPageSize, vPageSize); fprintf(stderr, " pageMargin = %6.1f × %6.1f\n", hPageMargin, vPageMargin); fprintf(stderr, " slotSize = %6.1f × %6.1f\n", hSlotSize, vSlotSize); fprintf(stderr, " picSize = %6.1f × %6.1f\n", hPicSize, vPicSize); fprintf(stderr, " picMargin = %6.1f × %6.1f\n", hPicMargin, vPicMargin); fprintf(stderr, " count = %6d × %6d\n", hCount, vCount); } /* Check for page overflow: */ if (hSlotSize*hCount - 2*hPicMargin > hPageSize) { fprintf(stderr, "warning -- pictures too wide for page\n"); } if (vSlotSize*vCount - 2*vPicMargin > vPageSize) { fprintf(stderr, "warning -- pictures too tall for page\n"); } /* Compute top left corner of first slot in page: */ double hFirst = (hPageSize - hCount*hSlotSize)/2.0; double hFirstMin = (ps->eps ? 0.0 : 36.0) - hPicMargin; if (hFirst < hFirstMin) { hFirst = hFirstMin; } double vFirst = vPageSize - (vPageSize - vCount*vSlotSize)/2.0; double vFirstMax = vPageSize - ((ps->eps ? 0.0 : 36.0) - hPicMargin); if (vFirst > vFirstMax) { vFirst = vFirstMax; } /* Save layout parameters: */ ps->hPicSize = hPicSize; ps->vPicSize = vPicSize; ps->hSlotSize = hSlotSize; ps->vSlotSize = vSlotSize; ps->hFirst = hFirst; ps->vFirst = vFirst; ps->hCount = hCount; ps->vCount = vCount; } /* START OF NEW PAGE */ void pswr_new_page(PSStream *ps, const char *pageName) { if (pswr_within_page(ps)) { pswr_end_page(ps); } pswr_begin_page(ps, pageName); affirm(pswr_within_page(ps), "duh?"); affirm(! pswr_page_dirty(ps), "duh?"); } void pswr_sync_page(PSStream *ps, const char *pageName) { if (pswr_page_dirty(ps)) { pswr_new_page(ps, pageName); } affirm(! pswr_page_dirty(ps), "duh?"); } void pswr_fill_row(PSStream *ps) { if ((pswr_within_page(ps)) && (ps->curSlot >= 0)) { int leftSlot = (ps->curSlot % ps->hCount) * ps->hCount; ps->curSlot = leftSlot + ps->hCount - 1; } } void pswr_fill_page(PSStream *ps) { if (pswr_within_page(ps)) { ps->curSlot = ps->hCount*ps->vCount - 1; affirm(! pswr_next_slot_available(ps), "duh?"); } } /* START OF NEW PICTURE */ void pswr_new_picture ( PSStream *ps, /* Postscript picture stream. */ double xMin, double xMax, /* Client X plotting range. */ double yMin, double yMax /* Client Y plotting range. */ ) { /* Make sure that there is a current page: */ if (! pswr_within_page(ps)) { pswr_begin_page(ps, NULL); } /* Make sure that there is a next slot in the page: */ if (! pswr_next_slot_available(ps)) { /* Page exhausted, start a new one: */ pswr_end_page(ps); pswr_begin_page(ps, NULL); affirm(pswr_next_slot_available(ps), "duh?"); } /* Advance to that slot: */ int nextSlot = ps->curSlot+1; affirm((nextSlot >= 0) && (nextSlot < ps->hCount*ps->vCount), "duh?"); /* Get row and column indices of slot: */ int hIndex = nextSlot % ps->hCount; int vIndex = nextSlot / ps->hCount; /* Get actual plot window {[hmin_hmax]×[vmin_vmax]} for this slot: */ double hPicSize = ps->hPicSize; double vPicSize = ps->vPicSize; double hMin = ps->hFirst + hIndex*ps->hSlotSize + ps->hPicMargin; double vMax = ps->vFirst - vIndex*ps->vSlotSize - ps->vPicMargin; double hMax = hMin + hPicSize; double vMin = vMax - vPicSize; /* Adjust plot rectangle to fit client aspect ratio: */ double hScale = hPicSize/(xMax - xMin); double vScale = vPicSize/(yMax - yMin); double rh = hPicSize/2*(hScale <= vScale ? 1.0 : vScale/hScale); double rv = vPicSize/2*(vScale <= hScale ? 1.0 : hScale/vScale); double hCtr = (hMax + hMin)/2; double vCtr = (vMax + vMin)/2; pswr_set_window ( ps, xMin, xMax, yMin, yMax, hCtr-rh, hCtr+rh, vCtr-rv, vCtr+rv, 1,1 ); /* Fix the current slot, which was clobbered by {pswr_set_window}: */ ps->curSlot = nextSlot; /* Reset graphics state: */ pswr_set_pen(ps, 0.0,0.0,0.0, 0.15, 0.0,0.0); pswr_set_label_font(ps, "Courier", 10.0); if (ps->verbose) { fprintf(stderr, "-- plot ranges --\n"); fprintf ( stderr, " client [%8.4f _ %8.4f] x [%8.4f _ %8.4f]\n", xMin, xMax, yMin, yMax ); fprintf ( stderr, " device [%8.4f _ %8.4f] x [%8.4f _ %8.4f]\n", hCtr-rh, hCtr+rh, vCtr-rv, vCtr+rv ); } } /* PLOTTING WINDOW */ void pswr_set_window ( PSStream *ps, double xmin, double xmax, double ymin, double ymax, double hmin, double hmax, double vmin, double vmax, int xn, int yn ) { affirm(pswr_within_page(ps), "bad state"); /* Tell {pswr_new_picture} that the page is all full: */ ps->curSlot = ps->hCount*ps->vCount - 1; /* Save the window parameters in the "PSStream" record: */ pswr_save_window_data ( ps, xmin, xmax, ymin, ymax, hmin, hmax, vmin, vmax, xn, yn ); /* Set the window up in the Postcript file: */ FILE *file = ps->file; pswr_write_window_setup_cmds(file, hmin, hmax, vmin, vmax, xn, yn); fflush(file); } /* DRAWING COMMANDS */ void pswr_set_pen ( PSStream *ps, double R, double G, double B, double width, double dashlength, double dashspace ) { affirm(pswr_within_page(ps), "bad state"); FILE *file = ps->file; fprintf(file, "%5.3f %5.3f %5.3f setrgbcolor\n", R, G, B); fprintf(file, "%.3f setlinewidth\n", width * mm); if ((dashlength == 0.0) | (dashspace == 0.0)) { fprintf(file, " [ ] 0 setdash\n"); } else { fprintf(file, " [ %.3f %.3f ] 0 setdash\n", dashlength * mm, dashspace * mm ); } } void pswr_segment ( PSStream *ps, double xa, double ya, double xb, double yb ) { affirm(pswr_within_page(ps), "bad state"); double psxa = ps->hmin + ps->xscale * (xa - ps->xmin); double psya = ps->vmin + ps->yscale * (ya - ps->ymin); double psxb = ps->hmin + ps->xscale * (xb - ps->xmin); double psyb = ps->vmin + ps->yscale * (yb - ps->ymin); if (pswr_segment_is_invisible(ps, psxa, psya, psxb, psyb)) { return; } FILE *file = ps->file; fprintf(file, "%6.1f %6.1f %6.1f %6.1f segd\n", psxa, psya, psxb, psyb ); } void pswr_curve ( PSStream *ps, double xa, double ya, double xb, double yb, double xc, double yc, double xd, double yd ) { affirm(pswr_within_page(ps), "bad state"); double psxa = ps->hmin + ps->xscale * (xa - ps->xmin); double psya = ps->vmin + ps->yscale * (ya - ps->ymin); double psxb = ps->hmin + ps->xscale * (xb - ps->xmin); double psyb = ps->vmin + ps->yscale * (yb - ps->ymin); double psxc = ps->hmin + ps->xscale * (xc - ps->xmin); double psyc = ps->vmin + ps->yscale * (yc - ps->ymin); double psxd = ps->hmin + ps->xscale * (xd - ps->xmin); double psyd = ps->vmin + ps->yscale * (yd - ps->ymin); if (pswr_curve_is_invisible(ps, psxa, psya, psxb, psyb, psxc, psyc, psxd, psyd)) { return; } FILE *file = ps->file; fprintf(file, "%6.1f %6.1f %6.1f %6.1f %6.1f %6.1f %6.1f %6.1f arcd\n", psxa, psya, psxb, psyb, psxc, psyc, psxd, psyd ); } void pswr_coord_line(PSStream *ps, PSAxis axis, double pos) { affirm(pswr_within_page(ps), "bad state"); double pspos; if (axis == HOR) { pspos = ps->hmin + ps->xscale * (pos - ps->xmin); } else if (axis == VER) { pspos = ps->vmin + ps->yscale * (pos - ps->ymin); } else { affirm(FALSE, "invalid axis"); pspos = 0.0; } FILE *file = ps->file; fprintf(file, "%6.1f %sgrd\n", pspos, (axis == HOR ? "x" : "y")); } void pswr_axis(PSStream *ps, PSAxis axis, double pos, double lo, double hi) { affirm(pswr_within_page(ps), "bad state"); if (axis == HOR) { pswr_segment(ps, lo, pos, hi, pos); } else if (axis == VER) { pswr_segment(ps, pos, lo, pos, hi); } else { affirm(FALSE, "invalid axis"); } } void pswr_tick ( PSStream *ps, PSAxis axis, double xc, double yc, double ticksz, double align ) { affirm(pswr_within_page(ps), "bad state"); FILE *file = ps->file; double psxc = ps->hmin + ps->xscale * (xc - ps->xmin); double psyc = ps->vmin + ps->yscale * (yc - ps->ymin); double psxa, psya, psxb, psyb; if (axis == HOR) { psxa = psxb = psxc; psya = psyc - align*ticksz*mm; psyb = psyc + (1-align)*ticksz*mm; } else if (axis == VER) { psxa = psxc - align*ticksz*mm; psxb = psxc + (1-align)*ticksz*mm; psya = psyb = psyc; } else { affirm(FALSE, "invalid axis"); psxa = psxb = psya = psyb = 0.0; } if (pswr_segment_is_invisible(ps, psxa, psya, psxb, psyb)) { return; } fprintf(file, "%6.1f %6.1f %6.1f %6.1f segd\n", psxa, psya, psxb, psyb ); } void pswr_grid_lines(PSStream *ps) { affirm(pswr_within_page(ps), "bad state"); FILE *file = ps->file; fprintf(file, "gridlines\n"); } void pswr_frame(PSStream *ps) { affirm(pswr_within_page(ps), "bad state"); FILE *file = ps->file; fprintf(file, "wframe\n"); } void pswr_set_fill_color(PSStream *ps, double R, double G, double B) { affirm(pswr_within_page(ps), "bad state"); if (R < 0.0) { R = G = B = -1.0; } double *fc = ps->fillColor; if ((R != fc[0]) || (G != fc[1]) || (B != fc[2])) { FILE *file = ps->file; fc[0] = R; fc[1] = G; fc[2] = B; pswr_write_fill_color_set_cmd(file, fc); } } void pswr_rectangle ( PSStream *ps, double xlo, double xhi, double ylo, double yhi, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } FILE *file = ps->file; double psxlo = ps->hmin + ps->xscale * (xlo - ps->xmin); double psxhi = ps->hmin + ps->xscale * (xhi - ps->xmin); double psylo = ps->vmin + ps->yscale * (ylo - ps->ymin); double psyhi = ps->vmin + ps->yscale * (yhi - ps->ymin); if (pswr_rectangle_is_invisible(ps, psxlo, psxhi, psylo, psyhi)) { return; } fprintf(file, "%d %d %6.1f %6.1f %6.1f %6.1f", draw, fill, psxlo, psxhi, psylo, psyhi ); fprintf(file, " rec\n"); fflush(file); } void pswr_triangle ( PSStream *ps, double xa, double ya, double xb, double yb, double xc, double yc, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } double psxa = ps->hmin + ps->xscale * (xa - ps->xmin); double psya = ps->vmin + ps->yscale * (ya - ps->ymin); double psxb = ps->hmin + ps->xscale * (xb - ps->xmin); double psyb = ps->vmin + ps->yscale * (yb - ps->ymin); double psxc = ps->hmin + ps->xscale * (xc - ps->xmin); double psyc = ps->vmin + ps->yscale * (yc - ps->ymin); if (pswr_triangle_is_invisible(ps, psxa, psya, psxb, psyb, psxc, psyc)) { return; } FILE *file = ps->file; fprintf(file, "%d %d %6.1f %6.1f %6.1f %6.1f %6.1f %6.1f ", draw, fill, psxa, psya, psxb, psyb, psxc, psyc ); fprintf(file, " tri\n"); fflush(file); } void pswr_polygon ( PSStream *ps, double x[], double y[], int npoints, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } double *psx = (double *)malloc(npoints*sizeof(double)); double *psy = (double *)malloc(npoints*sizeof(double)); int i; /* Map points to device coordinates: */ for (i=0; ihmin + ps->xscale * (x[i] - ps->xmin); psy[i] = ps->vmin + ps->yscale * (y[i] - ps->ymin); } if (! pswr_polygon_is_invisible(ps, psx, psy, npoints)) { /* Plot them: */ FILE *file = ps->file; fprintf(file, "%d %d", draw, fill); if (npoints>6) fprintf(file, "\n"); for (i=0; i0) fprintf(file, "\n"); } else { fprintf(file, " "); } fprintf(file, "%6.1f %6.1f", psxi, psyi); } if (npoints > 6) fprintf(file, "\n"); fprintf(file, " %d", npoints); fprintf(file, " pol\n"); fflush(file); } free(psx); free(psy); } void pswr_circle ( PSStream *ps, double xc, double yc, double rad, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } double psxc = ps->hmin + ps->xscale * (xc - ps->xmin); double psyc = ps->vmin + ps->yscale * (yc - ps->ymin); double psrad = ps->yscale * rad; if (pswr_circle_is_invisible(ps, psxc, psyc, psrad)) { return; } FILE *file = ps->file; fprintf(file, "%d %d %6.1f %6.1f %6.1f", draw, fill, psxc, psyc, psrad); fprintf(file, " cir\n"); fflush(file); } void pswr_dot ( PSStream *ps, double xc, double yc, double rad, bool fill, bool draw ) { if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } FILE *file = ps->file; double psxc = ps->hmin + ps->xscale * (xc - ps->xmin); double psyc = ps->vmin + ps->yscale * (yc - ps->ymin); if (pswr_circle_is_invisible(ps, psxc, psyc, rad * mm)) { return; } fprintf(file, "%d %d %6.1f %6.1f %6.1f", draw, fill, psxc, psyc, rad * mm); fprintf(file, " cir\n"); fflush(file); } void pswr_arrowhead ( PSStream *ps, double xa, double ya, double xb, double yb, double width, double length, double fraction, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } /* Seg endpoints in device coords: */ double psxa = ps->xscale * (xa - ps->xmin); double psya = ps->yscale * (ya - ps->ymin); double psxb = ps->xscale * (xb - ps->xmin); double psyb = ps->yscale * (yb - ps->ymin); /* Unit direction vector: */ double dx = psxb - psxa; double dy = psyb - psya; double d = sqrt(dx*dx + dy*dy); dx /= d; dy /= d; /* Arrow dimensions in device units: */ double psw = width/2.0 * mm; double psh = length * mm; /* Corners of triangle: */ double noitcarf = 1.0 - fraction; double psxt = ps->hmin + noitcarf*psxa + fraction*psxb; double psyt = ps->vmin + noitcarf*psya + fraction*psyb; double psxu = psxt - psh * dx + psw * dy; double psyu = psyt - psh * dy - psw * dx; double psxv = psxt - psh * dx - psw * dy; double psyv = psyt - psh * dy + psw * dx; if (pswr_triangle_is_invisible(ps, psxt, psyt, psxu, psyu, psxv, psyv)) { return; } FILE *file = ps->file; fprintf(file, "%d %d %6.1f %6.1f %6.1f %6.1f %6.1f %6.1f", draw, fill, psxt, psyt, psxu, psyu, psxv, psyv); fprintf(file, " tri\n"); fflush(file); } void pswr_lune ( PSStream *ps, double xc, double yc, double rad, double tilt, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } double psxc = ps->hmin + ps->xscale * (xc - ps->xmin); double psyc = ps->vmin + ps->yscale * (yc - ps->ymin); double psrad = ps->yscale * rad; double pstilt = tilt * 180.0 / 3.1415926; if (pswr_lune_is_invisible(ps, psxc, psyc, psrad, pstilt)) { return; } FILE *file = ps->file; fprintf(file, "%d %d %6.1f %6.1f %6.1f %6.2f", draw, fill, psxc, psyc, psrad, pstilt); fprintf(file, " lun\n"); fflush(file); } void pswr_slice ( PSStream *ps, double xc, double yc, double rad, double start, double stop, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } double psxc = ps->hmin + ps->xscale * (xc - ps->xmin); double psyc = ps->vmin + ps->yscale * (yc - ps->ymin); double psrad = ps->yscale * rad; double psstart = start; double psstop = stop; if (pswr_slice_is_invisible(ps, psxc, psyc, psrad, psstart, psstop)) { return; } FILE *file = ps->file; fprintf(file, "%d %d %6.1f %6.1f %6.1f %6.2f %6.2f", draw, fill, psxc, psyc, psrad, psstart, psstop); fprintf(file, " pie\n"); fflush(file); } void pswr_grid_cell ( PSStream *ps, int xi, int yi, bool fill, bool draw ) { affirm(pswr_within_page(ps), "bad state"); if (ps->fillColor[0] < 0.0) { fill = FALSE; } if ((!draw) && (!fill)) { return; } FILE *file = ps->file; fprintf(file, "%d %d %3d %3d", draw, fill, xi, yi); fprintf(file, " cel\n"); fflush(file); } /* TEXT PRINTING */ void pswr_set_label_font(PSStream *ps, const char *font, double size) { affirm(pswr_within_page(ps), "bad state"); pswr_add_font(font, &(ps->nfonts), &(ps->fonts)); FILE *file = ps->file; pswr_write_label_font_setup_cmds(file, font, size); } void pswr_label ( PSStream *ps, const char *text, double x, double y, double xalign, double yalign ) { affirm(pswr_within_page(ps), "bad state"); double psx = ps->hmin + ps->xscale * (x - ps->xmin); double psy = ps->vmin + ps->yscale * (y - ps->ymin); FILE *file = ps->file; pswr_write_ps_string(file, text, "\\267"); fprintf(file, " "); fprintf(file, " %5.3f %5.3f %6.1f %6.1f lbsh\n", xalign, yalign, psx, psy ); fflush(file); } /* Buffer size for {pswr_add_caption}: */ #define PSWR_CAPBUFSIZE 50 void pswr_add_caption(PSStream *ps, const char *txt, double xalign) { affirm(pswr_within_page(ps), "bad state"); if (ps->captionLines > 0) { FILE *file = ps->file; char showcmd[PSWR_CAPBUFSIZE], nlcmd[PSWR_CAPBUFSIZE]; snprintf(showcmd, PSWR_CAPBUFSIZE, " %5.3f capsh", xalign); snprintf(nlcmd, PSWR_CAPBUFSIZE, ") %s\nnl (", showcmd); fprintf(file, "nl "); pswr_write_ps_string(file, txt, nlcmd); fprintf(file, showcmd); fprintf(file, "\n"); fflush(file); } } /* MISCELLANEOUS */ void pswr_comment(PSStream *ps, const char *title) { FILE *file = ps->file; affirm(file != NULL, "no file"); fprintf(ps->file, "\n%% [%s]\n", title); if (ps->verbose) { fprintf(stderr, "[%s]\n", title); } fflush(file); } double pswr_round_to_nice(double x) { /* Remove the sign of {x} and save it in {s}: */ double s = (x < 0 ? -1 : +1); x = fabs(x); /* Compensate for rounding errors in the algorithm below: */ x = 0.9999999 * x; /* If {x} is too small, don't bother: */ if (x < 1.0e-300) { return s*1.0e-300; } /* Finds the smallest power {z} of 10 that is no less than {x}: */ double z = 1.0; while (z/10.0 > x) { z /= 10.0; } while (z <= x ) { z *= 10.0; } /* Finds a nice multiple of that power of 10: */ if (x < 0.25 * s * z) { return 0.25 * z; } else if (x < 0.5 * z) { return 0.5 * s * z; } else { return s * z; } } /* PAPER SIZES */ void pswr_get_paper_dimensions(const char *papersize, double *xpt, double *ypt) { /* US sizes are defined in inches, which are 72 "pt" exactly: */ /* ISO paper sizes are defined in "mm", and need conversion: */ if ((strcmp(papersize, "letter") == 0) || (strcmp(papersize, "Letter") == 0)) { (*xpt) = 612.0; (*ypt) = 792.0; return; /* 8,5 x 11 in, 216 x 279 mm */ } if ((strcmp(papersize, "a4") == 0) || (strcmp(papersize, "A4") == 0)) { (*xpt) = 210 * mm; (*ypt) = 297 * mm; return; } if ((strcmp(papersize, "a3") == 0) || (strcmp(papersize, "A3") == 0)) { (*xpt) = 297 * mm; (*ypt) = 420 * mm; return; } if ((strcmp(papersize, "legal") == 0) || (strcmp(papersize, "Legal") == 0)) { (*xpt) = 612.0; (*ypt) = 1008.0; return; /* 8,5 x 14 in, 216 x 356 mm */ } if ((strcmp(papersize, "executive") == 0) || (strcmp(papersize, "Executive") == 0)) { (*xpt) = 540.0; (*ypt) = 720.0; return; /* 7,5 x 10 in, 190 x 254 mm */ } if ((strcmp(papersize, "ledger") == 0) || (strcmp(papersize, "Ledger") == 0) || (strcmp(papersize, "tabloid") == 0) || (strcmp(papersize, "Tabloid") == 0)) { (*xpt) = 792.0; (*ypt) = 1224.0; return; /* 11 x 17 in, 279 x 432 mm */ } if ((strcmp(papersize, "a10") == 0) || (strcmp(papersize, "A10") == 0)) { (*xpt) = 26 * mm; (*ypt) = 37 * mm; return; } if ((strcmp(papersize, "a9") == 0) || (strcmp(papersize, "A9") == 0)) { (*xpt) = 37 * mm; (*ypt) = 52 * mm; return; } if ((strcmp(papersize, "a8") == 0) || (strcmp(papersize, "A8") == 0)) { (*xpt) = 52 * mm; (*ypt) = 74 * mm; return; } if ((strcmp(papersize, "a7") == 0) || (strcmp(papersize, "A7") == 0)) { (*xpt) = 74 * mm; (*ypt) = 105 * mm; return; } if ((strcmp(papersize, "a6") == 0) || (strcmp(papersize, "A6") == 0)) { (*xpt) = 105 * mm; (*ypt) = 148 * mm; return; } if ((strcmp(papersize, "a5") == 0) || (strcmp(papersize, "A5") == 0)) { (*xpt) = 148 * mm; (*ypt) = 210 * mm; return; } if ((strcmp(papersize, "a2") == 0) || (strcmp(papersize, "A2") == 0)) { (*xpt) = 420 * mm; (*ypt) = 594 * mm; return; } if ((strcmp(papersize, "a1") == 0) || (strcmp(papersize, "A1") == 0)) { (*xpt) = 594 * mm; (*ypt) = 841 * mm; return; } if ((strcmp(papersize, "a0") == 0) || (strcmp(papersize, "A0") == 0)) { (*xpt) = 841 * mm; (*ypt) = 1189 * mm; return; } if ((strcmp(papersize, "2a0") == 0) || (strcmp(papersize, "2A0") == 0)) { (*xpt) = 1189 * mm; (*ypt) = 1682 * mm; return; } if ((strcmp(papersize, "4a0") == 0) || (strcmp(papersize, "4A0") == 0)) { (*xpt) = 1682 * mm; (*ypt) = 2378 * mm; return; } affirm(0, "unkown paper size"); }