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

plotPS.c

/*
 * plotPS.c --
 *
 * This file contains procedures that generate PS-format files
 * to describe a section of layout.
 *
 *     ********************************************************************* 
 *     * 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/plotPS.c,v 1.4 2008/01/29 02:41:57 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/tech.h"
#include "utils/malloc.h"
#include "utils/utils.h"
#include "windows/windows.h"
#include "commands/commands.h"
#include "dbwind/dbwind.h"
#include "textio/textio.h"

/* Records of the following type are used to describe how to generate
 * PS output for a particular set of mask layers.  Each style
 * describes the PS figures to draw for a particular set of
 * layers.  A single layer may participate in several ps styles.
 */

00047 typedef struct psstyle
{
    TileTypeBitMask grs_layers;           /* Layers to plot in this style. */
    int grs_stipple;                /* Index of fill to use. */
    int grs_color;                  /* Index of color to use. */
    struct psstyle *grs_next; /* Next style in chain. */
} PSStyle;

00055 typedef struct pspattern
{
    int           index;
    unsigned long stipple[8];
    struct pspattern    *pat_next;
} PSPattern;

00062 typedef struct pscolor
{
    int                 index;
    unsigned char color[4];
    struct pscolor      *col_next;
} PSColor;


static PSStyle *plotPSStyles = NULL;
static PSPattern *plotPSPatterns = NULL;
static PSColor    *plotPSColors = NULL;

int delta, xnmargin, ynmargin, xpmargin, ypmargin;
float fscale;

/* Most of the grs_stipple values are PS stipple numbers.  However,
 * if a grs_stipple value is less than zero, it means something special.
 * The definitions below give the possible alternatives:
 *
 * CROSS:         Draw a thick outline around the tile with
 *                a cross through it (used for contacts).
 * BORDER:        Same as CROSS, except draw the outline with
 *                no cross through it.
 * SOLID:         This is the same as a solid stipple but renders
 *                much faster.
 */

#define CROSS  -1
#define BORDER -2
#define SOLID  -3

/* The definitions below give the integers used for various PS
 * line drawing styles (brushes).
 */

#define PS_THIN         1
#define PS_MEDIUM 2
#define PS_THICK  3

/* The variables below are used to pass information from the top-level
 * procedure PlotPS down to the lower-level search functions
 * that are invoked for pieces of the layout.
 */

static FILE *file;            /* File to use for output. */
static PSStyle *curStyle;     /* Current style being output. */
static PSColor *curColor;     /* Current color being output. */
static PSPattern *curPattern; /* Current pattern being output. */
static int curLineWidth;      /* Current line width */
static int curFont;           /* Current font */
static TileTypeBitMask curMask;     /* Layers currently being searched:  this
                         * is the AND of the mask from curStyle and
                         * the layers that the user specified.
                         */
static Rect bbox;       /* Bounding box, in root coordinates, of
                         * area being plotted.
                         */

/* Parameters passed to the plotting process */

static char *defaultBoldFont = "/HelveticaBold";
static char *defaultFont = "/Helvetica";
char *PlotPSIdFont = NULL;
char *PlotPSNameFont = NULL;
char *PlotPSLabelFont = NULL;
int PlotPSIdSize = 8;
int PlotPSNameSize = 12;
int PlotPSLabelSize = 12;
int PlotPSBoundary = 1;  /* Print boundaries around all layers */
int PlotPSHeight = 792;  /* 11 inches * 72 PS units/inch */
int PlotPSWidth = 612;   /* 8.5 inches */
int PlotPSMargin = 72;   /* 1 inch */

int curx1, curx2, cury1, cury2;               /* Last encountered line */
int curxbot, curybot, curwidth, curheight;  /* Last encountered rectangle */

/*
 * ----------------------------------------------------------------------------
 *
 * PSReset()
 *
 *    Plot optimization:   Reset buffered line and rectangle to default values
 *
 * ----------------------------------------------------------------------------
 */

void
PSReset()
{
    curxbot = curybot = curwidth = curheight = -2;
    curx1 = curx2 = cury1 = cury2 = -2;
}


