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

plotVers.c

/*
 * plotVers.c --
 *
 * This file contains the procedures that generate plots on
 * Versatec-style black-and-white printers.
 *
 *     ********************************************************************* 
 *     * Copyright (C) 1985, 1990 Regents of the University of California. * 
 *     * Permission to use, copy, modify, and distribute this              * 
 *     * software and its documentation for any purpose and without        * 
 *     * fee is hereby granted, provided that the above copyright          * 
 *     * notice appear in all copies.  The University of California        * 
 *     * makes no representations about the suitability of this            * 
 *     * software for any purpose.  It is provided "as is" without         * 
 *     * express or implied warranty.  Export of this software outside     * 
 *     * of the United States of America may require an export license.    * 
 *     *********************************************************************
 */

#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-7.5/plot/plotVers.c,v 1.17 2008/11/16 22:06:54 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <stdlib.h>           /* For random() */
#include <string.h>
#include <math.h>       /* For dot cluster stipple generation */

#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "plot/plotInt.h"
#include "windows/windows.h"
#include "commands/commands.h"
#include "textio/textio.h"
#include "utils/utils.h"
#include "utils/tech.h"
#include "utils/signals.h"
#include "dbwind/dbwind.h"
#include "cif/cif.h"          /* for CIFGetOutputScale() */

#include "graphics/graphics.h"      /* for automatic color-versatec color setup */
#include "utils/styles.h"
#include "dbwind/dbwtech.h"

#ifdef VERSATEC

/* Library imports: */

extern int rasFileByteCount; 
  
/* Records of the following type are used to describe how to generate
 * output for the mask layers.  Each style describes a particular
 * stipple pattern.
 */

00061 typedef struct versatecstyle
{
    TileTypeBitMask vs_layers;            /* Layers to plot in this style. */
    Stipple vs_stipple;             /* Area stipple pattern to use. */
    Stipple vs_lineStipple;         /* Line stipple pattern to use. */
    int vs_flags;             /* Flag bits, see below. */
    struct versatecstyle *vs_next;  /* Pointer to next style in list. */

            /* If the color flag is false, all stipples will be black */
    VersatecColor vs_color;         /* Stipple color */
} VersatecStyle;

/* Flag values for VersatecStyles:
 *
 * VS_CROSS -     if this bit is set, then generate an outline with an
 *          X through the middle, like for contacts, instead of
 *          stippling.  The stipple pattern is ignored in this
 *          case.
 * VS_BORDER -    if this bit is set, generate an outline with no X
 *          through the middle and no stipple.  The stipple
 *          pattern is ignored in this case.
 */

#define VS_CROSS 1
#define VS_BORDER 2

static VersatecStyle *plotVersStyles;
static VersatecStyle *plotColorVersStyles;

char *plotVersatecColorNames[] = {
    "Black",
    "Cyan",
    "Magenta",
    "Yellow"
};

/*
 * ----------------------------------------------------------------------------
 * The parameters below control various aspects of the plotting
 * process.  The initial values are defaults for the versatec
 * printer.  However, many of them can be modified by users
 * with the "plot option" command.
 * ----------------------------------------------------------------------------
 */

/* Supported format.  Default is "hprtl". */

unsigned char PlotVersPlotType = HPRTL;

float PlotVersGamma = 1.0;    /* When auto-generating stipples, use
                         * this value for gamma (color value
                         * scaling; values > 1 make colors lighter)
                         */

int PlotVersWidth = 2400;     /* Number of dots across Versatec page.
                         * Should be a multiple of 32.
                         */
int PlotVersDotsPerInch = 300;      /* Dots per inch. */
int PlotVersSwathHeight = 64; /* Width of swath to generate at one time,
                         * in dots.
                         */

/* Name of printer to use for output: */

static char *defaultPrinter = "versatec";
char *PlotVersPrinter = NULL;

/* Command to use to actually print rasterized file.  Contains two %s'es,
 * which are supplied with the printer name and the name of the raster file.
 */

static char *defaultCommand = "lp -d %s %s";
char *PlotVersCommand = NULL;

/* Directory in which to create temporary file to hold raster: */

static char *defaultDirectory = "/tmp";
char *PlotTempDirectory = NULL;

/* Name of fonts to use: */

static char *defaultIdFont = "vfont.I.12";
char *PlotVersIdFont = NULL;
static char *defaultNameFont = "vfont.B.12";
char *PlotVersNameFont = NULL;
static char *defaultLabelFont = "vfont.R.8";
char *PlotVersLabelFont = NULL;

/*
 * ----------------------------------------------------------------------------
 * The variables below are shared between the top-level Versatec
 * plotting procedure and the lower-level search functions.  They
 * contain specific information about how to generate the current
 * plot.  There area three coordinate systems of interest here:
 *
 * 1. Magic root coordinates.
 * 2. Raster coordinates:  based on printer pixels, one unit per pixel,
 *    where (0,0) corresponds to the lower-leftmost dot that will be
 *    printed.
 * 3. Swath coordinates:  the raster will be much too large to keep in
 *    memory all at once, so it's generated in a series of horizontal
 *    swaths.  The stippling routines all work in swath-relative
 *    coordinates, which are the same as raster coordinates except for
 *    a y-displacement (swathY below).
 * ----------------------------------------------------------------------------
 */

Point plotLL;           /* Point in root Magic coords that corresponds
                         * to (0,0) in raster coordinates.
                         */
int swathY;       /* The y-coordinate in raster coordinates that
                         * corresponds to (0,0) in swath coords.  It's
                         * always >= 0.
                         */
static int scale;       /* How many (2**scaleShift)-ths of a pixel
                         * correspond to one Magic unit.
                         */
int scaleShift;         /* The idea is that one Magic unit is equal
                         * to scale/(2**scaleShift) pixels.
                         */
static Rect rootClip;         /* Total root area of the plot.  Used for
                         * clipping.
                         */
static Rect swathClip;        /* Rectangle used for clipping to the area of
                         * the current swath.  This is in swath
                         * coordinates.
                         */
static VersatecStyle *curStyle;     /* Current style being processed. */
static TileTypeBitMask curMask; /* Mask of layers currently being stippled.
                         * This is the AND of the mask from curStyle
                         * and the layers that the user wants plotted.
                         */
static int crossSize;         /* Length of each arm of the crosses used
                         * to draw labels, in pixel units.
                         */
static RasterFont *labelFont;  /* Font to use when rendering labels. */
static RasterFont *cellNameFont; /* Font to use when rendering cell names. */
static RasterFont *cellIdFont;       /* Font to use when rendering cell ids. */

#endif /* VERSATEC */

/*
 * ----------------------------------------------------------------------------
 *    PlotVersTechInit --
 *
 *    Called once at beginning of technology file read-in to initialize
 *    data structures.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Clears out the list of things to plot.
 * ----------------------------------------------------------------------------
 */

#ifdef VERSATEC

