/* * mzStart.c -- * * Code for making initial legs of route within the blocked areas ajacent to * start 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 #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" /* Forward declarations */ extern bool mzExtendInitPath(RoutePath *, RouteLayer *, Point, dlong, int, int); extern bool mzAddInitialContacts(); /* * ---------------------------------------------------------------------------- * * Simple search function for start tiles. This function is called only if * a tile of type TT_SAMENODE is found in the search area. * * Results: * Always return 1 (break on the first acceptable tile found) * * Side effects: * None. * * ---------------------------------------------------------------------------- */ int mzFindSamenodeFunc(Tile *tile, Point *point) { *point = tile->ti_ll; return 1; } /* * ---------------------------------------------------------------------------- * * mzStart -- * * Establish initial path segments from start term, considering inital * contacts and leading out of any SAMENODE blocks * present at start point. * * Results: * TRUE normally, FALSE if mzExtendInitPath discovered that the * start node is already connected to the destination node. * * Side effects: * mzAddPoint() called to add paths to appropriate queue. * * ---------------------------------------------------------------------------- */ #define EC_ALL_DIRECTIONS (EC_RIGHT | EC_LEFT | EC_UP | EC_DOWN) bool mzStart(term) ColoredRect *term; { RouteLayer *rL; RouteContact *rC; Tile *tp; bool returnCode = TRUE; Point point; int result; Rect srect; /* Find routelayer corresponding to type */ for(rL = mzActiveRLs; rL != NULL; rL = rL->rl_nextActive) { if(rL->rl_routeType.rt_tileType == term->cr_type) break; } /* Expand area to bottom and left to make sure we can find */ /* SAMENODE tiles to the bottom and left of the terminal. */ srect = term->cr_rect; srect.r_xbot--; srect.r_ybot--; /* Added by Tim 8/2/06---for start terminals on contact layers, */ /* run mzExtendInitPath for layer1 and set rL to layer2. */ if ((rL == NULL) && DBIsContact(term->cr_type)) { for (rC = mzRouteContacts ; rC != NULL; rC = rC->rc_next) { if (!(rC->rc_routeType.rt_active)) continue; if (TTMaskHasType(&(DBConnectTbl[term->cr_type]), rC->rc_rLayer1->rl_routeType.rt_tileType) && TTMaskHasType(&(DBConnectTbl[term->cr_type]), rC->rc_rLayer2->rl_routeType.rt_tileType)) { /* Search block plane for first unblocked tile */ result = DBSrPaintArea((Tile *)NULL, rC->rc_rLayer1->rl_routeType.rt_hBlock, &srect, &mzStartTypesMask, mzFindSamenodeFunc, &point); if (result == 1) { returnCode = mzExtendInitPath(NULL, rC->rc_rLayer1, point, (dlong)0, 0, EC_ALL_DIRECTIONS); rL = rC->rc_rLayer2; break; } } } } /* If no corresponding route layer, check for layers that connect */ if (rL == NULL) { for (rL = mzActiveRLs; rL != NULL; rL = rL->rl_nextActive) { if (TTMaskHasType(&(DBConnectTbl[term->cr_type]), rL->rl_routeType.rt_tileType)) break; } } /* If no corresponding route layer, return. */ /* This does not need a warning. The search for connected tiles adds */ /* tile types that may not correspond to an active route layer. Just */ /* ignore such tiles. */ if (rL == NULL) return returnCode; /* Find a valid start point in this terminal */ result = DBSrPaintArea((Tile *)NULL, rL->rl_routeType.rt_hBlock, &srect, &mzStartTypesMask, mzFindSamenodeFunc, &point); if (result == 1) { /* call mzExtendInitPath to do the real work */ returnCode = mzExtendInitPath(NULL, /* path so far */ rL, /* layer of new point */ point, /* start point */ (dlong)0, /* cost of new segment */ 0, /* length of path so far */ EC_ALL_DIRECTIONS); /* how to extend init path */ } return returnCode; } /* * ---------------------------------------------------------------------------- * * mzExtendInitPath -- * * Central routine for recursively building up initial path inside * SAMENODE. Adds specified point to an initial path, if resulting * path end is outside block, mzAddPoint() is called to add init path * to appropriate queue. * * Results: * TRUE normally, FALSE if a zero-length route was detected (start * node and destination node are already connected). * * Side effects: * Initial paths built up. * mzAddPoint() eventually called to add init paths to appropriate queue. * * ---------------------------------------------------------------------------- */ bool mzExtendInitPath(path, rL, point, cost, length, directions) RoutePath *path; /* Initial Path, being extended */ RouteLayer *rL; /* routelayer of new point */ Point point; /* new point for initPath */ dlong cost; /* cost of new segment */ int length; /* length of path (excluding new segment) */ int directions; /* directions to extend init path in */ { Tile *tp; bool returnCode = TRUE; int orient; int extendCode = 0; /* Get tile in rL blockage plane under new point */ tp = TiSrPointNoHint(rL->rl_routeType.rt_hBlock, &point); /* If new point blocked by a different node, just return */ if (TiGetType(tp) == TT_BLOCKED) return returnCode; /* Consider initial contacts */ if (path == NULL) returnCode = mzAddInitialContacts(rL, point); /* If no SAMENODE block, call mzAddPoint() to and initial path to * appropriate queue. */ switch (TiGetType(tp)) { /* Use standard extend code on TT_SAMENODE areas. */ /* (Tim, 10/4/06) */ case TT_SAMENODE: case TT_SPACE: extendCode = EC_ALL_DIRECTIONS | EC_UDCONTACTS | EC_LRCONTACTS; break; case TT_LEFT_WALK: extendCode = EC_WALKRIGHT; break; case TT_RIGHT_WALK: extendCode = EC_WALKLEFT; break; case TT_TOP_WALK: extendCode = EC_WALKDOWN; break; case TT_BOTTOM_WALK: extendCode = EC_WALKUP; break; case TT_ABOVE_LR_WALK: case TT_BELOW_LR_WALK: extendCode = EC_WALKLRCONTACT; break; case TT_ABOVE_UD_WALK: case TT_BELOW_UD_WALK: extendCode = EC_WALKUDCONTACT; break; case TT_DEST_AREA: TxError("Zero length route!\n"); extendCode = EC_COMPLETE; returnCode = FALSE; break; } if (extendCode == 0) return FALSE; /* This shouldn't happen */ /* determine orientation of new segment */ if (path == NULL) orient = 'O'; else if (path->rp_rLayer != rL) { if (path->rp_entry.p_x == point.p_x) orient = 'X'; else orient = 'O'; } else if (path->rp_entry.p_x == point.p_x) orient = 'V'; else { ASSERT(path->rp_entry.p_y==point.p_y,"mzExtendInitPath"); orient = 'H'; } /* Add initial path to appropriate queue */ mzAddPoint(path, &point, rL, orient, extendCode, &cost); return returnCode; } /* * ---------------------------------------------------------------------------- * * mzAddInitialContacts -- * * * Results: * TRUE normally, FALSE if zero-length route * * Side effects: * Calls mzExtendInitPath to add contact to initial path. * * ---------------------------------------------------------------------------- */ bool mzAddInitialContacts(rL, point) RouteLayer *rL; /* routelayer of initial point */ Point point; /* initial point */ { List *cL; Tile *tp; RouteContact *rC; RouteLayer *newRLayer; dlong conCost; RoutePath *initPath; bool returnCode = TRUE; /* Loop through contacts that connect to current rLayer */ for (cL=rL->rl_contactL; cL!=NULL; cL=LIST_TAIL(cL)) { rC = (RouteContact *) LIST_FIRST(cL); /* Don't use inactive contacts */ if (!(rC->rc_routeType.rt_active)) continue; /* Get "other" route Layer contact connects to */ if (rC->rc_rLayer1 == rL) { newRLayer = rC->rc_rLayer2; } else { ASSERT(rC->rc_rLayer2 == rL,"mzStart"); newRLayer = rC->rc_rLayer1; } /* Don't spread to inactive layers */ if (!(newRLayer->rl_routeType.rt_active)) continue; /* Don't place contact if blocked */ tp = TiSrPointNoHint(rC->rc_routeType.rt_hBlock, &point); if (TiGetType(tp) == TT_SAMENODE) { /* Check if the size of the tile meets min length requirement */ if (RIGHT(tp) - point.p_x <= rC->rc_routeType.rt_length - rC->rc_routeType.rt_width) { /* compute cost of contact */ conCost = (dlong) rC->rc_cost; /* build path consisting of initial point */ initPath = NEWPATH(); initPath->rp_rLayer = rL; initPath->rp_entry = point; initPath->rp_orient = 'O'; initPath->rp_cost = 0; initPath->rp_back = NULL; /* Extend thru new point */ returnCode = mzExtendInitPath(initPath, newRLayer, point, conCost, 0, EC_ALL_DIRECTIONS); } } /* Check vertical planes for contact points, too */ tp = TiSrPointNoHint(rC->rc_routeType.rt_vBlock, &point); if (TiGetType(tp) != TT_SAMENODE) continue; /* Check if the size of the tile meets min length requirement */ if (TOP(tp) - point.p_y <= rC->rc_routeType.rt_length - rC->rc_routeType.rt_width) continue; /* compute cost of contact */ conCost = (dlong) rC->rc_cost; /* build path consisting of initial point */ initPath = NEWPATH(); initPath->rp_rLayer = rL; initPath->rp_entry = point; initPath->rp_orient = 'X'; initPath->rp_cost = 0; initPath->rp_back = NULL; /* Extend thru new point */ returnCode = mzExtendInitPath(initPath, newRLayer, point, conCost, 0, EC_ALL_DIRECTIONS); } return returnCode; }