2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* mzSearch.c --
|
|
|
|
|
*
|
|
|
|
|
* Search strategy for maze router.
|
2020-05-23 23:13:14 +02:00
|
|
|
* Low level of Maze router (finding next interesting point) is done in
|
|
|
|
|
* mzSearchRight.c etc.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
2017-04-25 14:41:48 +02:00
|
|
|
* * Copyright (C) 1988, 1990 Michael H. Arnold and the Regents of the *
|
|
|
|
|
* * University of California. *
|
2020-05-23 23:13:14 +02:00
|
|
|
* * 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
|
|
|
* *********************************************************************
|
|
|
|
|
*
|
|
|
|
|
* SEARCH STRATEGY:
|
|
|
|
|
*
|
|
|
|
|
* Partial paths are expanded one interesting point at a time - that is a
|
|
|
|
|
* path is expanded to the next interesting point left, right, up and down
|
|
|
|
|
* and vias to neighboring layers are considered, then a new (though possibly
|
2020-05-23 23:13:14 +02:00
|
|
|
* one of the extensions just created) path is selected for expansion.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* The "search strategy" employed determines which partial-path is
|
|
|
|
|
* chosen for exansion at each stage.
|
|
|
|
|
*
|
|
|
|
|
* A windowed search strategy is used. At any given time the window
|
|
|
|
|
* bounds define a minimum and maximum distance to the goal. Partial paths
|
|
|
|
|
* are divided into three groups: those farther from the goal than the
|
|
|
|
|
* window, those within the window, and those nearer to the goal than the
|
|
|
|
|
* window. The window begins at the start point and is slowly shifted
|
2020-05-23 23:13:14 +02:00
|
|
|
* toward the goal over time. Normally the partial-path of least
|
2017-04-25 14:41:48 +02:00
|
|
|
* estimated-total-cost WITHIN
|
|
|
|
|
* the window is chosen for expansion, although a further path (i.e. one
|
|
|
|
|
* beyond the window) that has exceptionally low estimated-total-cost is
|
|
|
|
|
* sometimes chosen instead. When the trailing edge of the window reaches
|
|
|
|
|
* the goal, the search is deemed complete and the lowest cost complete
|
|
|
|
|
* path found is returned. However if no complete-path has been found
|
|
|
|
|
* searching will continue until the first complete path is found.
|
|
|
|
|
* The idea behind the windowed search is to
|
|
|
|
|
* expand the paths that promise to give the best (lowest cost) solution, but
|
|
|
|
|
* to slowly shift attention toward the goal to avoid the VERY long time
|
|
|
|
|
* it would take to examine all possible paths.
|
|
|
|
|
*
|
|
|
|
|
* In the case of many partial paths within the window, the above search may
|
|
|
|
|
* be too scattered; "blooming" is used to give a local-focus to the search
|
|
|
|
|
* by examining a number of expansions
|
|
|
|
|
* from a given partial path before going on to consider other paths. Blooming
|
|
|
|
|
* is equivalent to searching the move tree in chess before applyng static
|
|
|
|
|
* evaluations of "final" positions. In practice it makes the router behave
|
|
|
|
|
* much better.
|
|
|
|
|
*
|
|
|
|
|
* The search strategy is implemented with three heaps and four stacks:
|
2020-05-23 23:13:14 +02:00
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* mzMaxToGoHeap - keeps partial paths NEARER the goal than the window.
|
|
|
|
|
* these paths are not yet eligible for expansion.
|
|
|
|
|
* Whenever the window is moved, the top elements of
|
|
|
|
|
* this heap (i.e. those furthest from the goal) are
|
|
|
|
|
* moved onto the mzMinCostHeap (i.e. into the window).
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* mzMinCostHeap - keeps partial paths inside the window. the top of this
|
2017-04-25 14:41:48 +02:00
|
|
|
* heap, i.e. the least cost path inside
|
|
|
|
|
* the window, is compared with the least (penalized) cost of
|
|
|
|
|
* the paths beyond the window, and the lesser of these
|
|
|
|
|
* two is chosen for expansion.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* mzMinAdjCostHeap - keeps partial paths that are further from the goal
|
|
|
|
|
* than the
|
2017-04-25 14:41:48 +02:00
|
|
|
* window. These paths are sorted by adjusted cost.
|
|
|
|
|
* Adjusted cost is estimated-total-cost plus a penalty
|
|
|
|
|
* proportial to the distance of the path from the window.
|
|
|
|
|
* The ordering of the paths is independent of the current
|
|
|
|
|
* window position - so a "reference position" is used to
|
2020-05-23 23:13:14 +02:00
|
|
|
* avoid recomputing adjusted costs for these paths
|
2017-04-25 14:41:48 +02:00
|
|
|
* everytime the window moves. The adjusted cost of the
|
|
|
|
|
* top (least cost) element is normalized to the current
|
|
|
|
|
* window position before comparison with the least cost
|
|
|
|
|
* path on the mzMinCostHeap. The idea behind the
|
|
|
|
|
* mzMinAdjCostHeap is
|
|
|
|
|
* to discourage searching of paths beyond the window, but
|
2020-05-23 23:13:14 +02:00
|
|
|
* to do so in a gentle and flexible way, so that
|
2017-04-25 14:41:48 +02:00
|
|
|
* behaviour will degrade gracefully under unusual
|
|
|
|
|
* circumstances rather than fail catastrophically.
|
|
|
|
|
* For example, if the window moves too fast and all the
|
|
|
|
|
* reasonable paths are left behind, the search will
|
2020-05-23 23:13:14 +02:00
|
|
|
* degenerate to a simple cost-based search biased towards
|
2017-04-25 14:41:48 +02:00
|
|
|
* paths nearer to completion - a startegy that is
|
|
|
|
|
* adequate in many situations.
|
|
|
|
|
*
|
|
|
|
|
* mzBloomStack - paths in current local focus = all expansions of a given
|
|
|
|
|
* partial-path that do not exceed a given estimated-cost
|
|
|
|
|
* (also see stacks below)
|
|
|
|
|
*
|
|
|
|
|
* mzStraightStack - focus paths being extended in straight line.
|
|
|
|
|
*
|
|
|
|
|
* mzDownHillStack - focus paths followed only until cost increases.
|
|
|
|
|
*
|
|
|
|
|
* mzWalkStack - paths inside walk (i.e. inside blocked area adjacent to
|
|
|
|
|
* destination.
|
|
|
|
|
*
|
|
|
|
|
* If the walk stack is not empty the next path is taken from there (thus
|
|
|
|
|
* paths that have reached the threshold of a dest area are given priority.)
|
|
|
|
|
*
|
|
|
|
|
* Next priority is given to the down hill stack, thus a focus path is always
|
|
|
|
|
* expanded until the estimated cost increases.
|
|
|
|
|
*
|
|
|
|
|
* Next the straight stack is processed. The purpose of this stack is to
|
2020-05-23 23:13:14 +02:00
|
|
|
* consider straight extensions in all directions to some given minimum
|
2017-04-25 14:41:48 +02:00
|
|
|
* distance.
|
|
|
|
|
*
|
|
|
|
|
* Next the bloom stack itself is processed. All extensions derived from
|
|
|
|
|
* the bloom stack are placed on one of the stacks until a fixed cost increment
|
|
|
|
|
* is exceeded (in practice a small increment is used, thus the local focus
|
|
|
|
|
* is only extended in straight lines, and then downhill).
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* If all the stacks are empty, a new focus is pickd from the heaps and
|
2017-04-25 14:41:48 +02:00
|
|
|
* the bloom stack is initialized with it.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/mzrouter/mzSearch.c,v 1.2 2010/06/24 12:37:19 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "utils/geofast.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "utils/heap.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/list.h"
|
|
|
|
|
#include "debug/debug.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "mzrouter/mzrouter.h"
|
|
|
|
|
#include "mzrouter/mzInternal.h"
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
|
|
|
|
|
extern void mzExtendViaLRContacts();
|
|
|
|
|
extern void mzExtendViaUDContacts();
|
|
|
|
|
extern void mzBloomInit();
|
|
|
|
|
extern void mzMakeStatReport();
|
|
|
|
|
extern void mzExtendPath(RoutePath *);
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* mzSearch --
|
|
|
|
|
*
|
|
|
|
|
* Find a path between one of the starting terminals and the
|
|
|
|
|
* destination. The path must lie within the
|
|
|
|
|
* area mzBoundingRect.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a pointer to best complete RoutePath found (NULL
|
|
|
|
|
* if none found). This RoutePath may be passed to
|
|
|
|
|
* MZPaintPath() to be converted into paint.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Allocates RoutePaths from our own private storage area.
|
|
|
|
|
* The caller must copy these to permanent storage with
|
|
|
|
|
* mzCopyPath() prior to calling MZClean; otherwise,
|
|
|
|
|
* the returned RoutePath will be lost.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
RoutePath *
|
|
|
|
|
mzSearch(mzResult)
|
|
|
|
|
int *mzResult;
|
|
|
|
|
{
|
|
|
|
|
RoutePath *path; /* solution */
|
|
|
|
|
bool morePartialPaths = TRUE;
|
|
|
|
|
bool bloomLimitHit = FALSE;
|
|
|
|
|
bool windowSweepDoneAndCompletePathFound = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Report intial cost estimate */
|
|
|
|
|
if(mzVerbosity>=VERB_STATS)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Initial Cost Estimate: %.0f\n",
|
|
|
|
|
(double)(mzInitialEstimate));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("\nBEGINNING SEARCH.\n");
|
|
|
|
|
TxPrintf("\tmzWRate = %.0f\n", (double)(mzWRate));
|
|
|
|
|
TxPrintf("\tmzWInitialMinToGo = %.0f\n", (double)(mzWInitialMinToGo));
|
|
|
|
|
TxPrintf("\tmzWInitialMaxToGo = %.0f\n", (double)(mzWInitialMaxToGo));
|
|
|
|
|
TxPrintf("\tmzBloomDeltaCost = %.0f\n", (double)(mzBloomDeltaCost));
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
while (morePartialPaths &&
|
2017-04-25 14:41:48 +02:00
|
|
|
!windowSweepDoneAndCompletePathFound &&
|
|
|
|
|
!bloomLimitHit &&
|
|
|
|
|
!SigInterruptPending)
|
|
|
|
|
/* Find next path to extend from */
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("\nABOUT TO SELECT NEXT PATH TO EXTEND.\n");
|
|
|
|
|
TxMore("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* pop a stack */
|
|
|
|
|
path = NULL;
|
|
|
|
|
if(mzWalkStack != NULL)
|
|
|
|
|
{
|
|
|
|
|
mzPathSource = SOURCE_WALK;
|
|
|
|
|
path = (RoutePath *) ListPop(&mzWalkStack);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("POPPING TOP OF WALK STACK for extension.\n");
|
|
|
|
|
mzPrintPathHead(path);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
else if(mzDownHillStack != NULL)
|
|
|
|
|
{
|
|
|
|
|
mzPathSource = SOURCE_DOWNHILL;
|
|
|
|
|
path = (RoutePath *) ListPop(&mzDownHillStack);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("POPPING TOP OF DOWNHILL STACK for extension.\n");
|
|
|
|
|
mzPrintPathHead(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(mzStraightStack != NULL)
|
|
|
|
|
{
|
|
|
|
|
mzPathSource = SOURCE_STRAIGHT;
|
|
|
|
|
path = (RoutePath *) ListPop(&mzStraightStack);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("POPPING TOP OF STRAIGHT STACK for extension.\n");
|
|
|
|
|
mzPrintPathHead(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(mzBloomStack != NULL)
|
|
|
|
|
{
|
|
|
|
|
mzPathSource = SOURCE_BLOOM;
|
|
|
|
|
path = (RoutePath *) ListPop(&mzBloomStack);
|
|
|
|
|
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("POPPING TOP OF BLOOM STACK for extension.\n");
|
|
|
|
|
mzPrintPathHead(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Stacks contained a path, go about the buisness of extending it */
|
|
|
|
|
if(path)
|
|
|
|
|
{
|
|
|
|
|
/* Check hashtable to see if path already obsolete,
|
2020-05-23 23:13:14 +02:00
|
|
|
* (i.e. cheaper path to its enpt found.)
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
HashEntry *he;
|
|
|
|
|
PointKey pk;
|
|
|
|
|
RoutePath *hashedPath;
|
|
|
|
|
|
|
|
|
|
pk.pk_point = path->rp_entry;
|
|
|
|
|
pk.pk_rLayer = path->rp_rLayer;
|
|
|
|
|
pk.pk_orient = path->rp_orient;
|
|
|
|
|
#if SIZEOF_VOID_P == 8
|
|
|
|
|
pk.pk_buffer = 0; /* Otherwise the hash function screws up */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
he = HashFind(&mzPointHash, (char *) &pk);
|
|
|
|
|
hashedPath = (RoutePath *) HashGetValue(he);
|
|
|
|
|
ASSERT(hashedPath!=NULL,"mzFindPath");
|
|
|
|
|
|
|
|
|
|
if (path!=hashedPath)
|
|
|
|
|
{
|
|
|
|
|
/* DEBUG - report path rejected due to hash value. */
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("HASH LOOKUP reveals better path, REJECT path.\n");
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
|
|
|
|
/* better path to this pt already exists,
|
2017-04-25 14:41:48 +02:00
|
|
|
* skip to next path
|
|
|
|
|
*/
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure blockage planes have been generated around the path
|
|
|
|
|
* end.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
Point *point = &(path->rp_entry);
|
|
|
|
|
Tile *tp = TiSrPointNoHint(mzHBoundsPlane, point);
|
|
|
|
|
|
|
|
|
|
if (TiGetType(tp)==TT_SPACE ||
|
|
|
|
|
point->p_x == LEFT(tp) || point->p_x == RIGHT(tp))
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Path ends on vertical boundary of blockage");
|
|
|
|
|
TxPrintf(" planes, BLOCKAGE PLANES BEING EXTENDED.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mzExtendBlockBounds(point);
|
|
|
|
|
if(SigInterruptPending) continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
tp = TiSrPointNoHint(mzVBoundsPlane, point);
|
|
|
|
|
if (point->p_y == BOTTOM(tp) || point->p_y == TOP(tp))
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Path ends on horizontal boundary");
|
|
|
|
|
TxPrintf("of blockage planes, BLOCKAGE PLANES");
|
|
|
|
|
TxPrintf("BEING EXTENDED.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mzExtendBlockBounds(point);
|
|
|
|
|
if(SigInterruptPending) continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* DEBUG - if single-stepping, print data, show path end visually,
|
|
|
|
|
* and pause.
|
|
|
|
|
*/
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebStep))
|
|
|
|
|
{
|
|
|
|
|
Rect box;
|
|
|
|
|
CellDef *boxDef;
|
|
|
|
|
|
|
|
|
|
/* print stats on this path */
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
RoutePath *p;
|
|
|
|
|
|
|
|
|
|
/* path # */
|
|
|
|
|
TxPrintf("READY TO EXTEND PATH ");
|
2020-05-23 23:13:14 +02:00
|
|
|
TxPrintf("(blooms: %d, points-processed: %d):\n",
|
2017-04-25 14:41:48 +02:00
|
|
|
mzNumBlooms,
|
|
|
|
|
mzNumPaths);
|
|
|
|
|
mzPrintPathHead(path);
|
|
|
|
|
|
|
|
|
|
/* # of segments in path segments */
|
|
|
|
|
i=0;
|
|
|
|
|
for(p=path; p->rp_back!=0; p=p->rp_back)
|
|
|
|
|
i++;
|
|
|
|
|
TxPrintf(" (%d segments in path)\n", i);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* move box to path end-point */
|
|
|
|
|
if(ToolGetBox(&boxDef,&box))
|
|
|
|
|
{
|
|
|
|
|
int deltaX = box.r_xtop - box.r_xbot;
|
|
|
|
|
int deltaY = box.r_ytop - box.r_ybot;
|
|
|
|
|
box.r_ll = path->rp_entry;
|
|
|
|
|
box.r_ur.p_x = path->rp_entry.p_x + deltaX;
|
|
|
|
|
box.r_ur.p_y = path->rp_entry.p_y + deltaY;
|
|
|
|
|
DBWSetBox(mzRouteUse->cu_def, &box);
|
|
|
|
|
WindUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* wait for user to continue */
|
|
|
|
|
TxMore("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Extend Path */
|
|
|
|
|
mzExtendPath(path);
|
|
|
|
|
|
|
|
|
|
/* update statistics */
|
|
|
|
|
mzNumPaths++; /* increment number of paths processed */
|
|
|
|
|
if(--mzPathsTilReport == 0)
|
|
|
|
|
{
|
|
|
|
|
mzPathsTilReport = mzReportInterval;
|
|
|
|
|
mzMakeStatReport();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* stacks are empty, choose path from heaps to initial them with */
|
|
|
|
|
{
|
|
|
|
|
HeapEntry maxToGoTopBuf, minCostTopBuf, buf;
|
|
|
|
|
HeapEntry *maxToGoTop, *minCostTop, *minAdjCostTop;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("BLOOM STACK EMPTY. ");
|
|
|
|
|
TxPrintf("Choosing path from heaps to initial it with.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the bloom limit has been exceeded, stop searching */
|
2020-05-23 23:13:14 +02:00
|
|
|
if(mzBloomLimit >0 &&
|
2017-04-25 14:41:48 +02:00
|
|
|
mzNumBlooms > mzBloomLimit)
|
|
|
|
|
{
|
|
|
|
|
if(mzVerbosity>=VERB_BRIEF)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Bloom limit (%d) hit.\n", mzBloomLimit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bloomLimitHit = TRUE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set window thresholds */
|
|
|
|
|
{
|
|
|
|
|
dlong offset;
|
|
|
|
|
|
|
|
|
|
offset = (dlong) (mzWRate * mzNumBlooms);
|
|
|
|
|
|
|
|
|
|
if(offset <= mzWInitialMinToGo)
|
|
|
|
|
{
|
|
|
|
|
mzWindowMinToGo = mzWInitialMinToGo - offset;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mzWindowMinToGo = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(offset <= mzWInitialMaxToGo)
|
|
|
|
|
{
|
|
|
|
|
mzWindowMaxToGo = mzWInitialMaxToGo - offset;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mzWindowMaxToGo = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("New window thresholds: ");
|
|
|
|
|
TxPrintf("windowMinToGo = %.0f, ",
|
|
|
|
|
(double)mzWindowMinToGo);
|
|
|
|
|
TxPrintf("windowMaxToGo = %.0f\n ",
|
|
|
|
|
(double)mzWindowMaxToGo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If window sweep is complete, and a complete path
|
|
|
|
|
* has been found, stop searching.
|
|
|
|
|
*/
|
|
|
|
|
if((mzWindowMaxToGo == 0) &&
|
|
|
|
|
HeapLookAtTop(&mzMinCostCompleteHeap))
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("WINDOW SWEEP DONE AND COMPLETE PATH EXISTS.");
|
|
|
|
|
TxPrintf(" Stop searching.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
windowSweepDoneAndCompletePathFound = TRUE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
/* Move points that meet the minTogo threshold to window
|
2017-04-25 14:41:48 +02:00
|
|
|
* (Points are moved from the MaxToGo heap to the minCost heap)
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
2020-05-23 23:13:14 +02:00
|
|
|
TxPrintf("Moving paths into window ");
|
2017-04-25 14:41:48 +02:00
|
|
|
TxPrintf("(maxTogoHeap -> minCostHeap): \n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while((maxToGoTop=HeapRemoveTop(&mzMaxToGoHeap,
|
2020-05-23 23:13:14 +02:00
|
|
|
&maxToGoTopBuf)) != NULL &&
|
2017-04-25 14:41:48 +02:00
|
|
|
(maxToGoTop->he_union.hu_dlong >= mzWindowMinToGo))
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
mzPrintPathHead((RoutePath*)(maxToGoTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
HeapAddDLong(&mzMinCostHeap,
|
|
|
|
|
((RoutePath *)(maxToGoTop->he_id))->rp_cost,
|
2017-04-25 14:41:48 +02:00
|
|
|
(char *) (maxToGoTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
if(maxToGoTop!=NULL)
|
|
|
|
|
{
|
|
|
|
|
HeapAddDLong(&mzMaxToGoHeap,
|
2020-05-23 23:13:14 +02:00
|
|
|
maxToGoTop->he_union.hu_dlong,
|
2017-04-25 14:41:48 +02:00
|
|
|
(char *) (maxToGoTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear top of minCostHeap of points that no longer meet the
|
|
|
|
|
* mzWindowMaxToGo threshold.
|
|
|
|
|
* (minCostHeap -> minAdjCostHeap)
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Moving paths out of window ");
|
|
|
|
|
TxPrintf("(minCostHeap -> minAdjCostHeap): \n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while((minCostTop=HeapRemoveTop(&mzMinCostHeap,
|
|
|
|
|
&minCostTopBuf))!=NULL &&
|
|
|
|
|
(((RoutePath *)(minCostTop->he_id))->rp_togo >
|
|
|
|
|
mzWindowMaxToGo))
|
|
|
|
|
{
|
|
|
|
|
dlong adjCost;
|
|
|
|
|
|
|
|
|
|
/* compute adjusted cost */
|
|
|
|
|
adjCost = (dlong)((RoutePath *)(minCostTop->he_id))->rp_togo;
|
|
|
|
|
adjCost = (dlong)(adjCost * mzPenalty.rf_mantissa);
|
|
|
|
|
adjCost = adjCost >> mzPenalty.rf_nExponent;
|
|
|
|
|
adjCost += minCostTop->he_union.hu_dlong;
|
|
|
|
|
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
mzPrintPathHead((RoutePath*)(minCostTop->he_id));
|
|
|
|
|
TxPrintf(" Heap-key adjCost = %.0f\n", (double)adjCost);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add to adjusted cost heap */
|
|
|
|
|
HeapAddDLong(&mzMinAdjCostHeap, adjCost,
|
|
|
|
|
(char *) (minCostTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(minCostTop!=NULL)
|
|
|
|
|
{
|
|
|
|
|
HeapAddDLong(&mzMinCostHeap,
|
2020-05-23 23:13:14 +02:00
|
|
|
minCostTop->he_union.hu_dlong,
|
2017-04-25 14:41:48 +02:00
|
|
|
(char *) (minCostTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
/* Peek at tops of heaps
|
2017-04-25 14:41:48 +02:00
|
|
|
* (equal cost elements might have got shuffled above when
|
|
|
|
|
* we placed the last poped element back on the heap.)
|
|
|
|
|
*/
|
|
|
|
|
minAdjCostTop = HeapLookAtTop(&mzMinAdjCostHeap);
|
|
|
|
|
maxToGoTop = HeapLookAtTop(&mzMaxToGoHeap);
|
|
|
|
|
minCostTop = HeapLookAtTop(&mzMinCostHeap);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Print tops of maxToGo, minCost and minAdjCost heaps */
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Max togo top:\n");
|
|
|
|
|
if(maxToGoTop)
|
|
|
|
|
{
|
|
|
|
|
mzPrintPathHead((RoutePath*)(maxToGoTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TxPrintf(" nil\n");
|
|
|
|
|
}
|
|
|
|
|
TxPrintf("Min cost top:\n");
|
|
|
|
|
if(minCostTop)
|
|
|
|
|
{
|
|
|
|
|
mzPrintPathHead((RoutePath*)(minCostTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TxPrintf(" nil\n");
|
|
|
|
|
}
|
|
|
|
|
TxPrintf("Min adjcost top:\n");
|
|
|
|
|
if(minAdjCostTop)
|
|
|
|
|
{
|
2020-05-23 23:13:14 +02:00
|
|
|
TxPrintf(" Heap-key adjCost: %.0f\n",
|
2017-04-25 14:41:48 +02:00
|
|
|
(double)(minAdjCostTop->he_union.hu_dlong));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TxPrintf(" nil\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(minCostTop && minAdjCostTop)
|
|
|
|
|
/* need to compare minCostTop and minAdjCostTop */
|
|
|
|
|
{
|
|
|
|
|
/* compute adjusted cost corresponding to current window
|
|
|
|
|
* position (we only penalize for amount toGo exceeding
|
|
|
|
|
* mzWindowMaxToGo)
|
|
|
|
|
*/
|
|
|
|
|
dlong cost, adjCost;
|
|
|
|
|
|
|
|
|
|
cost =(dlong)((RoutePath *)(minAdjCostTop->he_id))->rp_cost;
|
|
|
|
|
adjCost = (dlong)((RoutePath *)(minAdjCostTop->he_id))->rp_togo;
|
|
|
|
|
ASSERT(adjCost >= mzWindowMaxToGo,"mzSearch");
|
|
|
|
|
adjCost -= mzWindowMaxToGo;
|
|
|
|
|
adjCost *= mzPenalty.rf_mantissa;
|
|
|
|
|
adjCost = adjCost >> mzPenalty.rf_nExponent;
|
|
|
|
|
adjCost += cost;
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
TxPrintf("WINDOW-CORRECTED ADJCOST: %.0f\n",
|
|
|
|
|
(double)(adjCost));
|
|
|
|
|
}
|
|
|
|
|
if(minCostTop->he_union.hu_dlong <= adjCost)
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("INITIALIZING BLOOM STACK ");
|
|
|
|
|
TxPrintf("WITH TOP OF MIN COST HEAP.\n");
|
|
|
|
|
}
|
|
|
|
|
minCostTop = HeapRemoveTop(&mzMinCostHeap, &buf);
|
|
|
|
|
mzBloomInit((RoutePath *) (minCostTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("INITIALIZING BLOOM STACK ");
|
|
|
|
|
TxPrintf("WITH TOP OF MIN ADJCOST HEAP.\n");
|
|
|
|
|
}
|
|
|
|
|
minAdjCostTop = HeapRemoveTop(&mzMinAdjCostHeap, &buf);
|
|
|
|
|
mzBloomInit((RoutePath *) (minAdjCostTop->he_id));
|
|
|
|
|
mzNumOutsideBlooms++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(minCostTop)
|
|
|
|
|
/* minAdjCostHeap empty, so bloom from minCostTop */
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("INITIALIZING BLOOM STACK ");
|
|
|
|
|
TxPrintf("WITH TOP OF MIN COST HEAP.\n");
|
|
|
|
|
}
|
|
|
|
|
minCostTop = HeapRemoveTop(&mzMinCostHeap, &buf);
|
|
|
|
|
mzBloomInit((RoutePath *) (minCostTop->he_id));
|
|
|
|
|
}
|
|
|
|
|
else if(minAdjCostTop)
|
|
|
|
|
/* minCost Heap empty, so bloom from minAdjCostTop */
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("INITIALIZING BLOOM STACK ");
|
|
|
|
|
TxPrintf("WITH TOP OF MIN ADJCOST HEAP.\n");
|
|
|
|
|
}
|
|
|
|
|
minAdjCostTop = HeapRemoveTop(&mzMinAdjCostHeap, &buf);
|
|
|
|
|
mzBloomInit((RoutePath *) (minAdjCostTop->he_id));
|
|
|
|
|
mzNumOutsideBlooms++;
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-05-23 23:13:14 +02:00
|
|
|
/* minCost and minAdjCost heaps empty,
|
2017-04-25 14:41:48 +02:00
|
|
|
* bloom from top of TOGO heap */
|
|
|
|
|
{
|
|
|
|
|
if(maxToGoTop)
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("INITIALIZING BLOOM STACK ");
|
|
|
|
|
TxPrintf("WITH TOP OF MAX TOGO HEAP.\n");
|
|
|
|
|
}
|
|
|
|
|
maxToGoTop = HeapRemoveTop(&mzMaxToGoHeap, &buf);
|
|
|
|
|
mzBloomInit((RoutePath *) (maxToGoTop->he_id));
|
|
|
|
|
mzNumOutsideBlooms++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* No paths left to extend from */
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("NO PATHS LEFT TO EXTEND FROM.\n");
|
|
|
|
|
}
|
|
|
|
|
morePartialPaths = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Give final stat report. */
|
|
|
|
|
mzMakeStatReport();
|
|
|
|
|
|
|
|
|
|
/* Return best complete path */
|
|
|
|
|
{
|
|
|
|
|
HeapEntry heEntry;
|
|
|
|
|
|
|
|
|
|
if(HeapRemoveTop(&mzMinCostCompleteHeap,&heEntry))
|
|
|
|
|
{
|
|
|
|
|
if (mzResult)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
*mzResult = MZ_CURRENT_BEST;
|
|
|
|
|
else
|
|
|
|
|
*mzResult = MZ_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
return (RoutePath *)(heEntry.he_id);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (mzResult)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
*mzResult = MZ_INTERRUPTED;
|
|
|
|
|
else
|
|
|
|
|
*mzResult = MZ_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* mzExtendPath --
|
|
|
|
|
*
|
|
|
|
|
* Spread out to next interesting point in four directions, and to adjacent
|
|
|
|
|
* layers through contacts.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds new routepaths to the queues (ie. heaps and bloomstack).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mzExtendPath(path)
|
|
|
|
|
RoutePath *path;
|
|
|
|
|
{
|
|
|
|
|
int extendCode = path->rp_extendCode;
|
|
|
|
|
|
|
|
|
|
if (extendCode & EC_RIGHT)
|
|
|
|
|
{
|
|
|
|
|
mzExtendRight(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extendCode & EC_LEFT)
|
|
|
|
|
{
|
|
|
|
|
mzExtendLeft(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extendCode & EC_UP)
|
|
|
|
|
{
|
|
|
|
|
mzExtendUp(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extendCode & EC_DOWN)
|
|
|
|
|
{
|
|
|
|
|
mzExtendDown(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extendCode & EC_UDCONTACTS)
|
|
|
|
|
{
|
|
|
|
|
mzExtendViaUDContacts(path);
|
|
|
|
|
}
|
|
|
|
|
if (extendCode & EC_LRCONTACTS)
|
|
|
|
|
{
|
|
|
|
|
mzExtendViaLRContacts(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extendCode >= EC_WALKRIGHT)
|
|
|
|
|
{
|
|
|
|
|
if (extendCode & EC_WALKRIGHT)
|
|
|
|
|
{
|
|
|
|
|
mzWalkRight(path);
|
|
|
|
|
}
|
|
|
|
|
else if (extendCode & EC_WALKLEFT)
|
|
|
|
|
{
|
|
|
|
|
mzWalkLeft(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (extendCode & EC_WALKUP)
|
|
|
|
|
{
|
|
|
|
|
mzWalkUp(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (extendCode & EC_WALKDOWN)
|
|
|
|
|
{
|
|
|
|
|
mzWalkDown(path);
|
|
|
|
|
}
|
|
|
|
|
else if (extendCode & EC_WALKUDCONTACT)
|
|
|
|
|
{
|
|
|
|
|
mzWalkUDContact(path);
|
|
|
|
|
}
|
|
|
|
|
else if (extendCode & EC_WALKLRCONTACT)
|
|
|
|
|
{
|
|
|
|
|
mzWalkLRContact(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* mzExtendViaLRContacts --
|
|
|
|
|
*
|
|
|
|
|
* Spread from a point to other planes reachable from it,
|
|
|
|
|
* by using contacts. Stacked contacts are allowed. Search the horizontal
|
|
|
|
|
* block plane. Limit to areas that fit the contact minimum length.
|
|
|
|
|
*
|
|
|
|
|
* Results None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds RoutePaths to the heap (mzReservePathCostHeap).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
mzExtendViaLRContacts(path)
|
|
|
|
|
RoutePath *path;
|
|
|
|
|
{
|
|
|
|
|
Point p = path->rp_entry, *lastCpos = NULL;
|
2020-05-23 23:13:14 +02:00
|
|
|
RouteLayer *rLayer = path->rp_rLayer;
|
2017-04-25 14:41:48 +02:00
|
|
|
RouteContact *rC;
|
|
|
|
|
List *cL;
|
|
|
|
|
RouteLayer *newRLayer;
|
|
|
|
|
Tile *tp;
|
|
|
|
|
TileType type, lastCtype = TT_SPACE;
|
|
|
|
|
RoutePath *spath;
|
|
|
|
|
int bendDist = 0;
|
|
|
|
|
|
|
|
|
|
/* DEBUG - trace calls to this routine */
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
TxPrintf("EXTENDING WITH CONTACTS (HORIZONTAL)\n");
|
|
|
|
|
|
|
|
|
|
/* Check what the last contact was and remember its */
|
|
|
|
|
/* position. Do not allow two contacts of the same */
|
|
|
|
|
/* type within a DRC error distance of each other. */
|
|
|
|
|
|
|
|
|
|
for (spath = path; spath && spath->rp_back && (spath->rp_orient != 'O');
|
|
|
|
|
spath = spath->rp_back);
|
|
|
|
|
if (spath->rp_back)
|
|
|
|
|
{
|
|
|
|
|
lastCpos = &spath->rp_entry;
|
|
|
|
|
rC = MZGetContact(spath, spath->rp_back);
|
|
|
|
|
lastCtype = rC->rc_routeType.rt_tileType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check where the last route bend is. Don't allow a */
|
|
|
|
|
/* contact within a DRC error distance of a bend. */
|
|
|
|
|
|
|
|
|
|
if (path)
|
|
|
|
|
{
|
|
|
|
|
if (path->rp_orient == 'V')
|
|
|
|
|
{
|
|
|
|
|
for (spath = path->rp_back; spath && spath->rp_orient == 'V';
|
|
|
|
|
spath = spath->rp_back);
|
|
|
|
|
if (spath && spath->rp_orient == 'H')
|
|
|
|
|
bendDist = spath->rp_entry.p_y - p.p_y;
|
|
|
|
|
if (bendDist < 0)
|
|
|
|
|
bendDist += rLayer->rl_routeType.rt_width;
|
|
|
|
|
}
|
|
|
|
|
else if (path->rp_orient == 'H')
|
|
|
|
|
{
|
|
|
|
|
for (spath = path->rp_back; spath && spath->rp_orient == 'H';
|
|
|
|
|
spath = spath->rp_back);
|
|
|
|
|
if (spath && spath->rp_orient == 'V')
|
|
|
|
|
bendDist = spath->rp_entry.p_x - p.p_x;
|
|
|
|
|
if (bendDist < 0)
|
|
|
|
|
bendDist += rLayer->rl_routeType.rt_width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Loop through contacts that connect to current rLayer */
|
|
|
|
|
for (cL=rLayer->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 == rLayer)
|
|
|
|
|
{
|
|
|
|
|
newRLayer = rC->rc_rLayer2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ASSERT(rC->rc_rLayer2 == rLayer,
|
|
|
|
|
"mzExtendViaLRContacts");
|
|
|
|
|
newRLayer = rC->rc_rLayer1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't spread to inactive layers */
|
|
|
|
|
if (!(newRLayer->rl_routeType.rt_active)) continue;
|
|
|
|
|
|
|
|
|
|
/* Find tile on contact plane that contains point. */
|
|
|
|
|
|
|
|
|
|
tp = TiSrPointNoHint(rC->rc_routeType.rt_hBlock, &p);
|
|
|
|
|
type = TiGetType(tp);
|
|
|
|
|
|
|
|
|
|
/* 1. If blocked, don't place a contact */
|
|
|
|
|
if ((type != TT_SPACE) && (type != TT_SAMENODE))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* 2. If tile space is not long enough for the contact, don't place */
|
|
|
|
|
if (RIGHT(tp) - p.p_x <= rC->rc_routeType.rt_length
|
|
|
|
|
- rC->rc_routeType.rt_width)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* 3. Check distance from last contact, if the same type */
|
|
|
|
|
if (rC->rc_routeType.rt_tileType == lastCtype)
|
|
|
|
|
{
|
|
|
|
|
int cdist = rC->rc_routeType.rt_spacing[lastCtype] +
|
|
|
|
|
rC->rc_routeType.rt_width;
|
|
|
|
|
if ((abs(p.p_x - lastCpos->p_x) < cdist) &&
|
|
|
|
|
(abs(p.p_y - lastCpos->p_y) < cdist))
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 4. Check distance to last route bend */
|
|
|
|
|
if (bendDist != 0)
|
|
|
|
|
{
|
|
|
|
|
int cwidth = rC->rc_routeType.rt_width;
|
|
|
|
|
int spacing = rC->rc_routeType.rt_spacing[rLayer->rl_routeType.rt_tileType];
|
|
|
|
|
if (bendDist > cwidth && bendDist < cwidth + spacing)
|
|
|
|
|
continue;
|
|
|
|
|
if (bendDist < 0 && bendDist > -spacing)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* OK to drop a contact here */
|
|
|
|
|
{
|
|
|
|
|
dlong conCost;
|
|
|
|
|
int extendCode;
|
|
|
|
|
|
|
|
|
|
/* set contact cost */
|
|
|
|
|
conCost = (dlong) rC->rc_cost;
|
|
|
|
|
|
|
|
|
|
/* determine appropriate extendcode */
|
|
|
|
|
tp = TiSrPointNoHint(newRLayer->rl_routeType.rt_hBlock, &p);
|
|
|
|
|
type = TiGetType(tp);
|
|
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case TT_SPACE:
|
|
|
|
|
case TT_SAMENODE:
|
|
|
|
|
extendCode = EC_RIGHT | EC_LEFT | EC_UP | EC_DOWN;
|
|
|
|
|
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:
|
|
|
|
|
/* TO DO: Check if stacked contacts are allowed! */
|
|
|
|
|
extendCode = EC_WALKLRCONTACT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TT_ABOVE_UD_WALK:
|
|
|
|
|
case TT_BELOW_UD_WALK:
|
|
|
|
|
/* TO DO: Check if stacked contacts are allowed! */
|
|
|
|
|
extendCode = EC_WALKUDCONTACT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TT_DEST_AREA:
|
|
|
|
|
|
|
|
|
|
extendCode = EC_COMPLETE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* this shouldn't happen */
|
|
|
|
|
ASSERT(FALSE,"mzExtendViaLRContacts");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finally add point after contact */
|
|
|
|
|
mzAddPoint(path, &p, newRLayer, 'O', extendCode, &conCost);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* mzExtendViaUDContacts --
|
|
|
|
|
*
|
|
|
|
|
* Spread from a point to other planes reachable from it,
|
|
|
|
|
* by using contacts. Stacked contacts are allowed. Search the vertical
|
|
|
|
|
* block plane. Limit to areas that fit the contact minimum length.
|
|
|
|
|
*
|
|
|
|
|
* Results None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds RoutePaths to the heap (mzReservePathCostHeap).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
mzExtendViaUDContacts(path)
|
|
|
|
|
RoutePath *path;
|
|
|
|
|
{
|
|
|
|
|
Point p = path->rp_entry, *lastCpos = NULL;
|
2020-05-23 23:13:14 +02:00
|
|
|
RouteLayer *rLayer = path->rp_rLayer;
|
2017-04-25 14:41:48 +02:00
|
|
|
RouteContact *rC;
|
|
|
|
|
List *cL;
|
|
|
|
|
RouteLayer *newRLayer;
|
|
|
|
|
Tile *tp;
|
|
|
|
|
TileType type, lastCtype = TT_SPACE;
|
|
|
|
|
RoutePath *spath;
|
|
|
|
|
int bendDist = 0;
|
|
|
|
|
|
|
|
|
|
/* DEBUG - trace calls to this routine */
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
TxPrintf("EXTENDING WITH CONTACTS (VERTICAL)\n");
|
|
|
|
|
|
|
|
|
|
/* Check what the last contact was and remember its */
|
|
|
|
|
/* position. Do not allow two contacts of the same */
|
|
|
|
|
/* type within a DRC error distance of each other. */
|
|
|
|
|
|
|
|
|
|
for (spath = path; spath && spath->rp_back && (spath->rp_orient != 'X');
|
|
|
|
|
spath = spath->rp_back);
|
|
|
|
|
if (spath->rp_back)
|
|
|
|
|
{
|
|
|
|
|
lastCpos = &spath->rp_entry;
|
|
|
|
|
rC = MZGetContact(spath, spath->rp_back);
|
|
|
|
|
lastCtype = rC->rc_routeType.rt_tileType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check where the last route bend is. Don't allow a */
|
|
|
|
|
/* contact within a DRC error distance of a bend. */
|
|
|
|
|
|
|
|
|
|
if (path)
|
|
|
|
|
{
|
|
|
|
|
if (path->rp_orient == 'V')
|
|
|
|
|
{
|
|
|
|
|
for (spath = path->rp_back; spath && spath->rp_orient == 'V';
|
|
|
|
|
spath = spath->rp_back);
|
|
|
|
|
if (spath && spath->rp_orient == 'H')
|
|
|
|
|
bendDist = spath->rp_entry.p_y - p.p_y;
|
|
|
|
|
if (bendDist < 0)
|
|
|
|
|
bendDist += rLayer->rl_routeType.rt_width;
|
|
|
|
|
}
|
|
|
|
|
else if (path->rp_orient == 'H')
|
|
|
|
|
{
|
|
|
|
|
for (spath = path->rp_back; spath && spath->rp_orient == 'H';
|
|
|
|
|
spath = spath->rp_back);
|
|
|
|
|
if (spath && spath->rp_orient == 'V')
|
|
|
|
|
bendDist = spath->rp_entry.p_x - p.p_x;
|
|
|
|
|
if (bendDist < 0)
|
|
|
|
|
bendDist += rLayer->rl_routeType.rt_width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Loop through contacts that connect to current rLayer */
|
|
|
|
|
for (cL=rLayer->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 == rLayer)
|
|
|
|
|
{
|
|
|
|
|
newRLayer = rC->rc_rLayer2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ASSERT(rC->rc_rLayer2 == rLayer,
|
|
|
|
|
"mzExtendViaUDContacts");
|
|
|
|
|
newRLayer = rC->rc_rLayer1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't spread to inactive layers */
|
|
|
|
|
if (!(newRLayer->rl_routeType.rt_active)) continue;
|
|
|
|
|
|
|
|
|
|
/* Find tile on contact plane that contains point. */
|
|
|
|
|
|
|
|
|
|
tp = TiSrPointNoHint(rC->rc_routeType.rt_vBlock, &p);
|
|
|
|
|
type = TiGetType(tp);
|
|
|
|
|
|
|
|
|
|
/* 1. If blocked, don't place a contact */
|
|
|
|
|
if ((type != TT_SPACE) && (type != TT_SAMENODE))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* 2. If tile space is not long enough for the contact, don't place */
|
|
|
|
|
if (TOP(tp) - p.p_y <= rC->rc_routeType.rt_length
|
|
|
|
|
- rC->rc_routeType.rt_width)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* 3. Check distance from last contact, if the same type */
|
|
|
|
|
if (rC->rc_routeType.rt_tileType == lastCtype)
|
|
|
|
|
{
|
|
|
|
|
int cdist = rC->rc_routeType.rt_spacing[lastCtype] +
|
|
|
|
|
rC->rc_routeType.rt_width;
|
|
|
|
|
if ((abs(p.p_x - lastCpos->p_x) < cdist) &&
|
|
|
|
|
(abs(p.p_y - lastCpos->p_y) < cdist))
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 4. Check distance to last route bend */
|
|
|
|
|
if (bendDist != 0)
|
|
|
|
|
{
|
|
|
|
|
int cwidth = rC->rc_routeType.rt_width;
|
|
|
|
|
int spacing = rC->rc_routeType.rt_spacing[rLayer->rl_routeType.rt_tileType];
|
|
|
|
|
if (bendDist > cwidth && bendDist < cwidth + spacing)
|
|
|
|
|
continue;
|
|
|
|
|
if (bendDist < 0 && bendDist > -spacing)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* OK to drop a contact here */
|
|
|
|
|
{
|
|
|
|
|
dlong conCost;
|
|
|
|
|
int extendCode;
|
|
|
|
|
|
|
|
|
|
/* set contact cost */
|
|
|
|
|
conCost = (dlong) rC->rc_cost;
|
|
|
|
|
|
|
|
|
|
/* determine appropriate extendcode */
|
|
|
|
|
tp = TiSrPointNoHint(newRLayer->rl_routeType.rt_vBlock, &p);
|
|
|
|
|
type = TiGetType(tp);
|
|
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case TT_SPACE:
|
|
|
|
|
case TT_SAMENODE:
|
|
|
|
|
extendCode = EC_RIGHT | EC_LEFT | EC_UP | EC_DOWN;
|
|
|
|
|
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:
|
|
|
|
|
/* TO DO: Check if stacked contacts are allowed! */
|
|
|
|
|
extendCode = EC_WALKLRCONTACT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TT_ABOVE_UD_WALK:
|
|
|
|
|
case TT_BELOW_UD_WALK:
|
|
|
|
|
/* TO DO: Check if stacked contacts are allowed! */
|
|
|
|
|
extendCode = EC_WALKUDCONTACT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TT_DEST_AREA:
|
|
|
|
|
|
|
|
|
|
extendCode = EC_COMPLETE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* this shouldn't happen */
|
|
|
|
|
ASSERT(FALSE,"mzExtendViaUDContacts");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finally add point after contact */
|
|
|
|
|
mzAddPoint(path, &p, newRLayer, 'X', extendCode, &conCost);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* mzAddPoint --
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* Process interesting point. If point within bounds and not redundant,
|
2017-04-25 14:41:48 +02:00
|
|
|
* link to previous path, update cost, and add to heap.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds a RoutePath to the heap.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
mzAddPoint(path, p, rLayer, orient, extendCode, costptr)
|
|
|
|
|
RoutePath *path; /* path that new point extends */
|
|
|
|
|
Point *p; /* new point */
|
|
|
|
|
RouteLayer *rLayer; /* Route Layer of new point */
|
2020-05-23 23:13:14 +02:00
|
|
|
int orient; /* 'H' = endpt of hor seg, 'V' = endpt of vert seg,
|
2017-04-25 14:41:48 +02:00
|
|
|
* 'O' = LR contact, 'X' = UD contact,
|
|
|
|
|
* 'B' = first point in path and blocked
|
|
|
|
|
*/
|
|
|
|
|
int extendCode; /* interesting directions to extend in */
|
|
|
|
|
dlong *costptr; /* Incremental cost of new path segment */
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
RoutePath *newPath;
|
|
|
|
|
RoutePath *hashedPath;
|
|
|
|
|
HashEntry *he;
|
|
|
|
|
PointKey pk;
|
|
|
|
|
dlong togo, cost;
|
|
|
|
|
|
|
|
|
|
/* DEBUG - print candidate frontier point */
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("mzAddPoint called: point=(%d,%d), layer=%s, orient='%c'\n",
|
|
|
|
|
p->p_x, p->p_y,
|
|
|
|
|
DBTypeLongNameTbl[rLayer->rl_routeType.rt_tileType],
|
|
|
|
|
orient);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cost = *costptr;
|
|
|
|
|
ASSERT(cost >= 0,"mzAddPoint");
|
|
|
|
|
|
|
|
|
|
/* Ignore if outside of bounding box */
|
|
|
|
|
if (!GEO_ENCLOSE(p, &mzBoundingRect))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* get estimated distance togo */
|
|
|
|
|
if(extendCode == EC_COMPLETE)
|
|
|
|
|
togo = 0;
|
|
|
|
|
else
|
|
|
|
|
togo = mzEstimatedCost(p);
|
|
|
|
|
|
|
|
|
|
/* compute (total) cost for new path */
|
|
|
|
|
{
|
|
|
|
|
/* initially cost = cost of new leg in path */
|
|
|
|
|
|
|
|
|
|
/* Add jogcost if appropriate */
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
if (path != NULL &&
|
2017-04-25 14:41:48 +02:00
|
|
|
path->rp_rLayer == rLayer &&
|
|
|
|
|
path->rp_orient != 'O' && path->rp_orient != 'X' &&
|
|
|
|
|
path->rp_orient != orient)
|
|
|
|
|
{
|
|
|
|
|
cost += rLayer->rl_jogCost;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
/* Add estimated total cost prior to new point,
|
2017-04-25 14:41:48 +02:00
|
|
|
* (or cost so far in the case of initial paths).
|
|
|
|
|
*/
|
|
|
|
|
if (path != NULL)
|
|
|
|
|
{
|
|
|
|
|
cost += path->rp_cost;
|
|
|
|
|
}
|
|
|
|
|
/* If not initial path, subtract out old estimated cost togo */
|
|
|
|
|
if (mzPathSource != SOURCE_INIT)
|
|
|
|
|
{
|
|
|
|
|
cost -= path->rp_togo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add new estimated cost to completion */
|
|
|
|
|
cost += togo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check hash table to see if cheaper path to this point already
|
|
|
|
|
* found - if so don't add this point.
|
|
|
|
|
*/
|
|
|
|
|
pk.pk_point = *p;
|
|
|
|
|
pk.pk_rLayer = rLayer;
|
|
|
|
|
pk.pk_orient = orient;
|
|
|
|
|
#if SIZEOF_VOID_P == 8
|
|
|
|
|
pk.pk_buffer = 0; /* Otherwise the hash function screws up */
|
2020-05-23 23:13:14 +02:00
|
|
|
#endif
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
he = HashFind(&mzPointHash, (char *) &pk);
|
|
|
|
|
hashedPath = (RoutePath *) HashGetValue(he);
|
|
|
|
|
|
|
|
|
|
if (hashedPath != NULL && (hashedPath->rp_cost <= cost))
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("new point NOT added, at least as good "
|
|
|
|
|
"path to pt already exists: ");
|
|
|
|
|
TxPrintf("new cost = %.0f, ",
|
|
|
|
|
(double)(cost));
|
|
|
|
|
TxPrintf("cheapest cost = %.0f\n",
|
|
|
|
|
(double)(hashedPath->rp_cost));
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If initial path, update min initial cost */
|
|
|
|
|
if(mzPathSource==SOURCE_INIT)
|
|
|
|
|
{
|
|
|
|
|
if(cost < mzMinInitialCost)
|
|
|
|
|
{
|
|
|
|
|
mzMinInitialCost = cost;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create new path element */
|
|
|
|
|
newPath = NEWPATH();
|
|
|
|
|
newPath->rp_rLayer = rLayer;
|
|
|
|
|
newPath->rp_entry = *p;
|
|
|
|
|
newPath->rp_orient = orient;
|
|
|
|
|
newPath->rp_cost = cost;
|
|
|
|
|
newPath->rp_extendCode = extendCode;
|
|
|
|
|
newPath->rp_togo = togo;
|
|
|
|
|
newPath->rp_back = path;
|
|
|
|
|
|
|
|
|
|
/* keep statistics */
|
|
|
|
|
mzNumPathsGened++;
|
|
|
|
|
|
|
|
|
|
/* Enter in hash table */
|
|
|
|
|
HashSetValue(he, (ClientData) newPath);
|
|
|
|
|
|
|
|
|
|
/* Add to appropriate queue or stack */
|
|
|
|
|
if(extendCode == EC_COMPLETE)
|
|
|
|
|
{
|
|
|
|
|
if (DebugIsSet(mzDebugID, mzDebMaze))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("PATH COMPLETE (WALKED IN). Add to complete heap.\n");
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
HeapAddDLong(&mzMinCostCompleteHeap, newPath->rp_cost,
|
2017-04-25 14:41:48 +02:00
|
|
|
(char *) newPath);
|
|
|
|
|
|
|
|
|
|
/* compute stats and make completed path report */
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
mzNumComplete++;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if(mzVerbosity>=VERB_STATS)
|
|
|
|
|
{
|
|
|
|
|
dlong cost, excessCost;
|
|
|
|
|
double excessPercent;
|
|
|
|
|
|
|
|
|
|
mzMakeStatReport();
|
|
|
|
|
|
|
|
|
|
TxPrintf("PATH #%d ", mzNumComplete);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
cost = newPath->rp_cost;
|
|
|
|
|
TxPrintf("cst:%.0f, ", (double)(newPath->rp_cost));
|
|
|
|
|
if(cost < mzInitialEstimate)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("(<est)");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
excessCost = cost - mzInitialEstimate;
|
|
|
|
|
excessPercent = 100.0 * (double)(excessCost)/
|
|
|
|
|
(double)(mzInitialEstimate);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
TxPrintf("overrun: %.0f%%", excessPercent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TxPrintf("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(extendCode >= EC_WALKRIGHT)
|
|
|
|
|
{
|
|
|
|
|
LIST_ADD(newPath, mzWalkStack);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch(mzPathSource)
|
|
|
|
|
{
|
|
|
|
|
case SOURCE_BLOOM:
|
|
|
|
|
if(orient=='O')
|
|
|
|
|
{
|
|
|
|
|
/* just changing layers, add back to bloom */
|
|
|
|
|
LIST_ADD(newPath, mzBloomStack);
|
|
|
|
|
}
|
|
|
|
|
else if((orient=='H' && rLayer->rl_hCost<=rLayer->rl_vCost) ||
|
|
|
|
|
(orient=='V' && rLayer->rl_vCost<=rLayer->rl_hCost))
|
|
|
|
|
{
|
|
|
|
|
/* going in preferred direction */
|
|
|
|
|
LIST_ADD(newPath, mzStraightStack);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* non preferred, add to heaps */
|
|
|
|
|
HeapAddDLong(&mzMaxToGoHeap, togo, (char *) newPath);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SOURCE_STRAIGHT:
|
|
|
|
|
if(path->rp_orient==orient && (cost < mzBloomMaxCost))
|
|
|
|
|
{
|
|
|
|
|
/* straight and within bounds, keep going*/
|
|
|
|
|
LIST_ADD(newPath, mzStraightStack);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* from here on, follow downhill only */
|
|
|
|
|
LIST_ADD(newPath, mzDownHillStack);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SOURCE_DOWNHILL:
|
|
|
|
|
{
|
|
|
|
|
dlong oldCostPlusOne;
|
|
|
|
|
|
|
|
|
|
oldCostPlusOne = path->rp_cost + 1;
|
|
|
|
|
if(cost <oldCostPlusOne)
|
|
|
|
|
{
|
|
|
|
|
/* cost within a unit, keep following down hill */
|
|
|
|
|
LIST_ADD(newPath, mzDownHillStack);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* increased cost, add to heaps */
|
|
|
|
|
HeapAddDLong(&mzMaxToGoHeap, togo, (char *) newPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SOURCE_INIT:
|
|
|
|
|
/* Initial points go on heap */
|
|
|
|
|
HeapAddDLong(&mzMaxToGoHeap, togo, (char *) newPath);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* mzBloomInit --
|
|
|
|
|
*
|
|
|
|
|
* Initialize bloom stack with given path.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds a routepath to bloom stack, and sets mzBloomMaxCost.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
mzBloomInit(path)
|
|
|
|
|
RoutePath *path; /* path that new point extends */
|
|
|
|
|
{
|
|
|
|
|
ASSERT(mzBloomStack==NULL,"mzBloomInit");
|
|
|
|
|
|
|
|
|
|
LIST_ADD(path, mzBloomStack);
|
|
|
|
|
mzBloomMaxCost = path->rp_cost + mzBloomDeltaCost;
|
|
|
|
|
|
|
|
|
|
mzNumBlooms++;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* mzMakeStatReport --
|
|
|
|
|
*
|
|
|
|
|
* Print out route statistics
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Output via TxPrintf()
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
mzMakeStatReport()
|
|
|
|
|
{
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* if we aren't being verbose, skip this */
|
|
|
|
|
if(mzVerbosity<VERB_STATS) return;
|
|
|
|
|
|
|
|
|
|
TxPrintf(" Blms:%d(%d)", mzNumBlooms - mzNumOutsideBlooms,
|
|
|
|
|
mzNumBlooms);
|
|
|
|
|
|
|
|
|
|
TxPrintf(" Wndw:%.0f(%.0f%%)", (double)(mzWindowMaxToGo),
|
|
|
|
|
(100.0 * (1- (double)(mzWindowMaxToGo)/
|
|
|
|
|
((double)(mzInitialEstimate) +(double)(mzWWidth)))));
|
|
|
|
|
|
|
|
|
|
TxPrintf(" Pts:%d(%d)",
|
|
|
|
|
mzNumPaths,
|
|
|
|
|
mzNumPathsGened);
|
|
|
|
|
|
|
|
|
|
TxPrintf(" Blkgen: %dx%.0f",
|
|
|
|
|
mzBlockGenCalls,
|
|
|
|
|
mzBlockGenArea/mzBlockGenCalls);
|
|
|
|
|
|
|
|
|
|
TxPrintf("(%.0f/icst)",
|
|
|
|
|
(double)mzBlockGenArea/(double)(mzInitialEstimate));
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
TxPrintf("\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|