void
PlotVersTechInit()
{
    VersatecStyle *style;

    for (style = plotVersStyles; style != NULL; style = style->vs_next)
    {
      freeMagic((char *) style);
    }
    plotVersStyles = NULL;

    if (PlotVersPrinter == NULL)
      StrDup(&PlotVersPrinter, defaultPrinter);
    if (PlotVersCommand == NULL)
      StrDup(&PlotVersCommand, defaultCommand);
    if (PlotTempDirectory == NULL)
      StrDup(&PlotTempDirectory, defaultDirectory);
    if (PlotVersIdFont == NULL)
      StrDup(&PlotVersIdFont, defaultIdFont);
    if (PlotVersNameFont == NULL)
      StrDup(&PlotVersNameFont, defaultNameFont);
    if (PlotVersLabelFont == NULL)
      StrDup(&PlotVersLabelFont, defaultLabelFont);
}

#else

void
PlotVersTechInit()
{}

#endif /* VERSATEC */

#ifdef VERSATEC


/*
 * ----------------------------------------------------------------------------
 *    PlotColorVersTechInit --
 *
 *    Called once at beginning of technology file read-in to initialize
 *    data structures.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Clears out the list of things to plot.
 * ----------------------------------------------------------------------------
 */

void
PlotColorVersTechInit()
{
    VersatecStyle *style;

    for (style = plotColorVersStyles; style != NULL; style = style->vs_next)
    {
      freeMagic((char *) style);
    }
    plotColorVersStyles = NULL;

    if (PlotVersPrinter == NULL)
      StrDup(&PlotVersPrinter, defaultPrinter);
    if (PlotVersCommand == NULL)
      StrDup(&PlotVersCommand, defaultCommand);
    if (PlotTempDirectory == NULL)
      StrDup(&PlotTempDirectory, defaultDirectory);
    if (PlotVersIdFont == NULL)
      StrDup(&PlotVersIdFont, defaultIdFont);
    if (PlotVersNameFont == NULL)
      StrDup(&PlotVersNameFont, defaultNameFont);
    if (PlotVersLabelFont == NULL)
      StrDup(&PlotVersLabelFont, defaultLabelFont);
}

/*
 * ----------------------------------------------------------------------------
 *    PlotColorVersTechFinal --
 *
 *    Called once at end of technology file read-in to create a default
 *    style if none was defined, and to fill in line stipple patterns.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Clears out the list of things to plot.
 * ----------------------------------------------------------------------------
 */

void
PlotColorVersTechFinal()
{
    VersatecStyle *new, *style;
    int cs, i, j, k, l, m, fill, stipple;
    int cc, ff, red, green, blue, colors[3];

    if (plotColorVersStyles == NULL)
    {
      /* Generate temporary halftone screens for each color.      */

      int p[YELLOW + 1];
      int CMYstip[16][16];
      int CMYorder[YELLOW + 1][256][2];
      double t, r, x, y;

      for (k = 0; k < 4; k++)
      {
          p[k] = 0;
          for (i = 0; i < 256; i++)
            for (j = 0; j < 2; j++)
                CMYorder[k][i][j] = 0;
      }
      for (i = 0; i < 16; i++)
          for (j = 0; j < 16; j++)
            CMYstip[i][j] = 0;

      t = r = 0.0;
      for (k = 0; k < 16384; k++)
      { 
         x = r * cos(t);
         y = r * sin(t);      /* Expanding spiral */

         /* Magenta center dot */
         i = (int)(x + 8.5);
         j = (int)(y + 8.5);
         if (i >= 0 && i < 16 && j >= 0 && j < 16 && (CMYstip[i][j] & 1) == 0) {
            CMYstip[i][j] |= 1;
            CMYorder[MAGENTA][p[MAGENTA]][0] = i;
            CMYorder[MAGENTA][p[MAGENTA]][1] = j;
            p[MAGENTA]++;
         }

         /* Magenta corner dot */
         i = (int)((x < 0) ? x + 17 : x);
         j = (int)((y < 0) ? y + 17 : y);
         if (i >= 0 && i < 16 && j >= 0 && j < 16 && (CMYstip[i][j] & 1) == 0) {
            CMYstip[i][j] |= 1;
            CMYorder[MAGENTA][p[MAGENTA]][0] = i;
            CMYorder[MAGENTA][p[MAGENTA]][1] = j;
            p[MAGENTA]++;
         }

         /* Cyan top/bottom dot */
         i = (int)(x + 8.5);
         j = (int)((y < 0) ? y + 17 : y);
         if (i >= 0 && i < 16 && j >= 0 && j < 16 && (CMYstip[i][j] & 2) == 0) {
            CMYstip[i][j] |= 2;
            CMYorder[CYAN][p[CYAN]][0] = i;
            CMYorder[CYAN][p[CYAN]][1] = j;
            p[CYAN]++;
         }

         /* Cyan left/right dot */

         i = (int)((x < 0) ? x + 17 : x);
         j = (int)(y + 8.5);
         if (i >= 0 && i < 16 && j >= 0 && j < 16 && (CMYstip[i][j] & 2) == 0) {
            CMYstip[i][j] |= 2;
            CMYorder[CYAN][p[CYAN]][0] = i;
            CMYorder[CYAN][p[CYAN]][1] = j;
            p[CYAN]++;
         }

         /* Yellow lower-left dot */

         i = (int)((x < -4.25) ? x + 12.75 : x + 4.25);
         j = (int)((y < -4.25) ? y + 12.75 : y + 4.25);
         if (i >= 0 && i < 16 && j >= 0 && j < 16 && (CMYstip[i][j] & 4) == 0) {
            CMYstip[i][j] |= 4;
            CMYorder[YELLOW][p[YELLOW]][0] = i;
            CMYorder[YELLOW][p[YELLOW]][1] = j;
            p[YELLOW]++;
         }

         /* Yellow upper-right dot */

         i = (int)((x > 4.25) ? x - 4.25 : x + 12.75);
         j = (int)((y > 4.25) ? y - 4.25 : y + 12.75);
         if (i >= 0 && i < 16 && j >= 0 && j < 16 && (CMYstip[i][j] & 4) == 0) {
            CMYstip[i][j] |= 4;
            CMYorder[YELLOW][p[YELLOW]][0] = i;
            CMYorder[YELLOW][p[YELLOW]][1] = j;
            p[YELLOW]++;
         }

         /* Increase radius and angle to move outward on spiral */
         t += 0.05;
         // r += 0.005;
         r += 0.002;
      }
      
      for (j = 0; j < DBWNumStyles; j++)
      {
          cc = GrStyleTable[j + TECHBEGINSTYLES].color;
          GrGetColor(cc, &red, &green, &blue);
          // colors[0] = 255 - red;
          // colors[1] = 255 - green;
          // colors[2] = 255 - blue;
          colors[0] = (int)(255.0 * pow((1.0 - ((double)red / 255.0)),
                  PlotVersGamma));
          colors[1] = (int)(255.0 * pow((1.0 - ((double)green / 255.0)),
                  PlotVersGamma));
          colors[2] = (int)(255.0 * pow((1.0 - ((double)blue / 255.0)),
                  PlotVersGamma));

          for (cc = CYAN; cc <= YELLOW; cc++)
          {
            new = (VersatecStyle *)mallocMagic(sizeof(VersatecStyle));
            TTMaskZero(&new->vs_layers);
            TTMaskSetMask(&new->vs_layers, DBWStyleToTypes(j));

            /* Set the Versatec style to border or cross if the   */
            /* display style is so defined.                       */

            new->vs_color = cc;
            new->vs_flags = 0;
            switch (GrStyleTable[j + TECHBEGINSTYLES].fill)
            {
                case GR_STCROSS:
                  new->vs_flags = VS_CROSS;
                  break;
                case GR_STOUTLINE:
                  new->vs_flags = VS_BORDER;
                  break;
                case GR_STSTIPPLE:
                  stipple = GrStyleTable[j + TECHBEGINSTYLES].stipple;
                  break;
                case GR_STSOLID:
                  stipple = -1;
                  break;
            }

            /* Clear the stipple */
            for (i = 0; i < 16; i++) new->vs_stipple[i] = 0;

            /* Fill bits of vs_stipple to match the color, using  */
            /* dot clusters computed above.  To avoid aliasing    */
            /* effects from the display stipple masks, we ensure  */
            /* that the correct density of each color plane is    */
            /* met for the area defined by the display stipple.   */

            /* Display style stipple is 8x8; PlotVers stipple is  */
            /* 16 x 16, so we correct for the factor of 2.        */

            fill = colors[cc - CYAN];

            /* Find the number of pixels to fill, and prorate fill      */
            /* factor accordingly.                          */

            if (stipple >= 0)
            {
                ff = 0;
                for (i = 0; i < 8; i++)
                  for (k = 0; k < 8; k++)
                  {
                      l = GrStippleTable[stipple][i];
                      if (((l >> k) & 0x1) != 0)
                        ff += 4;
                  }
                fill *= ff;
                fill /= 256;
            }

            /* Fill the color plane stipples where they           */
            /* intersect with the display stipple, up to the      */
            /* color density required.                      */

            ff = 0;           /* cumulative fill factor */
            for (m = 0; m < 256; m++)
            {
                i = CMYorder[cc][m][0];
                k = CMYorder[cc][m][1];
                if (stipple >= 0)
                {
                  l = GrStippleTable[stipple][i >> 1];
                  if (((l >> ((k % 16) >> 1)) & 0x1) == 0)
                      continue;
                }

                new->vs_stipple[i] |= (0x1 << k);
                new->vs_stipple[i] |= (0x1 << (16 + k));
                if (++ff > fill) break;
            }

            new->vs_next = plotColorVersStyles;
            plotColorVersStyles = new;
          }
      }
    }

    for (style = plotColorVersStyles; style != NULL; style = style->vs_next)
    {
      fill = 0;
      for (i = 0; i < 16; i++)
      {
          cs = style->vs_stipple[i];
          for (j = 0; j < 8 * sizeof(int); j++)
          {
            if (cs & 0x1) fill++;
            cs >>= 1;
          }
      }

      /* "fill" is the number of bits of this color out of 512. */
      /* Now make it 30% darker */

      fill = (512 + 2 * fill) / 3;

      /* Randomly fill bits of vs_lineStipple to the density of "fill" */
      for (i = 0; i < 16; i++)
      {
          cs = 0;
          for (j = 0; j < 8 * sizeof(int); j++)
          {
            cs <<= 1;
            if ((random() % 512) < fill) cs |= 0x1;
          }
          style->vs_lineStipple[i] = cs;
      }
    }
}

