/* * plotVers.c -- * * This file contains the procedures that generate plots on * Versatec-style black-and-white printers. * * ********************************************************************* * * 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/plotVers.c,v 1.3 2010/06/24 12:37:25 tim Exp $"; #endif /* not lint */ #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 "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 "dbwind/dbwind.h" #include "cif/cif.h" /* for CIFGetOutputScale() */ #ifdef VERSATEC /* Library imports: */ extern int rasFileByteCount; /* Records of the following type are used to describe how to generate * output for the mask layers. Each style describes a particular * stipple pattern. */ typedef struct versatecstyle { TileTypeBitMask vs_layers; /* Layers to plot in this style. */ Stipple vs_stipple; /* Stipple pattern to use. */ int vs_flags; /* Flag bits, see below. */ struct versatecstyle *vs_next; /* Pointer to next style in list. */ /* If the color flag is false, all stipples will be black */ VersatecColor vs_color; /* Stipple color */ } VersatecStyle; /* Flag values for VersatecStyles: * * VS_CROSS - if this bit is set, then generate an outline with an * X through the middle, like for contacts, instead of * stippling. The stipple pattern is ignored in this * case. * VS_BORDER - if this bit is set, generate an outline with no X * through the middle and no stipple. The stipple * pattern is ignored in this case. */ #define VS_CROSS 1 #define VS_BORDER 2 static VersatecStyle *plotVersStyles; static VersatecStyle *plotColorVersStyles; char *plotVersatecColorNames[] = { "Black", "Cyan", "Magenta", "Yellow" }; /* * ---------------------------------------------------------------------------- * The parameters below control various aspects of the plotting * process. The initial values are defaults for the versatec * printer. However, many of them can be modified by users * with the "plot option" command. * ---------------------------------------------------------------------------- */ /* Supported format. Default is "hprtl". */ unsigned char PlotVersPlotType = HPRTL; int PlotVersWidth = 2400; /* Number of dots across Versatec page. * Should be a multiple of 32. */ int PlotVersDotsPerInch = 300; /* Dots per inch. */ int PlotVersSwathHeight = 64; /* Width of swath to generate at one time, * in dots. */ /* Name of printer to use for output: */ static char *defaultPrinter = "versatec"; char *PlotVersPrinter = NULL; /* Command to use to actually print rasterized file. Contains two %s'es, * which are supplied with the printer name and the name of the raster file. */ static char *defaultCommand = "lp -d %s %s"; char *PlotVersCommand = NULL; /* Directory in which to create temporary file to hold raster: */ static char *defaultDirectory = "/tmp"; char *PlotTempDirectory = NULL; /* Name of fonts to use: */ static char *defaultIdFont = "vfont.I.12"; char *PlotVersIdFont = NULL; static char *defaultNameFont = "vfont.B.12"; char *PlotVersNameFont = NULL; static char *defaultLabelFont = "vfont.R.8"; char *PlotVersLabelFont = NULL; /* * ---------------------------------------------------------------------------- * The variables below are shared between the top-level Versatec * 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). * ---------------------------------------------------------------------------- */ Point plotLL; /* Point in root Magic coords that corresponds * to (0,0) in raster coordinates. */ int swathY; /* The y-coordinate in raster coordinates that * corresponds to (0,0) in swath coords. It's * always >= 0. */ static int scale; /* How many (2**scaleShift)-ths of a pixel * correspond to one Magic unit. */ 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 VersatecStyle *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 *labelFont; /* Font to use when rendering labels. */ static RasterFont *cellNameFont; /* Font to use when rendering cell names. */ static RasterFont *cellIdFont; /* Font to use when rendering cell ids. */ #endif /* VERSATEC */ /* * ---------------------------------------------------------------------------- * PlotVersTechInit -- * * 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. * ---------------------------------------------------------------------------- */ #ifdef VERSATEC void PlotVersTechInit() { VersatecStyle *style; for (style = plotVersStyles; style != NULL; style = style->vs_next) { freeMagic((char *) style); } plotVersStyles = NULL; if (PlotVersPrinter == NULL) StrDup(&PlotVersPrinter, defaultPrinter); if (PlotVersCommand == NULL) StrDup(&PlotVersCommand, defaultCommand); if (PlotTempDirectory == NULL) StrDup(&PlotTempDirectory, defaultDirectory); if (PlotVersIdFont == NULL) StrDup(&PlotVersIdFont, defaultIdFont); if (PlotVersNameFont == NULL) StrDup(&PlotVersNameFont, defaultNameFont); if (PlotVersLabelFont == NULL) StrDup(&PlotVersLabelFont, defaultLabelFont); } #else void PlotVersTechInit() {} #endif /* VERSATEC */ /* * ---------------------------------------------------------------------------- * PlotColorVersTechInit -- * * 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. * ---------------------------------------------------------------------------- */ #ifdef VERSATEC void PlotColorVersTechInit() { VersatecStyle *style; for (style = plotColorVersStyles; style != NULL; style = style->vs_next) { freeMagic((char *) style); } plotColorVersStyles = NULL; if (PlotVersPrinter == NULL) StrDup(&PlotVersPrinter, defaultPrinter); if (PlotVersCommand == NULL) StrDup(&PlotVersCommand, defaultCommand); if (PlotTempDirectory == NULL) StrDup(&PlotTempDirectory, defaultDirectory); if (PlotVersIdFont == NULL) StrDup(&PlotVersIdFont, defaultIdFont); if (PlotVersNameFont == NULL) StrDup(&PlotVersNameFont, defaultNameFont); if (PlotVersLabelFont == NULL) StrDup(&PlotVersLabelFont, defaultLabelFont); } #else void PlotColorVersTechInit() {} #endif /* VERSATEC */ /* * ---------------------------------------------------------------------------- * PlotVersTechLine -- * * This procedure is invoked by the technology module once for * each line in the "versatec" 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 Versatec styles. * ---------------------------------------------------------------------------- */ #ifdef VERSATEC bool PlotVersTechLine(sectionName, argc, argv) char *sectionName; /* Name of this section (unused). */ int argc; /* Number of arguments on line. */ char *argv[]; /* Pointers to fields of line. */ { VersatecStyle *new; int i; new = (VersatecStyle *) mallocMagic(sizeof(VersatecStyle)); DBTechNoisyNameMask(argv[0], &new->vs_layers); if (argc == 2) { if (strcmp(argv[1], "X") == 0) new->vs_flags = VS_CROSS; else if (strcmp(argv[1], "B") == 0) new->vs_flags = VS_BORDER; else { TechError("Second field must be \"X\" or \"B\"\n"); freeMagic((char *) new); return TRUE; } } else { int i, value; if (argc != 17) { TechError("\"versatec\" lines must have either 2 or 17 fields.\n"); freeMagic((char *)new); return TRUE; } new->vs_color = 0; new->vs_flags = 0; for (i = 0; i < 16; i++) { (void) sscanf(argv[i+1], "%x", &value); new->vs_stipple[i] = (value<<16) | (value & 0xffff); #ifndef WORDS_BIGENDIAN new->vs_stipple[i] = PlotSwapBytes(new->vs_stipple[i]); #endif /* WORDS_BIGENDIAN */ } } new->vs_next = plotVersStyles; plotVersStyles = new; return TRUE; } #else bool PlotVersTechLine(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; } #endif /* VERSATEC */ /* * ---------------------------------------------------------------------------- * PlotColorVersTechLine -- * * This procedure is invoked by the technology module once for * each line in the "colorversatec" 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 ColorVersatec styles. * ---------------------------------------------------------------------------- */ #ifdef VERSATEC bool PlotColorVersTechLine(sectionName, argc, argv) char *sectionName; /* Name of this section (unused). */ int argc; /* Number of arguments on line. */ char *argv[]; /* Pointers to fields of line. */ { VersatecStyle *new; static struct { char *l_str; int l_color; } colors[] = { "black", BLACK, "cyan", CYAN, "magenta", MAGENTA, "yellow", YELLOW, "K", BLACK, "C", CYAN, "M", MAGENTA, "Y", YELLOW, 0 }; int i; new = (VersatecStyle *)mallocMagic(sizeof(VersatecStyle)); DBTechNoisyNameMask(argv[0], &new->vs_layers); if (argc == 2) { new->vs_color = BLACK; if (strcmp(argv[1], "X") == 0) new->vs_flags = VS_CROSS; else if (strcmp(argv[1], "B") == 0) new->vs_flags = VS_BORDER; else { TechError("Second field must be \"X\" or \"B\"\n"); freeMagic((char *) new); return TRUE; } } else { int i, j, value; if (argc != 3 && argc != 4 && argc != 6 && argc != 10 && argc != 18) { TechError("\"colorversatec\" lines must have 2 fields + 1, 2, 4, 8," " or 16 stipple word values.\n"); freeMagic((char *)new); return TRUE; } i = LookupStruct(argv[1], (LookupTable *) colors, sizeof colors[0]); if (i < 0) { TechError("First field must be BLACK, CYAN, MAGENTA or YELLOW.\n"); freeMagic((char *)new); return TRUE; } new->vs_color = colors[i].l_color; new->vs_flags = 0; for (j = 0; j < 16; j += (argc - 2)) { for (i = 0; i < (argc - 2); i++) { sscanf(argv[i + 2], "%x", &value); new->vs_stipple[j + i] = (value << 16) | (value & 0xffff); #ifndef WORDS_BIGENDIAN new->vs_stipple[j + i] = PlotSwapBytes(new->vs_stipple[i]); #endif /* WORDS_BIGENDIAN */ } } } new->vs_next = plotColorVersStyles; plotColorVersStyles = new; return TRUE; } #else bool PlotColorVersTechLine(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; } #endif /* VERSATEC */ #ifdef VERSATEC /* * ---------------------------------------------------------------------------- * * plotTransToSwath -- * * Transforms a rectangle from Magic root coordinates to the * coordinates of the current swath. * * Results: * None. * * Side effects: * Dst is modified to hold a rectangle that has been transformed * to swath coordinates. * * ---------------------------------------------------------------------------- */ void plotTransToSwath(src, dst) Rect *src; /* Rectangle in Magic root coords. */ Rect *dst; /* Rectangle to be filled in with swath * corresponding to src. */ { dst->r_xbot = ((src->r_xbot - plotLL.p_x)*scale) >> scaleShift; dst->r_xtop = ((src->r_xtop - plotLL.p_x)*scale) >> scaleShift; dst->r_ybot = (((src->r_ybot - plotLL.p_y)*scale) >> scaleShift) - swathY; dst->r_ytop = (((src->r_ytop - plotLL.p_y)*scale) >> scaleShift) - swathY; } /* * ---------------------------------------------------------------------------- * * plotVersLine -- * * This procedure plots a line of a given thickness. * * Results: * None. * * Side effects: * The current raster is modified. * * ---------------------------------------------------------------------------- */ void plotVersLine(area, widen, raster) 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. */ Raster *raster; /* Raster to write to */ { 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)) PlotFillRaster(raster, &swathArea, PlotBlackStipple); } else PlotRastFatLine(raster, &swathArea.r_ll, &swathArea.r_ur, widen); } /* * ---------------------------------------------------------------------------- * * plotVersRect -- * * This procedure takes a rectangular area, given in Magic root * coordinates, translates it to swath coordinates, and draws * it as an outline of a given thickness. * * Results: * None. * * Side effects: * Modifies raster. * * ---------------------------------------------------------------------------- */ void plotVersRect(area, widen, raster) 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. */ Raster *raster; /* Raster to plot to */ { Rect side; /* First, the bottom side. */ if (area->r_xbot != area->r_xtop) { side = *area; side.r_ytop = side.r_ybot; plotVersLine(&side, widen, raster); /* 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; plotVersLine(&side, widen, raster); } } /* Now do the left side. */ if (area->r_ybot != area->r_ytop) { side = *area; side.r_xtop = side.r_xbot; plotVersLine(&side, widen, raster); /* 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; plotVersLine(&side, widen, raster); } } } /* * ---------------------------------------------------------------------------- * * plotVersTile -- * * 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 plotVersTile(tile, cxp) Tile *tile; /* Tile that's of type to be output. */ TreeContext *cxp; /* Describes search in progress. */ { Rect tileArea, rootArea, swathArea, edge; TileType ntype; Tile *neighbor; Transform *trans = &cxp->tc_scx->scx_trans; Raster *raster = (Raster *)cxp->tc_filter->tf_arg; /* Transform tile coords to root coords and then to swath coords. */ TITORECT(tile, &tileArea); GEOTRANSRECT(trans, &tileArea, &rootArea); plotTransToSwath(&rootArea, &swathArea); /* Handle X'ed things specially. */ if (curStyle->vs_flags & VS_CROSS) { if (!IsSplit(tile)) if (((swathArea.r_xtop - swathArea.r_xbot) > 6) && ((swathArea.r_ytop - swathArea.r_ybot) > 6)) { Rect r2; plotVersLine(&rootArea, 0, raster); r2.r_xtop = rootArea.r_xbot; r2.r_ybot = rootArea.r_ybot; r2.r_xbot = rootArea.r_xtop; r2.r_ytop = rootArea.r_ytop; plotVersLine(&r2, 0, raster); } } if (IsSplit(tile)) { int i, j; TileType dinfo; Rect r; dinfo = DBTransformDiagonal(TiGetTypeExact(tile), &cxp->tc_scx->scx_trans); if (!(curStyle->vs_flags & VS_BORDER) && !(curStyle->vs_flags & VS_CROSS)) PlotPolyRaster(raster, &swathArea, &swathClip, dinfo, curStyle->vs_stipple); /* Diagonal is always drawn (clipping handled in plotVersLine) */ r = rootArea; if (dinfo & TT_DIRECTION) { /* swap X to make diagonal go the other way */ r.r_xbot = r.r_xtop; r.r_xtop = rootArea.r_xbot; } plotVersLine(&r, 0, raster); } else { /* Clip and then stipple. */ GEOCLIP(&swathArea, &swathClip); if (swathArea.r_xbot > swathArea.r_xtop) return 0; if (swathArea.r_ybot > swathArea.r_ytop) return 0; if (!(curStyle->vs_flags & VS_BORDER) && !(curStyle->vs_flags & VS_CROSS)) PlotFillRaster(raster, &swathArea, curStyle->vs_stipple); } /* Now output lines for any edges between material of the type * currently being drawn and material of other types. This is * done by searching along the tile's borders for neighbors that * have the wrong types. First, search the tile's bottom border * (unless it is at infinity). */ if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile)))) goto searchleft; /* nothing on bottom of split */ if (tileArea.r_ybot > TiPlaneRect.r_ybot) { edge.r_ybot = edge.r_ytop = tileArea.r_ybot; for (neighbor = LB(tile); LEFT(neighbor) < tileArea.r_xtop; neighbor = TR(neighbor)) { ntype = TiGetTopType(neighbor); if (TTMaskHasType(&curMask, ntype)) continue; edge.r_xbot = LEFT(neighbor); edge.r_xtop = RIGHT(neighbor); if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot; if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop; GEOTRANSRECT(trans, &edge, &rootArea); plotVersLine(&rootArea, 0, raster); } } searchleft: if (IsSplit(tile) && (SplitSide(tile))) goto searchtop; /* Nothing on left side of split */ /* Now go along the tile's left border, doing the same thing. Ignore * edges that are at infinity. */ if (tileArea.r_xbot > TiPlaneRect.r_xbot) { edge.r_xbot = edge.r_xtop = tileArea.r_xbot; for (neighbor = BL(tile); BOTTOM(neighbor) < tileArea.r_ytop; neighbor = RT(neighbor)) { ntype = TiGetRightType(neighbor); if (TTMaskHasType(&curMask, ntype)) continue; edge.r_ybot = BOTTOM(neighbor); edge.r_ytop = TOP(neighbor); if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot; if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop; GEOTRANSRECT(trans, &edge, &rootArea); plotVersLine(&rootArea, 0, raster); } } /* Same thing for the tile's top border. */ searchtop: if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile))) goto searchright; /* Nothing on top side of tile */ if (tileArea.r_ytop < TiPlaneRect.r_ytop) { edge.r_ybot = edge.r_ytop = tileArea.r_ytop; for (neighbor = RT(tile); RIGHT(neighbor) > tileArea.r_xbot; neighbor = BL(neighbor)) { ntype = TiGetBottomType(neighbor); if (TTMaskHasType(&curMask, ntype)) continue; edge.r_xbot = LEFT(neighbor); edge.r_xtop = RIGHT(neighbor); if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot; if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop; GEOTRANSRECT(trans, &edge, &rootArea); plotVersLine(&rootArea, 0, raster); } } /* Finally, the right border. */ searchright: if (IsSplit(tile) && !(SplitSide(tile))) return 0; /* Nothing on right side of tile */ if (tileArea.r_xtop < TiPlaneRect.r_xtop) { edge.r_xbot = edge.r_xtop = tileArea.r_xtop; for (neighbor = TR(tile); TOP(neighbor) > tileArea.r_ybot; neighbor = LB(neighbor)) { ntype = TiGetLeftType(neighbor); if (TTMaskHasType(&curMask, ntype)) continue; edge.r_ybot = BOTTOM(neighbor); edge.r_ytop = TOP(neighbor); if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot; if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop; GEOTRANSRECT(trans, &edge, &rootArea); plotVersLine(&rootArea, 0, raster); } } return 0; } /* * ---------------------------------------------------------------------------- * * plotVersLabel -- * * 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 plotVersLabel(scx, label, tpath, raster) SearchContext *scx; /* Describes state of search when label * was found. */ Label *label; /* Label that was found. */ TerminalPath *tpath; /* Ignored. */ Raster *raster; /* Raster to write to */ { 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(labelFont, 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)) PlotFillRaster(raster, &tmp, PlotBlackStipple); 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)) PlotFillRaster(raster, &tmp, PlotBlackStipple); } else { /* Line or rectangle. Draw outline. */ plotVersRect(&rootArea, 1, raster); } /* Output the text for the label. Before outputting the label, * erase the area where the label will appear in order to make * the label more visible. */ 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; GEOCLIP(&labelSize, &swathClip); PlotClearRaster(raster, &labelSize); PlotRasterText(raster, &swathClip, labelFont, label->lab_text, &point); return 0; } /* * ---------------------------------------------------------------------------- * * plotVersCell -- * * 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 plotVersCell(scx, raster) SearchContext *scx; /* Describes cell whose bbox is to * be plotted. */ Raster *raster; /* Raster to write to */ { char idName[100]; Rect rootArea, swathArea, textSize; Point point; CellDef *def; /* Convert the cell's bounding box to root coordinates and then * draw as a thick outline. */ def = scx->scx_use->cu_def; GeoTransRect(&scx->scx_trans, &def->cd_bbox, &rootArea); plotVersRect(&rootArea, 2, raster); if (!PlotShowCellNames) return (0); /* Output the cell's name and id text. */ if (cellNameFont != NULL) { plotTransToSwath(&rootArea, &swathArea); PlotTextSize(cellNameFont, 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; PlotRasterText(raster, &swathClip, cellNameFont, def->cd_name, &point); } if (cellIdFont != NULL) { DBPrintUseId(scx, idName, 100, TRUE); PlotTextSize(cellIdFont, 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; PlotRasterText(raster, &swathClip, cellIdFont, idName, &point); } return 0; } /* * ---------------------------------------------------------------------------- * * PlotVersatec -- * * This procedure generates a raster file suitable for driving * printers like the Versatec black-and-white family, and runs * a spooling program to print the file. * * If PlotVersPlotType is VERSATEC_COLOR, it will generate a * versatec color plot file in straight color raster format. * * If PlotVersPlotType is HPGL2 or HPRTL, it will generate * an HPRTL file for the supported HP plotters. * * Results: * None. * * Side effects: * Lots of disk space is chewed up by the file. * * ---------------------------------------------------------------------------- */ void PlotVersatec(scx, layers, xMask, user_scale) 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 user_scale; /* Scalefactor of output */ { static char *yesNo[] = {"no", "yes", NULL}; int dotsAcross, dotsDown, swathsDown, scaleDown; int mag_width; /* lambda */ float width; /* inches */ char fileName[200], command[300], answer[32]; float length, mBytes; Transform tinv; int action, result; FILE *file; VersatecColor color; bool haveColorMessage; int usedScale, maxScale; float oscale; Raster *raster = NULL; /* CMYK color separated raster buffers. */ Raster *kRaster = NULL, *cRaster = NULL, *mRaster = NULL, *yRaster = NULL; haveColorMessage = FALSE; GeoTransRect(&scx->scx_trans, &scx->scx_area, &rootClip); GEO_EXPAND(&rootClip, 1, &rootClip); /* Get conversion factor (internal units to inches) */ oscale = CIFGetOutputScale(1000); /* convert to microns */ oscale *= 3.937e-5; /* convert to inches */ /* Compute plot width from scalefactor */ mag_width = rootClip.r_xtop - rootClip.r_xbot; maxScale = ((float)PlotVersWidth / (float)PlotVersDotsPerInch) / (oscale * (float)mag_width); width = (float)user_scale * oscale * (float)mag_width; dotsAcross = (int)(width * (float)PlotVersDotsPerInch); if (dotsAcross <= 0 || dotsAcross > PlotVersWidth) { dotsAcross = PlotVersWidth; usedScale = maxScale; } else usedScale = user_scale; /* Recompute width based on the actual scale used */ width = (float)usedScale * oscale * (float)mag_width; /* * 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) / mag_width; 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 >= 8) 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 + PlotVersSwathHeight - 1)/PlotVersSwathHeight; dotsDown = swathsDown * PlotVersSwathHeight; mBytes = ((PlotVersWidth/8)*dotsDown)/1000000.0; length = dotsDown; length /= PlotVersDotsPerInch; TxPrintf("Plot will be %.1f inches wide by %.1f inches long.\n", width, length); TxPrintf("It will take %.2f Megabytes in \"%s\".\n", (PlotVersPlotType == HPRTL || PlotVersPlotType == HPGL2) ? 4.0 * mBytes : mBytes, PlotTempDirectory); TxPrintf("Lambda: %.3f (um) Requested scale: %dX Actual scale: %dX " "[Full scale: %dX].\n", CIFGetOutputScale(1000), user_scale, usedScale, maxScale); 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 a swath raster if * we don't already have one. If the swath size has changed, * recycle the raster for a new one. */ if ((raster != NULL) && ((raster->ras_width != PlotVersWidth) || (raster->ras_height != PlotVersSwathHeight))) { if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL) { PlotFreeRaster(cRaster); PlotFreeRaster(mRaster); PlotFreeRaster(yRaster); } PlotFreeRaster(kRaster); raster = NULL; } if (raster == NULL) { if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL) { cRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth); mRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth); yRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth); } kRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth); raster = kRaster; } /* Load font information for the plot, if it isn't already * loaded. */ labelFont = PlotLoadFont(PlotVersLabelFont); cellNameFont = PlotLoadFont(PlotVersNameFont); cellIdFont = PlotLoadFont(PlotVersIdFont); /* Compute the name of the file to use for output, and open it. */ sprintf(fileName, "%s/magicPlotXXXXXX", PlotTempDirectory); result = mkstemp(fileName); if (result == -1) { TxError("Failed to 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 - (PlotVersWidth*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 (color = BLACK; color <= YELLOW; color++) { int swathsDownThisColor; swathsDownThisColor = swathsDown; rasFileByteCount = 0; /* issue preamble for this color's raster. if we are doing colors */ switch (PlotVersPlotType) { case HPRTL: PlotHPRTLHeader(PlotVersWidth, dotsDown, PlotVersDotsPerInch, file); break; case HPGL2: PlotHPGL2Header(PlotVersWidth, dotsDown, PlotVersDotsPerInch, usedScale, file); break; case VERSATEC_COLOR: if (PlotDumpColorPreamble(color, file, dotsDown, PlotVersWidth) != 0) goto error; if (SigInterruptPending) goto error; TxPrintf("\nDumping %s Raster:", plotVersatecColorNames[color]); TxFlush(); break; } for (swathsDownThisColor -= 1; swathsDownThisColor >= 0; swathsDownThisColor -= 1) { SearchContext scx2; Rect root, labelArea; int labelHeight; swathY = swathsDownThisColor * PlotVersSwathHeight; if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL) { PlotClearRaster(cRaster, (Rect *) NULL); PlotClearRaster(mRaster, (Rect *) NULL); PlotClearRaster(yRaster, (Rect *) NULL); } PlotClearRaster(kRaster, (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 >= PlotVersWidth) swathClip.r_xtop = PlotVersWidth - 1; if (swathClip.r_ytop >= PlotVersSwathHeight) swathClip.r_ytop = PlotVersSwathHeight - 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; if (labelFont != NULL) { labelHeight = (labelFont->fo_bbox.r_ytop - labelFont->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 Versatec style, output stippled areas for all * the tiles requested by the style. */ switch (PlotVersPlotType) { case VERSATEC_BW: curStyle = plotVersStyles; break; case HPGL2: case HPRTL: curStyle = plotColorVersStyles; if (curStyle == NULL) { TxError("Warning: No color versatec styles are defined" " in the technology file!\nPlotting aborted.\n"); return; } break; default: curStyle = plotColorVersStyles; if (!haveColorMessage) { TxError("Warning: No color versatec styles are defined" " in the technology file!\nPlot will be" " monochrome.\n"); haveColorMessage = TRUE; curStyle = plotVersStyles; } } if (curStyle == NULL) { TxError("Warning: No monochrome versatec styles are" " defined in the technology file!\nPlotting" " aborted.\n"); return; } for ( ; curStyle != NULL; curStyle = curStyle->vs_next) { /* if we are plotting in B&W, then visit all the tiles in this * swath, otherwise only visit them if they should be * plotted in the current style's color. */ if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL) { switch (curStyle->vs_color) { case CYAN: raster = cRaster; break; case MAGENTA: raster = mRaster; break; case YELLOW: raster = yRaster; break; default: raster = kRaster; break; } } if ((PlotVersPlotType != VERSATEC_COLOR) || (curStyle->vs_color == color)) { TTMaskAndMask3(&curMask, layers, &curStyle->vs_layers); (void) DBTreeSrTiles(&scx2, &curMask, xMask, plotVersTile, (ClientData) raster); } } raster = kRaster; /* Output labels, if they are wanted. */ if (TTMaskHasType(layers, L_LABEL) && (color == BLACK) && (labelFont != NULL)) { curMask = *layers; TTMaskSetType(&curMask, TT_SPACE); GeoTransRect(&tinv, &labelArea, &scx2.scx_area); (void) DBTreeSrLabels(&scx2, &curMask, xMask, (TerminalPath *) NULL, TF_LABEL_ATTACH, plotVersLabel, (ClientData) raster); } /* Output subcell bounding boxes, if they are wanted. */ if (TTMaskHasType(layers, L_CELL) && color == BLACK) { (void) DBTreeSrCells(&scx2, xMask, plotVersCell, (ClientData) raster); } TxPrintf("#"); TxFlush(); switch (PlotVersPlotType) { case HPGL2: case HPRTL: PlotDumpHPRTL(file, kRaster, cRaster, mRaster, yRaster); break; case VERSATEC_COLOR: case VERSATEC_BW: if (PlotDumpRaster(raster, file) != 0) goto error; if (SigInterruptPending) goto error; break; } } /* Only the VERSATEC_COLOR type runs colors separately */ if (PlotVersPlotType != VERSATEC_COLOR) break; TxPrintf ("\nWrote %d bytes of data.\n", rasFileByteCount); } /* Write trailers */ switch (PlotVersPlotType) { case HPGL2: PlotHPGL2Trailer(file); break; case HPRTL: PlotHPRTLTrailer(file); break; } /* Close the file and issue the command to plot it. */ TxPrintf("\n"); fclose(file); sprintf(command, PlotVersCommand, PlotVersPrinter, fileName); if (system(command) != 0) { TxError("Couldn't execute spooler command to print \"%s\"\n", fileName); } return; error: TxError("\nVersatec plot aborted.\n"); fclose(file); unlink(fileName); } #endif /* VERSATEC */