1588 lines
46 KiB
C
1588 lines
46 KiB
C
/* 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 const 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 <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "tcltk/tclmagic.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 "graphics/graphics.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(void)
|
|
{
|
|
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(void)
|
|
{
|
|
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();
|
|
}
|
|
|
|
/* Structure used by cifFlatMaskHints, below */
|
|
|
|
typedef struct _maskHintsData
|
|
{
|
|
Transform *mh_trans;
|
|
CellDef *mh_def;
|
|
} MaskHintsData;
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cifMaskHints --
|
|
*
|
|
* Copy a mask hint into a target cell by adding it to the
|
|
* property list of the target cell. If the target cell already
|
|
* has the same mask hint key, then the mask hint value is
|
|
* appended to the property in the target cell def.
|
|
*
|
|
* Returns:
|
|
* 0 to keep the search going.
|
|
*
|
|
* Side effects:
|
|
* Modifies properties of the target cell def.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* DEPRECATED */
|
|
int
|
|
cifMaskHints(
|
|
char *name,
|
|
char *value,
|
|
CellDef *targetDef)
|
|
{
|
|
char *propvalue, *newval;
|
|
bool propfound;
|
|
|
|
if (!strncmp(name, "MASKHINTS_", 10))
|
|
{
|
|
/* Check if name exists already in the flattened cell */
|
|
propvalue = (char *)DBPropGet(targetDef, name, &propfound);
|
|
if (propfound)
|
|
{
|
|
/* Append value to the property */
|
|
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
|
|
sprintf(newval, "%s %s", propvalue, value);
|
|
}
|
|
else
|
|
newval = StrDup((char **)NULL, value);
|
|
|
|
DBPropPut(targetDef, name, newval);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cifFlatMaskHints --
|
|
*
|
|
* Copy a mask hint into a flattened cell by transforming it into the
|
|
* coordinate system of the flattened cell, and adding it to the
|
|
* property list of the flattened cell.
|
|
*
|
|
* Returns:
|
|
* 0 to keep the search going.
|
|
*
|
|
* Side effects:
|
|
* Modifies properties of the cell def passed in MaskHintsData.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cifFlatMaskHints(
|
|
char *name,
|
|
char *value,
|
|
MaskHintsData *mhd)
|
|
{
|
|
Rect r, newr;
|
|
char *vptr, *newval, *lastval, *propvalue;
|
|
bool propfound;
|
|
int lastlen, numvals;
|
|
|
|
if (!strncmp(name, "MASKHINTS_", 10))
|
|
{
|
|
newval = (char *)NULL;
|
|
vptr = value;
|
|
while (*vptr != '\0')
|
|
{
|
|
numvals = sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
|
|
&r.r_xtop, &r.r_ytop);
|
|
if (numvals == 4)
|
|
{
|
|
/* Transform rectangle to top level coordinates */
|
|
GeoTransRect(mhd->mh_trans, &r, &newr);
|
|
lastval = newval;
|
|
lastlen = (lastval) ? strlen(lastval) : 0;
|
|
newval = mallocMagic(40 + lastlen);
|
|
if (lastval)
|
|
strcpy(newval, lastval);
|
|
else
|
|
*newval = '\0';
|
|
sprintf(newval + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
|
|
newr.r_xbot, newr.r_ybot, newr.r_xtop, newr.r_ytop);
|
|
if (lastval) freeMagic(lastval);
|
|
|
|
/* Parse through the four values and check if there's more */
|
|
while (*vptr && isspace(*vptr)) vptr++;
|
|
while (*vptr && !isspace(*vptr)) vptr++;
|
|
while (*vptr && isspace(*vptr)) vptr++;
|
|
while (*vptr && !isspace(*vptr)) vptr++;
|
|
while (*vptr && isspace(*vptr)) vptr++;
|
|
while (*vptr && !isspace(*vptr)) vptr++;
|
|
while (*vptr && isspace(*vptr)) vptr++;
|
|
while (*vptr && !isspace(*vptr)) vptr++;
|
|
while (*vptr && isspace(*vptr)) vptr++;
|
|
}
|
|
else
|
|
{
|
|
TxError("MASKHINTS_%s: Expected 4 values, found only %d\n",
|
|
name + 10, numvals);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check if name exists already in the flattened cell */
|
|
propvalue = (char *)DBPropGet(mhd->mh_def, name, &propfound);
|
|
if (propfound)
|
|
{
|
|
/* Append newval to the property */
|
|
lastval = newval;
|
|
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2);
|
|
sprintf(newval, "%s %s", propvalue, lastval);
|
|
freeMagic(lastval);
|
|
}
|
|
DBPropPut(mhd->mh_def, name, newval);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* CIFCopyMaskHints --
|
|
*
|
|
* Callback function to copy mask hints from one cell into another.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May modify properties in the target cell.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
CIFCopyMaskHints(
|
|
SearchContext *scx,
|
|
CellDef *targetDef)
|
|
{
|
|
MaskHintsData mhd;
|
|
|
|
CellDef *sourceDef = scx->scx_use->cu_def;
|
|
mhd.mh_trans = &scx->scx_trans;
|
|
mhd.mh_def = targetDef;
|
|
|
|
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cifHierCopyMaskHints --
|
|
*
|
|
* Callback function to copy mask hints from a subcell into a flattened
|
|
* cell, which is passed in the clientData record.
|
|
*
|
|
* Results:
|
|
* Always returns 0 to keep the search alive.
|
|
*
|
|
* Side effects:
|
|
* May modify properties in the flattened cell.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cifHierCopyMaskHints(
|
|
SearchContext *scx,
|
|
ClientData clientData)
|
|
{
|
|
MaskHintsData mhd;
|
|
|
|
mhd.mh_trans = &scx->scx_trans;
|
|
mhd.mh_def = (CellDef *)clientData;
|
|
|
|
DBPropEnum(scx->scx_use->cu_def, cifFlatMaskHints, &mhd);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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 *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)
|
|
if (!(CIFCurStyle->cs_flags & CWF_SEE_NO_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(
|
|
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);
|
|
|
|
/* Flatten mask hints in the area of interest */
|
|
CIFCopyMaskHints(scx, CIFComponentDef);
|
|
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
|
|
(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, scx->scx_use->cu_def, &rootArea,
|
|
CIFComponentPlanes, &CIFCurStyle->cs_hierLayers, FALSE,
|
|
TRUE, TRUE, (ClientData)NULL);
|
|
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 *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 *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;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cifHierTempCheckFunc --
|
|
*
|
|
* This function is like cifHierCheckFunc() (see above), but is used
|
|
* for "templayers", where any parent/child disagreement should be
|
|
* considered a non-issue as far as output is concerned. Only the
|
|
* actual mask layer will report any problems.
|
|
*
|
|
* Results:
|
|
* Always returns 0 to keep the search alive.
|
|
*
|
|
* Side effects:
|
|
* Error messages may be output.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cifHierTempCheckFunc(
|
|
Tile *tile, /* Tile containing CIF. */
|
|
Plane *plane) /* Plane to check against and modify. */
|
|
{
|
|
Rect area;
|
|
|
|
TiToRect(tile, &area);
|
|
|
|
if (IsSplit(tile))
|
|
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFEraseTable,
|
|
(PaintUndoInfo *) NULL);
|
|
else
|
|
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 *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(
|
|
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;
|
|
if (CIFCurStyle->cs_layers[i]->cl_flags & CIF_TEMP)
|
|
(void) DBSrPaintArea((Tile *) NULL, CIFComponentPlanes[i],
|
|
&TiPlaneRect, &CIFSolidBits, cifHierTempCheckFunc,
|
|
(ClientData) CIFTotalPlanes[i]);
|
|
else
|
|
(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(
|
|
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;
|
|
int cuts, totcuts;
|
|
float pdone, plast;
|
|
|
|
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;
|
|
|
|
/* This routine can take a long time, so use the display
|
|
* timer to force a 5-second progress check (like is done
|
|
* with extract)
|
|
*/
|
|
GrDisplayStatus = DISPLAY_IN_PROGRESS;
|
|
SigSetTimer(5); /* Print at 5-second intervals */
|
|
cuts = 0;
|
|
pdone = 0.0;
|
|
plast = 0.0;
|
|
|
|
/* 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);
|
|
|
|
totcuts = (totalArea.r_ytop - totalArea.r_ybot + stepSize - 1)
|
|
/ stepSize;
|
|
totcuts *= ((totalArea.r_xtop - totalArea.r_xbot + stepSize - 1)
|
|
/ stepSize);
|
|
|
|
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) <= 0) 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);
|
|
/* Flatten mask hints in the area of interest */
|
|
CIFCopyMaskHints(&scx, CIFTotalDef);
|
|
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
|
(ClientData)CIFTotalDef);
|
|
|
|
CIFErrorDef = def;
|
|
CIFGen(CIFTotalDef, def, &interaction, CIFTotalPlanes,
|
|
&CIFCurStyle->cs_hierLayers, TRUE, TRUE, TRUE,
|
|
(ClientData)NULL);
|
|
|
|
/* 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, def, &interaction, CIFComponentPlanes,
|
|
&CIFCurStyle->cs_hierLayers, FALSE, TRUE, TRUE,
|
|
(ClientData)NULL);
|
|
|
|
/* 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();
|
|
|
|
cuts++;
|
|
pdone = 100.0 * ((float)cuts / (float)totcuts);
|
|
if ((((pdone - plast) > 1.0) || (cuts == totcuts)) && (cuts > 1))
|
|
{
|
|
/* Only print something if the 5-second timer has expired */
|
|
if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
|
|
{
|
|
TxPrintf("Completed %d%%\n", (int)(pdone + 0.5));
|
|
plast = pdone;
|
|
TxFlushOut();
|
|
|
|
GrDisplayStatus = DISPLAY_IN_PROGRESS;
|
|
SigSetTimer(5);
|
|
}
|
|
#ifdef MAGIC_WRAPPER
|
|
/* We need to let Tk paint the console display */
|
|
while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
CIFHierTileOps += CIFTileOps - oldTileOps;
|
|
|
|
GrDisplayStatus = DISPLAY_IDLE;
|
|
SigRemoveTimer();
|
|
|
|
UndoEnable();
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cifHierElementFuncLow(
|
|
CellUse *use, /* CellUse being array-checked. */
|
|
Transform *transform, /* Transform from this instance to
|
|
* the parent.
|
|
*/
|
|
int x,
|
|
int y, /* Indices of this instance. */
|
|
Rect *checkArea) /* Area (in parent coords) to be
|
|
* CIF-generated.
|
|
*/
|
|
{
|
|
if (((x - use->cu_xlo) < 2) && ((y - use->cu_ylo) < 2))
|
|
return cifHierElementFunc(use, transform, x, y, checkArea);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cifHierElementFuncHigh(
|
|
CellUse *use, /* CellUse being array-checked. */
|
|
Transform *transform, /* Transform from this instance to
|
|
* the parent.
|
|
*/
|
|
int x,
|
|
int y, /* Indices of this instance. */
|
|
Rect *checkArea) /* Area (in parent coords) to be
|
|
* CIF-generated.
|
|
*/
|
|
{
|
|
if (((use->cu_xhi - x) < 2) && ((use->cu_yhi - y) < 2))
|
|
return cifHierElementFunc(use, transform, x, y, checkArea);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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(
|
|
CellUse *use, /* CellUse being array-checked. */
|
|
Transform *transform, /* Transform from this instance to
|
|
* the parent.
|
|
*/
|
|
int x,
|
|
int 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);
|
|
CIFCopyMaskHints(&scx, CIFTotalDef);
|
|
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
|
(ClientData)CIFTotalDef);
|
|
|
|
DBCellClearDef(CIFComponentDef);
|
|
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
|
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
|
(ClientData)CIFComponentDef);
|
|
|
|
CIFErrorDef = (CellDef *) NULL;
|
|
CIFGen(CIFComponentDef, use->cu_def, checkArea, CIFComponentPlanes,
|
|
&CIFCurStyle->cs_hierLayers, FALSE, TRUE, TRUE,
|
|
(ClientData)NULL);
|
|
|
|
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 *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)
|
|
{
|
|
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(
|
|
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;
|
|
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 only */
|
|
/* look at the bottom-left 2x2 set when calculating A and B, and */
|
|
/* only look at the top-right 2x2 set when calculating C and D. */
|
|
|
|
/* 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.
|
|
*
|
|
* (Updated 6/7/2021) A and B should be calculated and processed
|
|
* completely independently of C and D, or else if the array is
|
|
* small and the radius is large, then results from one will get
|
|
* picked up when making copies of the other, resulting in things
|
|
* getting painted out-of-bounds.
|
|
*/
|
|
|
|
/* 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, cifHierElementFuncLow,
|
|
(ClientData) &A);
|
|
CIFErrorDef = use->cu_parent;
|
|
CIFGen(CIFTotalDef, use->cu_def, &A, CIFTotalPlanes,
|
|
&CIFCurStyle->cs_hierLayers, FALSE, TRUE, TRUE,
|
|
(ClientData)NULL);
|
|
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, cifHierElementFuncLow,
|
|
(ClientData) &B);
|
|
CIFErrorDef = use->cu_parent;
|
|
CIFGen(CIFTotalDef, use->cu_def, &B, CIFTotalPlanes,
|
|
&CIFCurStyle->cs_hierLayers, FALSE, TRUE, TRUE,
|
|
(ClientData)NULL);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 core of the array (copied from A and B). Copy area
|
|
* from A, but not to exceed 1/2 Y array separation, into the
|
|
* inside area of the array. If the expanded area is > 1/2
|
|
* the array separation, then there is no need to copy from
|
|
* area B. Otherwise, copy area from B, extending up to
|
|
* the bottom of the area just copied, and not to exceed
|
|
* 1/2 the X array separation.
|
|
*/
|
|
|
|
cifHierXSpacing = xsep * scale;
|
|
cifHierYSpacing = ysep * scale;
|
|
cifHierXCount = nx-1;
|
|
cifHierYCount = ny-1;
|
|
|
|
/* Find top edge of cell */
|
|
A.r_xbot = use->cu_bbox.r_xbot;
|
|
A.r_xtop = use->cu_bbox.r_xbot + xsep;
|
|
A.r_ybot = use->cu_bbox.r_ybot + ysep;
|
|
A.r_ytop = use->cu_bbox.r_ybot + ysize;
|
|
/* Expand up/down but not by more than 1/2 ysep */
|
|
if ((2 * radius) > ysep)
|
|
{
|
|
A.r_ybot -= (ysep >> 1);
|
|
A.r_ytop += (ysep >> 1);
|
|
}
|
|
else
|
|
{
|
|
A.r_ybot -= radius;
|
|
A.r_ytop += radius;
|
|
}
|
|
SCALE(&A, scale, &cifArea);
|
|
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
|
|
&cifArea, &CIFSolidBits, cifHierPaintArrayFunc,
|
|
(ClientData) NULL);
|
|
|
|
/* If the radius is more than half of ysep then there */
|
|
/* is nothing left that needs to be copied. */
|
|
|
|
if ((2 * radius) < ysep)
|
|
{
|
|
/* Find right edge of cell */
|
|
B.r_ybot = use->cu_bbox.r_ybot;
|
|
B.r_ytop = use->cu_bbox.r_ybot + ysep;
|
|
|
|
if (B.r_ytop > A.r_ybot) B.r_ytop = A.r_ybot;
|
|
|
|
B.r_xbot = use->cu_bbox.r_xbot + xsep;
|
|
B.r_xtop = use->cu_bbox.r_xbot + xsize;
|
|
/* Expand left/right but not by more than 1/2 xsep */
|
|
if ((2 * radius) > xsep)
|
|
{
|
|
B.r_xbot -= (xsep >> 1);
|
|
B.r_xtop += (xsep >> 1);
|
|
}
|
|
else
|
|
{
|
|
B.r_xbot -= radius;
|
|
B.r_xtop += radius;
|
|
}
|
|
SCALE(&B, scale, &cifArea);
|
|
(void) DBSrPaintArea((Tile *) NULL, CIFTotalPlanes[i],
|
|
&cifArea, &CIFSolidBits, cifHierPaintArrayFunc,
|
|
(ClientData) NULL);
|
|
}
|
|
}
|
|
}
|
|
CIFHierRects += CIFTileOps - oldTileOps;
|
|
}
|
|
|
|
/* Clean up from areas A and B */
|
|
cifHierCleanup();
|
|
anyInteractions = FALSE;
|
|
|
|
/* Now do areas C and D */
|
|
|
|
/* 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, cifHierElementFuncHigh,
|
|
(ClientData) &C);
|
|
CIFErrorDef = use->cu_parent;
|
|
CIFGen(CIFTotalDef, use->cu_def, &C, CIFTotalPlanes,
|
|
&CIFCurStyle->cs_hierLayers, FALSE, TRUE, TRUE,
|
|
(ClientData)NULL);
|
|
anyInteractions = TRUE;
|
|
}
|
|
|
|
if ((xsep < xsize + radius) && (ysep < ysize + radius))
|
|
{
|
|
/* 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, cifHierElementFuncHigh,
|
|
(ClientData) &D);
|
|
CIFErrorDef = use->cu_parent;
|
|
CIFGen(CIFTotalDef, use->cu_def, &D, CIFTotalPlanes,
|
|
&CIFCurStyle->cs_hierLayers, FALSE, TRUE, TRUE,
|
|
(ClientData)NULL);
|
|
}
|
|
|
|
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 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 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);
|
|
}
|
|
}
|
|
CIFHierRects += CIFTileOps - oldTileOps;
|
|
}
|
|
|
|
cifHierCleanup();
|
|
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(
|
|
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();
|
|
}
|