magic/mzrouter/mzWalk.c

691 lines
18 KiB
C
Raw Normal View History

/*
* mzWalk.c --
*
* Code for Completing final legs of route within the blocked areas ajacent to
* dest areas.
*
* *********************************************************************
* * Copyright (C) 1988, 1990 Michael H. Arnold 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:";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/heap.h"
#include "database/database.h"
#include "utils/signals.h"
#include "textio/textio.h"
#include "utils/list.h"
#include "debug/debug.h"
#include "mzrouter/mzrouter.h"
#include "mzrouter/mzInternal.h"
/*
* ----------------------------------------------------------------------------
*
* mzWalkRight --
*
* Extend path inside a to-the-right walk.
*
* Results:
* None.
*
* Side effects:
* mzAddPoint() called to add extended path to appropriate queue.
*
* ----------------------------------------------------------------------------
*/
void
mzWalkRight(path)
RoutePath *path;
{
Point pOrg; /* point to extend from */
Point pNew; /* next interesting point in direction of extension */
dlong segCost; /* cost of segment between pOrg and pNew */
int extendCode; /* Interesting directions to extend in */
Tile *tpThis; /* Tile containing org point */
/* DEBUG - trace calls to this routine. */
if (DebugIsSet(mzDebugID, mzDebMaze))
TxPrintf("WALKING RIGHT\n");
/* pOrg = current end of path */
pOrg = path->rp_entry;
/* get blockage plane tile under pOrg */
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_hBlock,&pOrg);
/* org point should be in walk to left of dest area */
ASSERT(TiGetType(tpThis)==TT_LEFT_WALK,"mzWalkRight");
/* traverse to right edge of this walk to get to dest area */
pNew.p_x = RIGHT(tpThis);
pNew.p_y = pOrg.p_y;
/* mark as complete path */
extendCode = EC_COMPLETE;
/* compute cost of path segment from pOrg to pNew */
{
Tile *tp;
bool rotate;
tp = TiSrPointNoHint(mzVRotatePlane, &pOrg);
rotate = (TiGetType(tp) != TT_SPACE);
if (rotate)
segCost = (dlong) ((pNew.p_x - pOrg.p_x) *
path->rp_rLayer->rl_vCost);
else
segCost = (dlong) ((pNew.p_x - pOrg.p_x) *
path->rp_rLayer->rl_hCost);
}
/* Compute additional cost for paralleling nearest hint segment */
/* (Start at low end of segment and move to high end computing hint cost
* as we go)
*/
{
Tile *tp;
dlong hintCost;
int deltaUp, deltaDown, delta;
Point lowPt;
for(lowPt = pOrg; lowPt.p_x < pNew.p_x; lowPt.p_x = RIGHT(tp))
{
/* find tile in hint plane containing lowPt */
tp = TiSrPointNoHint(mzVHintPlane,&lowPt);
/* find nearest hint segment and add appropriate cost */
if(TiGetType(tp) != TT_MAGNET)
{
deltaUp = (TiGetType(RT(tp)) == TT_MAGNET) ?
TOP(tp) - lowPt.p_y : -1;
deltaDown = (TiGetType(LB(tp)) == TT_MAGNET) ?
lowPt.p_y - BOTTOM(tp) : -1;
/* delta = distance to nearest hint */
if (deltaUp < 0)
{
if (deltaDown < 0)
delta = 0;
else
delta = deltaDown;
}
else
{
if (deltaDown < 0)
delta = deltaUp;
else
delta = MIN(deltaUp,deltaDown);
}
if(delta>0)
{
hintCost = (dlong) ((MIN(RIGHT(tp),pNew.p_x) - lowPt.p_x) *
path->rp_rLayer->rl_hintCost);
hintCost *= delta;
segCost += hintCost;
}
}
}
}
/* Process the new point */
mzAddPoint(path, &pNew, path->rp_rLayer, 'H', extendCode, &segCost);
return;
}
/*
* ----------------------------------------------------------------------------
*
* mzWalkLeft --
*
* Extend path inside a to-the-left walk.
*
* Results:
* None.
*
* Side effects:
* mzAddPoint() called to add extended path to appropriate queue.
*
* ----------------------------------------------------------------------------
*/
void
mzWalkLeft(path)
RoutePath *path;
{
Point pOrg; /* point to extend from */
Point pNew; /* next interesting point in direction of extension */
dlong segCost; /* cost of segment between pOrg and pNew */
int extendCode; /* Interesting directions to extend in */
Tile *tpThis; /* Tile containing org point */
RouteType *rtype; /* Structure of material type at destination */
/* DEBUG - trace calls to this routine. */
if (DebugIsSet(mzDebugID, mzDebMaze))
TxPrintf("WALKING LEFT\n");
/* pOrg = current end of path */
pOrg = path->rp_entry;
/* get blockage plane tile under pOrg */
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_hBlock,&pOrg);
rtype = &path->rp_rLayer->rl_routeType;
/* org point should be in walk to right of dest area */
ASSERT(TiGetType(tpThis)==TT_RIGHT_WALK,"mzWalkLeft");
/* traverse just past left edge of this walk to get to dest area */
pNew.p_x = LEFT(tpThis) - 1;
pNew.p_y = pOrg.p_y;
/* mark as complete path */
extendCode = EC_COMPLETE;
/* compute cost of path segment from pOrg to pNew */
{
Tile *tp;
bool rotate;
tp = TiSrPointNoHint(mzVRotatePlane, &pOrg);
rotate = (TiGetType(tp) != TT_SPACE);
if (rotate)
segCost = (dlong) ((pOrg.p_x - pNew.p_x) *
path->rp_rLayer->rl_vCost);
else
segCost = (dlong) ((pOrg.p_x - pNew.p_x) *
path->rp_rLayer->rl_hCost);
}
/* Compute additional cost for paralleling nearest hint segment */
/* (Start at low end of segment and move to high end computing hint cost
* as we go)
*/
{
Tile *tp;
dlong hintCost;
int deltaUp, deltaDown, delta;
Point lowPt;
for(lowPt = pNew; lowPt.p_x < pOrg.p_x; lowPt.p_x = RIGHT(tp))
{
/* find tile in hint plane containing lowPt */
tp = TiSrPointNoHint(mzVHintPlane,&lowPt);
/* find nearest hint segment and add appropriate cost */
if(TiGetType(tp) != TT_MAGNET)
{
deltaUp = (TiGetType(RT(tp)) == TT_MAGNET) ?
TOP(tp) - lowPt.p_y : -1;
deltaDown = (TiGetType(LB(tp)) == TT_MAGNET) ?
lowPt.p_y - BOTTOM(tp) : -1;
/* delta = distance to nearest hint */
if (deltaUp < 0)
{
if (deltaDown < 0)
delta = 0;
else
delta = deltaDown;
}
else
{
if (deltaDown < 0)
delta = deltaUp;
else
delta = MIN(deltaUp,deltaDown);
}
if(delta>0)
{
hintCost = (dlong) ((MIN(RIGHT(tp),pOrg.p_x) - lowPt.p_x) *
path->rp_rLayer->rl_hintCost);
hintCost *= delta;
segCost += hintCost;
}
}
}
}
/* Process the new point */
mzAddPoint(path, &pNew, path->rp_rLayer, 'H', extendCode, &segCost);
return;
}
/*
* ----------------------------------------------------------------------------
*
* mzWalkUp --
*
* Extend path inside a up-walk.
*
* Results:
* None.
*
* Side effects:
* mzAddPoint() called to add extended path to appropriate queue.
*
* ----------------------------------------------------------------------------
*/
void
mzWalkUp(path)
RoutePath *path;
{
Point pOrg; /* point to extend from */
Point pNew; /* next interesting point in direction of extension */
dlong segCost; /* cost of segment between pOrg and pNew */
int extendCode; /* Interesting directions to extend in */
Tile *tpThis; /* Tile containing org point */
/* DEBUG - trace calls to this routine. */
if (DebugIsSet(mzDebugID, mzDebMaze))
TxPrintf("WALKING UP\n");
/* pOrg = current end of path */
pOrg = path->rp_entry;
/* get blockage plane tile under pOrg */
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_vBlock,&pOrg);
/* org point should be in walk to left of dest area */
ASSERT(TiGetType(tpThis)==TT_BOTTOM_WALK,"mzWalkUp");
/* traverse to top edge of this walk to get to dest area */
pNew.p_x = pOrg.p_x;
pNew.p_y = TOP(tpThis);
/* mark as complete path */
extendCode = EC_COMPLETE;
/* compute cost of path segment from pOrg to pNew */
{
Tile *tp;
bool rotate;
tp = TiSrPointNoHint(mzHRotatePlane, &pOrg);
rotate = (TiGetType(tp) != TT_SPACE);
if (rotate)
segCost = (dlong) ((pNew.p_y - pOrg.p_y) *
path->rp_rLayer->rl_hCost);
else
segCost = (dlong) ((pNew.p_y - pOrg.p_y) *
path->rp_rLayer->rl_vCost);
}
/* Compute additional cost for paralleling nearest hint segment */
/* (Start at low end of segment and move to high end computing hint cost
* as we go)
*/
{
Tile *tp;
dlong hintCost;
int deltaRight, deltaLeft, delta;
Point lowPt;
for(lowPt = pOrg; lowPt.p_y < pNew.p_y; lowPt.p_y = TOP(tp))
{
/* find tile in hint plane containing lowPt */
tp = TiSrPointNoHint(mzHHintPlane,&lowPt);
/* find nearest hint segment and add appropriate cost */
if(TiGetType(tp) != TT_MAGNET)
{
deltaRight = (TiGetType(TR(tp)) == TT_MAGNET) ?
RIGHT(tp) - lowPt.p_x : -1;
deltaLeft = (TiGetType(BL(tp)) == TT_MAGNET) ?
lowPt.p_x - LEFT(tp) : -1;
/* delta = distance to nearest hint */
if (deltaRight < 0)
{
if (deltaLeft < 0)
delta = 0;
else
delta = deltaLeft;
}
else
{
if (deltaLeft < 0)
delta = deltaRight;
else
delta = MIN(deltaRight,deltaLeft);
}
if(delta>0)
{
hintCost = (dlong) ((MIN(TOP(tp),pNew.p_y) - lowPt.p_y) *
path->rp_rLayer->rl_hintCost);
hintCost *= delta;
segCost += hintCost;
}
}
}
}
/* Process the new point */
mzAddPoint(path, &pNew, path->rp_rLayer, 'V', extendCode, &segCost);
return;
}
/*
* ----------------------------------------------------------------------------
*
* mzWalkDown --
*
* Extend path inside a down-walk.
*
* Results:
* None.
*
* Side effects:
* mzAddPoint() called to add extended path to appropriate queue.
*
* ----------------------------------------------------------------------------
*/
void
mzWalkDown(path)
RoutePath *path;
{
Point pOrg; /* point to extend from */
Point pNew; /* next interesting point in direction of extension */
dlong segCost; /* cost of segment between pOrg and pNew */
int extendCode; /* Interesting directions to extend in */
Tile *tpThis; /* Tile containing org point */
RouteType *rtype; /* Structure of material at destination */
/* DEBUG - trace calls to this routine. */
if (DebugIsSet(mzDebugID, mzDebMaze))
TxPrintf("WALKING DOWN\n");
/* pOrg = current end of path */
pOrg = path->rp_entry;
/* get blockage plane tile under pOrg */
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_vBlock,&pOrg);
rtype = &path->rp_rLayer->rl_routeType;
/* org point should be in walk to left of dest area */
ASSERT(TiGetType(tpThis)==TT_TOP_WALK,"mzWalkDown");
/* traverse to just past edge of this walk to get to dest area */
pNew.p_x = pOrg.p_x;
pNew.p_y = BOTTOM(tpThis) - 1;
/* mark as complete path */
extendCode = EC_COMPLETE;
/* compute cost of path segment from pOrg to pNew */
{
Tile *tp;
bool rotate;
tp = TiSrPointNoHint(mzHRotatePlane, &pOrg);
rotate = (TiGetType(tp) != TT_SPACE);
if (rotate)
segCost = (dlong) ((pOrg.p_y - pNew.p_y) *
path->rp_rLayer->rl_hCost);
else
segCost = (dlong) ((pOrg.p_y - pNew.p_y) *
path->rp_rLayer->rl_vCost);
}
/* Compute additional cost for paralleling nearest hint segment */
/* (Start at low end of segment and move to high end computing hint cost
* as we go)
*/
{
Tile *tp;
dlong hintCost;
int deltaRight, deltaLeft, delta;
Point lowPt;
for(lowPt = pNew; lowPt.p_y < pOrg.p_y; lowPt.p_y = TOP(tp))
{
/* find tile in hint plane containing lowPt */
tp = TiSrPointNoHint(mzHHintPlane,&lowPt);
/* find nearest hint segment and add appropriate cost */
if(TiGetType(tp) != TT_MAGNET)
{
deltaRight = (TiGetType(TR(tp)) == TT_MAGNET) ?
RIGHT(tp) - lowPt.p_x : -1;
deltaLeft = (TiGetType(BL(tp)) == TT_MAGNET) ?
lowPt.p_x - LEFT(tp) : -1;
/* delta = distance to nearest hint */
if (deltaRight < 0)
{
if (deltaLeft < 0)
delta = 0;
else
delta = deltaLeft;
}
else
{
if (deltaLeft < 0)
delta = deltaRight;
else
delta = MIN(deltaRight,deltaLeft);
}
if(delta>0)
{
hintCost = (dlong) ((MIN(TOP(tp),pOrg.p_y) - lowPt.p_y) *
path->rp_rLayer->rl_hintCost);
hintCost *= delta;
segCost += hintCost;
}
}
}
}
/* Process the new point */
mzAddPoint(path, &pNew, path->rp_rLayer, 'V', extendCode, &segCost);
return;
}
/*
* ----------------------------------------------------------------------------
*
* mzWalkLRContact --
*
* Extend path to dest area (above or below) via contact.
*
* Results:
* None.
*
* Side effects:
* mzAddPoint() called to add extended path to appropriate queue.
*
* ----------------------------------------------------------------------------
*/
void
mzWalkLRContact(path)
RoutePath *path;
{
Point pOrg; /* point to extend from */
int extendCode; /* Interesting directions to extend in */
RouteContact *rC; /* Route contact to make connection with */
RouteLayer *newRL; /* Route layer of dest area */
dlong conCost; /* Cost of final contact */
int walkType; /* TT_ABOVE_LR_WALK or TT_BELOW_LR_WALK */
Tile *tpThis; /* Tile containing org point */
Tile *tpCont; /* Tile allowing contact placement */
/* DEBUG - trace calls to this routine. */
if (DebugIsSet(mzDebugID, mzDebMaze))
TxPrintf("WALKING HOME VIA LR CONTACT\n");
/* pOrg = current end of path */
pOrg = path->rp_entry;
/* get blockage plane tile under pOrg. Contact walks were painted */
/* into the hBlock plane. */
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_hBlock,&pOrg);
walkType = TiGetType(tpThis);
/* find contact type that connects to route layer. */
for(rC=mzRouteContacts; rC!=NULL; rC=rC->rc_next)
{
/* if not active, skip it */
if(!(rC->rc_routeType.rt_active)) continue;
/* if it doesn't connect to both current and dest layers, skip it */
if((walkType == TT_BELOW_LR_WALK) && (rC->rc_rLayer1 != path->rp_rLayer))
continue;
if((walkType == TT_ABOVE_LR_WALK) && (rC->rc_rLayer2 != path->rp_rLayer))
continue;
/* if contact blocked, skip it */
tpCont = TiSrPointNoHint(rC->rc_routeType.rt_hBlock, &pOrg);
if (TiGetType(tpCont) == TT_BLOCKED)
continue;
/* if contact is non-square and doesn't fit, skip it */
if (RIGHT(tpThis) - pOrg.p_x <= rC->rc_routeType.rt_length
- rC->rc_routeType.rt_width)
continue;
/* if we got this far we found our contact, break out of the loop */
break;
}
/* There should always be an rC that works */
ASSERT(rC!=NULL,"mzWalkLRContact");
if (rC == NULL) return; /* For now, non-square contacts may cause this
* point to be reached. Fix in mzBlock.c?
*/
/* Compute the new route layer */
newRL = (rC->rc_rLayer1 != path->rp_rLayer) ? rC->rc_rLayer1 : rC->rc_rLayer2;
/* compute contact cost */
conCost = (dlong) rC->rc_cost;
/* Add final point */
mzAddPoint(path, &pOrg, newRL, 'O', EC_COMPLETE, &conCost);
return;
}
/*
* ----------------------------------------------------------------------------
*
* mzWalkUDContact --
*
* Extend path to dest area (above or below) via contact.
*
* Results:
* None.
*
* Side effects:
* mzAddPoint() called to add extended path to appropriate queue.
*
* ----------------------------------------------------------------------------
*/
void
mzWalkUDContact(path)
RoutePath *path;
{
Point pOrg; /* point to extend from */
int extendCode; /* Interesting directions to extend in */
RouteContact *rC; /* Route contact to make connection with */
RouteLayer *newRL; /* Route layer of dest area */
dlong conCost; /* Cost of final contact */
int walkType; /* TT_ABOVE_UD_WALK or TT_BELOW_UD_WALK */
Tile *tpThis; /* Tile containing org point */
Tile *tpCont; /* Tile allowing contact placement */
/* DEBUG - trace calls to this routine. */
if (DebugIsSet(mzDebugID, mzDebMaze))
TxPrintf("WALKING HOME VIA UD CONTACT\n");
/* pOrg = current end of path */
pOrg = path->rp_entry;
/* get blockage plane tile under pOrg. Contact walks were painted */
/* into the hBlock plane. */
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_vBlock,&pOrg);
walkType = TiGetType(tpThis);
/* find contact type that connects to route layer. */
for(rC=mzRouteContacts; rC!=NULL; rC=rC->rc_next)
{
/* if not active, skip it */
if(!(rC->rc_routeType.rt_active)) continue;
/* if it doesn't connect to both current and dest layers, skip it */
if((walkType == TT_BELOW_UD_WALK) && (rC->rc_rLayer1 != path->rp_rLayer))
continue;
if((walkType == TT_ABOVE_UD_WALK) && (rC->rc_rLayer2 != path->rp_rLayer))
continue;
/* if contact blocked, skip it */
tpCont = TiSrPointNoHint(rC->rc_routeType.rt_vBlock, &pOrg);
if (TiGetType(tpCont) == TT_BLOCKED)
continue;
/* if contact is non-square and doesn't fit, skip it */
if (TOP(tpThis) - pOrg.p_y <= rC->rc_routeType.rt_length
- rC->rc_routeType.rt_width)
continue;
/* if we got this far we found our contact, break out of the loop */
break;
}
/* There should always be an rC that works */
ASSERT(rC!=NULL,"mzWalkUDContact");
if (rC == NULL) return; /* For now, non-square contacts may cause this
* point to be reached. Fix in mzBlock.c?
*/
/* Compute the new route layer */
newRL = (rC->rc_rLayer1 != path->rp_rLayer) ? rC->rc_rLayer1 : rC->rc_rLayer2;
/* compute contact cost */
conCost = (dlong) rC->rc_cost;
/* Add final point */
mzAddPoint(path, &pOrg, newRL, 'X', EC_COMPLETE, &conCost);
return;
}