2025 lines
48 KiB
C
2025 lines
48 KiB
C
/*
|
|
* mzEstimate.c --
|
|
*
|
|
* Management of tile plane for estimation of remaining cost to completion.
|
|
*
|
|
* Contains code for building estimation plane (just prior to route), and
|
|
* routine for computing estimates (using the estimation plane) during routing.
|
|
*
|
|
* *********************************************************************
|
|
* * 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. *
|
|
* *********************************************************************
|
|
*
|
|
* EXPLANATION OF ESTIMATION CODE:
|
|
* The purpose of the estimation code is to estimate cost to completion
|
|
* from any point to the destintation taking into account the need to
|
|
* detour around major obstactles such as subcells and fences.
|
|
*
|
|
* The estimation plane permits multiple destination area (routes are
|
|
* made to what ever area is easiest to reach). The mzrouter also permits
|
|
* multiple start points of course.
|
|
*
|
|
* To achieve this purpose, prior to beginning the search for a route an
|
|
* estimation plane is generated with info that allows quick estimation
|
|
* of cost to completion during routing.
|
|
*
|
|
* The estimation plane contains
|
|
* ``solid'' tiles for major obstacles (subcells and fences) and space
|
|
* tiles. The space tiles are split on the extensions of solid tile edges
|
|
* so that one can always get from a solid tile corner straight out to
|
|
* the next blocking solid tile along tile edges. Space tiles are also split
|
|
* outward in each direction from the destination point.
|
|
*
|
|
* Estimators are generated for each tile in the estimation plane that allow
|
|
* estimates to be made for points in that tile. An estimator consists
|
|
* of five numbers:
|
|
* (x0,y0,hcost,vcost,cost0)
|
|
* that are used in the following formula:
|
|
* EstCost = (x - x0)*hcost + (y -y0)*vcost + cost0.
|
|
* An estimator represents the approximate cost of a path beginning at any
|
|
* point (x,y) in the current tile and proceedings horizontally and then
|
|
* vertically
|
|
* (or vice versa) to the tile corner (x0,y0) and then following the cheapest
|
|
* path along tile-edges to a destination area. The cheapest path from
|
|
* (x0,y0) is precomputed and has cost cost0. Currently only
|
|
* tile corners (x0,y0) of the tile the estimator is attached to are used
|
|
* for estimators. Estimators are also generated for paths from edges of
|
|
* a tile straight across to the nearest dest area (with out jogs). These
|
|
* "straight shot" estimators have zero hcost or vcost.
|
|
* Several estimators are attached to each
|
|
* tile, and the least cost one is used for any given (x,y).
|
|
*
|
|
* The estimation plane is generated in the following steps:
|
|
*
|
|
* 1. Generate solid tiles for unexpanded subcells (if subcells
|
|
can not be routed across on any active layer) and fences.
|
|
*
|
|
* 2. Split space tiles along extended edges of solid tiles and
|
|
* destination areas.
|
|
*
|
|
* 3. Assign a horizontal and vertical cost for routing in each tile.
|
|
* Cost for space tiles is cost of min active route-layer, cost for
|
|
* solid tiles is INFINITY. (could be more sophisticated - e.g.
|
|
* if routing is allowed over subcells on an expensive layer.)
|
|
*
|
|
* 4. Apply djikstra's shortest path algorithm to graph whose vertices
|
|
* are tile-corners and whose edges are tile edges. Weight on
|
|
* hor edges is min hor cost of the two adjacent tiles, weight on
|
|
* vertical edges is min of vert costs of adjacent tiles. Djikstra's
|
|
* algor. computes least cost path along tile-edges to
|
|
* destination for all tile corners
|
|
* (e.g. it generates all the cost0's for the estimators).
|
|
*
|
|
* 5. Build estimators for each tile - currently one estimator is built
|
|
* for each corner of the tile.
|
|
*
|
|
* 6. Trim away redundant estimators - currently if an estimator e0 is
|
|
* always cheaper than a second e1, e1 is thrown away.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/mzrouter/mzEstimate.c,v 1.2 2008/06/01 18:37:44 tim Exp $";
|
|
#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 "database/database.h"
|
|
#include "utils/signals.h"
|
|
#include "textio/textio.h"
|
|
#include "windows/windows.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "utils/malloc.h"
|
|
#include "utils/list.h"
|
|
#include "debug/debug.h"
|
|
#include "textio/textio.h"
|
|
#include "utils/heap.h"
|
|
#include "mzrouter/mzrouter.h"
|
|
#include "mzrouter/mzInternal.h"
|
|
|
|
/* largest finite tile plane coordinates, need to reduce INFINITY and MINFINITY
|
|
* defined in tile.h because of some funny buisness off at infinity?
|
|
*/
|
|
|
|
/* Special case mips machines because of a compiler bug, as of 8/9/89 */
|
|
#ifdef mips
|
|
static int MAX_FINITE_COORDINATE = (INFINITY-10);
|
|
static int MIN_FINITE_COORDINATE = (MINFINITY+10);
|
|
#else
|
|
#define MAX_FINITE_COORDINATE (INFINITY-10)
|
|
#define MIN_FINITE_COORDINATE (MINFINITY+10)
|
|
#endif
|
|
|
|
/*----------- Vertex structure for shortest path algorithm ---------------*/
|
|
typedef struct vertex
|
|
{
|
|
int vx_status; /* which corner in tile, IN set when min distance
|
|
* to vertex determined (shortest path algor) */
|
|
Tile *vx_tile; /* tile vertex is attached to */
|
|
dlong vx_cost; /* Min cost from here to destination point */
|
|
} Vertex;
|
|
|
|
#define VX_CORNER 7
|
|
#define VX_NONE 0
|
|
#define VX_L_LEFT 1
|
|
#define VX_U_LEFT 2
|
|
#define VX_L_RIGHT 4
|
|
#define VX_IN 8
|
|
|
|
/* Estimators for estimating cost from point within tile, (x,y), along a
|
|
* certain path to destination.
|
|
*
|
|
* EstCost = (x - x0) * hCost + (y - y0) * vCost + cost0
|
|
*/
|
|
typedef struct estimate
|
|
{
|
|
int e_x0;
|
|
int e_y0;
|
|
dlong e_cost0;
|
|
int e_hCost;
|
|
int e_vCost;
|
|
struct estimate *e_next;
|
|
} Estimate;
|
|
|
|
/* --------------- tileCosts structure --------------------------------------*/
|
|
/* One of these is associated with each tile in the mzEstimate plane. They
|
|
* are pointed to by the client fields of the tiles.
|
|
*/
|
|
typedef struct tileCosts
|
|
{
|
|
int tc_hCost; /* horizontal cost / unit distance */
|
|
int tc_vCost; /* vertical cost / unit distance */
|
|
Vertex tc_vxLLeft; /* Vertices corresponding to 3 corners of this tile */
|
|
Vertex tc_vxULeft;
|
|
Vertex tc_vxLRight;
|
|
Estimate *tc_estimates; /* path estimates for point in this tile */
|
|
} TileCosts;
|
|
|
|
/*---------------- static data, local to this file --------------------------*/
|
|
bool mzEstimateExists = FALSE; /* Set on first call to mzBuildEstimate */
|
|
|
|
/* Forward declarations */
|
|
extern void mzCleanEstimate();
|
|
extern void mzBuildCornerEstimators();
|
|
extern void mzBuildStraightShotEstimators();
|
|
extern void mzSplitTiles();
|
|
extern void mzAssignVertexCosts();
|
|
extern void mzAddVertex();
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzBuildEstimate --
|
|
* Setup contents of Estimation plane.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side effects:
|
|
* Add tiles to mzEstimate plane, create a tileCost struc for each tile
|
|
* complete with estimates.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mzBuildEstimate()
|
|
{
|
|
/* Clear estimation plane, reclaiming storage */
|
|
if(mzEstimateExists)
|
|
{
|
|
mzCleanEstimate();
|
|
}
|
|
mzEstimateExists = TRUE; /* Set flag, so we know to clean next time */
|
|
|
|
/* Now build the estimate plane from scratch */
|
|
if(mzEstimate)
|
|
{
|
|
bool subcellsOpaque;
|
|
|
|
/* determine whether subcells can be crossed on any active layer */
|
|
{
|
|
RouteLayer *rL;
|
|
|
|
subcellsOpaque = TRUE;
|
|
for(rL = mzActiveRLs;
|
|
rL!=NULL && subcellsOpaque;
|
|
rL=rL->rl_nextActive)
|
|
{
|
|
if(rL->rl_routeType.rt_spacing[TT_SUBCELL] < 0)
|
|
{
|
|
subcellsOpaque = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If over-the-cell routing is not possible,
|
|
* add a tile to the estimation plane for each unexpanded subcell.
|
|
*
|
|
* NOTE: A 0 expansion mask is special cased since
|
|
* the mzrouter interpets a 0 mask to mean all subcells are
|
|
* expanded,
|
|
* while DBTreeSrCells() takes a 0 mask to mean all subcells are
|
|
* unexpanded.
|
|
*/
|
|
if(mzCellExpansionMask != 0 && subcellsOpaque)
|
|
{
|
|
int mzAddSubcellEstFunc();
|
|
SearchContext scx;
|
|
|
|
scx.scx_area = mzBoundingRect;
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
scx.scx_use = mzRouteUse;
|
|
|
|
/* clip area to bounding box to avoid overflow during transfroms */
|
|
GEOCLIP(&(scx.scx_area),&(mzRouteUse->cu_def->cd_bbox));
|
|
|
|
DBTreeSrCells(
|
|
&scx,
|
|
mzCellExpansionMask,
|
|
mzAddSubcellEstFunc,
|
|
(ClientData) &mzBoundingRect);
|
|
}
|
|
|
|
/* If route is OUTSIDE fence, add ``fence'' tiles to estimation plane
|
|
* for each FENCE tile on fence plane.
|
|
* If route is INSIDE fence, add ``fence'' tiles for each SPACE tile on
|
|
* the fence plane.
|
|
*/
|
|
{
|
|
int mzAddFenceEstFunc();
|
|
|
|
if(mzInsideFence)
|
|
{
|
|
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzHFencePlane,
|
|
&mzBoundingRect,
|
|
&DBSpaceBits,
|
|
mzAddFenceEstFunc,
|
|
(ClientData) &mzBoundingRect);
|
|
}
|
|
else
|
|
{
|
|
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzHFencePlane,
|
|
&mzBoundingRect,
|
|
&DBAllButSpaceBits,
|
|
mzAddFenceEstFunc,
|
|
(ClientData) &mzBoundingRect);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add a tile to the estimation plane for each dest area, and cut
|
|
* holes at the walks leading to the dest areas
|
|
*/
|
|
{
|
|
int mzProcessDestEstFunc();
|
|
SearchContext scx;
|
|
|
|
scx.scx_area = mzBoundingRect;
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
scx.scx_use = mzDestAreasUse;
|
|
|
|
/* clip area to bounding box to avoid overflow during transforms */
|
|
GEOCLIP(&(scx.scx_area),&(mzDestAreasUse->cu_def->cd_bbox));
|
|
|
|
(void) DBTreeSrTiles(
|
|
&scx,
|
|
&DBAllButSpaceAndDRCBits,
|
|
0,
|
|
mzProcessDestEstFunc,
|
|
(ClientData) NULL);
|
|
}
|
|
|
|
/*--- Split space tiles at edges of solid tiles. ---*/
|
|
{
|
|
int mzBuildSolidsListFunc();
|
|
List *solidsList = NULL;
|
|
List *l;
|
|
|
|
/* Build list of all solid,
|
|
* i.e. nonspace, tiles on estimation plane. */
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzEstimatePlane,
|
|
&TiPlaneRect, /* max paintable rect. */
|
|
&DBAllButSpaceBits,
|
|
mzBuildSolidsListFunc,
|
|
(ClientData) &solidsList);
|
|
|
|
/* Split tiles along perpendiculars of solid tile corners. */
|
|
for(l=solidsList; l!=NULL; l = LIST_TAIL(l))
|
|
{
|
|
Tile *solid = (Tile *) LIST_FIRST(l);
|
|
Point p;
|
|
|
|
/* lower left corner */
|
|
mzSplitTiles(mzEstimatePlane,&(solid->ti_ll));
|
|
|
|
/* top left corner */
|
|
p.p_x = LEFT(solid);
|
|
p.p_y = TOP(solid);
|
|
mzSplitTiles(mzEstimatePlane,&p);
|
|
|
|
/* top right corner */
|
|
p.p_x = RIGHT(solid);
|
|
mzSplitTiles(mzEstimatePlane,&p);
|
|
|
|
/* bottom right corner */
|
|
p.p_y = BOTTOM(solid);
|
|
mzSplitTiles(mzEstimatePlane,&p);
|
|
}
|
|
|
|
/* Free up solids list */
|
|
ListDealloc(solidsList);
|
|
}
|
|
|
|
/* Assign costs to tiles in estimation plane:
|
|
* Dest tiles - 0 cost.
|
|
* Space tiles - min active costs.
|
|
* Fence tiles - infinite cost.
|
|
* Subcell tiles - infinite cost.
|
|
*/
|
|
{
|
|
int mzAssignCostsFunc();
|
|
TileCosts spaceCosts;
|
|
RouteLayer *rL;
|
|
|
|
/* set space costs to min costs of active layers */
|
|
spaceCosts.tc_hCost = INT_MAX;
|
|
spaceCosts.tc_vCost = INT_MAX;
|
|
for(rL = mzRouteLayers; rL!=NULL; rL=rL->rl_next)
|
|
{
|
|
if(rL->rl_routeType.rt_active)
|
|
{
|
|
if(rL->rl_hCost < spaceCosts.tc_hCost)
|
|
spaceCosts.tc_hCost = rL->rl_hCost;
|
|
if(rL->rl_vCost < spaceCosts.tc_vCost)
|
|
spaceCosts.tc_vCost = rL->rl_vCost;
|
|
}
|
|
}
|
|
|
|
/* visit all tiles in estimate plane attaching cost structures
|
|
* (including vertices) to the client fields. Horizontal and
|
|
* vertical costs are assigned.
|
|
*/
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzEstimatePlane,
|
|
&TiPlaneRect,
|
|
&DBAllTypeBits,
|
|
mzAssignCostsFunc,
|
|
(ClientData) &spaceCosts);
|
|
}
|
|
|
|
/* Apply djikstra shortest path algorithm to determine minimum costs
|
|
* to vertices in tile edge graph.
|
|
*/
|
|
mzAssignVertexCosts();
|
|
|
|
/* Build cost estimates for each tile in estimate plane */
|
|
{
|
|
int mzBuildEstimatesFunc();
|
|
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzEstimatePlane,
|
|
&TiPlaneRect,
|
|
&DBAllTypeBits,
|
|
mzBuildEstimatesFunc,
|
|
(ClientData) NULL);
|
|
}
|
|
|
|
/* Trim away redundant cost estimates on tiles */
|
|
{
|
|
int mzTrimEstimatesFunc();
|
|
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzEstimatePlane,
|
|
&TiPlaneRect,
|
|
&DBAllTypeBits,
|
|
mzTrimEstimatesFunc,
|
|
(ClientData) NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzCleanEstimate --
|
|
*
|
|
* Clear estimate plane and reclaim storage.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side effects:
|
|
* See Above.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mzCleanEstimate()
|
|
{
|
|
if (mzEstimateExists)
|
|
{
|
|
int mzReclaimTCFunc();
|
|
|
|
SigDisableInterrupts(); /* Make atomic so we don't forget to reclaim
|
|
* anything nor reclaim it twice.
|
|
*/
|
|
|
|
/* visit all tiles in estimate plane reclaiming attached
|
|
* cost structures.
|
|
*/
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzEstimatePlane,
|
|
&TiPlaneRect, /* max paintable rect */
|
|
&DBAllTypeBits,
|
|
mzReclaimTCFunc,
|
|
(ClientData) NULL);
|
|
|
|
DBClearPaintPlane(mzEstimatePlane);
|
|
|
|
mzEstimateExists = FALSE;
|
|
|
|
SigEnableInterrupts();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzReclaimTCFunc --
|
|
*
|
|
* Free TileCost struc (prior to erasing old estimate plane.)
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Frees TileCost pointed to by client field in tile struc. Clears
|
|
* client field pointer - just a precaution.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzReclaimTCFunc(tile, notUsed)
|
|
Tile *tile;
|
|
ClientData notUsed;
|
|
{
|
|
if (tile->ti_client != (ClientData)CLIENTDEFAULT)
|
|
{
|
|
TileCosts *tc = ((TileCosts *) (tile->ti_client));
|
|
Estimate *e;
|
|
|
|
/* free estimates attached to tilecosts struc */
|
|
for(e=tc->tc_estimates; e!=NULL; e=e->e_next)
|
|
{
|
|
freeMagic((char *) e);
|
|
}
|
|
|
|
/* free tilecosts struc */
|
|
freeMagic((char *) (tile->ti_client));
|
|
|
|
/* reset client field in tile */
|
|
tile->ti_client = ((ClientData) CLIENTDEFAULT);
|
|
}
|
|
|
|
/* return 0 - to continue traversal of old estimate plane */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzProcessDestEstFunc --
|
|
*
|
|
* Filter function called via DBTreeSrTiles on behalf of mzBuildEstimate()
|
|
* above, for each dest area in the area of interest. Searches blockage
|
|
* planes for dest tiles and walks under dest area and paints corresponding
|
|
* tiles in estimation plane.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Paints into mzEstimatePlane
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzProcessDestEstFunc(tile, cxp)
|
|
Tile *tile;
|
|
TreeContext *cxp;
|
|
{
|
|
SearchContext *scx = cxp->tc_scx;
|
|
TileType type = TiGetType(tile);
|
|
RouteType *rT;
|
|
Rect r, rect;
|
|
|
|
/* Transform to result coordinates */
|
|
TITORECT(tile, &r);
|
|
GEOTRANSRECT(&scx->scx_trans, &r, &rect);
|
|
|
|
/* Grow rect by max walk size in all directions so we find walks as
|
|
* well as the dest area.
|
|
*/
|
|
rect.r_xbot -= mzMaxWalkLength;
|
|
rect.r_ybot -= mzMaxWalkLength;
|
|
rect.r_xtop += mzMaxWalkLength;
|
|
rect.r_ytop += mzMaxWalkLength;
|
|
|
|
/* find route type for this dest area */
|
|
{
|
|
rT = mzActiveRTs;
|
|
while ((rT->rt_tileType != type) && (rT!=NULL))
|
|
{
|
|
rT = rT->rt_nextActive;
|
|
}
|
|
ASSERT(rT!=NULL,"mzAddDestTileEstFunc");
|
|
}
|
|
|
|
/* process dest and walk tiles below dest area */
|
|
{
|
|
int mzDestTileEstFunc();
|
|
TileTypeBitMask destMask;
|
|
|
|
TTMaskSetOnlyType(&destMask, TT_DEST_AREA);
|
|
TTMaskSetType(&destMask, TT_LEFT_WALK);
|
|
TTMaskSetType(&destMask, TT_RIGHT_WALK);
|
|
TTMaskSetType(&destMask, TT_TOP_WALK);
|
|
TTMaskSetType(&destMask, TT_BOTTOM_WALK);
|
|
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
rT->rt_hBlock,
|
|
&rect,
|
|
&destMask,
|
|
mzDestTileEstFunc,
|
|
(ClientData) NULL);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzDestTileEstFunc --
|
|
*
|
|
* Paint dest area into estimate plane, or cut whole over walks.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Modifies estimate plane.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzDestTileEstFunc(tile, cdarg)
|
|
Tile *tile;
|
|
ClientData cdarg;
|
|
{
|
|
Rect rect;
|
|
|
|
/* set rect to bounding box of tile */
|
|
TITORECT(tile, &rect);
|
|
|
|
if(TiGetType(tile)==TT_DEST_AREA)
|
|
/* paint dest area into estimate plane */
|
|
{
|
|
DBPaintPlane(mzEstimatePlane,
|
|
&rect,
|
|
mzEstimatePaintTbl[TT_EST_DEST],
|
|
(PaintUndoInfo *) NULL);
|
|
}
|
|
else
|
|
/* cut hole for walk in estimate plane */
|
|
{
|
|
DBPaintPlane(mzEstimatePlane,
|
|
&rect,
|
|
mzEstimatePaintTbl[TT_SPACE],
|
|
(PaintUndoInfo *) NULL);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzAddSubcellEstFunc --
|
|
*
|
|
* Filter function called via DBTreeSrTiles on behalf of mzBuildEstimate()
|
|
* above, for each unexpanded subcell in the area of interest,
|
|
* a TT_EST_SUBCELL tile is painted on each estimate plane for
|
|
* the bounding box of the subcell.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Paints into mzEstimatePlane
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzAddSubcellEstFunc(scx, cdarg)
|
|
SearchContext *scx;
|
|
ClientData cdarg;
|
|
{
|
|
Rect r, rDest;
|
|
|
|
/* Transform bounding box to result coords */
|
|
r = scx->scx_use->cu_def->cd_bbox;
|
|
GEOTRANSRECT(&scx->scx_trans, &r, &rDest);
|
|
|
|
/* paint subcell block onto estimate plane */
|
|
DBPaintPlane(mzEstimatePlane,
|
|
&rDest,
|
|
mzEstimatePaintTbl[TT_EST_SUBCELL],
|
|
(PaintUndoInfo *) NULL);
|
|
|
|
/* continue search */
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzAddFenceEstFunc --
|
|
*
|
|
* Filter function called via DBSrPaintArea on behalf of mzBuildEstimate()
|
|
* above, for each fence tile in the area of interest,
|
|
* a TT_EST_FENCE tile is painted on the estimate plane for
|
|
* each nonspace tile on the fence plane.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Paints into mzEstimatePlane
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzAddFenceEstFunc(tile, buildArea)
|
|
Tile *tile;
|
|
Rect *buildArea; /* currently ignored */
|
|
{
|
|
Rect r;
|
|
|
|
/* Get boundary of tile */
|
|
TITORECT(tile, &r);
|
|
|
|
/* paint fence into estimate plane */
|
|
DBPaintPlane(mzEstimatePlane,
|
|
&r,
|
|
mzEstimatePaintTbl[TT_EST_FENCE],
|
|
(PaintUndoInfo *) NULL);
|
|
|
|
/* continue search */
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzBuildSolidsList --
|
|
*
|
|
* Called by DBSrPaintArea for each solid tile in estimation plane
|
|
* Creates list of these tiles.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Adds to list passed as arg.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzBuildSolidsListFunc(tile, listPtr)
|
|
Tile *tile;
|
|
List **listPtr; /* pointer to list to add tile to */
|
|
{
|
|
LIST_ADD(tile,*listPtr);
|
|
|
|
/* return 0 - to continue search */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzAssignCostsFunc --
|
|
*
|
|
* Assigns horizontal and vertical costs to tiles in estimate plane.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Adds to list passed as arg.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
mzAssignCostsFunc(tile, spaceCosts)
|
|
Tile *tile;
|
|
TileCosts *spaceCosts; /* costs to assign to space tiles */
|
|
{
|
|
Tile *tRight, *tUp;
|
|
TileCosts *newCosts;
|
|
Vertex *v;
|
|
|
|
/* Alloc TileCosts struc for this tile, and attach it */
|
|
newCosts = (TileCosts *) mallocMagic((unsigned) (sizeof(TileCosts)));
|
|
tile->ti_client = (ClientData) newCosts;
|
|
|
|
/* Assign hor and vert costs for tile */
|
|
switch(TiGetType(tile))
|
|
{
|
|
case TT_EST_DEST:
|
|
newCosts->tc_hCost = 0;
|
|
newCosts->tc_vCost = 0;
|
|
break;
|
|
|
|
case TT_SPACE:
|
|
*newCosts = *spaceCosts;
|
|
break;
|
|
|
|
case TT_EST_FENCE:
|
|
case TT_EST_SUBCELL:
|
|
newCosts->tc_hCost = INT_MAX;
|
|
newCosts->tc_vCost = INT_MAX;
|
|
break;
|
|
|
|
default:
|
|
/* unrecognized tile type */
|
|
ASSERT(FALSE,"mzAssignCostsFunc");
|
|
}
|
|
|
|
/* add lower-left vertex */
|
|
v = &(newCosts->tc_vxLLeft);
|
|
v->vx_status = VX_L_LEFT;
|
|
v->vx_tile = tile;
|
|
v->vx_cost = COST_MAX;
|
|
|
|
/* add lower-right vertex, if at 'T' */
|
|
NEXT_TILE_RIGHT(tRight, tile, BOTTOM(tile));
|
|
if (BOTTOM(tRight)!=BOTTOM(tile))
|
|
{
|
|
/* lower-right vertex at 'T', so add it */
|
|
v = &(newCosts->tc_vxLRight);
|
|
v->vx_status = VX_L_RIGHT;
|
|
v->vx_tile = tile;
|
|
v->vx_cost = COST_MAX;
|
|
}
|
|
else
|
|
{
|
|
/* no 'T' */
|
|
newCosts->tc_vxLRight.vx_status = VX_NONE;
|
|
}
|
|
|
|
/* add upper-left vertex, if at 'T' */
|
|
NEXT_TILE_UP(tUp, tile, LEFT(tile));
|
|
if (LEFT(tUp)!=LEFT(tile))
|
|
{
|
|
/* upper-left vertex at 'T', so add it */
|
|
v = &(newCosts->tc_vxULeft);
|
|
v->vx_status = VX_U_LEFT;
|
|
v->vx_tile = tile;
|
|
v->vx_cost = COST_MAX;
|
|
}
|
|
else
|
|
{
|
|
/* no 'T' */
|
|
newCosts->tc_vxULeft.vx_status = VX_NONE;
|
|
}
|
|
|
|
/* initial estimates to NULL list */
|
|
newCosts->tc_estimates = NULL;
|
|
|
|
/* return 0 - to continue traversal of estimate plane */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzDestInitialAssignFunc
|
|
*
|
|
* Add one vertex of dest tile to adjacency heap to initialize graph for
|
|
* Djikstra's shortest path computation.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Initials cost to zero and adds a vertex to adjacency heap.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
mzDestInitialAssignFunc(tile, cdarg)
|
|
Tile *tile;
|
|
ClientData cdarg;
|
|
{
|
|
Heap *adjHeap = (Heap *) cdarg;
|
|
Vertex *v;
|
|
|
|
/* get lower left vertex */
|
|
v = &(((TileCosts *)(tile->ti_client))->tc_vxLLeft);
|
|
|
|
/* cost from dest is zero */
|
|
v->vx_cost = 0;
|
|
|
|
/* add vertex to adjHeap */
|
|
HeapAddDLong(adjHeap, 0, (char *) v);
|
|
|
|
/* return 0 - to continue search */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzBuildEstimatesFunc --
|
|
*
|
|
* Build path estimates for this tile.
|
|
* (For now builds
|
|
* + one estimate for each corner of the tile.
|
|
* + one estimate for no jog path to destination in each direction where
|
|
* this is possible.)
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Adds estimates to TileCost struc attached to tile.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzBuildEstimatesFunc(tile, notUsed)
|
|
Tile *tile;
|
|
ClientData notUsed;
|
|
{
|
|
|
|
mzBuildCornerEstimators(tile);
|
|
mzBuildStraightShotEstimators(tile);
|
|
|
|
/* return 0 - to continue traversal of estimate plane */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzBuildCornerEstimators --
|
|
*
|
|
* Build path estimates for paths via corners of this tile.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Adds estimates to TileCost struc attached to tile.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mzBuildCornerEstimators(tile)
|
|
Tile *tile;
|
|
{
|
|
TileCosts *tc = (TileCosts *) (tile->ti_client);
|
|
Vertex *vLLeft = NULL;
|
|
Vertex *vULeft = NULL;
|
|
Vertex *vLRight = NULL;
|
|
Vertex *vURight = NULL;
|
|
|
|
/* find vertex strucs corresponding to four corners.
|
|
* (NULL, for corners at infinity)
|
|
*/
|
|
{
|
|
Tile *tUp, *tRight, *tDiag;
|
|
Tile *tRT, *tTR;
|
|
|
|
if(LEFT(tile)>=MIN_FINITE_COORDINATE)
|
|
{
|
|
if(BOTTOM(tile)>=MIN_FINITE_COORDINATE)
|
|
{
|
|
/* Lower Left */
|
|
vLLeft = &(tc->tc_vxLLeft);
|
|
}
|
|
|
|
if(TOP(tile)<=MAX_FINITE_COORDINATE)
|
|
{
|
|
/* Upper Left */
|
|
NEXT_TILE_UP(tUp, tile, LEFT(tile));
|
|
if (LEFT(tUp)<LEFT(tile))
|
|
{
|
|
/* upper-left vertex at 'T', so stored with tile */
|
|
vULeft = &(tc->tc_vxULeft);
|
|
}
|
|
else
|
|
{
|
|
/* no 'T', stored with tUp */
|
|
vULeft = &(((TileCosts *)(tUp->ti_client))->tc_vxLLeft);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(RIGHT(tile)<=MAX_FINITE_COORDINATE)
|
|
{
|
|
if(BOTTOM(tile)>=MIN_FINITE_COORDINATE)
|
|
{
|
|
/* Lower Right */
|
|
NEXT_TILE_RIGHT(tRight, tile, BOTTOM(tile));
|
|
if (BOTTOM(tRight)<BOTTOM(tile))
|
|
{
|
|
/* lower-right vertex at 'T', so stored with tile */
|
|
vLRight = &(tc->tc_vxLRight);
|
|
}
|
|
else
|
|
{
|
|
/* no 'T', stored with tRight */
|
|
vLRight = &(((TileCosts *)(tRight->ti_client))->tc_vxLLeft);
|
|
}
|
|
}
|
|
|
|
if(TOP(tile)<=MAX_FINITE_COORDINATE)
|
|
{
|
|
/* Upper Right */
|
|
tRT = RT(tile); /* right top corner stitch (up) */
|
|
tTR = TR(tile); /* top right corner stitch (to right) */
|
|
if(RIGHT(tRT)>RIGHT(tile))
|
|
{
|
|
/* upper right at 'T' stored with tTR */
|
|
vURight = &(((TileCosts *)(tTR->ti_client))->tc_vxULeft);
|
|
}
|
|
else if (TOP(tTR)>TOP(tile))
|
|
{
|
|
/* upper right at 'T' stored with tRT */
|
|
vURight = &(((TileCosts *)(tRT->ti_client))->tc_vxLRight);
|
|
}
|
|
else
|
|
{
|
|
/* no 'T', stored in own tile */
|
|
NEXT_TILE_UP(tDiag, tTR, RIGHT(tile));
|
|
vURight = &(((TileCosts *)(tDiag->ti_client))->tc_vxLLeft);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Build estimates */
|
|
{
|
|
Estimate *e;
|
|
|
|
/* Estimate for lower left corner */
|
|
if (vLLeft)
|
|
{
|
|
e = (Estimate *) mallocMagic((unsigned) (sizeof(Estimate)));
|
|
e->e_x0 = LEFT(tile);
|
|
e->e_y0 = BOTTOM(tile);
|
|
e->e_cost0 = vLLeft->vx_cost;
|
|
e->e_hCost = tc->tc_hCost;
|
|
e->e_vCost = tc->tc_vCost;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
|
|
/* Estimate for lower right corner */
|
|
if (vLRight)
|
|
{
|
|
e = (Estimate *) mallocMagic((unsigned) (sizeof(Estimate)));
|
|
e->e_x0 = RIGHT(tile);
|
|
e->e_y0 = BOTTOM(tile);
|
|
e->e_cost0 = vLRight->vx_cost;
|
|
e->e_hCost = tc->tc_hCost;
|
|
e->e_vCost = tc->tc_vCost;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
|
|
/* Estimate for upper right corner */
|
|
if (vURight)
|
|
{
|
|
e = (Estimate *) mallocMagic((unsigned) (sizeof(Estimate)));
|
|
e->e_x0 = RIGHT(tile);
|
|
e->e_y0 = TOP(tile);
|
|
e->e_cost0 = vURight->vx_cost;
|
|
e->e_hCost = tc->tc_hCost;
|
|
e->e_vCost = tc->tc_vCost;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
|
|
/* Estimate for upper left corner */
|
|
if (vULeft)
|
|
{
|
|
e = (Estimate *) mallocMagic((unsigned)(sizeof(Estimate)));
|
|
e->e_x0 = LEFT(tile);
|
|
e->e_y0 = TOP(tile);
|
|
e->e_cost0 = vULeft->vx_cost;
|
|
e->e_hCost = tc->tc_hCost;
|
|
e->e_vCost = tc->tc_vCost;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzBuildStraightShotEstimators --
|
|
*
|
|
* Build path estimates for paths straight to dest area (no jogs)
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Adds estimates to TileCost struc attached to tile.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
mzBuildStraightShotEstimators(tile)
|
|
Tile *tile;
|
|
{
|
|
TileCosts *tc = (TileCosts *) (tile->ti_client);
|
|
|
|
/* straight right */
|
|
{
|
|
Tile *tSolid = tile;
|
|
|
|
/* get first solid tile to right */
|
|
while(TiGetType(tSolid)==TT_SPACE &&
|
|
tSolid!=mzEstimatePlane->pl_right)
|
|
{
|
|
tSolid = TR(tSolid);
|
|
}
|
|
|
|
/* if dest tile, build estimator */
|
|
if(TiGetType(tSolid) == TT_EST_DEST)
|
|
{
|
|
Estimate *e;
|
|
|
|
e = (Estimate *) mallocMagic((unsigned)(sizeof(Estimate)));
|
|
e->e_x0 = RIGHT(tile);
|
|
e->e_y0 = 0;
|
|
if (tc->tc_hCost == INT_MAX)
|
|
e->e_cost0 = COST_MAX;
|
|
else
|
|
e->e_cost0 = (dlong) (LEFT(tSolid) - RIGHT(tile)) * tc->tc_hCost;
|
|
e->e_hCost = tc->tc_hCost;
|
|
e->e_vCost = 0;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
}
|
|
|
|
/* straight left */
|
|
{
|
|
Tile *tSolid = tile;
|
|
|
|
/* get first solid tile to left */
|
|
while(TiGetType(tSolid)==TT_SPACE &&
|
|
tSolid!=mzEstimatePlane->pl_left)
|
|
{
|
|
tSolid = BL(tSolid);
|
|
}
|
|
|
|
/* if dest tile, build estimator */
|
|
if(TiGetType(tSolid) == TT_EST_DEST)
|
|
{
|
|
Estimate *e;
|
|
|
|
e = (Estimate *) mallocMagic((unsigned)(sizeof(Estimate)));
|
|
e->e_x0 = LEFT(tile);
|
|
e->e_y0 = 0;
|
|
if (tc->tc_hCost == INT_MAX)
|
|
e->e_cost0 = COST_MAX;
|
|
else
|
|
e->e_cost0 = (dlong) (RIGHT(tSolid) - LEFT(tile)) * tc->tc_hCost;
|
|
e->e_hCost = tc->tc_hCost;
|
|
e->e_vCost = 0;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
}
|
|
|
|
/* straight up */
|
|
{
|
|
Tile *tSolid = tile;
|
|
|
|
/* get first solid tile above */
|
|
while(TiGetType(tSolid)==TT_SPACE &&
|
|
tSolid!=mzEstimatePlane->pl_top)
|
|
{
|
|
tSolid = RT(tSolid);
|
|
}
|
|
|
|
/* if dest tile, build estimator */
|
|
if(TiGetType(tSolid) == TT_EST_DEST)
|
|
{
|
|
Estimate *e;
|
|
|
|
e = (Estimate *) mallocMagic((unsigned)(sizeof(Estimate)));
|
|
e->e_x0 = 0;
|
|
e->e_y0 = TOP(tile);
|
|
if (tc->tc_vCost == INT_MAX)
|
|
e->e_cost0 = COST_MAX;
|
|
else
|
|
e->e_cost0 = (dlong) (BOTTOM(tSolid) - TOP(tile)) * tc->tc_vCost;
|
|
e->e_hCost = 0;
|
|
e->e_vCost = tc->tc_vCost;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
}
|
|
|
|
/* straight down */
|
|
{
|
|
Tile *tSolid = tile;
|
|
|
|
/* get first solid tile below */
|
|
while(TiGetType(tSolid)==TT_SPACE &&
|
|
tSolid!=mzEstimatePlane->pl_bottom)
|
|
{
|
|
tSolid = LB(tSolid);
|
|
}
|
|
|
|
/* if dest tile, build estimator */
|
|
if(TiGetType(tSolid) == TT_EST_DEST)
|
|
{
|
|
Estimate *e;
|
|
|
|
e = (Estimate *) mallocMagic((unsigned)(sizeof(Estimate)));
|
|
e->e_x0 = 0;
|
|
e->e_y0 = BOTTOM(tile);
|
|
if (tc->tc_vCost == INT_MAX)
|
|
e->e_cost0 = COST_MAX;
|
|
else
|
|
e->e_cost0 = (dlong)(TOP(tSolid) - BOTTOM(tile)) * tc->tc_vCost;
|
|
e->e_hCost = 0;
|
|
e->e_vCost = tc->tc_vCost;
|
|
e->e_next = tc->tc_estimates;
|
|
tc->tc_estimates = e;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* AlwaysAsGood --
|
|
*
|
|
* Compares two estimators.
|
|
*
|
|
* Results:
|
|
* Returns TRUE iff est1 is always less than or equal to est2.
|
|
*
|
|
* Side effects:
|
|
* modifies estimates list in TileCost struc attached to tile,
|
|
* specifically sets floating origin coords. (Floating coords
|
|
* are those with corresponding cost field of 0, hence
|
|
* there value does not matter when computing estimates. They
|
|
* are set here as a convience, to permit uniform treatment of
|
|
* all estimators within this function.)
|
|
*
|
|
*
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
AlwaysAsGood(est1, est2, tile)
|
|
Estimate *est1;
|
|
Estimate *est2;
|
|
Tile *tile;
|
|
{
|
|
if(est1->e_cost0 > est2->e_cost0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
/* check if using est1 even from est2 origin
|
|
* is cheaper than using est2 */
|
|
{
|
|
/* If est2 x origin is floating, set to worst case */
|
|
if(est2->e_hCost == 0)
|
|
{
|
|
est2->e_x0 = (ABS(LEFT(tile) - est1->e_x0) >
|
|
ABS(RIGHT(tile) - est1->e_x0)) ?
|
|
LEFT(tile) : RIGHT(tile);
|
|
}
|
|
|
|
/* If est2 y origin is floating, set to worst case */
|
|
if(est2->e_vCost == 0)
|
|
{
|
|
est2->e_y0 = (ABS(BOTTOM(tile) - est1->e_y0) >
|
|
ABS(TOP(tile) - est1->e_y0)) ?
|
|
BOTTOM(tile) : TOP(tile);
|
|
}
|
|
|
|
/* now compute the cost from est2 origin using est1 */
|
|
|
|
{
|
|
dlong hCost, vCost, cost;
|
|
|
|
if ((est1->e_hCost == INT_MAX) || (est1->e_vCost == INT_MAX))
|
|
return FALSE;
|
|
|
|
hCost = (dlong) (est1->e_hCost *
|
|
ABS(est2->e_x0 - est1->e_x0));
|
|
vCost = (dlong) (est1->e_vCost *
|
|
ABS(est2->e_y0 - est1->e_y0));
|
|
|
|
cost = hCost + vCost;
|
|
cost += est1->e_cost0;
|
|
|
|
return (cost <= est2->e_cost0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzTrimEstimatesFunc --
|
|
*
|
|
* Throw away redundant cost estimates.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* modifies estimates list in TileCost struc attached to tile.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzTrimEstimatesFunc(tile, notUsed)
|
|
Tile *tile;
|
|
ClientData notUsed;
|
|
{
|
|
TileCosts *tc = (TileCosts *) (tile->ti_client);
|
|
Estimate *e;
|
|
Estimate *reqEstimates = NULL;
|
|
|
|
e = tc->tc_estimates;
|
|
while(e)
|
|
{
|
|
Estimate *e2;
|
|
bool found = FALSE;
|
|
|
|
/* Check if a required estimate is always as good as e */
|
|
for(e2 = reqEstimates; e2!= NULL && !found; e2=e2->e_next)
|
|
{
|
|
if(AlwaysAsGood(e2,e,tile))
|
|
{
|
|
found = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Check if a not-yet-processed estimate is always as good as e */
|
|
for(e2 = e->e_next; e2!= NULL && !found; e2=e2->e_next)
|
|
{
|
|
if(AlwaysAsGood(e2,e,tile))
|
|
{
|
|
found = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Throw away e if redundant, else save on reqEstimates list, and
|
|
* continue with next unprocessed estimate.
|
|
*/
|
|
{
|
|
Estimate *eNext = e->e_next;
|
|
if(found)
|
|
/* Throw away */
|
|
{
|
|
freeMagic((char *) e);
|
|
}
|
|
else
|
|
/* Add to required list */
|
|
{
|
|
e->e_next = reqEstimates;
|
|
reqEstimates = e;
|
|
}
|
|
e = eNext;
|
|
}
|
|
}
|
|
|
|
/* save required estimate list */
|
|
tc->tc_estimates = reqEstimates;
|
|
|
|
/* return 0 - to continue traversal of estimate plane */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzSplitTiles --
|
|
*
|
|
* Split space tiles in four directions from point - stopping at solid tiles.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side effects:
|
|
* Modifies tile structure of plane.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mzSplitTiles(plane, point)
|
|
Plane * plane;
|
|
Point * point; /* origin from which tiles split */
|
|
{
|
|
Tile *pointTile = TiSrPointNoHint(plane, point);
|
|
Tile *t;
|
|
int x = point->p_x;
|
|
int y = point->p_y;
|
|
|
|
/* Don't split from infinite points */
|
|
if(x<MIN_FINITE_COORDINATE || x>MAX_FINITE_COORDINATE ||
|
|
y<MIN_FINITE_COORDINATE || y>MAX_FINITE_COORDINATE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* split tiles to right of point */
|
|
{
|
|
/* init t to tile to right of pointTile */
|
|
NEXT_TILE_RIGHT(t,pointTile,y);
|
|
|
|
while (TiGetType(t)==TT_SPACE && BOTTOM(t)!=y && t!=plane->pl_right)
|
|
{
|
|
/* split t */
|
|
t=TiSplitY(t, y);
|
|
|
|
/* move one tile to right */
|
|
NEXT_TILE_RIGHT(t,t,y);
|
|
}
|
|
}
|
|
|
|
/* split tiles up from point */
|
|
{
|
|
/* init t to tile above pointTile */
|
|
NEXT_TILE_UP(t,pointTile,x)
|
|
|
|
while (TiGetType(t)==TT_SPACE && LEFT(t)!=x && t!=plane->pl_top)
|
|
{
|
|
/* split t */
|
|
t=TiSplitX(t, x);
|
|
|
|
/* move one tile up */
|
|
NEXT_TILE_UP(t,t,x);
|
|
}
|
|
}
|
|
|
|
/* split tiles to left of point */
|
|
{
|
|
/* init t to tile to left of pointTile */
|
|
NEXT_TILE_LEFT(t,pointTile,y);
|
|
|
|
while (TiGetType(t)==TT_SPACE && BOTTOM(t)!=y && t!=plane->pl_left)
|
|
{
|
|
/* split t */
|
|
t = TiSplitY(t, y);
|
|
|
|
/* move one tile to left */
|
|
NEXT_TILE_LEFT(t,t,y);
|
|
}
|
|
}
|
|
|
|
/* split tiles down from point */
|
|
{
|
|
/* init t to tile below pointTile */
|
|
NEXT_TILE_DOWN(t,pointTile,x);
|
|
|
|
while (TiGetType(t)==TT_SPACE && LEFT(t)!=x && t!=plane->pl_bottom)
|
|
{
|
|
/* split t */
|
|
t=TiSplitX(t, x);
|
|
|
|
/* move one tile down */
|
|
NEXT_TILE_DOWN(t,t,x);
|
|
}
|
|
}
|
|
|
|
/* finally, if point is in a SPACE tile, split it in four */
|
|
if(TiGetType(pointTile)==TT_SPACE)
|
|
{
|
|
t = pointTile;
|
|
if(x != LEFT(t))
|
|
{
|
|
Tile *tOther = TiSplitX(t, x);
|
|
if(y != BOTTOM(tOther))
|
|
TiSplitY(tOther, y);
|
|
}
|
|
if(y != BOTTOM(t))
|
|
TiSplitY(t, y);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzAssignVertexCosts --
|
|
*
|
|
* Applies Djikstra's shortest path algorithm to compute minimum cost to
|
|
* each tile corner, assuming cost along edge is minimum of cost associated
|
|
* with adjacent tiles times length of the edge. (Hor costs for hor. edges,
|
|
* vertical costs for vertical edges.)
|
|
*
|
|
* Treats estimate plane as a graph, with tile corners as vertices and
|
|
* tile edges as nodes. Weights
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Fills in vertex costs in strucs hanging of clientData fields of
|
|
* tiles in estimation plane.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mzAssignVertexCosts()
|
|
{
|
|
Heap adjHeap; /* vertices adjacent to the IN set are put here */
|
|
HeapEntry buf, *he;
|
|
Tile *t;
|
|
|
|
/* Initialize Heap */
|
|
HeapInitType(&adjHeap, 1024, FALSE, FALSE, HE_DLONG);
|
|
|
|
/* Initial at least one vertex of each dest term to zero cost and add
|
|
* to adjHeap. Zero cost will be propagated to other vertices of dest
|
|
* terms since hcost and vcost are 0 for dest tiles.
|
|
*/
|
|
{
|
|
int mzDestInitialAssignFunc();
|
|
TileTypeBitMask destOnly;
|
|
|
|
TTMaskSetOnlyType(&destOnly, TT_EST_DEST);
|
|
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzEstimatePlane,
|
|
&mzBoundingRect,
|
|
&destOnly,
|
|
mzDestInitialAssignFunc,
|
|
(ClientData) &adjHeap);
|
|
}
|
|
|
|
/* keep adding least cost ADJACENT vertex to IN until no ADJACENT vertices
|
|
* left. (Vertices adjacent to the addvertex are added to adjHeap.)
|
|
*/
|
|
while((he = HeapRemoveTop(&adjHeap,&buf))!=NULL)
|
|
{
|
|
Vertex *v = (Vertex *)(he->he_id);
|
|
if (!(v->vx_status & VX_IN))
|
|
{
|
|
/* vertex not already IN, so process it */
|
|
mzAddVertex(v,&adjHeap);
|
|
}
|
|
}
|
|
|
|
/* Free heap */
|
|
HeapKill(&adjHeap, (void (*)()) NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzAddVertex --
|
|
*
|
|
* Subroutine of mzAssignVertexCosts.
|
|
* Adds least cost vertex on adjHeap to IN set. Adds vertices adjacent to
|
|
* new IN vertex to adjHeap, or adjusts there cost if they are already there.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Modifies adjHeap and vertex strucs attached to tiles
|
|
* on estimation plane.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mzAddVertex(vxThis, adjHeap)
|
|
Vertex *vxThis;
|
|
Heap *adjHeap;
|
|
{
|
|
Tile *tThis; /* Tile vxThis is attached to */
|
|
Point loc; /* location of vxThis */
|
|
Tile *tLoc; /* Tile containing location of vxThis */
|
|
Tile *tLeft, *tRight, *tAbove, *tBelow; /* Neighbors of tLoc */
|
|
|
|
/* Mark this vertex IN */
|
|
vxThis->vx_status |= VX_IN;
|
|
|
|
/* Ignore if we're already at maximum cost */
|
|
if (vxThis->vx_cost == COST_MAX) return;
|
|
|
|
/* compute location of this vertex, and tile containing that loc */
|
|
tThis = vxThis->vx_tile;
|
|
switch (vxThis->vx_status & VX_CORNER)
|
|
{
|
|
case VX_L_LEFT:
|
|
loc.p_x = LEFT(tThis);
|
|
loc.p_y = BOTTOM(tThis);
|
|
tLoc = tThis;
|
|
break;
|
|
|
|
case VX_L_RIGHT:
|
|
loc.p_x = RIGHT(tThis);
|
|
loc.p_y = BOTTOM(tThis);
|
|
NEXT_TILE_RIGHT(tLoc, tThis, BOTTOM(tThis));
|
|
break;
|
|
|
|
case VX_U_LEFT:
|
|
loc.p_x = LEFT(tThis);
|
|
loc.p_y = TOP(tThis);
|
|
NEXT_TILE_UP(tLoc, tThis, LEFT(tThis));
|
|
break;
|
|
}
|
|
|
|
/* find tiles neighboring loc */
|
|
NEXT_TILE_LEFT(tLeft, tLoc, loc.p_y);
|
|
NEXT_TILE_RIGHT(tRight, tLoc, loc.p_y);
|
|
NEXT_TILE_UP(tAbove, tLoc, loc.p_x);
|
|
NEXT_TILE_DOWN(tBelow, tLoc, loc.p_x);
|
|
|
|
/* process adjacent vertex ABOVE */
|
|
{
|
|
Vertex *vxAbove;
|
|
int yAbove;
|
|
|
|
/* Check for no edge above */
|
|
if(LEFT(tLoc)!=loc.p_x)
|
|
goto noAbove;
|
|
|
|
if(TOP(tLeft) < TOP(tLoc))
|
|
{
|
|
/* T from left */
|
|
vxAbove = &(((TileCosts *)(RT(tLeft)->ti_client))->tc_vxLRight);
|
|
yAbove = TOP(tLeft);
|
|
}
|
|
else
|
|
{
|
|
if(LEFT(tAbove)==LEFT(tLoc))
|
|
{
|
|
/* no T */
|
|
vxAbove = &(((TileCosts *)(tAbove->ti_client))->tc_vxLLeft);
|
|
yAbove = BOTTOM(tAbove);
|
|
}
|
|
else
|
|
{
|
|
/* T from bottom */
|
|
vxAbove = &(((TileCosts *)(tLoc->ti_client))->tc_vxULeft);
|
|
yAbove = BOTTOM(tAbove);
|
|
}
|
|
}
|
|
|
|
/* adjust cost */
|
|
{
|
|
int rate, distance;
|
|
dlong newCost;
|
|
|
|
if(yAbove > MAX_FINITE_COORDINATE) goto noAbove;
|
|
|
|
rate = MIN(((TileCosts *)(tLoc->ti_client))->tc_vCost,
|
|
((TileCosts *)(tLeft->ti_client))->tc_vCost);
|
|
|
|
if(rate == INT_MAX) goto noAbove;
|
|
|
|
distance = yAbove - loc.p_y;
|
|
newCost = (dlong) (rate * distance);
|
|
newCost += vxThis->vx_cost;
|
|
|
|
if(newCost < vxAbove->vx_cost)
|
|
{
|
|
vxAbove->vx_cost = newCost;
|
|
HeapAddDLong(adjHeap, newCost, (char *) vxAbove);
|
|
}
|
|
}
|
|
noAbove:;
|
|
}
|
|
|
|
|
|
/* process adjacent vertex to RIGHT */
|
|
{
|
|
Vertex *vxRight;
|
|
int xRight;
|
|
|
|
/* Check for no edge to RIGHT */
|
|
if(BOTTOM(tLoc)!=loc.p_y)
|
|
goto noRight;
|
|
|
|
if(RIGHT(tBelow) < RIGHT(tLoc))
|
|
{
|
|
/* T from below */
|
|
vxRight = &(((TileCosts *)(TR(tBelow)->ti_client))->tc_vxULeft);
|
|
xRight = RIGHT(tBelow);
|
|
}
|
|
else
|
|
{
|
|
if(BOTTOM(tRight)==BOTTOM(tLoc))
|
|
{
|
|
/* no T */
|
|
vxRight = &(((TileCosts *)(tRight->ti_client))->tc_vxLLeft);
|
|
xRight = LEFT(tRight);
|
|
}
|
|
else
|
|
{
|
|
/* T from left */
|
|
vxRight = &(((TileCosts *)(tLoc->ti_client))->tc_vxLRight);
|
|
xRight = LEFT(tRight);
|
|
}
|
|
}
|
|
|
|
/* adjust cost */
|
|
{
|
|
int rate, distance;
|
|
dlong newCost;
|
|
|
|
if(xRight > MAX_FINITE_COORDINATE) goto noRight;
|
|
|
|
rate = MIN(
|
|
((TileCosts *)(tLoc->ti_client))->tc_hCost,
|
|
((TileCosts *)(tBelow->ti_client))->tc_hCost);
|
|
|
|
if(rate == INT_MAX) goto noRight;
|
|
|
|
distance = xRight - loc.p_x;
|
|
newCost = (dlong) (rate * distance);
|
|
newCost += vxThis->vx_cost;
|
|
|
|
if (newCost < vxRight->vx_cost)
|
|
{
|
|
vxRight->vx_cost = newCost;
|
|
HeapAddDLong(adjHeap, newCost, (char *) vxRight);
|
|
}
|
|
}
|
|
noRight:;
|
|
}
|
|
|
|
/* For going down and to the left, we want tiles to contain their
|
|
* right and upper edges. Adjust tLoc and neighbors accordingly.
|
|
* The trick is to center tLoc and neighbors around loc - (1,1).
|
|
*/
|
|
{
|
|
Point locMinus;
|
|
|
|
/* locMinus used to get tiles for loc, that contain top and right
|
|
* edges.
|
|
*/
|
|
|
|
locMinus = loc;
|
|
--(locMinus.p_x);
|
|
--(locMinus.p_y);
|
|
|
|
if(BOTTOM(tLoc)>locMinus.p_y)
|
|
NEXT_TILE_DOWN(tLoc, tLoc, loc.p_x);
|
|
if(LEFT(tLoc)>locMinus.p_x)
|
|
NEXT_TILE_LEFT(tLoc, tLoc, locMinus.p_y);
|
|
|
|
/* find tiles neighboring loc */
|
|
NEXT_TILE_LEFT(tLeft, tLoc, locMinus.p_y);
|
|
NEXT_TILE_RIGHT(tRight, tLoc, locMinus.p_y);
|
|
NEXT_TILE_UP(tAbove, tLoc, locMinus.p_x);
|
|
NEXT_TILE_DOWN(tBelow, tLoc, locMinus.p_x);
|
|
}
|
|
|
|
/* process adjacent vertex BELOW */
|
|
{
|
|
Vertex *vxBelow;
|
|
int yBelow;
|
|
|
|
/* Check for no edge below */
|
|
if(RIGHT(tLoc)!=loc.p_x)
|
|
goto noBelow;
|
|
|
|
if(BOTTOM(tRight) >= BOTTOM(tLoc))
|
|
{
|
|
/* LowerLeft of tRight */
|
|
vxBelow = &(((TileCosts *)(tRight->ti_client))->tc_vxLLeft);
|
|
yBelow = BOTTOM(tRight);
|
|
}
|
|
else
|
|
{
|
|
/* T from Left */
|
|
vxBelow = &(((TileCosts *)(tLoc->ti_client))->tc_vxLRight);
|
|
yBelow = BOTTOM(tLoc);
|
|
}
|
|
|
|
/* adjust cost */
|
|
{
|
|
int rate, distance;
|
|
dlong newCost;
|
|
|
|
if(yBelow < MIN_FINITE_COORDINATE) goto noBelow;
|
|
|
|
rate = MIN(
|
|
((TileCosts *)(tLoc->ti_client))->tc_vCost,
|
|
((TileCosts *)(tRight->ti_client))->tc_vCost);
|
|
|
|
if(rate == INT_MAX) goto noBelow;
|
|
|
|
distance = loc.p_y - yBelow;
|
|
newCost = (dlong) (rate * distance);
|
|
newCost += vxThis->vx_cost;
|
|
|
|
if(newCost < vxBelow->vx_cost)
|
|
{
|
|
vxBelow->vx_cost = newCost;
|
|
HeapAddDLong(adjHeap, newCost, (char *) vxBelow);
|
|
}
|
|
}
|
|
noBelow:;
|
|
}
|
|
|
|
/* process adjacent vertex to LEFT */
|
|
{
|
|
Vertex *vxLeft;
|
|
int xLeft;
|
|
|
|
/* Check for no edge to Left */
|
|
if(TOP(tLoc)!=loc.p_y)
|
|
goto noLeft;
|
|
|
|
if(LEFT(tAbove) >= LEFT(tLoc))
|
|
{
|
|
/* LowerLeft of tAbove */
|
|
vxLeft = &(((TileCosts *)(tAbove->ti_client))->tc_vxLLeft);
|
|
xLeft = LEFT(tAbove);
|
|
}
|
|
else
|
|
{
|
|
/* T from Bottom */
|
|
vxLeft = &(((TileCosts *)(tLoc->ti_client))->tc_vxULeft);
|
|
xLeft = LEFT(tLoc);
|
|
}
|
|
|
|
/* adjust cost */
|
|
{
|
|
int rate, distance;
|
|
dlong newCost;
|
|
|
|
if(xLeft < MIN_FINITE_COORDINATE) goto noLeft;
|
|
|
|
rate = MIN(
|
|
((TileCosts *)(tLoc->ti_client))->tc_hCost,
|
|
((TileCosts *)(tAbove->ti_client))->tc_hCost);
|
|
|
|
if(rate == INT_MAX) goto noLeft;
|
|
|
|
distance = loc.p_x - xLeft;
|
|
newCost = (dlong) (rate * distance);
|
|
newCost += vxThis->vx_cost;
|
|
|
|
if(newCost < vxLeft->vx_cost)
|
|
{
|
|
vxLeft->vx_cost = newCost;
|
|
HeapAddDLong(adjHeap, newCost, (char *) vxLeft);
|
|
}
|
|
}
|
|
noLeft:;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzEstimatedCost --
|
|
*
|
|
* Results:
|
|
* Estimated cost of route from point to destination.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
// changed from DoubleInt to dlong
|
|
dlong
|
|
mzEstimatedCost(point)
|
|
Point *point;
|
|
{
|
|
Tile *t = TiSrPointNoHint(mzEstimatePlane, point);
|
|
TileCosts *tc = ((TileCosts *) t->ti_client);
|
|
Estimate *e;
|
|
dlong bestCost;
|
|
|
|
bestCost = COST_MAX;
|
|
for (e=tc->tc_estimates; e!=NULL; e=e->e_next)
|
|
{
|
|
dlong hCost, vCost, cost;
|
|
|
|
if (e->e_hCost == INT_MAX || e->e_vCost == INT_MAX) continue;
|
|
|
|
hCost = (dlong)e->e_hCost * (dlong)ABS(point->p_x - e->e_x0);
|
|
vCost = (dlong)e->e_vCost * (dlong)ABS(point->p_y - e->e_y0);
|
|
|
|
cost = hCost + vCost;
|
|
cost += e->e_cost0;
|
|
|
|
if(cost < bestCost)
|
|
bestCost = cost;
|
|
}
|
|
|
|
return bestCost;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzDumpEstimates --
|
|
*
|
|
* Dump info in estimate plane (for debugging).
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* info written to file or via TxPrintf()
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mzDumpEstimates(area,fd)
|
|
Rect *area;
|
|
FILE *fd;
|
|
{
|
|
int mzDumpEstFunc();
|
|
|
|
if(mzEstimateExists)
|
|
{
|
|
/* Visit each tile in the Estimate plane - dumping associated info */
|
|
DBSrPaintArea(NULL, /* no hint tile */
|
|
mzEstimatePlane,
|
|
area,
|
|
&DBAllTypeBits,
|
|
mzDumpEstFunc,
|
|
(ClientData) fd);
|
|
}
|
|
else
|
|
{
|
|
TxPrintf("No estimate plane!\n");
|
|
TxPrintf("(Must ``:*ir deb noclean true'' and do a route first.)\n");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mzDumpEstFunc --
|
|
*
|
|
* Filter function called via DBSrPaintArea on behalf of mzDumpEstimates()
|
|
* above, for each estimate tile in the area of interest,
|
|
* the info associated with each tile is dumped.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Dumps info associated with tile.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mzDumpEstFunc(tile, fd)
|
|
Tile *tile;
|
|
FILE *fd;
|
|
{
|
|
Rect r;
|
|
TileCosts *tilec = (TileCosts *) tile->ti_client;
|
|
|
|
/* Get boundary of tile */
|
|
TITORECT(tile, &r);
|
|
|
|
/* dump info, to file if provided, else to screen */
|
|
if(fd)
|
|
{
|
|
fprintf(fd,"\ntile %p\t\t (x: %d to %d, y: %d to %d)\n",
|
|
tile, r.r_xbot, r.r_xtop, r.r_ybot, r.r_ytop);
|
|
fprintf(fd,"\thcost = %d ",
|
|
tilec->tc_hCost);
|
|
fprintf(fd,"vcost = %d \n",
|
|
tilec->tc_vCost);
|
|
{
|
|
char str[100];
|
|
Estimate *e;
|
|
|
|
fprintf(fd,"\tEstimates:\n");
|
|
|
|
for(e=tilec->tc_estimates; e!=NULL; e=e->e_next)
|
|
{
|
|
fprintf(fd,"\t\t%"DLONG_PREFIX"d + ABS(x - %d)*%d + ABS(y - %d)*%d\n",
|
|
e->e_cost0,e->e_x0,e->e_hCost,
|
|
e->e_y0,e->e_vCost);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TxPrintf("\ntile %x\t\t (x: %d to %d, y: %d to %d)\n",
|
|
(pointertype) tile, r.r_xbot, r.r_xtop, r.r_ybot, r.r_ytop);
|
|
TxPrintf("\thcost = %d, ",
|
|
tilec->tc_hCost);
|
|
TxPrintf("vcost = %d \n",
|
|
tilec->tc_vCost);
|
|
{
|
|
char str[100];
|
|
Estimate *e;
|
|
|
|
TxPrintf("\tEstimates:\n");
|
|
|
|
for(e=tilec->tc_estimates; e!=NULL; e=e->e_next)
|
|
{
|
|
TxPrintf("\t\t%lld + ABS(x - %d)*%d + ABS(y - %d)*%d\n",
|
|
e->e_cost0,e->e_x0,e->e_hCost,
|
|
e->e_y0,e->e_vCost);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* continue search */
|
|
return (0);
|
|
}
|