#else

void
PlotColorVersTechInit()
{}

void
PlotColorVersTechFinal()
{}

#endif /* VERSATEC */


/*
 * ----------------------------------------------------------------------------
 *    PlotVersTechLine --
 *
 *    This procedure is invoked by the technology module once for
 *    each line in the "versatec" subsection of the "plot" section
 *    of the technology file.
 *
 * Results:
 *    Always returns TRUE (otherwise the technology module would
 *    abort Magic with a fatal error).
 *
 * Side effects:
 *    Builds up the table of Versatec styles.
 * ----------------------------------------------------------------------------
 */

#ifdef VERSATEC

bool
PlotVersTechLine(sectionName, argc, argv)
    char *sectionName;        /* Name of this section (unused). */
    int argc;                 /* Number of arguments on line. */
    char *argv[];       /* Pointers to fields of line. */
{
    VersatecStyle *new;
    int i;

    new = (VersatecStyle *) mallocMagic(sizeof(VersatecStyle));

    DBTechNoisyNameMask(argv[0], &new->vs_layers);

    if (argc == 2)
    {
        if (strcmp(argv[1], "X") == 0)
          new->vs_flags = VS_CROSS;
      else if (strcmp(argv[1], "B") == 0)
          new->vs_flags = VS_BORDER;
      else
      {
          TechError("Second field must be \"X\" or \"B\"\n");
          freeMagic((char *) new);
          return TRUE;
      }
    }
    else
    {
      int i, value;

      if (argc != 17)
      {
          TechError("\"versatec\" lines must have either 2 or 17 fields.\n");
          freeMagic((char *)new);
          return TRUE;
      }
      new->vs_color = 0;
      new->vs_flags = 0;
      for (i = 0; i < 16; i++)
      {
          (void) sscanf(argv[i+1], "%x", &value);
          new->vs_stipple[i] = (value<<16) | (value & 0xffff);
#ifndef WORDS_BIGENDIAN
          new->vs_stipple[i] = PlotSwapBytes(new->vs_stipple[i]);
#endif  /* WORDS_BIGENDIAN */
      }
    }

    new->vs_next = plotVersStyles;
    plotVersStyles = new;

    return TRUE;
}

#else

bool
PlotVersTechLine(sectionName, argc, argv)
    char *sectionName;        /* Name of this section (unused). */
    int argc;                 /* Number of arguments on line. */
    char *argv[];       /* Pointers to fields of line. */
{
    return TRUE;
}

#endif /* VERSATEC */

/*
 * ----------------------------------------------------------------------------
 *    PlotColorVersTechLine --
 *
 *    This procedure is invoked by the technology module once for
 *    each line in the "colorversatec" subsection of the "plot" section
 *    of the technology file.
 *
 * Results:
 *    Always returns TRUE (otherwise the technology module would
 *    abort Magic with a fatal error).
 *
 * Side effects:
 *    Builds up the table of ColorVersatec styles.
 * ----------------------------------------------------------------------------
 */

#ifdef VERSATEC