/*
 * ----------------------------------------------------------------------------
 *    PlotPSTechInit --
 *
 *    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
PlotPSTechInit()
{
    int i, j;
    PSStyle *style;
    PSColor *color;
    PSPattern *pattern;

    /* Clear out any old information */

    for (style = plotPSStyles; style != NULL; style = style->grs_next)
    {
      freeMagic((char *) style);
    }
    plotPSStyles = NULL;

    for (pattern = plotPSPatterns; pattern != NULL; pattern = pattern->pat_next)
    {
      freeMagic((char *) pattern);
    }
    plotPSPatterns = NULL;

    for (color = plotPSColors; color != NULL; color = color->col_next)
    {
      freeMagic((char *) color);
    }
    plotPSColors = NULL;

    if (!PlotPSIdFont)
      StrDup(&PlotPSIdFont, defaultFont);
    if (!PlotPSNameFont)
      StrDup(&PlotPSNameFont, defaultBoldFont);
    if (!PlotPSLabelFont)
      StrDup(&PlotPSLabelFont, defaultFont);
}

/*
 * ----------------------------------------------------------------------------
 *    PlotPSTechLine --
 *
 *    This procedure is invoked by the technology module once for
 *    each line in the "ps" 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 PS styles.
 * ----------------------------------------------------------------------------
 */

