Files
magic/cif/CIFsee.c
T
R. Timothy Edwards 7bdd9e1d4f Reworked the method from the previous set of commits, which creates
yet another property type "plane".  This allows mask hints to be
handled like tile planes.  That is, after all, what they represent.
Although this change is transparent to the end user (apart from a
slight performance improvement that is probably not noticeable), it
allows for a number of useful future extensions, including the
ability to handle non-Manhattan geometry in mask hints, and the
ability to view and edit mask hints like any other layout.
2026-03-10 14:25:02 -04:00

531 lines
15 KiB
C

/* CIFsee.c -
*
* This file provides procedures for displaying CIF layers on
* the screen using the highlight facilities.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFsee.c,v 1.5 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
#include "cif/CIFint.h"
#include "textio/textio.h"
#include "utils/undo.h"
/* C99 compat */
#include "drc/drc.h"
/* The following variable holds the CellDef into which feedback
* is to be placed for displaying CIF.
*/
static CellDef *cifSeeDef;
/* Verbosity of warning messages */
global int CIFWarningLevel = CIF_WARN_DEFAULT;
typedef struct {
CellDef *paintDef;
int layer;
} PaintLayerData;
typedef struct {
char *text;
int layer;
int style;
} SeeLayerData;
/*
* ----------------------------------------------------------------------------
*
* cifPaintDBFunc --
*
* This routine paints CIF back into the database at the inverse
* scale at which it was generated. Otherwise, it is very much like
* cifPaintCurrentFunc() in CIFrdcl.c.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* Paint is generated in the cell.
* ----------------------------------------------------------------------------
*/
int
cifPaintDBFunc(
Tile *tile, /* Tile of CIF information. */
TileType dinfo,
PaintLayerData *pld)
{
Rect area;
int pNum;
TileType type = pld->layer; /* Magic type to be painted. */
CellDef *paintDef = pld->paintDef; /* Cell to draw into. */
int cifScale = CIFCurStyle->cs_scaleFactor;
PaintUndoInfo ui;
/* Compute the area of the CIF tile, then scale it into
* Magic coordinates.
*/
TiToRect(tile, &area);
area.r_xtop /= cifScale;
area.r_xbot /= cifScale;
area.r_ytop /= cifScale;
area.r_ybot /= cifScale;
/* Check for degenerate areas (from rescale limiting) before painting */
if ((area.r_xbot == area.r_xtop) || (area.r_ybot == area.r_ytop))
return 0;
ui.pu_def = paintDef;
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (DBPaintOnPlane(type, pNum))
{
ui.pu_pNum = pNum;
DBNMPaintPlane(paintDef->cd_planes[pNum], TiGetTypeExact(tile) | dinfo,
&area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) &ui);
}
return 0; /* To keep the search alive. */
}
/*
* ----------------------------------------------------------------------------
*
* CIFPaintLayer --
*
* Generates CIF over a given area of a given cell, then
* paints the CIF layer back into the cell (or optionally,
* into a separate cell) as a magic layer.
*
* Results:
* None.
*
* Side effects:
* Highlight information is drawn on the screen.
*
* ----------------------------------------------------------------------------
*/
void
CIFPaintLayer(
CellDef *rootDef, /* Cell for which to generate CIF. Must be
* the rootDef of a window.
*/
Rect *area, /* Area in which to generate CIF. */
char *cifLayer, /* CIF layer to highlight on the screen. */
int magicLayer, /* Magic layer to paint with the result */
CellDef *paintDef) /* CellDef to paint into (may be NULL) */
{
int oldCount, i;
char msg[100];
SearchContext scx;
PaintLayerData pld;
TileTypeBitMask mask, depend;
/* Make sure the desired layer exists. */
if (!CIFNameToMask(cifLayer, &mask, &depend)) return;
/* Paint directly into the root cellDef if passed a NULL paintDef*/
pld.paintDef = (paintDef == NULL) ? rootDef : paintDef;
pld.layer = magicLayer;
/* Flatten the area and generate CIF for it. */
CIFErrorDef = rootDef;
CIFInitCells();
UndoDisable();
CIFDummyUse->cu_def = rootDef;
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
oldCount = DBWFeedbackCount;
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE, FALSE,
(ClientData)NULL);
DBCellClearDef(CIFComponentDef);
/* Report any errors that occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount-oldCount);
}
/* Paint back the chosen layer. */
UndoEnable();
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
if (TTMaskHasType(&mask, i))
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifPaintDBFunc, (ClientData)&pld);
DBWAreaChanged(rootDef, area, DBW_ALLWINDOWS, &mask);
DBReComputeBbox(rootDef);
DRCCheckThis(rootDef, TT_CHECKPAINT, area);
}
/*
* ----------------------------------------------------------------------------
*
* cifSeeFunc --
*
* Called once for each tile that is to be displayed as feedback.
* This procedure enters the tile as feedback. Note: the caller
* must arrange for cifSeeDef to contain a pointer to the cell
* def where feedback is to be displayed.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* A new feedback area is created over the tile. The parameter
* "text" is associated with the feedback.
* ----------------------------------------------------------------------------
*/
int
cifSeeFunc(
Tile *tile, /* Tile to be entered as feedback. */
TileType dinfo, /* Split tile information */
SeeLayerData *sld) /* Layer and explanation for the feedback. */
{
Rect area;
TiToRect(tile, &area);
if (((area.r_xbot & 0x1) || (area.r_ybot & 0x1))
&& (CIFWarningLevel == CIF_WARN_ALIGN))
{
TxError("Warning: Corner (%.1f, %.1f) has half-lambda placement.\n",
(float)area.r_xbot / (float)CIFCurStyle->cs_scaleFactor,
(float)area.r_ybot / (float)CIFCurStyle->cs_scaleFactor);
}
/* (NOTE: Preserve information about the geometry of a diagonal tile) */
DBWFeedbackAdd(&area, sld->text, cifSeeDef, CIFCurStyle->cs_scaleFactor,
sld->style | ((TiGetTypeExact(tile) | dinfo) &
(TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* CIFSeeLayer --
*
* Generates CIF over a given area of a given cell, then
* highlights a particular CIF layer on the screen.
*
* Results:
* None.
*
* Side effects:
* Highlight information is drawn on the screen.
*
* ----------------------------------------------------------------------------
*/
void
CIFSeeLayer(
CellDef *rootDef, /* Cell for which to generate CIF. Must be
* the rootDef of a window.
*/
Rect *area, /* Area in which to generate CIF. */
char *layer) /* CIF layer to highlight on the screen. */
{
int oldCount, i;
char msg[100];
SearchContext scx;
SeeLayerData sld;
TileTypeBitMask mask, depend;
/* Make sure the desired layer exists. */
if (!CIFNameToMask(layer, &mask, &depend)) return;
/* Flatten the area and generate CIF for it. */
CIFErrorDef = rootDef;
CIFInitCells();
UndoDisable();
CIFDummyUse->cu_def = rootDef;
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
oldCount = DBWFeedbackCount;
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
FALSE, (ClientData)NULL);
DBCellClearDef(CIFComponentDef);
/* Report any errors that occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount-oldCount);
}
/* Display the chosen layer. */
(void) sprintf(msg, "CIF layer \"%s\"", layer);
cifSeeDef = rootDef;
sld.text = msg;
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
{
if (TTMaskHasType(&mask, i))
{
sld.layer = i;
#ifdef THREE_D
sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle
+ TECHBEGINSTYLES;
#else
sld.style = STYLE_PALEHIGHLIGHTS;
#endif
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifSeeFunc, (ClientData)&sld);
}
}
UndoEnable();
}
/*
* ----------------------------------------------------------------------------
*
* CIFSeeHierLayer --
*
* This procedure is similar to CIFSeeLayer except that it only
* generates hierarchical interaction information.
*
* Results:
* None.
*
* Side effects:
* CIF information is highlighed on the screen. If arrays is
* TRUE, then CIF that stems from array interactions is displayed.
* if subcells is TRUE, then CIF stemming from subcell interactions
* is displayed. If both are TRUE, then both are displayed.
*
* ----------------------------------------------------------------------------
*/
void
CIFSeeHierLayer(
CellDef *rootDef, /* Def in which to compute CIF. Must be
* the root definition of a window.
*/
Rect *area, /* Area in which to generate CIF. */
char *layer, /* CIF layer to be highlighted. */
bool arrays, /* TRUE means show array interactions. */
bool subcells) /* TRUE means show subcell interactions. */
{
int i, oldCount;
SeeLayerData sld;
char msg[100];
TileTypeBitMask mask;
/* Check out the CIF layer name. */
if (!CIFNameToMask(layer, &mask, NULL)) return;
CIFErrorDef = rootDef;
oldCount = DBWFeedbackCount;
CIFClearPlanes(CIFPlanes);
if (subcells)
CIFGenSubcells(rootDef, area, CIFPlanes);
if (arrays)
CIFGenArrays(rootDef, area, CIFPlanes);
/* Report any errors that occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount - oldCount);
}
(void) sprintf(msg, "CIF layer \"%s\"", layer);
cifSeeDef = rootDef;
sld.text = msg;
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
{
if (TTMaskHasType(&mask, i))
{
sld.layer = i;
#ifdef THREE_D
sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle
+ TECHBEGINSTYLES;
#else
sld.style = STYLE_PALEHIGHLIGHTS;
#endif
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifSeeFunc, (ClientData)&sld);
}
}
}
/*
* ----------------------------------------------------------------------------
*
* CIFCoverageLayer --
*
* This procedure reports the total area coverage of a CIF layer
* within the bounding box of the root CellDef.
*
* Results:
* None.
*
* Side effects:
* Prints results.
*
* ----------------------------------------------------------------------------
*/
typedef struct {
long long coverage;
Rect bounds;
} coverstats;
void
CIFCoverageLayer(
CellDef *rootDef, /* Def in which to compute CIF coverage */
Rect *area, /* Area in which to compute coverage */
char *layer, /* CIF layer for coverage computation. */
bool dolist) /* If TRUE, report only the value, in decimal */
{
coverstats cstats;
int i, scale;
long long atotal, btotal;
SearchContext scx;
TileTypeBitMask mask, depend;
float fcover;
bool doBox = (area != &rootDef->cd_bbox) ? TRUE : FALSE;
/* Forward declaration */
int cifCoverageFunc(Tile *tile, TileType dinfo, ClientData *arg);
/* Check out the CIF layer name. */
if (!CIFNameToMask(layer, &mask, &depend)) return;
CIFErrorDef = rootDef;
CIFInitCells();
UndoDisable();
CIFDummyUse->cu_def = rootDef;
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
FALSE, (ClientData)NULL);
DBCellClearDef(CIFComponentDef);
cstats.coverage = 0;
cstats.bounds.r_xbot = cstats.bounds.r_xtop = 0;
cstats.bounds.r_ybot = cstats.bounds.r_ytop = 0;
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
if (TTMaskHasType(&mask, i))
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifCoverageFunc,
(ClientData) &cstats);
/* Print results */
scale = CIFCurStyle->cs_scaleFactor;
btotal = (long long)(area->r_xtop - area->r_xbot);
btotal *= (long long)(area->r_ytop - area->r_ybot);
btotal *= (long long)(scale * scale);
fcover = 0.0;
if (btotal > 0.0) fcover = (float)cstats.coverage / (float)btotal;
atotal = (long long)(cstats.bounds.r_xtop - cstats.bounds.r_xbot);
atotal *= (long long)(cstats.bounds.r_ytop - cstats.bounds.r_ybot);
if (dolist)
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *pobj;
pobj = Tcl_NewDoubleObj((double)fcover);
Tcl_SetObjResult(magicinterp, pobj);
#else
TxPrintf("%g\n", fcover);
#endif
}
else
{
TxPrintf("%s Area = %"DLONG_PREFIX"d CIF units^2\n", doBox ? "Cursor Box" :
"Cell", btotal);
TxPrintf("Layer Bounding Area = %"DLONG_PREFIX"d CIF units^2\n", atotal);
TxPrintf("Layer Total Area = %"DLONG_PREFIX"d CIF units^2\n", cstats.coverage);
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
"cell", 100.0 * fcover);
}
}
int
cifCoverageFunc(
Tile *tile,
TileType dinfo, /* (unused) */
ClientData *arg)
{
coverstats *cstats = (coverstats *)arg;
Rect r;
TiToRect(tile, &r);
cstats->coverage += (long long)(r.r_xtop - r.r_xbot) * (long long)(r.r_ytop - r.r_ybot);
GeoInclude(&r, &cstats->bounds);
return(0);
}