magic/plot/plotPixels.c

1488 lines
41 KiB
C
Raw Normal View History

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