diff --git a/Makefile b/Makefile index 2e483885..e6774696 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,9 @@ MAGICDIR = . PROGRAMS = magic TECH = scmos LIBRARIES = database utils extflat -MODULES = cmwind commands database dbwind debug drc extflat extract \ - graphics netmenu plow resis select sim textio tiles utils \ - windows wiring +MODULES = bplane cmwind commands database dbwind debug drc extflat \ + extract graphics netmenu plow resis select sim textio tiles \ + utils windows wiring MAKEFLAGS = INSTALL_CAD_DIRS = windows doc ${TECH} diff --git a/VERSION b/VERSION index 25e98fb9..a2f28f43 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.2.101 +8.4.0 diff --git a/bplane/Makefile b/bplane/Makefile new file mode 100644 index 00000000..f7b16860 --- /dev/null +++ b/bplane/Makefile @@ -0,0 +1,10 @@ +# +# rcsid "$Header: /usr/cvsroot/magic-8.0/drc/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $" +# + +MODULE = bplane +MAGICDIR = .. +SRCS = bpDump.c bpUtils.c bpBins.c bpEnum.c bpMain.c bpStat.c + +include ${MAGICDIR}/defs.mak +include ${MAGICDIR}/rules.mak diff --git a/bplane/README b/bplane/README new file mode 100644 index 00000000..fdf27d93 --- /dev/null +++ b/bplane/README @@ -0,0 +1,38 @@ +TODO +---- + +NOTE: nested enums are broken do to dynamic binning. + +Don't rebuild entire bplane when bbox grows. +unsubbing sometimes. + + +Some (remaining) bplane design issues: + +groups? + idea: support small number of groups by having + separate bplane for each group. Do selection this + way. Logically layered on top of bplanes - but may + want to integrate. + DECISION: defer for now. + +pack/unpack? + Seems incompatible with user alloc/dealloc. + Complicated. + DECISION: Forget it. + +coarse/fine with cache. + can be added later. should fit in nicely. + no special support needed. + +integrated find/add? + can add later. + don't worry about it now. + +May want to add attributes, via external hash. + + + + + + diff --git a/bplane/bpBins.c b/bplane/bpBins.c new file mode 100644 index 00000000..24a777f7 --- /dev/null +++ b/bplane/bpBins.c @@ -0,0 +1,716 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + + +/* bpBins.c + * + * Routines for creating and manipulating bin arrays. + * + */ + +#include +#include +#include "utils/utils.h" +#include "utils/malloc.h" +#include "database/database.h" +#include "utils/geometry.h" +#include "bplane/bplaneInt.h" + +/* debug */ +#define BPD 0 + +/* Tcl linked Parameters */ +int bpMinBAPop = 10; /* don't sub(bin) when count less than this */ +double bpMinAvgBinPop = 1.0; /* try to keep average bin pop at or + * below this + */ + +/* + * ---------------------------------------------------------------------------- + * + * roundUp -- Round up a number to a grid. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ int roundUp(int i, int res) +{ + int r = (i % res); + + /* Subtract negative number */ + if (r > 0) r = r - res; + return i - r; +} + +/* + * ---------------------------------------------------------------------------- + * + * bpBinArrayNew -- allocate new bin array. + * + * ---------------------------------------------------------------------------- + */ +static BinArray *bpBinArrayNew(int dx, /* x diameter of bins */ + int dy, /* y diameter of bins */ + Rect *bbox) /* area covered */ + +{ + BinArray *new; + Rect abbox; + int w, h, dimX, dimY, numBins; + int size; + + /* compute array dimensions */ + w = roundUp(GEO_WIDTH(bbox),dx); + h = roundUp(GEO_HEIGHT(bbox),dy); + dimX = w/dx; + dimY = h/dy; + numBins = dimX*dimY; + + /* allocate array */ + size = sizeof(BinArray) + numBins*(sizeof(void *)); + new = (BinArray *)callocMagic(size); + + /* initial */ + new->ba_bbox = *bbox; + new->ba_dx = dx; + new->ba_dy = dy; + new->ba_dimX = dimX; + new->ba_numBins = numBins; + + /* pull bbox back one from top-edge, right-edge, to simplify index + * computation in bpEnumPush + */ + new->ba_bbox.r_xtop --; + new->ba_bbox.r_ytop --; + + + + return new; +} + +/* + * ---------------------------------------------------------------------------- + * + * bpBinAdd -- add element to bin array + * + * ---------------------------------------------------------------------------- + */ +void bpBinAdd(BinArray *ba, + Element *e) +{ + int i; /* bin index */ + + /* compute bin index */ + if(GEO_WIDTH(&e->e_rect) >= ba->ba_dx || + GEO_HEIGHT(&e->e_rect) >= ba->ba_dy) + { + /* oversized */ + i = ba->ba_numBins; + } + else + { + /* x and y indices */ + int xi = (e->e_rect.r_xbot - ba->ba_bbox.r_xbot) / ba->ba_dx; + int yi = (e->e_rect.r_ybot - ba->ba_bbox.r_ybot) / ba->ba_dy; + + i = xi + yi*ba->ba_dimX ; + } + + /* add element */ + if(bpBinType(ba,i) == BT_ARRAY) + { + /* sub-binned */ + bpBinAdd(bpSubArray(ba,i), e); + } + else + { + /* simple list */ + Element *next = bpBinList(ba,i); + + /* link with next */ + e->e_link = next; + if(next) next->e_linkp = &e->e_link; + + /* link to head */ + ba->ba_bins[i] = e; + e->e_linkp = (Element **) &ba->ba_bins[i]; + } +} + +/* + * ---------------------------------------------------------------------------- + * + * bpBinArrayUnbuild - remove elements from bin array and Free the array + * + * Returns: (singly linked) list of elements formerly in the array + * + * ---------------------------------------------------------------------------- + */ +static Element *bpBinArrayUnbuild(BinArray *ba) +{ + Element *elements = NULL; + int numBins = ba->ba_numBins; + int i; + + /* empty the bins */ + for(i=0;i<=numBins;i++) + { + Element *l; + + if(bpBinType(ba,i) == BT_ARRAY) + { + /* sub-array, unbuild recursively */ + l = bpBinArrayUnbuild(bpSubArray(ba,i)); + } + else + { + /* Simple list */ + l = bpBinList(ba,i); + } + + /* collect elements */ + while(l) + { + Element *e = l; + l = e->e_link; + + e->e_link = elements; + elements = e; + } + } + + /* free the array */ + freeMagic((char *)ba); + + return elements; +} + + + +/* + * ---------------------------------------------------------------------------- + * bpListExceedsQ -- + * + * check if element list exceeds given length + * + * Returns size of list. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ int +bpListExceedsQ(Element *e, /* list */ + int n) /* length to check against */ +{ + n++; + + while(e && n) + { + n--; + e = e->e_link; + } + + return n==0; +} + +/* + * ---------------------------------------------------------------------------- + * + * bpBinArraySizeIt -- choose bin sizes for new bin array. + * + * RESULT: + * + * normally returns TRUE, + * returns FALSE on failure: could not come up with binning that + * makes progress. + * + * NOTE: the various 'return' parameters are not set on failure. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ bool +bpBinArraySizeIt(Rect *bbox, /* bin array bbox */ + Element *elements, /* initial elements */ + int *dxp, /* return bin x-diameter here */ + int *dyp, /* return bin y-diameter here */ + int *maxDXp, + int *maxDYp, + int *numBinsp, /* return number of bins here */ + int *countp) /* return number of elements here */ +{ + BinArray *ba; + int count; + double numBins; /* need double to avoid overflow on tentative calc. */ + int h = GEO_HEIGHT(bbox); + int w = GEO_WIDTH(bbox); + + int dx,dy; /* individual bin diameter */ + int maxEX, maxEY; /* max element dimensions */ + int maxDX, maxDY; /* max bin diameter allowed */ + int xDim, yDim; /* array dimensions */ + + int maxBins; /* max number of bins + * (due to bpMinAvgBinPop) + */ + + /* compute max element dimensions + * (would like bins coarser than max dimensisons) + */ + { + Element *e; + + maxEX = 0; + maxEY = 0; + count = 0; + + for(e=elements; e; e=e->e_link) + { + int ew = GEO_WIDTH(&e->e_rect); + int eh = GEO_HEIGHT(&e->e_rect); + + maxEX = MAX(maxEX,ew); + maxEY = MAX(maxEY,eh); + + count++; + } + } + + /* if too few elements, don't bother with binning */ + if(count < bpMinBAPop) return FALSE; + + /* if too tiny don't subbin, + * avoid nasty corner-cases in code below + */ + if(h<2 || w<2) return FALSE; + + /* tentatively choose bin size to fit all elements */ + dx = maxEX+1; + dy = maxEY+1; + + /* ensure we get at least two bins, so that + * subbining of sparse designs will work. + */ + maxDX = (w+1)/2; + maxDY = (h+1)/2; + + /* + fprintf(stderr,"bpBinArraySizeIt, initial " + "maxEX=%d maxEY=%d maxDX=%d maxDY=%d dx=%d dy=%d\n", + maxEX,maxEY,maxDX,maxDY,dx,dy); + */ + + if(dx <= maxDX) + { + /* x is cool */ + + if(dy <= maxDY) + { + /* totally cool */ + ; + } + else + { + /* y-dim too big for two bins, but x-dim cool, + * just reduce in x this time. + */ + dy = h+1; + } + } + else + { + /* x-dim too big for two bins */ + + if(dy <= maxDY) + { + /* x-dim too big for two bins but y=dim cool, + * just reduce in y this time + */ + dx = w+1; + } + else + { + /* BOTH x-dim and y-dim too big for two bins. + * We are screwed: will have some oversized. + * + * Choose betwen splitting in two horizontally or + * vertically, by which ever method results in the minimum + * number of oversized elements. + */ + int xOver=0; /* number of oversized if we reduce x-dim. */ + int yOver=0; /* number of oversized if we reduce y-dim. */ + Element *e; + + /* count potential oversized */ + for(e=elements; e; e=e->e_link) + { + int ew = GEO_WIDTH(&e->e_rect); + int eh = GEO_HEIGHT(&e->e_rect); + + if(ew >= maxDX) xOver++; + if(eh >= maxDY) yOver++; + } + + if(xOvermaxBins) + { + if(dx == w+1) + { + /* can't increase x-dim, so try increasing y-dim */ + int yDimTarget = maxBins/xDim; + + dy = (h+1) / MAX(yDimTarget,1); + dy = MIN(dy,maxDY); + } + else if (dy == h+1) + { + /* can't increase y-dim, so try increasing x-dim */ + int xDimTarget = maxBins/yDim; + + dx = (w+1) / MAX(xDimTarget,1); + dx = MIN(dx,maxDX); + } + else + { + /* try for square bins */ + double area = h * (w + 0.0); + int d = MAX(sqrt(area/maxBins),1); + + if(dmaxDX) + { + /* d too big for x-dim + * (this can happen for tall skinny bins) + * + * make x-dim maximal, and adjust y accordingly + */ + dx = w+1; + dy = MAX((h+1)/maxBins,dy); + dy = MIN(dy,maxDY); + } + else if(d>maxDY) + { + /* d too big for y-dim + * (this can happen for long squat bins) + * + * make y-dim maximal, and adjust x-dim accordingly + */ + dy = h+1; + dx = MAX((w+1)/maxBins,dx); + dx = MIN(dx,maxDX); + } + else + { + /* we're cool, create square bins */ + dx = d; + dy = d; + } + } + + /* update numBins */ + xDim = roundUp(w,dx)/dx; + yDim = roundUp(h,dy)/dy; + numBins = xDim*yDim; + + } + + /* DEBUG */ + if(BPD) + { + fprintf(stderr,"\nDEBUG bpBinArraySizeIt DONE, count=%d h=%d w=%d\n" + "\tmaxDX=%d maxDY=%d maxBins=%d\n" + "\tnumBins=%g dx=%d dy=%d\n", + count,h,w, + maxDX,maxDY,maxBins, + numBins,dx,dy); + } + + /* set results */ + if(dxp) *dxp = dx; + if(dyp) *dyp = dy; + if(maxDXp) *maxDXp = maxDX; + if(maxDYp) *maxDYp = maxDY; + if(numBinsp) *numBinsp = numBins; + if(countp) *countp = count; + + /* success */ + return TRUE; +} + +/* + * ---------------------------------------------------------------------------- + * + * bpBinArrayBuild1 -- build and populate bin array of given area and + * bin size. + * + * Returns: pointer to new bin array. + * + * ---------------------------------------------------------------------------- + */ +static BinArray *bpBinArrayBuild1(Rect *bbox, + Element *elements, /* initial elements */ + int dx, /* bin diameter */ + int dy) + +{ + BinArray *ba; + + /* build bin array */ + ba = bpBinArrayNew(dx, dy, bbox); + + /* transfer elements to bin array */ + while(elements) + { + Element *e; + + /* pop list */ + e = elements; + elements = e->e_link; + + bpBinAdd(ba, e); + } + + return ba; +} + +/* + * ---------------------------------------------------------------------------- + * + * bpBinArrayBuild -- build and populate bin array of given area, + * + * NOTE: optimal bin size determined by trial and error. + * oversized subbinned, as indicated. + * + * Returns: pointer to new bin array, NULL on failure. + * + * ---------------------------------------------------------------------------- + */ +BinArray *bpBinArrayBuild(Rect bbox, + Element *elements, /* initial elements */ + bool subbin) /* subbin as needed */ +{ + BinArray *ba; + int dx,dy; /* individual bin diameter */ + int maxDX, maxDY; + int numBins; + int count; + + + if(BPD) DumpRect("#### bpBinArrayBuild, TOP bbox= ", &bbox); + + /* figure out good bin dimensions */ + if(!bpBinArraySizeIt(&bbox, + elements, + &dx, + &dy, + &maxDX, + &maxDY, + &numBins, + &count)) return NULL; + + /* build the bin array */ + ba = bpBinArrayBuild1(&bbox, elements, dx, dy); + + if(!subbin) return ba; + + /* sub-bin normal bins */ + { + int dimX = ba->ba_dimX; + + int i; + for(i=0;iba_bins[i] = + (void *) ((pointertype) sub | BT_ARRAY); + } + } + } + + /* sub-bin oversized */ + { + BinArray *sub; + + sub = bpBinArrayBuild(bbox, + bpBinList(ba, numBins), + TRUE); + + if(sub) + { + ba->ba_bins[numBins] = + (void *) ((pointertype) sub | BT_ARRAY); + } + } + + if(BPD) + { + DumpRect("\n#### bpBinArrayBuild, DONE bbox= ", &bbox); + fprintf(stderr,"\n"); + } + return ba; +} + +/* + * ---------------------------------------------------------------------------- + * + * bpBinsUpdate -- update bplane bins + * + * Called prior to enumerations. + * + * ---------------------------------------------------------------------------- + */ +int bpBinLife = 0; +void bpBinsUpdate(BPlane *bp) +{ + Rect bbox; + bool oldBins; + + /* rebuild whenever inbox gets big */ + if(!bpListExceedsQ(bp->bp_inBox, bpMinBAPop-1)) return; + + /* fprintf(stderr,"DEBUG bpBinsUpdate - rebuilding bins.\n"); */ + + /* do bins already exist ? */ + oldBins = (bp->bp_rootNode != 0); + + /* if bins exist, dissolve them */ + if(oldBins) + { + Element *elist = bpBinArrayUnbuild(bp->bp_rootNode); + + /* add inbox to list */ + while(bp->bp_inBox) + { + /* pop from inbox */ + Element *e = bp->bp_inBox; + bp->bp_inBox = e->e_link; + + /* add to elist */ + e->e_link = elist; + elist = e; + } + + bp->bp_inBox = elist; + } + + /* compute accurate bbox */ + { + Element *e = bp->bp_inBox; + + bbox = e->e_rect; + + for(e=bp->bp_inBox; e; e=e->e_link) + { + GeoIncludeRectInBBox(&e->e_rect, &bbox); + } + } + + /* if rebuild, double bounding box, to avoid too many rebuilds */ + if(oldBins) + { + int dx = GEO_WIDTH(&bbox)/2; + int dy = GEO_HEIGHT(&bbox)/2; + bbox.r_xbot -= dx; + bbox.r_ybot -= dy; + bbox.r_xtop += dx; + bbox.r_ytop += dy; + } + + /* build and populate bin array */ + bp->bp_rootNode = bpBinArrayBuild(bbox, bp->bp_inBox, TRUE); + if(bp->bp_rootNode) bp->bp_inBox = NULL; + bp->bp_binArea = bbox; + bp->bp_binLife = bpBinLife; + bp->bp_inAdds = 0; + /* if(BPD) bpDump(bp, 0); */ +} + + + + + + + + + + + diff --git a/bplane/bpDump.c b/bplane/bpDump.c new file mode 100644 index 00000000..5a9c7c0c --- /dev/null +++ b/bplane/bpDump.c @@ -0,0 +1,316 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +/* bpDump.c + * + * routines to dump bin system (for debugging) + * + */ + +#include +#include "utils/utils.h" +#include "database/database.h" +#include "utils/geometry.h" +#include "bplane/bplaneInt.h" + +static int bpDumpFlags; /* set by bpDump, used by subroutines */ + +/* + * ---------------------------------------------------------------------------- + * bpIndent -- + * + * tab over n spaces on stderr + * + * ---------------------------------------------------------------------------- + */ +static void bpIndent(int n) +{ + int i; + + for(i=0;ir_xbot); + fprintf(stderr,"%d ", + r->r_ybot); + fprintf(stderr,"%d ", + r->r_xtop); + fprintf(stderr,"%d", + r->r_ytop); + } + else + { + fprintf(stderr,"%s ", + UnitsI2S(r->r_xbot)); + fprintf(stderr,"%s ", + UnitsI2S(r->r_ybot)); + fprintf(stderr,"%s ", + UnitsI2S(r->r_xtop)); + fprintf(stderr,"%s", + UnitsI2S(r->r_ytop)); + } +} + +/* + * ---------------------------------------------------------------------------- + * bpDumpElements -- + * + * list rects. + * + * ---------------------------------------------------------------------------- + */ +void bpDumpElements(Element *list, int indent) +{ + Element *e; + + for(e = list; e; e=e->e_link) + { + bpIndent(indent); + fprintf(stderr,"{element "); + + if(bpDumpFlags & BPD_LABELED) + { + LabeledElement *le = (LabeledElement *) e; + fprintf(stderr,"%s ", le->le_text); + } + + bpDumpRect(&e->e_rect); + fprintf(stderr,"}\n"); + + } +} + +/* + * ---------------------------------------------------------------------------- + * bpDumpEnums -- + * + * list active enumerations + * + * ---------------------------------------------------------------------------- + */ +void bpDumpEnums(BPEnum *bpe, int indent) +{ + for(; bpe; bpe=bpe->bpe_next) + { + bpIndent(indent); + fprintf(stderr,"{enum \"%s\"}", + bpe->bpe_id); + } +} + +/* + * ---------------------------------------------------------------------------- + * bpBinArrayDump -- + * + * recursively dump hierarchical bin system + * + * ---------------------------------------------------------------------------- + */ +static void bpBinArrayDump(BinArray *ba, int indent) +{ + + int numBins = ba->ba_numBins; + int dx = ba->ba_dx; + int dy = ba->ba_dy; + int dimX = ba->ba_dimX; + int dimY = numBins/dimX; + Rect *bbox = &ba->ba_bbox; + int xi,yi; + + /* open */ + bpIndent(indent); + fprintf(stderr,"{bin-array "); + + if(bpDumpFlags & BPD_INTERNAL_UNITS) + { + fprintf(stderr,"{dx %d} {dy %d} ", + dx,dy); + } + else + { + fprintf(stderr,"{dx %s} ", + UnitsI2S(dx)); + + fprintf(stderr,"{dy %s} ", + UnitsI2S(dy)); + } + fprintf(stderr,"{dimX %d} {dimY %d} { bbox ", + dimX, + dimY); + bpDumpRect(bbox); + fprintf(stderr," }\n"); + + /* bins */ + for(yi=0; yir_xbot + xi*dx; + area.r_ybot = bbox->r_ybot + yi*dy; + area.r_xtop = area.r_xbot + dx; + area.r_ytop = area.r_ybot + dy; + + /* skip empty bins */ + if(bpBinEmpty(ba,i)) continue; + + /* open bin */ + bpIndent(indent+2); + fprintf(stderr,"{bin {number %d} { bbox ", + i); + bpDumpRect(&area); + fprintf(stderr," }\n"); + + /* list bin contents */ + if(bpBinType(ba,i) == BT_ARRAY) + { + /* dump sub array */ + bpBinArrayDump( bpSubArray(ba,i), + indent+4); + } + else + { + /* list elements */ + bpDumpElements(bpBinList(ba,i),indent+4); + } + + /* close bin */ + bpIndent(indent+2); + fprintf(stderr,"}\n"); + } + } + + /* oversized */ + if(!bpBinEmpty(ba,numBins)) + { + /* open oversized */ + bpIndent(indent+2); + fprintf(stderr,"{oversized {bbox "); + bpDumpRect(bbox); + fprintf(stderr,"}\n"); + + /* list bin contents */ + if(bpBinType(ba,numBins) == BT_ARRAY) + { + /* dump sub array */ + bpBinArrayDump( bpSubArray(ba,numBins), + indent+4); + } + else + { + /* list elements */ + bpDumpElements(bpBinList(ba,numBins),indent+4); + } + + /* close oversized */ + bpIndent(indent+2); + fprintf(stderr,"}\n"); + } + + /* close bin array */ + bpIndent(indent); + fprintf(stderr,"}\n"); +} + +/* + * ---------------------------------------------------------------------------- + * bpDump -- + * + * dump bplane (for debugging) + * + * ---------------------------------------------------------------------------- + */ +void bpDump(BPlane *bp, int flags) +{ + fprintf(stderr, "======= BPLANE DUMP ======\n"); + + bpDumpFlags = flags; + + /* open bplane */ + fprintf(stderr,"{bplane {count %d} {bbox ", + bp->bp_count); + bpDumpRect(&bp->bp_bbox); + fprintf(stderr,"}\n"); + + /* list in box rects */ + bpIndent(2); + fprintf(stderr,"{in_box\n"); + + bpDumpElements(bp->bp_inBox,4); + bpIndent(2); + fprintf(stderr,"}\n"); + + /*** bins ***/ + bpIndent(2); + fprintf(stderr,"{binned {area "); + bpDumpRect(&bp->bp_binArea); + fprintf(stderr,"}\n"); + + if(bp->bp_rootNode) bpBinArrayDump(bp->bp_rootNode, 4); + bpIndent(2); + fprintf(stderr,"}\n"); + + /*** enums ***/ + bpIndent(2); + fprintf(stderr,"{enums\n"); + + bpDumpEnums(bp->bp_enums,4); + + bpIndent(2); + fprintf(stderr,"}\n"); + + /* close bplane */ + fprintf(stderr,"}\n"); +} + + + + + + + + + + diff --git a/bplane/bpEnum.c b/bplane/bpEnum.c new file mode 100644 index 00000000..542b5bb3 --- /dev/null +++ b/bplane/bpEnum.c @@ -0,0 +1,166 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + + +/* bpEnum.c - + * + * Search routines for bplanes + * + */ + +#include +#include "utils/utils.h" +#include "database/database.h" +#include "utils/geometry.h" +#include "bplane/bplaneInt.h" + +/* + * ---------------------------------------------------------------------------- + * BPEnumInit -- + * + * set up search. + * + * ---------------------------------------------------------------------------- + */ +void BPEnumInit(BPEnum *bpe, /* enum to initialize */ + BPlane *bp, + Rect *area, /* search area */ + int match, + char *id) /* for debugging */ +{ + bool inside = FALSE; + bpe->bpe_plane = bp; + bpe->bpe_id = id; + bpe->bpe_match = match; + bpe->bpe_top = bpe->bpe_stack; + + /* + fprintf(stderr,"DEBUG bpEnumInit, match=%d id=%s\n", + match, id); + */ + + /* link enum to bplane */ + bpe->bpe_next = bp->bp_enums; + bp->bp_enums = bpe; + + switch (match) + { + + case BPE_EQUAL: + GeoCanonicalRect(area, &bpe->bpe_srchArea); + bpe->bpe_nextElement = IHashLookUp(bp->bp_hashTable, &bpe->bpe_srchArea); + bpe->bpe_top->bps_state = BPS_HASH; + /* don't need to setup stack, just return */ + return; + + case BPE_ALL: + /* If we start 'INSIDE', no match checks will be done */ + bpe->bpe_top->bps_state = BPS_BINS_INSIDE; + inside = TRUE; + break; + + case BPE_TOUCH: + GeoCanonicalRect(area, &bpe->bpe_srchArea); + inside = GEO_SURROUND(&bpe->bpe_srchArea, &bp->bp_bbox); + if(inside) + { + bpe->bpe_top->bps_state = BPS_BINS_INSIDE; + } + else + { + bpe->bpe_top->bps_state = BPS_BINS; + bpe->bpe_subBinMinX = GEO_WIDTH(&bpe->bpe_srchArea)/2; + bpe->bpe_subBinMinY = GEO_HEIGHT(&bpe->bpe_srchArea)/2; + bpBinsUpdate(bp); + } + break; + + case BPE_OVERLAP: + GeoCanonicalRect(area, &bpe->bpe_srchArea); + GEO_EXPAND(&bpe->bpe_srchArea, -1, &bpe->bpe_srchArea); + inside = GEO_SURROUND(&bpe->bpe_srchArea, &bp->bp_bbox); + if(inside) + { + bpe->bpe_top->bps_state = BPS_BINS_INSIDE; + } + else + { + bpe->bpe_top->bps_state = BPS_BINS; + bpe->bpe_subBinMinX = GEO_WIDTH(&bpe->bpe_srchArea)/2; + bpe->bpe_subBinMinY = GEO_HEIGHT(&bpe->bpe_srchArea)/2; + bpBinsUpdate(bp); + } + break; + + default: + ASSERT(FALSE,"BPEnumInit, bad match value"); + } + + /* push rootnode */ + if(bp->bp_rootNode) + { + bpEnumPush(bpe, bp->bp_rootNode, inside); + bpe->bpe_nextElement = NULL; + } + else + { + /* no bins, go straight to inbox */ + bpe->bpe_top->bps_state = BPS_INBOX | inside; + bpe->bpe_nextElement = bp->bp_inBox; + } +} + +/* + * ---------------------------------------------------------------------------- + * BPEnumTerm -- + * + * terminate enumeration + * + * ---------------------------------------------------------------------------- + */ +void BPEnumTerm(BPEnum *bpe) +{ + BPEnum **linkp; + + /* + fprintf(stderr,"DEBUG bpEnumTerm, id=%s\n", + bpe->bpe_id); + */ + + /* unlink */ + + linkp = &bpe->bpe_plane->bp_enums; + while(*linkp && *linkp != bpe) linkp = &(*linkp)->bpe_next; + ASSERT(*linkp==bpe,"BPEnumTerm"); + *linkp = bpe->bpe_next; +} + + + + diff --git a/bplane/bpEnum.h b/bplane/bpEnum.h new file mode 100644 index 00000000..0de4050f --- /dev/null +++ b/bplane/bpEnum.h @@ -0,0 +1,537 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + +#ifndef _BPENUM_H +#define _BPENUM_H + +/* bpEnum.h -- + * + * inlined Search routines for bplanes (see also bpEnum.c) + * + */ + +#include +#include "utils/utils.h" +#include "utils/geometry.h" +#include "utils/geofast.h" +#include "bplane/bplane.h" +#include "bplane/bplaneInt.h" + +extern void DumpRect(char *msg, Rect *r); + +/* state machine states */ +#define BPS_BINS 0 +#define BPS_BINS_INSIDE 1 +#define BPS_INBOX 2 +#define BPS_INBOX_INSIDE 3 +#define BPS_HASH 4 +#define BPS_DONE 5 + +/* range code */ +#define R_LEFT 1 +#define R_RIGHT 2 +#define R_BOT 4 +#define R_TOP 8 + +/* + * ---------------------------------------------------------------------------- + * + * bpBinArea -- compute area covered by given bin. + * + * Returns: bin area. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ Rect bpBinArea(BinArray *ba, int i) +{ + int dimX = ba->ba_dimX; + int dx = ba->ba_dx; + int dy = ba->ba_dy; + int xi = i % dimX; + int yi = i / dimX; + Rect area; + + area.r_xbot = ba->ba_bbox.r_xbot + dx*xi; + area.r_ybot = ba->ba_bbox.r_ybot + dy*yi; + area.r_xtop = area.r_xbot + dx; + area.r_ytop = area.r_ybot + dy; + + return area; +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumRange -- + * + * Determine which edges of search area bin overlaps. + * + * (Used to make match checks as efficient as possible, for example if bin + * does not extend past srch area in any direction, no match checking is + * required) + * + * Returns: int encoding 'range'. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ int +bpEnumRange(Rect *bin, Rect *srch) +{ + int range = 0; + + if (bin->r_xbot < srch->r_xbot) range |= R_LEFT; + if (bin->r_xtop > srch->r_xtop) range |= R_RIGHT; + if (bin->r_ybot < srch->r_ybot) range |= R_BOT; + if (bin->r_ytop > srch->r_ytop) range |= R_TOP; + + return range; +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumMatchQ - + * + * Check if element intersects search area + * + * range specifies which search area boundaries the element + * can potentially extend beyond. + * + * We rely on the optimizing compiler to remove unnecessary checks + * based on compile time knowledge of range value. + * + * Returns: TRUE on match, FALSE otherwise. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ bool +bpEnumMatchQ(BPEnum *bpe, Element *e) +{ + Rect *area = &bpe->bpe_srchArea; + Rect *r = &e->e_rect; + + if(r->r_xtop < area->r_xbot) return FALSE; + if(r->r_xbot > area->r_xtop) return FALSE; + if(r->r_ytop < area->r_ybot) return FALSE; + if(r->r_ybot > area->r_ytop) return FALSE; + + return TRUE; +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumPushInside -- + * + * called by bpEnumPush when the binarray is entirely inside the search area + * + * push a bin array onto an enum stack. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ bool bpEnumPushInside(BPEnum *bpe, + BinArray *ba) +{ + BPStack *bps; + + /* push stack */ + ++bpe->bpe_top; + bps = bpe->bpe_top; + bps->bps_node = ba; + bps->bps_state = BPS_BINS_INSIDE; + + /* set up indices to scan entire bin array */ + bps->bps_i = -1; + bps->bps_max = ba->ba_numBins; + + return TRUE; +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumPush -- + * + * push a bin array onto an enum stack. + * + * normally returns TRUE, returns FALSE on (possible) state change. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ bool bpEnumPush(BPEnum *bpe, + BinArray *ba, + bool inside) +{ + Rect area; + Rect *bbox; + int dx; + int dy; + BPStack *bps; + + /* + fprintf(stderr,"DEBUG bpEnumPush, inside=%d\n", inside); + */ + + /* special case inside */ + if(inside) return bpEnumPushInside(bpe,ba); + + bbox = &ba->ba_bbox; + if(GEO_SURROUND(&bpe->bpe_srchArea,bbox)) + { + bpEnumPushInside(bpe,ba); + return FALSE; /* state change */ + } + + /* push stack */ + ++bpe->bpe_top; + bps = bpe->bpe_top; + bps->bps_node = ba; + bps->bps_state = BPS_BINS; + bps->bps_subbin = FALSE; + bps->bps_rejects = 0; + + /* compute search area for this bin array */ + dx = ba->ba_dx; + dy = ba->ba_dy; + area.r_xbot = bpe->bpe_srchArea.r_xbot - dx; + area.r_xtop = bpe->bpe_srchArea.r_xtop + 1; + area.r_ybot = bpe->bpe_srchArea.r_ybot - dy; + area.r_ytop = bpe->bpe_srchArea.r_ytop + 1; + GEOCLIP(&area,bbox); + + if(GEO_RECTNULL(&area)) + { + /* only need to check oversized */ + bps->bps_i = 0; + bps->bps_rowMax = 0; + bps->bps_max = 0; + } + else + { + /* setup indices for this array and search area */ + int dimX = ba->ba_dimX; + int i; + + /* make area relative to bin bbox */ + area.r_xbot -= bbox->r_xbot; + area.r_xtop -= bbox->r_xbot; + area.r_ybot -= bbox->r_ybot; + area.r_ytop -= bbox->r_ybot; + + /* DumpRect("area relative to bin bbox = ",&area); */ + + area.r_xbot /= ba->ba_dx; + area.r_xtop /= ba->ba_dx; + area.r_ybot /= ba->ba_dy; + area.r_ytop /= ba->ba_dy; + + i = area.r_ybot*dimX + area.r_xbot; /* next index */ + bps->bps_i = i-1; + bps->bps_rowMax = i + area.r_xtop - area.r_xbot; + bps->bps_max = area.r_ytop*dimX + area.r_xtop; + bps->bps_rowDelta = dimX + area.r_xbot - area.r_xtop; + bps->bps_dimX = dimX; + + /* consider subbinning? */ + if(dx >= bpe->bpe_subBinMinX || dy >= bpe->bpe_subBinMinY) + { + bps->bps_subbin = TRUE; + } + } + + return TRUE; +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumNextBin1 -- + * + * called by bpEnumNextBin() after indexes for new bin are setup + * + * returns: normally returns TRUE, returns FALSE on state change. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ bool +bpEnumNextBin1(BPEnum *bpe, BPStack *bps, bool inside) +{ + if(bpBinType(bps->bps_node,bps->bps_i) != BT_ARRAY) + { + bpe->bpe_nextElement = bpBinList(bps->bps_node,bps->bps_i); + return TRUE; + } + + /* array, push into it */ + return bpEnumPush(bpe, bpSubArray(bps->bps_node,bps->bps_i), inside); +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumNextBin -- + * + * called by bpEnumNextBINS to advance to next bin (bucket). + * + * cycles through normal bins first, then oversized, + * finally, for toplevel, sets INBOX state. + * + * sets bpe->bpe_nextElement to first element in next bin. + * + * returns: normally returns TRUE, returns FALSE on state change. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ bool +bpEnumNextBin(BPEnum *bpe, bool inside) +{ + BPStack *bps = bpe->bpe_top; + +#ifdef PARANOID + ASSERT(bps,"bpEnumNextBin"); + ASSERT(!bpe->bpe_nextElement,"bpEnumNextBin"); +#endif + + /* + fprintf(stderr,"DEBUG bpEnumNextBin TOP inside=%d nextElement=%x\n", + inside, bpe->bpe_nextElement); + */ + + /* consider subbining this bin before advancing to next */ + if(!inside) + { + if(bps->bps_rejects >= bpMinBAPop + && (bps->bps_subbin || bps->bps_i == bps->bps_node->ba_numBins)) + { + int i = bps->bps_i; + BinArray *ba = bps->bps_node; + BinArray *sub; + + /* fprintf(stderr,"DEBUG, subbining!\n"); */ + sub = bpBinArrayBuild(bpBinArea(ba,i), + bpBinList(ba,i), + FALSE); /* don't recursively subbin! */ + + if(sub) + { + ba->ba_bins[i] = + (void *) ((pointertype) sub | BT_ARRAY); + } + } + bps->bps_rejects = 0; + } + + /* handle inside case first */ + if(inside) + { + /* Inside case, cycle through all bins */ + + /* next bin */ + if(bps->bps_ibps_max) + { + bps->bps_i += 1; + return bpEnumNextBin1(bpe,bps,inside); + } + } + else + { + /* cycle only through relevant bins */ + + /* next in row */ + if(bps->bps_ibps_rowMax) + { + bps->bps_i += 1; + goto bin; + } + + /* next row */ + if(bps->bps_ibps_max) + { + bps->bps_i += bps->bps_rowDelta; + bps->bps_rowMax += bps->bps_dimX; + goto bin; + } + + /* oversized */ + if(bps->bps_i == bps->bps_max) + { + bps->bps_i = bps->bps_node->ba_numBins; + goto bin; + } + } + + /* pop stack */ + /* fprintf(stderr,"DEBUG BPEnumNextBin Pop.\n"); */ + bpe->bpe_top--; + if(bpe->bpe_top>bpe->bpe_stack) return FALSE; /* state may have changed */ + + /* inbox */ + /* fprintf(stderr,"DEBUG BPEnumNextBin INBOX.\n"); */ + bpe->bpe_nextElement = bpe->bpe_plane->bp_inBox; + bpe->bpe_top->bps_state = BPS_INBOX | inside; + return FALSE; /* state change */ + + /* dive into indexed bin */ + bin: + return bpEnumNextBin1(bpe,bps,inside); +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumNextBINS -- + * + * Handle BINS state for BPEnumNext() + * + * (bin enumeration.) + * + * ---------------------------------------------------------------------------- + */ +static __inline__ Element* bpEnumNextBINS(BPEnum *bpe, bool inside) +{ + /* bin by bin */ + do + { + /* search this bin */ + Element *e = bpe->bpe_nextElement; + + while(e && !inside && !bpEnumMatchQ(bpe,e)) + { + bpe->bpe_top->bps_rejects++; + e = e->e_link; + } + + if(e) + { + bpe->bpe_nextElement = e->e_link; + /* DumpRect("DEBUG e_rect= ",&e->e_rect); */ + return e; + } + + bpe->bpe_nextElement = NULL; + } + while(bpEnumNextBin(bpe,inside)); + + /* next state */ + return NULL; +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumNextINBOX -- + * + * Handle INBOX states for BPEnumNext() + * + * unbinned enumeration. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ Element *bpEnumNextINBOX(BPEnum *bpe, + bool inside) +{ + Element *e = bpe->bpe_nextElement; + + while(e && !inside && !bpEnumMatchQ(bpe,e)) e = e->e_link; + if(e) + { + bpe->bpe_nextElement = e->e_link; + return e; + } + + /* done */ + bpe->bpe_top->bps_state = BPS_DONE; + return NULL; +} + +/* + * ---------------------------------------------------------------------------- + * bpEnumNextHASH -- + * + * Handle HASH state for BPEnumNext() + * + * (hash based (EQUALS) enumerations.) + * + * ---------------------------------------------------------------------------- + */ +static __inline__ Element *bpEnumNextHASH(BPEnum *bpe) +{ + Element *e = bpe->bpe_nextElement; + + if(e) + { + bpe->bpe_nextElement = + IHashLookUpNext(bpe->bpe_plane->bp_hashTable, e); + } + else + { + bpe->bpe_top->bps_state = BPS_DONE; + } + return e; +} + +/* + * ---------------------------------------------------------------------------- + * BPEnumNext -- + * + * get next element in enumeration. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ void *BPEnumNext(BPEnum *bpe) +{ + Element *e; + + while(TRUE) + { + /* + fprintf(stderr,"DEBUG state=%d\n",bpe->bpe_top->bps_state); + */ + switch (bpe->bpe_top->bps_state) + { + case BPS_BINS: + if(e=bpEnumNextBINS(bpe, 0)) return e; + break; + + case BPS_BINS_INSIDE: + if(e=bpEnumNextBINS(bpe, 1)) return e; + break; + + case BPS_INBOX: + if(e=bpEnumNextINBOX(bpe, 0)) return e; + break; + + case BPS_INBOX_INSIDE: + if(e=bpEnumNextINBOX(bpe, 1)) return e; + break; + + case BPS_HASH: + if(e=bpEnumNextHASH(bpe)) return e; + break; + + case BPS_DONE: + return NULL; + + default: + ASSERT(FALSE,"BPEnumNext, bad state"); + } + } +} + +#endif /* _BPENUM_H */ diff --git a/bplane/bpMain.c b/bplane/bpMain.c new file mode 100644 index 00000000..f1c6c43c --- /dev/null +++ b/bplane/bpMain.c @@ -0,0 +1,273 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +/* bpMain.c + * + * Top-level routines for BPlanes + * (interface to other modules) + * + * See bpEnum.c for enum routines. + * See bpTcl.c for tcl-level interface. + */ + +#include +#include "utils/utils.h" +#include "utils/malloc.h" +#include "database/database.h" +#include "utils/geometry.h" +#include "bplane/bplaneInt.h" + +/* + * ---------------------------------------------------------------------------- + * BPNew -- + * + * Return newly created BPlane. + * + * ---------------------------------------------------------------------------- + */ +BPlane *BPNew(void) +{ + BPlane *new; + + new = (BPlane *)mallocMagic(sizeof(BPlane)); + + new->bp_bbox = GeoNullRect; + new->bp_bbox_exact = TRUE; + + new->bp_count = 0; + + /* ENUMS */ + new->bp_enums = NULL; + + /* HASH TABLE */ + new->bp_hashTable = IHashInit(4, /* initial buckets */ + OFFSET(Element, e_rect), /* key */ + OFFSET(Element, e_hashLink), + IHash4WordKeyHash, + IHash4WordKeyEq); + + /* IN BOX */ + new->bp_inBox = NULL; + + /* BINS */ + new->bp_binLife = 0; + new->bp_inAdds = 0; + new->bp_binArea = GeoNullRect; + new->bp_rootNode = NULL; + + return new; +} + +/* + * ---------------------------------------------------------------------------- + * BPFree -- + * + * free (empty) BPlane + * + * ---------------------------------------------------------------------------- + */ +void BPFree(BPlane *bp) +{ + ASSERT(bp->bp_count == 0,"BPFree"); + IHashFree(bp->bp_hashTable); + freeMagic((char *)bp); +} + +/* + * ---------------------------------------------------------------------------- + * BPAdd -- + * + * Add element to the given bplane + * + * NOTE: e_rect better be canonical! + * + * ---------------------------------------------------------------------------- + */ +void BPAdd(BPlane *bp, void *element) +{ + int size; + int binDim; + Element * e = element; + Rect *r = &e->e_rect; + + /* Don't allow adds during active enumerations. + * This is confusing, since newly added elements may or may not + * be enumerated in on going enumerations, is not particularly + * useful, since elements to add can just be stored up on a local + * list and added after the enumeration completes. + */ + ASSERT(!bp->bp_enums, + "BPAdd, attempted during active enumerations"); + + /* element rect must be canonical! */ +#ifdef PARANOID + ASSERT(GeoIsCanonicalRect(r),"BPAdd, rect must be canonical."); +#endif + + bp->bp_count++; + + /* update hash table */ + IHashAdd(bp->bp_hashTable, element); + + /* update bbox */ + if(bp->bp_count == 1) + { + bp->bp_bbox = *r; + } + else + { + GeoIncludeRectInBBox(r,&bp->bp_bbox); + } + + /* no bins? */ + if(!bp->bp_rootNode) goto inBox; + + /* doesn't fit inside bins ? */ + if(!GEO_SURROUND(&bp->bp_binArea,r)) goto inBox; + + /* bin element */ + bpBinAdd(bp->bp_rootNode, e); + return; + + /* add to in box */ + inBox: + bp->bp_inAdds++; + e->e_link = bp->bp_inBox; + bp->bp_inBox = e; + + /* maintain back pointers */ + e->e_linkp = &bp->bp_inBox; + if(e->e_link) e->e_link->e_linkp = &e->e_link; + +} + +/* + * ---------------------------------------------------------------------------- + * BPDelete -- + * + * remove element from bplane + * + * ---------------------------------------------------------------------------- + */ +void BPDelete(BPlane *bp, void *element) +{ + Element *e = element; + + ASSERT(e,"BPDelete"); + bp->bp_count--; + + /* if element was on edge of bbox, bbox may no longer + * be exact. + */ + if(bp->bp_bbox_exact && + (bp->bp_bbox.r_xbot == e->e_rect.r_xbot || + bp->bp_bbox.r_xtop == e->e_rect.r_xtop || + bp->bp_bbox.r_ybot == e->e_rect.r_ybot || + bp->bp_bbox.r_ytop == e->e_rect.r_ytop)) + { + bp->bp_bbox_exact = FALSE; + } + + /* advance any nextElement pointers at e */ + { + BPEnum *bpe; + + for(bpe=bp->bp_enums; bpe; bpe=bpe->bpe_next) + { + if(bpe->bpe_nextElement != e) continue; + + if(bpe->bpe_match == BPE_EQUAL) + { + bpe->bpe_nextElement = IHashLookUpNext(bp->bp_hashTable, e); + } + else + { + bpe->bpe_nextElement = e->e_link; + } + } + } + + IHashDelete(bp->bp_hashTable, e); + + /* next pointer of prev element */ + *e->e_linkp = e->e_link; + + /* back pointer of next element */ + if(e->e_link) e->e_link->e_linkp = e->e_linkp; +} + +/* + * ---------------------------------------------------------------------------- + * BPBBox -- + * + * Get current bplane bbox. + * + * returns: current bplane bbox + * (returns an inverted rect, if bplane is empty) + * + * ---------------------------------------------------------------------------- + */ +Rect BPBBox(BPlane *bp) +{ + + if(bp->bp_count == 0) return GeoInvertedRect; + + /* if bbox is not up-to-date, recompute */ + if(!bp->bp_bbox_exact) + { + BPEnum bpe; + Element *e; + + bp->bp_bbox_exact = TRUE; + + BPEnumInit(&bpe, + bp, + NULL, + BPE_ALL, + "BPBBox"); + + e = BPEnumNext(&bpe); + bp->bp_bbox = e->e_rect; + + while(e = BPEnumNext(&bpe)) + { + GeoIncludeRectInBBox(&e->e_rect, &bp->bp_bbox); + } + } + + return bp->bp_bbox; +} + + + + + + + + diff --git a/bplane/bpOpaque.h b/bplane/bpOpaque.h new file mode 100644 index 00000000..fb5440d3 --- /dev/null +++ b/bplane/bpOpaque.h @@ -0,0 +1,195 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +#ifndef _BPOPAQUE_H +#define _BPOPAQUE_H + +#ifndef _IHASH_H +#include "utils/ihash.h" +#endif /* _IHASH_H */ + +/* + * bpOpaque.h -- + * + * This file contains strucs directly or indirectly referenced by + * clients of bplane module, whose internals should be treated + * as opaque by clients. + * + * It is included by bplane.h + * + */ + +/* data element, stored in BPlane + * + * Storage managed by caller. + * Inital part must correspond to below. + */ +typedef struct element +{ + struct element *e_hashLink; + struct element *e_link; + struct element **e_linkp; /* back pointer for quick deletes */ + Rect e_rect; + /* client data goes here */ +} Element; + +/* number of link fields in element + * + * user code should not depend on more than 1 link. + * (and should only use/ref that link when element is not in a bplane) + */ +#define BP_NUM_LINKS 3 + +/* bin array */ +typedef struct binarray +{ + Rect ba_bbox; /* area covered by array */ + int ba_dx; /* dimensions of a single bin */ + int ba_dy; + int ba_dimX; /* number of bins in a row */ + int ba_numBins; /* number of regular bins (size of array - 1) */ + + void *ba_bins[1]; /* low order bit(s) used to encode type info. + * DON'T ACCESS DIRECTLY, USE MACROS BELOW + * + * (last bin is for oversized) + */ +} BinArray; + +/* bin types + * + * NOTE: its important that simple lists have type 0, i.e. are + * just standard pointers. This is so that the list head + * 'link' can be treated just as any other link, during + * deletion etc. + */ + +#define BT_TYPE_MASK 1 +#define BT_LIST 0 +#define BT_ARRAY 1 + +static __inline__ bool bpBinEmpty(BinArray *ba, int i) +{ + return ba->ba_bins[i] == NULL; +} + +static __inline__ bool bpBinType(BinArray *ba, int i) +{ + return (bool) (((pointertype) ba->ba_bins[i]) & BT_TYPE_MASK); +} + +static __inline__ Element *bpBinList(BinArray *ba, int i) +{ +#ifdef PARANOID + ASSERT(bpBinType(ba,i)==BT_LIST,"bpBinList"); +#endif + return (Element *) ba->ba_bins[i]; +} + +static __inline__ Element **bpBinListHead(BinArray *ba, int i) +{ +#ifdef PARANOID + ASSERT(bpBinType(ba,i)==BT_LIST,"bpBinList"); +#endif + return (Element **) &ba->ba_bins[i]; +} + +static __inline__ BinArray *bpSubArray(BinArray *ba, int i) +{ +#ifdef PARANOID + ASSERT(bpBinType(ba,i)==BT_ARRAY,"bpSubArray"); +#endif + return (BinArray *) ((pointertype) ba->ba_bins[i] & ~BT_TYPE_MASK); +} + +/* BPlane - toplevel struc */ +typedef struct bplane +{ + Rect bp_bbox; /* bbox (bin + in) */ + bool bp_bbox_exact; /* if set bp_bbox, is exact, + * if reset bp_bbox may be over-sized. + */ + int bp_count; /* total number of elements in bplane */ + struct bpenum *bp_enums; /* list of active enums */ + + /* HASH TABLE */ + IHashTable *bp_hashTable; /* hash table + * (for expediting BP_EQUAL searches) */ + /* IN BOX */ + Element *bp_inBox; /* elements not yet added to bin system */ + + /* BINS */ + int bp_binLife; /* set to binCount when bin system + * built, decremented on add/delete ops. + * bin system rebuilt when zero reached. + */ + int bp_inAdds; /* additions to inBox since last rebuild */ + + Rect bp_binArea; /* area covered by bin arrays */ + BinArray *bp_rootNode; /* top bin node */ +} BPlane; + +/* context for BPlane enumeration */ +typedef struct bpStack +{ + int bps_state; /* where we are at rolled in one convenient + * number (see BPS_* defs in bpEnum.h) + */ + BinArray *bps_node; /* current bin array */ + int bps_i; /* current index */ + int bps_rowMax; /* max index for this row */ + int bps_rowDelta; /* increment from end of one row to beginning + * of next. + */ + int bps_max; /* max index */ + int bps_dimX; /* row length */ + bool bps_subbin; /* if set consider subbinning */ + int bps_rejects; /* number of unmatching elements in current + * bin, used to decide when to subbin. + */ +} BPStack; + +/* enumeration 'handle' */ +typedef struct bpenum +{ + struct bpenum *bpe_next; /* all enums for bplane linked together */ + BPlane *bpe_plane; /* plane being searched */ + Rect bpe_srchArea; /* area being searched */ + int bpe_match; /* match criteria */ + char *bpe_id; /* for debug */ + int bpe_subBinMinX; + int bpe_subBinMinY; /* consider subbinning + * for bins bigger than this. + */ + Element *bpe_nextElement; /* next element in current list */ + BPStack *bpe_top; /* top of stack */ + BPStack bpe_stack[10000]; /* stack for tree traversal during enum */ +} BPEnum; + +#endif /* _BPOPAQUE_H */ diff --git a/bplane/bpStat.c b/bplane/bpStat.c new file mode 100644 index 00000000..dbee6d2c --- /dev/null +++ b/bplane/bpStat.c @@ -0,0 +1,304 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +/* bpStat.c + * + * routines to get bplane statistics. + * + */ + +#include +#include +#include "utils/utils.h" +#include "database/database.h" +#include "utils/geometry.h" +#include "bplane/bplaneInt.h" + +/* + * ---------------------------------------------------------------------------- + * bpCount -- + * + * count list of elements. + * + * Returns size of list. + * + * ---------------------------------------------------------------------------- + */ +int bpCount(Element *e) +{ + int i = 0; + + while(e) + { + i++; + e = e->e_link; + } + + return i; +} + +/* + * ---------------------------------------------------------------------------- + * bpStatBA -- + * + * compute bin array statistics. + * (includes sub-arrays) + * + * + * Returns memory used by bplane (excluding elements) + * + * ---------------------------------------------------------------------------- + */ +unsigned int bpStatBA(BinArray *ba, + int *totCount, /* total number of elements */ + int *totBins, /* ret tot num of bins */ + int *emptyBins, /* ret num of empty bins */ + int *binArraysp, /* ret num of bin arrays */ + int *maxEffp, /* ret max effective list length */ + int *maxBinCount, /* ret max count for regular bin */ + int *totUnbinned, /* ret tot num of e's not binned */ + int *maxDepth) /* ret max bin array depth */ +{ + Rect *bbox = &ba->ba_bbox; + int dx = ba->ba_dx; + int dy = ba->ba_dy; + int numBins = ba->ba_numBins; + int dimX = ba->ba_dimX; + int dimY = numBins/dimX; + int w = GEO_WIDTH(bbox); + int h = GEO_HEIGHT(bbox); + + /* initial statistics */ + unsigned int mem = 0; + int tot = 0; + int bins = 0; + int emptys = 0; + int binArrays = 1; + int maxCount = 0; + int maxEff = 0; + int maxEffSub = 0; + int maxSubCount = 0; + int unbinned = 0; + int depth = 1; + int maxDepthSub = 0; + int i; + + /* add bins in this array */ + bins += numBins; + + /* add memory usage for this array (sub arrays already tabulated) */ + if(ba) mem += sizeof(BinArray) + numBins*sizeof(void*); + + /* gather stats bin by bin */ + for(i=0;imaxCount) maxCount = count; + if(count==0) emptys++; + } + else + { + /* arrayed, recurse */ + int sMem, sTot, sBins, sEmptys, sBinArrays; + int sMaxEff, sMaxCount, sUnbinned, sDepth; + + sMem = bpStatBA(bpSubArray(ba,i), + &sTot, /* total number of elements */ + &sBins, /* ret tot num of bins */ + &sEmptys, /* ret num of empty bins */ + &sBinArrays, /* ret num bin arrays */ + &sMaxEff, /* ret max effective list length */ + &sMaxCount, /* ret max count for regular bin */ + &sUnbinned, /* ret tot num of e's not binned */ + &sDepth); /* ret max bin array depth */ + + mem += sMem; + tot += sTot; + bins += sBins; + emptys += sEmptys; + binArrays += sBinArrays; + if(sMaxEff > maxEffSub) maxEffSub = sMaxEff; + if(sMaxCount > maxCount) maxCount = sMaxCount; + if(sUnbinned > maxCount) maxCount = sUnbinned; + if(sDepth > maxDepthSub) maxDepthSub = sDepth; + } + } + + maxEff += MAX(maxCount,maxEffSub); + depth += maxDepthSub; + + /* oversized */ + if(bpBinType(ba,numBins) != BT_ARRAY) + { + /* oversized unbinned */ + int over = bpCount(bpBinList(ba,numBins)); + tot += over; + unbinned += over; + maxEff += over; + } + else + { + /* oversized is arrayed, recurse */ + int sMem, sTot, sBins, sEmptys, sBinArrays; + int sMaxEff, sMaxCount, sUnbinned, sDepth; + + sMem = bpStatBA(bpSubArray(ba,numBins), + &sTot, /* total number of elements */ + &sBins, /* ret tot num of bins */ + &sEmptys, /* ret num of empty bins */ + &sBinArrays, /* ret num bin arrays */ + &sMaxEff, /* ret max effective list length */ + &sMaxCount, /* ret max count for regular bin */ + &sUnbinned, /* ret tot num of e's not binned */ + &sDepth); /* ret max bin array depth */ + + mem += sMem; + tot += sTot; + bins += sBins; + emptys += sEmptys; + binArrays += sBinArrays; + maxEff += sMaxEff; + if(sMaxCount > maxCount) maxCount = sMaxCount; + unbinned += sUnbinned; + depth += sDepth; + } + + /* set results */ + if(totCount) *totCount = tot; + if(totBins) *totBins = bins; + if(emptyBins) *emptyBins = emptys; + if(binArraysp) *binArraysp = binArrays; + if(maxEffp) *maxEffp = maxEff; + if(maxBinCount) *maxBinCount = maxCount; + if(totUnbinned) *totUnbinned = unbinned; + if(maxDepth) *maxDepth = depth; + + return mem; +} + +/* + * ---------------------------------------------------------------------------- + * BPStat -- + * + * compute bplane statistics. + * + * Returns memory used by bplane (excluding elements) + * + * ---------------------------------------------------------------------------- + */ +unsigned int BPStat(BPlane *bp, + int *totCount, /* total number of elements */ + int *inBox, /* ret num of elements in inBox */ + int *totBins, /* ret tot num of bins */ + int *emptyBins, /* ret num of empty bins */ + int *binArraysp, /* ret tot num of bin arrays */ + int *maxEffp, /* ret max effective list length */ + int *maxBinCount, /* ret max count for regular bin */ + int *totUnbinned, /* ret tot num of e's not binned */ + int *maxDepth) /* ret max bin array depth */ +{ + BinArray *ba = bp->bp_rootNode; + int numBins; + unsigned int mem = 0; + int tot = 0; + int bins = 0; + int emptys = 0; + int binArrays = 0; + int maxEff = 0; + int maxCount = 0; + int unbinned = 0; + int depth = 0; + int in; + + /* bin arrays */ + if(ba) + { + mem += bpStatBA(bp->bp_rootNode, + &tot, /* total number of elements */ + &bins, /* ret tot num of bins */ + &emptys, /* ret tot num of empty bins */ + &binArrays, /* ret tot num of bin arrays */ + &maxEff, /* ret max effective list length */ + &maxCount, /* ret max count for regular bin */ + &unbinned, /* ret tot num of e's not binned */ + &depth); /* ret max bin array depth */ + } + + /* inbox */ + in = bpCount(bp->bp_inBox); + tot += in; + maxEff += in; + unbinned += in; + + /* add in memory usage for bplane */ + mem += sizeof(BPlane); + mem += IHashStats2(bp->bp_hashTable,NULL,NULL); + + /* set results */ + if(totCount) *totCount = tot; + if(inBox) *inBox = in; + if(totBins) *totBins = bins; + if(emptyBins) *emptyBins = emptys; + if(binArraysp) *binArraysp = binArrays; + if(maxEffp) *maxEffp = maxEff; + if(maxBinCount) *maxBinCount = maxCount; + if(totUnbinned) *totUnbinned = unbinned; + if(maxDepth) *maxDepth = depth; + + return mem; +} + + +/* + * ---------------------------------------------------------------------------- + * BPStatMemory -- + * + * returns memory usage of BPlane in bytes + * (exclusive of elements contained by the BPlane) + * + * ---------------------------------------------------------------------------- + */ +unsigned int BPStatMemory(BPlane *bp) +{ + return BPStat(bp, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); +} + diff --git a/bplane/bpTest.c b/bplane/bpTest.c new file mode 100644 index 00000000..82c4f131 --- /dev/null +++ b/bplane/bpTest.c @@ -0,0 +1,361 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +/* bpTest.c + * + * (regression) tests of bplane code + * + */ + +#include +#include +#include "utils.h" +#include "message.h" +#include "database.h" +#include "geometry.h" +#include "bplane.h" +#include "bplaneInt.h" +#include "debug.h" +#include "cifInt.h" + + +/* + * elements used by test code. + */ +typedef struct rectc +{ + struct rectc *rc_links[BP_NUM_LINKS]; + Rect rc_rect; +} RectC; + + +/* + * ---------------------------------------------------------------------------- + * bpRand -- + * generate a random int in given range. + * + * side effects: sets coords of input rect. + * ---------------------------------------------------------------------------- + */ +int bpRand(int min, int max) +{ + double f = rand()/ (double) RAND_MAX; /* random number in unit interval */ + return min + (int) ((max-min+1)*f); +} + +/* + * ---------------------------------------------------------------------------- + * bpTestRandRect -- + * generate a random unit rectangle inside bbox + * + * side effects: sets coords of input rect. + * ---------------------------------------------------------------------------- + */ +static void bpTestRandRect(Rect *r, Rect *bbox) +{ + r->r_xbot = bpRand(bbox->r_xbot,bbox->r_xtop-1); + r->r_ybot = bpRand(bbox->r_ybot,bbox->r_ytop-1); + r->r_xtop = r->r_xbot+1; + r->r_ytop = r->r_ybot+1; +} + +/* ====== GOLD snow test. + * ====== linked list implementation (to determine 'right' answer) + */ + +/* + * ---------------------------------------------------------------------------- + * bpTestIntersectGold -- + * + * check whether rc intersects list + * ---------------------------------------------------------------------------- + */ +static bool bpTestIntersectGold(RectC *rc, RectC *list) +{ + while(list) + { + if(GEO_TOUCH(&rc->rc_rect,&list->rc_rect)) return TRUE; + list=list->rc_links[0]; + } + return FALSE; +} + +/* + * ---------------------------------------------------------------------------- + * bpTestSnowGold -- + * populate square of dimension 'size' with non-overlapping random unit + * rectangles. Keep adding rectangles until failures exceed successes. + * (stop when maxFailures reached.) + * + * coded with simple linked list. + * + * ---------------------------------------------------------------------------- */ +void bpTestSnowGold(int size, bool trace) +{ + int failures = 0; + int successes = 0; + int i = 0; + int crc = 0; + RectC *result = NULL; + RectC *rc = NULL; + Rect area; + + fprintf(stderr,"BEGIN Snow GOLD, size=%d\n", size); + + /* set up area */ + area.r_xbot = 0; + area.r_ybot = 0; + area.r_xtop = size; + area.r_ytop = size; + + while(failures<=successes) + { + i++; + + if(!rc) rc = MALLOC_TAG(RectC *,rc, sizeof(RectC), "RectC"); + bpTestRandRect(&rc->rc_rect, &area); + + if(!bpTestIntersectGold(rc,result)) + { + if(trace) DumpRect("success ",&rc->rc_rect); + crc ^= i+ 3*rc->rc_rect.r_xbot+ 5*rc->rc_rect.r_ybot; + + rc->rc_links[0] = result; + result = rc; + rc = NULL; + + successes++; + } + else + { + if(trace) DumpRect("failure ",&rc->rc_rect); + + failures++; + } + } + + /* clean up */ + while(result) + { + /* pop */ + rc=result; + result=rc->rc_links[0]; + + /* free */ + FREE(rc); + } + + fprintf(stderr,"END Snow GOLD, size=%d failures=%d successes=%d crc=%d\n", + size, + failures, + successes, + crc); +} + +/* ====== bplane snow test. + */ + +/* + * ---------------------------------------------------------------------------- + * bpTestIntersect -- + * + * check whether rc intersects list + * ---------------------------------------------------------------------------- + */ +static bool bpTestIntersect(RectC *rc, BPlane *bp) +{ + BPEnum bpe; + int result; + + BPEnumInit(&bpe,bp, &rc->rc_rect, BPE_TOUCH,"bpTestIntersect"); + result = (BPEnumNext(&bpe)!=NULL); + BPEnumTerm(&bpe); + + return result; +} + +/* + * ---------------------------------------------------------------------------- + * bpTestSnow -- + * populate area with non-overlapping random unit rectangles. + * + * using bplane. + * + * ---------------------------------------------------------------------------- + */ +BPlane *bpTestSnow(int size, bool trace) +{ + int failures = 0; + int successes = 0; + int i = 0; + int crc = 0; + RectC *result = NULL; + RectC *rc = NULL; + BPlane *bp = BPNew(); + Rect area; + + fprintf(stderr,"BEGIN Snow, size=%d\n", size); + + /* set up area */ + area.r_xbot = 0; + area.r_ybot = 0; + area.r_xtop = size; + area.r_ytop = size; + + while(failures<=successes) + { + i++; + + if(!rc) rc = MALLOC_TAG(RectC *,rc, sizeof(RectC), "RectC"); + bpTestRandRect(&rc->rc_rect, &area); + + if(!bpTestIntersect(rc,bp)) + { + if(trace) DumpRect("success ",&rc->rc_rect); + crc ^= i+ 3*rc->rc_rect.r_xbot+ 5*rc->rc_rect.r_ybot; + + BPAdd(bp,rc); + rc = NULL; + + successes++; + } + else + { + if(trace) DumpRect("failure ",&rc->rc_rect); + failures++; + } + } + + fprintf(stderr,"END Snow, size=%d failures=%d success=%d crc=%d\n", + size, + failures, + successes, + crc); + + return bp; +} + +/* ====== Tile Plane based snow test. + */ + +/* + * ---------------------------------------------------------------------------- + * bpTestIntersectTile -- + * + * check whether r intersects existing tiles + * + * ---------------------------------------------------------------------------- + */ + +int bpTestIntersectTileFunc(Tile *tile, ClientData cd) +{ + return 1; +} + +static bool bpTestIntersectTile(Rect *r, Plane *plane) +{ + Rect area; + + /* catch touching tiles */ + area = *r; + area.r_xbot -= 1; + area.r_ybot -= 1; + + area.r_xtop += 1; + area.r_ytop += 1; + + return DBPlaneEnumAreaPaint((Tile *) NULL, + plane, + &area, + &DBAllButSpaceBits, + bpTestIntersectTileFunc, + NULL); +} + +/* + * ---------------------------------------------------------------------------- + * bpTestSnowTile -- + * populate area with non-overlapping random unit rectangles. + * + * using tile plane + * + * ---------------------------------------------------------------------------- + */ +Plane *bpTestSnowTile(int size, bool trace) +{ + int failures = 0; + int successes = 0; + int i = 0; + int crc = 0; + RectC *result = NULL; + RectC *rc = NULL; + Plane *plane = DBPlaneNew((ClientData) TT_SPACE); + Rect area; + + fprintf(stderr,"BEGIN Snow Tile, size=%d\n", size); + + /* set up area */ + area.r_xbot = 0; + area.r_ybot = 0; + area.r_xtop = size; + area.r_ytop = size; + + while(failures<=successes) + { + Rect r; + + i++; + bpTestRandRect(&r, &area); + + if(!bpTestIntersectTile(&r,plane)) + { + if(trace) DumpRect("success ",&r); + crc ^= i+ 3*r.r_xbot + 5*r.r_ybot; + + DBPaintPlane(plane, &r, CIFPaintTable, (PaintUndoInfo *) NULL); + rc = NULL; + + successes++; + } + else + { + if(trace) DumpRect("failure ",&r); + failures++; + } + } + + fprintf(stderr,"END Snow Tile, size=%d failures=%d success=%d crc=%d\n", + size, + failures, + successes, + crc); + + return plane; +} + diff --git a/bplane/bpUtils.c b/bplane/bpUtils.c new file mode 100644 index 00000000..209a9f7c --- /dev/null +++ b/bplane/bpUtils.c @@ -0,0 +1,77 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + + +/* bpUtils.c -- + * + * shared low-level routines for this module. + * + */ + +#include +#include "utils/utils.h" +#include "database/database.h" +#include "utils/geometry.h" +#include "bplane/bplaneInt.h" + + +/* + * ---------------------------------------------------------------------------- + * bpRectDim -- + * + * return dimension of rectangle in xDir + * + * ---------------------------------------------------------------------------- + */ +int bpRectDim(Rect *r, bool xDir) +{ + return xDir ? r->r_xtop - r->r_xbot : r->r_ytop - r->r_ybot; +} + +/* + * ---------------------------------------------------------------------------- + * bpBinIndices -- + * + * compute bin indices corresponding to area. + * + * ---------------------------------------------------------------------------- + */ +static __inline__ void +bpBinIndices(Rect area, /* area */ + Rect binArea, /* lower left corner of bin system */ + int indexBits, + int dim, + bool xDir, /* TRUE for x bin, FALSE for y bin */ + int *min, /* results go here */ + int *max) +{ + int ref, coord; + int index; + +} diff --git a/bplane/bplane.h b/bplane/bplane.h new file mode 100644 index 00000000..cf6dfe1f --- /dev/null +++ b/bplane/bplane.h @@ -0,0 +1,246 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +#ifndef _BPLANE_H +#define _BPLANE_H + +/* + * bplane.h -- + * + * This file defines the interface between the bplane + * module and the rest of max. + * + * BUGS + * ==== + * + * NOTE nested enums are currently broken do to dynamic binning. + * + * OVERVIEW OF BPLANES + * =================== + * + * BPlanes ('Binned' Planes) are a data-structure for storing, sorting, + * and accessing two dimensional geometric objects. + * + * BPlanes are an alternative to Planes, i.e. corner-stitched tile planes, + * defined in the tile module. + * + * Differences between Planes and BPlanes: + * -------------------------------------- + * + * 1. BPlanes are more memory efficient. + * Three pointers (+ a modest amount of binning overhead) + * replaces approximately 8 pointers (4/tile, approx. 1 space + * tile for each data tile). + * + * 2. BPlanes use a 'next' procedure for enumeration, instead of + * function call-backs. This allows client code to be simpler + * and more readable, partcularly with regard to passing state info. + * In addition gprof results are easier to interpet, since + * there is not confusion about which client procedures belong to + * a given "loop". + * + * 3. Planes fundamentally assume objects don't overlap, while BPlanes + * make no such assumption. This makes BPlanes more generally useful. + * In particular they are a natural choice for instance uses, + * labels, and non-manhattan polygons (sorted on bounding boxes). + * + * 4. Planes are optimized for merging (merging recangles + * into maximal horizontal strips) and neighbor access + * (finding nearest elements to current element). BPlanes are less + * efficient for these operations. + * + * 5. Planes generally cannot be safely modified during an enumeration, + * but BPlanes can. This makes operations such as delete, copy, and + * move simpler in BPlanes. + * + * Interface + * --------- + * + * 1. The structure of elements to be stored in BPlanes must be as + * follows: + * + * typedef struct foo + * { + * struct void *foo_bpLinks[BP_NUM_LINKS]; + * Rect foo_rect; + * + * } Foo + * + * 2. It is the clients responsiblity to alloc/free elements. + * + * 3. The client must set foo_rect before adding the element + * to a BPlane. foo_rect must be canonical: not inverted. + * + * 4. The BPlane module does not access or modify any client fields. + * + * 5. The client may access/modify client fields at any time. + * + * 6. As long as an element belongs to a BPlane (i.e. has been + * added via BPAdd() and not removed via BPDelete()): + * + * a. The client should not reference/modify the foo_bpLinks[] fields. + * b. The client may reference but should not modify the foo_rect + * field. + * c. The client should not call BPAdd() for the element + * (an element can only belong to one BPlane at at time). + * d. The client should not free the element! + * + * 7. The client may assume tht BP_NUM_LINKS is at least one, and + * may use foo_bpLinks[0], for his own purposes as long as an + * element does not belong to a bplane. + * + * 8. Concurrent (nested) enumerations of a bplane are permitted. + * + * 9. Elements may not be added to a bplane during active enumeration(s) + * on that bplane. + * + * 10. An element may be deleted from a bplane at any time, including + * during active enumeration(s) of that bplane. After an element + * has been deleted from a bplane, it will not be enumerated + * (i.e. returned by BPEnumNext() on that bplane). + * + * Example + * ------- + * + * Here is a procedure that takes an array of id'ed rectangles and an + * area as input, and prints the ids of all rectangles impinging on the + * area. + * + * typedef struct rid + * { + * struct rid *rid_bpLinks[BP_NUM_LINKS]; + * Rect rid_rect; + * char *rid_id; + * } RId; + * + * void findRects(RId data[], // ided rects + * int n, // number of rects in data + * Rect *area) // area to search + * { + * int i; + * BPEnum bpe; + * BPlane *bp; + * RId *rid; + * + * bp = BPNew(); + * for(i=0;irid_id); + * } + * BPEnumTerm(&bpe); + * + */ + +/* offset of a structure member (used to gen offsets for ihash stuff) */ +#if _MSC_VER +/* Microsoft compile complains about size of (void*), so must use (char*) */ +/* Could use (char*) in UNIX version too. */ +#define OFFSET(structure,member) \ +( ((char *) &(((structure *) 0))->member) - ((char *) 0) ) +#else +#define OFFSET(structure,member) \ +( ((void *) &(((structure *) 0))->member) - ((void *) 0) ) +#endif + +/* data-structures opaque to clients */ +#include "bplane/bpOpaque.h" + +/* create a new BPlane */ +extern BPlane *BPNew(void); + +/* free storate assoicated with a BPlane + * (The BPlane must be empty.) + */ +extern void BPFree(BPlane *bp); + +/* add an element to a BPlane */ +extern void BPAdd(BPlane *bp, + void *element); + +/* remove an element from a BPlane */ +extern void BPDelete(BPlane *bp, + void *element); + +/* begin an enumeration */ +extern void BPEnumInit(BPEnum *bpe, /* this procedure initializes this + * client supplied 'handle' for the + * enumeration. + */ + BPlane *bp, /* bplane to search */ + Rect *area, /* area to search */ + int match, /* see below */ + char *id); /* for debugging */ +/* match values */ + + /* enum all elements in the bplane (area arg must be null) */ +#define BPE_ALL 0 + /* element need only touch area */ +#define BPE_TOUCH 1 + /* some part of element must be inside (not just on boundary of) area */ +#define BPE_OVERLAP 2 + /* elements rect must be identical to area */ +#define BPE_EQUAL 3 + +/* return next element in enumeration (returns NULL if none) */ +#include "bplane/bpEnum.h" +/* inlined extern void *BPEnumNext(BPEnum *bpe); */ + +/* terminate enumeration + * + * (unterminated enumerations can cause great inefficiency since + * all active enumerations for a bplane must be considered whenever + * an element is added or deleted.) + */ +extern void BPEnumTerm(BPEnum *bpe); + +/* get current bounding box of BPlane */ +extern Rect BPBBox(BPlane *bp); + +/* compute number of bytes used by BPlane + * (does not count memory of the elements themselves) + */ +extern unsigned int BPStatMemory(BPlane *bp); + +/* tabulate statistics on a bplane */ +extern unsigned int +BPStat(BPlane *bp, + int *totCount, /* ret total number of elements */ + int *inBox, /* ret num of elements in inBox */ + int *totBins, /* ret tot num of bins */ + int *emptyBins, /* ret num of empty bins */ + int *binArraysp, /* ret num of bin arrays */ + int *maxEffp, /* ret max effective list length */ + int *maxBinCount, /* ret max count for regular bin */ + int *totUnbinned, /* ret tot num of e's not binned */ + int *maxDepth); /* ret max bin array depth */ + +#endif /* _BPLANE_H */ diff --git a/bplane/bplaneInt.h b/bplane/bplaneInt.h new file mode 100644 index 00000000..05814216 --- /dev/null +++ b/bplane/bplaneInt.h @@ -0,0 +1,82 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +/* + * bplaneInt.h -- + * + * This file defines constants and datastructures used internally by the + * bplane module, but not exported to the rest of the world. + */ +#ifndef _BPLANEINT_H +#define _BPLANEINT_H + +/* Tcl linked Parameters */ +extern int bpMinBAPop; /* don't sub(bin) when count less than this + */ +extern double bpMinAvgBinPop; /* try to keep average bin pop at or + * below this + */ + +/* LabeledElement + * + * Used in this module as elements for test bplanes. + */ +typedef struct labeledelement +{ + struct element *le_links[BP_NUM_LINKS]; + Rect le_rect; + /* client data goes here */ + char * le_text; +} LabeledElement; + +/* bins */ +extern void bpBinsUpdate(BPlane *bp); + +extern void bpBinAdd(BinArray *ba, Element *e); + +extern BinArray *bpBinArrayBuild(Rect bbox, + Element *elements, /* initial elements */ + bool subbin); /* subbin as needed */ + +/* dump (for debug) */ +extern void bpDumpRect(Rect *r); +extern void bpDump(BPlane *bp, int flags); +/* bpDump flags */ +/* labeled elements */ +# define BPD_LABELED 1 +# define BPD_INTERNAL_UNITS 2 + +/* test */ +void bpTestSnowGold(int size, bool trace); +extern BPlane *bpTestSnow(int size, bool trace); +extern Plane *bpTestSnowTile(int size, bool trace); + +extern int bpRand(int min, int max); + +#endif /* _BPLANEINT_H */ diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 65db84f9..e81c3965 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -3678,7 +3678,7 @@ cmdDumpParseArgs(cmdName, w, cmd, dummy, scx) Point childPoint, editPoint, rootPoint; CellDef *def, *rootDef, *editDef; bool hasChild, hasRoot, hasTrans; - Rect rootBox; + Rect rootBox, bbox; Transform *tx_cell, trans_cell; char **av; char *cellnameptr, *fullpathname; @@ -3792,6 +3792,25 @@ cmdDumpParseArgs(cmdName, w, cmd, dummy, scx) return FALSE; } + /* + * Get def's bounding box. If def is an abstract view with CDFIXEDBBOX + * set, then used the property FIXED_BBOX to set the bounding box. + */ + bbox = def->cd_bbox; + if (def->cd_flags & CDFIXEDBBOX) + { + char *propvalue; + bool found; + + propvalue = DBPropGet(def, "FIXED_BBOX", &found); + if (found) + { + if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, + &bbox.r_xtop, &bbox.r_ytop) != 4) + bbox = def->cd_bbox; + } + } + /* * Parse the remainder of the arguments to find out the reference * points in the child cell and the edit cell. Use the defaults @@ -3843,23 +3862,23 @@ cmdDumpParseArgs(cmdName, w, cmd, dummy, scx) p = Lookup(av[1], refPointNames); if (p == 0) /* lower left */ { - childPoint.p_x = def->cd_bbox.r_ll.p_x; - childPoint.p_y = def->cd_bbox.r_ll.p_y; + childPoint.p_x = bbox.r_ll.p_x; + childPoint.p_y = bbox.r_ll.p_y; } else if (p == 1) /* lower right */ { - childPoint.p_x = def->cd_bbox.r_ur.p_x; - childPoint.p_y = def->cd_bbox.r_ll.p_y; + childPoint.p_x = bbox.r_ur.p_x; + childPoint.p_y = bbox.r_ll.p_y; } else if (p == 2) /* upper left */ { - childPoint.p_x = def->cd_bbox.r_ll.p_x; - childPoint.p_y = def->cd_bbox.r_ur.p_y; + childPoint.p_x = bbox.r_ll.p_x; + childPoint.p_y = bbox.r_ur.p_y; } else if (p == 3) /* upper right */ { - childPoint.p_x = def->cd_bbox.r_ur.p_x; - childPoint.p_y = def->cd_bbox.r_ur.p_y; + childPoint.p_x = bbox.r_ur.p_x; + childPoint.p_y = bbox.r_ur.p_y; } else { @@ -3960,9 +3979,9 @@ default_action: { Rect r; - GeoTransRect(tx_cell, &def->cd_bbox, &r); - GeoTranslateTrans(tx_cell, def->cd_bbox.r_xbot - r.r_xbot, - def->cd_bbox.r_ybot - r.r_ybot, + GeoTransRect(tx_cell, &bbox, &r); + GeoTranslateTrans(tx_cell, bbox.r_xbot - r.r_xbot, + bbox.r_ybot - r.r_ybot, &trans_cell); } av += 1; @@ -3991,23 +4010,23 @@ default_action: p = Lookup(av[1], refPointNames); if (p == 0) /* lower left */ { - editPoint.p_x = def->cd_bbox.r_ll.p_x; - editPoint.p_y = def->cd_bbox.r_ll.p_y; + editPoint.p_x = bbox.r_ll.p_x; + editPoint.p_y = bbox.r_ll.p_y; } else if (p == 1) /* lower right */ { - editPoint.p_x = def->cd_bbox.r_ur.p_x; - editPoint.p_y = def->cd_bbox.r_ll.p_y; + editPoint.p_x = bbox.r_ur.p_x; + editPoint.p_y = bbox.r_ll.p_y; } else if (p == 2) /* upper left */ { - editPoint.p_x = def->cd_bbox.r_ll.p_x; - editPoint.p_y = def->cd_bbox.r_ur.p_y; + editPoint.p_x = bbox.r_ll.p_x; + editPoint.p_y = bbox.r_ur.p_y; } else if (p == 3) /* upper right */ { - editPoint.p_x = def->cd_bbox.r_ur.p_x; - editPoint.p_y = def->cd_bbox.r_ur.p_y; + editPoint.p_x = bbox.r_ur.p_x; + editPoint.p_y = bbox.r_ur.p_y; } else { @@ -4073,7 +4092,7 @@ default_action: * provided. */ if (!hasChild) - childPoint = def->cd_bbox.r_ll; + childPoint = bbox.r_ll; if (!hasRoot) { if (!ToolGetBox(&rootDef, &rootBox)) @@ -4102,7 +4121,7 @@ box_error: GeoTranslateTrans(&trans_cell, rootPoint.p_x - childPoint.p_x, rootPoint.p_y - childPoint.p_y, &scx->scx_trans); - scx->scx_area = def->cd_bbox; + scx->scx_area = bbox; return TRUE; usage: diff --git a/commands/CmdFI.c b/commands/CmdFI.c index 8669ea3c..c1568efc 100644 --- a/commands/CmdFI.c +++ b/commands/CmdFI.c @@ -1635,7 +1635,8 @@ CmdFindNetProc(nodename, use, rect, warn_not_found) /* Find the tile type of the tile at the specified point which */ /* exists on the plane pnum. */ - (void) TiSrArea(NULL, plane, &localrect, findTile, (ClientData) &ttype); + DBSrPaintArea(NULL, plane, &localrect, &DBAllTypeBits, findTile, + (ClientData) &ttype); } else { diff --git a/commands/CmdWizard.c b/commands/CmdWizard.c index 7d03c706..9cc4b0d5 100644 --- a/commands/CmdWizard.c +++ b/commands/CmdWizard.c @@ -832,7 +832,7 @@ cmdPsearchStats(str, tl, td, count) * * CmdTsearch -- * - * Call TiSrArea() a number of times over an area the size and shape of + * Call DBSrPaintArea() a number of times over an area the size and shape of * that specified by the box, each time over a different area in the * edit cell. * @@ -943,18 +943,12 @@ CmdTsearch(w, cmd) if (cmd->tx_argc < 5) { - (void) TiSrArea((Tile *) NULL, plane, &rsearch, + (void) DBSrPaintArea((Tile *) NULL, plane, &rsearch, &DBAllTypeBits, cmdTsrFunc, (ClientData) 0); } else { - /**** - if (strcmp(cmd->tx_argv[4], "mayo") == 0) - (void) TiSrAreaNR2((Tile *) NULL, plane, &rsearch, &mask, - cmdTsrFunc, (ClientData) 0); - else - ****/ - (void) DBSrPaintArea((Tile *) NULL, plane, &rsearch, &mask, + (void) DBSrPaintArea((Tile *) NULL, plane, &rsearch, &mask, cmdTsrFunc, (ClientData) 0); } } diff --git a/database/DBbound.c b/database/DBbound.c index 74ab4950..72ebc2b5 100644 --- a/database/DBbound.c +++ b/database/DBbound.c @@ -58,48 +58,38 @@ DBBoundCellPlane(def, extended, rect) cbs.found = FALSE; *rect = GeoNullRect; - if (TiSrArea((Tile *)NULL, def->cd_planes[PL_CELL], - &TiPlaneRect, dbCellBoundFunc, (ClientData) &filter) == 0) + if (DBSrCellPlaneArea(def->cd_cellPlane, &TiPlaneRect, + dbCellBoundFunc, (ClientData) &filter) == 0) return cbs.found; else return -1; } int -dbCellBoundFunc(tile, fp) - Tile *tile; +dbCellBoundFunc(use, fp) + CellUse *use; TreeFilter *fp; { - CellUse *use; - CellTileBody *body; Rect *bbox; DBCellBoundStruct *cbs; cbs = (DBCellBoundStruct *)fp->tf_arg; - for (body = (CellTileBody *) TiGetBody(tile); body != NULL; - body = body->ctb_next) + bbox = &use->cu_bbox; + if (cbs->found) { - use = body->ctb_use; - bbox = &use->cu_bbox; - if ((BOTTOM(tile) <= bbox->r_ybot) && (RIGHT(tile) >= bbox->r_xtop)) - { - if (cbs->found) - { - if (cbs->extended) - GeoInclude(&use->cu_extended, cbs->area); - else - GeoInclude(&use->cu_bbox, cbs->area); - } - else - { - if (cbs->extended) - *cbs->area = use->cu_extended; - else - *cbs->area = use->cu_bbox; - cbs->found = TRUE; - } - } + if (cbs->extended) + GeoInclude(&use->cu_extended, cbs->area); + else + GeoInclude(&use->cu_bbox, cbs->area); + } + else + { + if (cbs->extended) + *cbs->area = use->cu_extended; + else + *cbs->area = use->cu_bbox; + cbs->found = TRUE; } return 0; } diff --git a/database/DBcell.c b/database/DBcell.c index 6ad2ecc0..dcecc482 100644 --- a/database/DBcell.c +++ b/database/DBcell.c @@ -45,7 +45,7 @@ struct searchArg { CellUse * celluse; Rect * rect; - Plane * plane; + BPlane * bplane; }; #define TOPLEFT 10 @@ -55,6 +55,25 @@ struct searchArg #define TOPBOTTOMLEFTRIGHT 15 int dbCellDebug = 0; + +void +dbInstanceUnplace(CellUse *use) +{ + ASSERT(use != (CellUse *) NULL, "dbInstanceUnplace"); + + /* It's important that this code run with interrupts disabled, + * or else we could leave the subcell tile plane in a weird + * state. + */ + SigDisableInterrupts(); + + BPDelete(use->cu_parent->cd_cellPlane, use); + DBUndoCellUse(use, UNDO_CELL_DELETE); + + SigEnableInterrupts(); +} + + /* * ---------------------------------------------------------------------------- @@ -86,28 +105,18 @@ DBCellFindDup(use, parent) * something identical to use? */ { - Tile *tile; - CellTileBody *body; - CellUse *checkUse; + BPEnum bpe; + CellUse *dupUse; - tile = TiSrPoint((Tile *) NULL, parent->cd_planes[PL_CELL], - &use->cu_bbox.r_ll); - - for (body = (CellTileBody *) TiGetBody(tile); - body != NULL; - body = body->ctb_next) - { - checkUse = body->ctb_use; - if (use->cu_def != checkUse->cu_def) continue; - if ((use->cu_bbox.r_xbot != checkUse->cu_bbox.r_xbot) - || (use->cu_bbox.r_xtop != checkUse->cu_bbox.r_xtop) - || (use->cu_bbox.r_ybot != checkUse->cu_bbox.r_ybot) - || (use->cu_bbox.r_ytop != checkUse->cu_bbox.r_ytop)) - continue; - return checkUse; - } - return (CellUse *) NULL; + BPEnumInit(&bpe, parent->cd_cellPlane, &use->cu_bbox, BPE_EQUAL, + "DBCellFindDup"); + while (dupUse = BPEnumNext(&bpe)) + if (dupUse->cu_def == use->cu_def) break; + + BPEnumTerm(&bpe); + return dupUse; } + /* * ---------------------------------------------------------------------------- @@ -130,33 +139,30 @@ DBCellFindDup(use, parent) */ void -DBPlaceCell (celluse, targetcell) - CellUse * celluse; /* new celluse to add to subcell tile plane */ - CellDef * targetcell; /* parent cell's definition */ +DBPlaceCell (use, def) + CellUse * use; /* new celluse to add to subcell tile plane */ + CellDef * def; /* parent cell's definition */ { - Rect rect; /* argument to TiSrArea(), placeCellFunc() */ - Plane * plane; /* argument to TiSrArea(), placeCellFunc() */ - struct searchArg arg; /* argument to placeCellFunc() */ + Rect rect; /* argument to DBSrCellPlaneArea(), placeCellFunc() */ + BPlane *bplane; /* argument to DBSrCellPlaneArea(), placeCellFunc() */ + struct searchArg arg; /* argument to placeCellFunc() */ - ASSERT(celluse != (CellUse *) NULL, "DBPlaceCell"); - celluse->cu_parent = targetcell; - plane = targetcell->cd_planes[PL_CELL]; /* assign plane */ - rect = celluse->cu_bbox; - /* rect = celluse->cu_extended; */ - arg.rect = ▭ - arg.celluse = celluse; - arg.plane = plane; + ASSERT(use != (CellUse *) NULL, "DBPlaceCell"); + ASSERT(def, "DBPlaceCell"); + + /* To do: Check non-duplicate placement, check non-duplicate ID */ + + use->cu_parent = def; /* Be careful not to permit interrupts during this, or the * database could be left in a trashed state. */ SigDisableInterrupts(); - (void) TiSrArea((Tile *) NULL, plane, &rect, placeCellFunc, - (ClientData) &arg); - targetcell->cd_flags |= CDMODIFIED|CDGETNEWSTAMP; + BPAdd(def->cd_cellPlane, use); + def->cd_flags |= CDMODIFIED|CDGETNEWSTAMP; if (UndoIsEnabled()) - DBUndoCellUse(celluse, UNDO_CELL_PLACE); + DBUndoCellUse(use, UNDO_CELL_PLACE); SigEnableInterrupts(); } @@ -176,19 +182,12 @@ DBPlaceCell (celluse, targetcell) */ void -DBDeleteCell (celluse) - CellUse * celluse; +DBDeleteCell (use) + CellUse * use; { - Rect rect; /* argument to TiSrArea(), deleteCellFunc() */ - Plane * plane; /* argument to TiSrArea(), deleteCellFunc() */ - struct searchArg arg; /* argument to deleteCellFunc() */ + ASSERT(use != (CellUse *) NULL, "DBDeleteCell"); - ASSERT(celluse != (CellUse *) NULL, "DBDeleteCell"); - plane = celluse->cu_parent->cd_planes[PL_CELL]; /* assign plane */ - rect = celluse->cu_bbox; - arg.rect = ▭ - arg.plane = plane; - arg.celluse = celluse; + dbInstanceUnplace(use); /* It's important that this code run with interrupts disabled, * or else we could leave the subcell tile plane in a weird @@ -196,511 +195,10 @@ DBDeleteCell (celluse) */ SigDisableInterrupts(); - (void) TiSrArea((Tile *) NULL, plane, &rect, deleteCellFunc, - (ClientData) &arg); - celluse->cu_parent->cd_flags |= CDMODIFIED|CDGETNEWSTAMP; + use->cu_parent->cd_flags |= CDMODIFIED|CDGETNEWSTAMP; if (UndoIsEnabled()) - DBUndoCellUse(celluse, UNDO_CELL_DELETE); - celluse->cu_parent = (CellDef *) NULL; + DBUndoCellUse(use, UNDO_CELL_DELETE); + use->cu_parent = (CellDef *) NULL; SigEnableInterrupts(); } - -/* - * ---------------------------------------------------------------------------- - * placeCellFunc -- - * - * Add a new subcell to a tile. - * Clip the tile with respect to the subcell's bounding box. - * Insert the new CellTileBody into the linked list in ascending order - * based on the celluse pointer. - * This function is passed to TiSrArea. - * - * Results: - * 0 is always returned. - * - * Side effects: - * Modifies the subcell tile plane of the appropriate CellDef. - * Allocates a new CellTileBody. - * ---------------------------------------------------------------------------- - */ -int -placeCellFunc (tile, arg) - Tile * tile; /* target tile */ - struct searchArg * arg; /* celluse, rect, plane */ -{ - Tile * tp; - CellTileBody * body, * ctp, * ctplast; - -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("placeCellFunc called %x\n",tile); -#endif /* CELLDEBUG */ - - tp = clipCellTile (tile, arg->plane, arg->rect); - - body = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody))); - body->ctb_use = arg->celluse; - - ctp = (CellTileBody *) tp->ti_body; - ctplast = ctp; - while ((ctp != (CellTileBody *) NULL) && (ctp->ctb_use > body->ctb_use)) - { - ctplast = ctp; - ctp = ctp->ctb_next; - } - body->ctb_next = ctp; - - if (ctp == (CellTileBody *) tp->ti_body) /* empty list or front of list */ - TiSetBody(tp, body); - else /* after at least one CellTileBody */ - ctplast->ctb_next = body; - -/* merge tiles back into the the plane */ -/* requires that TiSrArea visit tiles in NW to SE wavefront */ - - if ( RIGHT(tp) == arg->rect->r_xtop) - { - if (BOTTOM(tp) == arg->rect->r_ybot) - cellTileMerge (tp, arg->plane, TOPBOTTOMLEFTRIGHT); - else - cellTileMerge (tp, arg->plane, TOPLEFTRIGHT); - } - else if (BOTTOM(tp) == arg->rect->r_ybot) - cellTileMerge (tp, arg->plane, TOPBOTTOMLEFT); - else - cellTileMerge (tp, arg->plane, TOPLEFT); - return 0; -} - -/* - * ---------------------------------------------------------------------------- - * deleteCellFunc -- - * - * Remove a subcell from a tile. - * This function is passed to TiSrArea. - * - * Results: - * Always returns 0. - * - * Side effects: - * Modifies the subcell tile plane of the appropriate CellDef. - * Deallocates a CellTileBody. - * ---------------------------------------------------------------------------- - */ - -int -deleteCellFunc (tile, arg) - Tile * tile; - struct searchArg * arg; /* plane, rect */ -{ - CellTileBody * ctp; /* CellTileBody to be freed */ - CellTileBody * ctplast; /* follows one behind ctp */ - CellUse * celluse; - -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("deleteCellFunc called %x\n",tile); -#endif /* CELLDEBUG */ - - celluse = arg->celluse; - - /* find the appropriate CellTileBody in the linked list */ - - ctp = (CellTileBody *) tile->ti_body; - ctplast = ctp; - while ((ctp != (CellTileBody *) NULL) && (ctp->ctb_use != celluse)) - { - ctplast = ctp; - ctp = ctp->ctb_next; - } - /* there should have been a match */ - if (ctp == (CellTileBody *) NULL) - { - ASSERT (ctp != (CellTileBody *) NULL, "deleteCellFunc"); - return 0; - } - - - /* relink the list with one CellTileBody deleted */ - if (ctp == ctplast) /* front of list */ - TiSetBody(tile, ctp->ctb_next); - else /* beyond front of list */ - ctplast->ctb_next = ctp->ctb_next; - - freeMagic((char *) ctp); - -/* merge tiles back into the the plane */ -/* requires that TiSrArea visit tiles in NW to SE wavefront */ - - if ( RIGHT(tile) == arg->rect->r_xtop) - { - if (BOTTOM(tile) == arg->rect->r_ybot) - cellTileMerge (tile, arg->plane, TOPBOTTOMLEFTRIGHT); - else - cellTileMerge (tile, arg->plane, TOPLEFTRIGHT); - } - else if (BOTTOM(tile) == arg->rect->r_ybot) - cellTileMerge (tile, arg->plane, TOPBOTTOMLEFT); - else - cellTileMerge (tile, arg->plane, TOPLEFT); - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * clipCellTile -- - * - * Clip the given tile against the given rectangle. - * - * Results: - * Returns a pointer to the clipped tile. - * - * Side effects: - * Modifies the database plane that contains the given tile. - * ---------------------------------------------------------------------------- - */ - -Tile * -clipCellTile (tile, plane, rect) - Tile * tile; - Plane * plane; - Rect * rect; -{ - Tile * newtile; - - if (TOP(tile) > rect->r_ytop) - { -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitY TOP\n"); -#endif /* CELLDEBUG */ - - newtile = TiSplitY (tile, rect->r_ytop); /* no merge */ - dupTileBody (tile, newtile); - } - if (BOTTOM(tile) < rect->r_ybot) - { -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitY BOTTOM\n"); -#endif /* CELLDEBUG */ - - newtile = tile; - tile = TiSplitY (tile, rect->r_ybot); /* no merge */ - dupTileBody (newtile, tile); - } - if (RIGHT(tile) > rect->r_xtop) - { -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitX RIGHT\n"); -#endif /* CELLDEBUG */ - - newtile = TiSplitX (tile, rect->r_xtop); - dupTileBody (tile, newtile); - cellTileMerge (newtile, plane, TOPBOTTOM); - } - if (LEFT(tile) < rect->r_xbot) - { -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitX LEFT\n"); -#endif /* CELLDEBUG */ - - newtile = tile; - tile = TiSplitX (tile, rect->r_xbot); - dupTileBody (newtile, tile); - cellTileMerge (newtile, plane, TOPBOTTOM); - } - return (tile); -} /* clipCellTile */ - -/* - * ---------------------------------------------------------------------------- - * dupTileBody -- - * - * Duplicate the body of an old tile as the body for a new tile. - * - * Results: - * None. - * - * Side effects: - * Allocates new CellTileBodies unless the old tile was a space tile. - * ---------------------------------------------------------------------------- - */ - -void -dupTileBody (oldtp, newtp) - Tile * oldtp; - Tile * newtp; -{ - CellTileBody * oldctb, * newctb, * newctblast; - - oldctb = (CellTileBody *) oldtp->ti_body; - if (oldctb != (CellTileBody *) NULL) - { - newctb = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody))); - TiSetBody(newtp, newctb); - newctb->ctb_use = oldctb->ctb_use; - - oldctb = oldctb->ctb_next; - newctblast = newctb; - - while (oldctb != (CellTileBody *) NULL) - { - newctb = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody))); - newctblast->ctb_next = newctb; - newctb->ctb_use = oldctb->ctb_use; - - oldctb = oldctb->ctb_next; - newctblast = newctb; - } - newctblast->ctb_next = (CellTileBody *) NULL; - } - else TiSetBody(newtp, NULL); -} /* dupTileBody */ - -/* - * ---------------------------------------------------------------------------- - * cellTileMerge -- - * - * Merge the given tile with its plane in the directions specified. - * - * Results: - * None. - * - * Side effects: - * Modifies the database plane that contains the given tile. - * ---------------------------------------------------------------------------- - */ - -void -cellTileMerge (tile, plane, direction) - Tile * tile; - Plane * plane; - int direction; /* TOP = 8, BOTTOM = 4, LEFT = 2, RIGHT = 1 */ -{ - Point topleft, bottomright; - Tile * dummy, * tpleft, * tpright, * tp1, * tp2; - -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("cellTileMerge %x\n",tile); -#endif /* CELLDEBUG */ - - topleft.p_x = LEFT(tile); - topleft.p_y = TOP(tile); - bottomright.p_x = RIGHT(tile); - bottomright.p_y = BOTTOM(tile); - - if ((direction >> 1) % 2) /* LEFT */ - { - tpright = tile; - tpleft = BL(tpright); - -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("LEFT %x %x\n",tpleft,tpright); -#endif /* CELLDEBUG */ - - while (BOTTOM(tpleft) < topleft.p_y) /* go up left edge */ - { - if (ctbListMatch (tpleft, tpright)) - { - if (BOTTOM(tpleft) < BOTTOM(tpright)) - { - dummy = tpleft; - tpleft = TiSplitY (tpleft, BOTTOM (tpright)); - dupTileBody (dummy, tpleft); - } - else if (BOTTOM(tpleft) > BOTTOM(tpright)) - { - dummy = tpright; - tpright = TiSplitY (tpright, BOTTOM (tpleft)); - dupTileBody (dummy, tpright); - } - - if (TOP(tpleft) > TOP(tpright)) - { - dummy = TiSplitY (tpleft, TOP(tpright)); - dupTileBody (tpleft, dummy); - } - else if (TOP(tpright) > TOP(tpleft)) - { - dummy = TiSplitY (tpright, TOP(tpleft)); - dupTileBody (tpright, dummy); - } - - freeCTBList (tpright); - TiJoinX (tpleft, tpright, plane); /* tpright disappears */ - - tpright = RT(tpleft); - if (BOTTOM(tpright) < topleft.p_y) tpleft = BL(tpright); - else tpleft = tpright; /* we're off the top of the tile */ - /* this will break the while loop */ - } /* if (ctbListMatch (tpleft, tpright)) */ - - else tpleft = RT(tpleft); - } /* while */ - tile = tpleft; /* for TiSrPoint in next IF statement */ - } - - if (direction % 2) /* RIGHT */ - { - tpright = TiSrPoint (tile, plane, &bottomright); - --(bottomright.p_x); - tpleft = TiSrPoint (tpright, plane, &bottomright); - ++(bottomright.p_x); - -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("RIGHT %x %x\n",tpleft,tpright); -#endif /* CELLDEBUG */ - - while (BOTTOM(tpright) < topleft.p_y) /* go up right edge */ - { - if (ctbListMatch (tpleft, tpright)) - { - if (BOTTOM(tpright) < BOTTOM(tpleft)) - { - dummy = tpright; - tpright = TiSplitY (tpright, BOTTOM(tpleft)); - dupTileBody (dummy, tpright); - } - else if (BOTTOM(tpleft) < BOTTOM(tpright)) - { - dummy = tpleft; - tpleft = TiSplitY (tpleft, BOTTOM(tpright)); - dupTileBody (dummy, tpleft); - } - - if (TOP(tpright) > TOP(tpleft)) - { - dummy = TiSplitY (tpright, TOP(tpleft)); - dupTileBody (tpright, dummy); - } - else if (TOP(tpleft) > TOP(tpright)) - { - dummy = TiSplitY (tpleft, TOP(tpright)); - dupTileBody (tpleft, dummy); - } - - freeCTBList (tpright); - TiJoinX (tpleft, tpright, plane); /* tpright disappears */ - - tpright = RT(tpleft); - while (LEFT(tpright) > bottomright.p_x) tpright = BL(tpright); - - /* tpleft can be garbage if we're off the top of the loop, */ - /* but it doesn't matter since the expression tests tpright */ - - tpleft = BL(tpright); - } /* if (ctbListMatch (tpleft, tpright)) */ - - else - { - tpright = RT(tpright); - while (LEFT(tpright) > bottomright.p_x) tpright = BL(tpright); - tpleft = BL(tpright); /* left side merges may have */ - /* created more tiles */ - } - } /* while */ - tile = tpright; /* for TiSrPoint in next IF statement */ - } - - if ((direction >> 3) % 2) /* TOP */ - { - tp1 = TiSrPoint (tile, plane, &topleft); /* merge across top */ - - --(topleft.p_y); - tp2 = TiSrPoint (tile, plane, &topleft);/* top slice of original tile */ - ++(topleft.p_y); - -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("TOP %x %x\n",tp1,tp2); -#endif /* CELLDEBUG */ - - if ((LEFT(tp1) == LEFT(tp2) ) && - (RIGHT(tp1) == RIGHT(tp2)) && - (ctbListMatch (tp1, tp2) )) - { - freeCTBList (tp2); - TiJoinY (tp1, tp2, plane); - } - - tile = tp1; /* for TiSrPoint in next IF statement */ - } - - if ((direction >> 2) % 2) /* BOTTOM */ - { - --(bottomright.p_x); - /* bottom slice of orig tile */ - tp1 = TiSrPoint (tile, plane, &bottomright); - - --(bottomright.p_y); - tp2 = TiSrPoint (tile, plane, &bottomright); /* merge across bottom */ - -#ifdef CELLDEBUG - if (dbCellDebug) TxPrintf("BOTTOM %x %x\n",tp1,tp2); -#endif /* CELLDEBUG */ - - if ((LEFT(tp1) == LEFT(tp2) ) && - (RIGHT(tp1) == RIGHT(tp2)) && - (ctbListMatch (tp1, tp2) )) - { - freeCTBList (tp2); - TiJoinY (tp1, tp2, plane); - } - } -} - -/* - * ---------------------------------------------------------------------------- - * freeCTBList -- - * - * Free all CellTileBodies attached to the give tile. - * - * Results: - * None. - * - * Side effects: - * Frees CellTileBodies. - * ---------------------------------------------------------------------------- - */ - -void -freeCTBList (tile) - Tile * tile; -{ - CellTileBody * ctp, * ctplast; - - ctp = (CellTileBody *) tile->ti_body; - while (ctp != (CellTileBody *) NULL) - { - ctplast = ctp; - ctp = ctp->ctb_next; - freeMagic((char *) ctplast); - } - TiSetBody(tile, NULL); -} - -/* - * ---------------------------------------------------------------------------- - * ctbListMatch -- - * - * Compare two linked lists of CellTileBodies, assuming that they are - * sorted in ascending order by celluse pointers. - * - * Results: - * True if the tiles have identical lists of CellTileBodies. - * - * Side effects: - * None. - * ---------------------------------------------------------------------------- - */ - -bool -ctbListMatch (tp1, tp2) - Tile * tp1, * tp2; -{ - CellTileBody * ctp1, * ctp2; - - ctp1 = (CellTileBody *) tp1->ti_body; - ctp2 = (CellTileBody *) tp2->ti_body; - while (ctp1 && ctp2 && (ctp1->ctb_use == ctp2->ctb_use)) - ctp1 = ctp1->ctb_next, ctp2 = ctp2->ctb_next; - - return ((ctp1 == (CellTileBody *) NULL) && (ctp2 == (CellTileBody *) NULL)); -} diff --git a/database/DBcellbox.c b/database/DBcellbox.c index 6eb8d95d..db702aa5 100644 --- a/database/DBcellbox.c +++ b/database/DBcellbox.c @@ -616,11 +616,6 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc) bool foundAny; int pNum; - /* Cells which declare their bounding box to be fixed */ - /* must return immediately. */ - - if (cellDef->cd_flags & CDFIXEDBBOX) return; - /* * Include area of subcells separately */ diff --git a/database/DBcellname.c b/database/DBcellname.c index 70977881..3ad4eb4d 100644 --- a/database/DBcellname.c +++ b/database/DBcellname.c @@ -1318,7 +1318,8 @@ DBCellDefAlloc() TTMaskZero(&cellDef->cd_types); HashInit(&cellDef->cd_idHash, 16, HT_STRINGKEYS); - cellDef->cd_planes[PL_CELL] = DBNewPlane((ClientData) NULL); + cellDef->cd_cellPlane = BPNew(); + cellDef->cd_planes[PL_ROUTER] = DBNewPlane((ClientData) NULL); for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++) cellDef->cd_planes[pNum] = DBNewPlane((ClientData) TT_SPACE); @@ -1512,9 +1513,10 @@ DBCellDefFree(cellDef) */ SigDisableInterrupts(); - DBFreeCellPlane(cellDef->cd_planes[PL_CELL]); - TiFreePlane(cellDef->cd_planes[PL_CELL]); + DBClearCellPlane(cellDef); /* Remove instances only */ + BPFree(cellDef->cd_cellPlane); /* Remove the cell plane itself */ + TiFreePlane(cellDef->cd_planes[PL_ROUTER]); for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++) { DBFreePaintPlane(cellDef->cd_planes[pNum]); diff --git a/database/DBcellsrch.c b/database/DBcellsrch.c index a8fb9edc..59d42b75 100644 --- a/database/DBcellsrch.c +++ b/database/DBcellsrch.c @@ -51,7 +51,53 @@ struct seeTypesArg TileTypeBitMask *saa_mask; /* Mask of tile types seen in search */ Rect *saa_rect; /* Search area in root coordinates */ }; - + +/* + *----------------------------------------------------------------------------- + * + * DBSrCellPlaneArea -- + * + * Searches a CellDef's cell plane and calls function func() for each + * cell use found. + * + * func() must be in the form: + * + * int func(CellUse *use, ClientData cdata) + * + * and must return 0 to keep the search running, or 1 to end the search. + * + * Replaces the original TiSrArea() routine, but with the function's + * first argument as a CellUse pointer rather than a Tile pointer, + * since the tile plane has been replaced with the BPlane method. + * + * Returns 1 if the func() returns 1; otherwise returns 0 to keep the + * search alive. + * + *----------------------------------------------------------------------------- + */ + +int +DBSrCellPlaneArea(BPlane *plane, Rect *rect, int (*func)(), ClientData arg) +{ + BPEnum bpe; + CellUse *use; + int rval = 0; + + BPEnumInit(&bpe, plane, rect, BPE_OVERLAP, "DBSrCellPlaneArea"); + + while (use = BPEnumNext(&bpe)) + { + if ((*func)(use, arg)) + { + rval = 1; + break; + } + } + + BPEnumTerm(&bpe); + return rval; +} + /* *----------------------------------------------------------------------------- * @@ -81,7 +127,7 @@ struct seeTypesArg * * The client procedure should not modify any of the paint planes in * the cells visited by DBTreeSrTiles, because we use DBSrPaintArea - * instead of TiSrArea as our paint-tile enumeration function. + * as our paint-tile enumeration function. * * Results: * 0 is returned if the search finished normally. 1 is returned @@ -112,7 +158,7 @@ DBTreeSrTiles(scx, mask, xMask, func, cdarg) int (*func)(); /* Function to apply at each qualifying tile */ ClientData cdarg; /* Client data for above function */ { - int dbCellTileSrFunc(); + int dbCellPlaneSrFunc(); TreeFilter filter; /* Set up the filter and call the recursive filter function */ @@ -124,7 +170,7 @@ DBTreeSrTiles(scx, mask, xMask, func, cdarg) filter.tf_dinfo = 0; filter.tf_planes = DBTechTypesToPlanes(mask); - return dbCellTileSrFunc(scx, &filter); + return dbCellPlaneSrFunc(scx, &filter); } /* @@ -154,7 +200,7 @@ DBTreeSrNMTiles(scx, dinfo, mask, xMask, func, cdarg) int (*func)(); /* Function to apply at each qualifying tile */ ClientData cdarg; /* Client data for above function */ { - int dbCellTileSrFunc(); + int dbCellPlaneSrFunc(); TreeFilter filter; /* Set up the filter and call the recursive filter function */ @@ -166,17 +212,17 @@ DBTreeSrNMTiles(scx, dinfo, mask, xMask, func, cdarg) filter.tf_dinfo = dinfo; filter.tf_planes = DBTechTypesToPlanes(mask); - return dbCellTileSrFunc(scx, &filter); + return dbCellPlaneSrFunc(scx, &filter); } /* - * dbCellTileSrFunc -- + * dbCellPlaneSrFunc -- * * Recursive filter procedure applied to the cell by DBTreeSrTiles(). */ int -dbCellTileSrFunc(scx, fp) +dbCellPlaneSrFunc(scx, fp) SearchContext *scx; TreeFilter *fp; { @@ -184,7 +230,7 @@ dbCellTileSrFunc(scx, fp) CellDef *def = scx->scx_use->cu_def; int pNum; - ASSERT(def != (CellDef *) NULL, "dbCellTileSrFunc"); + ASSERT(def != (CellDef *) NULL, "dbCellPlaneSrFunc"); if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask)) return 0; if ((def->cd_flags & CDAVAILABLE) == 0) @@ -219,10 +265,10 @@ dbCellTileSrFunc(scx, fp) /* * Now apply ourselves recursively to each of the CellUses - * in our tile plane. + * in our cell plane. */ - if (DBCellSrArea(scx, dbCellTileSrFunc, (ClientData) fp)) + if (DBCellSrArea(scx, dbCellPlaneSrFunc, (ClientData) fp)) return 1; else return 0; } @@ -270,7 +316,7 @@ DBTreeSrUniqueTiles(scx, mask, xMask, func, cdarg) int (*func)(); /* Function to apply at each qualifying tile */ ClientData cdarg; /* Client data for above function */ { - int dbCellTileSrFunc(); + int dbCellPlaneSrFunc(); TreeFilter filter; /* Set up the filter and call the recursive filter function */ @@ -288,7 +334,7 @@ DBTreeSrUniqueTiles(scx, mask, xMask, func, cdarg) * dbCellUniqueTileSrFunc -- * * Recursive filter procedure applied to the cell by DBTreeSrUniqueTiles(). - * This is similar to dbCellTileSrFunc, except that for each plane searched, + * This is similar to dbCellPlaneSrFunc, except that for each plane searched, * only the tile types having that plane as their home plane will be passed * to the filter function. Contacts will therefore be processed only once. */ @@ -348,8 +394,6 @@ dbCellUniqueTileSrFunc(scx, fp) * * DBNoTreeSrTiles -- * - * (*** Move to database module after tested) - * * NOTE: THIS PROCEDURE IS EXACTLY LIKE DBTreeSrTiles EXCEPT THAT IT DOES * NOT SEARCH SUBCELLS. * @@ -377,7 +421,7 @@ dbCellUniqueTileSrFunc(scx, fp) * * The client procedure should not modify any of the paint planes in * the cells visited by DBTreeSrTiles, because we use DBSrPaintArea - * instead of TiSrArea as our paint-tile enumeration function. + * as our paint-tile enumeration function. * * Results: * 0 is returned if the search finished normally. 1 is returned @@ -1030,7 +1074,6 @@ DBCellSrArea(scx, func, cdarg) { TreeFilter filter; TreeContext context; - Rect expanded; int dbCellSrFunc(); filter.tf_func = func; @@ -1042,22 +1085,10 @@ DBCellSrArea(scx, func, cdarg) if (!DBCellRead(scx->scx_use->cu_def, (char *) NULL, TRUE, NULL)) return 0; - /* In order to make this work with zero-size areas, we first expand - * the area by before searching the tile plane. DbCellSrFunc will - * check carefully to throw out things that don't overlap the original - * area. The expansion is tricky because we mustn't expand infinities. - */ - - expanded = scx->scx_area; - if (expanded.r_xbot > TiPlaneRect.r_xbot) expanded.r_xbot -= 1; - if (expanded.r_ybot > TiPlaneRect.r_ybot) expanded.r_ybot -= 1; - if (expanded.r_xtop < TiPlaneRect.r_xtop) expanded.r_xtop += 1; - if (expanded.r_ytop < TiPlaneRect.r_ytop) expanded.r_ytop += 1; - - if (TiSrArea((Tile *) NULL, scx->scx_use->cu_def->cd_planes[PL_CELL], - &expanded, dbCellSrFunc, (ClientData) &context)) + if (DBSrCellPlaneArea(scx->scx_use->cu_def->cd_cellPlane, + &scx->scx_area, dbCellSrFunc, (ClientData) &context)) return 1; - else return 0; + return 0; } /* @@ -1066,17 +1097,7 @@ DBCellSrArea(scx, func, cdarg) * dbCellSrFunc -- * * Filter procedure for DBCellSrArea. Applies the procedure given - * to DBCellSrArea to any of the CellUses in the tile that are - * enumerable. - * - * Since subcells are allowed to overlap, a single tile body may - * refer to many subcells and a single subcell may be referred to - * by many tile bodies. To insure that each CellUse is enumerated - * exactly once, the procedure given to DBCellSrArea is only applied - * to a CellUse when its lower right corner is contained in the - * tile to dbCellSrFunc (or otherwise at the last tile encountered - * in the event the lower right corner of the CellUse is outside the - * search rectangle). + * to DBCellSrArea to any of the CellUses in the given area. * * Results: * 0 is normally returned, and 1 is returned if an abort occurred. @@ -1089,88 +1110,56 @@ DBCellSrArea(scx, func, cdarg) */ int -dbCellSrFunc(tile, cxp) - Tile *tile; +dbCellSrFunc(use, cxp) + CellUse *use; TreeContext *cxp; { TreeFilter *fp = cxp->tc_filter; SearchContext *scx = cxp->tc_scx; - CellUse *use; Rect *bbox; - CellTileBody *body; SearchContext newScx; Transform t, tinv; - Rect tileArea; - int srchBot, srchRight; int xlo, xhi, ylo, yhi, xbase, ybase, xsep, ysep, clientResult; - srchBot = scx->scx_area.r_ybot; - srchRight = scx->scx_area.r_xtop; - TITORECT(tile, &tileArea); + bbox = &use->cu_bbox; + newScx.scx_use = use; - /* Make sure that this tile really does overlap the search area - * (it could be just touching because of the expand-by-one in - * DBCellSrArea). - */ - - if (!GEO_OVERLAP(&tileArea, &scx->scx_area)) return 0; - - for (body = (CellTileBody *) TiGetBody(tile); - body != NULL; - body = body->ctb_next) + /* If not an array element, life is much simpler */ + if (use->cu_xlo == use->cu_xhi && use->cu_ylo == use->cu_yhi) { - use = newScx.scx_use = body->ctb_use; - ASSERT(use != (CellUse *) NULL, "dbCellSrFunc"); - - /* The check below is to ensure that we only enumerate each - * cell once, even though it appears in many different tiles - * in the subcell plane. - */ - - bbox = &use->cu_bbox; - if ( (tileArea.r_ybot <= bbox->r_ybot || - (tileArea.r_ybot <= srchBot && bbox->r_ybot < srchBot)) - && (tileArea.r_xtop >= bbox->r_xtop || - (tileArea.r_xtop >= srchRight && bbox->r_xtop >= srchRight))) - { - /* If not an array element, life is much simpler */ - if (use->cu_xlo == use->cu_xhi && use->cu_ylo == use->cu_yhi) - { - newScx.scx_x = use->cu_xlo, newScx.scx_y = use->cu_yhi; - if (SigInterruptPending) return 1; - GEOINVERTTRANS(&use->cu_transform, &tinv); - GeoTransTrans(&use->cu_transform, &scx->scx_trans, + newScx.scx_x = use->cu_xlo, newScx.scx_y = use->cu_yhi; + if (SigInterruptPending) return 1; + GEOINVERTTRANS(&use->cu_transform, &tinv); + GeoTransTrans(&use->cu_transform, &scx->scx_trans, &newScx.scx_trans); - GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area); - if ((*fp->tf_func)(&newScx, fp->tf_arg) == 1) - return 1; - continue; - } - - /* - * More than a single array element; - * check to see which ones overlap our search area. - */ - DBArrayOverlap(use, &scx->scx_area, &xlo, &xhi, &ylo, &yhi); - xsep = (use->cu_xlo > use->cu_xhi) ? -use->cu_xsep : use->cu_xsep; - ysep = (use->cu_ylo > use->cu_yhi) ? -use->cu_ysep : use->cu_ysep; - for (newScx.scx_y = ylo; newScx.scx_y <= yhi; newScx.scx_y++) - for (newScx.scx_x = xlo; newScx.scx_x <= xhi; newScx.scx_x++) - { - if (SigInterruptPending) return 1; - xbase = xsep * (newScx.scx_x - use->cu_xlo); - ybase = ysep * (newScx.scx_y - use->cu_ylo); - GeoTransTranslate(xbase, ybase, &use->cu_transform, &t); - GEOINVERTTRANS(&t, &tinv); - GeoTransTrans(&t, &scx->scx_trans, &newScx.scx_trans); - GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area); - clientResult = (*fp->tf_func)(&newScx, fp->tf_arg); - if (clientResult == 2) goto skipArray; - else if (clientResult == 1) return 1; - } - } - skipArray: continue; + GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area); + if ((*fp->tf_func)(&newScx, fp->tf_arg) == 1) + return 1; + return 0; } + + /* + * More than a single array element; + * check to see which ones overlap our search area. + */ + DBArrayOverlap(use, &scx->scx_area, &xlo, &xhi, &ylo, &yhi); + xsep = (use->cu_xlo > use->cu_xhi) ? -use->cu_xsep : use->cu_xsep; + ysep = (use->cu_ylo > use->cu_yhi) ? -use->cu_ysep : use->cu_ysep; + for (newScx.scx_y = ylo; newScx.scx_y <= yhi; newScx.scx_y++) + for (newScx.scx_x = xlo; newScx.scx_x <= xhi; newScx.scx_x++) + { + if (SigInterruptPending) return 1; + xbase = xsep * (newScx.scx_x - use->cu_xlo); + ybase = ysep * (newScx.scx_y - use->cu_ylo); + GeoTransTranslate(xbase, ybase, &use->cu_transform, &t); + GEOINVERTTRANS(&t, &tinv); + GeoTransTrans(&t, &scx->scx_trans, &newScx.scx_trans); + GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area); + clientResult = (*fp->tf_func)(&newScx, fp->tf_arg); + if (clientResult == 2) return 0; + else if (clientResult == 1) return 1; + } + return 0; } @@ -1179,9 +1168,10 @@ dbCellSrFunc(tile, cxp) * * DBCellEnum -- * - * Apply the supplied procedure once to each CellUse in the subcell tile + * Apply the supplied procedure once to each CellUse in the subcell * plane of the supplied CellDef. This procedure is not a geometric - * search, but rather a hierarchical enumeration. + * search, but rather a hierarchical enumeration. Use DBSrCellPlaneArea() + * for geometric searches over an area. * * The procedure should be of the following form: * int @@ -1216,7 +1206,7 @@ DBCellEnum(cellDef, func, cdarg) filter.tf_arg = cdarg; if ((cellDef->cd_flags & CDAVAILABLE) == 0) if (!DBCellRead(cellDef, (char *) NULL, TRUE, NULL)) return 0; - if (TiSrArea((Tile *) NULL, cellDef->cd_planes[PL_CELL], + if (DBSrCellPlaneArea(cellDef->cd_cellPlane, &TiPlaneRect, dbEnumFunc, (ClientData) &filter)) return 1; else return 0; @@ -1228,11 +1218,7 @@ DBCellEnum(cellDef, func, cdarg) * dbEnumFunc -- * * Filter procedure for DBCellEnum. Applies the procedure given - * to DBCellEnum to any of the CellUses in the tile that are - * enumerable. - * - * The scheme used for handling overlapping subcells is the same - * as used in DBCellSrArea above. + * to DBCellEnum to the visited CellUse. * * Results: * 0 normally, 1 if abort occurred. @@ -1245,28 +1231,17 @@ DBCellEnum(cellDef, func, cdarg) */ int -dbEnumFunc(tile, fp) - Tile *tile; +dbEnumFunc(use, fp) + CellUse *use; TreeFilter *fp; { - CellUse *use; - CellTileBody *body; Rect *bbox; - for (body = (CellTileBody *) TiGetBody(tile); - body != NULL; - body = body->ctb_next) - { - use = body->ctb_use; - ASSERT(use != (CellUse *) NULL, "dbCellSrFunc"); - - bbox = &use->cu_bbox; - if ((BOTTOM(tile) <= bbox->r_ybot) && (RIGHT(tile) >= bbox->r_xtop)) - if ((*fp->tf_func)(use, fp->tf_arg)) return 1; - } + bbox = &use->cu_bbox; + if ((*fp->tf_func)(use, fp->tf_arg)) return 1; return 0; } - + /* * ---------------------------------------------------------------------------- * @@ -1594,10 +1569,10 @@ dbTileScaleFunc(tile, scvals) * DBSrCellUses -- * * Do function "func" for each cell use in cellDef, passing "arg" as - * client data. Unlike DBEnumCell, this routine first collects a linked - * list of cell uses, then performs the function on the list, so that - * the search cannot be corrupted by, removing or reallocating the use - * structure from the cell def. Function "func" takes 2 arguments: + * client data. This routine first collects a linked list of cell uses, + * then performs the function on the list, so that the search cannot be + * corrupted by (specifically) removing the use structure from the cell + * def's bplane. Function "func" takes 2 arguments: * * int func(Celluse *use, ClientData arg) {} * @@ -1671,7 +1646,7 @@ dbScaleCell(cellDef, scalen, scaled) */ int scalen, scaled; /* scale numerator and denominator. */ { - int dbCellTileEnumFunc(), dbCellUseEnumFunc(); + int dbCellScaleFunc(), dbCellUseEnumFunc(); Label *lab; int pNum; LinkedTile *lhead, *lt; @@ -1731,31 +1706,13 @@ dbScaleCell(cellDef, scalen, scaled) lu = lu->cu_next; } - /* Scale the position of all subcell uses. Count all of the tiles in the */ + /* Scale the position of all subcell uses. Count all of the cells in the */ /* subcell plane, and scale those without reference to the actual cells (so */ /* we don't count the cells multiple times). */ lhead = NULL; - (void) TiSrArea((Tile *)NULL, cellDef->cd_planes[PL_CELL], &TiPlaneRect, - dbCellTileEnumFunc, (ClientData) &lhead); - - /* Scale each of the tiles in the linked list by (n / d) */ - /* Don't scale (M)INFINITY on boundary tiles! */ - - lt = lhead; - while (lt != NULL) - { - DBScalePoint(<->tile->ti_ll, scalen, scaled); - lt = lt->t_next; - } - - /* Free this linked tile structure */ - lt = lhead; - while (lt != NULL) - { - freeMagic((char *)lt); - lt = lt->t_next; - } + (void) DBSrCellPlaneArea(cellDef->cd_cellPlane, &TiPlaneRect, + dbCellUseEnumFunc, (ClientData) &lhead); /* Scale all of the paint tiles in this cell by creating a new plane */ /* and copying all tiles into the new plane at scaled dimensions. */ @@ -1810,33 +1767,33 @@ donecell: DBScalePoint(&cellDef->cd_extended.r_ll, scalen, scaled); DBScalePoint(&cellDef->cd_extended.r_ur, scalen, scaled); - return 0; -} + /* If the cell is an abstract view with a fixed bounding box, then */ + /* adjust the bounding box property to match the new scale. */ -/* - * ---------------------------------------------------------------------------- - * - * dbCellTileEnumFunc -- - * - * Enumeration procedure called on each tile encountered in the search of - * the cell plane. Adds the tile to a linked list of tiles. - * - * ---------------------------------------------------------------------------- - */ + if ((cellDef->cd_flags & CDFIXEDBBOX) != 0) + { + Rect r; + bool found; + char *propval; -int -dbCellTileEnumFunc(tile, arg) - Tile *tile; - LinkedTile **arg; -{ - LinkedTile *lt; + propval = (char *)DBPropGet(cellDef, "FIXED_BBOX", &found); + if (found) + { + if (sscanf(propval, "%d %d %d %d", &r.r_xbot, &r.r_ybot, + &r.r_xtop, &r.r_ytop) == 4) + { + DBScalePoint(&r.r_ll, scalen, scaled); + DBScalePoint(&r.r_ur, scalen, scaled); - lt = (LinkedTile *) mallocMagic(sizeof(LinkedTile)); + propval = (char *)mallocMagic(40); + sprintf(propval, "%d %d %d %d", r.r_xbot, r.r_ybot, + r.r_xtop, r.r_ytop); + DBPropPut(cellDef, "FIXED_BBOX", propval); + } + } + + } - lt->tile = tile; - lt->t_next = (*arg); - (*arg) = lt; - return 0; } diff --git a/database/DBcellsubr.c b/database/DBcellsubr.c index a430d671..b1323af7 100644 --- a/database/DBcellsubr.c +++ b/database/DBcellsubr.c @@ -131,25 +131,20 @@ DBCellCopyDefBody(sourceDef, destDef) */ SigDisableInterrupts(); - (void) TiSrArea((Tile *) NULL, destDef->cd_planes[PL_CELL], - &TiPlaneRect, dbCopyDefFunc, (ClientData) destDef); + (void) DBSrCellPlaneArea(destDef->cd_cellPlane, + &TiPlaneRect, dbCopyDefFunc, (ClientData) destDef); SigEnableInterrupts(); } int -dbCopyDefFunc(tile, def) - Tile *tile; /* Tile to search for subcell uses. */ +dbCopyDefFunc(use, def) + CellUse *use; /* Subcell use. */ CellDef *def; /* Set parent pointer in each use to this. */ { - CellTileBody *ctb; - - for (ctb = (CellTileBody *) tile->ti_body; ctb != NULL; - ctb = ctb->ctb_next) - { - ctb->ctb_use->cu_parent = def; - } + use->cu_parent = def; return 0; } + /* * ---------------------------------------------------------------------------- @@ -185,19 +180,8 @@ DBCellClearDef(cellDef) SigDisableInterrupts(); - /* - * We use a simple optimization to avoid trying - * to clear an already empty plane. - */ - plane = cellDef->cd_planes[PL_CELL]; - tile = TR(plane->pl_left); - if (TiGetBody(tile) != (ClientData) NULL - || LB(tile) != plane->pl_bottom - || TR(tile) != plane->pl_right - || RT(tile) != plane->pl_top) - { - DBClearCellPlane(plane); - } + /* Remove all instances from the cell plane */ + DBClearCellPlane(cellDef); /* Reduce clutter by reinitializing the id hash table */ HashKill(&cellDef->cd_idHash); @@ -224,41 +208,7 @@ DBCellClearDef(cellDef) SigEnableInterrupts(); } -/* - * ---------------------------------------------------------------------------- - * - * DBClearCellPlane -- - * - * Remove all cell uses contained in the given cell tile plane. - * Deallocates the Tiles and CellTileBodies contained in the plane, - * and constructs a new plane containing a single tile with a null - * tile body. - * - * Results: - * None. - * - * Side effects: - * Modifies the database plane given. - * - * ---------------------------------------------------------------------------- - */ -void -DBClearCellPlane(plane) - Plane *plane; -{ - Tile *newCenterTile; - - /* Free all tiles from plane, and delete all uses */ - DBFreeCellPlane(plane); - - /* Allocate a new central space tile with a NULL body */ - newCenterTile = TiAlloc(); - plane->pl_hint = newCenterTile; - TiSetBody(newCenterTile, NULL); - dbSetPlaneTile(plane, newCenterTile); -} - /* * ---------------------------------------------------------------------------- * diff --git a/database/DBconnect.c b/database/DBconnect.c index ff007e5d..b44053d5 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -647,6 +647,11 @@ dbcUnconnectFunc(tile, clientData) * when a label is found which is connected to paint belonging to the * network, it adds it to the destination definition. * + * In addition to simply adding a label to the destination, this + * routine also checks port connections on abstract cells. Abstract + * cells can have multiple ports of the same name with implied + * connectivity between them. + * * Results: * Always 0. * @@ -674,10 +679,11 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) GeoTransPointDelta(&scx->scx_trans, &lab->lab_offset, &offset); rotate = GeoTransAngle(&scx->scx_trans, lab->lab_rotate); - /* Only add labels if they are on the search top level */ - /* (NOTE: Could add hierachical labels using tpath) */ + /* Do not add any labels to the destination unless they are on */ + /* the top level (Note: Could alter label to be placed with */ + /* tpath). */ - if (scx->scx_use == csa2->csa2_topscx->scx_use) + if (csa2->csa2_topscx->scx_use == scx->scx_use) { DBEraseLabelsByContent(def, &r, -1, lab->lab_text); DBPutFontLabel(def, &r, lab->lab_font, lab->lab_size, rotate, &offset, @@ -689,30 +695,72 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) CellDef *orig_def = scx->scx_use->cu_def; Label *slab; int lidx = lab->lab_flags & PORT_NUM_MASK; + TileTypeBitMask *connectMask; /* Check for equivalent ports. For any found, call */ /* DBTreeSrTiles recursively on the type and area */ /* of the label. */ + /* Don't recurse, just add area to the csa2_list. */ + /* To avoid infinite recursion, only look at labels */ + /* forward of the currently searched label, and only */ + /* add the next one to the list. If there are more */ + /* equivalent ports, they will be found when processing */ + /* this label's area. */ - for (slab = orig_def->cd_labels; slab != NULL; slab = slab->lab_next) - if ((slab->lab_flags & PORT_DIR_MASK) && (slab != lab)) + for (slab = lab->lab_next; slab != NULL; slab = slab->lab_next) + if (slab->lab_flags & PORT_DIR_MASK) if ((slab->lab_flags & PORT_NUM_MASK) == lidx) { - SearchContext scx2 = *csa2->csa2_topscx; - TileTypeBitMask mask; + Rect newarea; + int pNum; // Do NOT go searching on labels connected to space! if (slab->lab_type == TT_SPACE) continue; - TTMaskSetOnlyType(&mask, slab->lab_type); - GeoTransRect(&scx->scx_trans, &slab->lab_rect, &scx2.scx_area); - // Expand search area by 1 to capture edge and point labels. - scx2.scx_area.r_xbot--; - scx2.scx_area.r_xtop++; - scx2.scx_area.r_ybot--; - scx2.scx_area.r_ytop++; - DBTreeSrTiles(&scx2, &mask, csa2->csa2_xMask, - dbcConnectFunc, (ClientData) csa2); + GeoTransRect(&scx->scx_trans, &slab->lab_rect, &newarea); + + // Avoid infinite looping. If material under the label + // has already been added to the destination, then ignore. + + connectMask = &csa2->csa2_connect[slab->lab_type]; + + pNum = DBPlane(slab->lab_type); + if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], + &newarea, connectMask, dbcUnconnectFunc, + (ClientData) NULL) == 1) + continue; + + newarea.r_xbot--; + newarea.r_xtop++; + newarea.r_ybot--; + newarea.r_ytop++; + + /* Register the area and connection mask as needing to be processed */ + + if (++csa2->csa2_top == csa2->csa2_size) + { + /* Reached list size limit---need to enlarge the list */ + /* Double the size of the list every time we hit the limit */ + + conSrArea *newlist; + int i, lastsize = csa2->csa2_size; + + csa2->csa2_size *= 2; + + newlist = (conSrArea *)mallocMagic(csa2->csa2_size + * sizeof(conSrArea)); + memcpy((void *)newlist, (void *)csa2->csa2_list, + (size_t)lastsize * sizeof(conSrArea)); + freeMagic((char *)csa2->csa2_list); + csa2->csa2_list = newlist; + } + + csa2->csa2_list[csa2->csa2_top].area = newarea; + csa2->csa2_list[csa2->csa2_top].connectMask = connectMask; + csa2->csa2_list[csa2->csa2_top].dinfo = 0; + + /* See above: Process only one equivalent port at a time */ + break; } } return 0; @@ -760,7 +808,6 @@ dbcConnectFunc(tile, cx) TileType loctype = TiGetTypeExact(tile); TileType dinfo = 0; int pNum = cx->tc_plane; - unsigned char searchtype; CellDef *def; TiToRect(tile, &tileArea); @@ -809,34 +856,12 @@ dbcConnectFunc(tile, cx) if (DBIsContact(loctype)) { -// TileType ctype; -// TileTypeBitMask *cMask, *rMask = DBResidueMask(loctype); - -// TTMaskSetOnlyType(¬ConnectMask, loctype); - /* Different contact types may share residues (6/18/04) */ /* Use TTMaskIntersect(), not TTMaskEqual()---types */ /* which otherwise stack may be in separate cells */ /* (12/1/05) */ -// for (ctype = TT_TECHDEPBASE; ctype < DBNumUserLayers; ctype++) -// { -// if (DBIsContact(ctype)) -// { -// cMask = DBResidueMask(ctype); -// if (TTMaskIntersect(rMask, cMask)) -// TTMaskSetType(¬ConnectMask, ctype); -// } -// } - /* The mask of contact types must include all stacked contacts */ -// for (ctype = DBNumUserLayers; ctype < DBNumTypes; ctype++) -// { -// cMask = DBResidueMask(ctype); -// if (TTMaskHasType(cMask, loctype)) -// TTMaskSetType(¬ConnectMask, ctype); -// } -// TTMaskCom(¬ConnectMask); TTMaskZero(¬ConnectMask); TTMaskSetMask(¬ConnectMask, &DBNotConnectTbl[loctype]); @@ -864,43 +889,6 @@ dbcConnectFunc(tile, cx) &newarea, DBStdPaintTbl(loctype, pNum), (PaintUndoInfo *) NULL); - /* Check the source def for any labels belonging to this */ - /* tile area and plane, and add them to the destination. */ - - searchtype = TF_LABEL_ATTACH; - if (IsSplit(tile)) - { - /* If the tile is split, then labels attached to the */ - /* opposite point of the triangle are NOT connected. */ - - if (SplitSide(tile)) - { - if (SplitDirection(tile)) - searchtype |= TF_LABEL_ATTACH_NOT_SW; - else - searchtype |= TF_LABEL_ATTACH_NOT_NW; - } - else - { - if (SplitDirection(tile)) - searchtype |= TF_LABEL_ATTACH_NOT_NE; - else - searchtype |= TF_LABEL_ATTACH_NOT_SE; - } - } - - /* Note that the search must be done from the top since zero-size */ - /* port labels can be on any part of the hierarchy with no paint */ - /* underneath in its own cell to trigger the callback function. */ - - /* Copy information from top search context into new search context */ - scx2 = *csa2->csa2_topscx; - scx2.scx_area = newarea; - - DBTreeSrLabels(&scx2, connectMask, csa2->csa2_xMask, NULL, - searchtype, dbcConnectLabelFunc, - (ClientData) csa2); - /* Since the whole area of this tile hasn't been recorded, * we must process its area to find any other tiles that * connect to it. Add each of them to the list of things @@ -947,12 +935,6 @@ dbcConnectFunc(tile, cx) newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea)); memcpy((void *)newlist, (void *)csa2->csa2_list, (size_t)lastsize * sizeof(conSrArea)); - // for (i = 0; i < lastsize; i++) - // { - // newlist[i].area = csa2->csa2_list[i].area; - // newlist[i].connectMask = csa2->csa2_list[i].connectMask; - // newlist[i].dinfo = csa2->csa2_list[i].dinfo; - // } freeMagic((char *)csa2->csa2_list); csa2->csa2_list = newlist; } @@ -1023,6 +1005,7 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, destUse) struct conSrArg2 csa2; TileTypeBitMask *newmask; TileType newtype; + unsigned char searchtype; csa2.csa2_use = destUse; csa2.csa2_xMask = xMask; @@ -1052,6 +1035,37 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, destUse) (ClientData) &csa2); else DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, (ClientData) &csa2); + + /* Check the source def for any labels belonging to this */ + /* tile area and plane, and add them to the destination. */ + + /* (This code previously in dbcConnectFunc, but the change to */ + /* BPlane for cells means that the cell search cannot be run */ + /* from the top within another cell search.) */ + + searchtype = TF_LABEL_ATTACH; + if (newtype & TT_DIAGONAL) + { + /* If the tile is split, then labels attached to the */ + /* opposite point of the triangle are NOT connected. */ + + if (newtype & TT_SIDE) + { + if (newtype & TT_DIRECTION) + searchtype |= TF_LABEL_ATTACH_NOT_SW; + else + searchtype |= TF_LABEL_ATTACH_NOT_NW; + } + else + { + if (newtype & TT_DIRECTION) + searchtype |= TF_LABEL_ATTACH_NOT_NE; + else + searchtype |= TF_LABEL_ATTACH_NOT_SE; + } + } + DBTreeSrLabels(scx, newmask, xMask, NULL, searchtype, + dbcConnectLabelFunc, (ClientData) &csa2); } freeMagic((char *)csa2.csa2_list); diff --git a/database/DBio.c b/database/DBio.c index 09ee7d7a..b10f9e43 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -1584,17 +1584,17 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled) if (!strcmp(propertyname, "GDS_FILE")) cellDef->cd_flags |= CDVENDORGDS; - /* Also process FIXED_BBOX property, but do not keep */ - /* the property, as it should be regenerated on cell */ - /* output from the current scale. */ + /* Also process FIXED_BBOX property, as units must match */ if (!strcmp(propertyname, "FIXED_BBOX")) { + Rect locbbox; + if (sscanf(propertyvalue, "%d %d %d %d", - &(cellDef->cd_bbox.r_xbot), - &(cellDef->cd_bbox.r_ybot), - &(cellDef->cd_bbox.r_xtop), - &(cellDef->cd_bbox.r_ytop)) != 4) + &(locbbox.r_xbot), + &(locbbox.r_ybot), + &(locbbox.r_xtop), + &(locbbox.r_ytop)) != 4) { TxError("Cannot read bounding box values in %s property", propertyname); @@ -1605,20 +1605,24 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled) { if (scalen > 1) { - cellDef->cd_bbox.r_xbot *= scalen; - cellDef->cd_bbox.r_ybot *= scalen; - cellDef->cd_bbox.r_xtop *= scalen; - cellDef->cd_bbox.r_ytop *= scalen; + locbbox.r_xbot *= scalen; + locbbox.r_ybot *= scalen; + locbbox.r_xtop *= scalen; + locbbox.r_ytop *= scalen; } if (scaled > 1) { - cellDef->cd_bbox.r_xbot /= scaled; - cellDef->cd_bbox.r_ybot /= scaled; - cellDef->cd_bbox.r_xtop /= scaled; - cellDef->cd_bbox.r_ytop /= scaled; + locbbox.r_xbot /= scaled; + locbbox.r_ybot /= scaled; + locbbox.r_xtop /= scaled; + locbbox.r_ytop /= scaled; } - cellDef->cd_extended = cellDef->cd_bbox; cellDef->cd_flags |= CDFIXEDBBOX; + storedvalue = (char *)mallocMagic(40); + sprintf(storedvalue, "%d %d %d %d", + locbbox.r_xbot, locbbox.r_ybot, + locbbox.r_xtop, locbbox.r_ytop); + (void) DBPropPut(cellDef, propertyname, storedvalue); } } else @@ -2538,27 +2542,6 @@ DBCellWriteFile(cellDef, f) DBPropEnum(cellDef, dbWritePropFunc, (ClientData)f); } - /* Fixed bounding box goes into a special property in output file */ - /* This is not kept internally as a property, so that it can be */ - /* read and written in the correct units without regard to internal */ - /* changes in scaling. */ - - if (cellDef->cd_flags & CDFIXEDBBOX) - { - // If there were no explicit properties, then we need to - // write the header - - if (cellDef->cd_props == (ClientData)NULL) - FPRINTF(f, "<< properties >>\n"); - - sprintf(lstring, "string FIXED_BBOX %d %d %d %d\n", - cellDef->cd_bbox.r_xbot / reducer, - cellDef->cd_bbox.r_ybot / reducer, - cellDef->cd_bbox.r_xtop / reducer, - cellDef->cd_bbox.r_ytop / reducer); - FPRINTF(f, lstring); - } - FPRINTF(f, "<< end >>\n"); if (fflush(f) == EOF || ferror(f)) diff --git a/database/DBtcontact.c b/database/DBtcontact.c index 922c3a9f..193be338 100644 --- a/database/DBtcontact.c +++ b/database/DBtcontact.c @@ -765,13 +765,13 @@ DBTechFinalContact() /* * Initialize the masks of planes on which each type appears. - * It will contain all planes (except subcell) for space, + * It will contain all planes (except router) for space, * the home plane for each type up to DBNumTypes, and no * planes for undefined types. Also update the mask of * types visible on each plane. */ - DBTypePlaneMaskTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_CELL)); + DBTypePlaneMaskTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_ROUTER)); for (primaryType = 0; primaryType < DBNumTypes; primaryType++) { pNum = DBPlane(primaryType); diff --git a/database/DBtechname.c b/database/DBtechname.c index 199bd89e..152415b4 100644 --- a/database/DBtechname.c +++ b/database/DBtechname.c @@ -393,8 +393,8 @@ DBTechTypesToPlanes(mask) TileType t; PlaneMask planeMask, noCellMask, retMask; - /* Space tiles are present in all planes but the cell plane */ - noCellMask = ~(PlaneNumToMaskBit(PL_CELL)); + /* Space tiles are present in all planes but the router plane */ + noCellMask = ~(PlaneNumToMaskBit(PL_ROUTER)); if (TTMaskHasType(mask, TT_SPACE)) { retMask = PlaneNumToMaskBit(DBNumPlanes) - 1; retMask &= noCellMask; diff --git a/database/DBtechtype.c b/database/DBtechtype.c index 5851b5a5..2bd4c03b 100644 --- a/database/DBtechtype.c +++ b/database/DBtechtype.c @@ -70,7 +70,7 @@ TileTypeBitMask DBTechActiveLayerBits; /* Layers marked locked in the techfile * /* Table of default, builtin planes */ DefaultPlane dbTechDefaultPlanes[] = { - PL_CELL, "subcell", + PL_ROUTER, "router", PL_DRC_ERROR, "designRuleError", PL_DRC_CHECK, "designRuleCheck", PL_M_HINT, "mhint", @@ -584,8 +584,8 @@ DBTechFinalType() TTMaskZero(&DBTechActiveLayerBits); TTMaskSetMask(&DBTechActiveLayerBits, &DBActiveLayerBits); - /* Space is visible on all planes but the subcell plane */ - TTMaskZero(&DBPlaneTypes[PL_CELL]); + /* Space is visible on all planes except the router */ + TTMaskZero(&DBPlaneTypes[PL_ROUTER]); for (pNum = PL_PAINTBASE; pNum < PL_MAXTYPES; pNum++) TTMaskSetOnlyType(&DBPlaneTypes[pNum], TT_SPACE); } diff --git a/database/DBtiles.c b/database/DBtiles.c index 3834055f..f21ee274 100644 --- a/database/DBtiles.c +++ b/database/DBtiles.c @@ -334,9 +334,6 @@ enum_next: * * NOTE: * - * THIS IS THE PREFERRED WAY TO FIND ALL TILES IN A GIVEN AREA; - * TiSrArea IS OBSOLETE FOR ALL BUT THE SUBCELL PLANE. - * * Results: * 0 is returned if the search completed normally. 1 is returned * if it aborted. @@ -786,15 +783,10 @@ enumerate: /* * -------------------------------------------------------------------- * - * DBFreeCellPlane -- + * DBClearCellPlane -- * - * Deallocate all tiles in the cell tile plane of a given CellDef. - * Also deallocates the lists of CellTileBodies and their associated - * CellUses, but not their associated CellDefs. - * Don't free the cell tile plane itself or the four boundary tiles. - * - * Since cell tile planes contain less stuff than paint tile planes - * usually, we don't have to be as performance-conscious here. + * Removes all CellUses from a def's cell plane. Does not remove the + * cell plane itself. * * Results: * None. @@ -806,54 +798,40 @@ enumerate: */ void -DBFreeCellPlane(plane) - Plane *plane; /* Plane whose storage is to be freed */ +DBClearCellPlane(def) + CellDef *def; { - int dbFreeCellFunc(); + int dbDeleteCellUse(); /* Forward reference */ /* Don't let this search be interrupted. */ - SigDisableInterrupts(); - (void) TiSrArea((Tile *) NULL, plane, &TiPlaneRect, - dbFreeCellFunc, (ClientData) NULL); + + /* Remove everything from the BPlane */ + /* Do not use BPDelete() inside a BPEnum loop. Use DBSrCellUses */ + /* to get a linked list of cell instances, then remove each one. */ + + DBSrCellUses(def, dbDeleteCellUse, (ClientData)NULL); + SigEnableInterrupts(); } /* - * Filter function called via TiSrArea on behalf of DBFreeCellPlane() - * above. Deallocates each tile it is passed. If the tile has a vanilla - * body, only the tile is deallocated; otherwise, the tile body and its - * label list are both deallocated along with the tile itself. + * -------------------------------------------------------------------- + * + * dbDeleteCellUse --- + * + * Callback function from DBSrCellUses, calls BPDelete to remove a + * cell use from the cell plane + * + * -------------------------------------------------------------------- */ -int -dbFreeCellFunc(tile) - Tile *tile; +int dbDeleteCellUse(CellUse *use, ClientData arg) { - CellTileBody *body; - CellUse *use; - Rect *bbox; - - for (body = (CellTileBody *) TiGetBody(tile); - body != NULL; - body = body->ctb_next) - { - use = body->ctb_use; - ASSERT(use != (CellUse *) NULL, "dbCellSrFunc"); - - bbox = &use->cu_bbox; - if ((BOTTOM(tile) <= bbox->r_ybot) && (RIGHT(tile) >= bbox->r_xtop)) - { - /* The parent must be null before DBCellDeleteUse will work */ - use->cu_parent = (CellDef *) NULL; - DBCellDeleteUse(use); - } - freeMagic((char *)body); - } - - TiFree(tile); + dbInstanceUnplace(use); return 0; } + /* * -------------------------------------------------------------------- diff --git a/database/DBtimestmp.c b/database/DBtimestmp.c index 8143eced..ce34b2e8 100644 --- a/database/DBtimestmp.c +++ b/database/DBtimestmp.c @@ -147,12 +147,9 @@ DBFixMismatch() * the uses. */ - if (!(cellDef->cd_flags & CDFIXEDBBOX)) - { - cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_xbot - 1; - cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_xbot - 1; - DBReComputeBbox(cellDef); - } + cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_xbot - 1; + cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_xbot - 1; + DBReComputeBbox(cellDef); /* Now, for each parent, recheck the parent in both the * old area of the child and the new area. diff --git a/database/DBtpaint2.c b/database/DBtpaint2.c index 1a0919f2..4f42de66 100644 --- a/database/DBtpaint2.c +++ b/database/DBtpaint2.c @@ -149,9 +149,9 @@ dbTechPaintErasePlanes() TileType t, s; int pNum; - /* Space tiles are special: they may appear on any plane */ - DBTypePaintPlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_CELL)); - DBTypeErasePlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_CELL)); + /* Space tiles are special: they may appear on any plane except router */ + DBTypePaintPlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_ROUTER)); + DBTypeErasePlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_ROUTER)); /* Skip TT_SPACE */ for (t = 1; t < DBNumTypes; t++) diff --git a/database/database.h.in b/database/database.h.in index 5b9bd777..4202e074 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -33,6 +33,10 @@ #include "utils/hash.h" #endif /* _HASH_H */ +#ifndef _BPLANE_H +#include "bplane/bplane.h" +#endif /* _BPLANE_H */ + /* ----------------------- Tunable constants -------------------------- */ #define MAXPLANES 64 /* Maximum number of planes per cell */ @@ -185,7 +189,7 @@ typedef unsigned char PaintResultType; #define PL_MAXTYPES MAXPLANES /* Maximum number of planes per cell */ -#define PL_CELL 0 /* Cell plane */ +#define PL_ROUTER 0 /* Used by the router and plow modules */ #define PL_DRC_CHECK 1 /* DRC plane for CHECK tiles */ #define PL_DRC_ERROR 2 /* DRC plane for ERROR tiles */ #define PL_M_HINT 3 /* magnet hints for irouter */ @@ -325,6 +329,7 @@ typedef struct celldef #endif char *cd_name; /* Name of cell */ struct celluse *cd_parents; /* NULL-terminated list of all uses */ + BPlane *cd_cellPlane; /* Instance locations */ Plane *cd_planes[MAXPLANES]; /* Tiles */ ClientData cd_client; /* This space for rent */ int cd_timestamp; /* Unique integer identifying last @@ -461,6 +466,17 @@ typedef struct typedef struct celluse { + /* Binning plane element struct header---must go first! */ + void *cu_bpLinks[BP_NUM_LINKS]; /* link fields */ + Rect cu_bbox; /* Bounding box of this use, with + * arraying taken into account, in + * coordinates of the parent def. + */ + /* End of BPlane header */ + + Rect cu_extended; /* Bounding box of this use, including + * the area of rendered text labels. + */ unsigned int cu_expandMask; /* Mask of windows in which this use * is expanded. */ @@ -473,13 +489,6 @@ typedef struct celluse * or NULL for end of list. */ CellDef *cu_parent; /* Cell def containing this use */ - Rect cu_bbox; /* Bounding box of this use, with - * arraying taken into account, in - * coordinates of the parent def. - */ - Rect cu_extended; /* Bounding box of this use, including - * the area of rendered text labels. - */ ClientData cu_client; /* This space for rent */ } CellUse; @@ -521,20 +530,6 @@ typedef struct celluse #define CU_DESCEND_NO_LOCK 0x0007 /* Descend unlocked subcells only */ #define CU_DESCEND_NONE 0x0009 /* Descend no subcells */ -/* - * All subcells used by a cell are part of another tile plane, - * called the `cell plane'. To handle overlap, each tile in - * this plane points to a list of cell uses that appear in the - * area covered by the tile. Where there is overlap, this list - * will contain more than one tile. - */ - -typedef struct celltilebody -{ - CellUse *ctb_use; /* Cell used */ - struct celltilebody *ctb_next; /* Next tile body on list */ -} CellTileBody; - /* * Declare tile type structure for non-manhattan geometry */ diff --git a/dbwind/DBWdisplay.c b/dbwind/DBWdisplay.c index 8ea1b3bd..3082a380 100644 --- a/dbwind/DBWdisplay.c +++ b/dbwind/DBWdisplay.c @@ -183,7 +183,7 @@ DBWredisplay(w, rootArea, clipArea) GrLock(w, TRUE); /* Round up the redisplay area by 1 pixel on all sides. This - * is needed because TiSrArea won't return tiles that touch + * is needed because DBSrPaintArea won't return tiles that touch * the area without overlapping it. Without the round-up, there * will be occasional (in fact, frequent), one-pixel wide slivers. */ @@ -516,9 +516,9 @@ DBWredisplay(w, rootArea, clipArea) dbwWatchTrans = crec->dbw_watchTrans; dbwWatchDemo = ((crec->dbw_flags & DBW_WATCHDEMO) != 0); dbwSeeTypes = ((crec->dbw_flags & DBW_SEETYPES) != 0); - (void) TiSrArea((Tile *) NULL, + (void) DBSrPaintArea((Tile *) NULL, crec->dbw_watchDef->cd_planes[crec->dbw_watchPlane], - &dbwWatchArea, dbwTileFunc, (ClientData) NULL); + &dbwWatchArea, &DBAllTypeBits, dbwTileFunc, (ClientData) NULL); } /* Record information so that the highlight manager will redisplay @@ -1114,7 +1114,7 @@ dbwTileFunc(tile) GrPutText(string, STYLE_DRAWTILE, &p, GEO_CENTER, GR_TEXT_LARGE, FALSE, &r2, (Rect *) NULL); -#define OFFSET 12 +#define XYOFFSET 12 for (i=0; i<4; i++) { @@ -1125,25 +1125,25 @@ dbwTileFunc(tile) case 0: stitch = BL(tile); p = pLL; - yoffset = OFFSET; + yoffset = XYOFFSET; pos = GEO_NORTHEAST; break; case 1: stitch = LB(tile); p = pLL; - xoffset = OFFSET; + xoffset = XYOFFSET; pos = GEO_NORTHEAST; break; case 2: stitch = RT(tile); p = pUR; - xoffset = -OFFSET; + xoffset = -XYOFFSET; pos = GEO_SOUTHWEST; break; case 3: stitch = TR(tile); p = pUR; - yoffset = -OFFSET; + yoffset = -XYOFFSET; pos = GEO_SOUTHWEST; break; } diff --git a/drc/DRCsubcell.c b/drc/DRCsubcell.c index 53eca616..ae53645d 100644 --- a/drc/DRCsubcell.c +++ b/drc/DRCsubcell.c @@ -43,9 +43,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ static Rect drcSubIntArea; /* Accumulates area of interactions. */ static CellDef *drcSubDef; /* Cell definition we're checking. */ static int drcSubRadius; /* Interaction radius. */ -static CellTileBody *drcCurSub; /* Holds current tile when checking to see - * if more than one use in an area. - */ static Rect drcSubLookArea; /* Area where we're looking for interactions */ static void (*drcSubFunc)(); /* Error function. */ static ClientData drcSubClientData; @@ -69,52 +66,10 @@ extern int DRCErrorType; /* * ---------------------------------------------------------------------------- * - * drcFindOtherCells -- + * drcSubcellFunc -- * - * This is a search function invoked when looking around a given - * cell for interactions. If a tile is found other than drcCurSub, - * then it constitutes an interaction, and its area is included - * into the area parameter. - * - * Results: - * Always returns 0 to keep the search alive. - * - * Side effects: - * The area parameter may be modified by including the area - * of the current tile. - * - * ---------------------------------------------------------------------------- - */ - -int -drcFindOtherCells(tile, area) - Tile *tile; /* Tile in subcell plane. */ - Rect *area; /* Area in which to include interactions. */ -{ - CellUse *use; - CellTileBody *ctbptr = (CellTileBody *) tile->ti_body; - - /* XXX */ - /* if (ctbptr == NULL) return 0; */ - - if (ctbptr == drcCurSub) return 0; - - for (ctbptr = (CellTileBody *) TiGetBody(tile); ctbptr != NULL; - ctbptr = ctbptr->ctb_next) - { - use = ctbptr->ctb_use; - GeoInclude(&use->cu_bbox, area); - } - return 0; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcSubcellTileFunc -- - * - * Called by TiSrArea when looking for interactions in - * a given area. It sees if this subcell tile participates + * Called by DBSrCellPlaneArea when looking for interactions in + * a given area. It sees if this subcell participates * in any interactions in the area we're rechecking. * * Results: @@ -128,36 +83,23 @@ drcFindOtherCells(tile, area) */ int -drcSubcellTileFunc(tile, propagate) - Tile *tile; /* Subcell tile. */ +drcSubcellFunc(subUse, propagate) + CellUse *subUse; /* Subcell instance. */ bool *propagate; /* Errors to propagate up */ { Rect area, haloArea, intArea, subIntArea, locIntArea; int i; - CellTileBody *ctbptr = (CellTileBody *) tile->ti_body; - CellUse *subUse; - - if (ctbptr == NULL) return 0; /* To determine interactions, find the bounding box of * all paint and other subcells within one halo of this - * subcell tile (and also within the original area where + * subcell (and also within the original area where * we're recomputing errors). */ - /* XXX This is not right---the area of the cell plane tile is not */ - /* the area of the subcell. */ - /* TiToRect(tile, &area); */ + area = subUse->cu_bbox; - for (ctbptr = (CellTileBody *) TiGetBody(tile); ctbptr != NULL; - ctbptr = ctbptr->ctb_next) - { - subUse = ctbptr->ctb_use; - area = subUse->cu_bbox; - - GEO_EXPAND(&area, drcSubRadius, &haloArea); - GeoClip(&haloArea, &drcSubLookArea); - } + GEO_EXPAND(&area, drcSubRadius, &haloArea); + GeoClip(&haloArea, &drcSubLookArea); intArea = GeoNullRect; for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) @@ -171,28 +113,14 @@ drcSubcellTileFunc(tile, propagate) /* interaction area of the parent. Ultimately this is recursive as */ /* all cells are checked and errors propagate to the top level. */ - /* XXX */ - for (ctbptr = (CellTileBody *) TiGetBody(tile); ctbptr != NULL; - ctbptr = ctbptr->ctb_next) - { - subUse = ctbptr->ctb_use; - subIntArea = GeoNullRect; - DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR], + subIntArea = GeoNullRect; + DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR], &TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea, (ClientData) &subIntArea); - GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea); - GeoInclude(&locIntArea, &intArea); - if (!GEO_RECTNULL(&subIntArea)) *propagate = TRUE; - } - drcCurSub = ctbptr; - (void) TiSrArea((Tile *) NULL, drcSubDef->cd_planes[PL_CELL], - &haloArea, drcFindOtherCells, (ClientData) &intArea); - if (GEO_RECTNULL(&intArea)) return 0; - - GEO_EXPAND(&intArea, drcSubRadius, &intArea); - GeoClip(&intArea, &haloArea); - (void) GeoInclude(&intArea, &drcSubIntArea); + GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea); + GeoInclude(&locIntArea, &intArea); + if (!GEO_RECTNULL(&subIntArea)) *propagate = TRUE; return 0; } @@ -330,8 +258,8 @@ DRCFindInteractions(def, area, radius, interaction) drcSubIntArea = GeoNullRect; GEO_EXPAND(area, radius, &drcSubLookArea); propagate = FALSE; - (void) TiSrArea((Tile *) NULL, def->cd_planes[PL_CELL], - &drcSubLookArea, drcSubcellTileFunc, (ClientData)(&propagate)); + (void) DBSrCellPlaneArea(def->cd_cellPlane, &drcSubLookArea, + drcSubcellFunc, (ClientData)(&propagate)); /* If there seems to be an interaction area, make a second pass * to make sure there's more than one cell with paint in the diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index af204cdb..6f600f2d 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -1552,8 +1552,7 @@ esMakePorts(hc, cdata) char *name, *portname, *tptr, *aptr, *locname; int j; - /* Done when the bottom of the hierarchy is reached */ - if (HashGetNumEntries(&def->def_uses) == 0) return 0; + if (def->def_uses == NULL) return 0; /* Bottom of hierarchy */ for (conn = (Connection *)def->def_conns; conn; conn = conn->conn_next) { @@ -1580,11 +1579,13 @@ esMakePorts(hc, cdata) // Find the cell for the instance portdef = NULL; - he = HashFind(&updef->def_uses, portname); - if (he != NULL) + for (use = updef->def_uses; use; use = use->use_next) { - use = (Use *)HashGetValue(he); - portdef = use->use_def; + if (!strcmp(use->use_id, portname)) + { + portdef = use->use_def; + break; + } } if ((aptr == NULL) || (aptr > tptr)) *tptr = '/'; @@ -1659,11 +1660,13 @@ esMakePorts(hc, cdata) // Find the cell for the instance portdef = NULL; - he = HashFind(&updef->def_uses, portname); - if (he != NULL) + for (use = updef->def_uses; use; use = use->use_next) { - use = (Use *)HashGetValue(he); - portdef = use->use_def; + if (!strcmp(use->use_id, portname)) + { + portdef = use->use_def; + break; + } } if ((aptr == NULL) || (aptr > tptr)) *tptr = '/'; @@ -1744,7 +1747,7 @@ esHierVisit(hc, cdata) if (def != topdef) { - if ((def->def_devs == NULL) && (HashGetNumEntries(&def->def_uses) == 0)) + if (def->def_devs == NULL && def->def_uses == NULL) { if (locDoSubckt == AUTO) { diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 381cdcf1..153fc69d 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -2061,7 +2061,7 @@ extOutputDevices(def, transList, outFile) if (ExtCurStyle->exts_deviceClass[t] == DEV_RSUBCKT) { - /* nothing */ + /* (Nothing) */ } else if (hasModel) /* SPICE semiconductor resistor */ { @@ -2079,7 +2079,6 @@ extOutputDevices(def, transList, outFile) fprintf(outFile, " \"%s\"", (subsName == NULL) ? "None" : subsName); } - break; case DEV_CAP: @@ -2145,7 +2144,7 @@ extOutputDevices(def, transList, outFile) if (ExtCurStyle->exts_deviceClass[t] == DEV_CSUBCKT) { - /* (Nothing) */ + /* (Nothing) */ } else /* SPICE semiconductor resistor */ { diff --git a/extract/ExtInter.c b/extract/ExtInter.c index e0626faa..9c7a5e35 100644 --- a/extract/ExtInter.c +++ b/extract/ExtInter.c @@ -113,7 +113,7 @@ ExtFindInteractions(def, halo, bloatby, resultPlane) * not including, the subtree under consideration. */ extInterUse = (CellUse *) NULL; - (void) extCellSrArea(&scx, extInterSubtree, (ClientData) NULL); + (void) DBCellSrArea(&scx, extInterSubtree, (ClientData) NULL); /* * Process parent paint if there were any subcells. @@ -123,7 +123,7 @@ ExtFindInteractions(def, halo, bloatby, resultPlane) if (extInterUse) { extInterUse = (CellUse *) NULL; - (void) extCellSrArea(&scx, extInterSubtreePaint, (ClientData) def); + (void) DBCellSrArea(&scx, extInterSubtreePaint, (ClientData) def); } UndoEnable(); } @@ -179,7 +179,7 @@ extInterSubtree(scx) BLOATBY(&parentScx.scx_area, extInterHalo); parentScx.scx_trans = GeoIdentityTransform; parentScx.scx_use = extParentUse; - (void) extCellSrArea(&parentScx, extInterSubtreeClip, (ClientData) scx); + (void) DBCellSrArea(&parentScx, extInterSubtreeClip, (ClientData) scx); } return (2); } @@ -286,7 +286,7 @@ extInterSubtreeTile(tile, cxp) else newscx.scx_area = r; newscx.scx_trans = GeoIdentityTransform; newscx.scx_use = extParentUse; - (void) extCellSrArea(&newscx, extInterOverlapSubtree, (ClientData) NULL); + (void) DBCellSrArea(&newscx, extInterOverlapSubtree, (ClientData) NULL); return (0); } @@ -394,7 +394,7 @@ extInterOverlapTile(tile, cxp) * * The client procedure should not modify any of the paint planes in * the cells visited by extTreeSrTiles, because we use DBSrPaintArea - * instead of TiSrArea as our paint-tile enumeration function. + * as our paint-tile enumeration function. * * Results: * 0 is returned if the search finished normally. 1 is returned @@ -442,7 +442,7 @@ extTreeSrPaintArea(scx, func, cdarg) return (1); /* Visit our children recursively */ - return (extCellSrArea(scx, extTreeSrFunc, (ClientData) &filter)); + return (DBCellSrArea(scx, extTreeSrFunc, (ClientData) &filter)); } /* @@ -477,215 +477,6 @@ extTreeSrFunc(scx, fp) return (1); /* Visit our children recursively */ - return (extCellSrArea(scx, extTreeSrFunc, (ClientData) fp)); + return (DBCellSrArea(scx, extTreeSrFunc, (ClientData) fp)); } - -/* - *----------------------------------------------------------------------------- - * - * extCellSrArea -- - * - * Apply the supplied procedure to each of the cellUses found in the - * given area in the subcell plane of the child def of the supplied - * search context. - * - * The procedure is applied to each array element in each cell use that - * overlaps the clipping rectangle. The scx_x and scx_y parts of - * the SearchContext passed to the filter function correspond to the - * array element being visited. The same CellUse is, of course, passed - * as scx_use for all elements of the array. - * - * The array elements are visited by varying the X coordinate fastest. - * - * The procedure should be of the following form: - * int - * func(scx, cdarg) - * SearchContext *scx; - * ClientData cdarg; - * { - * } - * - * Func normally returns 0. If it returns 1 then the search is - * aborted. If it returns 2, then any remaining elements in the - * current array are skipped. - * - * Results: - * 0 is returned if the search terminated normally. 1 is - * returned if it was aborted. - * - * Side effects: - * Whatever side effects are brought about by applying the - * procedure supplied. - * - *----------------------------------------------------------------------------- - */ -int -extCellSrArea(scx, func, cdarg) - SearchContext *scx; - /* Pointer to search context specifying a cell use to - * search, an area in the coordinates of the cell's - * def, and a transform back to "root" coordinates. - * The area may have zero size. - */ - int (*func)(); /* Function to apply at every tile found */ - ClientData cdarg; /* Argument to pass to function */ -{ - int xlo, xhi, ylo, yhi, xbase, ybase, xsep, ysep, clientResult; - int srchBot, srchRight; - Plane *plane = scx->scx_use->cu_def->cd_planes[PL_CELL]; - Tile *tp, *tpnew; - Rect *rect, *bbox; - CellUse *use; - SearchContext newScx; - CellTileBody *body; - Transform t, tinv; - TreeFilter filter; - Rect expanded; - Point start; - - filter.tf_func = func; - filter.tf_arg = cdarg; - - if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0) - if (!DBCellRead(scx->scx_use->cu_def, (char *) NULL, TRUE, NULL)) - return 0; - - /* - * In order to make this work with zero-size areas, we first expand - * the area by before searching the tile plane. extCellSrFunc will - * check carefully to throw out things that don't overlap the original - * area. The expansion is tricky because we mustn't expand infinities. - */ - - expanded = scx->scx_area; - if (expanded.r_xbot > TiPlaneRect.r_xbot) expanded.r_xbot -= 1; - if (expanded.r_ybot > TiPlaneRect.r_ybot) expanded.r_ybot -= 1; - if (expanded.r_xtop < TiPlaneRect.r_xtop) expanded.r_xtop += 1; - if (expanded.r_ytop < TiPlaneRect.r_ytop) expanded.r_ytop += 1; - rect = &expanded; - - /* Start along the top of the LHS of the search area */ - start.p_x = rect->r_xbot; - start.p_y = rect->r_ytop - 1; - tp = plane->pl_hint; - GOTOPOINT(tp, &start); - - /* Each iteration visits another tile on the LHS of the search area */ - while (TOP(tp) > rect->r_ybot) - { - /* Each iteration enumerates another tile */ -enumerate: - plane->pl_hint = tp; - if (SigInterruptPending) - return (1); - - /* - * Since subcells are allowed to overlap, a single tile body may - * refer to many subcells and a single subcell may be referred to - * by many tile bodies. To insure that each CellUse is enumerated - * exactly once, the procedure given to DBCellSrArea is only applied - * to a CellUse when its lower right corner is contained in the - * tile to dbCellSrFunc (or otherwise at the last tile encountered - * in the event the lower right corner of the CellUse is outside the - * search rectangle). - */ - srchBot = scx->scx_area.r_ybot; - srchRight = scx->scx_area.r_xtop; - for (body = (CellTileBody *) TiGetBody(tp); - body != NULL; - body = body->ctb_next) - { - use = newScx.scx_use = body->ctb_use; - ASSERT(use != (CellUse *) NULL, "dbCellSrFunc"); - - /* - * The check below is to ensure that we only enumerate each - * cell once, even though it appears in many different tiles - * in the subcell plane. - */ - bbox = &use->cu_bbox; - if ( (BOTTOM(tp) <= bbox->r_ybot || - (BOTTOM(tp) <= srchBot && bbox->r_ybot < srchBot)) - && (RIGHT(tp) >= bbox->r_xtop || - (RIGHT(tp) >= srchRight && bbox->r_xtop >= srchRight))) - { - /* - * Make sure that this cell really does overlap the - * search area (it could be just touching because of - * the expand-by-one in DBCellSrArea). - */ - if (!GEO_OVERLAP(&scx->scx_area, bbox)) continue; - - /* If not an array element, it's much simpler */ - if (use->cu_xlo == use->cu_xhi && use->cu_ylo == use->cu_yhi) - { - newScx.scx_x = use->cu_xlo, newScx.scx_y = use->cu_yhi; - if (SigInterruptPending) return 1; - GEOINVERTTRANS(&use->cu_transform, &tinv); - GEOTRANSTRANS(&use->cu_transform, &scx->scx_trans, - &newScx.scx_trans); - GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area); - if ((*func)(&newScx, filter.tf_arg) == 1) - return 1; - continue; - } - - /* - * More than a single array element; - * check to see which ones overlap our search area. - */ - DBArrayOverlap(use, &scx->scx_area, &xlo, &xhi, &ylo, &yhi); - xsep = (use->cu_xlo > use->cu_xhi) - ? -use->cu_xsep : use->cu_xsep; - ysep = (use->cu_ylo > use->cu_yhi) - ? -use->cu_ysep : use->cu_ysep; - for (newScx.scx_y = ylo; newScx.scx_y<=yhi; newScx.scx_y++) - for (newScx.scx_x = xlo; newScx.scx_x<=xhi; newScx.scx_x++) - { - if (SigInterruptPending) return 1; - xbase = xsep * (newScx.scx_x - use->cu_xlo); - ybase = ysep * (newScx.scx_y - use->cu_ylo); - GEOTRANSTRANSLATE(xbase, ybase, &use->cu_transform, &t); - GEOINVERTTRANS(&t, &tinv); - GEOTRANSTRANS(&t, &scx->scx_trans, &newScx.scx_trans); - GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area); - clientResult = (*func)(&newScx, filter.tf_arg); - if (clientResult == 2) goto skipArray; - else if (clientResult == 1) return 1; - } - } - skipArray: continue; - } - - tpnew = TR(tp); - if (LEFT(tpnew) < rect->r_xtop) - { - while (BOTTOM(tpnew) >= rect->r_ytop) tpnew = LB(tpnew); - if (BOTTOM(tpnew) >= BOTTOM(tp) || BOTTOM(tp) <= rect->r_ybot) - { - tp = tpnew; - goto enumerate; - } - } - - /* Each iteration returns one tile further to the left */ - while (LEFT(tp) > rect->r_xbot) - { - if (BOTTOM(tp) <= rect->r_ybot) - return (0); - tpnew = LB(tp); - tp = BL(tp); - if (BOTTOM(tpnew) >= BOTTOM(tp) || BOTTOM(tp) <= rect->r_ybot) - { - tp = tpnew; - goto enumerate; - } - } - - /* At left edge -- walk down to next tile along the left edge */ - for (tp = LB(tp); RIGHT(tp) <= rect->r_xbot; tp = TR(tp)) - /* Nothing */; - } - return (0); -} diff --git a/extract/ExtMain.c b/extract/ExtMain.c index 2eba659f..46e9db7f 100644 --- a/extract/ExtMain.c +++ b/extract/ExtMain.c @@ -475,7 +475,7 @@ extContainsGeometry(def, allButUse, area) bool extContainsCellFunc(); int pNum; - if (TiSrArea((Tile *) NULL, def->cd_planes[PL_CELL], area, + if (DBSrCellPlaneArea(def->cd_cellPlane, area, extContainsCellFunc, (ClientData) allButUse)) return (TRUE); @@ -489,17 +489,11 @@ extContainsGeometry(def, allButUse, area) } bool -extContainsCellFunc(tile, allButUse) - Tile *tile; +extContainsCellFunc(use, allButUse) + CellUse *use; CellUse *allButUse; { - CellTileBody *ctb; - - for (ctb = (CellTileBody *) TiGetBody(tile); ctb; ctb = ctb->ctb_next) - if (ctb->ctb_use != allButUse) - return (TRUE); - - return (FALSE); + return (use != allButUse) ? TRUE : FALSE; } int diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 24c91726..8c8c91cf 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -31,6 +31,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "tcltk/tclmagic.h" #include "utils/magic.h" +#include "tcltk/tclmagic.h" #include "utils/geometry.h" #include "utils/geofast.h" #include "tiles/tile.h" @@ -175,10 +176,10 @@ extSubtree(parentUse, reg, f) * halo has been set above to reflect the maximum distance for * sidewall coupling capacitance). */ - b = &def->cd_bbox; - /* Monitor progress, for large designs */ + /* Monitor progress, for large designs, and allow display refresh at intervals */ + totcuts = (b->r_ytop - b->r_ybot + ExtCurStyle->exts_stepSize - 1) / ExtCurStyle->exts_stepSize; totcuts *= ((b->r_xtop - b->r_xbot + ExtCurStyle->exts_stepSize - 1) @@ -233,7 +234,6 @@ extSubtree(parentUse, reg, f) /* even if there were no other interactions found. */ SearchContext scx; - GEOCLIP(&ha.ha_clipArea, &r); scx.scx_trans = GeoIdentityTransform; scx.scx_area = r; scx.scx_use = ha.ha_parentUse; @@ -243,8 +243,8 @@ extSubtree(parentUse, reg, f) cuts++; pdone = 100.0 * ((float)cuts / (float)totcuts); if ((((pdone - plast) > 5.0) || (cuts == totcuts)) && (cuts > 1)) { - TxPrintf("Completed %d%%\n", (int)(pdone + 0.5)); - plast = pdone; + TxPrintf("Completed %d%%\n", (int)(pdone + 0.5)); + plast = pdone; TxFlushOut(); #ifdef MAGIC_WRAPPER diff --git a/extract/ExtTech.c b/extract/ExtTech.c index c4744879..c79c55e9 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -2854,14 +2854,14 @@ zinit: } /* If global variable "doConvert" is TRUE, then we convert from */ - /* microns to lambda and microns^2 to lambda^2, based on the */ - /* current value of DBLambda and output scale. */ + /* microns to lambda and microns^2 to lambda^2. */ if (doConvert) { - /* Convert from micron units in the file to the current */ - /* physical scalefactor as determined by the default CIF */ - /* output scale. */ + /* Use current CIF output scale for determining the scale */ + /* factor between micron units in the extract section and */ + /* lambda units of the database (conversion from lambda to */ + /* internal units is done separately). */ float dscale = CIFGetOutputScale(1000); diff --git a/lef/defRead.c b/lef/defRead.c index 370e3992..f7f7ee32 100644 --- a/lef/defRead.c +++ b/lef/defRead.c @@ -577,7 +577,7 @@ DefReadLocation(use, f, oscale, tptr) float oscale; Transform *tptr; { - Rect *r, tr; + Rect *r, tr, rect; int keyword; char *token; float x, y; @@ -611,7 +611,25 @@ DefReadLocation(use, f, oscale, tptr) /* restore the lower-left corner position. */ if (use) + { r = &use->cu_def->cd_bbox; + + /* Abstract views with fixed bounding boxes use the FIXED_BBOX property */ + + if (use->cu_def->cd_flags & CDFIXEDBBOX) + { + char *propval; + bool found; + + propval = DBPropGet(use->cu_def, "FIXED_BBOX", &found); + if (found) + { + if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot, + &rect.r_xtop, &rect.r_ytop) == 4) + r = ▭ + } + } + } else r = &GeoNullRect; @@ -805,9 +823,9 @@ DefReadPins(f, rootDef, sname, oscale, total) currect = LefReadRect(f, curlayer, oscale); if (pending) { - flags = PORT_DIR_MASK; /* If layer was unknown, set to space and force */ /* non-sticky. */ + flags = PORT_DIR_MASK; if (curlayer < 0) curlayer = TT_SPACE; else @@ -828,9 +846,9 @@ DefReadPins(f, rootDef, sname, oscale, total) pending = TRUE; else { - flags = PORT_DIR_MASK; /* If layer was unknown, set to space and force */ /* non-sticky. */ + flags = PORT_DIR_MASK; if (curlayer < 0) curlayer = TT_SPACE; else diff --git a/lef/lefRead.c b/lef/lefRead.c index 29040813..08e1b08f 100644 --- a/lef/lefRead.c +++ b/lef/lefRead.c @@ -1350,7 +1350,7 @@ LefReadMacro(f, mname, oscale, importForeign) CellDef *lefMacro; HashEntry *he; - char *token, tsave[128]; + char *token, tsave[128], *propval; int keyword, pinNum; float x, y; bool has_size, is_imported = FALSE; @@ -1544,13 +1544,16 @@ origin_error: if (is_imported) { - /* Redefine cell bounding box to match the LEF macro */ - /* Leave "extended" to mark the original bounding box */ + /* Define the FIXED_BBOX property to match the LEF macro */ if (has_size) { - lefMacro->cd_bbox = lefBBox; lefMacro->cd_flags |= CDFIXEDBBOX; + propval = (char *)mallocMagic(40); + sprintf(propval, "%d %d %d %d", + lefBBox.r_xbot, lefBBox.r_ybot, + lefBBox.r_xtop, lefBBox.r_ytop); + DBPropPut(lefMacro, "FIXED_BBOX", propval); } } else @@ -1564,15 +1567,21 @@ origin_error: } else { - char *propstr = (char *)mallocMagic(64); int reducer = DBCellFindScale(lefMacro); lefMacro->cd_bbox = lefBBox; lefMacro->cd_extended = lefBBox; } - /* Fix the bounding box and do not allow edits */ - lefMacro->cd_flags |= /* CDNOEDIT | */ CDFIXEDBBOX; + /* Set the placement bounding box property to the current bounding box */ + lefMacro->cd_flags |= CDFIXEDBBOX; + propval = (char *)mallocMagic(40); + sprintf(propval, "%d %d %d %d", + lefMacro->cd_bbox.r_xbot, + lefMacro->cd_bbox.r_ybot, + lefMacro->cd_bbox.r_xtop, + lefMacro->cd_bbox.r_ytop); + DBPropPut(lefMacro, "FIXED_BBOX", propval); DRCCheckThis(lefMacro, TT_CHECKPAINT, &lefMacro->cd_bbox); } diff --git a/magic/Makefile b/magic/Makefile index fb695b95..1f8a857b 100644 --- a/magic/Makefile +++ b/magic/Makefile @@ -8,15 +8,25 @@ SRCS = magicTop.c include ${MAGICDIR}/defs.mak -EXTRA_LIBS = ${MAGICDIR}/cmwind/libcmwind.o ${MAGICDIR}/commands/libcommands.o \ - ${MAGICDIR}/database/libdatabase.o ${MAGICDIR}/dbwind/libdbwind.o \ - ${MAGICDIR}/drc/libdrc.o ${MAGICDIR}/debug/libdebug.o \ - ${MAGICDIR}/extract/libextract.o ${MAGICDIR}/graphics/libgraphics.o \ - ${MAGICDIR}/select/libselect.o ${MAGICDIR}/textio/libtextio.o \ - ${MAGICDIR}/tiles/libtiles.o ${MAGICDIR}/windows/libwindows.o \ - ${MAGICDIR}/wiring/libwiring.o ${MAGICDIR}/resis/libresis.o \ - ${MAGICDIR}/sim/libsim.o ${MAGICDIR}/netmenu/libnetmenu.o \ - ${MAGICDIR}/plow/libplow.o ${MAGICDIR}/utils/libutils.o \ +EXTRA_LIBS = ${MAGICDIR}/bplane/libbplane.o \ + ${MAGICDIR}/cmwind/libcmwind.o \ + ${MAGICDIR}/commands/libcommands.o \ + ${MAGICDIR}/database/libdatabase.o \ + ${MAGICDIR}/dbwind/libdbwind.o \ + ${MAGICDIR}/drc/libdrc.o \ + ${MAGICDIR}/debug/libdebug.o \ + ${MAGICDIR}/extract/libextract.o \ + ${MAGICDIR}/graphics/libgraphics.o \ + ${MAGICDIR}/select/libselect.o \ + ${MAGICDIR}/textio/libtextio.o \ + ${MAGICDIR}/tiles/libtiles.o \ + ${MAGICDIR}/windows/libwindows.o \ + ${MAGICDIR}/wiring/libwiring.o \ + ${MAGICDIR}/resis/libresis.o \ + ${MAGICDIR}/sim/libsim.o \ + ${MAGICDIR}/netmenu/libnetmenu.o \ + ${MAGICDIR}/plow/libplow.o \ + ${MAGICDIR}/utils/libutils.o \ ${MAIN_EXTRA_LIBS} BITMAPS = up.xbm down.xbm left.xbm right.xbm zoom.xbm lock.xbm diff --git a/plow/PlowMain.c b/plow/PlowMain.c index ac2b333c..2a8b1105 100644 --- a/plow/PlowMain.c +++ b/plow/PlowMain.c @@ -739,7 +739,7 @@ plowPropagateRect(def, userRect, lc, changedArea) lc, plowInitialPaint, (ClientData) plowRect.r_xtop); /* Find any subcells crossed by the plow */ - (void) TiSrArea((Tile *) NULL, plowYankDef->cd_planes[PL_CELL], + (void) DBSrCellPlaneArea(plowYankDef->cd_cellPlane, &cellPlowRect, plowInitialCell, (ClientData) &cellPlowRect); /* While edges remain, process them */ @@ -1120,7 +1120,7 @@ plowFindSelCell(yankUse, editUse) return (0); edge.e_flags = 0; - edge.e_pNum = PL_CELL; + edge.e_pNum = PL_ROUTER; edge.e_use = yankUse; edge.e_ytop = yankUse->cu_bbox.r_ytop; edge.e_ybot = yankUse->cu_bbox.r_ybot; @@ -1443,45 +1443,39 @@ plowInitialPaint(edge, xnew) */ int -plowInitialCell(cellTile, plowRect) - Tile *cellTile; +plowInitialCell(use, plowRect) + CellUse *use; Rect *plowRect; { - CellTileBody *ctb; - CellUse *use; int xmove; Edge edge; - edge.e_pNum = PL_CELL; - for (ctb = (CellTileBody *) TiGetBody(cellTile); ctb; ctb = ctb->ctb_next) + if (use->cu_bbox.r_xbot < plowRect->r_xbot) { - use = ctb->ctb_use; - if (use->cu_bbox.r_xbot < plowRect->r_xbot) - { - if (use->cu_bbox.r_xtop >= plowRect->r_xtop) - continue; + if (use->cu_bbox.r_xtop >= plowRect->r_xtop) + return 0; - /* Dragging this cell by its front edge */ - xmove = plowRect->r_xtop - use->cu_bbox.r_xtop; - } - else - { - /* Pushing this cell by its back edge */ - xmove = plowRect->r_xtop - use->cu_bbox.r_xbot; - } - - edge.e_use = use; - edge.e_flags = E_ISINITIAL; - edge.e_ytop = use->cu_bbox.r_ytop; - edge.e_ybot = use->cu_bbox.r_ybot; - edge.e_x = use->cu_bbox.r_xtop; - edge.e_newx = use->cu_bbox.r_xtop + xmove; - edge.e_ltype = PLOWTYPE_CELL; - edge.e_rtype = PLOWTYPE_CELL; - (void) plowQueueAdd(&edge); + /* Dragging this cell by its front edge */ + xmove = plowRect->r_xtop - use->cu_bbox.r_xtop; + } + else + { + /* Pushing this cell by its back edge */ + xmove = plowRect->r_xtop - use->cu_bbox.r_xbot; } - return (0); + edge.e_pNum = PL_ROUTER; + edge.e_use = use; + edge.e_flags = E_ISINITIAL; + edge.e_ytop = use->cu_bbox.r_ytop; + edge.e_ybot = use->cu_bbox.r_ybot; + edge.e_x = use->cu_bbox.r_xtop; + edge.e_newx = use->cu_bbox.r_xtop + xmove; + edge.e_ltype = PLOWTYPE_CELL; + edge.e_rtype = PLOWTYPE_CELL; + (void) plowQueueAdd(&edge); + + return 0; } /* diff --git a/plow/PlowRules2.c b/plow/PlowRules2.c index af9e6925..2748ae96 100644 --- a/plow/PlowRules2.c +++ b/plow/PlowRules2.c @@ -856,8 +856,7 @@ void prFindCells(edge) Edge *edge; /* Edge being moved */ { - Plane *cellPlane = plowYankDef->cd_planes[PL_CELL]; - Tile *cellTile = cellPlane->pl_hint; + BPlane *cellPlane = plowYankDef->cd_cellPlane; struct applyRule ar; Rect searchArea; @@ -867,18 +866,7 @@ prFindCells(edge) searchArea.r_xtop = edge->e_newx + DRCTechHalo; ar.ar_moving = edge; - /* - * Don't bother doing anything if there is a single space tile - * beneath the plow. - */ - if (TiGetBody(cellTile) == (ClientData) NULL - && LEFT(cellTile) <= searchArea.r_xbot - && BOTTOM(cellTile) <= searchArea.r_ybot - && RIGHT(cellTile) >= searchArea.r_xtop - && TOP(cellTile) >= searchArea.r_ytop) - return; - - (void) TiSrArea(cellTile, cellPlane, &searchArea, plowFoundCell, + (void) DBSrCellPlaneArea(cellPlane, &searchArea, plowFoundCell, (ClientData) &ar); } @@ -947,7 +935,7 @@ prCell(edge) cellArea.r_xtop = edge->e_newx + DRCTechHalo; cellArea.r_ybot = edge->e_ybot - DRCTechHalo; cellArea.r_ytop = edge->e_ytop + DRCTechHalo; - (void) TiSrArea((Tile *) NULL, plowYankDef->cd_planes[edge->e_pNum], + (void) DBSrCellPlaneArea(plowYankDef->cd_cellPlane, &cellArea, plowFoundCell, (ClientData) &ar); } @@ -1068,52 +1056,47 @@ plowCellPushPaint(impactedEdge, ar) */ int -plowFoundCell(cellTile, ar) - Tile *cellTile; +plowFoundCell(use, ar) + CellUse *use; struct applyRule *ar; { Edge *movingEdge = ar->ar_moving; - CellTileBody *ctb; int xmove, xsep; - CellUse *use; Edge edge; - edge.e_pNum = PL_CELL; - for (ctb = (CellTileBody *) TiGetBody(cellTile); ctb; ctb = ctb->ctb_next) - { - use = ctb->ctb_use; - if (use->cu_bbox.r_xbot <= movingEdge->e_x) - { - /* - * If dragging the cell, move it by as much as this edge. - */ - xmove = movingEdge->e_newx - movingEdge->e_x; - } - else - { - /* - * If pushing the cell, keep it DRCTechHalo in front of the edge - * unless it was already closer. - */ - xsep = use->cu_bbox.r_xbot - movingEdge->e_x; - if (xsep > DRCTechHalo) xsep = DRCTechHalo; - xmove = movingEdge->e_newx + xsep - use->cu_bbox.r_xbot; - } + edge.e_pNum = PL_ROUTER; - /* Only queue the edge if the cell has not moved far enough */ - if ((use->cu_client != (ClientData)CLIENTDEFAULT) && + if (use->cu_bbox.r_xbot <= movingEdge->e_x) + { + /* + * If dragging the cell, move it by as much as this edge. + */ + xmove = movingEdge->e_newx - movingEdge->e_x; + } + else + { + /* + * If pushing the cell, keep it DRCTechHalo in front of the edge + * unless it was already closer. + */ + xsep = use->cu_bbox.r_xbot - movingEdge->e_x; + if (xsep > DRCTechHalo) xsep = DRCTechHalo; + xmove = movingEdge->e_newx + xsep - use->cu_bbox.r_xbot; + } + + /* Only queue the edge if the cell has not moved far enough */ + if ((use->cu_client != (ClientData)CLIENTDEFAULT) && ((int)(use->cu_client) < xmove)) - { - edge.e_use = use; - edge.e_flags = 0; - edge.e_ytop = use->cu_bbox.r_ytop; - edge.e_ybot = use->cu_bbox.r_ybot; - edge.e_x = use->cu_bbox.r_xtop; - edge.e_newx = use->cu_bbox.r_xtop + xmove; - edge.e_ltype = PLOWTYPE_CELL; - edge.e_rtype = PLOWTYPE_CELL; - (void) (*plowPropagateProcPtr)(&edge); - } + { + edge.e_use = use; + edge.e_flags = 0; + edge.e_ytop = use->cu_bbox.r_ytop; + edge.e_ybot = use->cu_bbox.r_ybot; + edge.e_x = use->cu_bbox.r_xtop; + edge.e_newx = use->cu_bbox.r_xtop + xmove; + edge.e_ltype = PLOWTYPE_CELL; + edge.e_rtype = PLOWTYPE_CELL; + (void) (*plowPropagateProcPtr)(&edge); } return (0); diff --git a/plow/PlowYank.c b/plow/PlowYank.c index 532ec4db..08d24276 100644 --- a/plow/PlowYank.c +++ b/plow/PlowYank.c @@ -249,7 +249,7 @@ plowYankUpdateCell(yankChildUse) /* Restore the delta since DBPlaceCell re-initializes it to 0 */ yankChildUse->cu_client = savedelta; - /* Return 1 so TiSrArea doesn't bomb */ + /* Return 1 so DBSrCellPlaneArea doesn't bomb */ return (1); } } diff --git a/router/rtrDcmpose.c b/router/rtrDcmpose.c index fdfcb419..21466435 100644 --- a/router/rtrDcmpose.c +++ b/router/rtrDcmpose.c @@ -226,16 +226,18 @@ RtrDecompose(routeUse, area, netList) * Clear the valid flags for horizontal edges for all space tiles in * the error plane of the result cell. */ - (void) TiSrArea((Tile *) NULL, cdTo->cd_planes[PL_DRC_ERROR], &RouteArea, - rtrSrClear, (ClientData) &RouteArea); + (void) DBSrPaintArea((Tile *) NULL, cdTo->cd_planes[PL_DRC_ERROR], + &RouteArea, &DBAllTypeBits, rtrSrClear, + (ClientData) &RouteArea); /* * Enumerate all tiles in the given area. * If a tile is not a space tile, then perform the corner * extension algorithm. */ - (void) TiSrArea((Tile *) NULL, cdTo->cd_planes[PL_DRC_CHECK], &RouteArea, - rtrSrFunc, (ClientData) (cdTo->cd_planes[PL_DRC_ERROR])); + (void) DBSrPaintArea((Tile *) NULL, cdTo->cd_planes[PL_DRC_CHECK], + &RouteArea, &DBAllTypeBits, rtrSrFunc, + (ClientData) (cdTo->cd_planes[PL_DRC_ERROR])); /* Allow the modified area to be redisplayed if the cell is visible */ DBReComputeBbox(cdTo); @@ -344,8 +346,8 @@ rtrSrCells(scx, targetDef) * * Round a rectangle out to the nearest grid line, and * extend to a point halfway to the next grid point (if - * roundUp is TRUE) or back half a grid from the nearest - * grid line (if roundUp is FALSE). + * doRoundUp is TRUE) or back half a grid from the nearest + * grid line (if doRoundUp is FALSE). * * The halfway points are chosen to be RtrGridSpacing/2 * down or to the left from grid lines. Before rounding, @@ -362,16 +364,16 @@ rtrSrCells(scx, targetDef) */ void -rtrRoundRect(r, sepUp, sepDown, roundUp) +rtrRoundRect(r, sepUp, sepDown, doRoundUp) Rect *r; int sepUp, sepDown; - bool roundUp; + bool doRoundUp; { int halfGrid = RtrGridSpacing / 2; r->r_xbot = RTR_GRIDDOWN(r->r_xbot - sepDown, RtrOrigin.p_x); r->r_ybot = RTR_GRIDDOWN(r->r_ybot - sepDown, RtrOrigin.p_y); - if (roundUp) + if (doRoundUp) { r->r_xbot -= halfGrid; r->r_ybot -= halfGrid; @@ -390,7 +392,7 @@ rtrRoundRect(r, sepUp, sepDown, roundUp) */ r->r_xtop = RTR_GRIDUP(r->r_xtop + sepUp, RtrOrigin.p_x); r->r_ytop = RTR_GRIDUP(r->r_ytop + sepUp, RtrOrigin.p_y); - if (roundUp) + if (doRoundUp) { r->r_xtop += RtrGridSpacing - halfGrid; r->r_ytop += RtrGridSpacing - halfGrid; @@ -503,7 +505,7 @@ rtrSplitToArea(area, def) * * rtrSrClear -- * - * TiSrArea function for each tile in the error plane of the __CHANNEL__ + * DBSrPaintArea function for each tile in the error plane of the __CHANNEL__ * def. Sets the flags to 0 in internal space tiles, marking horizontal * invalid. Mark edges at the boundary of the routing region as valid. * @@ -561,12 +563,12 @@ rtrSrClear(tile, area) * * rtrSrFunc -- * - * Search function called from TiSrArea for each tile in the cell tile + * Search function called from DBSrPaintArea for each tile in the * plane. Do this search in the OLD TILE PLANE. Process corners * bordering space tiles. * * Results: - * Returns a 0 to TiSrArea so it won't abort the search. + * Returns a 0 to DBSrPaintArea so it won't abort the search. * * Side effects: * Modifies the result plane to reflect the channel structure. diff --git a/router/rtrMain.c b/router/rtrMain.c index 45aa49a4..26844c1c 100644 --- a/router/rtrMain.c +++ b/router/rtrMain.c @@ -127,8 +127,8 @@ Route(routeUse, routeArea) * but don't do anything else. */ RtrChannelList = (GCRChannel *) NULL; - (void) TiSrArea((Tile *) NULL, RtrChannelPlane, &RouteArea, - rtrMakeChannel, (ClientData) &RouteArea); + (void) DBSrPaintArea((Tile *) NULL, RtrChannelPlane, &RouteArea, + &DBAllTypeBits, rtrMakeChannel, (ClientData) &RouteArea); if (!SigInterruptPending) { errs = GARoute(RtrChannelList, routeUse, &netList); @@ -149,7 +149,7 @@ done: * * rtrMakeChannel -- * - * Function passed to TiSrArea to enumerate space tiles and convert them + * Function passed to DBSrPaintArea to enumerate space tiles and convert them * to channels. Clip all tiles against the box 'clipBox'. Don't set * hazards for this channel; that has to happen after stem assignment. * diff --git a/router/rtrSide.c b/router/rtrSide.c index deb36781..a9e880f7 100644 --- a/router/rtrSide.c +++ b/router/rtrSide.c @@ -228,14 +228,14 @@ rtrSideProcess(use, side, area, trans) { /* EAST (easy case since we don't have to transform) */ case GEO_EAST: - rtrSideTransPlane = use->cu_def->cd_planes[PL_CELL]; + rtrSideTransPlane = use->cu_def->cd_planes[PL_ROUTER]; break; /* Other cases use the transformed plane */ case GEO_SOUTH: case GEO_NORTH: case GEO_WEST: - rtrSideTransPlane = rtrSideTransDef->cd_planes[PL_CELL]; + rtrSideTransPlane = rtrSideTransDef->cd_planes[PL_ROUTER]; scx.scx_area = *area; scx.scx_use = use; scx.scx_trans = *trans; @@ -245,19 +245,19 @@ rtrSideProcess(use, side, area, trans) } /* Initialize all client fields to NULL in the cell tile plane */ - (void) TiSrArea((Tile *) NULL, rtrSideTransPlane, &rtrSideArea, - rtrSideInitClient, (ClientData) INFINITY); + (void) DBSrPaintArea((Tile *) NULL, rtrSideTransPlane, &rtrSideArea, + &DBAllTypeBits, rtrSideInitClient, (ClientData) INFINITY); /* Process all Sides for this direction */ - retval = TiSrArea((Tile *) NULL, rtrSideTransPlane, &rtrSideArea, - rtrEnumSidesFunc, (ClientData) NULL); + retval = DBSrPaintArea((Tile *) NULL, rtrSideTransPlane, &rtrSideArea, + &DBAllTypeBits, rtrEnumSidesFunc, (ClientData) NULL); /* Clean up; be absolutely sure to reset client info */ if (side == GEO_EAST) { SigDisableInterrupts(); - (void) TiSrArea((Tile *) NULL, rtrSideTransPlane, area, - rtrSideInitClient, (ClientData) CLIENTDEFAULT); + (void) DBSrPaintArea((Tile *) NULL, rtrSideTransPlane, area, + &DBAllTypeBits, rtrSideInitClient, (ClientData) CLIENTDEFAULT); SigEnableInterrupts(); } diff --git a/select/selDisplay.c b/select/selDisplay.c index 90b06233..8e00ccb0 100644 --- a/select/selDisplay.c +++ b/select/selDisplay.c @@ -307,11 +307,34 @@ selRedisplayCellFunc(scx, window) SearchContext *scx; /* Describes cell found. */ MagWindow *window; /* Window in which to redisplay. */ { - Rect tmp, screen; + Rect tmp, screen, bbox; Point p; char idName[100]; - GeoTransRect(&scx->scx_trans, &scx->scx_use->cu_def->cd_bbox, &tmp); + /* Selections of cells with a fixed bounding box flag show the outline */ + /* of the fixed bounding box, not the actual bounding box. */ + + if (scx->scx_use->cu_def->cd_flags & CDFIXEDBBOX) + { + bool found; + char *propval; + + propval = (char *)DBPropGet(scx->scx_use->cu_def, "FIXED_BBOX", &found); + if (found) + { + if (sscanf(propval, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, + &bbox.r_xtop, &bbox.r_ytop) == 4) + GeoTransRect(&scx->scx_trans, &bbox, &tmp); + else + found = FALSE; + } + if (!found) + GeoTransRect(&scx->scx_trans, &scx->scx_use->cu_def->cd_bbox, &tmp); + } + else + { + GeoTransRect(&scx->scx_trans, &scx->scx_use->cu_def->cd_bbox, &tmp); + } if (!DBSrPaintArea((Tile *) NULL, selRedisplayPlane, &tmp, &DBAllButSpaceBits, selAlways1, (ClientData) NULL)) return 0; diff --git a/sim/SimDBstuff.c b/sim/SimDBstuff.c index 72092caf..67c09c8f 100644 --- a/sim/SimDBstuff.c +++ b/sim/SimDBstuff.c @@ -676,7 +676,7 @@ SimSrConnect(def, startArea, mask, connect, bounds, func, clientData) * * The client procedure should not modify any of the paint planes in * the cells visited by SimTreeSrTiles, because we use DBSrPaintArea - * instead of TiSrArea as our paint-tile enumeration function. + * as our paint-tile enumeration function. * * Results: * 0 is returned if the search finished normally. 1 is returned diff --git a/tiles/Makefile b/tiles/Makefile index 2bd943b3..e5684e01 100644 --- a/tiles/Makefile +++ b/tiles/Makefile @@ -4,7 +4,7 @@ MODULE = tiles MAGICDIR = .. -SRCS = tile.c search.c search2.c +SRCS = tile.c search.c include ${MAGICDIR}/defs.mak include ${MAGICDIR}/rules.mak diff --git a/tiles/search2.c b/tiles/search2.c deleted file mode 100644 index 8739f3ef..00000000 --- a/tiles/search2.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * search2.c -- - * - * Area searching. - * - * ********************************************************************* - * * 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/tiles/search2.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; -#endif /* not lint */ - -#include - -#include "utils/magic.h" -#include "utils/geometry.h" -#include "tiles/tile.h" -#include "utils/signals.h" - -/* -------------------- Local function headers ------------------------ */ - -int tiSrAreaEnum(); - -/* - * -------------------------------------------------------------------- - * - * TiSrArea -- - * - * Find all tiles contained in or incident upon a given area. - * Applies the given procedure to all tiles found. The procedure - * should be of the following form: - * - * int - * func(tile, cdata) - * Tile *tile; - * ClientData cdata; - * { - * } - * - * Func normally should return 0. If it returns 1 then the search - * will be aborted. - * - * THIS PROCEDURE IS OBSOLETE EXCEPT FOR THE SUBCELL PLANE. USE - * DBSrPaintArea() IF YOU WANT TO SEARCH FOR PAINT TILES. - * - * Results: - * 0 is returned if the search completed normally. 1 is returned - * if it aborted. - * - * Side effects: - * Whatever side effects result from application of the - * supplied procedure. - * - * NOTE: - * The procedure called is free to do anything it wishes to tiles - * which have already been visited in the area search, but it must - * not affect anything about tiles not visited other than possibly - * corner stitches to tiles already visited. - * - * ************************************************************************* - * ************************************************************************* - * **** **** - * **** WARNING **** - * **** **** - * **** This code is INCREDIBLY sensitive to modification! **** - * **** Change it only with the utmost caution, or you'll **** - * **** be verrry sorry! **** - * **** **** - * ************************************************************************* - * ************************************************************************* - * - * -------------------------------------------------------------------- - */ - -int -TiSrArea(hintTile, plane, rect, func, arg) - Tile *hintTile; /* Tile at which to begin search, if not NULL. - * If this is NULL, use the hint tile supplied - * with plane. - */ - Plane *plane; /* Plane in which tiles lie. This is used to - * provide a hint tile in case hintTile == NULL. - * The hint tile in the plane is updated to be - * the last tile visited in the area enumeration. - */ - Rect *rect;/* Area to search */ - int (*func)(); /* Function to apply at each tile */ - ClientData arg; /* Additional argument to pass to (*func)() */ -{ - Point here; - Tile *tp, *enumTR, *enumTile; - int enumRight, enumBottom; - - /* - * We will scan from top to bottom along the left hand edge - * of the search area, searching for tiles. Each tile we - * find in this search will be enumerated. - */ - - here.p_x = rect->r_xbot; - here.p_y = rect->r_ytop - 1; - enumTile = hintTile ? hintTile : plane->pl_hint; - GOTOPOINT(enumTile, &here); - plane->pl_hint = enumTile; - - while (here.p_y >= rect->r_ybot) - { - if (SigInterruptPending) return 1; - /* - * Find the tile (tp) immediately below the one to be - * enumerated (enumTile). This must be done before we enumerate - * the tile, as the filter function applied to enumerate - * it can result in its deallocation or modification in - * some other way. - */ - here.p_y = BOTTOM(enumTile) - 1; - tp = enumTile; - GOTOPOINT(tp, &here); - plane->pl_hint = tp; - - enumRight = RIGHT(enumTile); - enumBottom = BOTTOM(enumTile); - enumTR = TR(enumTile); - if ((*func)(enumTile, arg)) return 1; - - /* - * If the right boundary of the tile being enumerated is - * inside of the search area, recursively enumerate - * tiles to its right. - */ - - if (enumRight < rect->r_xtop) - if (tiSrAreaEnum(enumTR, enumBottom, rect, func, arg)) - return 1; - enumTile = tp; - } - return 0; -} - -/* - * -------------------------------------------------------------------- - * - * tiSrAreaEnum -- - * - * Perform the recursive edge search of the tile which has just been - * enumerated in an area search. The arguments passed are the RT - * corner stitch and bottom coordinate of the tile just enumerated. - * - * Results: - * 0 is returned if the search completed normally, 1 if - * it was aborted. - * - * Side effects: - * Attempts to enumerate recursively each tile found in walking - * along the right edge of the tile just enumerated. Whatever - * side effects occur result from the application of the client's - * filter function. - * - * -------------------------------------------------------------------- - */ - -int -tiSrAreaEnum(enumRT, enumBottom, rect, func, arg) - Tile *enumRT; /* TR corner stitch of tile just enumerated */ - int enumBottom; /* Bottom coordinate of tile just enumerated */ - Rect *rect; /* Area to search */ - int (*func)(); /* Function to apply at each tile */ - ClientData arg; /* Additional argument to pass to (*func)() */ -{ - Tile *tp, *tpLB, *tpTR; - int tpRight, tpNextTop, tpBottom, srchBottom; - int atBottom = (enumBottom <= rect->r_ybot); - - - /* - * Begin examination of tiles along right edge. - * A tile to the right of the one being enumerated is enumerable if: - * - its bottom lies at or above that of the tile being enumerated, or, - * - the bottom of the tile being enumerated lies at or below the - * bottom of the search rectangle. - */ - - if ((srchBottom = enumBottom) < rect->r_ybot) - srchBottom = rect->r_ybot; - - for (tp = enumRT, tpNextTop = TOP(tp); tpNextTop > srchBottom; tp = tpLB) - { - if (SigInterruptPending) return 1; - - /* - * Since the client's filter function may result in this tile - * being deallocated or otherwise modified, we must extract - * all the information we will need from the tile before we - * apply the filter function. - */ - - tpLB = LB(tp); - tpNextTop = TOP(tpLB); /* Since TOP(tpLB) comes from tp */ - - if (BOTTOM(tp) < rect->r_ytop && (atBottom || BOTTOM(tp) >= enumBottom)) - { - /* - * We extract more information from the tile, which we will use - * after applying the filter function. - */ - - tpRight = RIGHT(tp); - tpBottom = BOTTOM(tp); - tpTR = TR(tp); - if ((*func)(tp, arg)) return 1; - - /* - * If the right boundary of the tile being enumerated is - * inside of the search area, recursively enumerate - * tiles to its right. - */ - - if (tpRight < rect->r_xtop) - if (tiSrAreaEnum(tpTR, tpBottom, rect, func, arg)) - return 1; - } - } - return 0; -} diff --git a/utils/Makefile b/utils/Makefile index 642267dc..e8dd8a50 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -6,11 +6,11 @@ MODULE = utils MAGICDIR = .. LIB_SRCS = LIBdbio.c LIBmain.c LIBtextio.c SRCS = args.c child.c dqueue.c finddisp.c flock.c flsbuf.c fraction.c \ - geometry.c getrect.c hash.c heap.c list.c lookup.c lookupany.c \ - lookupfull.c macros.c main.c malloc.c match.c maxrect.c netlist.c \ - niceabort.c parser.c path.c pathvisit.c port.c printstuff.c \ - signals.c stack.c strdup.c runstats.c set.c show.c tech.c \ - touchtypes.c undo.c + geometry.c getrect.c hash.c heap.c ihash.c list.c lookup.c \ + lookupany.c lookupfull.c macros.c main.c malloc.c match.c \ + maxrect.c netlist.c niceabort.c parser.c path.c pathvisit.c \ + port.c printstuff.c signals.c stack.c strdup.c runstats.c set.c \ + show.c tech.c touchtypes.c undo.c include ${MAGICDIR}/defs.mak diff --git a/utils/geometry.c b/utils/geometry.c index 4f6761c0..7821da83 100644 --- a/utils/geometry.c +++ b/utils/geometry.c @@ -75,6 +75,7 @@ global int GeoOppositePos[] = */ global Rect GeoNullRect = { 0, 0, 0, 0 }; +global Rect GeoInvertedRect = { 0, 0, -1, -1 }; global Point GeoOrigin = { 0, 0 }; @@ -714,6 +715,24 @@ GeoIncludePoint(src, dst) } } +/*------------------------------------------------------------------- + * GeoIncludeRectInBBox() -- + * + * Expand bounding box to include rectangle r + * + *------------------------------------------------------------------- + */ +void +GeoIncludeRectInBBox(r, bbox) + Rect *r; + Rect *bbox; +{ + bbox->r_xbot = MIN(bbox->r_xbot,r->r_xbot); + bbox->r_ybot = MIN(bbox->r_ybot,r->r_ybot); + bbox->r_xtop = MAX(bbox->r_xtop,r->r_xtop); + bbox->r_ytop = MAX(bbox->r_ytop,r->r_ytop); +} + /*------------------------------------------------------------------- * GeoClip -- diff --git a/utils/geometry.h b/utils/geometry.h index 02a79df9..1cfb175e 100644 --- a/utils/geometry.h +++ b/utils/geometry.h @@ -190,6 +190,7 @@ extern int GeoRectPointSide(Rect *, Point *); extern int GeoRectRectSide(Rect *, Rect *); extern void GeoIncludePoint(Point *, Rect *); extern void GeoDecomposeTransform(Transform *, bool *, int *); +extern void GeoIncludeRectInBBox(Rect *, Rect *bbox); /* *------------------------------------------------------------------- @@ -207,6 +208,7 @@ extern Transform GeoRef45Transform; extern Transform GeoRef135Transform; extern Rect GeoNullRect; +extern Rect GeoInvertedRect; extern Point GeoOrigin; extern int GeoOppositePos[]; diff --git a/utils/ihash.c b/utils/ihash.c new file mode 100644 index 00000000..e6f8c7ef --- /dev/null +++ b/utils/ihash.c @@ -0,0 +1,360 @@ +// ************************************************************************ +// +// Copyright (c) 1995-2002 Juniper Networks, Inc. All rights reserved. +// +// Permission is hereby granted, without written agreement and without +// license or royalty fees, to use, copy, modify, and distribute this +// software and its documentation for any purpose, provided that the +// above copyright notice and the following three paragraphs appear in +// all copies of this software. +// +// IN NO EVENT SHALL JUNIPER NETWORKS, INC. BE LIABLE TO ANY PARTY FOR +// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// JUNIPER NETWORKS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +// DAMAGE. +// +// JUNIPER NETWORKS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +// NON-INFRINGEMENT. +// +// THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND JUNIPER +// NETWORKS, INC. HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +// ************************************************************************ + + + +/* ihash.c -- + * + * Implements "internal" hash, i.e. hash on user supplied structures, + * without need for parallel hash entry structs. + * + * pointers involving users structs are cast to (void *) + * This should make the pointer arithmetic work out regardless + * of alignments within structs. + * + * See ihash.h + * + */ + +#define DEREF(ptr,offset) ((ptr)+(offset)) + +static char rcsid[] = "$Header$"; +#include +#include +#include "utils/magic.h" +#include "utils/malloc.h" +#include "utils/utils.h" +#include "utils/ihash.h" + + +/* + * The following defines the ratio of # entries to # buckets + * at which we rebuild the table to make it larger. + */ +static int iHashResizeRatio = 3; + +/* forward reference */ +static void iHashResize(IHashTable *table); + +/* create a new hash table */ +/* offsets should be generated by pointer subtraction of (void *) pointers */ +extern IHashTable *IHashInit( + int nBuckets, + int keyOffset, + int nextOffset, + int (*hashFn)(void* key), + int (*sameKeyFn)(void* key1, void* key2) + ) +{ + IHashTable *table; + + table = (IHashTable *)mallocMagic(sizeof(IHashTable)); + table->iht_table = (void **)callocMagic(sizeof(void *)*nBuckets); + table->iht_nBucketsInit = nBuckets; + table->iht_nBuckets = nBuckets; + table->iht_nEntries = 0; + table->iht_keyOffset = keyOffset; + table->iht_nextOffset = nextOffset; + table->iht_hashFn = hashFn; + table->iht_sameKeyFn = sameKeyFn; + + return table; +} + + + +/* free hash table (does not free client structures) */ +void IHashFree(IHashTable *table) +{ + freeMagic((char *) table->iht_table); /* free buckets */ + freeMagic((char *) table); +} + +/* delete all entrys (and restore initial hash table size) */ +void IHashClear(IHashTable *table) +{ + /* reinitial bucket array */ + freeMagic((char *) table->iht_table); + table->iht_table = (void **)callocMagic(sizeof(void *)*table->iht_nBucketsInit); + + table->iht_nBuckets = table->iht_nBucketsInit; + table->iht_nEntries = 0; +} + +/* lookup an entry in table */ +void *IHashLookUp(IHashTable *table, void *key) +{ + int hash; + int bucket; + void *entry; + + hash = (table->iht_hashFn)(key); + bucket = ABS(hash) % table->iht_nBuckets; + + for(entry=table->iht_table[bucket]; + entry && !(table->iht_sameKeyFn)(key, DEREF(entry,(table->iht_keyOffset))); + entry = *((void **) DEREF(entry,table->iht_nextOffset))) /* empty body*/; + + return entry; +} + + +/* return next matching entry */ +void *IHashLookUpNext(IHashTable *table, void *prevEntry) +{ + void *entry; + void *key = DEREF(prevEntry,table->iht_keyOffset); + int hash = (table->iht_hashFn)(key); + int bucket = ABS(hash) % table->iht_nBuckets; + + for(entry = *((void **) DEREF(prevEntry,table->iht_nextOffset)); + entry && !(table->iht_sameKeyFn)(key,DEREF(entry,table->iht_keyOffset)); + entry = *((void **) DEREF(entry,table->iht_nextOffset))) /* empty body*/; + + return entry; +} + +/* add an entry in table */ +void IHashAdd(IHashTable *table, void *entry) +{ + int hash; + int bucket; + +/* ASSERT(!IHashLookUp(IHashTable, entry+IHashTable->iht_keyOffset),"IHashAdd"); */ + + hash = (table->iht_hashFn)(DEREF(entry,table->iht_keyOffset)); + bucket = ABS(hash) % table->iht_nBuckets; + + *(void **)DEREF(entry,table->iht_nextOffset) = table->iht_table[bucket]; + table->iht_table[bucket] = entry; + table->iht_nEntries++; + + /* if table getting crowded, resize it */ + if(table->iht_nEntries/table->iht_nBuckets >= iHashResizeRatio) + { + iHashResize(table); + } +} + +/* deletes an entry from table */ +/* + * NOTE: bplane code assumes IHashDelete() does not restructure table! + * (IHashLookUpNext() is called before IHashDelete(), and then the enum. + * is continued with further IHashLookUpNext() calls. + */ +void IHashDelete(IHashTable *table, void *entry) +{ + int hash; + int bucket; + void **pp; + int nextOffset = table->iht_nextOffset; + + hash = (table->iht_hashFn)DEREF(entry,table->iht_keyOffset); + bucket = ABS(hash) % table->iht_nBuckets; + + for(pp = &table->iht_table[bucket]; + (*pp) && (*pp) != entry; + pp = DEREF((*pp),nextOffset)); + + ASSERT(*pp,"IHashDelete"); + (*pp) = * (void **) DEREF(entry,nextOffset); + table->iht_nEntries--; +} + +/* return number of entries in table */ +int IHashEntries(IHashTable *table) +{ + return table->iht_nEntries; +} + +/* call back client func on each entry in hashtable */ +void IHashEnum(IHashTable *table, void (*clientFunc)(void *entry)) +{ + int bucket; + + for(bucket=0; bucketiht_nBuckets; bucket++) + { + void *entry; + for(entry=table->iht_table[bucket]; + entry; + entry = *((void **) DEREF(entry,table->iht_nextOffset))) + { + (*clientFunc)(entry); + } + } +} + +/* grow hash table */ +static void iHashResize(IHashTable *table) +{ + void **oldBuckets = table->iht_table; + int oldSize = table->iht_nBuckets; + int newSize = oldSize*4; + int bucket; + + /* alloc a new table */ + table->iht_table = (void **)callocMagic(sizeof(void *)*newSize); + table->iht_nBuckets = newSize; + table->iht_nEntries = 0; + + /* add back all entries in old table */ + for(bucket=0; bucketiht_nextOffset)); + IHashAdd(table,entry); + } + } + + /* finally, free old table */ + freeMagic((char *) oldBuckets); +} + +/* print out statistics */ +void IHashStats(IHashTable *table) +{ + int bucket; + + fprintf(stderr,"Internal Hash Statistics:\n"); + fprintf(stderr,"\tinitial buckets = %d\n", table->iht_nBucketsInit); + fprintf(stderr,"\tbuckets = %d\n", table->iht_nBuckets); + fprintf(stderr,"\tentries = %d\n", table->iht_nEntries); + fprintf(stderr,"\tkey offset = %d\n", table->iht_keyOffset); + fprintf(stderr,"\tnext offset = %d\n", table->iht_nextOffset); + fprintf(stderr,"\ndistribution: "); + + for(bucket=0; bucketiht_nBuckets; bucket++) + { + void *entry; + int num = 0; + for(entry=table->iht_table[bucket]; + entry; + entry = *((void **) DEREF(entry,table->iht_nextOffset))) + { + num++; + } + fprintf(stderr,"%d ",num); + } +} + +/* return statistics on hash table (returns memory utilized by table) */ +int IHashStats2(IHashTable *table, + int *nBuckets, /* if non-null return num buckets here */ + int *nEntries) /* if non-null return num entries here */ +{ + + if(nBuckets) *nBuckets = table->iht_nBuckets; + if(nEntries) *nEntries = table->iht_nEntries; + + return + UtlsStatMallocMem(sizeof(IHashTable)) + + UtlsStatMallocMem(sizeof(void *)* table->iht_nBuckets); +} + +/* hash for key fields that are pointers to strings */ +int IHashStringPKeyHash(void *key) +{ + char *s = * (char **) key; + int i=0; + + /* Add up the characters as though this were a number */ + while (*s != 0) i = (i*10) + (*s++ - '0'); + if(i<0) i = -i; + + return i; +} + +/* compare string pointer keys */ +int IHashStringPKeyEq(void *key1, void *key2) +{ + return strcmp(* (char **) key1, * (char **) key2)==0; +} + +/* hash for key fields that are strings */ +int IHashStringKeyHash(void *key) +{ + char *s = (char *) key; + int i=0; + + /* Add up the characters as though this were a number */ + while (*s != 0) i = (i*10) + (*s++ - '0'); + if(i<0) i = -i; + + return i; +} + +/* compare string keys */ +int IHashStringKeyEq(void *key1, void *key2) +{ + return strcmp((char *) key1, (char *) key2)==0; +} + +/* hash for key fields that are 32 bit words */ +int IHashWordKeyHash(void *keyp) +{ + /* just use the value of word itself! */ + return * (int *) keyp; +} + +/* compare struc for 32 bit word keys */ +int IHashWordKeyEq(void *key1p, void *key2p) +{ + return ( *(int *) key1p == * (int *) key2p); +} + + +/* hash for n-byte field */ +static __inline__ int +iHash(void *key, int n) +{ + char *s = (char *) key; + int hash=0; + int i; + + /* Add up the characters as though this were a number */ + for(i=0;i