/* * plotPixels.c -- * * This file contains the procedures that generate pix files. each file is * a sequence of unsigned chars, each triplet of chars representing a red, * green and blue value between 0 and 255 for a pixel. Pixels go across left * to right, and down the image. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plot/plotPixels.c,v 1.2 2008/06/01 18:37:45 tim Exp $"; #endif /* not lint */ #include #include #include #include #include "utils/magic.h" #include "utils/geometry.h" #include "utils/geofast.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "dbwind/dbwtech.h" #include "utils/malloc.h" #include "plot/plotInt.h" #include "windows/windows.h" #include "commands/commands.h" #include "textio/textio.h" #include "utils/utils.h" #include "utils/tech.h" #include "utils/signals.h" #include "utils/styles.h" #include "graphics/graphics.h" #include "dbwind/dbwind.h" #ifdef LLNL /* forward declarations */ void PlotPixFatLine(); /* * ---------------------------------------------------------------------------- * The parameters below control various aspects of the plotting * process. The initial values are defaults for the pixels * printer. However, many of them can be modified by users * with the "plot option" command. * ---------------------------------------------------------------------------- */ int PlotPixWidth = 512; /* Number of dots across image. */ int PlotPixHeight = 512; /* Height of swath to generate at one time, * in dots. */ /* Directory in which to create temporary file to hold raster: */ static char *defaultDirectory = "/usr/tmp"; extern char *PlotTempDirectory; /* * ---------------------------------------------------------------------------- * The variables below are shared between the top-level pixels * plotting procedure and the lower-level search functions. They * contain specific information about how to generate the current * plot. There area three coordinate systems of interest here: * * 1. Magic root coordinates. * 2. Raster coordinates: based on printer pixels, one unit per pixel, * where (0,0) corresponds to the lower-leftmost dot that will be * printed. * 3. Swath coordinates: the raster will be much too large to keep in * memory all at once, so it's generated in a series of horizontal * swaths. The stippling routines all work in swath-relative * coordinates, which are the same as raster coordinates except for * a y-displacement (swathY below). * ---------------------------------------------------------------------------- */ static PixRaster *pixRasterSwath = NULL; /* Raster used to hold current swath. */ extern Point plotLL; /* Point in root Magic coords that corresponds * to (0,0) in raster coordinates. */ extern int swathY; /* The y-coordinate in raster coordinates that * corresponds to (0,0) in swath coords. It's * always >= 0. */ int scale; /* How many (2**scaleShift)-ths of a pixel * correspond to one Magic unit. */ extern int scaleShift; /* The idea is that one Magic unit is equal * to scale/(2**scaleShift) pixels. */ static Rect rootClip; /* Total root area of the plot. Used for * clipping. */ static Rect swathClip; /* Rectangle used for clipping to the area of * the current swath. This is in swath * coordinates. */ static int curStyle; /* Current style being processed. */ static TileTypeBitMask *curMask; /* Mask of layers currently being stippled. * This is the AND of the mask from curStyle * and the layers that the user wants plotted. */ static int crossSize; /* Length of each arm of the crosses used * to draw labels, in pixel units. */ static RasterFont *labelPixFont; /* Font to use when rendering labels. */ static RasterFont *cellNamePixFont; /* Font to use when rendering cell names. */ static RasterFont *cellIdPixFont; /* Font to use when rendering cell ids. */ #endif /* LLNL */ /* * ---------------------------------------------------------------------------- * PlotPixTechInit -- * * Called once at beginning of technology file read-in to initialize * data structures. * * Results: * None. * * Side effects: * Clears out the list of things to plot. * ---------------------------------------------------------------------------- */ void PlotPixTechInit() { /* most intersting stuff is done by PlotVersTechInit -- setting default * plot directory, default font names, etc. */ } /* * ---------------------------------------------------------------------------- * PlotPixTechLine -- * * This procedure is invoked by the technology module once for * each line in the "pixels" subsection of the "plot" section * of the technology file. * * Results: * Always returns TRUE (otherwise the technology module would * abort Magic with a fatal error). * * Side effects: * Builds up the table of pixels styles. * ---------------------------------------------------------------------------- */ /* ARGSUSED */ bool PlotPixTechLine(sectionName, argc, argv) char *sectionName; /* Name of this section (unused). */ int argc; /* Number of arguments on line. */ char *argv[]; /* Pointers to fields of line. */ { return TRUE; } #ifdef LLNL /* * ---------------------------------------------------------------------------- * * PlotPixPoint -- * * Sets a particular pixel of a PixRaster. * * Results: * None. * * Side effects: * If x and y lie inside the raster then the pixel that they select * is set to 1. If x or y is outside the raster area then nothing * happens. * * ---------------------------------------------------------------------------- */ void PlotPixPoint(raster, x, y, style) PixRaster *raster; /* Raster containing pixel to be * filled. */ int x, y; /* Coordinates of pixel. */ int style; /* style to render the pixel with. */ { char *rp; /* ptr to pixel to change. */ if ((x < 0) || (x >= raster->pix_width)) return; y = (raster->pix_height - 1) - y; if ((y < 0) || (y >= raster->pix_height)) return; rp = raster->pix_pixels + x + y*raster->pix_width; *rp = (*rp & ~(GrStyleTable[style].mask)) | (GrStyleTable[style].color & GrStyleTable[style].mask); } /* * ---------------------------------------------------------------------------- * * PlotPixArbLine -- * * Draws a one-pixel-wide line between two points. * * Results: * None. * * Side effects: * A line is drawn between pixels src and dst. Only the portion * of the line that lies inside the raster is drawn; the endpoints * may lie outside the raster (this feature is necessary to draw * straight lines that cross multiple swaths). * * ---------------------------------------------------------------------------- */ void PlotPixArbLine(raster, src, dst, style) Raster *raster; /* Where to render the line. */ Point *src; /* One endpoint of line, in raster coords. */ Point *dst; /* The other endpoint, in raster coords. */ int style; /* Display style to render this line in */ { int x, y, dx, dy, xinc, incr1, incr2, d, done; /* Compute the total x- and y-motions, and arrange for the line to be * drawn in increasing order of y-coordinate. */ dx = dst->p_x - src->p_x; dy = dst->p_y - src->p_y; if (dy < 0) { dy = -dy; dx = -dx; x = dst->p_x; y = dst->p_y; dst = src; } else { x = src->p_x; y = src->p_y; } /* The code below is just the Bresenham algorithm from Foley and * Van Dam (pp. 435), modified slightly so that it can work in * all directions. */ if (dx < 0) { xinc = -1; dx = -dx; } else xinc = 1; if (dx >= dy) { d = 2*dy - dx; incr1 = 2*dy; incr2 = 2*(dy - dx); done = dst->p_x; for ( ; x != done ; x += xinc) { PlotPixPoint(raster, x, y, style); if (d < 0) d += incr1; else { d += incr2; y += 1; } } } else { d = 2*dx - dy; incr1 = 2*dx; incr2 = 2*(dx - dy); done = dst->p_y; for ( ; y != done ; y += 1) { PlotPixPoint(raster, x, y, style); if (d < 0) d += incr1; else { d += incr2; x += xinc; } } } PlotPixPoint(raster, x, y, style); } /* * ---------------------------------------------------------------------------- * * plotPixLine -- * * This procedure plots a line of a given thickness. * * Results: * None. * * Side effects: * The current raster is modified. * * ---------------------------------------------------------------------------- */ void plotPixLine(area, widen, style) Rect *area; /* The "corner" points of this rectangle * give the endpoints of the line, in * Magic root coordinates. */ int widen; /* Amount by which to widen line. 0 means * line is drawn one pixel wide, 1 means 3 * pixels wide, etc. */ int style; /* style in which to render the line */ { Rect swathArea; plotTransToSwath(area, &swathArea); /* Handle Manhattan lines using rectangle-drawing, since it's faster. */ if ((swathArea.r_xbot == swathArea.r_xtop) || (swathArea.r_ybot == swathArea.r_ytop)) { GEO_EXPAND(&swathArea, widen, &swathArea); GEOCLIP(&swathArea, &swathClip); if ((swathArea.r_xbot <= swathArea.r_xtop) && (swathArea.r_ybot <= swathArea.r_ytop)) plotFillPixRaster(pixRasterSwath, &swathArea,style, GR_STSOLID); } else PlotPixFatLine(pixRasterSwath, &swathArea.r_ll, &swathArea.r_ur, widen, curStyle); } /* * ---------------------------------------------------------------------------- * * PlotPixFatLine -- * * Draws a line many pixels wide between two points. * * Results: * None. * * Side effects: * A line is drawn between pixels src and dst. Only the portion * of the line that lies inside the raster is drawn; the endpoints * may lie outside the raster (this feature is necessary to draw * straight lines that cross multiple swaths). The line is drawn * several pixels wide, as determined by the "widen" parameter. * The ends of the line are square, not rounded, which may cause * upleasant effects for some uses. If the line is Manhattan, * this procedure is very inefficient: it's better to use the * PlotFillPixRaster procedure. * * ---------------------------------------------------------------------------- */ void PlotPixFatLine(raster, src, dst, widen, style) PixRaster *raster; /* Where to render the line. */ Point *src; /* One endpoint of line, in raster coords. */ Point *dst; /* The other endpoint, in raster coords. */ int widen; /* How much to widen the line. 0 means the * line is one pixel wide, 1 means it's 3 * pixels wide, and so on. */ int style; { double dx, dy, x, y; int nLines; /* Just draw (2*widen) + 1 lines spaced about one pixel apart. * The first lines here compute how far apart to space the lines. */ nLines = (2*widen) + 1; x = dst->p_x - src->p_x; y = dst->p_y - src->p_y; dy = sqrt(x*x + y*y); dx = y/dy; dy = -x/dy; x = -dy*(widen); y = dx*(widen); for (x = -dx*widen, y = -dy*widen; nLines > 0; nLines -= 1, x += dx, y += dy) { Point newSrc, newDst; if (x > 0) newSrc.p_x = (x + .5); else newSrc.p_x = (x - .5); if (y > 0) newSrc.p_y = (y + .5); else newSrc.p_y = (y - .5); newDst.p_x = dst->p_x + newSrc.p_x; newDst.p_y = dst->p_y + newSrc.p_y; newSrc.p_x += src->p_x; newSrc.p_y += src->p_y; PlotPixArbLine(raster, &newSrc, &newDst, style); } } /* * ---------------------------------------------------------------------------- * * plotPixRect -- * * This procedure takes a rectangular area, given in Magic root * coordinates, and draws it as an outline of a given thickness. * * Results: * None. * * Side effects: * Modifies raster. * * ---------------------------------------------------------------------------- */ void plotPixRect(area, widen, style) Rect *area; /* Rectangular area to draw, in root * coordinates. */ int widen; /* If zero, rectangular outline is drawn * one pixel wide. If non-zero, the outline * is widened by this many units on each * side. */ int style; /* style in which to render the rect */ { Rect side; /* First, the bottom side. */ if (area->r_xbot != area->r_xtop) { side = *area; side.r_ytop = side.r_ybot; plotPixLine(&side, widen,style); /* Now the top side, if it doesn't coincide with the bottom. */ if (area->r_ybot != area->r_ytop) { side = *area; side.r_ybot = side.r_ytop; plotPixLine(&side, widen, style); } } /* Now do the left side. */ if (area->r_ybot != area->r_ytop) { side = *area; side.r_xtop = side.r_xbot; plotPixLine(&side, widen, style); /* Now the right side, if it doesn't coincide with the left. */ if (area->r_xbot != area->r_xtop) { side = *area; side.r_xbot = side.r_xtop; plotPixLine(&side, widen, style); } } } /* * ---------------------------------------------------------------------------- * * plotPixTile -- * * This procedure is called for paint tiles. It renders each tile * in the current style, in the current swath. * * Results: * Always returns 0 to keep the search alive. * * Side effects: * Modifies the raster area. * * ---------------------------------------------------------------------------- */ int plotPixTile(tile, cxp) Tile *tile; /* Tile that's of type to be output. */ TreeContext *cxp; /* Describes search in progress. */ { Rect tileArea, rootArea, swathArea; Transform *trans = &cxp->tc_scx->scx_trans; /* Transform tile coords to root coords and then to swath coords. */ TITORECT(tile, &tileArea); #ifdef DEBUG TxPrintf("PlotPixTile: (%d,%d)(%d,%d) ", tileArea.r_xbot, tileArea.r_ybot, tileArea.r_xtop, tileArea.r_ytop); #endif GEOTRANSRECT(trans, &tileArea, &rootArea); plotTransToSwath(&rootArea, &swathArea); /* Clip and then fill with the color. */ GEOCLIP(&swathArea, &swathClip); if (swathArea.r_xbot > swathArea.r_xtop) return 0; if (swathArea.r_ybot > swathArea.r_ytop) return 0; #ifdef DEBUG TxPrintf(">> (%d,%d)(%d,%d)\n", swathArea.r_xbot, swathArea.r_ybot, swathArea.r_xtop, swathArea.r_ytop); #endif /* if the current style's fill-mode is GR_STOUTLINE or GR_STCROSS * we cannot let plotFillPixRaster render the tile, since we get * extra horizontal lines at swath boundaries. Too bad, it was a * neat idea, but we cannot force the user to render the entire * image at once (*sigh*) */ if((GrStyleTable[curStyle].fill == GR_STOUTLINE) || (GrStyleTable[curStyle].fill == GR_STCROSS)) { /* draw the outline */ plotPixRect(&tileArea, 1, curStyle); } if (GrStyleTable[curStyle].fill == GR_STCROSS) { /* draw the cross */ Point src, dst; src = swathArea.r_ll; dst = swathArea.r_ur; PlotPixFatLine(pixRasterSwath, &src, &dst, 1, curStyle); src.p_y = swathArea.r_ytop; dst.p_y = swathArea.r_ybot; PlotPixFatLine(pixRasterSwath, &src, &dst, 1, curStyle); } plotFillPixRaster(pixRasterSwath, &swathArea, curStyle, -1); return 0; } /* * ---------------------------------------------------------------------------- * * plotPixLabel -- * * This procedure is invoked for labels. It generates bits to * display the label in the current raster swath. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * Modifies the raster. * * ---------------------------------------------------------------------------- */ int plotPixLabel(scx, label) SearchContext *scx; /* Describes state of search when label * was found. */ Label *label; /* Label that was found. */ { Rect rootArea, swathArea, labelSize; Point point; int pos; /* Translate the label's area and relative position to root * coordinates and then to swath coordinates. Figure out * the point relative to which the label is to be positioned. */ GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea); plotTransToSwath(&rootArea, &swathArea); pos = GeoTransPos(&scx->scx_trans, label->lab_just); PlotTextSize(labelPixFont, label->lab_text, &labelSize); switch (pos) { case GEO_NORTH: case GEO_NORTHEAST: case GEO_NORTHWEST: point.p_y = swathArea.r_ytop + crossSize + 2 - labelSize.r_ybot; break; case GEO_CENTER: case GEO_WEST: case GEO_EAST: point.p_y = (swathArea.r_ytop + swathArea.r_ybot)/2; point.p_y -= (labelSize.r_ytop + labelSize.r_ybot)/2; break; case GEO_SOUTH: case GEO_SOUTHEAST: case GEO_SOUTHWEST: point.p_y = swathArea.r_ybot - crossSize - 2 - labelSize.r_ytop; break; } switch (pos) { case GEO_WEST: case GEO_NORTHWEST: case GEO_SOUTHWEST: point.p_x = swathArea.r_xbot - crossSize - 2 - labelSize.r_xtop; break; case GEO_CENTER: case GEO_NORTH: case GEO_SOUTH: point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2; point.p_x -= (labelSize.r_xtop + labelSize.r_xbot)/2; break; case GEO_EAST: case GEO_NORTHEAST: case GEO_SOUTHEAST: point.p_x = swathArea.r_xtop + crossSize + 2 - labelSize.r_xbot; break; } /* Output lines marking the label's area. Different things are * done depending on whether the label is a point, a line, or an * area. */ if ((rootArea.r_xbot == rootArea.r_xtop) && (rootArea.r_ybot == rootArea.r_ytop)) { Rect tmp; /* Point label. Output a cross. */ tmp = swathArea; tmp.r_ytop += crossSize; tmp.r_ybot -= crossSize; GEO_EXPAND(&tmp, 1, &tmp); GEOCLIP(&tmp, &swathClip); if ((tmp.r_xbot <= tmp.r_xtop) && (tmp.r_ybot <= tmp.r_ytop)) plotFillPixRaster(pixRasterSwath, &tmp, STYLE_LABEL, GR_STSOLID); tmp = swathArea; tmp.r_xtop += crossSize; tmp.r_xbot -= crossSize; GEO_EXPAND(&tmp, 1, &tmp); GEOCLIP(&tmp, &swathClip); if ((tmp.r_xbot <= tmp.r_xtop) && (tmp.r_ybot <= tmp.r_ytop)) plotFillPixRaster(pixRasterSwath, &tmp,STYLE_LABEL, GR_STSOLID); } else { /* Line or rectangle. Draw outline. * plotFillPixRaster will outline the area if STYLE_LABEL has * fill mode GR_STOUTLINE. * Cute, berry, but it loses when the rect crosses a swath boundary. */ GEOCLIP(&swathArea, &swathClip); plotPixRect(&rootArea, 1, STYLE_LABEL); /* plotFillPixRaster(pixRasterSwath, &swathArea, STYLE_LABEL, -1); */ } /* Output the text for the label. */ labelSize.r_xbot += point.p_x - 1; labelSize.r_xtop += point.p_x + 1; labelSize.r_ybot += point.p_y - 1; labelSize.r_ytop += point.p_y + 1; PlotPixRasterText(pixRasterSwath, &swathClip, labelPixFont, label->lab_text, &point, STYLE_LABEL); return 0; } /* * ---------------------------------------------------------------------------- * * plotPixCell -- * * This procedure is invoked for unexpanded cells. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * The raster is modified to depict the cell's boundary, * name, and instance id. * * ---------------------------------------------------------------------------- */ int plotPixCell(scx) SearchContext *scx; /* Describes cell whose bbox is to * be plotted. */ { char idName[100]; Rect rootArea, swathArea, textSize; Point point; CellDef *def; /* Convert the cell's bounding box to root coordinates and then * draw the outline. */ def = scx->scx_use->cu_def; GeoTransRect(&scx->scx_trans, &def->cd_bbox, &rootArea); plotPixRect(&rootArea, 1, STYLE_BLACK); if (!PlotShowCellNames) return (0); /* Output the cell's name and id text. */ plotTransToSwath(&rootArea, &swathArea); PlotTextSize(cellNamePixFont, def->cd_name, &textSize); point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2; point.p_x -= (textSize.r_xtop + textSize.r_xbot)/2; point.p_y = (2*swathArea.r_ytop + swathArea.r_ybot)/3; point.p_y -= (textSize.r_ytop + textSize.r_ybot)/2; PlotPixRasterText(pixRasterSwath, &swathClip, cellNamePixFont, def->cd_name, &point, STYLE_BBOX); (void) DBPrintUseId(scx, idName, 100, TRUE); PlotTextSize(cellIdPixFont, idName, &textSize); point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2; point.p_x -= (textSize.r_xtop + textSize.r_xbot)/2; point.p_y = (swathArea.r_ytop + 2*swathArea.r_ybot)/3; point.p_y -= (textSize.r_ytop + textSize.r_ybot)/2; PlotPixRasterText(pixRasterSwath, &swathClip, cellIdPixFont, idName, &point, STYLE_BBOX); return 0; } /* * ---------------------------------------------------------------------------- * * Plotpixels -- * * This procedure generates a pix file usable by various programs * that produce images on Dicomed cameras and so on. * * Results: * None. * * Side effects: * Lots and lots of disk space is chewed up by the file. * * ---------------------------------------------------------------------------- */ void PlotPixels(scx, layers, xMask, width) SearchContext *scx; /* The use and area and transformation * in this describe what to plot. */ TileTypeBitMask *layers; /* Tells what layers to plot. Only * paint layers in this mask, and also * expanded according to xMask, are * plotted. If L_LABELS is set, then * labels on the layers are also * plotted, if expanded according to * xMask. If L_CELL is set, then * subcells that are unexpanded * according to xMask are plotted as * bounding boxes. */ int xMask; /* An expansion mask, used to indicate * the window whose expansion status * will be used to determine * visibility. Zero means treat * everything as expanded. */ int width; /* How many pixels across the plot * should be. */ { static char *yesNo[] = {"no", "yes", NULL}; int dotsAcross, dotsDown, swathsDown, scaleDown; char fileName[200], answer[32]; float mBytes; Transform tinv; int action, result; FILE *file; /* * check to make sure that the swath height is a multiple of 8 so that stipples * will look correct across swath boundaries. */ if (PlotPixHeight & 007) { TxPrintf("Warning: plot parameter \"pixheight\" is not a multiple of 8. It\n"); TxPrintf("will be rounded from %d to %d.\n", PlotPixHeight, (PlotPixHeight&(~007))+8); PlotPixHeight = (PlotPixHeight&(~007))+8; } /* did the user specify an explicit width? */ if (width != 0) PlotPixWidth = width; GeoTransRect(&scx->scx_trans, &scx->scx_area, &rootClip); GEO_EXPAND(&rootClip, 1, &rootClip); dotsAcross = width; if (dotsAcross <= 0) dotsAcross = PlotPixWidth; /* * Compute the number of pixels per magic unit. * This number will be the fraction: scale / (1 << scaleShift). * In order to be reasonably sure that we have enough precision * in the numerator of the fraction, require that scale have at * least three bits (i.e., be greater than or equal to 4). */ for (scale = 0, scaleShift = 4; ; scaleShift++) { scaleDown = 1 << scaleShift; scale = (scaleDown * dotsAcross) / (rootClip.r_xtop - rootClip.r_xbot); if (scaleShift >= 8 * sizeof (int)) { TxError("The area selected is too many lambda wide to plot.\n"); TxError("(There are numerical problems with rasterizing it).\n"); TxError("Try selecting a smaller area, or else asking for "); TxError("a wider plot.\n"); return; } if (scale >= 4) break; } /* * Compute scaling information, and tell the user how big the * plot will be. */ dotsDown = ((rootClip.r_ytop - rootClip.r_ybot)*scale) >> scaleShift; swathsDown = (dotsDown + PlotPixHeight - 1)/PlotPixHeight; dotsDown = swathsDown * PlotPixHeight; mBytes = (double)(PlotPixWidth*dotsDown)*3.0/1000000.0; TxPrintf("Plot will take %.2f Megabytes in \"%s\".\n", mBytes, PlotTempDirectory); do { TxPrintf("Do you still want the plot? [yes] "); if (TxGetLine(answer, sizeof answer) == NULL || answer[0] == '\0') { action = 1; break; } } while ((action = Lookup(answer, yesNo)) < 0); if (action == 0) return; /* The plot has been "approved". Now obtain swath rasters if * we don't already have them. If the swath size has changed, * recycle the rasters for new ones. */ if (pixRasterSwath == NULL) pixRasterSwath = PlotNewPixRaster(PlotPixHeight, PlotPixWidth); else { if ((pixRasterSwath->pix_width != PlotPixWidth) || (pixRasterSwath->pix_height != PlotPixHeight)) { PlotFreePixRaster(pixRasterSwath); pixRasterSwath = PlotNewPixRaster(PlotPixHeight, PlotPixWidth); } } /* Load font information for the plot, if it isn't already * loaded. We use the "versatec" fonts for convenience. */ labelPixFont = PlotLoadFont(PlotVersLabelFont); cellNamePixFont = PlotLoadFont(PlotVersNameFont); cellIdPixFont = PlotLoadFont(PlotVersIdFont); if ((labelPixFont == NULL) || (cellNamePixFont == NULL) || (cellIdPixFont == NULL)) { TxPrintf("PlotPixels: can't load fonts\n"); return; } /* Compute the name of the file to use for output, and open it. */ sprintf(fileName, "%s/magicPlot-%d-%d-XXXXXX", PlotTempDirectory, PlotPixWidth, PlotPixHeight*swathsDown); result = mkstemp(fileName); if (result == -1) { TxError("Couldn't create temporary filename for %s\n", fileName); return; } file = PaOpen(fileName, "w", (char *) NULL, (char *) NULL, (char *) NULL, (char **) NULL); if (file == NULL) { TxError("Couldn't open file \"%s\" to write plot.\n", fileName); return; } /* Set up the rest of the transformation variables. * Arrange for the plot to be centered on the page. */ plotLL.p_y = rootClip.r_ybot; plotLL.p_x = (rootClip.r_xtop+rootClip.r_xbot)/2 - (PlotPixWidth*8)/scale; if (plotLL.p_x > rootClip.r_xbot) plotLL.p_x = rootClip.r_xbot; /* Compute a distance equal to 1/8th the size of a typical wire * (max of thicknesses of routing layers). This is used to offset * text from labels and to compute cross size for point labels. */ if (RtrMetalWidth > RtrPolyWidth) crossSize = (RtrMetalWidth*scale)/(scaleDown*8); else crossSize = (RtrPolyWidth*scale)/(scaleDown*8); if (crossSize < 2) crossSize = 2; /* Step down the page one swath at a time, rasterizing everything * that overlaps the current swath, then outputting the swath. */ GeoInvertTrans(&scx->scx_trans, &tinv); for (swathsDown -= 1; swathsDown >= 0; swathsDown -= 1) { SearchContext scx2; Rect root, labelArea; int labelHeight; swathY = swathsDown * PlotPixHeight; PlotClearPixRaster(pixRasterSwath, (Rect *) NULL); /* Compute the area of the swath that overlaps the portion of * the layout we're plotting. */ plotTransToSwath(&rootClip, &swathClip); if (swathClip.r_xbot < 0) swathClip.r_xbot = 0; if (swathClip.r_ybot < 0) swathClip.r_ybot = 0; if (swathClip.r_xtop >= PlotPixWidth) swathClip.r_xtop = PlotPixWidth - 1; if (swathClip.r_ytop >= PlotPixHeight) swathClip.r_ytop = PlotPixHeight - 1; /* Compute the area of layout that overlaps this swath. This is * done twice, once for mask material and once for labels. The * separate computation for labels is because labels stick out * from their positioning points. We may have to search a larger * area than just the swath in order to find all the labels that * must be drawn in this swath. Only the y-direction needs to * be expanded this way, since we're only swathing in y. Even * non-label stuff has to be expanded slightly, because lines * are drawn more than 1 pixel thick. */ scx2 = *scx; root.r_xbot = (scaleDown*swathClip.r_xbot)/scale + plotLL.p_x; root.r_xtop = (scaleDown*swathClip.r_xtop)/scale + plotLL.p_x; root.r_ybot = (scaleDown*(swathY-4))/scale + plotLL.p_y; root.r_ytop = (scaleDown*(swathY+swathClip.r_ytop+4))/scale+plotLL.p_y; GEO_EXPAND(&root, 1, &root); GeoTransRect(&tinv, &root, &scx2.scx_area); labelArea.r_xbot = root.r_xbot; labelArea.r_xtop = root.r_xtop; labelHeight = (labelPixFont->fo_bbox.r_ytop - labelPixFont->fo_bbox.r_ybot) + 2; labelArea.r_ybot = (scaleDown*(swathY-crossSize-labelHeight))/scale + plotLL.p_y; labelArea.r_ytop = (scaleDown*(swathY+swathClip.r_ytop+crossSize+labelHeight))/scale + plotLL.p_y; GEO_EXPAND(&labelArea, 1, &labelArea); /* For each style, output areas for all the tiles * requested by the style. */ for (curStyle = 0; curStyle < DBWNumStyles; curStyle++) { /* visit all the tiles in this swath */ curMask = DBWStyleToTypes(curStyle); (void) DBTreeSrTiles(&scx2, curMask, xMask, plotPixTile, (ClientData) NULL); } /* Output labels, if they are wanted. */ if (TTMaskHasType(layers, L_LABEL)) { curMask = layers; TTMaskSetType(curMask, TT_SPACE); GeoTransRect(&tinv, &labelArea, &scx2.scx_area); (void)DBTreeSrLabels(&scx2, curMask, xMask, (TerminalPath *) NULL, TF_LABEL_ATTACH, plotPixLabel, (ClientData) NULL); } /* Output subcell bounding boxes, if they are wanted. */ if (TTMaskHasType(layers, L_CELL)) { (void) DBTreeSrCells(&scx2, xMask, plotPixCell, (ClientData) NULL); } TxPrintf("#"); TxFlush(); if (PlotDumpPixRaster(pixRasterSwath,file)!= 0) goto error; if (SigInterruptPending) goto error; } /* Close the file and tell the user where it is */ fclose(file); TxPrintf("\nPlot complete. pix file is \"%s\"\n", fileName); return; error: TxError("\npixel plot aborted.\n"); fclose(file); unlink(fileName); } /* * ---------------------------------------------------------------------------- * * PlotNewPixRaster -- * * Allocate and initialize a new raster structure. * * Results: * The return value is a pointer to the new PixRaster object. * * Side effects: * Memory is allocated. * * ---------------------------------------------------------------------------- */ PixRaster * PlotNewPixRaster(height, width) int height; /* PixRaster's height in pixels.*/ int width; /* PixRaster's width in pixels.*/ { PixRaster *new; new = (PixRaster *) mallocMagic(sizeof(PixRaster)); new->pix_width = width; new->pix_height = height; new->pix_pixels = (char *) mallocMagic((unsigned) (height * width)); return new; } /* * ---------------------------------------------------------------------------- * * PlotFreePixRaster -- * * Frees up the memory associated with an existing PixRaster structure. * * Results: * None. * * Side effects: * The storage associated with PixRaster is returned to the allocator. * * ---------------------------------------------------------------------------- */ void PlotFreePixRaster(pr) PixRaster *pr; /* PixRaster whose memory is to be freed. * Should have been created with * PlotNewPixRaster. */ { freeMagic((char *) pr->pix_pixels); freeMagic((char *) pr); } /* * ---------------------------------------------------------------------------- * * PlotClearPixRaster -- * * This procedure clears out an area of the PixRaster. * * Results: * None. * * Side effects: * The area of the PixRaster indicated by "area" is set to all zeroes. * * ---------------------------------------------------------------------------- */ void PlotClearPixRaster(pr, area) PixRaster *pr; /* PixRaster that's to be cleared. */ Rect *area; /* Area to be cleared, in PixRaster * coords. NULL means clear the * whole PixRaster. */ { char *left, *right, *cur; int line; if (area == NULL) { bzero((char *) pr->pix_pixels, pr->pix_height*pr->pix_width); return; } /* Compute the address of the leftmost word in the topmost line * to be cleared, and the rightmost word in the topmost line to * be cleared. */ left = pr->pix_pixels + ((pr->pix_height-1) - area->r_ytop)* pr->pix_width; right = left + area->r_xtop; left += area->r_xbot; /* Clear the area one PixRaster line at a time, top to bottom. */ for (line = area->r_ytop; line >= area->r_ybot; line -= 1) { /* Clear the line. */ for (cur = left; cur <= right; cur += 1) *cur = 0; left += pr->pix_width; right += pr->pix_width; } } /* * ---------------------------------------------------------------------------- * * plotFillPixRaster -- * * Given a PixRaster and an area, this procedure renders the given area * of the PixRaster with a particular stipple pattern or other * appropriate style. * * Results: * None. * * Side effects: * The current PixRaster is modified.. * * ---------------------------------------------------------------------------- */ void plotFillPixRaster(pr, area, style, fill) PixRaster *pr; /* Pointer to PixRaster whose bits are * to be filled in. */ Rect *area; /* Area to be filled in pixel coords. * This is an inclusive area: it * includes the boundary pixels. The * caller must ensure that it is * clipped to the PixRaster area. */ int style; /* index of style to be used */ int fill; /* if >0, override GrStyleTable fill mode */ { char *left, *cur; int line; char *right; int curStipple, curColor, curMask; /* local copies so we don't have to * continually indirect through * GrStyleTable */ Rect r; /* for passing to plotPixLine */ #ifdef DEBUG TxPrintf("plotFillPixRaster: raster buffer@0x%x : ", pr->pix_pixels); TxPrintf(" (%d,%d)(%d,%d)\n", area->r_xbot, area->r_ybot, area->r_xtop, area->r_ytop); #endif /* Compute the address of the leftmost word in the topmost line * to be filled, and the rightmost word in the topmost line to * be filled. */ /* find beginning of first swath line that is affected */ left = pr->pix_pixels + ((pr->pix_height-1) - area->r_ytop)*pr->pix_width; right = left + area->r_xtop; /* right edge */ left += area->r_xbot; /* left edge */ /* Process the area one PixRaster line at a time, top to bottom. */ curStipple = GrStyleTable[style].stipple; curColor = GrStyleTable[style].color; curMask = GrStyleTable[style].mask; /* * now select the appropriate rendering style * and render the area. If we were passed a non-negative fill argument, * let it override the fill mode from GrStyleTable. Otherwise, use the * mode from the table. This is so we can make solid areas in STYLE_LABEL, * for example, instead of getting the arms of the crosses hollow. */ if (fill < 0) fill = GrStyleTable[style].fill; switch (fill) { case GR_STSTIPPLE: #ifdef DEBUG TxPrintf ("Stipple: %d %d %d %d %d %d %d %d \n", GrStippleTable[curStipple][0], GrStippleTable[curStipple][1], GrStippleTable[curStipple][2], GrStippleTable[curStipple][3], GrStippleTable[curStipple][4], GrStippleTable[curStipple][5], GrStippleTable[curStipple][6], GrStippleTable[curStipple][7]); #endif for (line = area->r_ytop; line >= area->r_ybot; line -= 1) { for (cur = left; cur <= right; cur += 1) /* select "line" of stipple pattern and AND it with the bitmask * for the bit in the line * x&07 == x % 8 and is faster */ if(GrStippleTable[curStipple][line&07] & 1<<(int)((7-(cur-pr->pix_pixels)% pr->pix_width)&07)) *cur = (*cur & ~curMask) | (curColor & curMask); left += pr->pix_width; right += pr->pix_width; } break; case GR_STGRID: /* not implemented */ break; /* cross and outline are handled at a higher level */ case GR_STCROSS: /* can't do it here due to swath boundary problems. */ break; case GR_STOUTLINE: break; case GR_STSOLID: default: for (line = area->r_ytop; line >= area->r_ybot; line -= 1) { for (cur = left; cur <= right; cur += 1) *cur = (*cur & ~curMask) | (curColor & curMask); left += pr->pix_width; right += pr->pix_width; } break; } } /* * ---------------------------------------------------------------------------- * * PlotDumpPixRaster -- * * Writes out the contents of the given PixRaster to the given file, * in binary format. Goes trhough color map table to get the values for * each pixel. * * Results: * Returns 0 if all was well. Returns non-zero if there was * an I/O error. In this event, this procedure prints an * error message before returning. * * Side effects: * Information is added to file. * * ---------------------------------------------------------------------------- */ int PlotDumpPixRaster(pr, file) PixRaster *pr; /* PixRaster to be dumped. */ FILE *file; /* File stream on which to dump it. */ { int i; int r, g, b; for (i = 0; i < (pr->pix_width) * (pr->pix_height); i++) { GrGetColor(pr->pix_pixels[i], &r, &g, &b); if (putc(r, file) == EOF) /* red */ { TxError("I/O error in writing PixRaster file: %s.\n", strerror(errno)); return 1; } if (putc(g, file) == EOF) /* green */ { TxError("I/O error in writing PixRaster file: %s.\n", strerror(errno)); return 1; } if (putc(b, file) == EOF) /* blue */ { TxError("I/O error in writing PixRaster file: %s.\n", strerror(errno)); return 1; } } return 0; } /* * ---------------------------------------------------------------------------- * * PlotPixRasterText -- * * Given a text string and a font, this procedure scan-converts * the string and writespixels in the current raster that correspond * to on-bits in the text. * * Results: * None. * * Side effects: * Bits are modified in the raster. * * ---------------------------------------------------------------------------- */ void PlotPixRasterText(raster, clip, font, string, point, style) PixRaster *raster; /* Raster whose bits are to be filled in. */ Rect *clip; /* Area to which to clip the text. Must be * entirely within the area of the raster. */ RasterFont *font; /* Font to use for rasterizing string. Must * have been obtained by calling PlotLoadFont. */ char *string; /* String of text to rasterize. */ Point *point; /* X-Y coordinates of origin of text. The * origin need not be inside the area of * the raster, but only raster points inside * the area will be modified. */ int style; /* style for the text to be rendered in -- * used only for the correct color. */ { int xOrig; /* X-origin for current character. */ int color; color = GrStyleTable[style].color; /* Outer loop: process each character. */ xOrig = point->p_x; for (; *string != 0; string++) { int cBytesPerLine, i; struct dispatch *d; /* Descriptor for current character. */ /* Handle spaces and tabs specially by just spacing over. */ if ((*string == ' ') || (*string == '\t')) { xOrig += font->fo_chars['t'].width; continue; } /* Middle loop: render each character one raster line at a * time, from top to bottom. Skip rows that are outside the * area of the raster. */ d = &font->fo_chars[*string]; cBytesPerLine = (d->left + d->right + 7) >> 3; for (i = 0; i < d->up + d->down; i++) { int y, j; char *charBitPtr; y = point->p_y + d->up - 1 - i; if (y < clip->r_ybot) break; if (y > clip->r_ytop) continue; /* Inner loop: process a series of bytes in a row to * render one raster line of one character. Be sure * to skip areas that fall outside the raster to the * left or right. */ for (j = -d->left, charBitPtr = font->fo_bits + d->addr + i*cBytesPerLine; j < d->right; j += 8, charBitPtr++) { char *rPtr; int charBits, x, k; x = xOrig + j; if (x > clip->r_xtop) break; if (x < clip->r_xbot - 7) continue; rPtr = (char *) raster->pix_pixels; rPtr += (raster->pix_height - 1 - y)*raster->pix_width + x; charBits = *charBitPtr & 0xff; /* Inner inner loop: process the bytes worth of bits, setting * pixels in the raster to the current color */ for(k=7;k>=0;k--) { if(charBits&(1<width; } } #endif /* LLNL */