Files
magic/plot/plotVers.c
T
Darryl L. Miles e88dcba1c5 CodeQL File{MayNot,Never}BeClosed.ql file-handle resource leaks
Guided by CodeQL static code analyser.

FileMayNotBeClosed.ql
FileMayNeverBeClosed.ql

The trick with "if(fp != stdout)" is problematic (to analyser) as
technically 'stdout' can be a global pointer that COULD be modified any
time, so it might have changed between the fopen() and fclose() calls so
the close MAY NEVER occurs (which is problem the analyzer can see).

So local state is maintained as a bool which will also clarify to the
compiler see the intention without concern for external stdout
modification.

Some items appear to be out and out leaks when certain commands are use.
2025-02-22 21:02:49 -05:00

1489 lines
42 KiB
C

/*
* 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 <stdio.h>
#include <string.h>
/* C99 compat */
#include <stdlib.h>
#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() */
/* C99 compat */
#include "plot/plotInt.h"
#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
{
unsigned int value;
int i;
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 const struct { const 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
{
unsigned int value;
int i, j;
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], (const 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 const char * const 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");
goto error_close_only;
}
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");
goto error_close_only;
}
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);
return;
error_close_only:
fclose(file);
}
#endif /* VERSATEC */