835 lines
23 KiB
C
835 lines
23 KiB
C
/*
|
||
* plotGremlin.c --
|
||
*
|
||
* This file contains procedures that generate Gremlin-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-8.0/plot/plotGremln.c,v 1.2 2008/06/01 18:37:45 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
|
||
* Gremlin output for a particular set of mask layers. Each style
|
||
* describes the Gremlin figures to draw for a particular set of
|
||
* layers. A single layer may participate in several gremlin styles.
|
||
*/
|
||
|
||
#ifdef GREMLIN
|
||
|
||
typedef struct gremlinstyle
|
||
{
|
||
TileTypeBitMask grs_layers; /* Layers to plot in this style. */
|
||
int grs_stipple; /* Type of fill to use. See below. */
|
||
struct gremlinstyle *grs_next; /* Next style in chain. */
|
||
} GremlinStyle;
|
||
|
||
static GremlinStyle *plotGremlinStyles;
|
||
|
||
/* Most of the grs_stipple values are Gremlin 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.
|
||
*/
|
||
|
||
#define CROSS -1
|
||
#define BORDER -2
|
||
|
||
/* The definitions below give the integers used for various Gremlin
|
||
* line drawing styles (brushes).
|
||
*/
|
||
|
||
#define GREMLIN_DOTTED 1
|
||
#define GREMLIN_DASHED 4
|
||
#define GREMLIN_DOTDASH 2
|
||
#define GREMLIN_THIN 5
|
||
#define GREMLIN_MEDIUM 6
|
||
#define GREMLIN_THICK 3
|
||
|
||
/* The variables below are used to pass information from the top-level
|
||
* procedure PlotGremlin down to the lower-level search functions
|
||
* that are invoked for pieces of the layout.
|
||
*/
|
||
|
||
static FILE *file; /* File to use for output. */
|
||
static float scale; /* Multiply this by Magic units to get
|
||
* Gremlin units.
|
||
*/
|
||
static GremlinStyle *curStyle; /* Current style being output. */
|
||
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.
|
||
*/
|
||
#endif /* GREMLIN */
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
* PlotGremlinTechInit --
|
||
*
|
||
* 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 GREMLIN
|
||
|
||
void
|
||
PlotGremlinTechInit()
|
||
{
|
||
GremlinStyle *style;
|
||
|
||
for (style = plotGremlinStyles; style != NULL; style = style->grs_next)
|
||
{
|
||
freeMagic((char *) style);
|
||
}
|
||
plotGremlinStyles = NULL;
|
||
}
|
||
|
||
#else
|
||
|
||
void
|
||
PlotGremlinTechInit()
|
||
{}
|
||
|
||
#endif /* GREMLIN */
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
* PlotGremlinTechLine --
|
||
*
|
||
* This procedure is invoked by the technology module once for
|
||
* each line in the "gremlin" 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 Gremlin styles.
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
#ifdef GREMLIN
|
||
|
||
bool
|
||
PlotGremlinTechLine(sectionName, argc, argv)
|
||
char *sectionName; /* Name of this section (unused). */
|
||
int argc; /* Number of arguments on line. */
|
||
char *argv[]; /* Pointers to fields of line. */
|
||
{
|
||
GremlinStyle *new;
|
||
int stipple, i;
|
||
|
||
if (argc != 2)
|
||
{
|
||
TechError("\"gremlin\" lines must have exactly 2 arguments.\n");
|
||
return TRUE;
|
||
}
|
||
|
||
if (strcmp(argv[1], "X") == 0)
|
||
stipple = CROSS;
|
||
else if (strcmp(argv[1], "B") == 0)
|
||
stipple = BORDER;
|
||
else
|
||
{
|
||
if (!StrIsInt(argv[1]))
|
||
{
|
||
TechError("2nd field must be an integer or \"X\" or \"B\".\n");
|
||
return TRUE;
|
||
}
|
||
stipple = atoi(argv[1]);
|
||
}
|
||
|
||
new = (GremlinStyle *) mallocMagic(sizeof(GremlinStyle));
|
||
|
||
DBTechNoisyNameMask(argv[0], &new->grs_layers);
|
||
|
||
/* Replace non-primary contact images with primary images. */
|
||
|
||
for (i = TT_TECHDEPBASE; i < DBNumTypes; i++)
|
||
{
|
||
if TTMaskHasType(&new->grs_layers, i)
|
||
TTMaskSetMask(&new->grs_layers, &DBLayerTypeMaskTbl[i]);
|
||
}
|
||
TTMaskAndMask(&new->grs_layers, &DBUserLayerBits);
|
||
new->grs_stipple = stipple;
|
||
new->grs_next = plotGremlinStyles;
|
||
plotGremlinStyles = new;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#else
|
||
|
||
bool
|
||
PlotGremlinTechLine(sectionName, argc, argv)
|
||
char *sectionName; /* Name of this section (unused). */
|
||
int argc; /* Number of arguments on line (unused). */
|
||
char *argv[]; /* Pointers to fields of line (unused). */
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
#endif /* GREMLIN */
|
||
|
||
#ifdef GREMLIN
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* plotGremlinLine --
|
||
*
|
||
* Outputs a line into the current Gremlin file.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* I/O.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
plotGremlinLine(p1, p2, lineStyle)
|
||
Point *p1, *p2; /* Endpoints of line, given in root
|
||
* coordinates.
|
||
*/
|
||
int lineStyle; /* Gremlin line style to use for line. */
|
||
{
|
||
float x1, x2, y1, y2, limit;
|
||
|
||
/* 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;
|
||
if (x1 < 0)
|
||
{
|
||
y1 += (-x1)*(y2-y1)/(x2-x1);
|
||
x1 = 0;
|
||
}
|
||
if (x2 > limit)
|
||
{
|
||
y2 -= (x2-limit)*(y2-y1)/(x2-x1);
|
||
x2 = limit;
|
||
}
|
||
|
||
/* 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;
|
||
if (y1 < 0)
|
||
{
|
||
x1 += (-y1)*(x2-x1)/(y2-y1);
|
||
y1 = 0;
|
||
}
|
||
if (y2 > limit)
|
||
{
|
||
x2 -= (y2-limit)*(x2-x1)/(y2-y1);
|
||
y2 = limit;
|
||
}
|
||
|
||
/* Lastly, scale and generate Gremlin output. */
|
||
|
||
x1 *= scale;
|
||
x2 *= scale;
|
||
y1 *= scale;
|
||
y2 *= scale;
|
||
|
||
fprintf(file, "VECTOR\n");
|
||
fprintf(file, "%.3f %.3f\n%.3f %.3f\n", x1, y1, x2, y2);
|
||
fprintf(file, "*\n%d 0\n0 \n", lineStyle);
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* plotGremlinRect --
|
||
*
|
||
* Outputs Gremlin statements to draw a rectangular area as
|
||
* an outline with a given line style.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Adds information to the current Gremlin file.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
plotGremlinRect(rect, lineStyle)
|
||
Rect *rect; /* Rectangle to be drawn, in root coords. */
|
||
int lineStyle; /* Gremlin line style to use for outline. */
|
||
{
|
||
Point p;
|
||
|
||
p.p_x = rect->r_xbot;
|
||
p.p_y = rect->r_ytop;
|
||
plotGremlinLine(&rect->r_ll, &p, lineStyle);
|
||
plotGremlinLine(&p, &rect->r_ur, lineStyle);
|
||
p.p_x = rect->r_xtop;
|
||
p.p_y = rect->r_ybot;
|
||
plotGremlinLine(&rect->r_ur, &p, lineStyle);
|
||
plotGremlinLine(&p, &rect->r_ll, lineStyle);
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* plotGremlinPaint --
|
||
*
|
||
* 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
|
||
plotGremlinPaint(tile, cxp)
|
||
Tile *tile; /* Tile that's of type to be output. */
|
||
TreeContext *cxp; /* Describes search in progress. */
|
||
{
|
||
Rect tileArea, edge, rootArea;
|
||
float xbot, xtop, ybot, ytop;
|
||
Tile *neighbor;
|
||
|
||
/* First transform tile coords to root coords */
|
||
|
||
TiToRect(tile, &tileArea);
|
||
GeoTransRect(&cxp->tc_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;
|
||
|
||
plotGremlinRect(&rootArea, GREMLIN_MEDIUM);
|
||
if (curStyle->grs_stipple == CROSS)
|
||
{
|
||
ul.p_x = rootArea.r_xbot;
|
||
ul.p_y = rootArea.r_ytop;
|
||
lr.p_x = rootArea.r_xtop;
|
||
lr.p_y = rootArea.r_ybot;
|
||
plotGremlinLine(&rootArea.r_ll, &rootArea.r_ur, GREMLIN_MEDIUM);
|
||
plotGremlinLine(&ul, &lr, GREMLIN_MEDIUM);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* This tile gets "normal" processing (i.e. stippling and outlining).
|
||
* Clip it to the plotting area and translate to Gremlin coords.
|
||
* Then output Gremlin information for stippled interior.
|
||
*/
|
||
|
||
GeoClip(&rootArea, &bbox);
|
||
xbot = (rootArea.r_xbot - bbox.r_xbot) * scale;
|
||
xtop = (rootArea.r_xtop - bbox.r_xbot) * scale;
|
||
ybot = (rootArea.r_ybot - bbox.r_ybot) * scale;
|
||
ytop = (rootArea.r_ytop - bbox.r_ybot) * scale;
|
||
fprintf(file, "POLYGON\n");
|
||
fprintf(file, "%.3f %.3f\n%.3f %.3f\n%.3f %.3f\n%.3f %.3f\n%.3f %.3f\n",
|
||
xbot, ybot, xtop, ybot, xtop, ytop, xbot, ytop, xbot, ybot);
|
||
fprintf(file, "*\n0 %d\n0 \n", curStyle->grs_stipple);
|
||
|
||
/* 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).
|
||
*/
|
||
|
||
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))
|
||
{
|
||
if (TTMaskHasType(&curMask, TiGetType(neighbor))) 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(&cxp->tc_scx->scx_trans, &edge, &rootArea);
|
||
plotGremlinLine(&rootArea.r_ll, &rootArea.r_ur, GREMLIN_THIN);
|
||
}
|
||
}
|
||
|
||
/* 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))
|
||
{
|
||
if (TTMaskHasType(&curMask, TiGetType(neighbor))) 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(&cxp->tc_scx->scx_trans, &edge, &rootArea);
|
||
plotGremlinLine(&rootArea.r_ll, &rootArea.r_ur, GREMLIN_THIN);
|
||
}
|
||
}
|
||
|
||
/* Same thing for the tile's top border. */
|
||
|
||
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))
|
||
{
|
||
if (TTMaskHasType(&curMask, TiGetType(neighbor))) 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(&cxp->tc_scx->scx_trans, &edge, &rootArea);
|
||
plotGremlinLine(&rootArea.r_ll, &rootArea.r_ur, GREMLIN_THIN);
|
||
}
|
||
}
|
||
|
||
/* Finally, the right border. */
|
||
|
||
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))
|
||
{
|
||
if (TTMaskHasType(&curMask, TiGetType(neighbor))) 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(&cxp->tc_scx->scx_trans, &edge, &rootArea);
|
||
plotGremlinLine(&rootArea.r_ll, &rootArea.r_ur, GREMLIN_THIN);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* plotGremlinLabel --
|
||
*
|
||
* This procedure is invoked once for each label overlapping the
|
||
* area being plotted. It generates Gremlin output to describe
|
||
* the label.
|
||
*
|
||
* Results:
|
||
* Always returns 0 to keep the search from aborting.
|
||
*
|
||
* Side effects:
|
||
* Gremlin information is output.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
plotGremlinLabel(scx, label)
|
||
SearchContext *scx; /* Describes state of search when label
|
||
* was found.
|
||
*/
|
||
Label *label; /* Label that was found. */
|
||
{
|
||
Rect rootArea;
|
||
float x, y;
|
||
float delta;
|
||
int pos;
|
||
|
||
/* Mapping from our GEO_xxx positions to Gremlin object types: */
|
||
|
||
static char *gremlinPosition[] =
|
||
{
|
||
"CENTCENT",
|
||
"BOTCENT",
|
||
"BOTLEFT",
|
||
"CENTLEFT",
|
||
"TOPLEFT",
|
||
"TOPCENT",
|
||
"TOPRIGHT",
|
||
"CENTRIGHT",
|
||
"BOTRIGHT"
|
||
};
|
||
|
||
/* 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*scale/8;
|
||
else delta = RtrPolyWidth*scale/8;
|
||
|
||
/* Translate the label's area and relative position to root
|
||
* coordinates, and figure out the point relative to which
|
||
* the label is to be positioned.
|
||
*/
|
||
|
||
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) * scale;
|
||
y += delta;
|
||
break;
|
||
|
||
case GEO_CENTER:
|
||
case GEO_WEST:
|
||
case GEO_EAST:
|
||
y = (rootArea.r_ytop + rootArea.r_ybot - 2*bbox.r_ybot)*scale/2;
|
||
break;
|
||
|
||
case GEO_SOUTH:
|
||
case GEO_SOUTHEAST:
|
||
case GEO_SOUTHWEST:
|
||
y = (rootArea.r_ybot - bbox.r_ybot) * scale;
|
||
y -= delta;
|
||
break;
|
||
}
|
||
switch (pos)
|
||
{
|
||
case GEO_WEST:
|
||
case GEO_NORTHWEST:
|
||
case GEO_SOUTHWEST:
|
||
x = (rootArea.r_xbot - bbox.r_xbot) * scale;
|
||
x -= delta;
|
||
break;
|
||
|
||
case GEO_CENTER:
|
||
case GEO_NORTH:
|
||
case GEO_SOUTH:
|
||
x = (rootArea.r_xtop + rootArea.r_xbot - 2*bbox.r_xbot)*scale/2;
|
||
break;
|
||
|
||
case GEO_EAST:
|
||
case GEO_NORTHEAST:
|
||
case GEO_SOUTHEAST:
|
||
x = (rootArea.r_xtop - bbox.r_xbot) * scale;
|
||
x += delta;
|
||
break;
|
||
}
|
||
|
||
/* 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) * scale) + delta) &&
|
||
(y <= ((bbox.r_ytop - bbox.r_ybot) * scale) + delta))
|
||
{
|
||
fprintf(file, "%s\n", gremlinPosition[pos]);
|
||
fprintf(file, "%.3f %.3f\n*\n", x, y);
|
||
fprintf(file, "1 1\n"); /* Roman font, small characters */
|
||
fprintf(file, "%d %s\n", strlen(label->lab_text), label->lab_text);
|
||
}
|
||
|
||
/* 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))
|
||
{
|
||
/* Point label. Output a cross. */
|
||
|
||
float top, bot;
|
||
|
||
x = (rootArea.r_xbot - bbox.r_xbot) * scale;
|
||
y = (rootArea.r_ybot - bbox.r_ybot) * scale;
|
||
top = y + delta;
|
||
bot = y - delta;
|
||
fprintf(file, "VECTOR\n%.3f %.3f\n%.3f %.3f\n*\n", x, bot, x, top);
|
||
fprintf(file, "6 1\n0 \n"); /* Medium thickness */
|
||
top = x + delta;
|
||
bot = x - delta;
|
||
fprintf(file, "VECTOR\n%.3f %.3f\n%.3f %.3f\n*\n", bot, y, top, y);
|
||
fprintf(file, "6 1\n0 \n"); /* Medium thickness */
|
||
}
|
||
else if ((rootArea.r_xbot == rootArea.r_xtop) ||
|
||
(rootArea.r_ybot == rootArea.r_ytop))
|
||
{
|
||
/* Line label. Just draw a medium-thickness line. */
|
||
|
||
plotGremlinLine(&rootArea.r_ll, &rootArea.r_ur, GREMLIN_MEDIUM);
|
||
}
|
||
else
|
||
{
|
||
/* Rectangular. Draw lines around the boundary. */
|
||
|
||
plotGremlinRect(&rootArea, GREMLIN_MEDIUM);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* plotGremlinCell --
|
||
*
|
||
* 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:
|
||
* Gremlin information is output to describe the cell.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
plotGremlinCell(scx)
|
||
SearchContext *scx; /* Describes cell whose bbox is to
|
||
* be plotted.
|
||
*/
|
||
{
|
||
extern bool PlotShowCellNames;
|
||
char idName[100];
|
||
Rect rootArea;
|
||
CellDef *def;
|
||
float 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);
|
||
plotGremlinRect(&rootArea, GREMLIN_THICK);
|
||
|
||
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)*scale/2;
|
||
y = (2*rootArea.r_ytop + rootArea.r_ybot - 3*bbox.r_ybot)*scale/3;
|
||
if ((x >= 0) && (y >= 0) &&
|
||
(x <= (bbox.r_xtop - bbox.r_xbot)*scale) &&
|
||
(y <= (bbox.r_ytop - bbox.r_ybot)*scale))
|
||
{
|
||
fprintf(file, "CENTCENT\n%.3f %.3f\n*\n", x, y);
|
||
fprintf(file, "3 2\n%d %s\n", strlen(def->cd_name), def->cd_name);
|
||
}
|
||
|
||
/* 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)*scale/2;
|
||
y = (rootArea.r_ytop + 2*rootArea.r_ybot - 3*bbox.r_ybot)*scale/3;
|
||
if ((x >= 0) && (y >= 0) &&
|
||
(x <= (bbox.r_xtop - bbox.r_xbot)*scale) &&
|
||
(y <= (bbox.r_ytop - bbox.r_ybot)*scale))
|
||
{
|
||
(void) DBPrintUseId(scx, idName, 100, TRUE);
|
||
fprintf(file, "CENTCENT\n%.3f %.3f\n*\n", x, y);
|
||
fprintf(file, "2 2\n%d %s\n", strlen(idName), idName);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* PlotGremlin --
|
||
*
|
||
* This procedure generates a Gremlin file to describe an area of
|
||
* a layout.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
PlotGremlin(fileName, scx, layers, xMask)
|
||
char *fileName; /* Name of Gremlin 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 size, tmp;
|
||
|
||
/* Compute a scale factor between our coordinates and Gremlin
|
||
* coordinates. Pick an even power of two that will make all
|
||
* the Gremlin units fall between 0 and 512.
|
||
*/
|
||
|
||
GeoTransRect(&scx->scx_trans, &scx->scx_area, &bbox);
|
||
size = bbox.r_xtop - bbox.r_xbot;
|
||
tmp = bbox.r_ytop - bbox.r_ybot;
|
||
if (size < tmp) size = tmp;
|
||
scale = 64.0;
|
||
while (scale*size > 512)
|
||
scale /= 2.0;
|
||
|
||
/* Open the Gremlin file and output header information. */
|
||
|
||
file = PaOpen(fileName, "w", (char *) NULL, ".", (char *) NULL,
|
||
(char **) NULL);
|
||
if (file == NULL)
|
||
{
|
||
TxError("Couldn't write Gremlin file \"%s\".\n", fileName);
|
||
return;
|
||
}
|
||
fprintf(file, "sungremlinfile\n");
|
||
fprintf(file, "1 0.00 0.00\n");
|
||
|
||
/* For each Gremlin style, find all the paint layers that belong
|
||
* to that style and put plot information into the file.
|
||
*/
|
||
|
||
for (curStyle = plotGremlinStyles; curStyle != NULL;
|
||
curStyle = curStyle->grs_next)
|
||
{
|
||
TTMaskAndMask3(&curMask, layers, &curStyle->grs_layers);
|
||
(void) DBTreeSrTiles(scx, &curMask, xMask, plotGremlinPaint,
|
||
(ClientData) NULL);
|
||
}
|
||
|
||
/* Output labels, if they are wanted. */
|
||
|
||
if (TTMaskHasType(layers, L_LABEL))
|
||
{
|
||
curMask = *layers;
|
||
TTMaskSetType(&curMask, TT_SPACE);
|
||
(void) DBTreeSrLabels(scx, &curMask, xMask, (TerminalPath *) NULL,
|
||
TF_LABEL_ATTACH, plotGremlinLabel, (ClientData) NULL);
|
||
}
|
||
|
||
/* Output subcell bounding boxes, if they are wanted. */
|
||
|
||
if (TTMaskHasType(layers, L_CELL))
|
||
{
|
||
(void) DBTreeSrCells(scx, xMask, plotGremlinCell, (ClientData) NULL);
|
||
}
|
||
|
||
/* Output trailer information into the file, and close it. */
|
||
|
||
fprintf(file, "-1\n");
|
||
fclose(file);
|
||
return;
|
||
}
|
||
|
||
#endif /* GREMLIN */
|