bool
PlotColorVersTechLine(sectionName, argc, argv)
    char *sectionName;        /* Name of this section (unused). */
    int argc;                 /* Number of arguments on line. */
    char *argv[];       /* Pointers to fields of line. */
{
    VersatecStyle *new;
    static struct { char *l_str; int l_color; } colors[] = {
      "black",   BLACK,
      "cyan",        CYAN,
      "magenta", MAGENTA,
      "yellow",  YELLOW,
      "K",     BLACK,
      "C",     CYAN,
      "M",     MAGENTA,
      "Y",     YELLOW,
      0
    };
    int i;

    new = (VersatecStyle *)mallocMagic(sizeof(VersatecStyle));

    DBTechNoisyNameMask(argv[0], &new->vs_layers);

    if (argc == 2)
    {
      new->vs_color = BLACK;
        if (strcmp(argv[1], "X") == 0)
          new->vs_flags = VS_CROSS;
      else if (strcmp(argv[1], "B") == 0)
          new->vs_flags = VS_BORDER;
      else
      {
          TechError("Second field must be \"X\" or \"B\"\n");
          freeMagic((char *) new);
          return TRUE;
      }
    }
    else
    {
      int i, j, value;

      if (argc != 3 && argc != 4 && argc != 6 && argc != 10 && argc != 18)
      {
          TechError("\"colorversatec\" lines must have 2 fields + 1, 2, 4, 8,"
            " or 16 stipple word values.\n");
          freeMagic((char *)new);
          return TRUE;
      }
      i = LookupStruct(argv[1], (LookupTable *) colors, sizeof colors[0]);
      if (i < 0)
      {
          TechError("First field must be BLACK, CYAN, MAGENTA or YELLOW.\n");
          freeMagic((char *)new);
          return TRUE;
      }
      new->vs_color = colors[i].l_color;
      new->vs_flags = 0;
      for (j = 0; j < 16; j += (argc - 2))
      {
          for (i = 0; i < (argc - 2); i++)
          {
            sscanf(argv[i + 2], "%x", &value);
            new->vs_stipple[j + i] = (value << 16) | (value & 0xffff);
#ifndef WORDS_BIGENDIAN
            new->vs_stipple[j + i] = PlotSwapBytes(new->vs_stipple[i]);
#endif  /* WORDS_BIGENDIAN */
          }
      }
    }

    new->vs_next = plotColorVersStyles;
    plotColorVersStyles = new;

    return TRUE;
}

#else

bool
PlotColorVersTechLine(sectionName, argc, argv)
    char *sectionName;        /* Name of this section (unused). */
    int argc;                 /* Number of arguments on line. */
    char *argv[];       /* Pointers to fields of line. */
{
    return TRUE;
}

#endif /* VERSATEC */

#ifdef VERSATEC

/*
 * ----------------------------------------------------------------------------
 *
 * plotTransToSwath --
 *
 *    Transforms a rectangle from Magic root coordinates to the
 *    coordinates of the current swath.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Dst is modified to hold a rectangle that has been transformed
 *    to swath coordinates.
 *
 * ----------------------------------------------------------------------------
 */