bool
PlotPSTechLine(sectionName, argc, argv)
    char *sectionName;        /* Name of this section (unused). */
    int argc;                 /* Number of arguments on line. */
    char *argv[];       /* Pointers to fields of line. */
{
    PSStyle *newstyle;
    PSColor *newcolor;
    PSPattern *newpattern;
    int i, color, stipple;
    
    if (argc != 9 && argc != 5 && argc != 3)
    {
      TechError("\"ps\" lines must have either 9, 5, or 3 arguments.\n");
      return TRUE;
    }

    if (argc == 9)      /* pattern definition */
    {
      newpattern = (PSPattern *) mallocMagic(sizeof(PSPattern));
      sscanf(argv[0], "%d", &(newpattern->index));
      for(i = 0; i < 8; i++)
      {
          sscanf(argv[1 + i], "%08lx", &(newpattern->stipple[i]));
      }
      newpattern->pat_next = plotPSPatterns;
      plotPSPatterns = newpattern;
    }
    else if (argc == 5) /* color definition */
    {
      int tmpint;
      newcolor = (PSColor *) mallocMagic(sizeof(PSColor));
      sscanf(argv[0], "%d", &(newcolor->index));
      for(i = 0; i < 4; i++)
      {
          sscanf(argv[1 + i], "%d", &tmpint);
          newcolor->color[i] = (unsigned char)(tmpint & 0xff);
      }
      newcolor->col_next = plotPSColors;
      plotPSColors = newcolor;
    }
    else {   /* 3 args: layer definition */
      if (!StrIsInt(argv[1]))
      {
          TechError("2nd field must be an integer\n");
          return TRUE;
      }
      color = atoi(argv[1]);

      if (strcmp(argv[2], "X") == 0)
          stipple = CROSS;
      else if (strcmp(argv[2], "B") == 0)
          stipple = BORDER;
      else if (strcmp(argv[2], "S") == 0)
          stipple = SOLID;
      else
      {
          if (!StrIsInt(argv[2]))
          {
            TechError("3rd field must be an integer or \"S\", \"X\", or \"B\".\n");
            return TRUE;
          }
          stipple = atoi(argv[2]);
        }

      newstyle = (PSStyle *) mallocMagic(sizeof(PSStyle));

      DBTechNoisyNameMask(argv[0], &newstyle->grs_layers);

      /* Replace non-primary contact images with primary images. */

      for (i = TT_TECHDEPBASE; i < DBNumTypes; i++)
      {
          if TTMaskHasType(&newstyle->grs_layers, i)
            TTMaskSetMask(&newstyle->grs_layers, &DBLayerTypeMaskTbl[i]);
      }
      TTMaskAndMask(&newstyle->grs_layers, &DBUserLayerBits);
      newstyle->grs_stipple = stipple;
      newstyle->grs_color = color;
      newstyle->grs_next = plotPSStyles;
      plotPSStyles = newstyle;
    }

    return TRUE;
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotPSFlushRect()
 *
 *    Plot optimization:   Draw last buffered rectangle.
 *
 * ----------------------------------------------------------------------------
 */

void
plotPSFlushRect(style)
    int style;
{
    if (curwidth > 0)
    {
      if (style == SOLID)
          fprintf(file, "%d %d %d %d ms\n", curxbot, curybot,
                  curwidth, curheight);
      else
          fprintf(file, "%d %d %d %d fb\n", curxbot, curybot,
                  curxbot + curwidth, curybot + curheight);
    }
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotPSFlushLine()
 *
 *    Plot optimization:   Draw last buffered line.
 *
 * ----------------------------------------------------------------------------
 */

void
plotPSFlushLine()
{
    if (cury1 == cury2)
    {
      if (curx1 != curx2)     /* true only if nothing is buffered */
          fprintf(file, "%d %d %d hl\n", curx2 - curx1, curx1, cury1);
    }
    else if (curx1 == curx2)
      fprintf(file, "%d %d %d vl\n", cury2 - cury1, curx1, cury1);
    else
      fprintf(file, "%d %d %d %d ml\n", curx1, cury1, curx2, cury2);
}


/*
 * ----------------------------------------------------------------------------
 *
 * plotPSLine --
 *
 *    Outputs a line into the current PS file.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    I/O.
 *
 * ----------------------------------------------------------------------------
 */

void
plotPSLine(p1, p2)
    Point *p1, *p2;           /* Endpoints of line, given in root
                         * coordinates.
                         */
{
    int x1, x2, y1, y2, limit, diff;
    bool tmptf;

    /* Clip the line to the rectangular area being output.  First,
     * arrange for the first x-coordinate to be the smaller, then
     * clip against vertical lines at the x-boundaries.
     */

    if (p1->p_x <= p2->p_x)
    {
      x1 = p1->p_x - bbox.r_xbot;
      x2 = p2->p_x - bbox.r_xbot;
      y1 = p1->p_y - bbox.r_ybot;
      y2 = p2->p_y - bbox.r_ybot;
    }
    else
    {
      x1 = p2->p_x - bbox.r_xbot;
      x2 = p1->p_x - bbox.r_xbot;
      y1 = p2->p_y - bbox.r_ybot;
      y2 = p1->p_y - bbox.r_ybot;
    }
    limit = bbox.r_xtop - bbox.r_xbot;
    if ((x1 > limit) || (x2 < 0)) return;

    /* Now clip against horizontal lines at the y-boundaries. */

    if (y2 < y1)
    {
      float tmp;
      tmp = y2; y2 = y1; y1 = tmp;
      tmp = x2; x2 = x1; x1 = tmp;
    }
    limit = bbox.r_ytop - bbox.r_ybot;
    if ((y1 > limit) || (y2 < 0)) return;

    /* compare against last output line and merge if possible */
    if (((x1 == x2) && (x1 == curx1) && (x2 == curx2)
            && ((tmptf = (y1 == cury2)) || (y2 == cury1))))
    {
      if (tmptf) cury2 = y2; 
      else cury1 = y1;
    }
    else if (((y1 == y2) && (y1 == cury1) && (y2 == cury2)
            && ((tmptf = (x1 == curx2)) || (x2 == curx1))))
    {
      if (tmptf) curx2 = x2;
      else curx1 = x1;
    }
    else
    {
      plotPSFlushLine();
      curx1 = x1;
      curx2 = x2;
      cury1 = y1;
      cury2 = y2;
    }
}


/*
 * ----------------------------------------------------------------------------
 *
 * plotPSRect --
 *
 *    Outputs PS statements to draw a rectangular area as
 *    an outline with a given line style.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    Adds information to the current PS file.
 *
 * ----------------------------------------------------------------------------
 */

void
plotPSRect(rect, style)
    Rect *rect;   /* Rectangle to be drawn, in root coords. */
    int style;
{
    int x, y, w, h;

    /* Output all boxes with any part visible.  Depend on PostScript to */
    /* do the clipping of any boxes crossing the plot boundary.         */

    x = rect->r_xbot - bbox.r_xbot;
    if ((x < 0) || (rect->r_xbot > bbox.r_xtop)) return;
    w = rect->r_xtop - rect->r_xbot;
    y = rect->r_ybot - bbox.r_ybot;
    if ((y < 0) || (rect->r_ybot > bbox.r_ytop)) return;
    h = rect->r_ytop - rect->r_ybot;

    fprintf(file, "%d %d %d %d m%c\n", x, y, w, h, (style == CROSS) ? 'x' :
            (style == SOLID) ? 's' : 'r');
}


/*
 * ----------------------------------------------------------------------------
 *
 * plotPSPaint --
 *
 *    This procedure is invoked once for each paint rectangle in
 *    the area being plotted.
 *
 * Results:
 *    Always returns 0 to keep the search alive.
 *
 * Side effects:
 *    Outputs information for the tile, including stipple for its
 *    interior, and a solid line for any portion of the boundary
 *    of the tile that is adjacent to a tile NOT in this style.
 *
 * ----------------------------------------------------------------------------
 */

int
plotPSPaint(tile, cxp)
    Tile *tile;               /* Tile that's of type to be output. */
    TreeContext *cxp;         /* Describes search in progress. */
{
    Rect tileArea, edge, rootArea;
    int xbot, width, ybot, height;
    Tile *neighbor;
    SearchContext *scx = cxp->tc_scx;
    bool tmptf;
    TileType ntype;

    /* First transform tile coords to root coords */
    
    TiToRect(tile, &tileArea);
    GeoTransRect(&scx->scx_trans, &tileArea, &rootArea);

    /* See if this tile gets special handling. */

    if ((curStyle->grs_stipple == CROSS) || (curStyle->grs_stipple == BORDER))
    {
      /* Draw tile as a thick outline with a cross from corner
       * to corner, and skip the rest of this procedure.
       */

      Point ul, lr;

      if (curLineWidth != PS_MEDIUM) {
          fprintf(file, "l2\n");
          curLineWidth = PS_MEDIUM;
      }

      plotPSRect(&rootArea, curStyle->grs_stipple);
      return 0;
    }

#ifdef NONMANHATTAN
    /* If this is a triangle, output the last rect and deal with this one */
    /* individually.                                          */

    if (IsSplit(tile))
    {
      int np, i, j;
      TileType dinfo;
      Point polyp[5];

      plotPSFlushRect(curStyle->grs_stipple);
      plotPSFlushLine();
      PSReset();

      /* Side and direction are altered by geometric transformations */

      dinfo = DBTransformDiagonal(TiGetTypeExact(tile), &scx->scx_trans);

      /* Use GrClipTriangle() routine to get the n-sided polygon that */
      /* results from clipping a triangle to the clip region.           */

      GrClipTriangle(&rootArea, &bbox, TRUE, dinfo, polyp, &np);
      for (i = 0; i < np; i++)
      {
         polyp[i].p_x -= bbox.r_xbot;
         polyp[i].p_y -= bbox.r_ybot;
         fprintf(file, "%d %d ", polyp[i].p_x, polyp[i].p_y);
      }
      fprintf(file, "%d tb\n", np);

      if (PlotPSBoundary)
      {
          if (curLineWidth != PS_THIN) {
            fprintf(file, "l1\n");
            curLineWidth = PS_THIN;
          }

          /* Diagonal is always drawn */

          for (i = 0; i < np; i++)
          {
            j = (i + 1) % np;
            if (polyp[i].p_x != polyp[j].p_x &&
                  polyp[i].p_y != polyp[j].p_y)
            {
                fprintf(file, "%d %d %d %d ml\n", polyp[i].p_x, polyp[i].p_y,
                  polyp[j].p_x, polyp[j].p_y);
                break;
            }
          }
      }
    }
    else
    {
#endif

    /* This tile gets "normal" processing (i.e. stippling and outlining).
     * Clip it to the plotting area and output.
     */

    GeoClip(&rootArea, &bbox);
    xbot = rootArea.r_xbot - bbox.r_xbot;
    width = rootArea.r_xtop - rootArea.r_xbot;
    ybot = rootArea.r_ybot - bbox.r_ybot;
    height = rootArea.r_ytop - rootArea.r_ybot;

    /* compare against last output rectangle and merge if possible */
    if ((width == curwidth) && (xbot == curxbot) && ((tmptf = (ybot == curybot
      + curheight)) || (ybot + height == curybot)))
    {
      curheight += height;
      if (!tmptf) curybot = ybot; 
    }
    else if ((height == curheight) && (ybot == curybot) && ((tmptf = (xbot == curxbot
      + curwidth)) || (xbot + width == curxbot)))
    {
      curwidth += width;
      if (!tmptf) curxbot = xbot;
    }
    else
    {
      plotPSFlushRect(curStyle->grs_stipple);
      curheight = height;
      curwidth = width;
      curxbot = xbot;
      curybot = ybot;
    }

    if (PlotPSBoundary && (curLineWidth != PS_THIN)) {
      fprintf(file, "l1\n");
      curLineWidth = PS_THIN;
    }

#ifdef NONMANHATTAN
    }
#endif

    if (!PlotPSBoundary) return 0;  /* No borders */

    /* 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).
     *
     * (This code is essentially a duplicate of selRedisplayFunc())
     */
    
#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))
      {
#ifdef NONMANHATTAN
          ntype = TiGetTopType(neighbor);
#else
          ntype = TiGetTypeExact(neighbor);
#endif
          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(&scx->scx_trans, &edge, &rootArea);
          plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
      }
    }

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

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

    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))
      {
#ifdef NONMANHATTAN
          ntype = TiGetRightType(neighbor);
#else
          ntype = TiGetTypeExact(neighbor);
#endif
          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(&scx->scx_trans, &edge, &rootArea);
          plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
      }
    }

    /* 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))
      {
#ifdef NONMANHATTAN
          ntype = TiGetBottomType(neighbor);
#else
          ntype = TiGetTypeExact(neighbor);
#endif
          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(&scx->scx_trans, &edge, &rootArea);
          plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
      }
    }

    /* 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))
      {
#ifdef NONMANHATTAN
          ntype = TiGetLeftType(neighbor);
#else
          ntype = TiGetTypeExact(neighbor);
#endif
          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(&scx->scx_trans, &edge, &rootArea);
          plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
      }
    }

    return 0;
}


/*
 * ----------------------------------------------------------------------------
 *
 * plotPSLabelPosition --
 *
 *    Determine the label position, orientation, and approximate bounding box
 *
 * ----------------------------------------------------------------------------
 */

