magic/plot/plotPS.c

1322 lines
35 KiB
C

/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}