void
plotTransToSwath(src, dst)
    Rect *src;          /* Rectangle in Magic root coords. */
    Rect *dst;          /* Rectangle to be filled in with swath
                         * corresponding to src.
                         */
{
    dst->r_xbot = ((src->r_xbot - plotLL.p_x)*scale) >> scaleShift;
    dst->r_xtop = ((src->r_xtop - plotLL.p_x)*scale) >> scaleShift;
    dst->r_ybot = (((src->r_ybot - plotLL.p_y)*scale) >> scaleShift) - swathY;
    dst->r_ytop = (((src->r_ytop - plotLL.p_y)*scale) >> scaleShift) - swathY;
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotVersLine  --
 *
 *    This procedure plots a line of a given thickness.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    The current raster is modified.
 *
 * ----------------------------------------------------------------------------
 */

void
plotVersLine(area, widen, raster, stipple)
    Rect *area;               /* The "corner" points of this rectangle
                         * give the endpoints of the line, in
                         * Magic root coordinates.
                         */
    int widen;                /* Amount by which to widen line.  0 means
                         * line is drawn one pixel wide, 1 means 3
                         * pixels wide, etc.
                         */
    Raster *raster;           /* Raster to write to */
    Stipple *stipple;         /* Pattern to use to get the right line color */
{
    Rect swathArea;

    plotTransToSwath(area, &swathArea);

    /* Handle Manhattan lines using rectangle-drawing, since it's faster. */

    if ((swathArea.r_xbot == swathArea.r_xtop) ||
          (swathArea.r_ybot == swathArea.r_ytop))
    {
      GEO_EXPAND(&swathArea, widen, &swathArea);
      GEOCLIP(&swathArea, &swathClip);
      if ((swathArea.r_xbot <= swathArea.r_xtop) &&
            (swathArea.r_ybot <= swathArea.r_ytop))
          PlotFillRaster(raster, &swathArea, stipple);
    }
    else
    PlotRastFatLine(raster, &swathArea.r_ll, &swathArea.r_ur, widen, stipple);
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotVersRect --
 *
 *    This procedure takes a rectangular area, given in Magic root
 *    coordinates, translates it to swath coordinates, and draws
 *    it as an outline of a given thickness.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Modifies raster.
 *
 * ----------------------------------------------------------------------------
 */

void
plotVersRect(area, widen, raster, stipple)
    Rect *area;   /* Rectangular area to draw, in root
                         * coordinates.
                         */
    int widen;                /* If zero, rectangular outline is drawn
                         * one pixel wide.  If non-zero, the outline
                         * is widened by this many units on each
                         * side.
                         */
    Raster *raster;           /* Raster to plot to */
    Stipple *stipple;         /* Pattern to use to get the right line color */
{
    Rect side;

    /* First, the bottom side. */

    if (area->r_xbot != area->r_xtop)
    {
      side = *area;
      side.r_ytop = side.r_ybot;
      plotVersLine(&side, widen, raster, stipple);

      /* Now the top side, if it doesn't coincide with the bottom. */

      if (area->r_ybot != area->r_ytop)
      {
          side = *area;
          side.r_ybot = side.r_ytop;
          plotVersLine(&side, widen, raster, stipple);
      }
    }

    /* Now do the left side. */

    if (area->r_ybot != area->r_ytop)
    {
      side = *area;
      side.r_xtop = side.r_xbot;
      plotVersLine(&side, widen, raster, stipple);

      /* Now the right side, if it doesn't coincide with the left. */

      if (area->r_xbot != area->r_xtop)
      {
          side = *area;
          side.r_xbot = side.r_xtop;
          plotVersLine(&side, widen, raster, stipple);
      }
    }
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotVersTile --
 *
 *    This procedure is called for paint tiles.  It renders each tile
 *    in the current style, in the current swath.
 *
 * Results:
 *    Always returns 0 to keep the search alive.
 *
 * Side effects:
 *    Modifies the raster area.
 *
 * ----------------------------------------------------------------------------
 */

int
plotVersTile(tile, cxp)
    Tile *tile;   /* Tile that's of type to be output. */
    TreeContext *cxp;         /* Describes search in progress. */
{
    Rect tileArea, rootArea, swathArea, edge;
    TileType ntype;
    Tile *neighbor;
    Transform *trans = &cxp->tc_scx->scx_trans;
    Raster *raster = (Raster *)cxp->tc_filter->tf_arg;

    /* Transform tile coords to root coords and then to swath coords. */
    
    TITORECT(tile, &tileArea);
    GEOTRANSRECT(trans, &tileArea, &rootArea);
    plotTransToSwath(&rootArea, &swathArea);

    /* Handle X'ed things specially. */
    
    if (curStyle->vs_flags & VS_CROSS)
    {
#ifdef NONMANHATTAN
      if (!IsSplit(tile))
#endif
          if (((swathArea.r_xtop - swathArea.r_xbot) > 6)
                  && ((swathArea.r_ytop - swathArea.r_ybot) > 6))
          {
            Rect r2;
            plotVersLine(&rootArea, 0, raster, curStyle->vs_lineStipple);
            r2.r_xtop = rootArea.r_xbot;
            r2.r_ybot = rootArea.r_ybot;
            r2.r_xbot = rootArea.r_xtop;
            r2.r_ytop = rootArea.r_ytop;
            plotVersLine(&r2, 0, raster, curStyle->vs_lineStipple);
          }
    }

#ifdef NONMANHATTAN
    if (IsSplit(tile))
    {
      int i, j;
      TileType dinfo;
      Rect r;

      dinfo = DBTransformDiagonal(TiGetTypeExact(tile), &cxp->tc_scx->scx_trans);
      if (!(curStyle->vs_flags & VS_BORDER) && !(curStyle->vs_flags & VS_CROSS))
          PlotPolyRaster(raster, &swathArea, &swathClip, dinfo,
                        curStyle->vs_stipple);

      /* Diagonal is always drawn (clipping handled in plotVersLine) */

      r = rootArea;
      if (dinfo & TT_DIRECTION)
      {
          /* swap X to make diagonal go the other way */
          r.r_xbot = r.r_xtop;
          r.r_xtop = rootArea.r_xbot;
      }
      plotVersLine(&r, 0, raster, curStyle->vs_lineStipple);
    }
    else
    {
#endif

    /* Clip and then stipple. */

    GEOCLIP(&swathArea, &swathClip);
    if (swathArea.r_xbot > swathArea.r_xtop) return 0;
    if (swathArea.r_ybot > swathArea.r_ytop) return 0;
    if (!(curStyle->vs_flags & VS_BORDER) && !(curStyle->vs_flags & VS_CROSS))
      PlotFillRaster(raster, &swathArea, curStyle->vs_stipple);

#ifdef NONMANHATTAN
    }
#endif

    /* Now output lines for any edges between material of the type
     * currently being drawn and material of other types.  This is
     * done by searching along the tile's borders for neighbors that
     * have the wrong types.  First, search the tile's bottom border
     * (unless it is at infinity).
     */
    
#ifdef NONMANHATTAN
    if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
      goto searchleft;  /* nothing on bottom of split */
#endif

    if (tileArea.r_ybot > TiPlaneRect.r_ybot)
    {
      edge.r_ybot = edge.r_ytop = tileArea.r_ybot;
      for (neighbor = LB(tile); LEFT(neighbor) < tileArea.r_xtop;
            neighbor = TR(neighbor))
      {
          ntype = TiGetTopType(neighbor);
          if (TTMaskHasType(&curMask, ntype)) continue;
          edge.r_xbot = LEFT(neighbor);
          edge.r_xtop = RIGHT(neighbor);
          if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot;
          if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop;
          GEOTRANSRECT(trans, &edge, &rootArea);
          plotVersLine(&rootArea, 0, raster, curStyle->vs_lineStipple);
      }
    }

searchleft:
#ifdef NONMANHATTAN
    if (IsSplit(tile) && (SplitSide(tile)))
      goto searchtop;         /* Nothing on left side of split */
#endif

    /* Now go along the tile's left border, doing the same thing.   Ignore
     * edges that are at infinity.
     */

    if (tileArea.r_xbot > TiPlaneRect.r_xbot)
    {
      edge.r_xbot = edge.r_xtop = tileArea.r_xbot;
      for (neighbor = BL(tile); BOTTOM(neighbor) < tileArea.r_ytop;
            neighbor = RT(neighbor))
      {
          ntype = TiGetRightType(neighbor);
          if (TTMaskHasType(&curMask, ntype)) continue;
          edge.r_ybot = BOTTOM(neighbor);
          edge.r_ytop = TOP(neighbor);
          if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot;
          if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop;
          GEOTRANSRECT(trans, &edge, &rootArea);
          plotVersLine(&rootArea, 0, raster, curStyle->vs_lineStipple);
      }
    }

    /* Same thing for the tile's top border. */

searchtop:
#ifdef NONMANHATTAN
    if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile)))
      goto searchright;       /* Nothing on top side of tile */
#endif

    if (tileArea.r_ytop < TiPlaneRect.r_ytop)
    {
      edge.r_ybot = edge.r_ytop = tileArea.r_ytop;
      for (neighbor = RT(tile); RIGHT(neighbor) > tileArea.r_xbot;
            neighbor = BL(neighbor))
      {
          ntype = TiGetBottomType(neighbor);
          if (TTMaskHasType(&curMask, ntype)) continue;
          edge.r_xbot = LEFT(neighbor);
          edge.r_xtop = RIGHT(neighbor);
          if (edge.r_xbot < tileArea.r_xbot) edge.r_xbot = tileArea.r_xbot;
          if (edge.r_xtop > tileArea.r_xtop) edge.r_xtop = tileArea.r_xtop;
          GEOTRANSRECT(trans, &edge, &rootArea);
          plotVersLine(&rootArea, 0, raster, curStyle->vs_lineStipple);
      }
    }

    /* Finally, the right border. */

searchright:
#ifdef NONMANHATTAN
    if (IsSplit(tile) && !(SplitSide(tile)))
      return 0;         /* Nothing on right side of tile */
#endif

    if (tileArea.r_xtop < TiPlaneRect.r_xtop)
    {
      edge.r_xbot = edge.r_xtop = tileArea.r_xtop;
      for (neighbor = TR(tile); TOP(neighbor) > tileArea.r_ybot;
            neighbor = LB(neighbor))
      {
          ntype = TiGetLeftType(neighbor);
          if (TTMaskHasType(&curMask, ntype)) continue;
          edge.r_ybot = BOTTOM(neighbor);
          edge.r_ytop = TOP(neighbor);
          if (edge.r_ybot < tileArea.r_ybot) edge.r_ybot = tileArea.r_ybot;
          if (edge.r_ytop > tileArea.r_ytop) edge.r_ytop = tileArea.r_ytop;
          GEOTRANSRECT(trans, &edge, &rootArea);
          plotVersLine(&rootArea, 0, raster, curStyle->vs_lineStipple);
      }
    }
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotVersLabel --
 *
 *    This procedure is invoked for labels.  It generates bits to
 *    display the label in the current raster swath.
 *
 * Results:
 *    Always returns 0 to keep the search from aborting.
 *
 * Side effects:
 *    Modifies the raster.
 *
 * ----------------------------------------------------------------------------
 */

int
plotVersLabel(scx, label, tpath, raster)
    SearchContext *scx;       /* Describes state of search when label
                         * was found.
                         */
    Label *label;       /* Label that was found. */
    TerminalPath *tpath;      /* Ignored. */
    Raster *raster;           /* Raster to write to */
{
    Rect rootArea, swathArea, labelSize;
    Point point;
    int pos;

    /* Translate the label's area and relative position to root
     * coordinates and then to swath coordinates.  Figure out
     * the point relative to which the label is to be positioned.
     */

    GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea);
    plotTransToSwath(&rootArea, &swathArea);
    pos = GeoTransPos(&scx->scx_trans, label->lab_just);
    PlotTextSize(labelFont, label->lab_text, &labelSize);

    switch (pos)
    {
      case GEO_NORTH:
      case GEO_NORTHEAST:
      case GEO_NORTHWEST:
          point.p_y = swathArea.r_ytop + crossSize + 2 - labelSize.r_ybot;
          break;

      case GEO_CENTER:
      case GEO_WEST:
      case GEO_EAST:
          point.p_y = (swathArea.r_ytop + swathArea.r_ybot)/2;
          point.p_y -= (labelSize.r_ytop + labelSize.r_ybot)/2;
          break;
      
      case GEO_SOUTH:
      case GEO_SOUTHEAST:
      case GEO_SOUTHWEST:
          point.p_y = swathArea.r_ybot - crossSize - 2 - labelSize.r_ytop;
          break;
    }
    switch (pos)
    {
      case GEO_WEST:
      case GEO_NORTHWEST:
      case GEO_SOUTHWEST:
          point.p_x = swathArea.r_xbot - crossSize - 2 - labelSize.r_xtop;
          break;
      
      case GEO_CENTER:
      case GEO_NORTH:
      case GEO_SOUTH:
          point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2;
          point.p_x -= (labelSize.r_xtop + labelSize.r_xbot)/2;
          break;
      
      case GEO_EAST:
      case GEO_NORTHEAST:
      case GEO_SOUTHEAST:
          point.p_x = swathArea.r_xtop + crossSize + 2 - labelSize.r_xbot;
          break;
    }

    /* Output lines marking the label's area.  Different things are
     * done depending on whether the label is a point, a line, or an
     * area.
     */
    
    if ((rootArea.r_xbot == rootArea.r_xtop) &&
          (rootArea.r_ybot == rootArea.r_ytop))
    {
      Rect tmp;

      /* Point label.  Output a cross. */

      tmp = swathArea;
      tmp.r_ytop += crossSize;
      tmp.r_ybot -= crossSize;
      GEO_EXPAND(&tmp, 1, &tmp);
      GEOCLIP(&tmp, &swathClip);
      if ((tmp.r_xbot <= tmp.r_xtop) &&
            (tmp.r_ybot <= tmp.r_ytop))
          PlotFillRaster(raster, &tmp, PlotBlackStipple);
      tmp = swathArea;
      tmp.r_xtop += crossSize;
      tmp.r_xbot -= crossSize;
      GEO_EXPAND(&tmp, 1, &tmp);
      GEOCLIP(&tmp, &swathClip);
      if ((tmp.r_xbot <= tmp.r_xtop) &&
            (tmp.r_ybot <= tmp.r_ytop))
          PlotFillRaster(raster, &tmp, PlotBlackStipple);
    }
    else
    {
      /* Line or rectangle.  Draw outline. */

      plotVersRect(&rootArea, 1, raster, PlotBlackStipple);
    }

    /* Output the text for the label.  Before outputting the label,
     * erase the area where the label will appear in order to make
     * the label more visible.
     */

    labelSize.r_xbot += point.p_x - 1;
    labelSize.r_xtop += point.p_x + 1;
    labelSize.r_ybot += point.p_y - 1;
    labelSize.r_ytop += point.p_y + 1;
    GEOCLIP(&labelSize, &swathClip);
    PlotClearRaster(raster, &labelSize);
    PlotRasterText(raster, &swathClip, labelFont, label->lab_text, &point);

    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotVersCell --
 *
 *    This procedure is invoked for unexpanded cells.
 *
 * Results:
 *    Always returns 0 to keep the search from aborting.
 *
 * Side effects:
 *    The raster is modified to depict the cell's boundary,
 *    name, and instance id.
 *
 * ----------------------------------------------------------------------------
 */

int
plotVersCell(scx, raster)
    SearchContext *scx;       /* Describes cell whose bbox is to
                         * be plotted.
                         */   
    Raster *raster;           /* Raster to write to */
{
    char idName[100];
    Rect rootArea, swathArea, textSize;
    Point point;
    CellDef *def;

    /* Convert the cell's bounding box to root coordinates and then
     * draw as a thick outline.
     */

    def = scx->scx_use->cu_def;
    GeoTransRect(&scx->scx_trans, &def->cd_bbox, &rootArea);
    plotVersRect(&rootArea, 2, raster, PlotBlackStipple);

    if (!PlotShowCellNames)
      return (0);

    /* Output the cell's name and id text. */
    if (cellNameFont != NULL)
    {
      plotTransToSwath(&rootArea, &swathArea);
      PlotTextSize(cellNameFont, def->cd_name, &textSize);
      point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2;
      point.p_x -= (textSize.r_xtop + textSize.r_xbot)/2;
      point.p_y = (2*swathArea.r_ytop + swathArea.r_ybot)/3;
      point.p_y -= (textSize.r_ytop + textSize.r_ybot)/2;
      PlotRasterText(raster, &swathClip, cellNameFont, def->cd_name, &point);
    }

    if (cellIdFont != NULL)
    {
      DBPrintUseId(scx, idName, 100, TRUE);
      PlotTextSize(cellIdFont, idName, &textSize);
      point.p_x = (swathArea.r_xtop + swathArea.r_xbot)/2;
      point.p_x -= (textSize.r_xtop + textSize.r_xbot)/2;
      point.p_y = (swathArea.r_ytop + 2*swathArea.r_ybot)/3;
      point.p_y -= (textSize.r_ytop + textSize.r_ybot)/2;
      PlotRasterText(raster, &swathClip, cellIdFont, idName, &point);
    }
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * PlotVersatec --
 *
 *    This procedure generates a raster file suitable for driving
 *    printers like the Versatec black-and-white family, and runs
 *    a spooling program to print the file.
 *
 *    If PlotVersPlotType is VERSATEC_COLOR, it will generate a
 *    versatec color plot file in straight color raster format.
 *
 *    If PlotVersPlotType is HPGL2 or HPRTL, it will generate
 *    an HPRTL file for the supported HP plotters. 
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Lots of disk space is chewed up by the file.
 *
 * ----------------------------------------------------------------------------
 */

void
PlotVersatec(scx, layers, xMask, user_scale)
    SearchContext *scx;             /* The use and area and transformation
                               * in this describe what to plot.
                               */
    TileTypeBitMask *layers;        /* Tells what layers to plot.  Only
                               * paint layers in this mask, and also
                               * expanded according to xMask, are
                               * plotted.  If L_LABELS is set, then
                               * labels on the layers are also
                               * plotted, if expanded according to
                               * xMask.  If L_CELL is set, then
                               * subcells that are unexpanded
                               * according to xMask are plotted as
                               * bounding boxes.
                               */
    int xMask;                      /* An expansion mask, used to indicate
                               * the window whose expansion status
                               * will be used to determine
                               * visibility.  Zero means treat
                               * everything as expanded.
                               */
    int user_scale;                 /* Scalefactor of output */
{
    static char *yesNo[] = {"no", "yes", NULL};
    int dotsAcross, dotsDown, swathsDown, scaleDown;
    int mag_width;                  /* lambda */
    float width;              /* inches */      
    char fileName[200], command[300], answer[32];
    float length, mBytes;
    Transform tinv;
    int action, result;
    FILE *file;
    VersatecColor color;
    bool haveColorMessage;
    int usedScale, maxScale;
    float oscale;
    Raster *raster = NULL;

    /* CMYK color separated raster buffers.     */
    Raster *kRaster, *cRaster, *mRaster, *yRaster;

    haveColorMessage = FALSE;
    GeoTransRect(&scx->scx_trans, &scx->scx_area, &rootClip);
    GEO_EXPAND(&rootClip, 1, &rootClip);

    /* Get conversion factor (internal units to inches) */
    oscale = CIFGetOutputScale(1000);     /* convert to microns */
    oscale *= 3.937e-5;             /* convert to inches */
   
    /* Compute plot width from scalefactor */
    mag_width = rootClip.r_xtop - rootClip.r_xbot;
    maxScale = ((float)PlotVersWidth / (float)PlotVersDotsPerInch)
            / (oscale * (float)mag_width);
    width = (float)user_scale * oscale * (float)mag_width;

    dotsAcross = (int)(width * (float)PlotVersDotsPerInch);
    if (dotsAcross <= 0 || dotsAcross > PlotVersWidth)
    {
      dotsAcross = PlotVersWidth;
      usedScale = maxScale;
    }
    else
      usedScale = user_scale;

    /* Recompute width based on the actual scale used */
    width = (float)usedScale * oscale * (float)mag_width;

    /*
     * Compute the number of pixels per magic unit.
     * This number will be the fraction: scale / (1 << scaleShift).
     * In order to be reasonably sure that we have enough precision
     * in the numerator of the fraction, require that scale have at
     * least three bits (i.e., be greater than or equal to 4).
     */
    for (scale = 0, scaleShift = 4; ; scaleShift++)
    {
      scaleDown = 1 << scaleShift;
      scale = (scaleDown * dotsAcross) / mag_width;
      if (scaleShift >= 8 * sizeof (int))
      {
          TxError("The area selected is too many lambda wide to plot.\n");
          TxError("(There are numerical problems with rasterizing it).\n");
          TxError("Try selecting a smaller area, or else asking for ");
          TxError("a wider plot.\n");
          return;
      }
      if (scale >= 8)
          break;
    }

    /*
     * Compute scaling information, and tell the user how big the
     * plot will be.
     */
    dotsDown = ((rootClip.r_ytop - rootClip.r_ybot)*scale) >> scaleShift;
    swathsDown = (dotsDown + PlotVersSwathHeight - 1)/PlotVersSwathHeight;
    dotsDown = swathsDown * PlotVersSwathHeight;
    mBytes = ((PlotVersWidth/8)*dotsDown)/1000000.0;
    length = dotsDown;
    length /= PlotVersDotsPerInch;
    TxPrintf("Plot will be %.1f inches wide by %.1f inches long.\n", width, length);
    TxPrintf("It will take %.2f Megabytes in \"%s\".\n", 
            (PlotVersPlotType == HPRTL || PlotVersPlotType == HPGL2)
            ? 4.0 * mBytes : mBytes, PlotTempDirectory);
    TxPrintf("Lambda: %.3f (um)       Requested scale: %dX    Actual scale: %dX   "
            "[Full scale: %dX].\n", CIFGetOutputScale(1000),
            user_scale, usedScale, maxScale);
    do
    {
      TxPrintf("Do you still want the plot? [yes] ");
      if (TxGetLine(answer, sizeof answer) == NULL || answer[0] == '\0')
      {
          action = 1;
          break;
      }
    } while ((action = Lookup(answer, yesNo)) < 0);
    if (action == 0) return;

    /* The plot has been "approved".  Now obtain a swath raster if
     * we don't already have one.  If the swath size has changed,
     * recycle the raster for a new one.
     */
    
    if ((raster != NULL) && ((raster->ras_width != PlotVersWidth)
            || (raster->ras_height != PlotVersSwathHeight)))
    {
      if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
      {
          PlotFreeRaster(cRaster);
          PlotFreeRaster(mRaster);
          PlotFreeRaster(yRaster);
      }
      PlotFreeRaster(kRaster);
      raster = NULL;
    }

    if (raster == NULL)
    {
      if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
      {
          cRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
          mRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
          yRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
      }
      kRaster = PlotNewRaster(PlotVersSwathHeight, PlotVersWidth);
      raster = kRaster;
    }

    /* Load font information for the plot, if it isn't already
     * loaded.
     */
    
    labelFont = PlotLoadFont(PlotVersLabelFont);
    cellNameFont = PlotLoadFont(PlotVersNameFont);
    cellIdFont = PlotLoadFont(PlotVersIdFont);

    /* Compute the name of the file to use for output, and open it. */

    sprintf(fileName, "%s/magicPlotXXXXXX", PlotTempDirectory);
    result = mkstemp(fileName);
    if (result == -1)
    {
      TxError("Failed to create temporary filename for %s\n", fileName);
      return;
    }
    file = PaOpen(fileName, "w", (char *) NULL, (char *) NULL, (char *) NULL,
          (char **) NULL);
    if (file == NULL)
    {
      TxError("Couldn't open file \"%s\" to write plot.\n", fileName);
      return;
    }
    /* Set up the rest of the transformation variables.
     * Arrange for the plot to be centered on the page.
     */

    plotLL.p_y = rootClip.r_ybot;
    plotLL.p_x = (rootClip.r_xtop+rootClip.r_xbot)/2 - (PlotVersWidth*8)/scale;
    if (plotLL.p_x > rootClip.r_xbot)
      plotLL.p_x = rootClip.r_xbot;

    /* Compute a distance equal to 1/8th the size of a typical wire
     * (max of thicknesses of routing layers).  This is used to offset
     * text from labels and to compute cross size for point labels.
     */

    if (RtrMetalWidth > RtrPolyWidth)
      crossSize = (RtrMetalWidth*scale)/(scaleDown*8);
    else crossSize = (RtrPolyWidth*scale)/(scaleDown*8);
    if (crossSize < 2) crossSize = 2;

    /* Step down the page one swath at a time, rasterizing everything
     * that overlaps the current swath, then outputting the swath.
     */
    
    GeoInvertTrans(&scx->scx_trans, &tinv);
    for (color = BLACK; color <= YELLOW; color++)
    {
      int swathsDownThisColor;

      swathsDownThisColor = swathsDown;
      rasFileByteCount = 0;

      /* issue preamble for this color's raster. if we are doing colors */
      switch (PlotVersPlotType)
      {
          case HPRTL:
            PlotHPRTLHeader(PlotVersWidth, dotsDown, PlotVersDotsPerInch, file);
            break;
          case HPGL2:
            PlotHPGL2Header(PlotVersWidth, dotsDown, PlotVersDotsPerInch,
                  usedScale, file);
            break; 
          case VERSATEC_COLOR:
              if (PlotDumpColorPreamble(color, file, dotsDown, PlotVersWidth) != 0)
                goto error;
            if (SigInterruptPending)
                goto error;

            TxPrintf("\nDumping %s Raster:", plotVersatecColorNames[color]);
            TxFlush();
            break;
      }
      for (swathsDownThisColor -= 1; 
           swathsDownThisColor >= 0; 
           swathsDownThisColor -= 1)
      {
          SearchContext scx2;
          Rect root, labelArea;
          int labelHeight;

          swathY = swathsDownThisColor * PlotVersSwathHeight;
          if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
          {
            PlotClearRaster(cRaster, (Rect *) NULL);
            PlotClearRaster(mRaster, (Rect *) NULL);
            PlotClearRaster(yRaster, (Rect *) NULL);
          }
          PlotClearRaster(kRaster, (Rect *) NULL);

          /* Compute the area of the swath that overlaps the portion of
           * the layout we're plotting.
           */
      
          plotTransToSwath(&rootClip, &swathClip);
          if (swathClip.r_xbot < 0) swathClip.r_xbot = 0;
          if (swathClip.r_ybot < 0) swathClip.r_ybot = 0;
          if (swathClip.r_xtop >= PlotVersWidth)
            swathClip.r_xtop = PlotVersWidth - 1;
          if (swathClip.r_ytop >= PlotVersSwathHeight)
            swathClip.r_ytop = PlotVersSwathHeight - 1;

          /* Compute the area of layout that overlaps this swath.  This is
           * done twice, once for mask material and once for labels.  The
           * separate computation for labels is because labels stick out
           * from their positioning points.  We may have to search a larger
           * area than just the swath in order to find all the labels that
           * must be drawn in this swath.  Only the y-direction needs to
           * be expanded this way, since we're only swathing in y.  Even
           * non-label stuff has to be expanded slightly, because lines
           * are drawn more than 1 pixel thick.
           */
      
          scx2 = *scx;
          root.r_xbot = (scaleDown*swathClip.r_xbot)/scale + plotLL.p_x;
          root.r_xtop = (scaleDown*swathClip.r_xtop)/scale + plotLL.p_x;
          root.r_ybot = (scaleDown*(swathY-4))/scale + plotLL.p_y;
          root.r_ytop = (scaleDown*(swathY+swathClip.r_ytop+4))/scale+plotLL.p_y;
          GEO_EXPAND(&root, 1, &root);
          GeoTransRect(&tinv, &root, &scx2.scx_area);

          labelArea.r_xbot = root.r_xbot;
          labelArea.r_xtop = root.r_xtop;

          if (labelFont != NULL)
          {
            labelHeight = (labelFont->fo_bbox.r_ytop
                  - labelFont->fo_bbox.r_ybot) + 2;
            labelArea.r_ybot = (scaleDown * (swathY - crossSize
                  - labelHeight)) / scale + plotLL.p_y;
            labelArea.r_ytop = (scaleDown * (swathY + swathClip.r_ytop
                  + crossSize + labelHeight)) / scale + plotLL.p_y;
            GEO_EXPAND(&labelArea, 1, &labelArea);
          }

          /* For each Versatec style, output stippled areas for all
           * the tiles requested by the style. 
           */

          switch (PlotVersPlotType)
          {
              case VERSATEC_BW:
                curStyle = plotVersStyles;
                break;
              case HPGL2: case HPRTL:
                curStyle = plotColorVersStyles; 
                if (curStyle == NULL)
                {
                    TxError("Warning:  No color versatec styles are defined"
                        " in the technology file!\nPlotting aborted.\n");
                  return;
                }
                break;
            default:
                curStyle = plotColorVersStyles; 
                if (!haveColorMessage)
                {
                  TxError("Warning:  No color versatec styles are defined"
                            " in the technology file!\nPlot will be"
                            " monochrome.\n");
                  haveColorMessage = TRUE; 
                  curStyle = plotVersStyles;
                }
          }
          if (curStyle == NULL)
          {
            TxError("Warning:  No monochrome versatec styles are"
                      " defined in the technology file!\nPlotting"
                      " aborted.\n");
            return;
          }

          for ( ; curStyle != NULL; curStyle = curStyle->vs_next)
          {
            /* if we are plotting in B&W, then visit all the tiles in this
             * swath, otherwise only visit them if they should be
             * plotted in the current style's color.
             */
            if (PlotVersPlotType == HPGL2 || PlotVersPlotType == HPRTL)
            {
                switch (curStyle->vs_color)
                {
                  case CYAN:
                      raster = cRaster;
                      break;
                  case MAGENTA:
                      raster = mRaster;
                      break;
                  case YELLOW:
                      raster = yRaster;
                      break;
                  default:
                      raster = kRaster;
                      break;
                }
            }

            if ((PlotVersPlotType != VERSATEC_COLOR) || (curStyle->vs_color == color))
            {
                TTMaskAndMask3(&curMask, layers, &curStyle->vs_layers);
                (void) DBTreeSrTiles(&scx2, &curMask, xMask, plotVersTile,
                             (ClientData) raster);
            }
          }

          raster = kRaster;

          /* Output labels, if they are wanted. */

          if (TTMaskHasType(layers, L_LABEL) && (color == BLACK) &&
                  (labelFont != NULL))
          {
            curMask = *layers;
            TTMaskSetType(&curMask, TT_SPACE);
            GeoTransRect(&tinv, &labelArea, &scx2.scx_area);
            (void) DBTreeSrLabels(&scx2, &curMask, xMask, (TerminalPath *) NULL,
                              plotVersLabel, (ClientData) raster);
          }

          /* Output subcell bounding boxes, if they are wanted. */

          if (TTMaskHasType(layers, L_CELL) && color == BLACK)
          {
            (void) DBTreeSrCells(&scx2, xMask, plotVersCell, (ClientData) raster);
          }

          TxPrintf("#");
          TxFlush();

          switch (PlotVersPlotType)
          {
            case HPGL2: case HPRTL:
                PlotDumpHPRTL(file, kRaster, cRaster, mRaster, yRaster);
                break;
            case VERSATEC_COLOR: case VERSATEC_BW:
                if (PlotDumpRaster(raster, file) != 0)
                  goto error;
                if (SigInterruptPending)
                  goto error;
                break;
          }
      }
      /* Only the VERSATEC_COLOR type runs colors separately */
      if (PlotVersPlotType != VERSATEC_COLOR) break;
      TxPrintf ("\nWrote %d bytes of data.\n", rasFileByteCount);
    }

    /* Write trailers */

    switch (PlotVersPlotType)
    {
      case HPGL2:
          PlotHPGL2Trailer(file);
          break;
      case HPRTL:
          PlotHPRTLTrailer(file);
          break;
    }

    /* Close the file and issue the command to plot it. */

    TxPrintf("\n");
    fclose(file);
    sprintf(command, PlotVersCommand, PlotVersPrinter, fileName);
    if (system(command) != 0)
    {
      TxError("Couldn't execute spooler command to print \"%s\"\n",
            fileName);
    }
    return;

    error:
    TxError("\nVersatec plot aborted.\n");
    fclose(file);
    unlink(fileName);
}

#endif /* VERSATEC */

Generated by  Doxygen 1.6.0   Back to index