Implemented first part of "mask hints", a method to allow mask

layers that are normally automatically generated to be supplemented
with additional geometry in the form of properties.  The first
commit implements a CIF operator "mask-hints" that tells CIFGenLayer
that additional geometry may be specified with a property named
"MASKHINTS_" plus the name passed to the operator as its only
argument.  A more extensive commit to be done will allow this
operator to be used on cifinput to use mask hints to retain the
exact geometry of mask layers used in the input file.
This commit is contained in:
Tim Edwards 2020-12-14 16:16:37 -05:00
parent 2b513eb3bb
commit ea9d8cc3e5
6 changed files with 208 additions and 45 deletions

View File

@ -1 +1 @@
8.3.96
8.3.97

View File

@ -4673,6 +4673,9 @@ CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata)
BridgeData *bridge;
BloatData *bloats;
bool hstop = FALSE;
char *propvalue;
bool found;
int (*cifGrowFuncPtr)() = (CIFCurStyle->cs_flags & CWF_GROW_EUCLIDEAN) ?
cifGrowEuclideanFunc : cifGrowFunc;
@ -5079,9 +5082,6 @@ CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata)
if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
{
char *propvalue;
bool found;
propvalue = (char *)DBPropGet(origDef, "FIXED_BBOX", &found);
if (!found) break;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
@ -5138,6 +5138,58 @@ CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata)
CIFPaintTable, (PaintUndoInfo *)NULL);
break;
/* The CIFOP_MASKHINTS operator checks the current cell for */
/* a property with "MASKHINTS_" followed by the name saved */
/* in the co_client record. If there is such a property, */
/* then the property value is parsed for geometry in */
/* internal units, grouped in sets of four values llx lly */
/* urx ury. */
case CIFOP_MASKHINTS:
{
int j, numfound;
char propname[512];
char *propptr;
char *layername = (char *)op->co_client;
sprintf(propname, "MASKHINTS_%s", layername);
propvalue = (char *)DBPropGet(origDef, propname, &found);
if (!found) break; /* No mask hints available */
propptr = propvalue;
while (TRUE)
{
numfound = sscanf(propptr, "%d %d %d %d",
&bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop);
if (numfound != 4)
{
/* To do: Allow keyword "rect", "tri", or "poly"
* at the start of the list and parse accordingly.
* For now, this only flags an error.
*/
TxError("MASKHINTS_%s: Cannot read rectangle values.\n",
propname);
break;
}
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
bbox.r_xbot *= cifScale;
bbox.r_xtop *= cifScale;
bbox.r_ybot *= cifScale;
bbox.r_ytop *= cifScale;
cifScale = 1;
DBNMPaintPlane(cifPlane, CIF_SOLIDTYPE, &bbox,
CIFPaintTable, (PaintUndoInfo *)NULL);
for (j = 0; j < 4; j++)
{
while (*propptr && isspace(*propptr)) propptr++;
while (*propptr && !isspace(*propptr)) propptr++;
}
}
}
break;
default:
continue;
}

View File

@ -142,6 +142,7 @@ typedef struct cifop
* CIFOP_CLOSE - Added 11/25/19---close up areas smaller than indicated
* CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
*/
#define CIFOP_AND 1
@ -166,6 +167,7 @@ typedef struct cifop
#define CIFOP_CLOSE 20
#define CIFOP_BRIDGE 21
#define CIFOP_BRIDGELIM 22
#define CIFOP_MASKHINTS 23
/* Added by Tim 10/21/2004 */
@ -224,12 +226,9 @@ typedef struct
*
* CIF_TEMP: Means that this is a temporary layer used to build
* up CIF information. It isn't output in the CIF file.
* CIF_BBOX_TOP: Indicates that the bounding box rectangle should
* only be generated if the cell is a top-level cell.
*/
#define CIF_TEMP 1
#define CIF_BBOX_TOP 2
/* The following data structure describes a complete set of CIF
* layers. The number of CIF layers (MAXCIFLAYERS) must not be

View File

@ -1054,6 +1054,8 @@ CIFTechLine(sectionName, argc, argv)
newOp->co_opcode = CIFOP_MAXRECT;
else if (strcmp(argv[0], "boundary") == 0)
newOp->co_opcode = CIFOP_BOUNDARY;
else if (strcmp(argv[0], "mask-hints") == 0)
newOp->co_opcode = CIFOP_MASKHINTS;
else if (strcmp(argv[0], "close") == 0)
newOp->co_opcode = CIFOP_CLOSE;
else if (strcmp(argv[0], "bridge") == 0)
@ -1247,6 +1249,11 @@ bloatCheck:
&newOp->co_cifMask, FALSE);
break;
case CIFOP_MASKHINTS:
if (argc != 2) goto wrongNumArgs;
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
break;
case CIFOP_MAXRECT:
if (argc == 2)
{
@ -1537,10 +1544,12 @@ cifComputeRadii(layer, des)
for (op = layer->cl_ops; op != NULL; op = op->co_next)
{
/* BBOX and NET operators should never be used hierarchically */
/* so ignore any grow/shrink operators that come after them. */
/* BBOX, NET, and MASKHINTS operators should never be used */
/* hierarchically so ignore any grow/shrink operators that */
/* come after them. */
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET)
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
op->co_opcode == CIFOP_MASKHINTS)
break;
/* If CIF layers are used, switch to the max of current
@ -1565,11 +1574,11 @@ cifComputeRadii(layer, des)
switch (op->co_opcode)
{
case CIFOP_AND: break;
case CIFOP_ANDNOT: break;
case CIFOP_OR: break;
case CIFOP_AND:
case CIFOP_ANDNOT:
case CIFOP_OR:
case CIFOP_MASKHINTS:
break;
case CIFOP_GROW:
case CIFOP_GROWMIN:
@ -1850,13 +1859,15 @@ CIFTechFinal()
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
/* of the SquaresData pointer from a following operator */
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
/* as a flag field, while CIFOP_NET uses it for a string. */
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
/* uses it for a string. */
else
{
switch (op->co_opcode)
{
case CIFOP_OR:
case CIFOP_BBOX:
case CIFOP_MASKHINTS:
case CIFOP_BOUNDARY:
case CIFOP_MAXRECT:
case CIFOP_NET:
@ -2388,6 +2399,7 @@ CIFTechOutputScale(n, d)
case CIFOP_OR:
case CIFOP_BBOX:
case CIFOP_BOUNDARY:
case CIFOP_MASKHINTS:
case CIFOP_MAXRECT:
case CIFOP_NET:
break;
@ -2502,9 +2514,10 @@ CIFTechOutputScale(n, d)
bridge->br_width /= lexpand;
break;
default:
/* op->co_opcode in CIFOP_OR is a pointer copy */
/* and in CIFOP_BBOX and CIFOP_MAXRECT is a */
/* flag, and in CIFOP_NET is a string. */
/* op->co_opcode in CIFOP_OR is a pointer copy, */
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
/* string. */
break;
}
}

