Logo Search packages:      
Sourcecode: magic version File versions  Download package

plotPixels.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-7.5/plot/plotPixels.c,v 1.4 2008/01/29 02:41:57 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,
                         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 */

Generated by  Doxygen 1.6.0   Back to index