magic/irouter/irRoute.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(
RouteLayer *rL,
const 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);
}
}
}
}