View File

@ -1775,6 +1775,100 @@ DBSrCellUses(cellDef, func, arg)
return retval;
}
/* Structure used by dbScaleProp() and dbMoveProp() */
typedef struct _cellpropstruct {
Point cps_point;
CellDef *cps_def;
} CellPropStruct;
/*
* ----------------------------------------------------------------------------
*
* dbScaleProp --
*
* Callback function for dbScaleCell. Finds properties that represent
* internal geometry (FIXED_BBOX and MASKHINTS_*) and scale the values
* by the numerator / denominator values passed as a pointer to a Point
* structure, where p_x is the numerator value and p_y is the denominator
* value.
*
* ----------------------------------------------------------------------------
*/
int dbScaleProp(name, value, cps)
char *name;
char *value;
CellPropStruct *cps;
{
int scalen, scaled;
char *newvalue;
Rect r;
if (!strcmp(name, "FIXED_BBOX") || !strncmp(name, "MASKHINTS_", 10))
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
}
return 0; /* Keep enumerating through properties */
}
/*
* ----------------------------------------------------------------------------
*
* dbMoveProp --
*
* Callback function for ??. Finds properties that represent
* internal geometry (FIXED_BBOX and MASKHINTS_*) and modifies the values
* by the X, Y values passed as a pointer to a Point structure in ClientData.
*
* ----------------------------------------------------------------------------
*/
int dbMoveProp(name, value, cps)
char *name;
char *value;
CellPropStruct *cps;
{
int origx, origy;
char *newvalue;
Rect r;
if (!strcmp(name, "FIXED_BBOX") || !strncmp(name, "MASKHINTS_", 10))
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
DBMovePoint(&r.r_ll, origx, origy);
DBMovePoint(&r.r_ur, origx, origy);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
}
return 0; /* Keep enumerating through properties */
}
/*
* ----------------------------------------------------------------------------
*
@ -1799,6 +1893,7 @@ dbScaleCell(cellDef, scalen, scaled)
LinkedCellUse *luhead, *lu;
Plane *newplane;
BPlane *cellPlane, *cellPlaneOrig;
CellPropStruct cps;
/* DBCellEnum() attempts to read unavailable celldefs. We don't */
/* want to do that here, so check CDAVAILABLE flag first. */
@ -1936,6 +2031,18 @@ donecell:
}
}
}
/* Check all properties for ones with keys beginning with "MASKHINTS_"
* or the key "FIXED_BBOX", and scale them by the same amount as all
* the geometry.
*/
cps.cps_point.p_x = scalen;
cps.cps_point.p_y = scaled;
cps.cps_def = cellDef;
DBPropEnum(cellDef, dbScaleProp, &cps);
return 0;
}
@ -2023,6 +2130,7 @@ DBMoveCell(cellDef, origx, origy)
LinkedCellUse *luhead, *lu;
Plane *newplane;
BPlane *cellPlane, *cellPlaneOrig;
CellPropStruct cps;
/* Unlike dbScaleCell(), this routine is only run on valid edit defs */
@ -2120,31 +2228,15 @@ donecell:
DBMovePoint(&cellDef->cd_extended.r_ll, origx, origy);
DBMovePoint(&cellDef->cd_extended.r_ur, origx, origy);
/* If the cell is an abstract view with a fixed bounding box, then */
/* adjust the bounding box property to match the new scale. */
/* Check all properties for ones with keys beginning with "MASKHINTS_"
* or the key "FIXED_BBOX", and move them by the same amount as all
* the geometry.
*/
if ((cellDef->cd_flags & CDFIXEDBBOX) != 0)
{
Rect r;
bool found;
char *propval;
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)
{
DBMovePoint(&r.r_ll, origx, origy);
DBMovePoint(&r.r_ur, origx, origy);
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);
}
}
}
cps.cps_point.p_x = origx;
cps.cps_point.p_y = origy;
cps.cps_def = cellDef;
DBPropEnum(cellDef, dbMoveProp, &cps);
return 0;
}

View File

@ -57,8 +57,15 @@ DBPropPut(cellDef, name, value)
HashEntry *entry;
char *oldvalue;
/* Honor the NOEDIT flag */
if (cellDef->cd_flags & CDNOEDIT) return;
/* Honor the NOEDIT flag. Note that the caller always assumes that */
/* the value would be saved in the hash table, so if it is not */
/* being used, then it must be freed here. */
if (cellDef->cd_flags & CDNOEDIT)
{
freeMagic((char *)value);
return;
}
if (cellDef->cd_props == (ClientData) NULL)
{