1193 lines
28 KiB
C
1193 lines
28 KiB
C
/*
|
|
* irRoute.c --
|
|
*
|
|
* Sets up route and calls maze router to do it.
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1987, 1990 Michael H. Arnold, Walter S. Scott, and *
|
|
* * the Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/irouter/irRoute.c,v 1.3 2008/12/11 04:20:08 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
/* --- Includes --- */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "utils/hash.h"
|
|
#include "tiles/tile.h"
|
|
#include "database/database.h"
|
|
#include "drc/drc.h"
|
|
#include "textio/textio.h"
|
|
#include "windows/windows.h"
|
|
#include "utils/main.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "debug/debug.h"
|
|
#include "utils/undo.h"
|
|
#include "utils/signals.h"
|
|
#include "utils/malloc.h"
|
|
#include "utils/list.h"
|
|
#include "utils/geofast.h"
|
|
#include "utils/touchingtypes.h"
|
|
#include "select/select.h"
|
|
#include "mzrouter/mzrouter.h"
|
|
#include "irouter/irouter.h"
|
|
#include "irouter/irInternal.h"
|
|
|
|
/* C99 compat */
|
|
#include "select/select.h"
|
|
|
|
/* --- Routines local to this file that are referenced before they are
|
|
* defined --- */
|
|
List *irChooseEndPtLayers();
|
|
|
|
/* -------------------- Structures Local to this File -------------------- */
|
|
|
|
/* clientdata structure passed to filter functions when searching for
|
|
* start and destination labels.
|
|
*/
|
|
typedef struct labelSearchData
|
|
{
|
|
Rect lsd_locRect; /* set to labels location by filter func */
|
|
char *lsd_name; /* label name to search for */
|
|
TileType lsd_type; /* layer that label is attached to */
|
|
int lsd_result; /* code giving result of search */
|
|
} LabelSearchData;
|
|
|
|
/* result codes for lsd_result above */
|
|
#define LSR_NOTFOUND 10
|
|
#define LSR_NOTUNIQUE 20
|
|
#define LSR_FOUND 30
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* irRoute --
|
|
*
|
|
* Top level procedure for the routing code. Initializes things, and
|
|
* calls the maze router to make a connection.
|
|
*
|
|
* Results:
|
|
* Passes back the result code of MZRoute() (see mzrouter.h for codes)
|
|
*
|
|
* Side effects:
|
|
* Paint route into editcell.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
irRoute(cmdWindow, startType, argStartPt, argStartLabel, argStartLayers,
|
|
destType, argDestRect, argDestLabel, argDestLayers)
|
|
MagWindow *cmdWindow; /* window route command issued to */
|
|
int startType; /* how start is specified */
|
|
Point *argStartPt; /* location to route from (in edit cell coords) */
|
|
char *argStartLabel; /* label to route from */
|
|
List *argStartLayers; /* OK route layers to start route on */
|
|
int destType; /* how dest is specified */
|
|
Rect *argDestRect; /* location to route to (in edit cell coords) */
|
|
char *argDestLabel; /* label to route to */
|
|
List *argDestLayers; /* OK route layers to end route on */
|
|
{
|
|
CellUse *routeUse; /* Toplevel cell visible during routing */
|
|
int expansionMask; /* Subcell expansion modes to use during
|
|
* routing */
|
|
Point startPt; /* start and dest terminals */
|
|
List *startLayers = NULL;
|
|
Rect destRect;
|
|
List *destLayers = NULL;
|
|
RoutePath *path = NULL; /* resulting path */
|
|
TileType startLayer = TT_SPACE;
|
|
int mzResult = MZ_NO_ACTION;
|
|
|
|
/* determine routeUse and expansionMask for this route. */
|
|
{
|
|
MagWindow *window = NULL;
|
|
|
|
/* find global reference window */
|
|
if(irRouteWid>=0)
|
|
{
|
|
window = WindSearchWid(irRouteWid);
|
|
if (window == NULL)
|
|
{
|
|
TxError("Couldn't find route window (%d),", irRouteWid);
|
|
TxError("using command window as reference.\n");
|
|
}
|
|
}
|
|
|
|
/* if no global reference window, use window command issued from */
|
|
if(window == NULL)
|
|
{
|
|
window = cmdWindow;
|
|
}
|
|
|
|
/* If reference window is nil, complain and exit */
|
|
if(window==NULL)
|
|
{
|
|
TxError("Point to a layout window first.\n");
|
|
return mzResult;
|
|
}
|
|
|
|
/* Set expansion mask to window route cmd issued to. Used
|
|
* during searches. Subcells are treated as expanded if expanded in
|
|
* window cmd issued to.
|
|
*/
|
|
expansionMask = ((DBWclientRec *)(window->w_clientData))->dbw_bitmask;
|
|
|
|
/* Set routeUse to rootuse of reference window -
|
|
* everything "visible" in
|
|
* the reference window is visible
|
|
* during routing.
|
|
* But resulting route
|
|
* is painted into edit cell. This distinction is important only
|
|
* in the case of a subedit. If the user subedits a cell, the
|
|
* context of the parent(s) will guide the route, but the route
|
|
* will be painted into the edit cell.
|
|
*/
|
|
routeUse = (CellUse *) (window->w_surfaceID);
|
|
|
|
/* make sure cmd issued from window in which edit cell
|
|
* is being edited */
|
|
if (!EditCellUse || EditRootDef != routeUse->cu_def)
|
|
{
|
|
TxError("Nothing being edited in route window.\n");
|
|
return mzResult;
|
|
}
|
|
}
|
|
|
|
/* initialize mzrouter */
|
|
MZInitRoute(irMazeParms, routeUse, expansionMask);
|
|
|
|
/* Figure out start coordinates */
|
|
{
|
|
Point irGetStartPoint();
|
|
|
|
startPt = irGetStartPoint(startType,
|
|
argStartPt,
|
|
argStartLabel,
|
|
&startLayer,
|
|
routeUse);
|
|
|
|
/* check for failure */
|
|
if(startPt.p_x == MINFINITY) goto abort;
|
|
}
|
|
|
|
/* Set maze router dest area(s) */
|
|
|
|
if(destType == DT_SELECTION)
|
|
/* add destination area for each selected area on an appropriate layer */
|
|
{
|
|
int irSelectedTileFunc();
|
|
|
|
if(argDestLayers == NULL)
|
|
/* no layer arg specified, generate dest areas for each active
|
|
* route layer
|
|
*/
|
|
{
|
|
RouteLayer *rL;
|
|
|
|
for (rL = irRouteLayers; rL != NULL; rL = rL->rl_next)
|
|
{
|
|
if(rL->rl_routeType.rt_active)
|
|
{
|
|
/* set dest area for each selected tile
|
|
* of type connecting to rL
|
|
*/
|
|
SelEnumPaint(
|
|
&(DBConnectTbl[rL->rl_routeType.rt_tileType]),
|
|
FALSE, /* TRUE = restricted to edit cell */
|
|
NULL, /* not used */
|
|
irSelectedTileFunc,
|
|
(ClientData *) rL /* type of destarea */
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
/* generate dest areas for layers that are both specified and active */
|
|
{
|
|
List *l;
|
|
|
|
for(l=argDestLayers; l!=NULL; l=LIST_TAIL(l))
|
|
{
|
|
RouteLayer *rL = (RouteLayer *) LIST_FIRST(l);
|
|
|
|
if(rL->rl_routeType.rt_active)
|
|
{
|
|
/* set dest area for each selected tile
|
|
* of type connecting to rL
|
|
*/
|
|
SelEnumPaint(
|
|
&(DBConnectTbl[rL->rl_routeType.rt_tileType]),
|
|
FALSE, /* TRUE = restricted to edit cell */
|
|
NULL, /* not used */
|
|
irSelectedTileFunc,
|
|
(ClientData *) rL /* type of destarea */
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
/* dest is defined by rectangle */
|
|
{
|
|
Rect irGetDestRect();
|
|
TileType destLayer = TT_SPACE;
|
|
|
|
destRect = irGetDestRect(destType,
|
|
argDestRect,
|
|
argDestLabel,
|
|
&destLayer,
|
|
routeUse);
|
|
|
|
/* check for failure */
|
|
if(destRect.r_xtop == MINFINITY) goto abort;
|
|
|
|
/* set a maze router dest area for extent of destRect
|
|
* on each permitted dest layer.
|
|
*/
|
|
if (destLayer != TT_SPACE)
|
|
{
|
|
RouteLayer *rL;
|
|
|
|
/* layer type returned by irGetDestRect */
|
|
|
|
for(rL = irRouteLayers; rL != NULL; rL = rL->rl_next)
|
|
{
|
|
if (rL->rl_routeType.rt_active &&
|
|
TTMaskHasType(&(DBConnectTbl[destLayer]),
|
|
rL->rl_routeType.rt_tileType))
|
|
{
|
|
MZAddDest(&destRect, rL->rl_routeType.rt_tileType);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (argDestLayers == NULL)
|
|
{
|
|
/* no layer arg specified, permit all active route layers */
|
|
RouteLayer *rL;
|
|
|
|
for (rL = irRouteLayers; rL != NULL; rL = rL->rl_next)
|
|
{
|
|
if(rL->rl_routeType.rt_active)
|
|
{
|
|
MZAddDest(&destRect,rL->rl_routeType.rt_tileType);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
/* permit only layers that are both specified and active */
|
|
{
|
|
List *l;
|
|
|
|
for(l=argDestLayers; l!=NULL; l=LIST_TAIL(l))
|
|
{
|
|
RouteLayer *rL = (RouteLayer *) LIST_FIRST(l);
|
|
|
|
if(rL->rl_routeType.rt_active)
|
|
{
|
|
MZAddDest(&destRect,rL->rl_routeType.rt_tileType);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (startLayer != TT_SPACE)
|
|
{
|
|
RouteLayer *rL;
|
|
|
|
/* layer type returned by irGetStartPoint */
|
|
|
|
for (rL = irRouteLayers; rL != NULL; rL = rL->rl_next)
|
|
{
|
|
if (rL->rl_routeType.rt_active &&
|
|
TTMaskHasType(&(DBConnectTbl[startLayer]),
|
|
rL->rl_routeType.rt_tileType))
|
|
|
|
{
|
|
MZAddStart(&startPt, rL->rl_routeType.rt_tileType);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Determine OK start layers */
|
|
|
|
List *l;
|
|
|
|
startLayers = irChooseEndPtLayers(
|
|
routeUse,
|
|
expansionMask,
|
|
&startPt,
|
|
argStartLayers,
|
|
"start");
|
|
if(SigInterruptPending) goto abort;
|
|
|
|
if(DebugIsSet(irDebugID,irDebEndPts))
|
|
{
|
|
TxPrintf("----- startLayers:\n");
|
|
MZPrintRLListNames(startLayers);
|
|
}
|
|
|
|
/* Set maze router start point(s) - one for each ok layer */
|
|
|
|
for(l=startLayers; l!=NULL;l=LIST_TAIL(l))
|
|
{
|
|
RouteLayer *rL = (RouteLayer *)LIST_FIRST(l);
|
|
TileType type = rL->rl_routeType.rt_tileType;
|
|
|
|
MZAddStart(&startPt, type);
|
|
}
|
|
}
|
|
|
|
/* Do the Route */
|
|
path = MZRoute(&mzResult);
|
|
/* If MZRoute is interrupted it returns best path
|
|
* found so far.
|
|
*/
|
|
|
|
if(SigInterruptPending)
|
|
{
|
|
if(path==NULL)
|
|
{
|
|
goto abort;
|
|
}
|
|
else
|
|
{
|
|
TxError("Search Interrupted!\n");
|
|
TxPrintf("Using best path found prior to interrupt.\n");
|
|
|
|
/* Clear interrupt to allow paint back of path */
|
|
SigInterruptPending = FALSE;
|
|
}
|
|
}
|
|
|
|
/* paint route back into edit cell */
|
|
if (path)
|
|
{
|
|
|
|
RouteLayer *finalRL = path->rp_rLayer;
|
|
CellUse *resultUse;
|
|
|
|
/* Have MazeRouter paint path into resultCell */
|
|
resultUse = MZPaintPath(path);
|
|
if(SigInterruptPending) goto abort;
|
|
|
|
/* Copy to edit cell transforming from root to edit
|
|
* coords.
|
|
* Also select the entire route.
|
|
* This paint job is undoable.
|
|
*/
|
|
{
|
|
SearchContext scx;
|
|
|
|
scx.scx_use = resultUse;
|
|
scx.scx_area = resultUse->cu_def->cd_bbox;
|
|
scx.scx_trans = RootToEditTransform;
|
|
(void) DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, EditCellUse);
|
|
DBReComputeBbox(EditCellUse->cu_def);
|
|
}
|
|
|
|
/* Select the route */
|
|
{
|
|
SearchContext scx;
|
|
|
|
/* Clear selection, and set selection display for reference
|
|
* window and other windows containing routeUse as root.
|
|
*/
|
|
SelectClear();
|
|
if(SelectRootDef != routeUse->cu_def)
|
|
{
|
|
SelectRootDef = routeUse->cu_def;
|
|
SelSetDisplay(SelectUse, SelectRootDef);
|
|
}
|
|
|
|
/* Copy route to selection cell, notifying undo of change */
|
|
scx.scx_use = resultUse;
|
|
scx.scx_area = resultUse->cu_def->cd_bbox;
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL);
|
|
(void) DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, SelectUse);
|
|
SelRememberForUndo(FALSE, SelectRootDef, &(scx.scx_area));
|
|
|
|
/* Setup redisplay */
|
|
DBReComputeBbox(SelectDef);
|
|
DBWHLRedraw(SelectRootDef, &(scx.scx_area), TRUE);
|
|
DBWAreaChanged(SelectDef, &SelectDef->cd_bbox, DBW_ALLWINDOWS,
|
|
&DBAllButSpaceBits);
|
|
}
|
|
|
|
/* Notify dbwind module (for redisplay), and DRC module
|
|
* of changed area */
|
|
{
|
|
Rect changedArea;
|
|
|
|
GeoTransRect(
|
|
&RootToEditTransform,
|
|
&(resultUse->cu_def->cd_bbox),
|
|
&changedArea);
|
|
DBWAreaChanged(EditCellUse->cu_def, &changedArea, DBW_ALLWINDOWS,
|
|
&DBAllButSpaceBits);
|
|
DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &changedArea);
|
|
|
|
}
|
|
|
|
/* Make sure we got here without interruption */
|
|
if(SigInterruptPending) goto abort;
|
|
|
|
TxPrintf("Done Routing.\n");
|
|
TxFlushOut();
|
|
}
|
|
else
|
|
{
|
|
TxError("Route Failed.\n");
|
|
}
|
|
|
|
abort:
|
|
if(SigInterruptPending)
|
|
{
|
|
TxError("Route Interrupted!\n");
|
|
}
|
|
|
|
ListDealloc(startLayers);
|
|
ListDealloc(destLayers);
|
|
|
|
/* reclaim storage used by mzrouter */
|
|
if(!DebugIsSet(irDebugID, irDebNoClean))
|
|
{
|
|
MZClean();
|
|
}
|
|
|
|
return mzResult;
|
|
}
|
|
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* irGetStartPoint --
|
|
*
|
|
* Compute start point.
|
|
*
|
|
* Results:
|
|
* Returns point.
|
|
*
|
|
* Side effects:
|
|
* Returns start layer type in startLayerPtr.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
Point
|
|
irGetStartPoint(startType, argStartPt, argStartLabel, startLayerPtr, routeUse)
|
|
int startType; /* how start is specified */
|
|
Point *argStartPt; /* location to route from
|
|
* (in edit cell coords) */
|
|
char *argStartLabel; /* label to route from */
|
|
TileType *startLayerPtr; /* layer type (returned value) */
|
|
CellUse *routeUse; /* toplevel cell visible to router */
|
|
{
|
|
Point startPt;
|
|
|
|
switch (startType)
|
|
{
|
|
case ST_POINT:
|
|
/* start point coords given */
|
|
{
|
|
/* convert from edit to routeUse coords (= root coordinates) */
|
|
GeoTransPoint(&EditToRootTransform,argStartPt,&startPt);
|
|
}
|
|
break;
|
|
|
|
case ST_CURSOR:
|
|
/* use cursor */
|
|
{
|
|
MagWindow *pointWindow;
|
|
|
|
pointWindow = ToolGetPoint(&startPt, (Rect *) NULL);
|
|
|
|
if (pointWindow == NULL)
|
|
{
|
|
TxError("Can not use cursor as start:");
|
|
TxError(" cursor not in layout window.\n");
|
|
goto abort;
|
|
}
|
|
|
|
if (routeUse->cu_def !=
|
|
((CellUse *)pointWindow->w_surfaceID)->cu_def)
|
|
{
|
|
TxError("Can not use cursor as start:");
|
|
TxError("cursor not in routecell.\n");
|
|
goto abort;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ST_LABEL:
|
|
/* label name given */
|
|
{
|
|
int irSelLabelsFunc();
|
|
int irAllLabelsFunc();
|
|
LabelSearchData lSD;
|
|
lSD.lsd_name = argStartLabel; /* name to match */
|
|
lSD.lsd_result = LSR_NOTFOUND;
|
|
|
|
/* first search selection */
|
|
(void) SelEnumLabels(&DBAllTypeBits,
|
|
FALSE, /* TRUE = search only edit cell */
|
|
(bool *) NULL,
|
|
irSelLabelsFunc,
|
|
(ClientData) &lSD);
|
|
|
|
if(SigInterruptPending) goto abort;
|
|
|
|
if (lSD.lsd_result == LSR_NOTUNIQUE)
|
|
{
|
|
TxError("Warning: Start label '%s' not unique.\n", argStartLabel);
|
|
}
|
|
else if (lSD.lsd_result == LSR_NOTFOUND)
|
|
/* No selected label matched, so search all labels */
|
|
{
|
|
|
|
(void) DBSrLabelLoc(routeUse,
|
|
argStartLabel,
|
|
irAllLabelsFunc,
|
|
(ClientData) &lSD);
|
|
|
|
if(SigInterruptPending) goto abort;
|
|
|
|
if (lSD.lsd_result == LSR_NOTUNIQUE)
|
|
{
|
|
TxError("Warning: Start label '%s' not unique.\n", argStartLabel);
|
|
}
|
|
else if (lSD.lsd_result == LSR_NOTFOUND)
|
|
{
|
|
TxError("Start label '%s' not found.\n",
|
|
argStartLabel);
|
|
goto abort;
|
|
}
|
|
}
|
|
|
|
startPt = lSD.lsd_locRect.r_ll;
|
|
if (startLayerPtr) *startLayerPtr = lSD.lsd_type;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* shouldn't happen */
|
|
{
|
|
ASSERT(FALSE,"irGetStartPoint");
|
|
goto abort;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return startPt;
|
|
|
|
abort:
|
|
startPt.p_x = MINFINITY;
|
|
startPt.p_y = MINFINITY;
|
|
return startPt;
|
|
}
|
|
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* irGetDestRect --
|
|
*
|
|
* Compute destination rectangle.
|
|
*
|
|
* Results:
|
|
* Returns rect.
|
|
*
|
|
* Side effects:
|
|
* Returns layer type in destLayerPtr.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
Rect
|
|
irGetDestRect(destType, argDestRect, argDestLabel, destLayerPtr, routeUse)
|
|
int destType; /* how dest is specified */
|
|
Rect *argDestRect; /* location to route to
|
|
* (in edit cell coords) */
|
|
char *argDestLabel; /* label to route to */
|
|
TileType *destLayerPtr; /* layer type (returned value) */
|
|
CellUse *routeUse; /* toplevel cell visible to router */
|
|
{
|
|
Rect destRect;
|
|
|
|
switch (destType)
|
|
{
|
|
case DT_RECT:
|
|
/* dest rect coords given */
|
|
{
|
|
/* convert from edit to routeUse coords (= root coordinates) */
|
|
GeoTransRect(&EditToRootTransform,argDestRect,&destRect);
|
|
}
|
|
break;
|
|
|
|
case DT_LABEL:
|
|
/* dest rect given as label */
|
|
{
|
|
int irSelLabelsFunc();
|
|
int irAllLabelsFunc();
|
|
LabelSearchData lSD;
|
|
lSD.lsd_name = argDestLabel; /* name to match */
|
|
lSD.lsd_result = LSR_NOTFOUND;
|
|
|
|
/* first search selection */
|
|
(void) SelEnumLabels(&DBAllTypeBits,
|
|
FALSE, /* TRUE = search only edit cell */
|
|
(bool *) NULL,
|
|
irSelLabelsFunc,
|
|
(ClientData) &lSD);
|
|
if(SigInterruptPending) goto abort;
|
|
|
|
if (lSD.lsd_result == LSR_NOTUNIQUE)
|
|
{
|
|
TxError("Warning: Destination label '%s' not unique.\n", argDestLabel);
|
|
}
|
|
else if (lSD.lsd_result == LSR_NOTFOUND)
|
|
{
|
|
/* No selected label matched, so search all labels */
|
|
(void) DBSrLabelLoc(routeUse,
|
|
argDestLabel,
|
|
irAllLabelsFunc,
|
|
(ClientData) &lSD);
|
|
if(SigInterruptPending) goto abort;
|
|
|
|
if (lSD.lsd_result == LSR_NOTUNIQUE)
|
|
{
|
|
TxError("Warning: Destination label '%s' not unique.\n",
|
|
argDestLabel);
|
|
}
|
|
else if (lSD.lsd_result == LSR_NOTFOUND)
|
|
{
|
|
TxError("Destination label '%s' not found.\n",
|
|
argDestLabel);
|
|
goto abort;
|
|
}
|
|
}
|
|
|
|
destRect = lSD.lsd_locRect;
|
|
if (destLayerPtr) *destLayerPtr = lSD.lsd_type;
|
|
}
|
|
break;
|
|
|
|
case DT_BOX:
|
|
/* use box as dest rect */
|
|
{
|
|
CellDef *boxDef;
|
|
Rect box;
|
|
|
|
if(!ToolGetBox(&boxDef,&box))
|
|
{
|
|
TxError("Can not use box for dest: No Box.\n");
|
|
goto abort;
|
|
}
|
|
|
|
if (boxDef != routeUse->cu_def)
|
|
{
|
|
TxError("Can not use box for dest: ");
|
|
TxError("box not in route cell.\n");
|
|
goto abort;
|
|
}
|
|
|
|
destRect = box;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* shouldn't happen */
|
|
{
|
|
ASSERT(FALSE,"irGetDestRect");
|
|
goto abort;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return destRect;
|
|
|
|
abort:
|
|
destRect.r_xbot = MINFINITY;
|
|
destRect.r_ybot = MINFINITY;
|
|
destRect.r_xtop = MINFINITY;
|
|
destRect.r_ytop = MINFINITY;
|
|
return destRect;
|
|
}
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* irSelLabelsFunc --
|
|
*
|
|
* Called by SelEnumLabels on behalf of irRoute above, to find selected
|
|
* label of given name.
|
|
*
|
|
* Results:
|
|
* Returns 0 on first match, 1 on second match (to terminate search)
|
|
*
|
|
* Side effects:
|
|
* Sets locRect in clientdata arg location off matching label.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
irSelLabelsFunc(label, cellUse, transform, clientData)
|
|
Label *label;
|
|
CellUse *cellUse;
|
|
Transform *transform;
|
|
ClientData clientData;
|
|
{
|
|
LabelSearchData *lsd = (LabelSearchData *)clientData;
|
|
CellDef *cellDef = cellUse->cu_def;
|
|
|
|
if (strcmp(lsd->lsd_name, label->lab_text) != 0)
|
|
{
|
|
/* this label doesn't match, continue search */
|
|
return 0;
|
|
}
|
|
else if (lsd->lsd_result == LSR_FOUND)
|
|
{
|
|
/* second match, set result and terminate search */
|
|
lsd->lsd_result = LSR_NOTUNIQUE;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
/* first match, set location, result, and continue search */
|
|
GeoTransRect(transform,
|
|
&(label->lab_rect), &(lsd->lsd_locRect));
|
|
lsd->lsd_result = LSR_FOUND;
|
|
lsd->lsd_type = label->lab_type;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* irAllLabelsFunc --
|
|
*
|
|
* Called by DBSrLabelLoc on behalf of irRoute above, to convert labelName
|
|
* to location of label with matching name.
|
|
*
|
|
* Results:
|
|
* Returns 0 on first match, 1 on second match (to terminate search)
|
|
*
|
|
* Side effects:
|
|
* Sets locRect in clientdata arg to location of matching label.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
irAllLabelsFunc(rect, name, label, clientData)
|
|
Rect *rect;
|
|
char *name;
|
|
Label *label;
|
|
ClientData clientData;
|
|
{
|
|
LabelSearchData *lsd = (LabelSearchData *)clientData;
|
|
|
|
if (lsd->lsd_result == LSR_FOUND)
|
|
{
|
|
if (GEO_SAMERECT(lsd->lsd_locRect, *rect)) return 0;
|
|
|
|
/* second match, so set result and terminate search */
|
|
lsd->lsd_result = LSR_NOTUNIQUE;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
/* first match, so set location, result, and continue search */
|
|
lsd->lsd_locRect = *rect;
|
|
lsd->lsd_type = label->lab_type;
|
|
lsd->lsd_result = LSR_FOUND;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* irSelectedTileFunc --
|
|
*
|
|
* Called by SelEnumPaint on behalf of irRoute above, to process tile
|
|
* associated with selection rect.
|
|
*
|
|
* Results:
|
|
* Always returns 0 to continue search.
|
|
*
|
|
* Side effects:
|
|
* Call MzAddDest on selected area.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
irSelectedTileFunc(rect, type, c)
|
|
Rect *rect;
|
|
TileType type;
|
|
ClientData c;
|
|
{
|
|
RouteLayer *rL = (RouteLayer *) c;
|
|
MZAddDest(rect, rL->rl_routeType.rt_tileType);
|
|
|
|
/* return 0 to continue search */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* LayerInTouchingContact --
|
|
*
|
|
* A Predicate. Checks whether the given routeLayer is a component of a
|
|
* contact type in touchingTypes. Used by irChooseEndPtLayers below.
|
|
*
|
|
* Results:
|
|
* TRUE if the RouteLayer is a component of a contact type in
|
|
* touchingTypes, else FALSE.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
LayerInTouchingContact(rL,touchingTypes)
|
|
RouteLayer *rL;
|
|
TileTypeBitMask touchingTypes;
|
|
{
|
|
RouteContact *rC;
|
|
|
|
for(rC=irRouteContacts; rC!=NULL; rC=rC->rc_next)
|
|
{
|
|
if(TTMaskHasType(&touchingTypes,rC->rc_routeType.rt_tileType) &&
|
|
(rC->rc_rLayer1==rL || rC->rc_rLayer2==rL))
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* irChooseEndPtLayers --
|
|
*
|
|
* Figure out what layers are ok at an endpoint - if ambiguous ask user.
|
|
*
|
|
* Results:
|
|
* List of ok layers at endpoint.
|
|
*
|
|
* Side effects:
|
|
* May query user about intended layers at an endpoint.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
List *
|
|
irChooseEndPtLayers(routeUse,expansionMask,endPt,argLayers,endPtName)
|
|
CellUse *routeUse;
|
|
int expansionMask; /* mask of expanded subcells */
|
|
Point *endPt;
|
|
List *argLayers;
|
|
char *endPtName;
|
|
{
|
|
List *activeLayers;
|
|
List *presentLayers;
|
|
List *presentContacts;
|
|
List *presentContactLayers;
|
|
|
|
static const char * const actionNames[] = { "no", "yes", 0 };
|
|
|
|
List *l;
|
|
RouteLayer *rL;
|
|
|
|
if (DebugIsSet(irDebugID, irDebEndPts))
|
|
{
|
|
TxPrintf("----- argLayers:\n");
|
|
MZPrintRLListNames(argLayers);
|
|
}
|
|
|
|
/* find activeLayers among argLayers (or irRouteLayers if argLayers NULL) */
|
|
activeLayers = NULL;
|
|
if(argLayers)
|
|
{
|
|
/* layers given in arg, search these */
|
|
for(l=argLayers; l!=NULL; l=LIST_TAIL(l))
|
|
{
|
|
rL = (RouteLayer*) LIST_FIRST(l);
|
|
if(rL->rl_routeType.rt_active)
|
|
{
|
|
LIST_ADD(rL,activeLayers);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* no layers given as arg, so search all route layers */
|
|
for(rL=irRouteLayers; rL!=NULL; rL=rL->rl_next)
|
|
if(rL->rl_routeType.rt_active)
|
|
{
|
|
LIST_ADD(rL,activeLayers);
|
|
}
|
|
}
|
|
|
|
if (DebugIsSet(irDebugID, irDebEndPts))
|
|
{
|
|
TxPrintf("----- activeLayers:\n");
|
|
MZPrintRLListNames(activeLayers);
|
|
}
|
|
|
|
/* make lists of contacts (connecting two active layers) and
|
|
* active layers which are present at the end point.
|
|
*/
|
|
{
|
|
TileTypeBitMask touchingTypes;
|
|
RouteContact *rC;
|
|
|
|
touchingTypes = TouchingTypes(routeUse, expansionMask, endPt);
|
|
|
|
/* Make list of present and active contacts */
|
|
presentContacts = NULL;
|
|
presentContactLayers = NULL;
|
|
for(rC =irRouteContacts; rC!=NULL; rC=rC->rc_next)
|
|
{
|
|
if(TTMaskHasType(&touchingTypes,rC->rc_routeType.rt_tileType) &&
|
|
ListContainsP(rC->rc_rLayer1, activeLayers) &&
|
|
ListContainsP(rC->rc_rLayer2, activeLayers))
|
|
{
|
|
LIST_ADD(rC, presentContacts);
|
|
LIST_ADD(rC->rc_rLayer1, presentContactLayers);
|
|
LIST_ADD(rC->rc_rLayer2, presentContactLayers);
|
|
}
|
|
}
|
|
|
|
if (DebugIsSet(irDebugID, irDebEndPts))
|
|
{
|
|
TxPrintf("----- presentContacts:\n");
|
|
MZPrintRCListNames(presentContacts);
|
|
|
|
TxPrintf("----- presentContactLayers:\n");
|
|
MZPrintRLListNames(presentContactLayers);
|
|
}
|
|
|
|
|
|
/* make list of present layers that are not constituents of contacts
|
|
* above. If a contact is touching the endpt but one of
|
|
* its constituent layers in not active, the other constituent
|
|
* layer is treated as a presentLayer.
|
|
*/
|
|
presentLayers = NULL;
|
|
for(l=activeLayers; l!=NULL; l=LIST_TAIL(l))
|
|
{
|
|
rL = (RouteLayer *) LIST_FIRST(l);
|
|
if((TTMaskHasType(&touchingTypes,rL->rl_routeType.rt_tileType) ||
|
|
LayerInTouchingContact(rL,touchingTypes)) &&
|
|
!ListContainsP(rL, presentContactLayers))
|
|
{
|
|
LIST_ADD(rL,presentLayers);
|
|
}
|
|
}
|
|
|
|
if (DebugIsSet(irDebugID, irDebEndPts))
|
|
{
|
|
TxPrintf("----- presentLayers:\n");
|
|
MZPrintRLListNames(presentLayers);
|
|
}
|
|
}
|
|
|
|
/* return appropriate layer list. */
|
|
{
|
|
int numContacts, numLayers;
|
|
|
|
numContacts = ListLength(presentContacts);
|
|
numLayers = ListLength(presentLayers);
|
|
|
|
if(numLayers == 0 && numContacts == 0)
|
|
{
|
|
/* No Layers present at endpt, return list of all active layers */
|
|
ListDealloc(presentLayers);
|
|
ListDealloc(presentContacts);
|
|
ListDealloc(presentContactLayers);
|
|
|
|
return(activeLayers);
|
|
}
|
|
else if(numLayers == 1 && numContacts == 0)
|
|
{
|
|
/* Exactly one layer is both active and present, return list
|
|
* containing only this layer.
|
|
*/
|
|
ListDealloc(activeLayers);
|
|
ListDealloc(presentContacts);
|
|
ListDealloc(presentContactLayers);
|
|
|
|
return(presentLayers);
|
|
}
|
|
else if(numLayers == 0 && numContacts == 1)
|
|
{
|
|
/* Just one active contact under endpoint,
|
|
* return layers connecting to that contact.
|
|
*/
|
|
List *l;
|
|
RouteContact *rC;
|
|
|
|
rC = (RouteContact *) LIST_FIRST(presentContacts);
|
|
l = (List *) NULL;
|
|
LIST_ADD(rC->rc_rLayer1,l);
|
|
LIST_ADD(rC->rc_rLayer2,l);
|
|
|
|
ListDealloc(activeLayers);
|
|
ListDealloc(presentLayers);
|
|
ListDealloc(presentContacts);
|
|
ListDealloc(presentContactLayers);
|
|
|
|
return(l);
|
|
}
|
|
else
|
|
{
|
|
/* Multiple nodes active and present, ask user which one
|
|
* he wants to route to.
|
|
*/
|
|
char answer[100];
|
|
RouteLayer *rL;
|
|
RouteLayer *pickedRL;
|
|
RouteContact *rC;
|
|
RouteContact *pickedRC;
|
|
|
|
TxPrintf("Multiple nodes present at %s point:",
|
|
endPtName);
|
|
for(l=presentContacts; l!=NULL; l=LIST_TAIL(l))
|
|
{
|
|
rC=(RouteContact *) LIST_FIRST(l);
|
|
TxPrintf(" %s",
|
|
DBTypeLongNameTbl[rC->rc_routeType.rt_tileType]);
|
|
}
|
|
for(l=presentLayers; l!=NULL; l=LIST_TAIL(l))
|
|
{
|
|
rL=(RouteLayer *) LIST_FIRST(l);
|
|
TxPrintf(" %s",
|
|
DBTypeLongNameTbl[rL->rl_routeType.rt_tileType]);
|
|
}
|
|
TxPrintf("\n");
|
|
|
|
for(pickedRC=NULL,l=presentContacts; l && !pickedRC; l=LIST_TAIL(l))
|
|
{
|
|
rC = (RouteContact *) LIST_FIRST(l);
|
|
if (!LIST_TAIL(l) && !presentLayers)
|
|
{
|
|
/* last choice, so take it */
|
|
pickedRC = rC;
|
|
}
|
|
else
|
|
{
|
|
/* ask user */
|
|
TxPrintf("Connect to %s? [yes] ",
|
|
DBTypeLongNameTbl[rC->rc_routeType.rt_tileType]);
|
|
if (TxGetLine(answer, sizeof answer) == NULL ||
|
|
answer[0] == '\0')
|
|
(void) strcpy(answer,"yes");
|
|
|
|
if(Lookup(answer, actionNames) == 1)
|
|
{
|
|
/* Yes */
|
|
pickedRC = rC;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pickedRC)
|
|
{
|
|
List *l;
|
|
|
|
l=NULL;
|
|
LIST_ADD(rC->rc_rLayer1,l);
|
|
LIST_ADD(rC->rc_rLayer2,l);
|
|
ListDealloc(activeLayers);
|
|
ListDealloc(presentLayers);
|
|
ListDealloc(presentContacts);
|
|
ListDealloc(presentContactLayers);
|
|
|
|
return(l);
|
|
}
|
|
|
|
for(pickedRL=NULL,l=presentLayers; l && !pickedRL; l=LIST_TAIL(l))
|
|
{
|
|
rL = (RouteLayer *) LIST_FIRST(l);
|
|
if(!LIST_TAIL(l))
|
|
{
|
|
/* Last choice so choose it automatically */
|
|
pickedRL=rL;
|
|
}
|
|
else
|
|
{
|
|
/* Ask user */
|
|
TxPrintf("Connect to %s? [yes] ",
|
|
DBTypeLongNameTbl[rL->rl_routeType.rt_tileType]);
|
|
if (TxGetLine(answer, sizeof answer) == NULL ||
|
|
answer[0] == '\0')
|
|
(void) strcpy(answer,"yes");
|
|
|
|
if(Lookup(answer, actionNames) == 1)
|
|
{
|
|
/* Yes */
|
|
pickedRL = rL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pickedRL)
|
|
{
|
|
l=NULL;
|
|
LIST_ADD(rL,l);
|
|
ListDealloc(activeLayers);
|
|
ListDealloc(presentLayers);
|
|
ListDealloc(presentContacts);
|
|
ListDealloc(presentContactLayers);
|
|
|
|
return(l);
|
|
}
|
|
|
|
/* User didn't pick anything, return null list */
|
|
{
|
|
ListDealloc(activeLayers);
|
|
ListDealloc(presentLayers);
|
|
ListDealloc(presentContacts);
|
|
ListDealloc(presentContactLayers);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|