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);
|
||
}
|