2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* PlowMain.c --
|
|
|
|
|
*
|
|
|
|
|
* Plowing.
|
|
|
|
|
* Main loop: set everything up, and then repeatedly remove an
|
|
|
|
|
* edge from the queue of pending edges and process it.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plow/PlowMain.c,v 1.2 2008/12/11 04:20:12 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <sys/resource.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "utils/undo.h"
|
|
|
|
|
#include "debug/debug.h"
|
|
|
|
|
#include "plow/plow.h"
|
|
|
|
|
#include "plow/plowInt.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "drc/drc.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "select/select.h"
|
|
|
|
|
#include "graphics/graphics.h"
|
|
|
|
|
|
2023-07-11 17:31:37 +02:00
|
|
|
#if defined(SYSV) || defined(__APPLE__) || defined(EMSCRIPTEN)
|
2017-04-25 14:41:48 +02:00
|
|
|
# define NO_RUSAGE
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Plowing jog horizon: see PlowExtendJogHorizon() for an explanation */
|
|
|
|
|
global int PlowJogHorizon = 0;
|
|
|
|
|
|
|
|
|
|
/* TRUE if we should straighten jogs automatically after each plow */
|
|
|
|
|
global bool PlowDoStraighten = FALSE;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Search rule table. These rules are used to search from a moving
|
|
|
|
|
* edge to find the other edges it causes to move. The procedure
|
|
|
|
|
* implementing each rule should be of the form:
|
|
|
|
|
*
|
|
|
|
|
* (*proc)(edge, rules)
|
|
|
|
|
* Edge *edge;
|
|
|
|
|
* PlowRule *rules;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* It may not modify the Edge pointed to by 'edge'.
|
|
|
|
|
* The edge is in the cell plowYankDef.
|
|
|
|
|
*/
|
|
|
|
|
RuleTableEntry plowSearchRulesTbl[MAXRULES];
|
|
|
|
|
RuleTableEntry *plowSearchRulesPtr = plowSearchRulesTbl;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Cell rules.
|
|
|
|
|
* Same as above.
|
|
|
|
|
*/
|
|
|
|
|
RuleTableEntry plowCellRulesTbl[MAXRULES];
|
|
|
|
|
RuleTableEntry *plowCellRulesPtr = plowCellRulesTbl;
|
|
|
|
|
|
|
|
|
|
/* Imported rules */
|
|
|
|
|
extern int prClearUmbra();
|
|
|
|
|
extern int prUmbra();
|
|
|
|
|
extern int prPenumbraTop(), prPenumbraBot();
|
|
|
|
|
extern int prFixedPenumbraTop(), prFixedPenumbraBot();
|
|
|
|
|
extern int prSliverTop(), prSliverBot();
|
|
|
|
|
extern int prInSliver();
|
|
|
|
|
extern int prIllegalTop(), prIllegalBot();
|
|
|
|
|
extern int prCoverTop(), prCoverBot();
|
|
|
|
|
extern int prFixedLHS(), prFixedRHS(), prFixedDragStubs();
|
|
|
|
|
extern int prContactLHS(), prContactRHS();
|
|
|
|
|
extern int prFindCells();
|
|
|
|
|
extern int prCell();
|
|
|
|
|
|
|
|
|
|
/* Defined elsewhere in this module */
|
|
|
|
|
extern CellDef *plowYankDef;
|
|
|
|
|
extern CellUse *plowYankUse;
|
|
|
|
|
extern CellDef *plowSpareDef;
|
|
|
|
|
extern CellUse *plowSpareUse;
|
|
|
|
|
extern Rect plowYankedArea;
|
|
|
|
|
extern int plowYankHalo;
|
|
|
|
|
|
|
|
|
|
/* Plow boundary information */
|
|
|
|
|
typedef struct pb
|
|
|
|
|
{
|
|
|
|
|
CellDef *pb_editDef; /* Cell to which this applies */
|
|
|
|
|
Rect pb_editArea; /* Area of boundary in edit cell coords */
|
|
|
|
|
|
|
|
|
|
/* The following exist for redisplay only */
|
|
|
|
|
CellDef *pb_rootDef; /* Display in all windows with this root */
|
|
|
|
|
Rect pb_rootArea; /* Area of boundary in root cell coords */
|
|
|
|
|
struct pb *pb_next; /* Next record in chain */
|
|
|
|
|
} PlowBoundary;
|
|
|
|
|
|
|
|
|
|
/* If the following is TRUE, enable checking of boundaries */
|
|
|
|
|
bool plowCheckBoundary = FALSE;
|
|
|
|
|
|
|
|
|
|
/* List of PlowBoundary records above */
|
|
|
|
|
PlowBoundary *plowBoundaryList = NULL;
|
|
|
|
|
|
|
|
|
|
/* TRUE if labels or cells were changed by plowing */
|
|
|
|
|
bool plowLabelsChanged;
|
|
|
|
|
|
|
|
|
|
/* Transform information to yank cell coordinates */
|
|
|
|
|
Transform plowYankTrans; /* Transform from original cell to yank cell */
|
|
|
|
|
Transform plowInverseTrans; /* Transform from yank cell to original cell */
|
|
|
|
|
Rect plowCellBbox; /* Transformed initial cell bounding box */
|
|
|
|
|
int plowDirection; /* Direction of plowing (GEO_*) */
|
|
|
|
|
|
|
|
|
|
/* Dummy whose cu_def pointer is reset to point to the def being plowed */
|
|
|
|
|
CellUse *plowDummyUse = (CellUse *) NULL;
|
|
|
|
|
|
|
|
|
|
/* Debugging */
|
|
|
|
|
RuleTableEntry *plowCurrentRule;/* Rule currently being applied */
|
|
|
|
|
RuleTableEntry plowRuleInitial; /* Dummy rule for debugging */
|
|
|
|
|
|
|
|
|
|
/* Procedure called for each edge affected by the one being moved */
|
|
|
|
|
int (*plowPropagateProcPtr)() = (int (*)()) NULL;
|
|
|
|
|
|
|
|
|
|
/* Statistics */
|
|
|
|
|
int plowQueuedEdges; /* Number of edges passed to plowQueueAdd */
|
|
|
|
|
int plowProcessedEdges; /* Number of times plowProcessEdge called */
|
|
|
|
|
int plowMovedEdges; /* Number of edges actually moved */
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
int plowInitialPaint(), plowInitialCell();
|
|
|
|
|
int plowUpdatePaintTile(), plowUpdateCell();
|
|
|
|
|
bool plowPastBoundary();
|
|
|
|
|
bool plowPropagateSel();
|
|
|
|
|
bool plowPropagateRect();
|
|
|
|
|
PlowRule *plowBuildWidthRules();
|
|
|
|
|
|
|
|
|
|
void plowMergeBottom(Tile *, Plane *);
|
|
|
|
|
void plowInitRule();
|
|
|
|
|
|
|
|
|
|
extern void PlowRedrawBound();
|
|
|
|
|
extern void PlowClearBound();
|
|
|
|
|
extern void plowUpdate();
|
|
|
|
|
extern void plowSetTrans();
|
|
|
|
|
extern void plowProcessEdge();
|
|
|
|
|
extern void plowMoveEdge();
|
|
|
|
|
extern void plowMergeTop();
|
|
|
|
|
extern void plowYankCreate();
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowSetBound --
|
|
|
|
|
*
|
|
|
|
|
* Set the bounding box for plowing.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* See above.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowSetBound(def, area, rootDef, rootArea)
|
|
|
|
|
CellDef *def; /* Def in which bounding area applies */
|
|
|
|
|
Rect *area; /* Area in 'def' coordinates */
|
|
|
|
|
CellDef *rootDef; /* Display bounding area in windows with this root */
|
|
|
|
|
Rect *rootArea; /* Area in 'rootDef' coordinates */
|
|
|
|
|
{
|
|
|
|
|
static bool firstTime = TRUE;
|
|
|
|
|
PlowBoundary *pb;
|
|
|
|
|
|
|
|
|
|
/* May eventually support a list, but for now, there's just one */
|
|
|
|
|
PlowClearBound();
|
|
|
|
|
pb = (PlowBoundary *) mallocMagic(sizeof (PlowBoundary));
|
|
|
|
|
|
|
|
|
|
pb->pb_rootDef = rootDef;
|
|
|
|
|
pb->pb_rootArea = *rootArea;
|
|
|
|
|
pb->pb_editDef = def;
|
|
|
|
|
pb->pb_editArea = *area;
|
|
|
|
|
pb->pb_next = (PlowBoundary *) NULL;
|
|
|
|
|
plowBoundaryList = pb;
|
|
|
|
|
plowCheckBoundary = TRUE;
|
|
|
|
|
|
|
|
|
|
/* Add ourselves as a client of the highlight handler */
|
|
|
|
|
if (firstTime)
|
|
|
|
|
DBWHLAddClient(PlowRedrawBound), firstTime = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Redisplay the highlight we just added */
|
|
|
|
|
DBWHLRedraw(rootDef, rootArea, FALSE);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowClearBound --
|
|
|
|
|
*
|
|
|
|
|
* Eliminate boundary checking for plowing.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Eliminates the highlight of the plowing bounding box.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowClearBound()
|
|
|
|
|
{
|
|
|
|
|
PlowBoundary *pb;
|
|
|
|
|
|
|
|
|
|
pb = plowBoundaryList;
|
|
|
|
|
plowCheckBoundary = FALSE;
|
|
|
|
|
plowBoundaryList = (PlowBoundary *) NULL;
|
|
|
|
|
for ( ; pb; pb = pb->pb_next)
|
|
|
|
|
{
|
|
|
|
|
DBWHLRedraw(pb->pb_rootDef, &pb->pb_rootArea, TRUE);
|
|
|
|
|
freeMagic((char *) pb);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowRedrawBound --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called by the highlight manager to redisplay
|
|
|
|
|
* plowing highlights. The window is locked before entry.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Plowing highlight information is redrawn, if there is any
|
|
|
|
|
* that needs redisplaying.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowRedrawBound(window, plane)
|
|
|
|
|
MagWindow *window; /* Window in which to redraw. */
|
|
|
|
|
Plane *plane; /* Non-space tiles on this plane indicate
|
|
|
|
|
* areas where highlights need to be
|
|
|
|
|
* redisplayed.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
Rect worldArea, screenArea;
|
|
|
|
|
CellDef *windowRoot;
|
|
|
|
|
PlowBoundary *pb;
|
|
|
|
|
extern int plowBoundAlways1(); /* Forward reference. */
|
|
|
|
|
|
|
|
|
|
/* Nothing to do if no boundaries */
|
|
|
|
|
if (!plowCheckBoundary)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
windowRoot = ((CellUse *) (window->w_surfaceID))->cu_def;
|
|
|
|
|
|
|
|
|
|
GrSetStuff(STYLE_DOTTEDHIGHLIGHTS);
|
|
|
|
|
WindSurfaceToScreen(window, &window->w_surfaceArea, &worldArea);
|
|
|
|
|
for (pb = plowBoundaryList; pb; pb = pb->pb_next)
|
|
|
|
|
{
|
|
|
|
|
/* Nothing to do if not in the right window */
|
|
|
|
|
if (windowRoot != pb->pb_rootDef)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* See if the current area needs to be redisplayed */
|
|
|
|
|
if (!DBSrPaintArea((Tile *) NULL, plane, &pb->pb_rootArea,
|
|
|
|
|
&DBAllButSpaceBits, plowBoundAlways1, (ClientData) NULL))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
WindSurfaceToScreen(window, &pb->pb_rootArea, &screenArea);
|
|
|
|
|
GeoClip(&screenArea, &worldArea);
|
|
|
|
|
GrFastBox(&screenArea);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowBoundAlways1()
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowStraighten --
|
|
|
|
|
*
|
|
|
|
|
* Straighten all jogs in the interior of the Rect 'area' in the CellDef 'def'
|
|
|
|
|
* by pulling them all in 'direction' (one of GEO_NORTH, GEO_SOUTH, GEO_EAST,
|
|
|
|
|
* or GEO_WEST) in such a way as to avoid moving any edges other than the jogs.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies the geometry of def in the area 'area'.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowStraighten(def, area, direction)
|
|
|
|
|
CellDef *def; /* Def whose jogs we should straighten */
|
|
|
|
|
Rect *area; /* Area in which jogs are to be straightened */
|
|
|
|
|
int direction; /* Pull all jogs in this direction to straighten them */
|
|
|
|
|
{
|
|
|
|
|
Rect changedArea, changedUserArea, yankArea;
|
|
|
|
|
bool saveCheckBoundary;
|
|
|
|
|
int saveJogHorizon;
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
PaintUndoInfo ui;
|
|
|
|
|
|
|
|
|
|
/* Make sure the yank buffers exist */
|
|
|
|
|
plowYankCreate();
|
|
|
|
|
|
|
|
|
|
/* Set the yank transforms plowYankTrans and plowInverseTrans */
|
|
|
|
|
plowSetTrans(direction);
|
|
|
|
|
|
|
|
|
|
/* Set the bounding box of this cell in yanked coordinates */
|
|
|
|
|
GeoTransRect(&plowYankTrans, &def->cd_bbox, &plowCellBbox);
|
|
|
|
|
|
|
|
|
|
/* Transform the straightening area into yank def coordinates */
|
|
|
|
|
GeoTransRect(&plowYankTrans, area, &yankArea);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Yank into yank buffer.
|
|
|
|
|
* Yank at least a tech halo around the area to make sure
|
|
|
|
|
* we detect all potential design-rule violations.
|
|
|
|
|
*/
|
|
|
|
|
plowDummyUse->cu_def = def;
|
|
|
|
|
UndoDisable();
|
|
|
|
|
DBCellClearDef(plowYankDef);
|
|
|
|
|
plowYankedArea.r_xbot = yankArea.r_xbot - DRCTechHalo;
|
|
|
|
|
plowYankedArea.r_ybot = yankArea.r_ybot - DRCTechHalo;
|
|
|
|
|
plowYankedArea.r_xtop = yankArea.r_xtop + DRCTechHalo;
|
|
|
|
|
plowYankedArea.r_ytop = yankArea.r_ytop + DRCTechHalo;
|
|
|
|
|
scx.scx_use = plowDummyUse;
|
|
|
|
|
scx.scx_trans = plowYankTrans;
|
|
|
|
|
GeoTransRect(&plowInverseTrans, &plowYankedArea, &scx.scx_area);
|
|
|
|
|
(void) DBCellCopyPaint(&scx, &DBAllButSpaceAndDRCBits, 0, plowYankUse);
|
|
|
|
|
(void) DBCellCopyCells(&scx, plowYankUse, (Rect *) NULL);
|
|
|
|
|
DBReComputeBbox(plowYankDef);
|
|
|
|
|
UndoEnable();
|
|
|
|
|
|
|
|
|
|
/* Temporarily disable boundary checking and jog horizon for the plow */
|
|
|
|
|
saveCheckBoundary = plowCheckBoundary;
|
|
|
|
|
saveJogHorizon = PlowJogHorizon;
|
|
|
|
|
plowCheckBoundary = FALSE;
|
|
|
|
|
PlowJogHorizon = 0;
|
|
|
|
|
|
|
|
|
|
/* Reduce jogs */
|
|
|
|
|
UndoDisable();
|
|
|
|
|
changedArea.r_xbot = changedArea.r_xtop = 0;
|
|
|
|
|
changedArea.r_ybot = changedArea.r_ytop = 0;
|
|
|
|
|
plowCleanupJogs(&yankArea, &changedArea);
|
|
|
|
|
UndoEnable();
|
|
|
|
|
|
|
|
|
|
/* Debugging */
|
|
|
|
|
DBWAreaChanged(plowYankDef,&TiPlaneRect,DBW_ALLWINDOWS,&DBAllButSpaceBits);
|
|
|
|
|
DBReComputeBbox(plowYankDef);
|
|
|
|
|
|
|
|
|
|
/* Restore previous state of boundary checking and jog horizon */
|
|
|
|
|
plowCheckBoundary = saveCheckBoundary;
|
|
|
|
|
PlowJogHorizon = saveJogHorizon;
|
|
|
|
|
|
|
|
|
|
/* Done if nothing was changed */
|
|
|
|
|
if (GEO_RECTNULL(&changedArea))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Erase area in original def */
|
|
|
|
|
ui.pu_def = def;
|
|
|
|
|
GeoTransRect(&plowInverseTrans, &changedArea, &changedUserArea);
|
|
|
|
|
GeoClip(&changedUserArea, &TiPlaneRect);
|
|
|
|
|
for (ui.pu_pNum = PL_TECHDEPBASE; ui.pu_pNum < DBNumPlanes; ui.pu_pNum++)
|
|
|
|
|
DBPaintPlane(def->cd_planes[ui.pu_pNum], &changedUserArea,
|
|
|
|
|
DBWriteResultTbl[TT_SPACE], &ui);
|
|
|
|
|
|
|
|
|
|
/* Stuff from yank buffer back into original def */
|
|
|
|
|
scx.scx_area = changedArea;
|
|
|
|
|
scx.scx_use = plowYankUse;
|
|
|
|
|
scx.scx_trans = plowInverseTrans;
|
|
|
|
|
(void) DBCellCopyPaint(&scx, &DBAllButSpaceAndDRCBits, 0, plowDummyUse);
|
|
|
|
|
DBReComputeBbox(def);
|
|
|
|
|
DBWAreaChanged(def, &changedUserArea, DBW_ALLWINDOWS, &DBAllButSpaceBits);
|
|
|
|
|
DRCCheckThis(def, TT_CHECKPAINT, &changedUserArea);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowSelection --
|
|
|
|
|
*
|
|
|
|
|
* Plow the entire selection by the distance indicated.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns FALSE if *pdistance had to be modified in order to keep the
|
|
|
|
|
* effects of plowing entirely within the limits specified by
|
|
|
|
|
* plowBoundaryList, or TRUE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Plows.
|
|
|
|
|
* If we return FALSE, then *pdistance will be modified as described above.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PlowSelection(def, pdistance, direction)
|
|
|
|
|
CellDef *def; /* Cell being plowed */
|
|
|
|
|
int *pdistance; /* Distance to plow */
|
|
|
|
|
int direction; /* One of GEO_NORTH, GEO_SOUTH, GEO_WEST, or GEO_EAST */
|
|
|
|
|
{
|
|
|
|
|
Rect changedArea;
|
|
|
|
|
bool firstTime;
|
|
|
|
|
|
|
|
|
|
/* Create the dummy yank buffers if they don't already exist */
|
|
|
|
|
plowYankCreate();
|
|
|
|
|
|
|
|
|
|
/* Set plowYankTrans and plowInverseTrans */
|
|
|
|
|
plowSetTrans(direction);
|
|
|
|
|
|
|
|
|
|
/* Set the bounding box of this cell in yanked coordinates */
|
|
|
|
|
GeoTransRect(&plowYankTrans, &def->cd_bbox, &plowCellBbox);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If boundary checking is enabled, the following loop may be
|
|
|
|
|
* executed several times because the original plow affected too
|
|
|
|
|
* much of the circuit. In this case, userRect gets updated to
|
|
|
|
|
* the amount the plow finally did move.
|
|
|
|
|
*/
|
|
|
|
|
firstTime = TRUE;
|
|
|
|
|
while (plowPropagateSel(def, pdistance, &changedArea))
|
|
|
|
|
firstTime = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!GEO_RECTNULL(&changedArea))
|
|
|
|
|
plowUpdate(def, direction, &changedArea);
|
|
|
|
|
|
|
|
|
|
return (firstTime);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Plow --
|
|
|
|
|
*
|
|
|
|
|
* Plow a given collection of layers.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns FALSE if userRect had to be modified in order to keep the
|
|
|
|
|
* effects of plowing entirely within the limits specified by
|
|
|
|
|
* plowBoundaryList, or TRUE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Plows.
|
|
|
|
|
* If we return FALSE, then userRect will be modified as described above.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
2025-02-17 10:49:04 +01:00
|
|
|
Plow(
|
|
|
|
|
CellDef *def, /* Cell being plowed */
|
|
|
|
|
Rect *userRect, /* The plow. Interpreted as per direction
|
2017-04-25 14:41:48 +02:00
|
|
|
* below.
|
|
|
|
|
*/
|
2025-02-17 10:49:04 +01:00
|
|
|
const TileTypeBitMask *layersp,/* The initial plow only sees these layers */
|
|
|
|
|
int direction) /* One of GEO_NORTH, GEO_SOUTH, GEO_WEST,
|
2017-04-25 14:41:48 +02:00
|
|
|
* or GEO_EAST.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
#ifdef COUNTWIDTHCALLS
|
|
|
|
|
extern int plowWidthNumCalls;
|
|
|
|
|
extern int plowWidthNumChoices;
|
|
|
|
|
#endif /* COUNTWIDTHCALLS */
|
2025-02-17 10:49:04 +01:00
|
|
|
TileTypeBitMask layers = *layersp; /* TTMaskCopy(&layers, layersp) */
|
2017-04-25 14:41:48 +02:00
|
|
|
TileTypeBitMask lc;
|
|
|
|
|
Rect changedArea;
|
|
|
|
|
bool firstTime;
|
|
|
|
|
|
|
|
|
|
/* Create the dummy yank buffers if they don't already exist */
|
|
|
|
|
plowYankCreate();
|
|
|
|
|
|
|
|
|
|
/* Set plowYankTrans and plowInverseTrans */
|
|
|
|
|
plowSetTrans(direction);
|
|
|
|
|
|
|
|
|
|
/* Set the bounding box of this cell in yanked coordinates */
|
|
|
|
|
GeoTransRect(&plowYankTrans, &def->cd_bbox, &plowCellBbox);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If boundary checking is enabled, the following loop may be
|
|
|
|
|
* executed several times because the original plow affected too
|
|
|
|
|
* much of the circuit. In this case, userRect gets updated to
|
|
|
|
|
* the amount the plow finally did move.
|
|
|
|
|
*/
|
|
|
|
|
firstTime = TRUE;
|
|
|
|
|
TTMaskCom2(&lc, &layers);
|
|
|
|
|
while (plowPropagateRect(def, userRect, lc, &changedArea))
|
|
|
|
|
firstTime = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!GEO_RECTNULL(&changedArea))
|
|
|
|
|
plowUpdate(def, direction, &changedArea);
|
|
|
|
|
|
|
|
|
|
#ifdef COUNTWIDTHCALLS
|
|
|
|
|
TxPrintf("Choices = %d Calls = %d Choices/Call = %.1f\n",
|
|
|
|
|
plowWidthNumChoices, plowWidthNumCalls,
|
|
|
|
|
((double) plowWidthNumChoices) / ((double) plowWidthNumCalls));
|
|
|
|
|
#endif /* COUNTWIDTHCALLS */
|
|
|
|
|
return (firstTime);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowUpdate --
|
|
|
|
|
*
|
|
|
|
|
* Update the original def after plowing.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the layout from plowYankDef.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowUpdate(def, direction, pChangedArea)
|
|
|
|
|
CellDef *def;
|
|
|
|
|
int direction;
|
|
|
|
|
Rect *pChangedArea;
|
|
|
|
|
{
|
|
|
|
|
Rect changedUserArea;
|
|
|
|
|
TileTypeBitMask *m;
|
|
|
|
|
PaintUndoInfo ui;
|
|
|
|
|
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
/* Mark cell as modified */
|
|
|
|
|
def->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
|
|
|
|
|
|
|
|
|
|
/* Bloat the changed area to catch edges on the LHS */
|
|
|
|
|
pChangedArea->r_xbot--, pChangedArea->r_ybot--;
|
|
|
|
|
pChangedArea->r_xtop++, pChangedArea->r_ytop++;
|
|
|
|
|
GeoTransRect(&plowInverseTrans, pChangedArea, &changedUserArea);
|
|
|
|
|
GeoClip(&changedUserArea, &TiPlaneRect); /* SANITY */
|
|
|
|
|
plowLabelsChanged = FALSE;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update the cells. Find whether each cell in the plowed
|
|
|
|
|
* planes has moved, and if so, move the corresponding cell
|
|
|
|
|
* in the original def.
|
|
|
|
|
*/
|
|
|
|
|
(void) DBCellEnum(plowYankDef, plowUpdateCell, (ClientData) def);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update the labels. This consists of changing the positions
|
|
|
|
|
* of each label that was dragged along with its paint. The
|
|
|
|
|
* labels come from the original def, since they didn't have
|
|
|
|
|
* to be yanked.
|
|
|
|
|
*/
|
|
|
|
|
plowUpdateLabels(plowYankDef, def, &changedUserArea);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update the paint. Erase the changed area from the original
|
|
|
|
|
* layout, and then paint back from the new layout. Use the
|
|
|
|
|
* transform plowInverseTrans to transform back from the yanked
|
|
|
|
|
* planes into coordinates of the original def.
|
|
|
|
|
*/
|
|
|
|
|
ui.pu_def = def;
|
|
|
|
|
for (ui.pu_pNum = PL_TECHDEPBASE; ui.pu_pNum < DBNumPlanes; ui.pu_pNum++)
|
|
|
|
|
{
|
|
|
|
|
/* Erase area in original def */
|
|
|
|
|
DBPaintPlane(def->cd_planes[ui.pu_pNum], &changedUserArea,
|
|
|
|
|
DBWriteResultTbl[TT_SPACE], &ui);
|
|
|
|
|
|
|
|
|
|
/* Update from yanked def */
|
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL, plowYankDef->cd_planes[ui.pu_pNum],
|
|
|
|
|
pChangedArea, &DBAllButSpaceBits,
|
|
|
|
|
plowUpdatePaintTile, (ClientData) &ui);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ashes to ashes */
|
|
|
|
|
done:
|
|
|
|
|
DBAdjustLabels(def, &changedUserArea);
|
|
|
|
|
DBReComputeBbox(plowYankDef);
|
|
|
|
|
DBReComputeBbox(def);
|
|
|
|
|
m = &DBAllButSpaceBits;
|
|
|
|
|
if (plowLabelsChanged) m = (TileTypeBitMask *) NULL;
|
|
|
|
|
DBWAreaChanged(def, &changedUserArea, DBW_ALLWINDOWS, m);
|
|
|
|
|
DRCCheckThis(def, TT_CHECKSUBCELL, &changedUserArea);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Final postpass: straighten any jogs in the area
|
|
|
|
|
* affected by this plow operation.
|
|
|
|
|
*/
|
|
|
|
|
if (PlowDoStraighten && !SigInterruptPending)
|
|
|
|
|
PlowStraighten(def, &changedUserArea, direction);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowPropagateRect --
|
|
|
|
|
*
|
|
|
|
|
* Do the actual work of plowing a single plow, propagating the
|
|
|
|
|
* effects of the initial plow to all geometry eventually affected by it.
|
|
|
|
|
*
|
|
|
|
|
* If the global bool plowCheckBoundary is TRUE, then we check against
|
|
|
|
|
* the boundaries in the list plowBoundaryList for edges that violate
|
|
|
|
|
* the limits set by those boundaries. If the effects of plowing extend
|
|
|
|
|
* outside of this area, we adjust userRect to the largest plowing rectangle
|
|
|
|
|
* that will not cause propagation into illegal areas. If userRect had to
|
|
|
|
|
* be adjusted, we return TRUE.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns TRUE if we had to adjust userRect, FALSE if not.
|
|
|
|
|
* If plowCheckBoundary is FALSE, we never return TRUE.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* See above.
|
|
|
|
|
* Sets the rectangle pointed to by 'changedArea' to be a
|
|
|
|
|
* bounding box around the area modified by plowing.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
plowPropagateRect(def, userRect, lc, changedArea)
|
|
|
|
|
CellDef *def; /* Def being plowed */
|
|
|
|
|
Rect *userRect; /* User-specified plow (we transform this) */
|
|
|
|
|
TileTypeBitMask lc; /* Complement of set of layers to plow */
|
|
|
|
|
Rect *changedArea; /* Set to bounding box around area modified */
|
|
|
|
|
{
|
|
|
|
|
Rect cellPlowRect, plowRect, r;
|
|
|
|
|
#ifndef NO_RUSAGE
|
|
|
|
|
struct rusage t1, t2;
|
|
|
|
|
#endif
|
|
|
|
|
int tooFar, pNum;
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
Edge edge;
|
|
|
|
|
|
|
|
|
|
changedArea->r_xbot = changedArea->r_xtop = 0;
|
|
|
|
|
changedArea->r_ybot = changedArea->r_ytop = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Back off by one lambda to catch edges underneath the plow.
|
|
|
|
|
* If no work to do, then we return FALSE.
|
|
|
|
|
*/
|
|
|
|
|
GeoTransRect(&plowYankTrans, userRect, &plowRect);
|
|
|
|
|
if (plowRect.r_xbot == plowRect.r_xtop)
|
|
|
|
|
return (FALSE);
|
|
|
|
|
|
|
|
|
|
cellPlowRect = plowRect;
|
|
|
|
|
plowRect.r_xbot--;
|
|
|
|
|
|
|
|
|
|
/* Clear the yank buffer for this iteration */
|
|
|
|
|
DBCellClearDef(plowYankDef);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Part 0.
|
|
|
|
|
* Yank the area of the plow, plus plowYankHalo, into a separate
|
|
|
|
|
* set of tile planes.
|
|
|
|
|
*/
|
|
|
|
|
plowDummyUse->cu_def = def;
|
|
|
|
|
UndoDisable();
|
|
|
|
|
scx.scx_use = plowDummyUse;
|
|
|
|
|
scx.scx_trans = plowYankTrans;
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebYankAll))
|
|
|
|
|
{
|
|
|
|
|
scx.scx_area.r_xbot = def->cd_bbox.r_xbot - 1;
|
|
|
|
|
scx.scx_area.r_ybot = def->cd_bbox.r_ybot - 1;
|
|
|
|
|
scx.scx_area.r_xtop = def->cd_bbox.r_xtop + 1;
|
|
|
|
|
scx.scx_area.r_ytop = def->cd_bbox.r_ytop + 1;
|
|
|
|
|
GeoTransRect(&plowYankTrans, &scx.scx_area, &plowYankedArea);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
plowYankedArea.r_xbot = plowRect.r_xbot - plowYankHalo;
|
|
|
|
|
plowYankedArea.r_xtop = plowRect.r_xtop + plowYankHalo;
|
|
|
|
|
plowYankedArea.r_ybot = plowRect.r_ybot - plowYankHalo;
|
|
|
|
|
plowYankedArea.r_ytop = plowRect.r_ytop + plowYankHalo;
|
|
|
|
|
GeoTransRect(&plowInverseTrans, &plowYankedArea, &scx.scx_area);
|
|
|
|
|
}
|
|
|
|
|
(void) DBCellCopyPaint(&scx, &DBAllButSpaceAndDRCBits, 0, plowYankUse);
|
|
|
|
|
(void) DBCellCopyCells(&scx, plowYankUse, (Rect *) NULL);
|
|
|
|
|
UndoEnable();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Part 1.
|
|
|
|
|
* Searching. This finds all the edges in the layout that have
|
|
|
|
|
* to move, and marks them with the distance they must move.
|
|
|
|
|
* Everything here works with the transformed cell. We initialize
|
|
|
|
|
* plowCurrentRule to null here so the debugging output for plowQueueAdd
|
|
|
|
|
* will reflect the fact that the edges found below are "initial" edges
|
|
|
|
|
* (those found by the plow itself, as opposed to by other edges).
|
|
|
|
|
*/
|
|
|
|
|
#ifndef NO_RUSAGE
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebTime))
|
|
|
|
|
getrusage(RUSAGE_SELF, &t1);
|
|
|
|
|
#endif
|
|
|
|
|
plowMovedEdges = plowProcessedEdges = plowQueuedEdges = 0;
|
|
|
|
|
plowQueueInit(&plowCellBbox, plowRect.r_xtop - plowRect.r_xbot);
|
|
|
|
|
|
|
|
|
|
/* Queue each edge found by the plowing rules */
|
|
|
|
|
plowPropagateProcPtr = plowQueueAdd;
|
|
|
|
|
|
|
|
|
|
/* Debugging */
|
|
|
|
|
plowCurrentRule = &plowRuleInitial;
|
|
|
|
|
|
|
|
|
|
/* Add the initial edges */
|
|
|
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
(void) plowSrShadowInitial(pNum, &plowRect,
|
2024-10-21 10:13:23 +02:00
|
|
|
lc, plowInitialPaint, INT2CD(plowRect.r_xtop));
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Find any subcells crossed by the plow */
|
2019-03-23 00:58:47 +01:00
|
|
|
(void) DBSrCellPlaneArea(plowYankDef->cd_cellPlane,
|
2024-10-21 10:13:23 +02:00
|
|
|
&cellPlowRect, plowInitialCell, PTR2CD(&cellPlowRect));
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* While edges remain, process them */
|
|
|
|
|
tooFar = 0;
|
|
|
|
|
while (plowQueueLeftmost(&edge))
|
|
|
|
|
{
|
|
|
|
|
/* Ignore edges that don't move (sanity check) */
|
|
|
|
|
if (edge.e_x == edge.e_newx)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we are doing boundary checking, don't add edges to the right of
|
|
|
|
|
* the boundary; just record how far they move. Edges whose original
|
|
|
|
|
* position is to the left of the boundary but cross it must still be
|
|
|
|
|
* queued for processing, since they can affect edges on the right of
|
|
|
|
|
* the boundary.
|
|
|
|
|
*/
|
|
|
|
|
if (plowCheckBoundary && plowPastBoundary(def, &edge, &tooFar))
|
|
|
|
|
continue;
|
|
|
|
|
if (!SigInterruptPending)
|
|
|
|
|
plowProcessEdge(&edge, changedArea);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clean up */
|
|
|
|
|
plowQueueDone();
|
|
|
|
|
#ifndef NO_RUSAGE
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebTime))
|
|
|
|
|
{
|
|
|
|
|
getrusage(RUSAGE_SELF, &t2);
|
|
|
|
|
plowShowTime(&t1, &t2, plowQueuedEdges,
|
|
|
|
|
plowProcessedEdges, plowMovedEdges);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/*
|
|
|
|
|
* If geometry to the right of the boundary moved, adjust
|
|
|
|
|
* the user's plow.
|
|
|
|
|
*/
|
|
|
|
|
if (tooFar)
|
|
|
|
|
{
|
|
|
|
|
GeoTransRect(&plowYankTrans, userRect, &r);
|
|
|
|
|
r.r_xtop -= tooFar;
|
|
|
|
|
GeoTransRect(&plowInverseTrans, &r, userRect);
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Successful plow */
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowPropagateSel --
|
|
|
|
|
*
|
|
|
|
|
* Do the actual work of plowing the selection, propagating the
|
|
|
|
|
* effects of each initial plow to all geometry eventually affected
|
|
|
|
|
* by them.
|
|
|
|
|
*
|
|
|
|
|
* If the global bool plowCheckBoundary is TRUE, then we check against
|
|
|
|
|
* the boundaries in the list plowBoundaryList for edges that violate
|
|
|
|
|
* the limits set by those boundaries. If the effects of plowing extend
|
|
|
|
|
* outside of this area, we adjust *pdistance to the largest plowing distance
|
|
|
|
|
* that will not cause propagation into illegal areas. If *pdistance had to
|
|
|
|
|
* be adjusted, we return TRUE.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns TRUE if we had to adjust *pdistance, FALSE if not.
|
|
|
|
|
* If plowCheckBoundary is FALSE, we never return TRUE.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* See above.
|
|
|
|
|
* Sets the rectangle pointed to by 'changedArea' to be a
|
|
|
|
|
* bounding box around the area modified by plowing.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
plowPropagateSel(def, pdistance, changedArea)
|
|
|
|
|
CellDef *def; /* Def being plowed */
|
|
|
|
|
int *pdistance; /* Distance to plow */
|
|
|
|
|
Rect *changedArea; /* Set to bounding box around area modified */
|
|
|
|
|
{
|
|
|
|
|
#ifndef NO_RUSAGE
|
|
|
|
|
struct rusage t1, t2;
|
|
|
|
|
#endif
|
|
|
|
|
int plowSelPaintBox(), plowSelCellBox();
|
|
|
|
|
int plowSelPaintPlow(), plowSelCellPlow();
|
|
|
|
|
Rect selBox;
|
|
|
|
|
int tooFar;
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
bool dummy;
|
|
|
|
|
Edge edge;
|
|
|
|
|
|
|
|
|
|
changedArea->r_xbot = changedArea->r_xtop = 0;
|
|
|
|
|
changedArea->r_ybot = changedArea->r_ytop = 0;
|
|
|
|
|
|
|
|
|
|
if (*pdistance <= 0)
|
|
|
|
|
return (FALSE);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find the bounding box for all material in the selection
|
|
|
|
|
* that lies in the edit cell.
|
|
|
|
|
*/
|
|
|
|
|
selBox.r_xbot = selBox.r_ybot = INFINITY;
|
|
|
|
|
selBox.r_xtop = selBox.r_ytop = MINFINITY;
|
|
|
|
|
SelEnumPaint(&DBAllButSpaceBits, TRUE, &dummy,
|
|
|
|
|
plowSelPaintBox, (ClientData) &selBox);
|
|
|
|
|
SelEnumCells(TRUE, &dummy, (SearchContext *) NULL,
|
|
|
|
|
plowSelCellBox, (ClientData) &selBox);
|
|
|
|
|
|
|
|
|
|
if (GEO_RECTNULL(&selBox))
|
|
|
|
|
return (FALSE);
|
|
|
|
|
|
|
|
|
|
/* Clear the yank buffer for this iteration */
|
|
|
|
|
DBCellClearDef(plowYankDef);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Yank the area of the selection, plus plowYankHalo,
|
|
|
|
|
* into a separate set of tile planes.
|
|
|
|
|
*/
|
|
|
|
|
plowDummyUse->cu_def = def;
|
|
|
|
|
UndoDisable();
|
|
|
|
|
scx.scx_use = plowDummyUse;
|
|
|
|
|
scx.scx_trans = plowYankTrans;
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebYankAll))
|
|
|
|
|
{
|
|
|
|
|
scx.scx_area.r_xbot = def->cd_bbox.r_xbot - 1;
|
|
|
|
|
scx.scx_area.r_ybot = def->cd_bbox.r_ybot - 1;
|
|
|
|
|
scx.scx_area.r_xtop = def->cd_bbox.r_xtop + 1;
|
|
|
|
|
scx.scx_area.r_ytop = def->cd_bbox.r_ytop + 1;
|
|
|
|
|
GeoTransRect(&plowYankTrans, &scx.scx_area, &plowYankedArea);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Note selBox is in parent def coordinates */
|
|
|
|
|
GeoTransRect(&plowYankTrans, &selBox, &plowYankedArea);
|
|
|
|
|
plowYankedArea.r_xtop += *pdistance + plowYankHalo;
|
|
|
|
|
plowYankedArea.r_xbot -= plowYankHalo;
|
|
|
|
|
plowYankedArea.r_ybot -= plowYankHalo;
|
|
|
|
|
plowYankedArea.r_ytop += plowYankHalo;
|
|
|
|
|
GeoTransRect(&plowInverseTrans, &plowYankedArea, &scx.scx_area);
|
|
|
|
|
}
|
|
|
|
|
(void) DBCellCopyPaint(&scx, &DBAllButSpaceAndDRCBits, 0, plowYankUse);
|
|
|
|
|
(void) DBCellCopyCells(&scx, plowYankUse, (Rect *) NULL);
|
|
|
|
|
UndoEnable();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Searching. This finds all the edges in the layout that have
|
|
|
|
|
* to move, and marks them with the distance they must move.
|
|
|
|
|
* Everything here works with the transformed cell. We initialize
|
|
|
|
|
* plowCurrentRule to null here so the debugging output for plowQueueAdd
|
|
|
|
|
* will reflect the fact that the edges found below are "initial" edges
|
|
|
|
|
* (those found by the plow itself, as opposed to by other edges).
|
|
|
|
|
*/
|
|
|
|
|
#ifndef NO_RUSAGE
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebTime))
|
|
|
|
|
getrusage(RUSAGE_SELF, &t1);
|
|
|
|
|
#endif
|
|
|
|
|
plowMovedEdges = plowProcessedEdges = plowQueuedEdges = 0;
|
|
|
|
|
plowQueueInit(&plowCellBbox, *pdistance);
|
|
|
|
|
|
|
|
|
|
/* Queue each edge found by the plowing rules */
|
|
|
|
|
plowPropagateProcPtr = plowQueueAdd;
|
|
|
|
|
|
|
|
|
|
/* Debugging */
|
|
|
|
|
plowCurrentRule = &plowRuleInitial;
|
|
|
|
|
|
|
|
|
|
/* Add everything in the selection */
|
|
|
|
|
SelEnumPaint(&DBAllButSpaceBits, TRUE, &dummy,
|
2024-10-21 10:13:23 +02:00
|
|
|
plowSelPaintPlow, INT2CD(*pdistance));
|
2017-04-25 14:41:48 +02:00
|
|
|
SelEnumCells(TRUE, &dummy, (SearchContext *) NULL,
|
2024-10-21 10:13:23 +02:00
|
|
|
plowSelCellPlow, INT2CD(*pdistance));
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* While edges remain, process them */
|
|
|
|
|
tooFar = 0;
|
|
|
|
|
while (plowQueueLeftmost(&edge))
|
|
|
|
|
{
|
|
|
|
|
/* Ignore edges that don't move (sanity check) */
|
|
|
|
|
if (edge.e_x == edge.e_newx)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we are doing boundary checking, don't add edges to the right of
|
|
|
|
|
* the boundary; just record how far they move. Edges whose original
|
|
|
|
|
* position is to the left of the boundary but cross it must still be
|
|
|
|
|
* queued for processing, since they can affect edges on the right of
|
|
|
|
|
* the boundary.
|
|
|
|
|
*/
|
|
|
|
|
if (plowCheckBoundary && plowPastBoundary(def, &edge, &tooFar))
|
|
|
|
|
continue;
|
|
|
|
|
if (!SigInterruptPending)
|
|
|
|
|
plowProcessEdge(&edge, changedArea);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clean up */
|
|
|
|
|
plowQueueDone();
|
|
|
|
|
#ifndef NO_RUSAGE
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebTime))
|
|
|
|
|
{
|
|
|
|
|
getrusage(RUSAGE_SELF, &t2);
|
|
|
|
|
plowShowTime(&t1, &t2, plowQueuedEdges,
|
|
|
|
|
plowProcessedEdges, plowMovedEdges);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/*
|
|
|
|
|
* If geometry to the right of the boundary moved,
|
|
|
|
|
* adjust the plow distance.
|
|
|
|
|
*/
|
|
|
|
|
if (tooFar)
|
|
|
|
|
{
|
|
|
|
|
*pdistance -= tooFar;
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Successful plow */
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowSelPaintBox --
|
|
|
|
|
* plowSelCellBox --
|
|
|
|
|
*
|
|
|
|
|
* Called on behalf of plowPropagateSel() above to find the bounding
|
|
|
|
|
* box for the material in the selection. Each is called for an element
|
|
|
|
|
* in the selection: a paint tile for plowSelPaintBox, or a subcell for
|
|
|
|
|
* plowSelCellBox. The bounding box *pSelBox is updated to include the
|
|
|
|
|
* area of the element.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Both return 0 always.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Both adjust *pSelBox;
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowSelPaintBox(rect, type, pSelBox)
|
|
|
|
|
Rect *rect;
|
|
|
|
|
TileType type;
|
|
|
|
|
Rect *pSelBox;
|
|
|
|
|
{
|
|
|
|
|
Rect editRect;
|
|
|
|
|
|
|
|
|
|
GeoTransRect(&RootToEditTransform, rect, &editRect);
|
|
|
|
|
GeoInclude(&editRect, pSelBox);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowSelCellBox(selUse, realUse, transform, pSelBox)
|
|
|
|
|
CellUse *selUse;
|
|
|
|
|
CellUse *realUse;
|
|
|
|
|
Transform *transform;
|
|
|
|
|
Rect *pSelBox;
|
|
|
|
|
{
|
|
|
|
|
GeoInclude(&realUse->cu_bbox, pSelBox);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowSelPaintPlow --
|
|
|
|
|
*
|
|
|
|
|
* Called on behalf of plowPropagateSel() above to queue the initial
|
|
|
|
|
* edges belonging to material in the selection. For paint, we create
|
|
|
|
|
* a plow at both the right and left edges of the tile.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 0 always.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Queues edges marked as initial (e_flags has E_ISINITIAL set).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowSelPaintPlow(rect, type, distance)
|
|
|
|
|
Rect *rect;
|
|
|
|
|
TileType type;
|
|
|
|
|
int distance;
|
|
|
|
|
{
|
|
|
|
|
int plowSelPaintAdd();
|
|
|
|
|
Rect editRect, plowRect, plowLHS, plowRHS;
|
|
|
|
|
TileTypeBitMask mask;
|
|
|
|
|
|
|
|
|
|
GeoTransRect(&RootToEditTransform, rect, &editRect);
|
|
|
|
|
GeoTransRect(&plowYankTrans, &editRect, &plowRect);
|
|
|
|
|
plowLHS = plowRHS = plowRect;
|
|
|
|
|
|
|
|
|
|
/* Queue the LHS */
|
|
|
|
|
plowLHS.r_xtop = plowLHS.r_xbot + distance;
|
|
|
|
|
#ifdef notdef
|
|
|
|
|
plowAtomize(DBPlane(type), &plowLHS, plowSelPaintAdd, (ClientData) NULL);
|
|
|
|
|
#endif /* notdef */
|
|
|
|
|
plowLHS.r_xbot--;
|
2025-02-17 10:54:10 +01:00
|
|
|
plowSrShadow(DBPlane(type), &plowLHS, &DBZeroTypeBits,
|
2024-10-21 10:13:23 +02:00
|
|
|
plowInitialPaint, INT2CD(plowLHS.r_xtop));
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Queue the RHS */
|
|
|
|
|
plowRHS.r_xbot = plowRHS.r_xtop;
|
|
|
|
|
plowRHS.r_xtop += distance;
|
|
|
|
|
#ifdef notdef
|
|
|
|
|
plowAtomize(DBPlane(type), &plowRHS, plowSelPaintAdd, (ClientData) NULL);
|
|
|
|
|
#endif /* notdef */
|
|
|
|
|
plowRHS.r_xbot--;
|
|
|
|
|
TTMaskSetOnlyType(&mask, type);
|
2025-02-17 10:54:10 +01:00
|
|
|
plowSrShadow(DBPlane(type), &plowRHS, &mask,
|
2024-10-21 10:13:23 +02:00
|
|
|
plowInitialPaint, INT2CD(plowRHS.r_xtop));
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowSelPaintAdd(edge)
|
|
|
|
|
Edge *edge;
|
|
|
|
|
{
|
|
|
|
|
int saveFlags = edge->e_flags;
|
|
|
|
|
|
|
|
|
|
edge->e_flags |= E_ISINITIAL;
|
|
|
|
|
plowQueueAdd(edge);
|
|
|
|
|
edge->e_flags = saveFlags;
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowSelCellPlow --
|
|
|
|
|
*
|
|
|
|
|
* Called on behalf of plowPropagateSel() above to queue the initial
|
|
|
|
|
* edges belonging to material in the selection. For subcells, we
|
|
|
|
|
* have to look for the subcell with the same use-id in our yank
|
|
|
|
|
* buffer, and then move it by its leading edge.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 0 always.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Queues edges.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowSelCellPlow(selUse, realUse, transform, distance)
|
|
|
|
|
CellUse *selUse; /* Cell in selection */
|
|
|
|
|
CellUse *realUse; /* Corresponding cell in def being plowed */
|
|
|
|
|
Transform *transform; /* UNUSED */
|
|
|
|
|
int distance; /* Plow distance */
|
|
|
|
|
{
|
|
|
|
|
int plowFindSelCell();
|
|
|
|
|
ClientData save;
|
|
|
|
|
|
|
|
|
|
/* Find the cell in the yanked def that has the same use-id as this one */
|
|
|
|
|
save = realUse->cu_client;
|
2024-10-21 10:13:23 +02:00
|
|
|
realUse->cu_client = INT2CD(distance);
|
|
|
|
|
(void) DBCellEnum(plowYankDef, plowFindSelCell, PTR2CD(realUse));
|
2017-04-25 14:41:48 +02:00
|
|
|
realUse->cu_client = save;
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowFindSelCell(yankUse, editUse)
|
|
|
|
|
CellUse *yankUse; /* Cell in the plow yank buffer */
|
|
|
|
|
CellUse *editUse; /* Cell from the original cell def */
|
|
|
|
|
{
|
|
|
|
|
Edge edge;
|
|
|
|
|
|
|
|
|
|
if (strcmp(yankUse->cu_id, editUse->cu_id) != 0)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
edge.e_flags = 0;
|
2019-03-23 00:58:47 +01:00
|
|
|
edge.e_pNum = PL_ROUTER;
|
2017-04-25 14:41:48 +02:00
|
|
|
edge.e_use = yankUse;
|
|
|
|
|
edge.e_ytop = yankUse->cu_bbox.r_ytop;
|
|
|
|
|
edge.e_ybot = yankUse->cu_bbox.r_ybot;
|
|
|
|
|
edge.e_x = yankUse->cu_bbox.r_xtop;
|
2024-10-21 10:13:23 +02:00
|
|
|
edge.e_newx = yankUse->cu_bbox.r_xtop + (int)CD2INT(editUse->cu_client);
|
2017-04-25 14:41:48 +02:00
|
|
|
edge.e_ltype = PLOWTYPE_CELL;
|
|
|
|
|
edge.e_rtype = PLOWTYPE_CELL;
|
|
|
|
|
(void) plowQueueAdd(&edge);
|
|
|
|
|
return (1);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* PlowExtendJogHorizon --
|
|
|
|
|
*
|
|
|
|
|
* Search above and below 'edge' for the closest "natural" jogs within
|
|
|
|
|
* plowJogHorizon of the top or bottom of the edge, and extend 'edge'
|
|
|
|
|
* to these jogs if they are found. If no jog is found in a particular
|
|
|
|
|
* direction, we leave that end of 'edge' (top/bottom) alone.
|
|
|
|
|
*
|
|
|
|
|
* A "natural" jog is nothing more than a change in the direction of
|
|
|
|
|
* an edge being followed. The following diagram gives an example, with
|
|
|
|
|
* the vertical arrows indicating the jog horizons. Note that the edge
|
|
|
|
|
* is extended up, because there is a natural jog there, but not down
|
|
|
|
|
* because the jog on the bottom is outside the horizon.
|
|
|
|
|
*
|
|
|
|
|
* +-------- ^ E--------
|
|
|
|
|
* | | E
|
|
|
|
|
* | | E
|
|
|
|
|
* | v E
|
|
|
|
|
* E E
|
|
|
|
|
* E E
|
|
|
|
|
* E E
|
|
|
|
|
* | ^ |
|
|
|
|
|
* | | |
|
|
|
|
|
* | | |
|
|
|
|
|
* | v |
|
|
|
|
|
* | |
|
|
|
|
|
* --------+ --------+
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May modify its argument 'edge' by extending it vertically.
|
|
|
|
|
* May also add additional edges via plowAtomizeEdge().
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PlowExtendJogHorizon(edge)
|
|
|
|
|
Edge *edge; /* Edge being moved */
|
|
|
|
|
{
|
|
|
|
|
int horizonTop, horizonBot, eTop, eBot;
|
|
|
|
|
Tile *tpR, *tpL;
|
|
|
|
|
Point startPoint;
|
|
|
|
|
bool rhsChanged;
|
|
|
|
|
Rect r, newEdgeR;
|
|
|
|
|
|
|
|
|
|
if (PlowJogHorizon == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
horizonTop = edge->e_ytop + PlowJogHorizon;
|
|
|
|
|
horizonBot = edge->e_ybot - PlowJogHorizon;
|
|
|
|
|
r.r_xbot = edge->e_x - 1;
|
|
|
|
|
r.r_xtop = edge->e_x + 1;
|
|
|
|
|
newEdgeR = edge->e_rect;
|
|
|
|
|
|
|
|
|
|
/* Extend to the top */
|
|
|
|
|
restarttop:
|
|
|
|
|
startPoint.p_x = edge->e_x - 1;
|
|
|
|
|
startPoint.p_y = edge->e_ytop;
|
|
|
|
|
tpL = TiSrPointNoHint(plowYankDef->cd_planes[edge->e_pNum], &startPoint);
|
|
|
|
|
r.r_ybot = r.r_ytop = edge->e_ytop;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Walk upwards.
|
|
|
|
|
* The loop terminates with r.r_ytop equal to the Y coordinate
|
|
|
|
|
* of the closest jog to our top, and eTop equal to the smaller
|
|
|
|
|
* of r.r_ytop and the Y coordinate of the closest point at which
|
|
|
|
|
* the RHS of the edge changed type.
|
|
|
|
|
*/
|
|
|
|
|
rhsChanged = FALSE;
|
|
|
|
|
while (RIGHT(tpL) == edge->e_x
|
|
|
|
|
&& TiGetTypeExact(tpL) == edge->e_ltype
|
|
|
|
|
&& BOTTOM(tpL) < horizonTop)
|
|
|
|
|
{
|
|
|
|
|
r.r_ytop = TOP(tpL);
|
|
|
|
|
if (plowYankMore(&r, 1, 1))
|
|
|
|
|
goto restarttop;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Walk along RHS to see if its type changed.
|
|
|
|
|
* If so, make eTop record the lowest point
|
|
|
|
|
* at which this happened.
|
|
|
|
|
*/
|
|
|
|
|
if (!rhsChanged)
|
|
|
|
|
for (tpR = TR(tpL); TOP(tpR) > r.r_ybot; tpR = LB(tpR))
|
|
|
|
|
if (TiGetTypeExact(tpR) != edge->e_rtype)
|
|
|
|
|
rhsChanged = TRUE, eTop = BOTTOM(tpR);
|
|
|
|
|
tpL = RT(tpL);
|
|
|
|
|
r.r_ybot = r.r_ytop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update if within the jog horizon */
|
|
|
|
|
if (r.r_ytop <= horizonTop && r.r_ytop > edge->e_ytop)
|
|
|
|
|
{
|
|
|
|
|
newEdgeR.r_ytop = r.r_ytop;
|
|
|
|
|
edge->e_ytop = (rhsChanged) ? eTop : r.r_ytop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Extend to the bottom */
|
|
|
|
|
restartbot:
|
|
|
|
|
startPoint.p_x = edge->e_x;
|
|
|
|
|
startPoint.p_y = edge->e_ybot - 1;
|
|
|
|
|
tpR = TiSrPointNoHint(plowYankDef->cd_planes[edge->e_pNum], &startPoint);
|
|
|
|
|
r.r_ybot = r.r_ytop = edge->e_ybot;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Walk down.
|
|
|
|
|
* The loop terminates with r.r_ybot equal to the Y coordinate
|
|
|
|
|
* of the closest jog to our bottom, and eBot equal to the larger
|
|
|
|
|
* of r.r_ytop and the Y coordinate of the closest point at which
|
|
|
|
|
* the RHS of the edge changed type.
|
|
|
|
|
*/
|
|
|
|
|
rhsChanged = FALSE;
|
|
|
|
|
while (LEFT(tpR) == edge->e_x && TOP(tpR) > horizonBot)
|
|
|
|
|
{
|
|
|
|
|
r.r_ybot = BOTTOM(tpR);
|
|
|
|
|
if (plowYankMore(&r, 1, 1))
|
|
|
|
|
goto restartbot;
|
|
|
|
|
|
|
|
|
|
/* Record where the RHS type changed if it did */
|
|
|
|
|
if (!rhsChanged && TiGetTypeExact(tpR) != edge->e_rtype)
|
|
|
|
|
rhsChanged = TRUE, eBot = TOP(tpR);
|
|
|
|
|
|
|
|
|
|
/* Walk up the LHS */
|
|
|
|
|
for (tpL = BL(tpR); BOTTOM(tpL) < r.r_ytop; tpL = RT(tpL))
|
|
|
|
|
if (TiGetTypeExact(tpL) != edge->e_ltype)
|
|
|
|
|
r.r_ybot = TOP(tpL);
|
|
|
|
|
|
|
|
|
|
if (r.r_ybot > BOTTOM(tpR))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
tpR = LB(tpR);
|
|
|
|
|
r.r_ytop = r.r_ybot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update if within the jog horizon */
|
|
|
|
|
if (r.r_ybot >= horizonBot && r.r_ybot < edge->e_ybot)
|
|
|
|
|
{
|
|
|
|
|
newEdgeR.r_ybot = r.r_ybot;
|
|
|
|
|
edge->e_ybot = (rhsChanged) ? eBot : r.r_ybot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newEdgeR.r_ytop > edge->e_ytop)
|
|
|
|
|
{
|
|
|
|
|
r = newEdgeR;
|
|
|
|
|
r.r_ybot = edge->e_ytop;
|
|
|
|
|
(void) plowAtomize(edge->e_pNum, &r, plowQueueAdd, (ClientData) NULL);
|
|
|
|
|
}
|
|
|
|
|
if (newEdgeR.r_ybot < edge->e_ybot)
|
|
|
|
|
{
|
|
|
|
|
r = newEdgeR;
|
|
|
|
|
r.r_ytop = edge->e_ybot;
|
|
|
|
|
(void) plowAtomize(edge->e_pNum, &r, plowQueueAdd, (ClientData) NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowSetTrans --
|
|
|
|
|
*
|
|
|
|
|
* Set up the transforms based on the direction we will be plowing.
|
|
|
|
|
* Just use simple rotations, since we always have the inverse
|
|
|
|
|
* transform around for copying stuff back.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Sets plowYankTrans and plowInverseTrans.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowSetTrans(direction)
|
|
|
|
|
int direction;
|
|
|
|
|
{
|
|
|
|
|
plowDirection = direction;
|
|
|
|
|
switch (direction)
|
|
|
|
|
{
|
|
|
|
|
case GEO_NORTH:
|
|
|
|
|
plowYankTrans = Geo90Transform;
|
|
|
|
|
break;
|
|
|
|
|
case GEO_SOUTH:
|
|
|
|
|
plowYankTrans = Geo270Transform;
|
|
|
|
|
break;
|
|
|
|
|
case GEO_WEST:
|
|
|
|
|
plowYankTrans = Geo180Transform;
|
|
|
|
|
break;
|
|
|
|
|
case GEO_EAST:
|
|
|
|
|
plowYankTrans = GeoIdentityTransform;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
GeoInvertTrans(&plowYankTrans, &plowInverseTrans);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowPastBoundary --
|
|
|
|
|
*
|
|
|
|
|
* Check to see if the edge is in an illegal region according to the
|
|
|
|
|
* boundaries on the list plowBoundaryList.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if we should not even bother to process this edge (because
|
|
|
|
|
* its initial position was in an invalid area), FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates *pmove to the farthest distance by which anything in an
|
|
|
|
|
* illegal area moves.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
plowPastBoundary(def, edge, pmove)
|
|
|
|
|
CellDef *def; /* Def being plowed */
|
|
|
|
|
Edge *edge; /* Edge being moved */
|
|
|
|
|
int *pmove; /* Updated to be the maximum distance by
|
|
|
|
|
* which something moves in an illegal area.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
PlowBoundary *pb;
|
|
|
|
|
int delta;
|
|
|
|
|
bool ret;
|
|
|
|
|
Rect r;
|
|
|
|
|
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
delta = 0;
|
|
|
|
|
for (pb = plowBoundaryList; pb; pb = pb->pb_next)
|
|
|
|
|
{
|
|
|
|
|
if (pb->pb_editDef != def)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
GeoTransRect(&plowYankTrans, &pb->pb_editArea, &r);
|
|
|
|
|
if (edge->e_x < r.r_xbot)
|
|
|
|
|
{
|
|
|
|
|
/* To the left of the boundary */
|
|
|
|
|
delta = MAX(edge->e_newx, r.r_xbot) - edge->e_x;
|
|
|
|
|
}
|
|
|
|
|
else if (edge->e_newx > r.r_xtop)
|
|
|
|
|
{
|
|
|
|
|
/* To the right of the boundary */
|
|
|
|
|
delta = edge->e_newx - MAX(edge->e_x, r.r_xtop);
|
|
|
|
|
if (edge->e_x > r.r_xtop) ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else if (edge->e_ytop > r.r_ytop || edge->e_ybot < r.r_ybot)
|
|
|
|
|
{
|
|
|
|
|
/* Above or below the boundary */
|
|
|
|
|
delta = edge->e_newx - edge->e_x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta > *pmove) *pmove = delta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowInitialPaint --
|
|
|
|
|
*
|
|
|
|
|
* Add one of the edges found initially by the plow to the queue
|
|
|
|
|
* of edges to move. The edge will move as far as 'xnew'.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds the edge to the queue of edges to move via plowQueueAdd().
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowInitialPaint(edge, xnew)
|
|
|
|
|
Edge *edge;
|
|
|
|
|
int xnew;
|
|
|
|
|
{
|
|
|
|
|
edge->e_newx = xnew;
|
|
|
|
|
edge->e_flags = E_ISINITIAL;
|
|
|
|
|
(void) plowQueueAdd(edge);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowInitialCell --
|
|
|
|
|
*
|
|
|
|
|
* Add a cell to the queue of edges to move. The cell will move as far
|
|
|
|
|
* as 'plowRect->r_xtop'.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds an edge to the queue of edges to move via plowQueueAdd().
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2019-03-23 00:58:47 +01:00
|
|
|
plowInitialCell(use, plowRect)
|
|
|
|
|
CellUse *use;
|
2017-04-25 14:41:48 +02:00
|
|
|
Rect *plowRect;
|
|
|
|
|
{
|
|
|
|
|
int xmove;
|
|
|
|
|
Edge edge;
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
if (use->cu_bbox.r_xbot < plowRect->r_xbot)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2019-03-23 00:58:47 +01:00
|
|
|
if (use->cu_bbox.r_xtop >= plowRect->r_xtop)
|
|
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
/* 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;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
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;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowProcessEdge --
|
|
|
|
|
*
|
|
|
|
|
* Process a single edge from the queue.
|
|
|
|
|
* Plowing is rule-based, so processing an edge consists of applying
|
|
|
|
|
* a sequence of rules. The overall algorithm is:
|
|
|
|
|
*
|
|
|
|
|
* - Yank more of the original cell if necessary.
|
|
|
|
|
* - Check to see if the edge has already moved; if so, we don't do
|
|
|
|
|
* anything further.
|
|
|
|
|
* - Apply extension rules. These are allowed to extend the edge
|
|
|
|
|
* but shouldn't search for new edges to be added to the edge queue.
|
|
|
|
|
* - Compute the real width rules for this material.
|
|
|
|
|
* - Apply search rules to each remaining segment of the clipped edge.
|
|
|
|
|
* These look for other edges to be added to the edge queue.
|
|
|
|
|
* - Update the edge's position. This consists of modifying the
|
|
|
|
|
* LEADING coordinates in the tiles along the edge, possibly
|
|
|
|
|
* splitting the tiles at the top and bottom of the edge.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May split and merge tiles.
|
|
|
|
|
* May cause additional area to be yanked from the original cell.
|
|
|
|
|
* Updates changedArea to include any additional area modified.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowProcessEdge(edge, changedArea)
|
|
|
|
|
Edge *edge; /* Edge to be processed (in plowYankDef) */
|
|
|
|
|
Rect *changedArea; /* Include any additional area changed in this area */
|
|
|
|
|
{
|
|
|
|
|
int amountToMove = edge->e_newx - edge->e_x;
|
|
|
|
|
RuleTableEntry *rte;
|
|
|
|
|
Tile *tp;
|
|
|
|
|
Point p;
|
|
|
|
|
Rect r;
|
|
|
|
|
|
|
|
|
|
/* Debugging */
|
|
|
|
|
if ((plowWhenTop && edge->e_x == plowWhenTopPoint.p_x
|
|
|
|
|
&& edge->e_ytop == plowWhenTopPoint.p_y)
|
|
|
|
|
|| (plowWhenBot && edge->e_x == plowWhenBotPoint.p_x
|
|
|
|
|
&& edge->e_ybot == plowWhenBotPoint.p_y))
|
|
|
|
|
{
|
|
|
|
|
plowDebugEdge(edge, (RuleTableEntry *) NULL, "matched edge");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Process cells specially.
|
|
|
|
|
* These don't get clipped, but are either processed
|
|
|
|
|
* completely or not at all.
|
|
|
|
|
*/
|
|
|
|
|
plowProcessedEdges++;
|
|
|
|
|
if (edge->e_use)
|
|
|
|
|
{
|
2024-10-21 10:13:23 +02:00
|
|
|
if (amountToMove > (int)CD2INT(edge->e_use->cu_client))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
/* Update area modified by plowing */
|
|
|
|
|
(void) GeoInclude(&edge->e_rect, changedArea);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See if the cell's bbox plus the distance to move
|
|
|
|
|
* forces us to yank more from the original cell.
|
|
|
|
|
*/
|
|
|
|
|
r = edge->e_use->cu_bbox;
|
|
|
|
|
r.r_xtop = edge->e_newx;
|
|
|
|
|
(void) plowYankMore(&r, plowYankHalo, 1);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update the cell's position.
|
|
|
|
|
* We do this here so we don't see the cell a
|
|
|
|
|
* second time. The whole cell moves, so we have
|
|
|
|
|
* to update the area changed by the area of the
|
|
|
|
|
* cell PLUS the area swept out by its RHS.
|
|
|
|
|
*/
|
2024-10-21 10:13:23 +02:00
|
|
|
edge->e_use->cu_client = INT2CD(amountToMove);
|
2017-04-25 14:41:48 +02:00
|
|
|
r = edge->e_use->cu_bbox;
|
|
|
|
|
r.r_xbot += amountToMove;
|
|
|
|
|
r.r_xtop += amountToMove;
|
|
|
|
|
(void) GeoInclude(&r, changedArea);
|
|
|
|
|
|
|
|
|
|
/* Apply cell rules */
|
|
|
|
|
for (rte = plowCellRulesTbl; rte < plowCellRulesPtr; rte++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&rte->rte_ltypes, edge->e_ltype)
|
|
|
|
|
&& TTMaskHasType(&rte->rte_rtypes, edge->e_rtype))
|
|
|
|
|
{
|
|
|
|
|
plowCurrentRule = rte;
|
|
|
|
|
(*rte->rte_proc)(edge, (PlowRule *) NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
plowMovedEdges++;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check to see if any of this edge needs to move. If it has
|
|
|
|
|
* already moved far enough, we can just return; otherwise,
|
|
|
|
|
* we process the entire edge as a whole. This check is necessary
|
|
|
|
|
* to avoid infinite loops.
|
|
|
|
|
*/
|
|
|
|
|
p.p_x = edge->e_x, p.p_y = edge->e_ytop - 1;
|
|
|
|
|
tp = TiSrPointNoHint(plowYankDef->cd_planes[edge->e_pNum], &p);
|
|
|
|
|
for ( ; TOP(tp) > edge->e_ybot; tp = LB(tp))
|
|
|
|
|
if (TRAILING(tp) < edge->e_newx)
|
|
|
|
|
goto worktodo;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Some or all of this edge must be moved.
|
|
|
|
|
* Extend it if necessary.
|
|
|
|
|
* Yank more if necessary.
|
|
|
|
|
* Compute its width.
|
|
|
|
|
* Apply the search rules.
|
|
|
|
|
* Update the coordinates of all tiles along this edge.
|
|
|
|
|
*/
|
|
|
|
|
worktodo:
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Extend this edge if we're reducing jogs.
|
|
|
|
|
* May cause other edges to be added.
|
|
|
|
|
*/
|
|
|
|
|
plowMovedEdges++;
|
|
|
|
|
if (PlowJogHorizon > 0)
|
|
|
|
|
PlowExtendJogHorizon(edge);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update area modified by plowing.
|
|
|
|
|
* This must happen after applying the extension rules above.
|
|
|
|
|
*/
|
|
|
|
|
(void) GeoInclude(&edge->e_rect, changedArea);
|
|
|
|
|
|
|
|
|
|
/* Apply search rules */
|
|
|
|
|
plowApplySearchRules(edge);
|
|
|
|
|
|
|
|
|
|
/* Update edge position */
|
|
|
|
|
plowMoveEdge(edge);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowApplySearchRules --
|
|
|
|
|
*
|
|
|
|
|
* Apply the search rules to an edge.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May call (*plowPropagateProcPtr)() if the search rules
|
|
|
|
|
* determine that edges must move. May yank more.
|
|
|
|
|
* May cause additional area to be yanked from the original cell.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plowApplySearchRules(edge)
|
|
|
|
|
Edge *edge;
|
|
|
|
|
{
|
|
|
|
|
PlowRule *widthRules, *rules;
|
|
|
|
|
RuleTableEntry *rte;
|
|
|
|
|
int halo;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Build list of width rules using computed (instead of min) width.
|
|
|
|
|
* This can also yank more.
|
|
|
|
|
*/
|
|
|
|
|
halo = plowYankHalo;
|
|
|
|
|
widthRules = plowBuildWidthRules(edge, &plowCellBbox, &halo);
|
|
|
|
|
|
|
|
|
|
/* Yank more if necessary */
|
|
|
|
|
(void) plowYankMore(&edge->e_rect, halo, 1);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Search rules.
|
|
|
|
|
* These generally won't need to yank more unless they deal
|
|
|
|
|
* with entire tiles.
|
|
|
|
|
*/
|
|
|
|
|
for (rte = plowSearchRulesTbl; rte < plowSearchRulesPtr; rte++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&rte->rte_ltypes, edge->e_ltype)
|
|
|
|
|
&& TTMaskHasType(&rte->rte_rtypes, edge->e_rtype))
|
|
|
|
|
{
|
|
|
|
|
plowCurrentRule = rte;
|
|
|
|
|
switch (rte->rte_whichRules)
|
|
|
|
|
{
|
|
|
|
|
/* Apply no rules */
|
|
|
|
|
case RTE_NULL:
|
|
|
|
|
rules = (PlowRule *) NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Apply width rules, but use actual widths */
|
|
|
|
|
case RTE_REALWIDTH:
|
|
|
|
|
rules = widthRules;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Apply minimum-width rules */
|
|
|
|
|
case RTE_MINWIDTH:
|
|
|
|
|
rules = plowWidthRulesTbl[edge->e_ltype][edge->e_rtype];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Apply spacing rules */
|
|
|
|
|
case RTE_SPACING:
|
|
|
|
|
rules = plowSpacingRulesTbl[edge->e_ltype][edge->e_rtype];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Only apply rule if no spacing rules apply */
|
|
|
|
|
case RTE_NOSPACING:
|
|
|
|
|
rules = plowSpacingRulesTbl[edge->e_ltype][edge->e_rtype];
|
|
|
|
|
if (rules)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
(*rte->rte_proc)(edge, rules);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowBuildWidthRules --
|
|
|
|
|
*
|
|
|
|
|
* Find the real width of the material being plowed, and construct
|
|
|
|
|
* a list of width rules that is the same as the normal list for
|
|
|
|
|
* this type of edge, but with the minimum distance replaced by the
|
|
|
|
|
* actual width if the actual width is greater than the minimum
|
|
|
|
|
* distance. (If the actual width is less than or equal to the
|
|
|
|
|
* minimum distance, we use the minimum distance instead).
|
|
|
|
|
*
|
|
|
|
|
* If the minimum-width rectangle about the starting edge touches the
|
|
|
|
|
* boundary of the yanked area, yank more and retry.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a pointer to the statically constructed rules list,
|
|
|
|
|
* or NULL if no width rules apply.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Since the width rules list is statically allocated, subsequent
|
|
|
|
|
* calls to plowBuildWidthRules() will trash the results of previous
|
|
|
|
|
* calls.
|
|
|
|
|
*
|
|
|
|
|
* May cause more of the original cell to be yanked.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
PlowRule *
|
|
|
|
|
plowBuildWidthRules(edge, bbox, phalo)
|
|
|
|
|
Edge *edge; /* Edge being moved */
|
|
|
|
|
Rect *bbox; /* Bounding box of def being plowed */
|
|
|
|
|
int *phalo; /* Update *phalo to be the max of its initial value
|
|
|
|
|
* and each of the widths we compute for the rules
|
|
|
|
|
* we return.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
extern char *maskToPrint();
|
|
|
|
|
static PlowRule widthRuleList[MAXRULES];
|
|
|
|
|
PlowRule *prMin, *prReal;
|
|
|
|
|
Rect maxBox;
|
|
|
|
|
int dist;
|
|
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
prMin = plowWidthRulesTbl[edge->e_ltype][edge->e_rtype];
|
|
|
|
|
if (prMin == NULL)
|
|
|
|
|
return ((PlowRule *) NULL);
|
|
|
|
|
|
|
|
|
|
/* At this point, know there will be at least one rule in the list */
|
|
|
|
|
for (prReal = widthRuleList;
|
|
|
|
|
prMin && prReal < &widthRuleList[MAXRULES];
|
|
|
|
|
prMin = prMin->pr_next, prReal++)
|
|
|
|
|
{
|
|
|
|
|
*prReal = *prMin;
|
|
|
|
|
prReal->pr_next = prReal + 1;
|
2025-02-17 10:49:58 +01:00
|
|
|
dist = plowFindWidth(edge, &prMin->pr_oktypes, bbox, &maxBox);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Conservative test of whether we need to yank more */
|
|
|
|
|
if (plowYankMore(&maxBox, 1, 1))
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebWidth))
|
|
|
|
|
TxPrintf("width: yank more and retry\n");
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
|
|
|
|
prReal->pr_dist = MAX(dist, prReal->pr_dist);
|
|
|
|
|
*phalo = MAX(*phalo, dist);
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebWidth))
|
|
|
|
|
TxPrintf("width: %d types: %s\n",
|
|
|
|
|
prReal->pr_dist, maskToPrint(&prReal->pr_oktypes));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(--prReal)->pr_next = (PlowRule *) NULL;
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebWidth))
|
|
|
|
|
plowDebugEdge(edge, (RuleTableEntry *) NULL, "find width");
|
|
|
|
|
|
|
|
|
|
return (widthRuleList);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowMoveEdge --
|
|
|
|
|
*
|
|
|
|
|
* Do the actual work of updating the coordinates of an edge. In general,
|
|
|
|
|
* the edge may have more than one tile on either side, as below:
|
|
|
|
|
*
|
|
|
|
|
* |
|
|
|
|
|
* |
|
|
|
|
|
* --------+
|
|
|
|
|
* +---------
|
|
|
|
|
* |
|
|
|
|
|
* |
|
|
|
|
|
* --------+
|
|
|
|
|
* |---------
|
|
|
|
|
* |
|
|
|
|
|
* --------+
|
|
|
|
|
* |
|
|
|
|
|
*
|
|
|
|
|
* Updating the coordinates consists of first clipping the tiles on
|
|
|
|
|
* either side so they do not extend vertically past the edge, then
|
|
|
|
|
* updating the TRAILING coordinates of all tiles along the RHS, and
|
|
|
|
|
* then merging vertically where possible.
|
|
|
|
|
*
|
|
|
|
|
* We only update TRAILING coordinates if they are not already far
|
|
|
|
|
* enough to the right.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May split and merge tiles.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowMoveEdge(edge)
|
|
|
|
|
Edge *edge; /* Edge to be moved */
|
|
|
|
|
{
|
|
|
|
|
Plane *plane = plowYankDef->cd_planes[edge->e_pNum];
|
|
|
|
|
Tile *tp, *tpL;
|
|
|
|
|
Point p;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find topmost tile along LHS of edge.
|
|
|
|
|
* The goal is to clip the topmost LHS and topmost RHS tiles
|
|
|
|
|
* so their tops are equal to the top of the edge.
|
|
|
|
|
*/
|
|
|
|
|
p.p_x = edge->e_x - 1;
|
|
|
|
|
p.p_y = edge->e_ytop - 1;
|
|
|
|
|
tp = TiSrPointNoHint(plane, &p);
|
|
|
|
|
ASSERT(RIGHT(tp) == edge->e_x, "plowMoveEdge");
|
|
|
|
|
|
|
|
|
|
/* Only clip top tiles if we must update their coordinates */
|
|
|
|
|
if (LEADING(tp) < edge->e_newx)
|
|
|
|
|
{
|
|
|
|
|
if (TOP(tp) > edge->e_ytop)
|
|
|
|
|
(void) plowSplitY(tp, edge->e_ytop); /* Tp is bottom tile */
|
|
|
|
|
tp = TR(tp); /* Top tile on RHS */
|
|
|
|
|
if (TOP(tp) > edge->e_ytop)
|
|
|
|
|
(void) plowSplitY(tp, edge->e_ytop); /* Tp is bottom tile */
|
|
|
|
|
}
|
|
|
|
|
else for (tp = TR(tp); BOTTOM(tp) >= edge->e_ytop; tp = LB(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now 'tp' is the top-right tile. Walk down the RHS, updating TRAILING
|
|
|
|
|
* coordinates if necessary, and merging each tile with its upper neighbor.
|
|
|
|
|
* Stop one short of the last tile.
|
|
|
|
|
*/
|
|
|
|
|
for (; BOTTOM(tp) > edge->e_ybot; tp = LB(tp))
|
|
|
|
|
{
|
|
|
|
|
if (TRAILING(tp) < edge->e_newx)
|
|
|
|
|
plowSetTrailing(tp, edge->e_newx);
|
|
|
|
|
plowMergeTop(tp, plane);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now 'tp' is the bottom-right tile.
|
|
|
|
|
* Clip it if necessary, and update its TRAILING coordinate. Merge it
|
|
|
|
|
* with both its upper and lower neighbors. If tp is the only tile on
|
|
|
|
|
* the RHS, its TRAILING coordinate doesn't get updated until here.
|
|
|
|
|
*/
|
|
|
|
|
if (TRAILING(tp) < edge->e_newx)
|
|
|
|
|
{
|
|
|
|
|
if (BOTTOM(tp) < edge->e_ybot)
|
|
|
|
|
{
|
|
|
|
|
/* Clip (no merging will be necessary) */
|
|
|
|
|
tp = plowSplitY(tp, edge->e_ybot);
|
|
|
|
|
plowSetTrailing(tp, edge->e_newx);
|
|
|
|
|
tpL = BL(tp);
|
|
|
|
|
}
|
|
|
|
|
else /* BOTTOM(tp) == edge->e_ybot */
|
|
|
|
|
{
|
|
|
|
|
/* Merge (no clipping was necessary) */
|
|
|
|
|
tpL = BL(tp);
|
|
|
|
|
plowSetTrailing(tp, edge->e_newx);
|
|
|
|
|
plowMergeBottom(tp, plane);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Split the bottom-left tile if necessary; otherwise, merge down */
|
|
|
|
|
if (BOTTOM(tpL) < edge->e_ybot)
|
|
|
|
|
tpL = plowSplitY(tpL, edge->e_ybot); /* TpL is upper tile */
|
|
|
|
|
else
|
|
|
|
|
plowMergeBottom(tpL, plane);
|
|
|
|
|
}
|
|
|
|
|
else for (tpL = BL(tp); TOP(tpL) <= edge->e_ybot; tpL = RT(tpL))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
plowMergeTop(tp, plane);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now 'tpL' is the bottom-left tile, which has already been merged
|
|
|
|
|
* with its lower neighbor. Walk up the rest of the LHS, merging
|
|
|
|
|
* each tile with its lower neighbor.
|
|
|
|
|
*/
|
|
|
|
|
for (tp = RT(tpL); BOTTOM(tp) < edge->e_ytop; tp = RT(tp))
|
|
|
|
|
plowMergeBottom(tp, plane);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If tp now extends above edge->e_ytop, then it must not have been split
|
|
|
|
|
* way up in the first step in this procedure, which means that its LEADING
|
|
|
|
|
* coordinate was already far enough to the right, which means that it was
|
|
|
|
|
* not changed. Hence, we needn't try to merge to its bottom.
|
|
|
|
|
*/
|
|
|
|
|
if (BOTTOM(tp) == edge->e_ytop)
|
|
|
|
|
plowMergeBottom(tp, plane);
|
|
|
|
|
|
|
|
|
|
if (DebugIsSet(plowDebugID, plowDebMove))
|
|
|
|
|
plowDebugEdge(edge, (RuleTableEntry *) NULL, "move");
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowSplitY --
|
|
|
|
|
*
|
|
|
|
|
* Split a tile vertically in two, returning a pointer to
|
|
|
|
|
* the newly created upper tile.
|
|
|
|
|
*
|
|
|
|
|
* The new tile has its ti_client edge positions set to that
|
|
|
|
|
* of the original tile.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a pointer to the newly created tile.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Splits the tile 'tp'.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Tile *
|
|
|
|
|
plowSplitY(tp, y)
|
|
|
|
|
Tile *tp;
|
2022-01-07 21:37:06 +01:00
|
|
|
int y;
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
Tile *newTile;
|
|
|
|
|
|
|
|
|
|
newTile = TiSplitY(tp, y);
|
|
|
|
|
newTile->ti_client = tp->ti_client;
|
|
|
|
|
TiSetBody(newTile, TiGetBody(tp));
|
|
|
|
|
|
|
|
|
|
return (newTile);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowMergeTop --
|
|
|
|
|
* plowMergeBottom --
|
|
|
|
|
*
|
|
|
|
|
* Merge the given tile with its upper/lower neighbor if appropriate:
|
|
|
|
|
* plowMergeTop merges with the upper neighbor, plowMergeBottom with
|
|
|
|
|
* the lower. This may happen only if the types are the same, the
|
|
|
|
|
* LEADING/TRAILING coordinate the same, and the LEFT and RIGHT
|
|
|
|
|
* coordinates the same.
|
|
|
|
|
*
|
|
|
|
|
* Guarantees that the tile pointer passed it as an argument will
|
|
|
|
|
* remain valid after the call.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May cause two tiles to be joined.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowMergeTop(tp, plane)
|
|
|
|
|
Tile *tp;
|
|
|
|
|
Plane *plane;
|
|
|
|
|
{
|
|
|
|
|
Tile *tpRT = RT(tp);
|
|
|
|
|
|
|
|
|
|
if (TiGetTypeExact(tp) == TiGetTypeExact(tpRT)
|
|
|
|
|
&& LEFT(tp) == LEFT(tpRT) && RIGHT(tp) == RIGHT(tpRT)
|
|
|
|
|
&& LEADING(tp) == LEADING(tpRT) && TRAILING(tp) == TRAILING(tpRT))
|
|
|
|
|
{
|
|
|
|
|
TiJoinY(tp, tpRT, plane);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowMergeBottom(tp, plane)
|
|
|
|
|
Tile *tp;
|
|
|
|
|
Plane *plane;
|
|
|
|
|
{
|
|
|
|
|
Tile *tpLB = LB(tp);
|
|
|
|
|
|
|
|
|
|
if (TiGetTypeExact(tp) == TiGetTypeExact(tpLB)
|
|
|
|
|
&& LEFT(tp) == LEFT(tpLB) && RIGHT(tp) == RIGHT(tpLB)
|
|
|
|
|
&& LEADING(tp) == LEADING(tpLB) && TRAILING(tp) == TRAILING(tpLB))
|
|
|
|
|
{
|
|
|
|
|
TiJoinY(tp, tpLB, plane);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-01 20:40:10 +02:00
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
2018-04-01 20:40:10 +02:00
|
|
|
* PlowAfterTech --
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Initialize the rule tables for plowing. This gets called after
|
|
|
|
|
* the technology file has been read, since we need to know about
|
|
|
|
|
* fixed-width objects.
|
|
|
|
|
*
|
|
|
|
|
* Also initialize the debugging information.
|
|
|
|
|
*
|
|
|
|
|
* Sets plowYankHalo to be the size of the halo around each edge that
|
|
|
|
|
* we use when checking to see if plowProcessEdge must yank more area
|
|
|
|
|
* from the original cell. If this halo extends outside plowYankedArea
|
|
|
|
|
* or touches it, we yank more. The size of the halo should be such
|
|
|
|
|
* that most of the plowing rules are guaranteed not to visit any area
|
|
|
|
|
* outside of it. Currently, DRCTechHalo is sufficient; only the rules
|
|
|
|
|
* moving whole tiles need anything bigger than this, and they are
|
|
|
|
|
* responsible for doing their own yanking if they need it.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* See above.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2018-04-01 20:40:10 +02:00
|
|
|
PlowAfterTech()
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
RuleTableEntry *rp, *re;
|
|
|
|
|
TileTypeBitMask allButSpace, allBits;
|
|
|
|
|
TileTypeBitMask cellTypes;
|
|
|
|
|
TileTypeBitMask widthL, widthR;
|
|
|
|
|
TileTypeBitMask spaceL, spaceR;
|
|
|
|
|
TileTypeBitMask mask;
|
|
|
|
|
TileType i, j;
|
|
|
|
|
|
2018-12-14 22:33:34 +01:00
|
|
|
/* Reset rules tables */
|
|
|
|
|
plowSearchRulesPtr = plowSearchRulesTbl;
|
|
|
|
|
plowCellRulesPtr = plowCellRulesTbl;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Set the masks we will use for all the rules below */
|
|
|
|
|
allButSpace = DBAllButSpaceAndDRCBits;
|
|
|
|
|
allBits = DBAllTypeBits;
|
|
|
|
|
TTMaskSetOnlyType(&cellTypes, PLOWTYPE_CELL);
|
|
|
|
|
TTMaskZero(&widthL);
|
|
|
|
|
TTMaskZero(&widthR);
|
|
|
|
|
TTMaskZero(&spaceL);
|
|
|
|
|
TTMaskZero(&spaceR);
|
|
|
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
|
|
|
{
|
|
|
|
|
if (plowWidthRulesTbl[i][j])
|
|
|
|
|
{
|
|
|
|
|
TTMaskSetType(&widthL, i);
|
|
|
|
|
TTMaskSetType(&widthR, j);
|
|
|
|
|
}
|
|
|
|
|
if (plowSpacingRulesTbl[i][j])
|
|
|
|
|
{
|
|
|
|
|
TTMaskSetType(&spaceL, i);
|
|
|
|
|
TTMaskSetType(&spaceR, j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dummy rule for debugging */
|
|
|
|
|
plowInitRule(&plowRuleInitial, (&plowRuleInitial) + 1, RTE_NULL,
|
|
|
|
|
(int (*)()) NULL,
|
|
|
|
|
"initial edge",
|
|
|
|
|
DBZeroTypeBits, DBZeroTypeBits);
|
|
|
|
|
|
|
|
|
|
/* Cell rules */
|
|
|
|
|
rp = plowCellRulesPtr;
|
|
|
|
|
re = &plowCellRulesTbl[MAXRULES];
|
|
|
|
|
/* Drag geometry with cells */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prCell,
|
|
|
|
|
"drag paint with cells",
|
|
|
|
|
allBits, cellTypes);
|
|
|
|
|
if (rp >= re) rp = re;
|
|
|
|
|
plowCellRulesPtr = rp;
|
|
|
|
|
|
|
|
|
|
/* Search rules */
|
|
|
|
|
rp = plowSearchRulesPtr;
|
|
|
|
|
re = &plowSearchRulesTbl[MAXRULES];
|
|
|
|
|
/* Clear the umbra */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prClearUmbra, "clear umbra",
|
|
|
|
|
allBits, allButSpace);
|
|
|
|
|
plowInitRule(rp++, re, RTE_REALWIDTH, prUmbra, "umbra width",
|
|
|
|
|
widthL, widthR);
|
|
|
|
|
plowInitRule(rp++, re, RTE_SPACING, prUmbra, "umbra spacing",
|
|
|
|
|
spaceL, spaceR);
|
|
|
|
|
|
|
|
|
|
/* Clear the penumbra */
|
|
|
|
|
plowInitRule(rp++, re, RTE_REALWIDTH, prPenumbraTop,
|
|
|
|
|
"top penumbra width",
|
|
|
|
|
widthL, widthR);
|
|
|
|
|
plowInitRule(rp++, re, RTE_SPACING, prPenumbraTop,
|
|
|
|
|
"top penumbra spacing",
|
|
|
|
|
spaceL, spaceR);
|
|
|
|
|
plowInitRule(rp++, re, RTE_REALWIDTH, prPenumbraBot,
|
|
|
|
|
"bottom penumbra width",
|
|
|
|
|
widthL, widthR);
|
|
|
|
|
plowInitRule(rp++, re, RTE_SPACING, prPenumbraBot,
|
|
|
|
|
"bottom penumbra spacing",
|
|
|
|
|
spaceL, spaceR);
|
|
|
|
|
|
|
|
|
|
/* Special penumbra searching when RHS is fixed */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NOSPACING, prFixedPenumbraTop,
|
|
|
|
|
"top penumbra spacing (RHS fixed-width)",
|
|
|
|
|
allBits, PlowFixedTypes);
|
|
|
|
|
plowInitRule(rp++, re, RTE_NOSPACING, prFixedPenumbraBot,
|
|
|
|
|
"bottom penumbra spacing (RHS fixed-width)",
|
|
|
|
|
allBits, PlowFixedTypes);
|
|
|
|
|
|
|
|
|
|
/* Avoid introducing slivers */
|
|
|
|
|
plowInitRule(rp++, re, RTE_MINWIDTH, prSliverTop,
|
|
|
|
|
"top width slivers",
|
|
|
|
|
widthL, widthR);
|
|
|
|
|
plowInitRule(rp++, re, RTE_SPACING, prSliverTop,
|
|
|
|
|
"top spacing slivers",
|
|
|
|
|
spaceL, spaceR);
|
|
|
|
|
plowInitRule(rp++, re, RTE_MINWIDTH, prSliverBot,
|
|
|
|
|
"bottom width slivers",
|
|
|
|
|
widthL, widthR);
|
|
|
|
|
plowInitRule(rp++, re, RTE_SPACING, prSliverBot,
|
|
|
|
|
"bottom spacing slivers",
|
|
|
|
|
spaceL, spaceR);
|
|
|
|
|
|
|
|
|
|
/* Inside slivers (plow too small) */
|
|
|
|
|
TTMaskCom2(&mask, &PlowFixedTypes);
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prInSliver,
|
|
|
|
|
"inside slivers",
|
|
|
|
|
mask, mask);
|
|
|
|
|
|
|
|
|
|
/* Avoid introducing illegal edges */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prIllegalTop,
|
|
|
|
|
"top illegal edges",
|
|
|
|
|
allBits, allBits);
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prIllegalBot,
|
|
|
|
|
"bottom illegal edges",
|
|
|
|
|
allBits, allBits);
|
|
|
|
|
|
|
|
|
|
/* Avoid uncovering "covered" materials (e.g, fets) */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prCoverTop,
|
|
|
|
|
"top covering",
|
|
|
|
|
PlowCoveredTypes, allBits);
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prCoverBot,
|
|
|
|
|
"bottom covering",
|
|
|
|
|
PlowCoveredTypes, allBits);
|
|
|
|
|
|
|
|
|
|
/* Preserve fixed-width objects */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prFixedLHS,
|
|
|
|
|
"LHS is fixed",
|
|
|
|
|
PlowFixedTypes, allBits);
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prFixedRHS,
|
|
|
|
|
"RHS is fixed",
|
|
|
|
|
allBits, PlowFixedTypes);
|
|
|
|
|
|
|
|
|
|
/* Fixed-width objects drag trailing stubs */
|
|
|
|
|
TTMaskCom2(&mask, &PlowDragTypes);
|
|
|
|
|
TTMaskClearType(&mask, TT_SPACE);
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prFixedDragStubs,
|
|
|
|
|
"RHS fixed dragging stubs",
|
|
|
|
|
mask, PlowDragTypes);
|
|
|
|
|
|
|
|
|
|
/* Couple contacts */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prContactLHS,
|
|
|
|
|
"LHS is contact",
|
|
|
|
|
PlowContactTypes, allBits);
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prContactRHS,
|
|
|
|
|
"RHS is contact",
|
|
|
|
|
allBits, PlowContactTypes);
|
|
|
|
|
|
|
|
|
|
/* Move cells out of the way */
|
|
|
|
|
plowInitRule(rp++, re, RTE_NULL, prFindCells,
|
|
|
|
|
"find cells",
|
|
|
|
|
allBits, allBits);
|
|
|
|
|
|
|
|
|
|
if (rp >= re) rp = re;
|
|
|
|
|
plowSearchRulesPtr = rp;
|
|
|
|
|
|
|
|
|
|
/* Initialize debugging flags */
|
|
|
|
|
plowDebugInit();
|
|
|
|
|
|
|
|
|
|
/* Initialize the yank halo */
|
|
|
|
|
plowYankHalo = DRCTechHalo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowInitRule(rtePtr, rteEnd, whichRules, proc, name, ltypes, rtypes)
|
|
|
|
|
RuleTableEntry *rtePtr; /* Pointer to entry to be added */
|
|
|
|
|
RuleTableEntry *rteEnd; /* Pointer to one past last entry in table */
|
|
|
|
|
int whichRules; /* Which rules to use (RTE_* from earlier) */
|
|
|
|
|
int (*proc)(); /* Procedure implementing the rule */
|
|
|
|
|
char *name; /* Name of this rule */
|
|
|
|
|
TileTypeBitMask ltypes, rtypes;
|
|
|
|
|
{
|
|
|
|
|
if (rtePtr >= rteEnd)
|
|
|
|
|
{
|
|
|
|
|
TxError("Too many rules in PlowMain.c (maximum %d)\n", MAXRULES);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
rtePtr->rte_whichRules = whichRules;
|
|
|
|
|
rtePtr->rte_proc = proc;
|
|
|
|
|
rtePtr->rte_name = name;
|
|
|
|
|
rtePtr->rte_ltypes = ltypes;
|
|
|
|
|
rtePtr->rte_rtypes = rtypes;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* plowYankCreate --
|
|
|
|
|
*
|
|
|
|
|
* Create the yank buffers used for plowing.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Creates the cells __PLOWYANK__ and __PLOWINCR__ if they
|
|
|
|
|
* don't already exist, and initializes plowYankDef, plowYankUse,
|
|
|
|
|
* and plowDummyUse.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plowYankCreate()
|
|
|
|
|
{
|
|
|
|
|
if (plowYankDef == NULL)
|
|
|
|
|
{
|
|
|
|
|
DBNewYank("__PLOWYANK__", &plowYankUse, &plowYankDef);
|
|
|
|
|
DBNewYank("__PLOWYANK__", &plowDummyUse, &plowYankDef);
|
|
|
|
|
DBNewYank("__PLOWINCR__", &plowSpareUse, &plowSpareDef);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef NO_RUSAGE
|
2022-12-28 18:20:43 +01:00
|
|
|
void
|
2017-04-25 14:41:48 +02:00
|
|
|
plowShowTime(t1, t2, nqueued, nprocessed, nmoved)
|
|
|
|
|
struct rusage *t1, *t2;
|
|
|
|
|
int nqueued, nprocessed, nmoved;
|
|
|
|
|
{
|
|
|
|
|
double secs, usecs;
|
|
|
|
|
|
|
|
|
|
secs = t2->ru_utime.tv_sec - t1->ru_utime.tv_sec;
|
|
|
|
|
usecs = (secs * 1000000.) + (t2->ru_utime.tv_usec - t1->ru_utime.tv_usec);
|
|
|
|
|
|
|
|
|
|
printf("%.2f sec, %d queued, %d processed, %d moved\n",
|
|
|
|
|
usecs/1000000., nqueued, nprocessed, nmoved);
|
|
|
|
|
}
|
|
|
|
|
#endif
|