/* CIFgen.c - * * This file provides routines that generate CIF from Magic * tile information, using one of the styles read from the * technology file. * * ********************************************************************* * * 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[] = "$Header: /ufs/repository/magic/cif/CIFgen.c,v 1.3 2001/03/29 19:50:03 tim Exp $"; #endif #include #include "misc/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "cif/CIFint.h" /* The following global arrays hold pointers to the CIF planes * generated by the procedures in this module. There are two * kinds of planes: real CIF, which will ostensibly be output, * and temporary layers used to build up more complex geometric * functions. */ global Plane *CIFPlanes[MAXCIFLAYERS]; /* The following are paint tables used by the routines that implement * the geometric operations on mask layers, such as AND, OR, GROW, * etc. There are really only two tables. The first will paint * CIF_SOLIDTYPE over anything else, and the second will paint * space over anything else. These tables are used on planes with * only two tile types, TT_SPACE and CIF_SOLIDTYPE, so they only * have two entries each. */ PaintResultType CIFPaintTable[] = {CIF_SOLIDTYPE, CIF_SOLIDTYPE}; PaintResultType CIFEraseTable[] = {TT_SPACE, TT_SPACE}; /* The following local variables are used as a convenience to pass * information between CIFGen and the various search functions. */ static int growDistance; /* Distance to grow stuff. */ static Plane *cifPlane; /* Plane acted on by search functions. */ static int cifScale; /* Scale factor to use on tiles. */ /* * ---------------------------------------------------------------------------- * * cifPaintFunc -- * * This search function is called during CIF_AND and CIF_OR * and CIF_ANDNOT operations for each relevant tile. * * Results: * Always returns 0 to keep the search alive. * * Side effects: * For the area of the tile, either paints or erases in * cifNewPlane, depending on the paint table passed as parameter. * The tile's area is scaled by cifScale first. * ---------------------------------------------------------------------------- */ int cifPaintFunc(tile, table) Tile *tile; PaintResultType *table; /* Used for painting. */ { Rect area; TiToRect(tile, &area); area.r_xbot *= cifScale; area.r_xtop *= cifScale; area.r_ybot *= cifScale; area.r_ytop *= cifScale; #ifdef NONMANHATTAN DBNMPaintPlane(cifPlane, TiGetTypeExact(tile), &area, table, (PaintUndoInfo *) NULL); #else DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL); #endif CIFTileOps += 1; return 0; } /* * ---------------------------------------------------------------------------- * * cifGrowFunc -- * * Called for each relevant tile during grow or shrink operations. * For growing, these are solid tiles. For shrinking, these are * space tiles. * * Results: * Always returns 0 to keep the search alive. * * Side effects: * Scales the tile by cifScale, then expands its area by the * distance in the current CIFOp, then paints this area into * cifNewPlane using the table passed as parameter. * ---------------------------------------------------------------------------- */ int cifGrowFunc(tile, table) Tile *tile; PaintResultType *table; /* Table to be used for painting. */ { Rect area; TileType oldType = TiGetTypeExact(tile); TiToRect(tile, &area); /* In scaling the tile, watch out for infinities!! If something * is already infinity, don't change it. */ if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot *= cifScale; if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot *= cifScale; if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop *= cifScale; if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop *= cifScale; #ifdef NONMANHATTAN /* Grow on diagonal tiles: grow rectangular tiles around the */ /* straight edges of the right-triangle, then copy the diagonal */ /* tile (at its original size) in the direction of the diagonal. */ /* Note: A diagonal tile, by definition, can't have infinities. */ if (oldType & TT_DIAGONAL) { Rect rtmp; /* Grow top and bottom */ rtmp.r_ybot = area.r_ybot - growDistance; rtmp.r_ytop = area.r_ytop + growDistance; /* Grow around left or right edge */ if (oldType & TT_SIDE) { rtmp.r_xbot = area.r_xtop - growDistance; rtmp.r_xtop = area.r_xtop + growDistance; } else { rtmp.r_xbot = area.r_xbot - growDistance; rtmp.r_xtop = area.r_xbot + growDistance; } DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL); /* Now do the same for the other edge. */ rtmp.r_xbot = area.r_xbot - growDistance; rtmp.r_xtop = area.r_xtop + growDistance; if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */ { rtmp.r_ybot = area.r_ytop - growDistance; rtmp.r_ytop = area.r_ytop + growDistance; } else /* bottom */ { rtmp.r_ybot = area.r_ybot - growDistance; rtmp.r_ytop = area.r_ybot + growDistance; } DBPaintPlane(cifPlane, &rtmp, table, (PaintUndoInfo *) NULL); /* Finally, Move and replace the diagonal tile */ if (oldType & TT_SIDE) { rtmp.r_xtop = area.r_xtop - growDistance; rtmp.r_xbot = area.r_xbot - growDistance; } else { rtmp.r_xtop = area.r_xtop + growDistance; rtmp.r_xbot = area.r_xbot + growDistance; } if (((oldType & TT_SIDE) >> 1) == (oldType & TT_DIRECTION)) /* top */ { rtmp.r_ytop = area.r_ytop - growDistance; rtmp.r_ybot = area.r_ybot - growDistance; } else /* bottom */ { rtmp.r_ytop = area.r_ytop + growDistance; rtmp.r_ybot = area.r_ybot + growDistance; } DBNMPaintPlane(cifPlane, oldType, &rtmp, table, (PaintUndoInfo *) NULL); } else { #endif /* In scaling the tile, watch out for infinities!! If something * is already infinity, don't change it. */ if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot -= growDistance; if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot -= growDistance; if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop += growDistance; if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop += growDistance; DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL); #ifdef NONMANHATTAN } #endif CIFTileOps += 1; return 0; } /* * ---------------------------------------------------------------------------- * * cifBloatFunc -- * * Called once for each tile to be selectively bloated. * * Results: * Always returns 0 to keep the search alive. * * Side effects: * Uses the bloat table in the current CIFOp to expand the * tile depending on which tiles it abuts, then paints the * expanded area into the new CIF plane. The bloat table * contains one entry for each tile type. When that tile * type is seen next to the current tile, the area of the current * tile is bloated by the table value in that location. The * only exception to this rule is that internal edges (between * two tiles of the same type) cause no bloating. * Note: the original tile is scaled into CIF coordinates. * ---------------------------------------------------------------------------- */ int cifBloatFunc(tile, bloatTable) Tile *tile; int *bloatTable; /* Table of bloat values, indexed by * tile type. */ { Rect tileArea, cifArea, bloat; TileType type, topLeftType, bottomRightType; Tile *t; type = TiGetType(tile); TiToRect(tile, &tileArea); /* Output the original area of the tile. */ cifArea = tileArea; cifArea.r_xbot *= cifScale; cifArea.r_xtop *= cifScale; cifArea.r_ybot *= cifScale; cifArea.r_ytop *= cifScale; #ifdef NONMANHATTAN DBNMPaintPlane(cifPlane, TiGetTypeExact(tile), &cifArea, CIFPaintTable, (PaintUndoInfo *) NULL); #else DBPaintPlane(cifPlane, &cifArea, CIFPaintTable, (PaintUndoInfo *) NULL); #endif /* Go around the tile, scanning the neighbors along each side. * Start with the left side, and output the bloats along that * side, if any. */ bloat.r_ybot = cifArea.r_ybot - bloatTable[TiGetType(LB(tile))]; bloat.r_xtop = cifArea.r_xbot; for (t = BL(tile); BOTTOM(t) < TOP(tile); t = RT(t)) { topLeftType = TiGetType(t); bloat.r_xbot = bloat.r_xtop - bloatTable[topLeftType]; if (TOP(t) > tileArea.r_ytop) bloat.r_ytop = cifArea.r_ytop; else bloat.r_ytop = cifScale * TOP(t); if ((bloatTable[topLeftType] != 0) && (topLeftType != type)) #ifdef NONMANHATTAN DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #else DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #endif bloat.r_ybot = bloat.r_ytop; } /* Now do the top side. Use the type of the top-left tile to * side-extend the left end of the top bloat in order to match * things up at the corner. */ bloat.r_ybot = cifArea.r_ytop; bloat.r_xtop = cifArea.r_xtop; for (t = RT(tile); RIGHT(t) > LEFT(tile); t = BL(t)) { TileType otherType = TiGetType(t); bloat.r_ytop = bloat.r_ybot + bloatTable[TiGetType(t)]; if (LEFT(t) <= tileArea.r_xbot) bloat.r_xbot = cifArea.r_xbot - bloatTable[topLeftType]; else bloat.r_xbot = cifScale * LEFT(t); if ((bloatTable[otherType] != 0) && (otherType != type)) #ifdef NONMANHATTAN DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #else DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #endif bloat.r_xtop = bloat.r_xbot; } /* Now do the right side. */ bloat.r_ytop = cifArea.r_ytop + bloatTable[TiGetType(RT(tile))]; bloat.r_xbot = cifArea.r_xtop; for (t = TR(tile); TOP(t) > BOTTOM(tile); t = LB(t)) { bottomRightType = TiGetType(t); bloat.r_xtop = bloat.r_xbot + bloatTable[bottomRightType]; if (BOTTOM(t) < tileArea.r_ybot) bloat.r_ybot = cifArea.r_ybot; else bloat.r_ybot = cifScale * BOTTOM(t); if ((bloatTable[bottomRightType] != 0) && (bottomRightType != type)) #ifdef NONMANHATTAN DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #else DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #endif bloat.r_ytop = bloat.r_ybot; } /* Now do the bottom side. Use the type of the bottom-right tile * to side-extend the right end of the bottom bloat in order to match * things up at the corner. */ bloat.r_ytop = cifArea.r_ybot; bloat.r_xbot = cifArea.r_xbot; for (t = LB(tile); LEFT(t) < RIGHT(tile); t = TR(t)) { TileType otherType = TiGetType(t); bloat.r_ybot = bloat.r_ytop - bloatTable[otherType]; if (RIGHT(t) >= tileArea.r_xtop) bloat.r_xtop = cifArea.r_xtop + bloatTable[bottomRightType]; else bloat.r_xtop = cifScale * RIGHT(t); if ((bloatTable[otherType] != 0) && (otherType != type)) #ifdef NONMANHATTAN DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #else DBPaintPlane(cifPlane, &bloat, CIFPaintTable, (PaintUndoInfo *) NULL); #endif bloat.r_xbot = bloat.r_xtop; } CIFTileOps += 1; return 0; } /* * ---------------------------------------------------------------------------- * * cifBloatMaxFunc -- * * Called once for each tile to be selectively bloated or * shrunk using the CIFOP_BLOATMAX or CIFOP_BLOATMIN operation. * * Results: * Always returns 0 to keep the search alive. * * Side effects: * Uses the bloat table in the current CIFOp to expand or shrink * the tile, depending on which tiles it abuts. The rectangular * area of the tile is modified by moving each side in or out * by the maximum bloat distance for any of its neighbors on * that side. The result is a new rectangle, which is OR'ed * into the result plane. Note: any edge between two tiles of * same type is given a zero bloat factor. * * ---------------------------------------------------------------------------- */ int cifBloatMaxFunc(tile, op) Tile *tile; /* The tile to be processed. */ CIFOp *op; /* Describes the operation to be performed * (all we care about is the opcode and * bloat table). */ { Rect area; int bloat, tmp; Tile *t; TileType type, otherType; /* Get the tile into CIF coordinates. */ type = TiGetType(tile); TiToRect(tile, &area); area.r_xbot *= cifScale; area.r_ybot *= cifScale; area.r_xtop *= cifScale; area.r_ytop *= cifScale; /* See how much to adjust the left side of the tile. */ if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000; else bloat = 10000000; for (t = BL(tile); BOTTOM(t) < TOP(tile); t = RT(t)) { otherType = TiGetType(t); if (otherType == type) continue; tmp = op->co_bloats[otherType]; if (op->co_opcode == CIFOP_BLOATMAX) { if (tmp > bloat) bloat = tmp; } else if (tmp < bloat) bloat = tmp; } if ((bloat < 10000000) && (bloat > -10000000)) area.r_xbot -= bloat; /* Now figure out how much to adjust the top side of the tile. */ if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000; else bloat = 10000000; for (t = RT(tile); RIGHT(t) > LEFT(tile); t = BL(t)) { otherType = TiGetType(t); if (otherType == type) continue; tmp = op->co_bloats[otherType]; if (op->co_opcode == CIFOP_BLOATMAX) { if (tmp > bloat) bloat = tmp; } else if (tmp < bloat) bloat = tmp; } if ((bloat < 10000000) && (bloat > -10000000)) area.r_ytop += bloat; /* Now the right side. */ if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000; else bloat = 10000000; for (t = TR(tile); TOP(t) > BOTTOM(tile); t = LB(t)) { otherType = TiGetType(t); if (otherType == type) continue; tmp = op->co_bloats[otherType]; if (op->co_opcode == CIFOP_BLOATMAX) { if (tmp > bloat) bloat = tmp; } else if (tmp < bloat) bloat = tmp; } if ((bloat < 10000000) && (bloat > -10000000)) area.r_xtop += bloat; /* Lastly, do the bottom side. */ if (op->co_opcode == CIFOP_BLOATMAX) bloat = -10000000; else bloat = 10000000; for (t = LB(tile); LEFT(t) < RIGHT(tile); t = TR(t)) { otherType = TiGetType(t); if (otherType == type) continue; tmp = op->co_bloats[otherType]; if (op->co_opcode == CIFOP_BLOATMAX) { if (tmp > bloat) bloat = tmp; } else if (tmp < bloat) bloat = tmp; } if ((bloat < 10000000) && (bloat > -10000000)) area.r_ybot -= bloat; /* Make sure the tile didn't shrink into negativity. If it's * ok, paint it into the new plane being built. */ if ((area.r_xbot > area.r_xtop) || (area.r_ybot > area.r_ytop)) { TiToRect(tile, &area); area.r_xbot *= cifScale; area.r_xtop *= cifScale; area.r_ybot *= cifScale; area.r_ytop *= cifScale; CIFError(&area, "tile inverted by shrink"); } else #ifdef NONMANHATTAN DBNMPaintPlane(cifPlane, TiGetTypeExact(tile), &area, CIFPaintTable, (PaintUndoInfo *) NULL); #else DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL); #endif CIFTileOps += 1; return 0; } /* * ---------------------------------------------------------------------------- * * cifSquareFunc -- * * Called for each relevant tile when chopping areas up into squares. * Chops each tile up into squares and paints into cifPlane. * * Results: * None. * * Side effects: * Stuff is painted into cifPlane. * * ---------------------------------------------------------------------------- */ int cifSquareFunc(tile, op) Tile *tile; /* Tile to be diced up. */ CIFOp *op; /* Describes how to generate squares. */ { Rect area, square; int i, nAcross, j, nUp, left; #ifdef NONMANHATTAN /* For now, don't allow squares on non-manhattan tiles */ if (IsSplit(tile)) return 0; #endif TiToRect(tile, &area); /* Compute the real border to leave around the sides. If only * one square will fit in a particular direction, center it * regardless of the requested border size. If more than one * square will fit, then fit it in extras only if at least the * requested border size can be left. Also center things in the * rectangle, so that the box's exact size doesn't matter. This * trickiness is done so that (a) coincident contacts from overlapping * cells always have their squares line up, regardless of the * orientation of the cells, and (b) we can generate contact vias * for non-square contact areas, for example poly-metal contacts * in the MOSIS CMOS process. */ nAcross = (area.r_xtop - area.r_xbot + op->co_bloats[2] - (2*op->co_bloats[0])) / (op->co_bloats[1] + op->co_bloats[2]); if (nAcross == 0) { left = (area.r_xbot + area.r_xtop - op->co_bloats[1])/2; if (left >= area.r_xbot) nAcross = 1; } else { left = (area.r_xbot + area.r_xtop + op->co_bloats[2] - (nAcross * (op->co_bloats[1] + op->co_bloats[2])))/2; } nUp= (area.r_ytop - area.r_ybot + op->co_bloats[2] - (2*op->co_bloats[0])) / (op->co_bloats[1] + op->co_bloats[2]); if (nUp == 0) { square.r_ybot = (area.r_ybot + area.r_ytop - op->co_bloats[1])/2; if (square.r_ybot >= area.r_ybot) nUp = 1; } else { square.r_ybot = (area.r_ybot + area.r_ytop + op->co_bloats[2] - (nUp * (op->co_bloats[1] + op->co_bloats[2])))/2; } for (i = 0; i < nUp; i += 1) { square.r_ytop = square.r_ybot + op->co_bloats[1]; square.r_xbot = left; for (j = 0; j < nAcross; j += 1) { square.r_xtop = square.r_xbot + op->co_bloats[1]; DBPaintPlane(cifPlane, &square, CIFPaintTable, (PaintUndoInfo *) NULL); CIFTileOps += 1; square.r_xbot += op->co_bloats[2] + op->co_bloats[1]; } square.r_ybot += op->co_bloats[2] + op->co_bloats[1]; } return 0; } /* * ---------------------------------------------------------------------------- * * cifSquareGridFunc -- * * Called for each relevant tile when chopping areas up into squares. * Chops each tile up into squares and paints into cifPlane. The * generated squares are on the grid (this code comes from UNC). * * Results: * None. * * Side effects: * Stuff is painted into cifPlane. * * ---------------------------------------------------------------------------- */ int cifSquareGridFunc(tile, op) Tile *tile; /* Tile to be diced up. */ CIFOp *op; /* Describes how to generate squares. */ { Rect area, square; int i, nAcross, j, nUp, left; int nUpHalf,nAcrossHalf,AcrossSpacer,UpSpacer; int new_left; int bottom; char Across_is_odd,Up_is_odd; int grid; #ifdef NONMANHATTAN /* For now, don't allow squares on non-manhattan tiles */ if (IsSplit(tile)) return 0; #endif TiToRect(tile, &area); /* Compute the real border to leave around the sides. If only * one square will fit in a particular direction, center it * regardless of the requested border size. If more than one * square will fit, then fit it in extras only if at least the * requested border size can be left. Also center things in the * rectangle, so that the box's exact size doesn't matter. This * trickiness is done so that (a) coincident contacts from overlapping * cells always have their squares line up, regardless of the * orientation of the cells, and (b) we can generate contact vias * for non-square contact areas, for example poly-metal contacts * in the MOSIS CMOS process. */ /* contacts may need to be generated on a grid. This routine, in its original incarnation did not handle this for cases where the lambda was not some integral multiple of (2*grid). The mods made here are meant to remedy these problems. New problems are introduced by these mods. In particular, some odd sized contacts will not be able to generate a centered contact structure. This will happen in the case where nAcross is odd and the width of the contact area is not an integral multiple of (2*grid). Similarly, the problem will occur if nUp is odd and the height of the contact area is not an integral multiple of (2*grid). The following assumptions have been made: 1. Lambda IS some integral multiple of the desired grid. 2. All bloats/shrinks to the contact areas are an integral multiple of the grid. 3. The contact size is an integral multiple of 2*grid 4. The spacing is an integral multiple of 2*grid. */ grid = op->co_bloats[3]; nAcross = (area.r_xtop - area.r_xbot + op->co_bloats[2] - (2*op->co_bloats[0])) / (op->co_bloats[1] + op->co_bloats[2]); if (nAcross == 0) { left = (area.r_xbot + area.r_xtop - op->co_bloats[1])/2; if (left >= area.r_xbot) nAcross = 1; } else { left = (area.r_xbot + area.r_xtop + op->co_bloats[2] - (nAcross * (op->co_bloats[1] + op->co_bloats[2])))/2; } AcrossSpacer = 0; nAcrossHalf = (nAcross/2) - 1; Across_is_odd = nAcross&1; /* align the left side to the grid */ new_left = left/grid; new_left = new_left*grid; if(new_left != left){ left = new_left; if(!Across_is_odd) AcrossSpacer = grid; } nUp= (area.r_ytop - area.r_ybot + op->co_bloats[2] - (2*op->co_bloats[0])) / (op->co_bloats[1] + op->co_bloats[2]); if (nUp == 0) { square.r_ybot = (area.r_ybot + area.r_ytop - op->co_bloats[1])/2; if (square.r_ybot >= area.r_ybot) nUp = 1; } else { square.r_ybot = (area.r_ybot + area.r_ytop + op->co_bloats[2] - (nUp * (op->co_bloats[1] + op->co_bloats[2])))/2; } UpSpacer = 0; nUpHalf = (nUp/2) - 1; Up_is_odd = nUp&1; /* align the bottom to the grid */ bottom = square.r_ybot/grid; bottom = bottom * grid; if(bottom != square.r_ybot){ square.r_ybot = bottom; if(!Up_is_odd) UpSpacer = grid; } for (i = 0; i < nUp; i += 1) { square.r_ytop = square.r_ybot + op->co_bloats[1]; square.r_xbot = left; for (j = 0; j < nAcross; j += 1) { square.r_xtop = square.r_xbot + op->co_bloats[1]; DBPaintPlane(cifPlane, &square, CIFPaintTable, (PaintUndoInfo *) NULL); CIFTileOps += 1; square.r_xbot += op->co_bloats[2] + op->co_bloats[1]; if(j == nAcrossHalf) square.r_xbot += AcrossSpacer; } square.r_ybot += op->co_bloats[2] + op->co_bloats[1]; if(i == nUpHalf && !Up_is_odd) square.r_ybot += UpSpacer; } return 0; } /* * ---------------------------------------------------------------------------- * * cifSrTiles -- * * This is a utility procedure that just calls DBSrPaintArea * one or more times for the planes being used in processing * one CIFOp. * * Results: * None. * * Side effects: * This procedure itself has no side effects. For each of the * paint or temporary planes indicated in cifOp, we call * DBSrPaintArea to find the desired tiles in the desired * area for the operation. DBSrPaintArea is given func as a * search function, and cdArg as ClientData. * * ---------------------------------------------------------------------------- */ void cifSrTiles(cifOp, area, cellDef, temps, func, cdArg) CIFOp *cifOp; /* Geometric operation being processed. */ Rect *area; /* Area of Magic paint to consider. */ CellDef *cellDef; /* CellDef to search for paint. */ Plane *temps[]; /* Planes to use for temporaries. */ int (*func)(); /* Search function to pass to DBSrPaintArea. */ ClientData cdArg; /* Client data for func. */ { TileTypeBitMask maskBits; TileType t; int i; /* When reading data from a cell, it must first be scaled to * CIF units. */ cifScale = CIFCurStyle->cs_scaleFactor; for (i = PL_DRC_CHECK; i < DBNumPlanes; i++) { maskBits = DBPlaneTypes[i]; TTMaskAndMask(&maskBits, &cifOp->co_paintMask); if (!TTMaskEqual(&maskBits, &DBZeroTypeBits)) (void) DBSrPaintArea((Tile *) NULL, cellDef->cd_planes[i], area, &cifOp->co_paintMask, func, cdArg); } /* When processing CIF data, use everything in the plane. */ cifScale = 1; for (t = 0; t < TT_MAXTYPES; t++, temps++) if (TTMaskHasType(&cifOp->co_cifMask, t)) (void) DBSrPaintArea((Tile *) NULL, *temps, &TiPlaneRect, &CIFSolidBits, func, (ClientData) cdArg); } /* * ---------------------------------------------------------------------------- * * CIFGenLayer -- * * This routine will generate one CIF layer. * It provides the core of the CIF generator. * * Results: * Returns a malloc'ed plane with tiles of type CIF_SOLIDTYPE * marking the area of this CIF layer as built up by op. * * Side effects: * None, except to create a new plane holding the CIF for the layer. * The CIF that's generated may fall outside of area... it's what * results from considering everything in area. In most cases the * caller will clip the results down to the desired area. * * ---------------------------------------------------------------------------- */ Plane * CIFGenLayer(op, area, cellDef, temps) CIFOp *op; /* List of CIFOps telling how to make layer. */ Rect *area; /* Area to consider when generating CIF. Only * material in this area will be considered, so * the caller should usually expand his desired * area by one CIF radius. */ CellDef *cellDef; /* CellDef to search when paint layers are * needed for operation. */ Plane *temps[]; /* Temporary layers to be used when needed * for operation. */ { Plane *temp; static Plane *nextPlane, *curPlane; /* Set up temporary planes used during computation. One of these * will be returned as the result (whichever is curPlane at the * end of the computation). The other is saved for later use. */ if (nextPlane == NULL) nextPlane = DBNewPlane((ClientData) TT_SPACE); curPlane = DBNewPlane((ClientData) TT_SPACE); /* Go through the geometric operations and process them one * at a time. */ for ( ; op != NULL; op = op->co_next) { switch (op->co_opcode) { /* For AND, first collect all the stuff to be anded with * plane in a temporary plane. Then find all the places * where there isn't any stuff, and erase from the * current plane. */ case CIFOP_AND: DBClearPaintPlane(nextPlane); cifPlane = nextPlane; cifSrTiles(op, area, cellDef, temps, cifPaintFunc, (ClientData) CIFPaintTable); cifPlane = curPlane; cifScale = 1; (void) DBSrPaintArea((Tile *) NULL, nextPlane, &TiPlaneRect, &DBSpaceBits, cifPaintFunc, (ClientData) CIFEraseTable); break; /* For OR, just use cifPaintFunc to OR the areas of all * relevant tiles into plane. */ case CIFOP_OR: cifPlane = curPlane; cifSrTiles(op, area, cellDef, temps, cifPaintFunc, (ClientData) CIFPaintTable); break; /* For ANDNOT, do exactly the same thing as OR, except erase * instead of paint. */ case CIFOP_ANDNOT: cifPlane = curPlane; cifSrTiles(op, area, cellDef, temps, cifPaintFunc, (ClientData) CIFEraseTable); break; /* For GROW, just find all solid tiles in the current plane, * and paint a larger version into a new plane. The switch * the current and new planes. */ case CIFOP_GROW: growDistance = op->co_distance; DBClearPaintPlane(nextPlane); cifPlane = nextPlane; cifScale = 1; (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect, &CIFSolidBits, cifGrowFunc, (ClientData) CIFPaintTable); temp = curPlane; curPlane = nextPlane; nextPlane = temp; break; /* SHRINK is just like grow except work from the space tiles. */ case CIFOP_SHRINK: growDistance = op->co_distance; DBClearPaintPlane(nextPlane); DBPaintPlane(nextPlane, &TiPlaneRect, CIFPaintTable, (PaintUndoInfo *) NULL); cifPlane = nextPlane; cifScale = 1; (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect, &DBSpaceBits, cifGrowFunc, (ClientData) CIFEraseTable); temp = curPlane; curPlane = nextPlane; nextPlane = temp; break; case CIFOP_BLOAT: cifPlane = curPlane; cifSrTiles(op, area, cellDef, temps, cifBloatFunc, (ClientData) op->co_bloats); break; case CIFOP_BLOATMAX: case CIFOP_BLOATMIN: cifPlane = curPlane; cifSrTiles(op, area, cellDef, temps, cifBloatMaxFunc, (ClientData) op); break; case CIFOP_SQUARES: DBClearPaintPlane(nextPlane); cifPlane = nextPlane; (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect, &CIFSolidBits, cifSquareFunc, (ClientData) op); temp = curPlane; curPlane = nextPlane; nextPlane = temp; break; case CIFOP_SQUARES_G: DBClearPaintPlane(nextPlane); cifPlane = nextPlane; (void) DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect, &CIFSolidBits, cifSquareGridFunc, (ClientData) op); temp = curPlane; curPlane = nextPlane; nextPlane = temp; break; default: continue; } } return curPlane; } /* * ---------------------------------------------------------------------------- * * CIFGen -- * * This procedure generates a complete set of CIF layers for * a particular area of a particular cell. NOTE: if the argument * genAllPlanes is FALSE, only planes for those layers having * a bit set in 'layers' are generated; the others are set * to NULL. * * Results: * None. * * Side effects: * The parameters realPlanes and tempPlanes are modified * to hold the CIF and temporary layers for area of cellDef, * as determined by the current CIF generation rules. * * ---------------------------------------------------------------------------- */ void CIFGen(cellDef, area, planes, layers, replace, genAllPlanes) CellDef *cellDef; /* Cell for which CIF is to be generated. */ Rect *area; /* Any CIF overlapping this area (in coords * of cellDef) will be generated. The CIF * will be clipped to this area. */ Plane **planes; /* Pointer to array of pointers to planes * to hold "real" CIF layers that are * generated. Pointers may initially be * NULL. */ TileTypeBitMask *layers; /* CIF layers to generate. */ bool replace; /* TRUE means that the new CIF is to replace * anything that was previously in planes. * FALSE means that the new CIF is to be * OR'ed in with the current contents of * planes. */ bool genAllPlanes; /* If TRUE, generate a tile plane even for * those layers not specified as being * generated in the 'layers' mask above. */ { int i; Plane *new[MAXCIFLAYERS]; Rect expanded, clip; /* * Generate the area in magic coordinates to search, and the area in * cif coordinates to use in clipping the results of CIFGenLayer(). */ cifGenClip(area, &expanded, &clip); /* * Generate all of the new layers in a temporary place. * If a layer isn't being generated, leave new[i] set to * NULL to indicate this fact. */ for (i = 0; i < CIFCurStyle->cs_nLayers; i++) { if (TTMaskHasType(layers,i)) { CIFErrorLayer = i; new[i] = CIFGenLayer(CIFCurStyle->cs_layers[i]->cl_ops, &expanded, cellDef, new); } else if (genAllPlanes) new[i] = DBNewPlane((ClientData) TT_SPACE); else new[i] = (Plane *) NULL; } /* * Now mask off all the unwanted material in the new layers, and * either OR them into the existing layers or replace the existing * material with them. */ for (i = 0; i < CIFCurStyle->cs_nLayers; i += 1) { if (new[i]) cifClipPlane(new[i], &clip); if (replace) { if (planes[i]) { DBFreePaintPlane(planes[i]); TiFreePlane(planes[i]); } planes[i] = new[i]; continue; } if (planes[i]) { if (new[i]) { cifPlane = planes[i]; cifScale = 1; (void) DBSrPaintArea((Tile *) NULL, new[i], &TiPlaneRect, &CIFSolidBits, cifPaintFunc, (ClientData) CIFPaintTable); DBFreePaintPlane(new[i]); TiFreePlane(new[i]); } } else planes[i] = new[i]; } } /* * ---------------------------------------------------------------------------- * * cifClipPlane -- * * Erase the portions of the plane 'plane' that lie outside of 'clip'. * * Results: * None. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ Void cifClipPlane(plane, clip) Plane *plane; Rect *clip; { Rect r; if (clip->r_xtop < TiPlaneRect.r_xtop) { r = TiPlaneRect; r.r_xbot = clip->r_xtop; DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL); } if (clip->r_ytop < TiPlaneRect.r_ytop) { r = TiPlaneRect; r.r_ybot = clip->r_ytop; DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL); } if (clip->r_xbot > TiPlaneRect.r_xbot) { r = TiPlaneRect; r.r_xtop = clip->r_xbot; DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL); } if (clip->r_ybot > TiPlaneRect.r_ybot) { r = TiPlaneRect; r.r_ytop = clip->r_ybot; DBPaintPlane(plane, &r, CIFEraseTable, (PaintUndoInfo *) NULL); } } /* * ---------------------------------------------------------------------------- * * cifGenClip -- * * Compute two new areas from the original area: one ('expanded') * is expanded by a CIF halo and is used to determine how much of * the database to search to find what's relevant for CIF generation; * the other ('clip') is the CIF equivalent of area and is used to * clip the resulting CIF. This code is tricky because area may run * off to infinity, and we have to be careful not to expand past infinity. * * Results: * None. * * Side effects: * Sets *expanded and *clip. * * ---------------------------------------------------------------------------- */ Void cifGenClip(area, expanded, clip) Rect *area; /* Any CIF overlapping this area (in coords * of cellDef) will be generated. The CIF * will be clipped to this area. */ Rect *expanded, *clip; { if (area->r_xbot > TiPlaneRect.r_xbot) { clip->r_xbot = area->r_xbot * CIFCurStyle->cs_scaleFactor; expanded->r_xbot = area->r_xbot - CIFCurStyle->cs_radius; } else clip->r_xbot = expanded->r_xbot = area->r_xbot; if (area->r_ybot > TiPlaneRect.r_ybot) { clip->r_ybot = area->r_ybot * CIFCurStyle->cs_scaleFactor; expanded->r_ybot = area->r_ybot - CIFCurStyle->cs_radius; } else clip->r_ybot = expanded->r_ybot = area->r_ybot; if (area->r_xtop < TiPlaneRect.r_xtop) { clip->r_xtop = area->r_xtop * CIFCurStyle->cs_scaleFactor; expanded->r_xtop = area->r_xtop + CIFCurStyle->cs_radius; } else clip->r_xtop = expanded->r_xtop = area->r_xtop; if (area->r_ytop < TiPlaneRect.r_ytop) { clip->r_ytop = area->r_ytop * CIFCurStyle->cs_scaleFactor; expanded->r_ytop = area->r_ytop + CIFCurStyle->cs_radius; } else clip->r_ytop = expanded->r_ytop = area->r_ytop; } /* * ---------------------------------------------------------------------------- * * CIFClearPlanes -- * * This procedure clears out a collection of CIF planes. * * Results: * None. * * Side effects: * Each of the planes in "planes" is re-initialized to point to * an empty paint plane. * * ---------------------------------------------------------------------------- */ void CIFClearPlanes(planes) Plane **planes; /* Pointer to an array of MAXCIFLAYERS * planes. */ { int i; for (i = 0; i < MAXCIFLAYERS; i++) { if (planes[i] == NULL) { planes[i] = DBNewPlane((ClientData) TT_SPACE); } else { DBClearPaintPlane(planes[i]); } } }