/* * plotPS.c -- * * This file contains procedures that generate PS-format files * to describe a section of layout. * * ********************************************************************* * * 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/plotPS.c,v 1.3 2010/06/24 12:37:25 tim Exp $"; #endif /* not lint */ #include #include #include #include "utils/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "utils/tech.h" #include "utils/malloc.h" #include "utils/utils.h" #include "windows/windows.h" #include "commands/commands.h" #include "dbwind/dbwind.h" #include "textio/textio.h" /* C99 compat */ #include "graphics/graphics.h" /* Records of the following type are used to describe how to generate * PS output for a particular set of mask layers. Each style * describes the PS figures to draw for a particular set of * layers. A single layer may participate in several ps styles. */ typedef struct psstyle { TileTypeBitMask grs_layers; /* Layers to plot in this style. */ int grs_stipple; /* Index of fill to use. */ int grs_color; /* Index of color to use. */ struct psstyle *grs_next; /* Next style in chain. */ } PSStyle; typedef struct pspattern { int index; unsigned long stipple[8]; struct pspattern *pat_next; } PSPattern; typedef struct pscolor { int index; unsigned char color[4]; struct pscolor *col_next; } PSColor; static PSStyle *plotPSStyles = NULL; static PSPattern *plotPSPatterns = NULL; static PSColor *plotPSColors = NULL; int delta, xnmargin, ynmargin, xpmargin, ypmargin; float fscale; /* Most of the grs_stipple values are PS stipple numbers. However, * if a grs_stipple value is less than zero, it means something special. * The definitions below give the possible alternatives: * * CROSS: Draw a thick outline around the tile with * a cross through it (used for contacts). * BORDER: Same as CROSS, except draw the outline with * no cross through it. * SOLID: This is the same as a solid stipple but renders * much faster. */ #define CROSS -1 #define BORDER -2 #define SOLID -3 /* The definitions below give the integers used for various PS * line drawing styles (brushes). */ #define PS_THIN 1 #define PS_MEDIUM 2 #define PS_THICK 3 /* The variables below are used to pass information from the top-level * procedure PlotPS down to the lower-level search functions * that are invoked for pieces of the layout. */ static FILE *file; /* File to use for output. */ static PSStyle *curStyle; /* Current style being output. */ static PSColor *curColor; /* Current color being output. */ static PSPattern *curPattern; /* Current pattern being output. */ static int curLineWidth; /* Current line width */ static int curFont; /* Current font */ static TileTypeBitMask curMask; /* Layers currently being searched: this * is the AND of the mask from curStyle and * the layers that the user specified. */ static Rect bbox; /* Bounding box, in root coordinates, of * area being plotted. */ /* Parameters passed to the plotting process */ static char *defaultBoldFont = "/HelveticaBold"; static char *defaultFont = "/Helvetica"; char *PlotPSIdFont = NULL; char *PlotPSNameFont = NULL; char *PlotPSLabelFont = NULL; int PlotPSIdSize = 8; int PlotPSNameSize = 12; int PlotPSLabelSize = 12; int PlotPSBoundary = 1; /* Print boundaries around all layers */ int PlotPSHeight = 792; /* 11 inches * 72 PS units/inch */ int PlotPSWidth = 612; /* 8.5 inches */ int PlotPSMargin = 72; /* 1 inch */ int curx1, curx2, cury1, cury2; /* Last encountered line */ int curxbot, curybot, curwidth, curheight; /* Last encountered rectangle */ /* * ---------------------------------------------------------------------------- * * PSReset() * * Plot optimization: Reset buffered line and rectangle to default values * * ---------------------------------------------------------------------------- */ void PSReset() { curxbot = curybot = curwidth = curheight = -2; curx1 = curx2 = cury1 = cury2 = -2; } /* * ---------------------------------------------------------------------------- * PlotPSTechInit -- * * 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 PlotPSTechInit() { int i, j; PSStyle *style; PSColor *color; PSPattern *pattern; /* Clear out any old information */ for (style = plotPSStyles; style != NULL; style = style->grs_next) { freeMagic((char *) style); } plotPSStyles = NULL; for (pattern = plotPSPatterns; pattern != NULL; pattern = pattern->pat_next) { freeMagic((char *) pattern); } plotPSPatterns = NULL; for (color = plotPSColors; color != NULL; color = color->col_next) { freeMagic((char *) color); } plotPSColors = NULL; if (!PlotPSIdFont) StrDup(&PlotPSIdFont, defaultFont); if (!PlotPSNameFont) StrDup(&PlotPSNameFont, defaultBoldFont); if (!PlotPSLabelFont) StrDup(&PlotPSLabelFont, defaultFont); } /* * ---------------------------------------------------------------------------- * PlotPSTechLine -- * * This procedure is invoked by the technology module once for * each line in the "ps" 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 PS styles. * ---------------------------------------------------------------------------- */ bool PlotPSTechLine(sectionName, argc, argv) char *sectionName; /* Name of this section (unused). */ int argc; /* Number of arguments on line. */ char *argv[]; /* Pointers to fields of line. */ { PSStyle *newstyle; PSColor *newcolor; PSPattern *newpattern; int i, color, stipple; if (argc != 9 && argc != 5 && argc != 3) { TechError("\"ps\" lines must have either 9, 5, or 3 arguments.\n"); return TRUE; } if (argc == 9) /* pattern definition */ { newpattern = (PSPattern *) mallocMagic(sizeof(PSPattern)); sscanf(argv[0], "%d", &(newpattern->index)); for(i = 0; i < 8; i++) { sscanf(argv[1 + i], "%08lx", &(newpattern->stipple[i])); } newpattern->pat_next = plotPSPatterns; plotPSPatterns = newpattern; } else if (argc == 5) /* color definition */ { int tmpint; newcolor = (PSColor *) mallocMagic(sizeof(PSColor)); sscanf(argv[0], "%d", &(newcolor->index)); for(i = 0; i < 4; i++) { sscanf(argv[1 + i], "%d", &tmpint); newcolor->color[i] = (unsigned char)(tmpint & 0xff); } newcolor->col_next = plotPSColors; plotPSColors = newcolor; } else { /* 3 args: layer definition */ if (!StrIsInt(argv[1])) { TechError("2nd field must be an integer\n"); return TRUE; } color = atoi(argv[1]); if (strcmp(argv[2], "X") == 0) stipple = CROSS; else if (strcmp(argv[2], "B") == 0) stipple = BORDER; else if (strcmp(argv[2], "S") == 0) stipple = SOLID; else { if (!StrIsInt(argv[2])) { TechError("3rd field must be an integer or \"S\", \"X\", or \"B\".\n"); return TRUE; } stipple = atoi(argv[2]); } newstyle = (PSStyle *) mallocMagic(sizeof(PSStyle)); DBTechNoisyNameMask(argv[0], &newstyle->grs_layers); /* Replace non-primary contact images with primary images. */ for (i = TT_TECHDEPBASE; i < DBNumTypes; i++) { if TTMaskHasType(&newstyle->grs_layers, i) TTMaskSetMask(&newstyle->grs_layers, &DBLayerTypeMaskTbl[i]); } TTMaskAndMask(&newstyle->grs_layers, &DBUserLayerBits); newstyle->grs_stipple = stipple; newstyle->grs_color = color; newstyle->grs_next = plotPSStyles; plotPSStyles = newstyle; } return TRUE; } /* * ---------------------------------------------------------------------------- * * plotPSFlushRect() * * Plot optimization: Draw last buffered rectangle. * * ---------------------------------------------------------------------------- */ void plotPSFlushRect(style) int style; { if (curwidth > 0) { if (style == SOLID) fprintf(file, "%d %d %d %d ms\n", curxbot, curybot, curwidth, curheight); else fprintf(file, "%d %d %d %d fb\n", curxbot, curybot, curxbot + curwidth, curybot + curheight); } } /* * ---------------------------------------------------------------------------- * * plotPSFlushLine() * * Plot optimization: Draw last buffered line. * * ---------------------------------------------------------------------------- */ void plotPSFlushLine() { if (cury1 == cury2) { if (curx1 != curx2) /* true only if nothing is buffered */ fprintf(file, "%d %d %d hl\n", curx2 - curx1, curx1, cury1); } else if (curx1 == curx2) fprintf(file, "%d %d %d vl\n", cury2 - cury1, curx1, cury1); else fprintf(file, "%d %d %d %d ml\n", curx1, cury1, curx2, cury2); } /* * ---------------------------------------------------------------------------- * * plotPSLine -- * * Outputs a line into the current PS file. * * Results: * None. * * Side effects: * I/O. * * ---------------------------------------------------------------------------- */ void plotPSLine(p1, p2) Point *p1, *p2; /* Endpoints of line, given in root * coordinates. */ { int x1, x2, y1, y2, limit, diff; bool tmptf; /* Clip the line to the rectangular area being output. First, * arrange for the first x-coordinate to be the smaller, then * clip against vertical lines at the x-boundaries. */ if (p1->p_x <= p2->p_x) { x1 = p1->p_x - bbox.r_xbot; x2 = p2->p_x - bbox.r_xbot; y1 = p1->p_y - bbox.r_ybot; y2 = p2->p_y - bbox.r_ybot; } else { x1 = p2->p_x - bbox.r_xbot; x2 = p1->p_x - bbox.r_xbot; y1 = p2->p_y - bbox.r_ybot; y2 = p1->p_y - bbox.r_ybot; } limit = bbox.r_xtop - bbox.r_xbot; if ((x1 > limit) || (x2 < 0)) return; /* Now clip against horizontal lines at the y-boundaries. */ if (y2 < y1) { float tmp; tmp = y2; y2 = y1; y1 = tmp; tmp = x2; x2 = x1; x1 = tmp; } limit = bbox.r_ytop - bbox.r_ybot; if ((y1 > limit) || (y2 < 0)) return; /* compare against last output line and merge if possible */ if (((x1 == x2) && (x1 == curx1) && (x2 == curx2) && ((tmptf = (y1 == cury2)) || (y2 == cury1)))) { if (tmptf) cury2 = y2; else cury1 = y1; } else if (((y1 == y2) && (y1 == cury1) && (y2 == cury2) && ((tmptf = (x1 == curx2)) || (x2 == curx1)))) { if (tmptf) curx2 = x2; else curx1 = x1; } else { plotPSFlushLine(); curx1 = x1; curx2 = x2; cury1 = y1; cury2 = y2; } } /* * ---------------------------------------------------------------------------- * * plotPSRect -- * * Outputs PS statements to draw a rectangular area as * an outline with a given line style. * * Results: * None. * * Side effects: * Adds information to the current PS file. * * ---------------------------------------------------------------------------- */ void plotPSRect(rect, style) Rect *rect; /* Rectangle to be drawn, in root coords. */ int style; { int x, y, w, h; /* Output all boxes with any part visible. Depend on PostScript to */ /* do the clipping of any boxes crossing the plot boundary. */ x = rect->r_xbot - bbox.r_xbot; if ((x < 0) || (rect->r_xbot > bbox.r_xtop)) return; w = rect->r_xtop - rect->r_xbot; y = rect->r_ybot - bbox.r_ybot; if ((y < 0) || (rect->r_ybot > bbox.r_ytop)) return; h = rect->r_ytop - rect->r_ybot; fprintf(file, "%d %d %d %d m%c\n", x, y, w, h, (style == CROSS) ? 'x' : (style == SOLID) ? 's' : 'r'); } /* * ---------------------------------------------------------------------------- * * plotPSPaint -- * * This procedure is invoked once for each paint rectangle in * the area being plotted. * * Results: * Always returns 0 to keep the search alive. * * Side effects: * Outputs information for the tile, including stipple for its * interior, and a solid line for any portion of the boundary * of the tile that is adjacent to a tile NOT in this style. * * ---------------------------------------------------------------------------- */ int plotPSPaint(tile, cxp) Tile *tile; /* Tile that's of type to be output. */ TreeContext *cxp; /* Describes search in progress. */ { Rect tileArea, edge, rootArea; int xbot, width, ybot, height; Tile *neighbor; SearchContext *scx = cxp->tc_scx; bool tmptf; TileType ntype; /* First transform tile coords to root coords */ TiToRect(tile, &tileArea); GeoTransRect(&scx->scx_trans, &tileArea, &rootArea); /* See if this tile gets special handling. */ if ((curStyle->grs_stipple == CROSS) || (curStyle->grs_stipple == BORDER)) { /* Draw tile as a thick outline with a cross from corner * to corner, and skip the rest of this procedure. */ Point ul, lr; if (curLineWidth != PS_MEDIUM) { fprintf(file, "l2\n"); curLineWidth = PS_MEDIUM; } plotPSRect(&rootArea, curStyle->grs_stipple); return 0; } /* If this is a triangle, output the last rect and deal with this one */ /* individually. */ if (IsSplit(tile)) { int np, i, j; TileType dinfo; Point polyp[5]; plotPSFlushRect(curStyle->grs_stipple); plotPSFlushLine(); PSReset(); /* Side and direction are altered by geometric transformations */ dinfo = DBTransformDiagonal(TiGetTypeExact(tile), &scx->scx_trans); /* Use GrClipTriangle() routine to get the n-sided polygon that */ /* results from clipping a triangle to the clip region. */ GrClipTriangle(&rootArea, &bbox, TRUE, dinfo, polyp, &np); for (i = 0; i < np; i++) { polyp[i].p_x -= bbox.r_xbot; polyp[i].p_y -= bbox.r_ybot; fprintf(file, "%d %d ", polyp[i].p_x, polyp[i].p_y); } fprintf(file, "%d tb\n", np); if (PlotPSBoundary) { if (curLineWidth != PS_THIN) { fprintf(file, "l1\n"); curLineWidth = PS_THIN; } /* Diagonal is always drawn */ for (i = 0; i < np; i++) { j = (i + 1) % np; if (polyp[i].p_x != polyp[j].p_x && polyp[i].p_y != polyp[j].p_y) { fprintf(file, "%d %d %d %d ml\n", polyp[i].p_x, polyp[i].p_y, polyp[j].p_x, polyp[j].p_y); break; } } } } else { /* This tile gets "normal" processing (i.e. stippling and outlining). * Clip it to the plotting area and output. */ GeoClip(&rootArea, &bbox); xbot = rootArea.r_xbot - bbox.r_xbot; width = rootArea.r_xtop - rootArea.r_xbot; ybot = rootArea.r_ybot - bbox.r_ybot; height = rootArea.r_ytop - rootArea.r_ybot; /* compare against last output rectangle and merge if possible */ if ((width == curwidth) && (xbot == curxbot) && ((tmptf = (ybot == curybot + curheight)) || (ybot + height == curybot))) { curheight += height; if (!tmptf) curybot = ybot; } else if ((height == curheight) && (ybot == curybot) && ((tmptf = (xbot == curxbot + curwidth)) || (xbot + width == curxbot))) { curwidth += width; if (!tmptf) curxbot = xbot; } else { plotPSFlushRect(curStyle->grs_stipple); curheight = height; curwidth = width; curxbot = xbot; curybot = ybot; } if (PlotPSBoundary && (curLineWidth != PS_THIN)) { fprintf(file, "l1\n"); curLineWidth = PS_THIN; } } if (!PlotPSBoundary) return 0; /* No borders */ /* 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). * * (This code is essentially a duplicate of selRedisplayFunc()) */ 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(&scx->scx_trans, &edge, &rootArea); plotPSLine(&rootArea.r_ll, &rootArea.r_ur); } } /* Now go along the tile's left border, doing the same thing. Ignore * edges that are at infinity. */ searchleft: if (IsSplit(tile) && SplitSide(tile)) goto searchtop; /* Nothing on left side of tile */ 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(&scx->scx_trans, &edge, &rootArea); plotPSLine(&rootArea.r_ll, &rootArea.r_ur); } } /* 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(&scx->scx_trans, &edge, &rootArea); plotPSLine(&rootArea.r_ll, &rootArea.r_ur); } } /* 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(&scx->scx_trans, &edge, &rootArea); plotPSLine(&rootArea.r_ll, &rootArea.r_ur); } } return 0; } /* * ---------------------------------------------------------------------------- * * plotPSLabelPosition -- * * Determine the label position, orientation, and approximate bounding box * * ---------------------------------------------------------------------------- */ int plotPSLabelPosition(scx, label, x, y, p) SearchContext *scx; /* Describes state of search when label * was found. */ Label *label; /* Label that was found. */ int *x; /* returned x position */ int *y; /* returned y position */ int *p; /* returned orientation */ { Rect rootArea; int pos; /* Mapping from our GEO_xxx positions to PS object types: */ static int psPosition[] = { 5, /* CENTCENT */ 1, /* TOPCENT */ 0, /* TOPRIGHT */ 4, /* CENTRIGHT */ 12, /* BOTRIGHT */ 13, /* BOTCENT */ 15, /* BOTLEFT */ 7, /* CENTLEFT */ 3 /* TOPLEFT */ }; GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea); pos = GeoTransPos(&scx->scx_trans, label->lab_just); switch (pos) { case GEO_NORTH: case GEO_NORTHEAST: case GEO_NORTHWEST: *y = (rootArea.r_ytop - bbox.r_ybot); *y += delta; break; case GEO_CENTER: case GEO_WEST: case GEO_EAST: *y = (rootArea.r_ytop + rootArea.r_ybot) / 2 - bbox.r_ybot; break; case GEO_SOUTH: case GEO_SOUTHEAST: case GEO_SOUTHWEST: *y = (rootArea.r_ybot - bbox.r_ybot); *y -= delta; break; } switch (pos) { case GEO_WEST: case GEO_NORTHWEST: case GEO_SOUTHWEST: *x = (rootArea.r_xbot - bbox.r_xbot); *x -= delta; break; case GEO_CENTER: case GEO_NORTH: case GEO_SOUTH: *x = (rootArea.r_xtop + rootArea.r_xbot) / 2 - bbox.r_xbot; break; case GEO_EAST: case GEO_NORTHEAST: case GEO_SOUTHEAST: *x = (rootArea.r_xtop - bbox.r_xbot); *x += delta; break; } *p = psPosition[pos]; return 0; } /* * ---------------------------------------------------------------------------- * * plotPSLabelBounds -- * * Estimate the bounding box extension based on label strings. * In reality, we need to know label sizes to compute the scale, * and we need to know the scale to compute label sizes. However, * in practice, we can only estimate the label size anyway, so we * allow for some slop and just wing it. * * ---------------------------------------------------------------------------- */ #define AVGCHARWIDTH 0.7 #define CHARHEIGHT 1.4 int plotPSLabelBounds(scx, label) SearchContext *scx; /* Describes state of search when label * was found. */ Label *label; /* Label that was found. */ { int pspos; int ls, psxsize, psysize; int llx, lly, urx, ury; int psdelta = (int)((float)delta / fscale); plotPSLabelPosition(scx, label, &llx, &lly, &pspos); urx = (int)((float)(llx - bbox.r_xtop) / fscale); ury = (int)((float)(lly - bbox.r_ytop) / fscale); llx = (int)((float)(bbox.r_xbot - llx) / fscale); lly = (int)((float)(bbox.r_ybot - lly) / fscale); ls = strlen(label->lab_text); psxsize = ls * (int)((float)PlotPSLabelSize * AVGCHARWIDTH); psysize = (int)((float)PlotPSLabelSize * CHARHEIGHT); switch (pspos) { case 0: ury += psysize + psdelta; urx += psxsize + psdelta; break; case 4: ury += psysize / 2; lly += psysize / 2; urx += psxsize + psdelta; break; case 12: lly += psysize + psdelta; urx += psxsize + psdelta; break; case 13: lly += psysize + psdelta; urx += psxsize / 2; llx += psxsize / 2; break; case 15: lly += psysize + psdelta; llx += psxsize + psdelta; break; case 7: ury += psysize / 2; lly += psysize / 2; llx += psxsize + psdelta; break; case 3: ury += psysize + psdelta; llx += psxsize + psdelta; break; case 1: ury += psysize + psdelta; urx += psxsize / 2; llx += psxsize / 2; break; case 5: ury += psysize / 2; lly += psysize / 2; urx += psxsize / 2; llx += psxsize / 2; break; } if (xpmargin < urx) xpmargin = urx; if (ypmargin < ury) ypmargin = ury; if (xnmargin < llx) xnmargin = llx; if (ynmargin < lly) ynmargin = lly; return 0; } /* * ---------------------------------------------------------------------------- * * plotPSLabelBox -- * * Output the box connected to a label * * ---------------------------------------------------------------------------- */ int plotPSLabelBox(scx, label) SearchContext *scx; /* Describes state of search when label * was found. */ Label *label; /* Label that was found. */ { Rect rootArea; int x, y; GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea); /* 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 (curLineWidth != PS_MEDIUM) { fprintf(file, "l2\n"); curLineWidth = PS_MEDIUM; } if ((rootArea.r_xbot == rootArea.r_xtop) && (rootArea.r_ybot == rootArea.r_ytop)) { /* Point label. Output a cross. */ x = (rootArea.r_xbot - bbox.r_xbot); y = (rootArea.r_ybot - bbox.r_ybot); fprintf(file, "%d %d %d pl\n", delta, x, y); } else if ((rootArea.r_xbot == rootArea.r_xtop) || (rootArea.r_ybot == rootArea.r_ytop)) { /* Line label. Just draw a medium-thickness line. */ plotPSLine(&rootArea.r_ll, &rootArea.r_ur); } else { /* Rectangular. Draw lines around the boundary. */ plotPSRect(&rootArea, 0); } return 0; } /* * ---------------------------------------------------------------------------- * * plotPSLabel -- * * This procedure is invoked once for each label overlapping the * area being plotted. It generates PS output to describe * the label. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * PS information is output. * * ---------------------------------------------------------------------------- */ int plotPSLabel(scx, label) SearchContext *scx; /* Describes state of search when label * was found. */ Label *label; /* Label that was found. */ { int x, y; int pspos; plotPSLabelPosition(scx, label, &x, &y, &pspos); /* Output the text for the label, if the label is within delta * of the area we're plotting (a large label could overlap a * bit of the area but stick out way off-screen too). */ if ((x >= -delta) && (y >= -delta) && (x <= (bbox.r_xtop - bbox.r_xbot) + delta) && (y <= (bbox.r_ytop - bbox.r_ybot) + delta)) { fprintf(file, "(%s) %d %d %d lb\n", label->lab_text, pspos, x, y); } return 0; } /* * ---------------------------------------------------------------------------- * * plotPSCell -- * * This procedure is invoked once for each unexpanded cell that * overlaps the area being plotted. * * Results: * Always returns 0 to keep the search from aborting. * * Side effects: * PS information is output to describe the cell. * * ---------------------------------------------------------------------------- */ int plotPSCell(scx) SearchContext *scx; /* Describes cell whose bbox is to * be plotted. */ { extern bool PlotShowCellNames; char idName[100]; Rect rootArea; CellDef *def; int x, y; /* 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); if (curLineWidth != PS_THICK) { fprintf(file, "l3\n"); curLineWidth = PS_THICK; } plotPSRect(&rootArea, 0); if (!PlotShowCellNames) return 0; /* Output the cell definition's name in the top of the bounding box. * Use a bold font (#3), in a medium size (#2). Make sure that the * name's positioning point is within the area we're plotting. */ x = (rootArea.r_xtop + rootArea.r_xbot - 2*bbox.r_xbot)/2; y = (2*rootArea.r_ytop + rootArea.r_ybot - 3*bbox.r_ybot)/3; if ((x >= 0) && (y >= 0) && (x <= (bbox.r_xtop - bbox.r_xbot)) && (y <= (bbox.r_ytop - bbox.r_ybot))) { fprintf(file, "f2 (%s) 5 %d %d lb\n", def->cd_name, x, y); } /* Output the cell id in the bottom of the bounding box. * Use an italic font (#2) in a medium size (#2). */ x = (rootArea.r_xtop + rootArea.r_xbot - 2*bbox.r_xbot)/2; y = (rootArea.r_ytop + 2*rootArea.r_ybot - 3*bbox.r_ybot)/3; if ((x >= 0) && (y >= 0) && (x <= (bbox.r_xtop - bbox.r_xbot)) && (y <= (bbox.r_ytop - bbox.r_ybot))) { (void) DBPrintUseId(scx, idName, 100, TRUE); fprintf(file, "f3 (%s) 5 %d %d lb\n", idName, x, y); } return 0; } /* * ---------------------------------------------------------------------------- * * PlotPS -- * * This procedure generates a PS file to describe an area of * a layout. * * Results: * None. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ void PlotPS(fileName, scx, layers, xMask) char *fileName; /* Name of PS file to write. */ 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 xsize, ysize; float yscale; int i, j; int twidth, theight; char *fontptr, *fptr2, *fptr3; char line_in[100]; PSReset(); /* Compute a scale factor between our coordinates and PS * coordinates. */ GeoTransRect(&scx->scx_trans, &scx->scx_area, &bbox); xsize = bbox.r_xtop - bbox.r_xbot; ysize = bbox.r_ytop - bbox.r_ybot; fscale = (float)(PlotPSWidth - 2 * PlotPSMargin) / (float)xsize; yscale = (float)(PlotPSHeight - 2 * PlotPSMargin) / (float)ysize; if (yscale < fscale) fscale = yscale; /* 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) delta = RtrMetalWidth / 8; else delta = RtrPolyWidth / 8; if (delta == 0) delta = 1; /* Go through labels once to estimate the bounding box, including labels */ xnmargin = ynmargin = xpmargin = ypmargin = 0; if (TTMaskHasType(layers, L_LABEL)) { curMask = *layers; TTMaskSetType(&curMask, TT_SPACE); (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL, TF_LABEL_ATTACH, plotPSLabelBounds, (ClientData) NULL); fscale = (float)(PlotPSWidth - 2 * PlotPSMargin - xnmargin - xpmargin) / (float)(xsize); yscale = (float)(PlotPSHeight - 2 * PlotPSMargin - ynmargin - ypmargin) / (float)(ysize); if (yscale < fscale) fscale = yscale; } twidth = (xsize * fscale) + xnmargin + xpmargin; theight = (ysize * fscale) + ynmargin + ypmargin; /* Open the PS file and output header information. */ file = PaOpen(fileName, "w", (char *) NULL, ".", (char *) NULL, (char **) NULL); if (file == NULL) { TxError("Couldn't write PS file \"%s\".\n", fileName); return; } fprintf(file, "%%!PS-Adobe-3.0 EPSF-3.0\n"); fprintf(file, "%%%%BoundingBox: %d %d %d %d\n", PlotPSMargin, PlotPSMargin, twidth + PlotPSMargin, theight + PlotPSMargin); fontptr = PlotPSIdFont; fprintf(file, "%%%%DocumentNeededResources: font %s", fontptr); if (!Match(fptr2 = PlotPSNameFont, fontptr)) fprintf(file, " font %s", fptr2); if (!Match(fptr3 = PlotPSLabelFont, fontptr)) if (!Match(fptr3, fptr2)) fprintf(file, " font %s", fptr3); fprintf(file, "\n"); fprintf(file, "%%%%EndComments\n"); /* Insert the prolog here */ { FILE *infile = PaOpen("magicps", "r", ".pro", ".", SysLibPath, NULL); if (infile != NULL) { while(fgets(line_in, 99, infile) != NULL) fputs(line_in, file); fclose(infile); } else fprintf(file, "\npostscript_prolog_is_missing\n\n"); } /* Insert the font definitions here. */ fprintf(file, "/f1 { %.3f %s sf } def\n", (float)PlotPSLabelSize / fscale, PlotPSLabelFont); fprintf(file, "/f2 { %.3f %s sf } def\n", (float)PlotPSNameSize / fscale, PlotPSNameFont); fprintf(file, "/f3 { %.3f %s sf } def\n", (float)PlotPSIdSize / fscale, PlotPSIdFont); /* Insert the color and stipple definitions here. */ for (curColor = plotPSColors; curColor != NULL; curColor = curColor->col_next) { fprintf(file, "/col%d {%.3f %.3f %.3f %.3f sc} bind def\n", curColor->index, (float)curColor->color[0] / 255.0, (float)curColor->color[1] / 255.0, (float)curColor->color[2] / 255.0, (float)curColor->color[3] / 255.0); } for (curPattern = plotPSPatterns; curPattern != NULL; curPattern = curPattern->pat_next) { fprintf(file, "{<"); for (j = 0; j < 8; j++) fprintf(file, "%08lx%08lx", curPattern->stipple[j], curPattern->stipple[j]); fprintf(file, ">} %d dp\n", curPattern->index); } fprintf(file, "%%%%EndResource\n%%%%EndProlog\n\n"); fprintf(file, "%%%%Page: 1 1\n"); fprintf(file, "/pgsave save def bop\n"); fprintf(file, "%% 0 0 offsets\nninit\n"); fprintf(file, "%d %d translate\n", PlotPSMargin + xnmargin, PlotPSMargin + ynmargin); fprintf(file, "%.3f %.3f scale\nminit\n", fscale, fscale); fprintf(file, "0 0 %d %d gsave rectclip\n", xsize, ysize); fprintf(file, "l2\nsp\n\n"); curLineWidth = PS_MEDIUM; /* For each PS style, find all the paint layers that belong * to that style and put plot information into the file. */ for (curStyle = plotPSStyles; curStyle != NULL; curStyle = curStyle->grs_next) { fprintf(file, "col%d\n", curStyle->grs_color); if (curStyle->grs_stipple >= 0) fprintf(file, "%d sl\n", curStyle->grs_stipple); TTMaskAndMask3(&curMask, layers, &curStyle->grs_layers); (void) DBTreeSrTiles(scx, &curMask, xMask, plotPSPaint, (ClientData) NULL); plotPSFlushRect(curStyle->grs_stipple); plotPSFlushLine(); PSReset(); } /* Output subcell bounding boxes, if they are wanted. */ if (TTMaskHasType(layers, L_CELL)) { (void) DBTreeSrCells(scx, xMask, plotPSCell, (ClientData) NULL); plotPSFlushRect(BORDER); plotPSFlushLine(); } /* Output label boxes followed by labels */ if (TTMaskHasType(layers, L_LABEL)) { curMask = *layers; TTMaskSetType(&curMask, TT_SPACE); (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL, TF_LABEL_ATTACH, plotPSLabelBox, (ClientData) NULL); plotPSFlushRect(BORDER); plotPSFlushLine(); PSReset(); fprintf(file, "grestore\n"); /* end clipping rectangle */ fprintf(file, "f1 0 setgray\n"); /* set font, set color to black */ curMask = *layers; TTMaskSetType(&curMask, TT_SPACE); (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL, TF_LABEL_ATTACH, plotPSLabel, (ClientData) NULL); } else { fprintf(file, "grestore\n"); /* end clipping rectangle */ } /* Output trailer information into the file, and close it. */ fprintf(file, "pgsave restore showpage\n\n"); fprintf(file, "%%%%Trailer\nMAGICsave restore\n%%%%EOF\n"); fclose(file); return; }