int
plotPSLabelPosition(scx, label, x, y, p)
    SearchContext *scx;       /* Describes state of search when label
                         * was found.
                         */
    Label *label;       /* Label that was found. */
    int *x;             /* returned x position */
    int *y;             /* returned y position */
    int *p;             /* returned orientation */
{
    Rect rootArea;
    int pos;

    /* Mapping from our GEO_xxx positions to PS object types: */

    static int psPosition[] =
    {
       5, /* CENTCENT */
       1, /* TOPCENT */
       0, /* TOPRIGHT */
       4, /* CENTRIGHT */
      12, /* BOTRIGHT */
      13, /* BOTCENT */
      15, /* BOTLEFT */
       7, /* CENTLEFT */
       3  /* TOPLEFT */
    };

    GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea);
    pos = GeoTransPos(&scx->scx_trans, label->lab_just);
    switch (pos)
    {
      case GEO_NORTH:
      case GEO_NORTHEAST:
      case GEO_NORTHWEST:
          *y = (rootArea.r_ytop - bbox.r_ybot);
          *y += delta;
          break;

      case GEO_CENTER:
      case GEO_WEST:
      case GEO_EAST:
          *y = (rootArea.r_ytop + rootArea.r_ybot) / 2 - bbox.r_ybot;
          break;
      
      case GEO_SOUTH:
      case GEO_SOUTHEAST:
      case GEO_SOUTHWEST:
          *y = (rootArea.r_ybot - bbox.r_ybot);
          *y -= delta;
          break;
    }
    switch (pos)
    {
      case GEO_WEST:
      case GEO_NORTHWEST:
      case GEO_SOUTHWEST:
          *x = (rootArea.r_xbot - bbox.r_xbot);
          *x -= delta;
          break;
      
      case GEO_CENTER:
      case GEO_NORTH:
      case GEO_SOUTH:
          *x = (rootArea.r_xtop + rootArea.r_xbot) / 2 - bbox.r_xbot;
          break;
      
      case GEO_EAST:
      case GEO_NORTHEAST:
      case GEO_SOUTHEAST:
          *x = (rootArea.r_xtop - bbox.r_xbot);
          *x += delta;
          break;
    }
    *p = psPosition[pos];
}


