magic/cif/CIFhier.c

1147 lines
34 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* CIFhier.c -
*
* This module handles hierarchy as part of the CIF generator.
* Because of the nature of the geometrical operations used
* to generate CIF, such as grow and shrink, the CIF representing
* two nearby subcells (or elements of an array) may require
* more than just the combined CIF of the two subcells considered
* separately. This module computes the extra CIF that may be
* needed.
*
* *********************************************************************
* * 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/cif/CIFhier.c,v 1.3 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "cif/CIFint.h"
#include "cif/cif.h"
#include "drc/drc.h"
#include "textio/textio.h"
#include "utils/undo.h"
#include "utils/malloc.h"
#include "utils/signals.h"
/* To compute CIF where there are interaction areas we do two things:
* 1. Compute the CIF by combining all the material in all the interacting
* cells together. CIFTotalUse and CIFTotalDef and CIFTotalPlanes
* are used to hold the flattened material and resulting CIF.
* 2. Compute the CIF that results by considering the material in each
* subtree separately and also the material in the parent separately.
* The paint for each subtree is first flattened into CIFComponentUse
* and CIFComponentDef, and the resulting CIF from each subtree is
* OR'ed together into CIFComponentPlanes.
*/
CellUse *CIFTotalUse = NULL;
CellDef *CIFTotalDef;
CellUse *CIFComponentUse;
CellDef *CIFComponentDef;
Plane *CIFTotalPlanes[MAXCIFLAYERS];
Plane *CIFComponentPlanes[MAXCIFLAYERS];
/* The following use is just used to turn a def into a use for calling
* procedures that want a use.
*/
CellUse *CIFDummyUse;
/* The following local variables are used to share information
* between top-level procedures and search functions.
*/
/* Used in cifHierPaintArrayFunc: */
Plane *cifHierCurPlane; /* Current plane. */
static int cifHierXSpacing, cifHierYSpacing, cifHierXCount, cifHierYCount;
/* Used in cifGrowSliver */
static CIFLayer *CurCifLayer;
/* Macro for scaling boxes into CIF coordinates: */
#define SCALE(src, scale, dst) \
(dst)->r_xbot = (src)->r_xbot * scale; \
(dst)->r_ybot = (src)->r_ybot * scale; \
(dst)->r_xtop = (src)->r_xtop * scale; \
(dst)->r_ytop = (src)->r_ytop * scale;
/*
* ----------------------------------------------------------------------------
*
* CIFInitCells --
*
* This procedure just sets up cell definitions and uses needed
* for hierarchical checking and other CIF uses.
*
* Results:
* None.
*
* Side effects:
* DRCUse, DRCDef, and DRCDummyUse are set up if they're not
* there already.
*
* ----------------------------------------------------------------------------
*/
void
CIFInitCells()
{
int i;
if (CIFTotalUse != NULL) return;
CIFTotalDef = DBCellLookDef("__CIF__");
if (CIFTotalDef == (CellDef *) NULL)
{
CIFTotalDef = DBCellNewDef("__CIF__");
ASSERT(CIFTotalDef != (CellDef *) NULL, "cifMakeCell");
DBCellSetAvail(CIFTotalDef);
CIFTotalDef->cd_flags |= CDINTERNAL;
}
CIFTotalUse = DBCellNewUse (CIFTotalDef, (char *) NULL);
DBSetTrans (CIFTotalUse, &GeoIdentityTransform);
CIFTotalUse->cu_expandMask = CU_DESCEND_SPECIAL; /* This is always expanded. */
CIFComponentDef = DBCellLookDef("__CIF2__");
if (CIFComponentDef == (CellDef *) NULL)
{
CIFComponentDef = DBCellNewDef("__CIF2__");
ASSERT(CIFComponentDef != (CellDef *) NULL, "cifMakeCell");
DBCellSetAvail(CIFComponentDef);
CIFComponentDef->cd_flags |= CDINTERNAL;
}
CIFComponentUse = DBCellNewUse (CIFComponentDef, (char *) NULL);
DBSetTrans (CIFComponentUse, &GeoIdentityTransform);
CIFComponentUse->cu_expandMask = CU_DESCEND_SPECIAL; /* This is always expanded. */
/* Clear out the planes used to collect hierarchical CIF. */
for (i = 0; i < MAXCIFLAYERS; i++)
{
CIFComponentPlanes[i] = NULL;
CIFTotalPlanes[i] = NULL;
}
/* Also create a dummy cell use to use for passing to
* procedures that need a use when all we've got is a def.
*/
CIFDummyUse = DBCellNewUse(CIFTotalDef, (char *) NULL);
DBSetTrans (CIFDummyUse, &GeoIdentityTransform);
}
/*
* ----------------------------------------------------------------------------
*
* cifHierCleanup --
*
* This procedure is called after CIF hierarchical processing
* to clean up the cells and tile planes use for hierarchy and
* release storage.
*
* Results:
* None.
*
* Side effects:
* All the CIF-related uses and planes are cleaned up.
*
* ----------------------------------------------------------------------------
*/
void
cifHierCleanup()
{
int i;
/* We can't afford for this clearing out to be interrupted, or
* it could cause the next CIF to be generated wrong.
*/
SigDisableInterrupts();
DBCellClearDef(CIFTotalDef);
DBCellClearDef(CIFComponentDef);
for (i = 0; i < MAXCIFLAYERS; i++)
{
if (CIFTotalPlanes[i] != NULL)
{
DBFreePaintPlane(CIFTotalPlanes[i]);
TiFreePlane(CIFTotalPlanes[i]);
CIFTotalPlanes[i] = NULL;
}
if (CIFComponentPlanes[i] != NULL)
{
DBFreePaintPlane(CIFComponentPlanes[i]);
TiFreePlane(CIFComponentPlanes[i]);
CIFComponentPlanes[i] = NULL;
}
}
SigEnableInterrupts();
}
/*
* ----------------------------------------------------------------------------
*
* cifHierCopyFunc --
*
* This procedure is called to copy paint from the database into
* flattened areas for CIF generation. It's important to use
* this procedure rather than calling DBCellCopyAllPaint. The
* reason is that DBCellCopyAllPaint clips the tiles to the
* edges of the search area. When generating CIF for layers like
* contacts, the exact location of the edge of the tile is
* important. Thus, this procedure always copies WHOLE tiles.
* Information will be clipped to the edge of the CIF generation
* area later.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* The tile is copied into the definition indicated by the
* client data.
*
* ----------------------------------------------------------------------------
*/
int
cifHierCopyFunc(tile, cxp)
Tile *tile; /* Pointer to tile to copy. */
TreeContext *cxp; /* Describes context of search, including
* transform and client data.
*/
{
TileType type = TiGetTypeExact(tile);
Rect sourceRect, targetRect;
int pNum;
CellDef *def = (CellDef *) cxp->tc_filter->tf_arg;
int dinfo = 0;
/* Ignore tiles in vendor GDS, unless this is specifically */
/* overridden by the "see-vendor" option. */
if (cxp->tc_scx->scx_use->cu_def->cd_flags & CDVENDORGDS)
{
if (!CIFCurStyle)
return 0;
else if (!(CIFCurStyle->cs_flags & CWF_SEE_VENDOR))
return 0;
}
/* Ignore space tiles, since they won't do anything anyway. */
if (IsSplit(tile))
{
dinfo = DBTransformDiagonal(type, &cxp->tc_scx->scx_trans);
type = (SplitSide(tile)) ? SplitRightType(tile) :
SplitLeftType(tile);
}
if (type == TT_SPACE) return 0;
/* Get the rectangular area, and transform to final coords. */
TiToRect(tile, &sourceRect);
GeoTransRect(&cxp->tc_scx->scx_trans, &sourceRect, &targetRect);
for (pNum = PL_SELECTBASE; pNum < DBNumPlanes; pNum++)
{
if (DBPaintOnPlane(type, pNum))
{
DBNMPaintPlane(def->cd_planes[pNum], dinfo, &targetRect,
DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL);
}
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifHierCellFunc --
*
* This procedure is invoked once for each subcell overlapping
* an interaction area. It flattens the subcell and its children
* in the area of the overlap, generates CIF for that area, and
* saves it in cifHierPieces.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* A new collection of CIF planes is added to cifHierPieces.
*
* ----------------------------------------------------------------------------
*/
int
cifHierCellFunc(scx)
SearchContext *scx; /* Describes cell and area in cell. */
{
SearchContext newscx;
Rect rootArea;
/* Do not call this function on cells that are vendor GDS */
/* (handled in cifHierCopyFunc()) */
/* if (scx->scx_use->cu_def->cd_flags & CDVENDORGDS) return 0; */
/* In order to generate CIF safely in the interaction area, we
* have to yank material in a larger area: bloats and shrinks
* may cause this material to affect CIF in the interaction area.
* This may actually be over-conservative, but it's safe. Think
* carefully before trying to optimize!
*/
DBCellClearDef(CIFComponentDef);
newscx = *scx;
GEO_EXPAND(&scx->scx_area, CIFCurStyle->cs_radius, &newscx.scx_area);
(void) DBTreeSrTiles(&newscx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
/* Set CIFErrorDef to NULL to ignore errors here... these will
* get reported anyway when the cell is CIF'ed non-hierarchically,
* so there's no point in making a second report here.
*/
CIFErrorDef = (CellDef *) NULL;
GeoTransRect(&scx->scx_trans, &scx->scx_area, &rootArea);
CIFGen(CIFComponentDef, &rootArea, CIFComponentPlanes,
&CIFCurStyle->cs_hierLayers, FALSE, TRUE);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifHierErrorFunc --
*
* This function is invoked when the combined CIF in a parent
* is LESS than the individual CIFs of the children. This means
* there are bogus rules in the CIF rule set.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* Error information is output.
*
* ----------------------------------------------------------------------------
*/
int
cifHierErrorFunc(tile, checkArea)
Tile *tile; /* Tile that covers area it shouldn't. */
Rect *checkArea; /* Intersection of this and tile is error. */
{
Rect area;
TiToRect(tile, &area);
/* Space in a diagonal tile is not an error if the corner containing
* space bounds the checkArea.
*/
if (IsSplit(tile))
if (((area.r_xbot == checkArea->r_xbot) && !SplitSide(tile)) ||
((area.r_xtop == checkArea->r_xtop) && SplitSide(tile)))
return 0;
GeoClip(&area, checkArea);
CIFError(&area, "parent and child disagree on CIF");
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifHierCheckFunc --
*
* This function is invoked once for each CIF tile coming from
* a subcell piece. It makes sure there are no space tiles over
* its area in "plane", then deletes everything from that area
* in "plane".
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* Error messages may be output.
*
* ----------------------------------------------------------------------------
*/
int
cifHierCheckFunc(tile, plane)
Tile *tile; /* Tile containing CIF. */
Plane *plane; /* Plane to check against and modify. */
{
Rect area;
TiToRect(tile, &area);
if (IsSplit(tile))
{
DBSrPaintNMArea((Tile *)NULL, plane, TiGetTypeExact(tile),
&area, &DBSpaceBits, cifHierErrorFunc, (ClientData) &area);
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFEraseTable,
(PaintUndoInfo *) NULL);
}
else
{
DBSrPaintArea((Tile *) NULL, plane, &area,
&DBSpaceBits, cifHierErrorFunc, (ClientData) &area);
DBPaintPlane(plane, &area, CIFEraseTable, (PaintUndoInfo *) NULL);
}
CIFTileOps++;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifHierPaintFunc --
*
* Called to transfer information from one CIF plane to another.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* The area of tile is painted into plane.
*
* ----------------------------------------------------------------------------
*/
int
cifHierPaintFunc(tile, plane)
Tile *tile;
Plane *plane; /* Plane in which to paint CIF over tile's
* area.
*/
{
Rect area;
TiToRect(tile, &area);
if (CIFCurStyle->cs_flags & CWF_GROW_SLIVERS) cifGrowSliver(tile, &area);
if (IsSplit(tile))
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFPaintTable,
(PaintUndoInfo *) NULL);
else
DBPaintPlane(plane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
CIFTileOps += 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifCheckAndErase --
*
* This utility procedure processes the hierarchical pieces
* in two ways. First, it makes sure that all the CIF in
* CIFComponentPlanes is present in CIFTotalPlanes. Second,
* it erases from CIFTotalPlanes any information that's in
* CIFComponentPlanes.
*
* Results:
* None.
*
* Side effects:
* The information in CIFTotalPlanes is reduced, and error messages
* may be output.
*
* ----------------------------------------------------------------------------
*/
void
cifCheckAndErase(style)
CIFStyle *style; /* Describes how to make CIF. */
{
int i;
/* Process all of the bits of CIF in CIFComponentPlanes. */
for (i=0; i<style->cs_nLayers; i++)
{
CIFErrorLayer = i;
if (CIFComponentPlanes[i] == NULL) continue;
(void) DBSrPaintArea((Tile *) NULL, CIFComponentPlanes[i],
&TiPlaneRect, &CIFSolidBits, cifHierCheckFunc,
(ClientData) CIFTotalPlanes[i]);
}
}
/*
* ----------------------------------------------------------------------------
*
* CIFGenSubcells --
*
* This procedure computes all of the CIF that must be added to
* a given area to compensate for interactions between subcells.
*
* Results:
* None.
*
* Side effects:
* The parameter "output" is modified (by OR'ing) to hold all
* the CIF that was generated for subcells.
*
* ----------------------------------------------------------------------------
*/
void
CIFGenSubcells(def, area, output)
CellDef *def; /* Parent cell for which CIF is computed. */
Rect *area; /* All CIF in this area is interesting. */
Plane **output; /* Array of pointers to planes into which
* the CIF output will be OR'ed (real CIF
* only).
*/
{
int stepSize, x, y, i, radius, oldTileOps, oldTileOps2;
Rect totalArea, square, interaction;
SearchContext scx;
UndoDisable();
CIFInitCells();
radius = CIFCurStyle->cs_radius;
stepSize = CIFCurStyle->cs_stepSize;
if (stepSize <= 0)
{
stepSize = 20*radius;
if (stepSize < 50) stepSize = 50;
}
CIFDummyUse->cu_def = def;
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
/* Any tile operations processed here get billed to hierarchy
* in addition to being added to the total.
*/
oldTileOps = CIFTileOps;
/* Divide the area of the cell up into squares, and step through
* the chunks. In each chunk, the first thing to do is to find
* out if there are any subcell interactions within one
* radius of the square.
*/
totalArea = *area;
GeoClip(&totalArea, &def->cd_bbox);
for (y = totalArea.r_ybot; y < totalArea.r_ytop; y += stepSize)
for (x = totalArea.r_xbot; x < totalArea.r_xtop; x += stepSize)
{
square.r_xbot = x;
square.r_ybot = y;
square.r_xtop = x + stepSize;
square.r_ytop = y + stepSize;
if (square.r_xtop > totalArea.r_xtop)
square.r_xtop = totalArea.r_xtop;
if (square.r_ytop > totalArea.r_ytop)
square.r_ytop = totalArea.r_ytop;
GEO_EXPAND(&square, radius, &square);
if (!DRCFindInteractions(def, &square, radius,
&interaction)) continue;
/* We've found an interaction. Flatten it into CIFTotalUse, then
* make CIF from what's flattened. Yank extra material to
* ensure that CIF is generated correctly.
*/
GEO_EXPAND(&interaction, CIFCurStyle->cs_radius, &scx.scx_area);
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFTotalDef);
CIFErrorDef = def;
CIFGen(CIFTotalDef, &interaction, CIFTotalPlanes,
&CIFCurStyle->cs_hierLayers, TRUE, TRUE);
/* Now go through all the subcells overlapping the area
* and generate CIF for each subcell individually. OR this
* combined CIF together into CIFComponentPlanes.
*/
scx.scx_area = interaction;
(void) DBCellSrArea(&scx, cifHierCellFunc, (ClientData) NULL);
/* Also generate CIF for the paint in the parent alone. Ignore
* CIF generation errors here, since they will already have been
* recorded when the parent was CIF'ed by itself.
*/
CIFErrorDef = (CellDef *) NULL;
CIFGen(def, &interaction, CIFComponentPlanes,
&CIFCurStyle->cs_hierLayers, FALSE, TRUE);
/* Make sure everything in the pieces is also in the overall
* CIF, then erase the piece stuff from the overall, and
* throw away the pieces.
*/
CIFErrorDef = def;
cifCheckAndErase(CIFCurStyle);
/* Lastly, paint everything from the pieces into the result
* planes.
*/
oldTileOps2 = CIFTileOps;
for (i=0; i<CIFCurStyle->cs_nLayers; i++)
{
CurCifLayer = CIFCurStyle->cs_layers[i]; /* for growSliver */
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
&TiPlaneRect, &CIFSolidBits, cifHierPaintFunc,
(ClientData) output[i]);
}
CIFHierRects += CIFTileOps - oldTileOps2;
cifHierCleanup();
}
CIFHierTileOps += CIFTileOps - oldTileOps;
UndoEnable();
}
/*
* ----------------------------------------------------------------------------
*
* cifHierElementFunc --
*
* This function is called once for each time an array element
* overlaps one of the four areas A, B, C, or D in cifHierArrayFunc
* (see below). Its job is to yank the relevant piece of this
* cell into CIFTotalDef, and also to yank the same piece into
* CIFComponentDef and generate a piece of CIF from it. The CIF
* from the piece is OR'ed into CIFComponentPlanes for later comparison
* with the parent.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* The cell CIFTotalUse is modified, as is CIFComponentUse and
* CIFComponentPlanes.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
int
cifHierElementFunc(use, transform, x, y, checkArea)
CellUse *use; /* CellUse being array-checked. */
Transform *transform; /* Transform from this instance to
* the parent.
*/
int x, y; /* Indices of this instance. */
Rect *checkArea; /* Area (in parent coords) to be
* CIF-generated.
*/
{
Rect defArea;
Transform tinv;
SearchContext scx;
GeoInvertTrans(transform, &tinv);
GeoTransRect(&tinv, checkArea, &defArea);
/* Yank extra material to ensure that CIF is generated correctly. */
GEO_EXPAND(&defArea, CIFCurStyle->cs_radius, &scx.scx_area);
scx.scx_trans = *transform;
scx.scx_use = use;
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFTotalDef);
DBCellClearDef(CIFComponentDef);
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFErrorDef = (CellDef *) NULL;
CIFGen(CIFComponentDef, checkArea, CIFComponentPlanes,
&CIFCurStyle->cs_hierLayers, FALSE, TRUE);
return 0;
}
/*
* ---------------------------------------------------------------------------
* cifGrowSliver() --
*
* This function is passed the address of a "sliver" rectangle. It then
* grows the shortest dimension of the sliver so that it is at least minimum
* width. The minimum width is found through the variable CurCifLayer which
* identifies the current layer being generated. A "minwidth" command has been
* added to the cifoutput section for which the minimum width of each layer
* can be specified.
*
* Results:
* Always return 0
*
* Side effects:
* Returns the modified rectangle in "area" (pointer)
* ---------------------------------------------------------------------------
*/
int
cifGrowSliver(tile, area)
Tile *tile;
Rect *area;
{
int height, width, expand_up, expand_side;
TiToRect(tile, area);
expand_up = (TiGetType(BL(tile)) != TT_SPACE) ||
(TiGetType(TR(tile)) != TT_SPACE);
expand_side = (TiGetType(LB(tile)) != TT_SPACE) ||
(TiGetType(RT(tile)) != TT_SPACE);
if (CurCifLayer->min_width == 0)
return 0;
height = area->r_ytop - area->r_ybot;
width = area->r_xtop - area->r_xbot;
printf("got sliver %d %d %d %d [%d,%d]\n",
area->r_xtop, area->r_xbot, area->r_ytop,
area->r_ybot, expand_up,expand_side);
if ((height < width) || expand_up)
{
if (height >= CurCifLayer->min_width) return 0;
area->r_ytop += (CurCifLayer->min_width - height)/2;
area->r_ybot -= (CurCifLayer->min_width - height)/2;
}
if ((width < height) || expand_side)
{
if(width >= CurCifLayer->min_width) return 0;
area->r_xtop += (CurCifLayer->min_width - width)/2;
area->r_xbot -= (CurCifLayer->min_width - width)/2;
}
printf("created sliver %d %d %d %d \n",
area->r_xtop, area->r_xbot, area->r_ytop, area->r_ybot);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifHierPaintArrayFunc --
*
* This function is used to paint in interaction tiles from an
* array. It is called once for each tile to be copied, and
* paints the tile into cifHierCurPlane. Then the tile is
* offset by cifHierXSpacing and cifHierYSpacing, and copied
* again and again, cifHierCount times in all. The caller must
* set up these shared variables.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* The plane pointed to by cifHierCurPlane gets modified.
*
* ----------------------------------------------------------------------------
*/
int
cifHierPaintArrayFunc(tile)
Tile *tile;
{
Rect area;
int i, j, xbot, xtop;
TiToRect(tile, &area);
if (CIFCurStyle->cs_flags & CWF_GROW_SLIVERS) cifGrowSliver(tile, &area);
xbot = area.r_xbot;
xtop = area.r_xtop;
for (i=0; i<cifHierYCount; i++)
{
for (j=0; j<cifHierXCount; j++)
{
DBPaintPlane(cifHierCurPlane, &area, CIFPaintTable,
(PaintUndoInfo *) NULL);
CIFTileOps += 1;
area.r_xbot += cifHierXSpacing;
area.r_xtop += cifHierXSpacing;
}
area.r_xbot = xbot;
area.r_xtop = xtop;
area.r_ybot += cifHierYSpacing;
area.r_ytop += cifHierYSpacing;
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifHierArrayFunc --
*
* This procedure is called once for each array that we
* are to generate interaction CIF for. It computes all
* the CIF that must be present in the parent to compensate
* for the interactions between array elements.
*
* Results:
* Always returns 2, to skip the remaining instances in the
* current array.
*
* Side effects:
* CIF is added to the set of planes indicated by output.
*
* Design:
* This procedure is something like a cross between drcArrayFunc
* and DRCGenSubcells. It computes interaction CIF in the four
* areas of the array shown below, then replicates it over all
* the other elements of the array.
*
* ------------------------------CCCCC--------------
* | | CCCCC |
* | | CCCCC |
* | | CCCCC |
* | | CCCCCDDDDDDDDDDDDDD
* ------------------------------CCCCCDDDDDDDDDDDDDD
* | | CCCCCDDDDDDDDDDDDDD
* | | | |
* | | | |
* AAAAAAAAAAAAAAAAAAA | |
* AAAAAAAAAAAAAAAAAAA------------------------------
* AAAAAAAAAAAAAAAAAAA | |
* | BBBBB | |
* | BBBBB | |
* | BBBBB | |
* --------------BBBBB------------------------------
* ----------------------------------------------------------------------------
*/
int
cifHierArrayFunc(scx, output)
SearchContext *scx; /* Information about the search. */
Plane **output; /* Array of planes to hold results. */
{
Rect childArea, parentArea, A, B, C, D, expandedArea;
CellUse *use;
int radius, xsep, ysep, xsize, ysize, nx, ny, i, oldTileOps;
int xhi, yhi;
bool anyInteractions = FALSE;
use = scx->scx_use;
radius = CIFCurStyle->cs_radius;
if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi))
return 2;
/* We only want interactions between neighboring cells, so reduce */
/* the array size to at most 2x2, process, then restore the */
/* original array count. */
xhi = use->cu_xhi;
yhi = use->cu_yhi;
if (use->cu_xlo != use->cu_xhi)
use->cu_xhi = use->cu_xlo + ((use->cu_xlo < use->cu_xhi) ? 1 : -1);
if (use->cu_ylo != use->cu_yhi)
use->cu_yhi = use->cu_ylo + ((use->cu_ylo < use->cu_yhi) ? 1 : -1);
/* Compute the sizes and separations of elements, in coordinates
* of the parent. If the array is 1-dimensional, we set the
* corresponding spacing to an impossibly large distance.
*/
childArea.r_xbot = 0;
childArea.r_ybot = 0;
/* Ensure that array width or height 1 corresponds to a separation */
/* large enough not to satisfy any conditions A, B, C, or D. */
if (use->cu_xlo == use->cu_xhi)
childArea.r_xtop = radius +
(use->cu_def->cd_bbox.r_xtop - use->cu_def->cd_bbox.r_xbot);
else childArea.r_xtop = use->cu_xsep;
if (use->cu_ylo == use->cu_yhi)
childArea.r_ytop = radius +
(use->cu_def->cd_bbox.r_ytop - use->cu_def->cd_bbox.r_ybot);
else childArea.r_ytop = use->cu_ysep;
GeoTransRect(&use->cu_transform, &childArea, &parentArea);
xsep = parentArea.r_xtop - parentArea.r_xbot;
ysep = parentArea.r_ytop - parentArea.r_ybot;
GeoTransRect(&use->cu_transform, &use->cu_def->cd_bbox, &parentArea);
xsize = parentArea.r_xtop - parentArea.r_xbot;
ysize = parentArea.r_ytop - parentArea.r_ybot;
nx = (use->cu_bbox.r_xtop - use->cu_bbox.r_xbot - xsize)/xsep;
nx += 1;
ny = (use->cu_bbox.r_ytop - use->cu_bbox.r_ybot - ysize)/ysep;
ny += 1;
/* Process each of the four areas A, B, C, and D. For each one,
* do three things: yank the relevant material into cell
* __CIF__, and generate a piece of CIF corresponding to each
* child area contributing to the overlap. This is all handled
* by the procedure cifHierElementFunc. Then generate the CIF
* for the combined information that was yanked into __CIF__.
* Collect all of the combined CIF from all four areas together
* into CIFTotalPlanes. Note: in each case we have to yank a larger
* area than we check, in order to include material that will be
* bloated or shrunk.
*/
/* A */
if (ysep < ysize + radius)
{
A.r_xbot = use->cu_bbox.r_xbot - radius;
A.r_xtop = use->cu_bbox.r_xbot + xsize + radius;
A.r_ybot = use->cu_bbox.r_ybot + ysep - radius;
A.r_ytop = use->cu_bbox.r_ybot + ysize + radius;
GEO_EXPAND(&A, CIFCurStyle->cs_radius, &expandedArea);
(void) DBArraySr(use, &expandedArea, cifHierElementFunc,
(ClientData) &A);
CIFErrorDef = use->cu_parent;
CIFGen(CIFTotalDef, &A, CIFTotalPlanes, &CIFCurStyle->cs_hierLayers,
FALSE, TRUE);
anyInteractions = TRUE;
}
/* C */
if (xsep < xsize + radius)
{
C.r_xbot = use->cu_bbox.r_xtop - xsize - radius;
C.r_xtop = use->cu_bbox.r_xtop - xsep + radius;
C.r_ybot = use->cu_bbox.r_ytop - ysize - radius;
C.r_ytop = use->cu_bbox.r_ytop + radius;
GEO_EXPAND(&C, CIFCurStyle->cs_radius, &expandedArea);
(void) DBArraySr(use, &expandedArea, cifHierElementFunc,
(ClientData) &C);
CIFErrorDef = use->cu_parent;
CIFGen(CIFTotalDef, &C, CIFTotalPlanes, &CIFCurStyle->cs_hierLayers,
FALSE, TRUE);
anyInteractions = TRUE;
}
if ((xsep < xsize + radius) && (ysep < ysize + radius))
{
/* B */
B.r_xbot = use->cu_bbox.r_xbot + xsep - radius;
B.r_xtop = use->cu_bbox.r_xbot + xsize + radius;
B.r_ybot = use->cu_bbox.r_ybot - radius;
B.r_ytop = use->cu_bbox.r_ybot + ysep - radius;
GEO_EXPAND(&B, CIFCurStyle->cs_radius, &expandedArea);
(void) DBArraySr(use, &expandedArea, cifHierElementFunc,
(ClientData) &B);
CIFErrorDef = use->cu_parent;
CIFGen(CIFTotalDef, &B, CIFTotalPlanes, &CIFCurStyle->cs_hierLayers,
FALSE, TRUE);
/* D */
D.r_xbot = use->cu_bbox.r_xtop - xsep + radius;
D.r_xtop = use->cu_bbox.r_xtop + radius;
D.r_ybot = use->cu_bbox.r_ytop - ysize - radius;
D.r_ytop = use->cu_bbox.r_ytop - ysep + radius;
GEO_EXPAND(&D, CIFCurStyle->cs_radius, &expandedArea);
(void) DBArraySr(use, &expandedArea, cifHierElementFunc,
(ClientData) &D);
CIFErrorDef = use->cu_parent;
CIFGen(CIFTotalDef, &D, CIFTotalPlanes, &CIFCurStyle->cs_hierLayers,
FALSE, TRUE);
}
if (anyInteractions)
{
/* Remove redundant CIF that's already in the children, and
* make sure everything in the kids is in the parent too.
*/
CIFErrorDef = use->cu_parent;
cifCheckAndErase(CIFCurStyle);
/* Lastly, paint everything back from our local planes into
* the planes of the caller. In doing this, stuff has to
* be replicated many times over to cover each of the array
* interaction areas.
*/
oldTileOps = CIFTileOps;
for (i=0; i<CIFCurStyle->cs_nLayers; i++)
{
int scale = CIFCurStyle->cs_scaleFactor;
Rect cifArea;
cifHierCurPlane = output[i];
CurCifLayer = CIFCurStyle->cs_layers[i]; /* for growSliver */
/* The left edge of the array (from A). */
if ((ny > 1) && (ysep < ysize + radius))
{
cifHierYSpacing = ysep * scale;
cifHierXSpacing = 0;
cifHierXCount = 1;
cifHierYCount = ny-1;
SCALE(&A, scale, &cifArea);
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
&cifArea, &CIFSolidBits, cifHierPaintArrayFunc,
(ClientData) NULL);
}
/* The top edge of the array (from C). */
if ((nx > 1) && (xsep < xsize + radius))
{
cifHierXSpacing = -xsep * scale;
cifHierYSpacing = 0;
cifHierXCount = nx-1;
cifHierYCount = 1;
SCALE(&C, scale, &cifArea);
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
&cifArea, &CIFSolidBits, cifHierPaintArrayFunc,
(ClientData) NULL);
}
if ((nx > 1) && (ny > 1) && (xsep < xsize + radius)
&& (ysep < ysize + radius))
{
/* The bottom edge of the array (from B). */
cifHierXSpacing = xsep * scale;
cifHierYSpacing = 0;
cifHierXCount = nx-1;
cifHierYCount = 1;
SCALE(&B, scale, &cifArea);
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
&cifArea, &CIFSolidBits, cifHierPaintArrayFunc,
(ClientData) NULL);
/* The right edge of the array (from D). */
cifHierXSpacing = 0;
cifHierYSpacing = -ysep * scale;
cifHierXCount = 1;
cifHierYCount = ny-1;
SCALE(&D, scale, &cifArea);
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
&cifArea, &CIFSolidBits, cifHierPaintArrayFunc,
(ClientData) NULL);
/* The core of the array (from A and B). This code is a bit
* tricky in order to work correctly even for arrays where
* radius < ysep. The "if" statement handles this case.
*/
cifHierXSpacing = xsep * scale;
cifHierYSpacing = ysep * scale;
cifHierXCount = nx-1;
cifHierYCount = ny-1;
parentArea.r_xbot = A.r_xtop - xsep;
parentArea.r_ybot = A.r_ytop - ysep;
if (parentArea.r_ybot > B.r_ytop) parentArea.r_ybot = B.r_ytop;
parentArea.r_xtop = A.r_xtop;
parentArea.r_ytop = A.r_ytop;
SCALE(&parentArea, scale, &cifArea);
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
&cifArea, &CIFSolidBits, cifHierPaintArrayFunc,
(ClientData) NULL);
}
}
CIFHierRects += CIFTileOps - oldTileOps;
}
cifHierCleanup();
/* Restore the array bounds of the array */
use->cu_xhi = xhi;
use->cu_yhi = yhi;
return 2;
}
/*
* ----------------------------------------------------------------------------
*
* CIFGenArrays --
*
* This procedure computes all of the CIF that must be added to
* a given area of a parent to compensate for interactions between
* elements of arrays in that area.
*
* Results:
* None.
*
* Side effects:
* The parameter output is modified (by OR'ing) to hold all
* the CIF that was generated for array interactions.
*
* ----------------------------------------------------------------------------
*/
void
CIFGenArrays(def, area, output)
CellDef *def; /* Parent cell for which CIF is computed. */
Rect *area; /* All CIF in this area is interesting. */
Plane **output; /* Array of pointers to planes into which
* the CIF output will be OR'ed (real CIF
* only, temp layers won't appear). If
* output is NULL, then CIF is stored in
* CIFPlanes, and the planes are initially
* cleared.
*/
{
SearchContext scx;
int i, oldTileOps;
UndoDisable();
CIFInitCells();
/* Bill all tile operations here to hierarchical processing in
* addition to adding to the total.
*/
oldTileOps = CIFTileOps;
if (output == NULL)
{
output = CIFPlanes;
for (i=0; i<CIFCurStyle->cs_nLayers; i++)
{
if (output[i] == NULL)
output[i] = DBNewPlane((ClientData) TT_SPACE);
else DBClearPaintPlane(output[i]);
}
}
scx.scx_area = *area;
scx.scx_use = CIFDummyUse;
CIFDummyUse->cu_def = def;
(void) DBCellSrArea(&scx, cifHierArrayFunc, (ClientData) output);
CIFHierTileOps += CIFTileOps - oldTileOps;
UndoEnable();
}