Files
magic/plot/plotPixels.c
T
R. Timothy Edwards 516c9d7635 First cut of pulling the TT_SIDE bit out of the tile database
and forcing it to be passed as an argument to all the callback
functions for the search routines that require it.  Magic now
compiles and runs with the new code, but there are a number of
known issues that need to be fixed up.  Committing now so that
I can rebase on the last update to the master branch.
2026-01-09 12:05:03 -05:00

1489 lines
41 KiB
C

/*
* 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, dinfo, cxp)
Tile *tile; /* Tile that's of type to be output. */
TileType dinfo; /* Split tile information (unhandled) */
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 */