/*
 * ----------------------------------------------------------------------------
 *
 * plotPSLabelBounds --
 *
 *    Estimate the bounding box extension based on label strings.
 *    In reality, we need to know label sizes to compute the scale,
 *    and we need to know the scale to compute label sizes.  However,
 *    in practice, we can only estimate the label size anyway, so we
 *    allow for some slop and just wing it.
 *
 * ----------------------------------------------------------------------------
 */

#define AVGCHARWIDTH 0.7
#define CHARHEIGHT 1.4

int
plotPSLabelBounds(scx, label)
    SearchContext *scx;       /* Describes state of search when label
                         * was found.
                         */
    Label *label;       /* Label that was found. */
{
    int pspos;
    int ls, psxsize, psysize;
    int llx, lly, urx, ury;
    int psdelta = (int)((float)delta / fscale);

    plotPSLabelPosition(scx, label, &llx, &lly, &pspos);
    urx = (int)((float)(llx - bbox.r_xtop) / fscale);
    ury = (int)((float)(lly - bbox.r_ytop) / fscale);
    llx = (int)((float)(bbox.r_xbot - llx) / fscale);
    lly = (int)((float)(bbox.r_ybot - lly) / fscale);
    ls = strlen(label->lab_text);
  
    psxsize = ls * (int)((float)PlotPSLabelSize * AVGCHARWIDTH);
    psysize = (int)((float)PlotPSLabelSize * CHARHEIGHT);

    switch (pspos) {
      case 0:
          ury += psysize + psdelta;
          urx += psxsize + psdelta;
          break;
      case 4:
          ury += psysize / 2;
          lly += psysize / 2;
          urx += psxsize + psdelta;
          break;
      case 12:
          lly += psysize + psdelta;
          urx += psxsize + psdelta;
          break;
      case 13:
          lly += psysize + psdelta;
          urx += psxsize / 2;
          llx += psxsize / 2;
          break;
      case 15:
          lly += psysize + psdelta;
          llx += psxsize + psdelta;
          break;
      case 7:
          ury += psysize / 2;
          lly += psysize / 2;
          llx += psxsize + psdelta;
          break;
      case 3:
          ury += psysize + psdelta;
          llx += psxsize + psdelta;
          break;
      case 1:
          ury += psysize + psdelta;
          urx += psxsize / 2;
          llx += psxsize / 2;
          break;
      case 5:
          ury += psysize / 2;
          lly += psysize / 2;
          urx += psxsize / 2;
          llx += psxsize / 2;
          break;
    }
 
    if (xpmargin < urx) xpmargin = urx;
    if (ypmargin < ury) ypmargin = ury;
    if (xnmargin < llx) xnmargin = llx;
    if (ynmargin < lly) ynmargin = lly;

    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotPSLabelBox --
 *
 *    Output the box connected to a label
 *
 * ----------------------------------------------------------------------------
 */

int
plotPSLabelBox(scx, label)
    SearchContext *scx;       /* Describes state of search when label
                         * was found.
                         */
    Label *label;       /* Label that was found. */
{
    Rect rootArea;
    int x, y;

    GeoTransRect(&scx->scx_trans, &label->lab_rect, &rootArea);

    /* 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 (curLineWidth != PS_MEDIUM) {
      fprintf(file, "l2\n");
      curLineWidth = PS_MEDIUM;
    }

    if ((rootArea.r_xbot == rootArea.r_xtop) &&
          (rootArea.r_ybot == rootArea.r_ytop))
    {
      /* Point label.  Output a cross. */

      x = (rootArea.r_xbot - bbox.r_xbot);
      y = (rootArea.r_ybot - bbox.r_ybot);
      fprintf(file, "%d %d %d pl\n", delta, x, y);
    }
    else if ((rootArea.r_xbot == rootArea.r_xtop) ||
           (rootArea.r_ybot == rootArea.r_ytop))
    {
      /* Line label.  Just draw a medium-thickness line. */

      plotPSLine(&rootArea.r_ll, &rootArea.r_ur);
    }
    else
    {
      /* Rectangular.  Draw lines around the boundary. */

      plotPSRect(&rootArea, 0);
    }
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotPSLabel --
 *
 *    This procedure is invoked once for each label overlapping the
 *    area being plotted.  It generates PS output to describe
 *    the label.
 *
 * Results:
 *    Always returns 0 to keep the search from aborting.
 *
 * Side effects:
 *    PS information is output.
 *
 * ----------------------------------------------------------------------------
 */

int
plotPSLabel(scx, label)
    SearchContext *scx;       /* Describes state of search when label
                         * was found.
                         */
    Label *label;       /* Label that was found. */
{
    int x, y;
    int pspos;

    plotPSLabelPosition(scx, label, &x, &y, &pspos);

    /* Output the text for the label, if the label is within delta
     * of the area we're plotting (a large label could overlap a
     * bit of the area but stick out way off-screen too).
     */
    
    if ((x >= -delta) && (y >= -delta) &&
          (x <= (bbox.r_xtop - bbox.r_xbot) + delta) &&
          (y <= (bbox.r_ytop - bbox.r_ybot) + delta))
    {
      fprintf(file, "(%s) %d %d %d lb\n", label->lab_text, pspos, x, y);
    }
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * plotPSCell --
 *
 *    This procedure is invoked once for each unexpanded cell that
 *    overlaps the area being plotted.
 *
 * Results:
 *    Always returns 0 to keep the search from aborting.
 *
 * Side effects:
 *    PS information is output to describe the cell.
 *
 * ----------------------------------------------------------------------------
 */

int
plotPSCell(scx)
    SearchContext *scx;       /* Describes cell whose bbox is to
                         * be plotted.
                         */   
{
    extern bool PlotShowCellNames;
    char idName[100];
    Rect rootArea;
    CellDef *def;
    int x, y;

    /* 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);
    if (curLineWidth != PS_THICK) {
      fprintf(file, "l3\n");
      curLineWidth = PS_THICK;
    }
    plotPSRect(&rootArea, 0);

    if (!PlotShowCellNames)
      return 0;

    /* Output the cell definition's name in the top of the bounding box.
     * Use a bold font (#3), in a medium size (#2).  Make sure that the
     * name's positioning point is within the area we're plotting.
     */

    x = (rootArea.r_xtop + rootArea.r_xbot - 2*bbox.r_xbot)/2;
    y = (2*rootArea.r_ytop + rootArea.r_ybot - 3*bbox.r_ybot)/3;
    if ((x >= 0) && (y >= 0) &&
          (x <= (bbox.r_xtop - bbox.r_xbot)) &&
          (y <= (bbox.r_ytop - bbox.r_ybot)))
    {
      fprintf(file, "f2 (%s) 5 %d %d lb\n", def->cd_name, x, y);
    }

    /* Output the cell id in the bottom of the bounding box.
     * Use an italic font (#2) in a medium size (#2).
     */

    x = (rootArea.r_xtop + rootArea.r_xbot - 2*bbox.r_xbot)/2;
    y = (rootArea.r_ytop + 2*rootArea.r_ybot - 3*bbox.r_ybot)/3;
    if ((x >= 0) && (y >= 0) &&
          (x <= (bbox.r_xtop - bbox.r_xbot)) &&
          (y <= (bbox.r_ytop - bbox.r_ybot)))
    {
      (void) DBPrintUseId(scx, idName, 100, TRUE);
      fprintf(file, "f3 (%s) 5 %d %d lb\n", idName, x, y);
    }

    return 0;
}


/*
 * ----------------------------------------------------------------------------
 *
 * PlotPS --
 *
 *    This procedure generates a PS file to describe an area of
 *    a layout.
 *
 * Results:
 *    None.
 *
 * Side effects:
 *    None.
 *
 * ----------------------------------------------------------------------------
 */

void
PlotPS(fileName, scx, layers, xMask)
    char *fileName;                 /* Name of PS file to write. */
    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 xsize, ysize;
    float yscale;
    FILE *infile;
    int i, j;
    int twidth, theight;
    char *fontptr, *fptr2, *fptr3;
    char line_in[100];

    PSReset();

    /* Compute a scale factor between our coordinates and PS
     * coordinates.
     */
    
    GeoTransRect(&scx->scx_trans, &scx->scx_area, &bbox);
    xsize = bbox.r_xtop - bbox.r_xbot;
    ysize = bbox.r_ytop - bbox.r_ybot;
    fscale = (float)(PlotPSWidth - 2 * PlotPSMargin) / (float)xsize;
    yscale = (float)(PlotPSHeight - 2 * PlotPSMargin) / (float)ysize;
    if (yscale < fscale) fscale = yscale;

    /* 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)
      delta = RtrMetalWidth / 8;
    else delta = RtrPolyWidth / 8;
    if (delta == 0) delta = 1;

    /* Go through labels once to estimate the bounding box, including labels */

    xnmargin = ynmargin = xpmargin = ypmargin = 0;
    if (TTMaskHasType(layers, L_LABEL))
    {
      curMask = *layers;
      TTMaskSetType(&curMask, TT_SPACE);
      (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL,
            plotPSLabelBounds, (ClientData) NULL);
      fscale = (float)(PlotPSWidth - 2 * PlotPSMargin - xnmargin - xpmargin)
            / (float)(xsize);
      yscale = (float)(PlotPSHeight - 2 * PlotPSMargin - ynmargin - ypmargin)
            / (float)(ysize);
        if (yscale < fscale) fscale = yscale;
    }
    twidth = (xsize * fscale) + xnmargin + xpmargin;
    theight = (ysize * fscale) + ynmargin + ypmargin;

    /* Open the PS file and output header information. */

    file = PaOpen(fileName, "w", (char *) NULL, ".", (char *) NULL,
          (char **) NULL);
    if (file == NULL)
    {
      TxError("Couldn't write PS file \"%s\".\n", fileName);
      return;
    }
    fprintf(file, "%%!PS-Adobe-3.0 EPSF-3.0\n");
    fprintf(file, "%%%%BoundingBox: %d %d %d %d\n",
            PlotPSMargin, PlotPSMargin, twidth + PlotPSMargin,
            theight + PlotPSMargin);
    fontptr = PlotPSIdFont;
    fprintf(file, "%%%%DocumentNeededResources: font %s", fontptr);
    if (!Match(fptr2 = PlotPSNameFont, fontptr));
        fprintf(file, " font %s", fptr2);
    if (!Match(fptr3 = PlotPSLabelFont, fontptr))
      if (!Match(fptr3, fptr2))
            fprintf(file, " font %s", fptr3);
    fprintf(file, "\n");
    fprintf(file, "%%%%EndComments\n");

    /* Insert the prolog here */

    infile = PaOpen("magicps", "r", ".pro", ".", SysLibPath, NULL);
    if (infile != NULL)
      while(fgets(line_in, 99, infile) != NULL)
          fputs(line_in, file);
    else
      fprintf(file, "\npostscript_prolog_is_missing\n\n");

    /* Insert the font definitions here. */

    fprintf(file, "/f1 { %.3f %s sf } def\n", (float)PlotPSLabelSize / fscale,
            PlotPSLabelFont);
    fprintf(file, "/f2 { %.3f %s sf } def\n", (float)PlotPSNameSize / fscale,
            PlotPSNameFont);
    fprintf(file, "/f3 { %.3f %s sf } def\n", (float)PlotPSIdSize / fscale,
            PlotPSIdFont);

    /* Insert the color and stipple definitions here. */

    for (curColor = plotPSColors; curColor != NULL;
       curColor = curColor->col_next)
    {
      fprintf(file, "/col%d {%.3f %.3f %.3f %.3f sc} bind def\n",
            curColor->index,
            (float)curColor->color[0] / 255.0,
            (float)curColor->color[1] / 255.0,
            (float)curColor->color[2] / 255.0,
            (float)curColor->color[3] / 255.0);
    }

    for (curPattern = plotPSPatterns; curPattern != NULL;
      curPattern = curPattern->pat_next)
    {
      fprintf(file, "{<");
      for (j = 0; j < 8; j++)
          fprintf(file, "%08x%08x", curPattern->stipple[j], curPattern->stipple[j]);
      fprintf(file, ">} %d dp\n", curPattern->index);
    }

    fprintf(file, "%%%%EndResource\n%%%%EndProlog\n\n");
    fprintf(file, "%%%%Page: 1 1\n");
    fprintf(file, "/pgsave save def bop\n");
    fprintf(file, "%% 0 0 offsets\nninit\n");
    fprintf(file, "%d %d translate\n", PlotPSMargin + xnmargin, PlotPSMargin
            + ynmargin);
    fprintf(file, "%.3f %.3f scale\nminit\n", fscale, fscale);
    fprintf(file, "0 0 %d %d gsave rectclip\n", xsize, ysize);
    fprintf(file, "l2\nsp\n\n");

    curLineWidth = PS_MEDIUM;

    /* For each PS style, find all the paint layers that belong
     * to that style and put plot information into the file.
     */
    
    for (curStyle = plotPSStyles; curStyle != NULL;
       curStyle = curStyle->grs_next)
    {
      fprintf(file, "col%d\n", curStyle->grs_color);
      if (curStyle->grs_stipple >= 0)
          fprintf(file, "%d sl\n", curStyle->grs_stipple);
      TTMaskAndMask3(&curMask, layers, &curStyle->grs_layers);
      (void) DBTreeSrTiles(scx, &curMask, xMask, plotPSPaint,
            (ClientData) NULL);
      plotPSFlushRect(curStyle->grs_stipple);
      plotPSFlushLine();
      PSReset();
    }

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

    if (TTMaskHasType(layers, L_CELL))
    {
      (void) DBTreeSrCells(scx, xMask, plotPSCell, (ClientData) NULL);
      plotPSFlushRect(BORDER);
      plotPSFlushLine();
    }

    /* Output label boxes followed by labels */

    if (TTMaskHasType(layers, L_LABEL))
    {
      curMask = *layers;
      TTMaskSetType(&curMask, TT_SPACE);
      (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL,
            plotPSLabelBox, (ClientData) NULL);
      plotPSFlushRect(BORDER);
      plotPSFlushLine();
      PSReset();
        fprintf(file, "grestore\n");      /* end clipping rectangle */
        fprintf(file, "f1 0 setgray\n");  /* set font, set color to black */

      curMask = *layers;
      TTMaskSetType(&curMask, TT_SPACE);
      (void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL,
            plotPSLabel, (ClientData) NULL);
    }
    else
    {
        fprintf(file, "grestore\n");      /* end clipping rectangle */
    }

    /* Output trailer information into the file, and close it. */

    fprintf(file, "pgsave restore showpage\n\n");
    fprintf(file, "%%%%Trailer\nMAGICsave restore\n%%%%EOF\n");
    fclose(file);
    return;
}

Generated by  Doxygen 1.6.0   Back to index