2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* DBcellsearch.c --
|
|
|
|
|
*
|
|
|
|
|
* Area searching which spans cell boundaries.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * Copyright (C) 1985, 1990 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcellsrch.c,v 1.7 2010/09/15 21:53:22 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2020-12-23 21:26:50 +01:00
|
|
|
#include <string.h>
|
2022-01-07 20:56:43 +01:00
|
|
|
#include <ctype.h>
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "utils/geofast.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "database/databaseInt.h"
|
2020-05-12 18:03:38 +02:00
|
|
|
#include "dbwind/dbwind.h"
|
2017-04-25 14:41:48 +02:00
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "mzrouter/mzrouter.h"
|
|
|
|
|
|
|
|
|
|
/* Quick hack for dbScalePlanes() access to the CIF/GDS paint table */
|
|
|
|
|
|
|
|
|
|
#ifdef CIF_MODULE
|
|
|
|
|
extern PaintResultType CIFPaintTable[];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following structure is used to accumulate information about
|
|
|
|
|
* the types of tiles visible underneath a given point in the database.
|
|
|
|
|
*/
|
|
|
|
|
struct seeTypesArg
|
|
|
|
|
{
|
|
|
|
|
TileTypeBitMask *saa_mask; /* Mask of tile types seen in search */
|
|
|
|
|
Rect *saa_rect; /* Search area in root coordinates */
|
|
|
|
|
};
|
2019-03-23 00:58:47 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBSrCellPlaneArea --
|
|
|
|
|
*
|
|
|
|
|
* Searches a CellDef's cell plane and calls function func() for each
|
|
|
|
|
* cell use found.
|
|
|
|
|
*
|
|
|
|
|
* func() must be in the form:
|
|
|
|
|
*
|
|
|
|
|
* int func(CellUse *use, ClientData cdata)
|
|
|
|
|
*
|
|
|
|
|
* and must return 0 to keep the search running, or 1 to end the search.
|
|
|
|
|
*
|
|
|
|
|
* Replaces the original TiSrArea() routine, but with the function's
|
|
|
|
|
* first argument as a CellUse pointer rather than a Tile pointer,
|
|
|
|
|
* since the tile plane has been replaced with the BPlane method.
|
|
|
|
|
*
|
|
|
|
|
* Returns 1 if the func() returns 1; otherwise returns 0 to keep the
|
|
|
|
|
* search alive.
|
|
|
|
|
*
|
2022-09-27 16:58:49 +02:00
|
|
|
* NOTE: struct BPEnum has an array size 10000, causing this routine to
|
|
|
|
|
* take up a half megabyte of stack space if the variable is declared
|
|
|
|
|
* inside the local frame. Use mallocMagic() instead.
|
2019-03-23 00:58:47 +01:00
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2025-01-31 17:38:39 +01:00
|
|
|
DBSrCellPlaneArea(BPlane *plane, const Rect *rect, int (*func)(), ClientData arg)
|
2019-03-23 00:58:47 +01:00
|
|
|
{
|
2025-11-07 17:00:22 +01:00
|
|
|
BPEnum sbpe;
|
2022-09-27 16:58:49 +02:00
|
|
|
BPEnum *bpe;
|
2019-03-23 00:58:47 +01:00
|
|
|
CellUse *use;
|
|
|
|
|
int rval = 0;
|
|
|
|
|
|
2025-11-07 17:00:22 +01:00
|
|
|
/* bpe = (BPEnum *)mallocMagic(sizeof(BPEnum)); */
|
|
|
|
|
bpe = &sbpe;
|
2022-09-27 16:58:49 +02:00
|
|
|
BPEnumInit(bpe, plane, rect, BPE_OVERLAP, "DBSrCellPlaneArea");
|
2019-03-23 00:58:47 +01:00
|
|
|
|
2024-10-04 18:19:27 +02:00
|
|
|
while ((use = BPEnumNext(bpe)))
|
2019-03-23 00:58:47 +01:00
|
|
|
{
|
|
|
|
|
if ((*func)(use, arg))
|
|
|
|
|
{
|
|
|
|
|
rval = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-27 16:58:49 +02:00
|
|
|
BPEnumTerm(bpe);
|
2025-11-07 17:00:22 +01:00
|
|
|
/* freeMagic(bpe); */
|
2019-03-23 00:58:47 +01:00
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBTreeSrTiles --
|
|
|
|
|
*
|
|
|
|
|
* Recursively search downward from the supplied CellUse for
|
|
|
|
|
* all visible paint tiles matching the supplied type mask.
|
|
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(tile, cxp)
|
|
|
|
|
* Tile *tile;
|
2026-01-03 02:12:37 +01:00
|
|
|
* TileType dinfo;
|
2017-04-25 14:41:48 +02:00
|
|
|
* TreeContext *cxp;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* The SearchContext is stored in cxp->tc_scx, and the user's arg is stored
|
|
|
|
|
* in cxp->tc_filter->tf_arg.
|
|
|
|
|
*
|
|
|
|
|
* In the above, the scx transform is the net transform from the coordinates
|
|
|
|
|
* of tile to "world" coordinates (or whatever coordinates the initial
|
|
|
|
|
* transform supplied to DBTreeSrTiles was a transform to). Func returns
|
|
|
|
|
* 0 under normal conditions. If 1 is returned, it is a request to
|
|
|
|
|
* abort the search.
|
|
|
|
|
*
|
|
|
|
|
* *** WARNING ***
|
|
|
|
|
*
|
|
|
|
|
* The client procedure should not modify any of the paint planes in
|
|
|
|
|
* the cells visited by DBTreeSrTiles, because we use DBSrPaintArea
|
2019-03-23 00:58:47 +01:00
|
|
|
* as our paint-tile enumeration function.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search finished normally. 1 is returned
|
|
|
|
|
* if the search was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBTreeSrTiles(scx, mask, xMask, func, cdarg)
|
|
|
|
|
SearchContext *scx; /* Pointer to search context specifying
|
|
|
|
|
* a cell use to search, an area in the
|
|
|
|
|
* coordinates of the cell's def, and a
|
|
|
|
|
* transform back to "root" coordinates.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask *mask; /* Only tiles with a type for which
|
|
|
|
|
* a bit in this mask is on are processed.
|
|
|
|
|
*/
|
|
|
|
|
int xMask; /* All subcells are visited recursively
|
|
|
|
|
* until we encounter uses whose flags,
|
|
|
|
|
* when anded with xMask, are not
|
|
|
|
|
* equal to xMask.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply at each qualifying tile */
|
|
|
|
|
ClientData cdarg; /* Client data for above function */
|
|
|
|
|
{
|
2019-03-23 00:58:47 +01:00
|
|
|
int dbCellPlaneSrFunc();
|
2017-04-25 14:41:48 +02:00
|
|
|
TreeFilter filter;
|
|
|
|
|
|
|
|
|
|
/* Set up the filter and call the recursive filter function */
|
|
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
filter.tf_mask = mask;
|
|
|
|
|
filter.tf_xmask = xMask;
|
|
|
|
|
filter.tf_dinfo = 0;
|
|
|
|
|
filter.tf_planes = DBTechTypesToPlanes(mask);
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
return dbCellPlaneSrFunc(scx, &filter);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* DBTreeSrNMTiles --
|
|
|
|
|
* This is a variant of the above in which the search is over
|
|
|
|
|
* a non-Manhattan area.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBTreeSrNMTiles(scx, dinfo, mask, xMask, func, cdarg)
|
|
|
|
|
SearchContext *scx; /* Pointer to search context specifying
|
|
|
|
|
* a cell use to search, an area in the
|
|
|
|
|
* coordinates of the cell's def, and a
|
|
|
|
|
* transform back to "root" coordinates.
|
|
|
|
|
*/
|
|
|
|
|
TileType dinfo; /* Type containing information about the
|
|
|
|
|
* diagonal area to search.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask *mask; /* Only tiles with a type for which
|
|
|
|
|
* a bit in this mask is on are processed.
|
|
|
|
|
*/
|
|
|
|
|
int xMask; /* All subcells are visited recursively
|
|
|
|
|
* until we encounter uses whose flags,
|
|
|
|
|
* when anded with xMask, are not
|
|
|
|
|
* equal to xMask.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply at each qualifying tile */
|
|
|
|
|
ClientData cdarg; /* Client data for above function */
|
|
|
|
|
{
|
2019-03-23 00:58:47 +01:00
|
|
|
int dbCellPlaneSrFunc();
|
2017-04-25 14:41:48 +02:00
|
|
|
TreeFilter filter;
|
|
|
|
|
|
|
|
|
|
/* Set up the filter and call the recursive filter function */
|
|
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
filter.tf_mask = mask;
|
|
|
|
|
filter.tf_xmask = xMask;
|
|
|
|
|
filter.tf_dinfo = dinfo;
|
|
|
|
|
filter.tf_planes = DBTechTypesToPlanes(mask);
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
return dbCellPlaneSrFunc(scx, &filter);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2019-03-23 00:58:47 +01:00
|
|
|
* dbCellPlaneSrFunc --
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Recursive filter procedure applied to the cell by DBTreeSrTiles().
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2019-03-23 00:58:47 +01:00
|
|
|
dbCellPlaneSrFunc(scx, fp)
|
2017-04-25 14:41:48 +02:00
|
|
|
SearchContext *scx;
|
|
|
|
|
TreeFilter *fp;
|
|
|
|
|
{
|
|
|
|
|
TreeContext context;
|
|
|
|
|
CellDef *def = scx->scx_use->cu_def;
|
|
|
|
|
int pNum;
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
ASSERT(def != (CellDef *) NULL, "dbCellPlaneSrFunc");
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
|
|
|
|
|
return 0;
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
|
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
context.tc_scx = scx;
|
|
|
|
|
context.tc_filter = fp;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Apply the function first to any of the tiles in the planes
|
|
|
|
|
* for this CellUse's CellDef that match the mask.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
if (PlaneMaskHasPlane(fp->tf_planes, pNum))
|
|
|
|
|
{
|
|
|
|
|
context.tc_plane = pNum;
|
|
|
|
|
if (fp->tf_dinfo & TT_DIAGONAL)
|
|
|
|
|
{
|
|
|
|
|
// TileType dinfo = DBTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
|
|
|
|
|
TileType dinfo = DBInvTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
|
|
|
|
|
if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
|
|
|
|
|
dinfo, &scx->scx_area, fp->tf_mask,
|
|
|
|
|
fp->tf_func, (ClientData) &context))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
|
|
|
|
|
&scx->scx_area, fp->tf_mask,
|
|
|
|
|
fp->tf_func, (ClientData) &context))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now apply ourselves recursively to each of the CellUses
|
2019-03-23 00:58:47 +01:00
|
|
|
* in our cell plane.
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
if (DBCellSrArea(scx, dbCellPlaneSrFunc, (ClientData) fp))
|
2017-04-25 14:41:48 +02:00
|
|
|
return 1;
|
|
|
|
|
else return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBTreeSrUniqueTiles --
|
|
|
|
|
*
|
|
|
|
|
* Recursively search downward from the supplied CellUse for
|
|
|
|
|
* all visible paint tiles matching the supplied type mask.
|
|
|
|
|
* This routine is like DBTreeSrTiles, above, except that it will
|
|
|
|
|
* only call the specified routine ONCE for each contact type, in
|
|
|
|
|
* the home plane of that contact type. Stacked contact types will
|
|
|
|
|
* only be processed if the current search plane matches the home
|
|
|
|
|
* plane of one of the stacked contact type's residues.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search finished normally. 1 is returned
|
|
|
|
|
* if the search was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBTreeSrUniqueTiles(scx, mask, xMask, func, cdarg)
|
|
|
|
|
SearchContext *scx; /* Pointer to search context specifying
|
|
|
|
|
* a cell use to search, an area in the
|
|
|
|
|
* coordinates of the cell's def, and a
|
|
|
|
|
* transform back to "root" coordinates.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask *mask; /* Only tiles with a type for which
|
|
|
|
|
* a bit in this mask is on are processed.
|
|
|
|
|
*/
|
|
|
|
|
int xMask; /* All subcells are visited recursively
|
|
|
|
|
* until we encounter uses whose flags,
|
|
|
|
|
* when anded with xMask, are not
|
|
|
|
|
* equal to xMask.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply at each qualifying tile */
|
|
|
|
|
ClientData cdarg; /* Client data for above function */
|
|
|
|
|
{
|
2019-03-23 00:58:47 +01:00
|
|
|
int dbCellPlaneSrFunc();
|
2017-04-25 14:41:48 +02:00
|
|
|
TreeFilter filter;
|
|
|
|
|
|
|
|
|
|
/* Set up the filter and call the recursive filter function */
|
|
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
filter.tf_mask = mask;
|
|
|
|
|
filter.tf_xmask = xMask;
|
|
|
|
|
filter.tf_planes = DBTechTypesToPlanes(mask);
|
|
|
|
|
|
|
|
|
|
return dbCellUniqueTileSrFunc(scx, &filter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* dbCellUniqueTileSrFunc --
|
|
|
|
|
*
|
|
|
|
|
* Recursive filter procedure applied to the cell by DBTreeSrUniqueTiles().
|
2019-03-23 00:58:47 +01:00
|
|
|
* This is similar to dbCellPlaneSrFunc, except that for each plane searched,
|
2017-04-25 14:41:48 +02:00
|
|
|
* only the tile types having that plane as their home plane will be passed
|
|
|
|
|
* to the filter function. Contacts will therefore be processed only once.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbCellUniqueTileSrFunc(scx, fp)
|
|
|
|
|
SearchContext *scx;
|
|
|
|
|
TreeFilter *fp;
|
|
|
|
|
{
|
|
|
|
|
TreeContext context;
|
|
|
|
|
TileTypeBitMask uMask;
|
|
|
|
|
CellDef *def = scx->scx_use->cu_def;
|
|
|
|
|
int pNum;
|
|
|
|
|
|
|
|
|
|
ASSERT(def != (CellDef *) NULL, "dbCellUniqueTileSrFunc");
|
|
|
|
|
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
|
|
|
|
|
return 0;
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
|
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
context.tc_scx = scx;
|
|
|
|
|
context.tc_filter = fp;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Apply the function first to any of the tiles in the planes
|
|
|
|
|
* for this CellUse's CellDef that match the mask.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
if (PlaneMaskHasPlane(fp->tf_planes, pNum))
|
|
|
|
|
{
|
|
|
|
|
uMask = DBHomePlaneTypes[pNum];
|
|
|
|
|
TTMaskAndMask(&uMask, fp->tf_mask);
|
|
|
|
|
if (!TTMaskIsZero(&uMask))
|
|
|
|
|
{
|
|
|
|
|
context.tc_plane = pNum;
|
|
|
|
|
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
|
|
|
|
|
&scx->scx_area, &uMask, fp->tf_func,
|
|
|
|
|
(ClientData) &context))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now apply ourselves recursively to each of the CellUses
|
|
|
|
|
* in our tile plane.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (DBCellSrArea(scx, dbCellUniqueTileSrFunc, (ClientData) fp))
|
|
|
|
|
return 1;
|
|
|
|
|
else return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBNoTreeSrTiles --
|
|
|
|
|
*
|
|
|
|
|
* NOTE: THIS PROCEDURE IS EXACTLY LIKE DBTreeSrTiles EXCEPT THAT IT DOES
|
|
|
|
|
* NOT SEARCH SUBCELLS.
|
|
|
|
|
*
|
|
|
|
|
* Searches the supplied CellUse (if expanded) for
|
|
|
|
|
* all visible paint tiles matching the supplied type mask.
|
|
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(tile, cxp)
|
|
|
|
|
* Tile *tile;
|
2026-01-03 02:12:37 +01:00
|
|
|
* TileType dinfo;
|
2017-04-25 14:41:48 +02:00
|
|
|
* TreeContext *cxp;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* The SearchContext is stored in cxp->tc_scx, and the user's arg is stored
|
|
|
|
|
* in cxp->tc_filter->tf_arg.
|
|
|
|
|
*
|
|
|
|
|
* In the above, the scx transform is the net transform from the coordinates
|
|
|
|
|
* of tile to "world" coordinates (or whatever coordinates the initial
|
|
|
|
|
* transform supplied to DBTreeSrTiles was a transform to). Func returns
|
|
|
|
|
* 0 under normal conditions. If 1 is returned, it is a request to
|
|
|
|
|
* abort the search.
|
|
|
|
|
*
|
|
|
|
|
* *** WARNING ***
|
|
|
|
|
*
|
|
|
|
|
* The client procedure should not modify any of the paint planes in
|
|
|
|
|
* the cells visited by DBTreeSrTiles, because we use DBSrPaintArea
|
2019-03-23 00:58:47 +01:00
|
|
|
* as our paint-tile enumeration function.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search finished normally. 1 is returned
|
|
|
|
|
* if the search was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
DBNoTreeSrTiles(scx, mask, xMask, func, cdarg)
|
|
|
|
|
SearchContext *scx; /* Pointer to search context specifying
|
|
|
|
|
* a cell use to search, an area in the
|
|
|
|
|
* coordinates of the cell's def, and a
|
|
|
|
|
* transform back to "root" coordinates.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask *mask; /* Only tiles with a type for which
|
|
|
|
|
* a bit in this mask is on are processed.
|
|
|
|
|
*/
|
|
|
|
|
int xMask; /* All subcells are visited recursively
|
|
|
|
|
* until we encounter uses whose flags,
|
|
|
|
|
* when anded with xMask, are not
|
|
|
|
|
* equal to xMask.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply at each qualifying tile */
|
|
|
|
|
ClientData cdarg; /* Client data for above function */
|
|
|
|
|
{
|
|
|
|
|
TreeContext context;
|
|
|
|
|
TreeFilter filter;
|
|
|
|
|
CellUse *cellUse = scx->scx_use;
|
|
|
|
|
CellDef *def = cellUse->cu_def;
|
|
|
|
|
int pNum;
|
|
|
|
|
|
|
|
|
|
ASSERT(def != (CellDef *) NULL, "DBNoTreeSrTiles");
|
|
|
|
|
if (!DBDescendSubcell(cellUse, xMask))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
|
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
filter.tf_mask = mask;
|
|
|
|
|
filter.tf_xmask = xMask;
|
|
|
|
|
filter.tf_planes = DBTechTypesToPlanes(mask);
|
|
|
|
|
|
|
|
|
|
context.tc_scx = scx;
|
|
|
|
|
context.tc_filter = &filter;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Apply the function first to any of the tiles in the planes
|
|
|
|
|
* for this CellUse's CellDef that match the mask.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
if (PlaneMaskHasPlane(filter.tf_planes, pNum))
|
|
|
|
|
{
|
|
|
|
|
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
|
|
|
|
|
&scx->scx_area, mask, func, (ClientData) &context))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return normally */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBTreeSrLabels --
|
|
|
|
|
*
|
|
|
|
|
* Recursively search downward from the supplied CellUse for
|
|
|
|
|
* all visible labels attached to layers matching the supplied
|
|
|
|
|
* type mask.
|
|
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(scx, label, tpath, cdarg)
|
|
|
|
|
* SearchContext *scx;
|
|
|
|
|
* Label *label;
|
|
|
|
|
* TerminalPath *tpath;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* In the above, the use associated with scx is the parent of the
|
|
|
|
|
* CellDef containing the tile which contains the label, and the
|
|
|
|
|
* transform associated is the net transform from the coordinates
|
|
|
|
|
* of the tile to "root" coordinates. Func normally returns 0. If
|
|
|
|
|
* func returns 1, it is a request to abort the search without finding
|
|
|
|
|
* any more labels.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search terminated normally. 1 is returned
|
|
|
|
|
* if the search was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
|
|
|
|
SearchContext *scx; /* Pointer to search context specifying
|
|
|
|
|
* a cell use to search, an area in the
|
|
|
|
|
* coordinates of the cell's def, and a
|
|
|
|
|
* transform back to "root" coordinates.
|
|
|
|
|
* The area may have zero size. Labels
|
|
|
|
|
* need only touch the area.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask * mask; /* Only visit labels attached to these types */
|
|
|
|
|
int xMask; /* All subcells are visited recursively
|
|
|
|
|
* until we encounter uses whose flags,
|
|
|
|
|
* when anded with xMask, are not
|
|
|
|
|
* equal to xMask.
|
|
|
|
|
*/
|
|
|
|
|
TerminalPath *tpath; /* Pointer to a structure describing a
|
|
|
|
|
* partially filled in terminal pathname.
|
|
|
|
|
* If this pointer is NULL, we don't bother
|
|
|
|
|
* filling it in further; otherwise, we add
|
|
|
|
|
* new pathname components as we encounter
|
|
|
|
|
* them.
|
|
|
|
|
*/
|
|
|
|
|
unsigned char flags; /* Flags to denote whether labels should be
|
|
|
|
|
* searched according to the area of the
|
|
|
|
|
* attachment, the area of the label itself,
|
|
|
|
|
* or both.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply at each qualifying tile */
|
|
|
|
|
ClientData cdarg; /* Client data for above function */
|
|
|
|
|
{
|
|
|
|
|
SearchContext scx2;
|
|
|
|
|
Label *lab;
|
|
|
|
|
Rect *r = &scx->scx_area;
|
|
|
|
|
CellUse *cellUse = scx->scx_use;
|
|
|
|
|
CellDef *def = cellUse->cu_def;
|
|
|
|
|
TreeFilter filter;
|
|
|
|
|
bool is_touching;
|
|
|
|
|
int dbCellLabelSrFunc();
|
|
|
|
|
|
|
|
|
|
ASSERT(def != (CellDef *) NULL, "DBTreeSrLabels");
|
|
|
|
|
if (!DBDescendSubcell(cellUse, xMask)) return 0;
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
|
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending) break;
|
|
|
|
|
is_touching = FALSE;
|
2017-08-02 04:14:42 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if ((lab->lab_font < 0) || (flags & TF_LABEL_ATTACH))
|
2017-08-02 04:14:42 +02:00
|
|
|
{
|
|
|
|
|
/* For non-manhattan searches, label must be in or */
|
|
|
|
|
/* touch the triangle. (to-do: needs a proper */
|
|
|
|
|
/* insideness test) */
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-08-02 04:14:42 +02:00
|
|
|
if (flags & TF_LABEL_ATTACH_CORNER)
|
|
|
|
|
{
|
|
|
|
|
Rect r1 = *r;
|
|
|
|
|
Rect r2 = *r;
|
|
|
|
|
if (flags & TF_LABEL_ATTACH_NOT_NE)
|
|
|
|
|
{
|
|
|
|
|
r1.r_ytop = r->r_ybot;
|
|
|
|
|
r2.r_xtop = r->r_xbot;
|
|
|
|
|
}
|
|
|
|
|
else if (flags & TF_LABEL_ATTACH_NOT_NW)
|
|
|
|
|
{
|
|
|
|
|
r1.r_ytop = r->r_ybot;
|
|
|
|
|
r2.r_xbot = r->r_xtop;
|
|
|
|
|
}
|
|
|
|
|
else if (flags & TF_LABEL_ATTACH_NOT_SE)
|
|
|
|
|
{
|
|
|
|
|
r1.r_ybot = r->r_ytop;
|
|
|
|
|
r2.r_xtop = r->r_xbot;
|
|
|
|
|
}
|
|
|
|
|
else if (flags & TF_LABEL_ATTACH_NOT_SW)
|
|
|
|
|
{
|
|
|
|
|
r1.r_ybot = r->r_ytop;
|
|
|
|
|
r2.r_xbot = r->r_xtop;
|
|
|
|
|
}
|
2023-07-30 02:36:46 +02:00
|
|
|
is_touching = GEO_TOUCH(&lab->lab_rect, &r1) ||
|
|
|
|
|
GEO_TOUCH(&lab->lab_rect, &r2);
|
2017-08-02 04:14:42 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
is_touching = GEO_TOUCH(&lab->lab_rect, r);
|
|
|
|
|
}
|
2020-02-14 15:36:30 +01:00
|
|
|
if (!is_touching && (flags & TF_LABEL_DISPLAY) && lab->lab_font >= 0)
|
|
|
|
|
{
|
|
|
|
|
/* Check against bounds of the rendered label text */
|
2017-04-25 14:41:48 +02:00
|
|
|
is_touching = GEO_TOUCH(&lab->lab_bbox, r);
|
2020-02-14 15:36:30 +01:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (is_touching && TTMaskHasType(mask, lab->lab_type))
|
|
|
|
|
if ((*func)(scx, lab, tpath, cdarg))
|
|
|
|
|
return (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
filter.tf_mask = mask;
|
|
|
|
|
filter.tf_xmask = xMask;
|
|
|
|
|
filter.tf_tpath = tpath;
|
|
|
|
|
filter.tf_flags = flags;
|
|
|
|
|
/* filter.tf_planes is unused */
|
|
|
|
|
|
|
|
|
|
/* Visit each child CellUse recursively.
|
|
|
|
|
* This code is a bit tricky because the area can have zero size.
|
|
|
|
|
* This would cause subcells never to be examined. What we do is
|
|
|
|
|
* to expand the area by 1 here, then require the labels to OVERLAP
|
|
|
|
|
* instead of just TOUCH. Be careful when expanding: can't expand
|
|
|
|
|
* any coordinate past infinity.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
scx2 = *scx;
|
|
|
|
|
if (scx2.scx_area.r_xbot > TiPlaneRect.r_xbot) scx2.scx_area.r_xbot -= 1;
|
|
|
|
|
if (scx2.scx_area.r_ybot > TiPlaneRect.r_ybot) scx2.scx_area.r_ybot -= 1;
|
|
|
|
|
if (scx2.scx_area.r_xtop < TiPlaneRect.r_xtop) scx2.scx_area.r_xtop += 1;
|
|
|
|
|
if (scx2.scx_area.r_ytop < TiPlaneRect.r_ytop) scx2.scx_area.r_ytop += 1;
|
|
|
|
|
if (DBCellSrArea(&scx2, dbCellLabelSrFunc, (ClientData) &filter))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* dbCellLabelSrFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter procedure applied to subcells by DBTreeSrLabels().
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbCellLabelSrFunc(scx, fp)
|
|
|
|
|
SearchContext *scx;
|
|
|
|
|
TreeFilter *fp;
|
|
|
|
|
{
|
|
|
|
|
Label *lab;
|
|
|
|
|
Rect *r = &scx->scx_area;
|
2025-01-31 20:46:43 +01:00
|
|
|
const TileTypeBitMask *mask = fp->tf_mask;
|
2017-04-25 14:41:48 +02:00
|
|
|
CellDef *def = scx->scx_use->cu_def;
|
|
|
|
|
char *tnext;
|
|
|
|
|
int result;
|
|
|
|
|
bool has_overlap;
|
|
|
|
|
|
|
|
|
|
ASSERT(def != (CellDef *) NULL, "dbCellLabelSrFunc");
|
|
|
|
|
if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask)) return 0;
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
|
|
|
|
return 0;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2022-03-08 19:55:07 +01:00
|
|
|
/* Do not add a path name of a top level window */
|
|
|
|
|
if (strncmp(scx->scx_use->cu_id, "Topmost ", 8))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2022-03-08 19:55:07 +01:00
|
|
|
if (fp->tf_tpath != (TerminalPath *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TerminalPath *tp = fp->tf_tpath;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2022-03-08 19:55:07 +01:00
|
|
|
tnext = tp->tp_next;
|
|
|
|
|
tp->tp_next = DBPrintUseId(scx, tp->tp_next, tp->tp_last-tp->tp_next,
|
2017-04-25 14:41:48 +02:00
|
|
|
FALSE);
|
2022-03-08 19:55:07 +01:00
|
|
|
if (tp->tp_next < tp->tp_last)
|
|
|
|
|
{
|
|
|
|
|
*(tp->tp_next++) = '/';
|
|
|
|
|
*(tp->tp_next) = '\0';
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Apply the function first to any of the labels in this def. */
|
|
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
{
|
|
|
|
|
has_overlap = FALSE;
|
|
|
|
|
if ((lab->lab_font < 0) || (fp->tf_flags & TF_LABEL_ATTACH))
|
|
|
|
|
has_overlap = GEO_OVERLAP(&lab->lab_rect, r);
|
|
|
|
|
if (!has_overlap && (fp->tf_flags & TF_LABEL_DISPLAY) && (lab->lab_font >= 0))
|
|
|
|
|
has_overlap = GEO_OVERLAP(&lab->lab_bbox, r);
|
|
|
|
|
|
|
|
|
|
if (has_overlap && TTMaskHasType(mask, lab->lab_type))
|
|
|
|
|
{
|
|
|
|
|
if ((*fp->tf_func)(scx, lab, fp->tf_tpath, fp->tf_arg))
|
|
|
|
|
{
|
|
|
|
|
result = 1;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now visit each child use recursively */
|
|
|
|
|
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
|
|
|
|
result = 1;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
/* Remove the trailing pathname component from the TerminalPath */
|
|
|
|
|
if (fp->tf_tpath != (TerminalPath *) NULL)
|
|
|
|
|
{
|
|
|
|
|
fp->tf_tpath->tp_next = tnext;
|
|
|
|
|
*tnext = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBTreeSrCells --
|
|
|
|
|
*
|
|
|
|
|
* Recursively search downward from the supplied CellUse for
|
|
|
|
|
* all CellUses whose parents are expanded but which themselves
|
|
|
|
|
* are unexpanded.
|
|
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(scx, cdarg)
|
|
|
|
|
* SearchContext *scx;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* In the above, the transform scx->scx_trans is from coordinates of
|
|
|
|
|
* the def of scx->scx_use to the "root". The array indices
|
|
|
|
|
* scx->scx_x and scx->scx_y identify this element if it is a
|
|
|
|
|
* component of an array. Func normally returns 0. If func returns
|
|
|
|
|
* 1, then the search is aborted. If func returns 2, then all
|
|
|
|
|
* remaining elements of the current array are skipped, but the
|
|
|
|
|
* search is not aborted.
|
|
|
|
|
*
|
2021-01-06 17:35:03 +01:00
|
|
|
* NOTE: Unlike DBTreeSrTiles and DBTreeSrLabels, the function is not
|
|
|
|
|
* applied to the top level cell, only to descendents.
|
|
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* Each element of an array is returned separately.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search terminated normally. 1 is
|
|
|
|
|
* returned if it was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBTreeSrCells(scx, xMask, func, cdarg)
|
|
|
|
|
SearchContext *scx; /* Pointer to search context specifying a cell use to
|
|
|
|
|
* search, an area in the coordinates of the cell's
|
|
|
|
|
* def, and a transform back to "root" coordinates.
|
|
|
|
|
*/
|
|
|
|
|
int xMask; /* All subcells are visited recursively until we
|
|
|
|
|
* encounter uses whose flags, when anded with
|
|
|
|
|
* xMask, are not equal to xMask. Func is called
|
|
|
|
|
* for these cells. A zero mask means all cells in
|
|
|
|
|
* the root use are considered not to be expanded,
|
|
|
|
|
* and hence are passed to func.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply to each qualifying cell */
|
|
|
|
|
ClientData cdarg; /* Client data for above function */
|
|
|
|
|
{
|
|
|
|
|
int dbTreeCellSrFunc();
|
|
|
|
|
CellUse *cellUse = scx->scx_use;
|
|
|
|
|
TreeContext context;
|
|
|
|
|
TreeFilter filter;
|
|
|
|
|
|
|
|
|
|
if (!DBDescendSubcell(cellUse, xMask))
|
|
|
|
|
return 0;
|
|
|
|
|
if ((cellUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(cellUse->cu_def, TRUE, TRUE, NULL))
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
context.tc_scx = scx;
|
|
|
|
|
context.tc_filter = &filter;
|
|
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
filter.tf_xmask = xMask;
|
|
|
|
|
|
|
|
|
|
if (DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) &filter))
|
|
|
|
|
return 1;
|
|
|
|
|
else return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* dbTreeCellSrFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter procedure applied to subcells by DBTreeSrCells().
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
|
int
|
|
|
|
|
dbTreeCellSrFunc(scx, fp)
|
|
|
|
|
SearchContext *scx; /* Pointer to context containing a
|
|
|
|
|
* CellUse and a transform from coord-
|
|
|
|
|
* inates of the def of the use to the
|
|
|
|
|
* "root" of the search.
|
|
|
|
|
*/
|
|
|
|
|
TreeFilter *fp;
|
|
|
|
|
{
|
|
|
|
|
CellUse *use = scx->scx_use;
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
/* DBDescendSubcell treats a zero expand mask as "expanded everywhere",
|
|
|
|
|
* whereas we want it to mean "expanded nowhere". Handle specially.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((fp->tf_xmask == CU_DESCEND_NO_LOCK) && (use->cu_flags & CU_LOCKED))
|
|
|
|
|
return 2;
|
2021-01-06 16:33:43 +01:00
|
|
|
else if (!DBDescendSubcell(use, fp->tf_xmask))
|
|
|
|
|
return (*fp->tf_func)(scx, fp->tf_arg);
|
2017-04-25 14:41:48 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((use->cu_def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(use->cu_def, TRUE, TRUE, NULL))
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2021-01-06 16:33:43 +01:00
|
|
|
if (fp->tf_xmask == CU_DESCEND_ALL)
|
|
|
|
|
{
|
|
|
|
|
result = (*fp->tf_func)(scx, fp->tf_arg);
|
|
|
|
|
if (result != 0) return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Run recursively on children in search area */
|
|
|
|
|
return DBCellSrArea(scx, dbTreeCellSrFunc, (ClientData) fp);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBSeeTypesAll --
|
|
|
|
|
*
|
|
|
|
|
* Set a TileTypeBitMask of all visible tiles beneath the given rectangle.
|
|
|
|
|
* "Beneath" in this case means "completely containing".
|
|
|
|
|
* The search takes place recursively down to all expanded cells beneath
|
|
|
|
|
* rootUse.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Sets the TileTypeBitMask pointed to by 'mask' to all types beneath
|
|
|
|
|
* the rectangle.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBSeeTypesAll(rootUse, rootRect, xMask, mask)
|
|
|
|
|
CellUse *rootUse; /* CellUse from which to begin search */
|
|
|
|
|
Rect *rootRect; /* Clipping rectangle in coordinates of CellUse's def */
|
|
|
|
|
int xMask; /* Expansion mask for DBTreeSrTiles() */
|
|
|
|
|
TileTypeBitMask *mask; /* Mask to set */
|
|
|
|
|
{
|
|
|
|
|
int dbSeeTypesAllSrFunc();
|
|
|
|
|
SearchContext scontext;
|
|
|
|
|
|
|
|
|
|
scontext.scx_use = rootUse;
|
|
|
|
|
scontext.scx_trans = GeoIdentityTransform;
|
|
|
|
|
scontext.scx_area = *rootRect;
|
|
|
|
|
|
|
|
|
|
TTMaskZero(mask);
|
|
|
|
|
(void) DBTreeSrTiles(&scontext, &DBAllTypeBits, xMask,
|
|
|
|
|
dbSeeTypesAllSrFunc, (ClientData) mask);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* dbSeeTypesAllSrFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter procedure applied to tiles by DBSeeTypesAll() above.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-03 02:12:37 +01:00
|
|
|
dbSeeTypesAllSrFunc(tile, dinfo, cxp)
|
2017-04-25 14:41:48 +02:00
|
|
|
Tile *tile;
|
2026-01-03 02:12:37 +01:00
|
|
|
TileType dinfo;
|
2017-04-25 14:41:48 +02:00
|
|
|
TreeContext *cxp;
|
|
|
|
|
{
|
|
|
|
|
Rect tileRect;
|
|
|
|
|
TileTypeBitMask *mask = (TileTypeBitMask *) cxp->tc_filter->tf_arg;
|
|
|
|
|
Rect *area = &cxp->tc_scx->scx_area;
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &tileRect);
|
|
|
|
|
if (GEO_OVERLAP((&tileRect), area))
|
|
|
|
|
{
|
|
|
|
|
if (IsSplit(tile))
|
2026-01-03 02:12:37 +01:00
|
|
|
TTMaskSetType(mask, (dinfo & TT_SIDE) ?
|
2017-04-25 14:41:48 +02:00
|
|
|
SplitRightType(tile) : SplitLeftType(tile));
|
|
|
|
|
else
|
|
|
|
|
TTMaskSetType(mask, TiGetType(tile));
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBSrRoots --
|
|
|
|
|
*
|
|
|
|
|
* Apply the supplied procedure to each CellUse that is a root of
|
|
|
|
|
* the given base CellDef. A root is a CellUse with no parent def.
|
|
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(cellUse, transform, cdarg)
|
|
|
|
|
* CellUse *cellUse;
|
|
|
|
|
* Transform *transform;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* Transform is from coordinates of baseDef to those of the def of cellUse.
|
|
|
|
|
* Func normally returns 0. If it returns 1 then the search is aborted.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search terminated normally. 1 is returned
|
|
|
|
|
* if it was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBSrRoots(baseDef, transform, func, cdarg)
|
|
|
|
|
CellDef *baseDef; /* Base CellDef, all of whose ancestors are
|
|
|
|
|
* searched for.
|
|
|
|
|
*/
|
|
|
|
|
Transform *transform; /* Transform from original baseDef to current
|
|
|
|
|
* baseDef.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply at each root cellUse */
|
|
|
|
|
ClientData cdarg; /* Client data for above function */
|
|
|
|
|
{
|
|
|
|
|
CellUse *parentUse;
|
|
|
|
|
int xoff, yoff, x, y;
|
|
|
|
|
Transform baseToParent, t;
|
|
|
|
|
|
|
|
|
|
if (baseDef == (CellDef *) NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
for (parentUse = baseDef->cd_parents; parentUse != NULL;
|
|
|
|
|
parentUse = parentUse->cu_nextuse)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending) return 1;
|
|
|
|
|
if (parentUse->cu_parent == (CellDef *) NULL)
|
|
|
|
|
{
|
|
|
|
|
GeoTransTrans(transform, &parentUse->cu_transform, &baseToParent);
|
|
|
|
|
if ((*func)(parentUse, &baseToParent, cdarg)) return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (x = parentUse->cu_xlo; x <= parentUse->cu_xhi; x++)
|
|
|
|
|
for (y = parentUse->cu_ylo; y <= parentUse->cu_yhi; y++)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
xoff = (x - parentUse->cu_xlo) * parentUse->cu_xsep;
|
|
|
|
|
yoff = (y - parentUse->cu_ylo) * parentUse->cu_ysep;
|
|
|
|
|
GeoTranslateTrans(transform, xoff, yoff, &t);
|
|
|
|
|
GeoTransTrans(&t, &parentUse->cu_transform, &baseToParent);
|
|
|
|
|
if (DBSrRoots(parentUse->cu_parent, &baseToParent,
|
|
|
|
|
func, cdarg)) return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBIsAncestor --
|
|
|
|
|
*
|
|
|
|
|
* Determine if cellDef1 is an ancestor of cellDef2.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if cellDef1 is an ancestor of cellDef2, FALSE if not.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
DBIsAncestor(cellDef1, cellDef2)
|
|
|
|
|
CellDef *cellDef1; /* Potential ancestor */
|
|
|
|
|
CellDef *cellDef2; /* Potential descendant -- this is where we
|
|
|
|
|
* start the search.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
CellUse *parentUse;
|
|
|
|
|
CellDef *parentDef;
|
|
|
|
|
|
|
|
|
|
if (cellDef1 == cellDef2)
|
|
|
|
|
return (TRUE);
|
|
|
|
|
|
|
|
|
|
for (parentUse = cellDef2->cd_parents; parentUse != NULL;
|
|
|
|
|
parentUse = parentUse->cu_nextuse)
|
|
|
|
|
{
|
|
|
|
|
if ((parentDef = parentUse->cu_parent) != (CellDef *) NULL)
|
|
|
|
|
if (DBIsAncestor(cellDef1, parentDef))
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBCellSrArea --
|
|
|
|
|
*
|
|
|
|
|
* Apply the supplied procedure to each of the cellUses found in the
|
|
|
|
|
* given area in the subcell plane of the child def of the supplied
|
|
|
|
|
* search context.
|
|
|
|
|
*
|
|
|
|
|
* The procedure is applied to each array element in each cell use that
|
|
|
|
|
* overlaps the clipping rectangle. The scx_x and scx_y parts of
|
|
|
|
|
* the SearchContext passed to the filter function correspond to the
|
|
|
|
|
* array element being visited. The same CellUse is, of course, passed
|
|
|
|
|
* as scx_use for all elements of the array.
|
|
|
|
|
*
|
|
|
|
|
* The array elements are visited by varying the X coordinate fastest.
|
|
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(scx, cdarg)
|
|
|
|
|
* SearchContext *scx;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* Func normally returns 0. If it returns 1 then the search is
|
|
|
|
|
* aborted. If it returns 2, then any remaining elements in the
|
|
|
|
|
* current array are skipped.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search terminated normally. 1 is
|
|
|
|
|
* returned if it was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBCellSrArea(scx, func, cdarg)
|
|
|
|
|
SearchContext *scx;
|
|
|
|
|
/* Pointer to search context specifying a cell use to
|
|
|
|
|
* search, an area in the coordinates of the cell's
|
|
|
|
|
* def, and a transform back to "root" coordinates.
|
|
|
|
|
* The area may have zero size.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply at every tile found */
|
|
|
|
|
ClientData cdarg; /* Argument to pass to function */
|
|
|
|
|
{
|
|
|
|
|
TreeFilter filter;
|
|
|
|
|
TreeContext context;
|
|
|
|
|
int dbCellSrFunc();
|
|
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
context.tc_filter = &filter;
|
|
|
|
|
context.tc_scx = scx;
|
|
|
|
|
|
|
|
|
|
if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(scx->scx_use->cu_def, TRUE, TRUE, NULL))
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
if (DBSrCellPlaneArea(scx->scx_use->cu_def->cd_cellPlane,
|
|
|
|
|
&scx->scx_area, dbCellSrFunc, (ClientData) &context))
|
2017-04-25 14:41:48 +02:00
|
|
|
return 1;
|
2019-03-23 00:58:47 +01:00
|
|
|
return 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbCellSrFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter procedure for DBCellSrArea. Applies the procedure given
|
2019-03-23 00:58:47 +01:00
|
|
|
* to DBCellSrArea to any of the CellUses in the given area.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is normally returned, and 1 is returned if an abort occurred.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2019-03-23 00:58:47 +01:00
|
|
|
dbCellSrFunc(use, cxp)
|
|
|
|
|
CellUse *use;
|
2017-04-25 14:41:48 +02:00
|
|
|
TreeContext *cxp;
|
|
|
|
|
{
|
|
|
|
|
TreeFilter *fp = cxp->tc_filter;
|
|
|
|
|
SearchContext *scx = cxp->tc_scx;
|
|
|
|
|
Rect *bbox;
|
|
|
|
|
SearchContext newScx;
|
|
|
|
|
Transform t, tinv;
|
|
|
|
|
int xlo, xhi, ylo, yhi, xbase, ybase, xsep, ysep, clientResult;
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
bbox = &use->cu_bbox;
|
|
|
|
|
newScx.scx_use = use;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
/* If not an array element, life is much simpler */
|
|
|
|
|
if (use->cu_xlo == use->cu_xhi && use->cu_ylo == use->cu_yhi)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2019-03-23 00:58:47 +01:00
|
|
|
newScx.scx_x = use->cu_xlo, newScx.scx_y = use->cu_yhi;
|
|
|
|
|
if (SigInterruptPending) return 1;
|
|
|
|
|
GEOINVERTTRANS(&use->cu_transform, &tinv);
|
|
|
|
|
GeoTransTrans(&use->cu_transform, &scx->scx_trans,
|
2017-04-25 14:41:48 +02:00
|
|
|
&newScx.scx_trans);
|
2019-03-23 00:58:47 +01:00
|
|
|
GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
|
|
|
|
|
if ((*fp->tf_func)(&newScx, fp->tf_arg) == 1)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
/*
|
|
|
|
|
* More than a single array element;
|
|
|
|
|
* check to see which ones overlap our search area.
|
|
|
|
|
*/
|
|
|
|
|
DBArrayOverlap(use, &scx->scx_area, &xlo, &xhi, &ylo, &yhi);
|
|
|
|
|
xsep = (use->cu_xlo > use->cu_xhi) ? -use->cu_xsep : use->cu_xsep;
|
|
|
|
|
ysep = (use->cu_ylo > use->cu_yhi) ? -use->cu_ysep : use->cu_ysep;
|
|
|
|
|
for (newScx.scx_y = ylo; newScx.scx_y <= yhi; newScx.scx_y++)
|
|
|
|
|
for (newScx.scx_x = xlo; newScx.scx_x <= xhi; newScx.scx_x++)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending) return 1;
|
|
|
|
|
xbase = xsep * (newScx.scx_x - use->cu_xlo);
|
|
|
|
|
ybase = ysep * (newScx.scx_y - use->cu_ylo);
|
|
|
|
|
GeoTransTranslate(xbase, ybase, &use->cu_transform, &t);
|
|
|
|
|
GEOINVERTTRANS(&t, &tinv);
|
|
|
|
|
GeoTransTrans(&t, &scx->scx_trans, &newScx.scx_trans);
|
|
|
|
|
GEOTRANSRECT(&tinv, &scx->scx_area, &newScx.scx_area);
|
|
|
|
|
clientResult = (*fp->tf_func)(&newScx, fp->tf_arg);
|
|
|
|
|
if (clientResult == 2) return 0;
|
|
|
|
|
else if (clientResult == 1) return 1;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
2019-03-23 00:58:47 +01:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBCellEnum --
|
|
|
|
|
*
|
2019-03-23 00:58:47 +01:00
|
|
|
* Apply the supplied procedure once to each CellUse in the subcell
|
2017-04-25 14:41:48 +02:00
|
|
|
* plane of the supplied CellDef. This procedure is not a geometric
|
2019-03-23 00:58:47 +01:00
|
|
|
* search, but rather a hierarchical enumeration. Use DBSrCellPlaneArea()
|
|
|
|
|
* for geometric searches over an area.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(use, cdarg)
|
|
|
|
|
* CellUse *use;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* Func returns 0 normally, 1 to abort the search.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 if search terminated normally, 1 if it aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBCellEnum(cellDef, func, cdarg)
|
|
|
|
|
CellDef *cellDef; /* Def whose subcell plane is to be searched */
|
|
|
|
|
int (*func)(); /* Function to apply at every tile found */
|
|
|
|
|
ClientData cdarg; /* Argument to pass to function */
|
|
|
|
|
{
|
|
|
|
|
TreeFilter filter;
|
|
|
|
|
int dbEnumFunc();
|
|
|
|
|
|
|
|
|
|
filter.tf_func = func;
|
|
|
|
|
filter.tf_arg = cdarg;
|
|
|
|
|
if ((cellDef->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(cellDef, TRUE, TRUE, NULL))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
if (DBSrCellPlaneArea(cellDef->cd_cellPlane,
|
2017-04-25 14:41:48 +02:00
|
|
|
&TiPlaneRect, dbEnumFunc, (ClientData) &filter))
|
|
|
|
|
return 1;
|
|
|
|
|
else return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbEnumFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter procedure for DBCellEnum. Applies the procedure given
|
2019-03-23 00:58:47 +01:00
|
|
|
* to DBCellEnum to the visited CellUse.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 normally, 1 if abort occurred.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever side effects are brought about by applying the
|
|
|
|
|
* procedure supplied.
|
|
|
|
|
*
|
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2019-03-23 00:58:47 +01:00
|
|
|
dbEnumFunc(use, fp)
|
|
|
|
|
CellUse *use;
|
2017-04-25 14:41:48 +02:00
|
|
|
TreeFilter *fp;
|
|
|
|
|
{
|
|
|
|
|
Rect *bbox;
|
|
|
|
|
|
2019-03-23 00:58:47 +01:00
|
|
|
bbox = &use->cu_bbox;
|
|
|
|
|
if ((*fp->tf_func)(use, fp->tf_arg)) return 1;
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2019-03-23 00:58:47 +01:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBArraySr --
|
|
|
|
|
*
|
|
|
|
|
* Finds all elements of an array that fall in a particular area
|
|
|
|
|
* of the parent, and calls func for each element found.
|
|
|
|
|
*
|
|
|
|
|
* The procedure should be of the following form:
|
|
|
|
|
* int
|
|
|
|
|
* func(cellUse, trans, x, y, cdarg)
|
|
|
|
|
* CellUse *celluse;
|
|
|
|
|
* Transform *trans;
|
|
|
|
|
* int x, y;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
* {}
|
|
|
|
|
*
|
|
|
|
|
* In the above, cellUse is the original cellUse, trans is
|
|
|
|
|
* a transformation from the coordinates of the cell def to
|
|
|
|
|
* the coordinates of the use (for this array element), x and
|
|
|
|
|
* y are the indices of this array element, and cdarg is
|
|
|
|
|
* the ClientData supplied to us. If 1 is returned by func,
|
|
|
|
|
* it is a signal to abort the search.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 is returned if the search finished normally. 1 is returned
|
|
|
|
|
* if the search was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever func does.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBArraySr(use, searchArea, func, cdarg)
|
|
|
|
|
CellUse *use; /* CellUse of array to be searched. */
|
|
|
|
|
Rect *searchArea; /* Area of interest, given in the
|
|
|
|
|
* coordinates of the parent (i.e. the
|
|
|
|
|
* cell use, not def). Must overlap
|
|
|
|
|
* the array bounding box.
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Function to apply for each overlapping
|
|
|
|
|
* array element.
|
|
|
|
|
*/
|
|
|
|
|
ClientData cdarg; /* Client-specific info to give to func. */
|
|
|
|
|
{
|
|
|
|
|
int xlo, xhi, ylo, yhi, x, y;
|
|
|
|
|
int xsep, ysep, xbase, ybase;
|
|
|
|
|
Transform t;
|
|
|
|
|
|
|
|
|
|
DBArrayOverlap(use, searchArea, &xlo, &xhi, &ylo, &yhi);
|
|
|
|
|
if (use->cu_xlo > use->cu_xhi) xsep = -use->cu_xsep;
|
|
|
|
|
else xsep = use->cu_xsep;
|
|
|
|
|
if (use->cu_ylo > use->cu_yhi) ysep = -use->cu_ysep;
|
|
|
|
|
else ysep = use->cu_ysep;
|
|
|
|
|
for (y = ylo; y <= yhi; y++)
|
|
|
|
|
for (x = xlo; x <= xhi; x++)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending) return 1;
|
|
|
|
|
xbase = xsep * (x - use->cu_xlo);
|
|
|
|
|
ybase = ysep * (y - use->cu_ylo);
|
|
|
|
|
GeoTransTranslate(xbase, ybase, &use->cu_transform, &t);
|
|
|
|
|
if ((*func)(use, &t, x, y, cdarg)) return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Linked list structures for tile, celldef, and celluse enumeration */
|
|
|
|
|
|
|
|
|
|
typedef struct LT1 /* A linked tile record */
|
|
|
|
|
{
|
|
|
|
|
Tile *tile; /* Pointer to a tile */
|
|
|
|
|
struct LT1 *t_next; /* Pointer to another linked tile record */
|
|
|
|
|
} LinkedTile;
|
|
|
|
|
|
|
|
|
|
typedef struct LCD1 /* A linked celldef record */
|
|
|
|
|
{
|
|
|
|
|
CellDef *cellDef; /* Pointer to a celldef */
|
|
|
|
|
struct LCD1 *cd_next; /* Pointer to another linked celldef record */
|
|
|
|
|
} LinkedCellDef;
|
|
|
|
|
|
|
|
|
|
typedef struct LCU1 /* A linked celluse record */
|
|
|
|
|
{
|
|
|
|
|
CellUse *cellUse; /* Pointer to a celluse */
|
|
|
|
|
struct LCU1 *cu_next; /* Pointer to another linked celluse record */
|
|
|
|
|
} LinkedCellUse;
|
|
|
|
|
|
2020-03-20 18:40:16 +01:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBMovePoint ---
|
|
|
|
|
*
|
|
|
|
|
* Move a point by a position (origx, origy). Ignore positions which
|
|
|
|
|
* are marked as (M)INFINITY.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if the point was moved (point position was not infinite)
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Point structure pointed to by the first argument is repositioned.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
DBMovePoint(p, origx, origy)
|
|
|
|
|
Point *p;
|
|
|
|
|
int origx, origy;
|
|
|
|
|
{
|
|
|
|
|
int result = FALSE;
|
|
|
|
|
if ((p->p_x < (INFINITY - 2)) && (p->p_x > (MINFINITY + 2)))
|
|
|
|
|
{
|
|
|
|
|
p->p_x -= origx;
|
|
|
|
|
result = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if ((p->p_y < (INFINITY + 2)) && (p->p_y > (MINFINITY + 2)))
|
|
|
|
|
{
|
|
|
|
|
p->p_y -= origy;
|
|
|
|
|
result = TRUE;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBScaleValue ---
|
|
|
|
|
*
|
|
|
|
|
* Scale an integer by a factor of (scalen / scaled). Always round down.
|
|
|
|
|
* this requires correcting integer arithmetic for negative numbers on
|
|
|
|
|
* the division step. Values representing INFINITY are not scaled.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if the value does not scale exactly, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Integer value passed as pointer is scaled, unless it represents
|
|
|
|
|
* an INFINITY measure.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
DBScaleValue(v, n, d)
|
|
|
|
|
int *v, n, d;
|
|
|
|
|
{
|
|
|
|
|
dlong llv = (dlong)(*v);
|
|
|
|
|
|
|
|
|
|
if ((llv < (dlong)(INFINITY - 2)) && (llv > (dlong)(MINFINITY + 2)))
|
|
|
|
|
{
|
|
|
|
|
llv *= (dlong)n;
|
|
|
|
|
|
|
|
|
|
if (llv > 0)
|
|
|
|
|
llv /= (dlong)d;
|
|
|
|
|
else if (llv < 0)
|
|
|
|
|
llv = ((llv + 1) / (dlong)d) - 1;
|
|
|
|
|
*v = (int)llv;
|
|
|
|
|
|
|
|
|
|
/* Hopefully we do not reach this error. If we do, there's */
|
|
|
|
|
/* not much we can do about it except to increase Magic's */
|
|
|
|
|
/* internal Point structure to hold 8-byte integer values. */
|
|
|
|
|
|
|
|
|
|
if ((dlong)(*v) != llv)
|
|
|
|
|
TxError("ERROR: ARITHMETIC OVERFLOW in DBScaleValue()!\n");
|
|
|
|
|
}
|
|
|
|
|
return (((*v) % d) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBScalePoint ---
|
|
|
|
|
*
|
|
|
|
|
* Scale a point by a factor of (scalen / scaled). Always round down.
|
|
|
|
|
* this requires correcting integer arithmetic for negative numbers on
|
|
|
|
|
* the division step.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if the point does not scale exactly, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Point structure pointed to by the first argument is scaled.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
DBScalePoint(p, n, d)
|
|
|
|
|
Point *p;
|
|
|
|
|
int n, d;
|
|
|
|
|
{
|
|
|
|
|
bool result;
|
|
|
|
|
result = DBScaleValue(&p->p_x, n, d);
|
|
|
|
|
result |= DBScaleValue(&p->p_y, n, d);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBScaleEverything ---
|
|
|
|
|
*
|
|
|
|
|
* Scale all geometry by a factor of (scalen / scaled). This procedure
|
|
|
|
|
* cannot be undone!
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* Every single tile, label, and cell is altered.
|
|
|
|
|
* Geometry may be irrevocably distorted if transformed measurements
|
|
|
|
|
* would be sub-integer. The MODIFIED flag is set on any cell for
|
|
|
|
|
* which any internal geometry does not scale precisely.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBScaleEverything(scalen, scaled)
|
|
|
|
|
int scalen, scaled;
|
|
|
|
|
{
|
2017-09-26 20:09:35 +02:00
|
|
|
void ToolScaleBox();
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
int dbCellDefEnumFunc();
|
|
|
|
|
LinkedCellDef *lhead, *lcd;
|
|
|
|
|
|
|
|
|
|
SigDisableInterrupts();
|
|
|
|
|
|
|
|
|
|
lhead = NULL;
|
2020-05-23 23:13:14 +02:00
|
|
|
(void) DBCellSrDefs(0, dbCellDefEnumFunc, (ClientData) &lhead);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Apply scaling function to each CellDef */
|
|
|
|
|
|
|
|
|
|
lcd = lhead;
|
|
|
|
|
while (lcd != NULL)
|
|
|
|
|
{
|
|
|
|
|
dbScaleCell(lcd->cellDef, scalen, scaled);
|
|
|
|
|
lcd = lcd->cd_next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free the linked CellDef list */
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
lcd = lhead;
|
|
|
|
|
while (lcd != NULL)
|
|
|
|
|
{
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1(&mm1, (char *)lcd);
|
2017-04-25 14:41:48 +02:00
|
|
|
lcd = lcd->cd_next;
|
|
|
|
|
}
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2020-05-12 18:03:38 +02:00
|
|
|
/* Scale all elements */
|
|
|
|
|
DBWScaleElements(scalen, scaled);
|
|
|
|
|
|
2025-06-07 10:22:04 +02:00
|
|
|
#ifdef ROUTE_MODULE
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Recovery of global plane pointers */
|
|
|
|
|
MZAttachHintPlanes();
|
2025-06-07 10:22:04 +02:00
|
|
|
#endif
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2017-09-26 20:09:35 +02:00
|
|
|
/* Modify root box */
|
|
|
|
|
ToolScaleBox(scalen, scaled);
|
|
|
|
|
|
|
|
|
|
/* Modify crosshair position */
|
|
|
|
|
DBWScaleCrosshair(scalen, scaled);
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
SigEnableInterrupts();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Structure needed to hold information about the plane to copy */
|
|
|
|
|
|
|
|
|
|
struct scaleArg {
|
|
|
|
|
int scalen;
|
|
|
|
|
int scaled;
|
|
|
|
|
int pnum;
|
|
|
|
|
Plane *ptarget;
|
|
|
|
|
bool doCIF;
|
|
|
|
|
bool modified;
|
|
|
|
|
};
|
|
|
|
|
|
2020-03-20 18:40:16 +01:00
|
|
|
struct moveArg {
|
|
|
|
|
int origx;
|
|
|
|
|
int origy;
|
|
|
|
|
int pnum;
|
|
|
|
|
Plane *ptarget;
|
|
|
|
|
bool modified;
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbScalePlane --
|
|
|
|
|
*
|
|
|
|
|
* Scaling procedure called on a single plane. Copies paint into the
|
|
|
|
|
* new plane at a scalefactor according to ratio (scalen / scaled)
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
dbScalePlane(oldplane, newplane, pnum, scalen, scaled, doCIF)
|
|
|
|
|
Plane *oldplane, *newplane;
|
|
|
|
|
int pnum;
|
|
|
|
|
int scalen, scaled;
|
|
|
|
|
bool doCIF;
|
|
|
|
|
{
|
|
|
|
|
int dbTileScaleFunc(); /* forward declaration */
|
|
|
|
|
struct scaleArg arg;
|
|
|
|
|
|
|
|
|
|
arg.scalen = scalen;
|
|
|
|
|
arg.scaled = scaled;
|
|
|
|
|
arg.ptarget = newplane;
|
|
|
|
|
arg.pnum = pnum;
|
|
|
|
|
arg.doCIF = doCIF;
|
|
|
|
|
arg.modified = FALSE;
|
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL, oldplane, &TiPlaneRect,
|
|
|
|
|
&DBAllButSpaceBits, dbTileScaleFunc, (ClientData) &arg);
|
|
|
|
|
|
|
|
|
|
return arg.modified;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbTileScaleFunc --
|
|
|
|
|
*
|
|
|
|
|
* Scaling procedure called on each tile being copied from one plane to
|
|
|
|
|
* another. Scaling ratio (scalen / scaled) is stored inside the struct
|
|
|
|
|
* scaleArg before calling.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-03 02:12:37 +01:00
|
|
|
dbTileScaleFunc(tile, dinfo, scvals)
|
2017-04-25 14:41:48 +02:00
|
|
|
Tile *tile;
|
2026-01-03 02:12:37 +01:00
|
|
|
TileType dinfo;
|
2017-04-25 14:41:48 +02:00
|
|
|
struct scaleArg *scvals;
|
|
|
|
|
{
|
|
|
|
|
TileType type;
|
|
|
|
|
Rect targetRect;
|
|
|
|
|
TileType exact;
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &targetRect);
|
|
|
|
|
|
|
|
|
|
if (DBScalePoint(&targetRect.r_ll, scvals->scalen, scvals->scaled))
|
|
|
|
|
scvals->modified = TRUE;
|
|
|
|
|
if (DBScalePoint(&targetRect.r_ur, scvals->scalen, scvals->scaled))
|
|
|
|
|
scvals->modified = TRUE;
|
|
|
|
|
|
|
|
|
|
/* Tile scaled out of existence! */
|
|
|
|
|
if ((targetRect.r_xtop - targetRect.r_xbot == 0) ||
|
|
|
|
|
(targetRect.r_ytop - targetRect.r_ybot == 0))
|
|
|
|
|
{
|
2024-09-30 05:49:16 +02:00
|
|
|
TxPrintf("Tile %p at (%d, %d) has zero area after scaling: Removed.\n",
|
2025-01-06 17:25:38 +01:00
|
|
|
(void *) tile, targetRect.r_xbot, targetRect.r_ybot);
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-03 02:12:37 +01:00
|
|
|
type = TiGetTypeExact(tile) | dinfo;
|
2017-04-25 14:41:48 +02:00
|
|
|
exact = type;
|
|
|
|
|
if (IsSplit(tile))
|
2026-01-03 02:12:37 +01:00
|
|
|
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
2017-04-25 14:41:48 +02:00
|
|
|
DBNMPaintPlane(scvals->ptarget, exact, &targetRect,
|
2024-10-02 07:59:00 +02:00
|
|
|
(
|
|
|
|
|
#ifdef CIF_MODULE
|
|
|
|
|
(scvals->doCIF) ? CIFPaintTable :
|
|
|
|
|
#endif
|
2017-04-25 14:41:48 +02:00
|
|
|
DBStdPaintTbl(type, scvals->pnum)),
|
|
|
|
|
(PaintUndoInfo *)NULL);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 18:40:16 +01:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbMovePlane --
|
|
|
|
|
*
|
|
|
|
|
* Relocation procedure called on a single plane. Copies paint into the
|
|
|
|
|
* new plane at a delta position (-origx, -origy)
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
dbMovePlane(oldplane, newplane, pnum, origx, origy)
|
|
|
|
|
Plane *oldplane, *newplane;
|
|
|
|
|
int pnum;
|
|
|
|
|
int origx, origy;
|
|
|
|
|
{
|
|
|
|
|
int dbTileMoveFunc(); /* forward declaration */
|
|
|
|
|
struct moveArg arg;
|
|
|
|
|
|
|
|
|
|
arg.origx = origx;
|
|
|
|
|
arg.origy = origy;
|
|
|
|
|
arg.ptarget = newplane;
|
|
|
|
|
arg.pnum = pnum;
|
|
|
|
|
arg.modified = FALSE;
|
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL, oldplane, &TiPlaneRect,
|
|
|
|
|
&DBAllButSpaceBits, dbTileMoveFunc, (ClientData) &arg);
|
|
|
|
|
|
|
|
|
|
return arg.modified;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbTileMoveFunc --
|
|
|
|
|
*
|
|
|
|
|
* Repositioning procedure called on each tile being copied from one plane
|
|
|
|
|
* to another. Delta position (-origx, -origy) is stored inside the struct
|
|
|
|
|
* moveArg before calling.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2026-01-03 02:12:37 +01:00
|
|
|
dbTileMoveFunc(tile, dinfo, mvvals)
|
2020-03-20 18:40:16 +01:00
|
|
|
Tile *tile;
|
2026-01-03 02:12:37 +01:00
|
|
|
TileType dinfo;
|
2020-03-20 18:40:16 +01:00
|
|
|
struct moveArg *mvvals;
|
|
|
|
|
{
|
|
|
|
|
TileType type;
|
|
|
|
|
Rect targetRect;
|
|
|
|
|
TileType exact;
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &targetRect);
|
|
|
|
|
|
|
|
|
|
mvvals->modified = TRUE;
|
|
|
|
|
DBMovePoint(&targetRect.r_ll, mvvals->origx, mvvals->origy);
|
|
|
|
|
DBMovePoint(&targetRect.r_ur, mvvals->origx, mvvals->origy);
|
|
|
|
|
|
2026-01-03 02:12:37 +01:00
|
|
|
type = TiGetTypeExact(tile) | dinfo;
|
2020-03-20 18:40:16 +01:00
|
|
|
exact = type;
|
|
|
|
|
if (IsSplit(tile))
|
2026-01-03 02:12:37 +01:00
|
|
|
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
2020-03-20 18:40:16 +01:00
|
|
|
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
|
|
|
|
|
DBStdPaintTbl(type, mvvals->pnum),
|
|
|
|
|
(PaintUndoInfo *)NULL);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBSrCellUses --
|
|
|
|
|
*
|
|
|
|
|
* Do function "func" for each cell use in cellDef, passing "arg" as
|
2019-03-23 00:58:47 +01:00
|
|
|
* client data. This routine first collects a linked list of cell uses,
|
|
|
|
|
* then performs the function on the list, so that the search cannot be
|
|
|
|
|
* corrupted by (specifically) removing the use structure from the cell
|
|
|
|
|
* def's bplane. Function "func" takes 2 arguments:
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* int func(Celluse *use, ClientData arg) {}
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* 0 one successful completion of the search, 1 on error.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* Whatever "func" does.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBSrCellUses(cellDef, func, arg)
|
|
|
|
|
CellDef *cellDef; /* Pointer to CellDef to search for uses. */
|
|
|
|
|
int (*func)(); /* Function to apply for each cell use. */
|
|
|
|
|
ClientData arg; /* data to be passed to function func(). */
|
|
|
|
|
{
|
|
|
|
|
int dbCellUseEnumFunc();
|
|
|
|
|
int retval;
|
|
|
|
|
CellUse *use;
|
|
|
|
|
LinkedCellUse *luhead, *lu;
|
|
|
|
|
|
|
|
|
|
/* DBCellEnum() attempts to read unavailable celldefs. We don't */
|
|
|
|
|
/* want to do that here, so check CDAVAILABLE flag first. */
|
|
|
|
|
|
|
|
|
|
if ((cellDef->cd_flags & CDAVAILABLE) == 0) return 0;
|
|
|
|
|
|
|
|
|
|
/* Enumerate all unique cell uses, and scale their position, */
|
|
|
|
|
/* transform, and array information. */
|
|
|
|
|
|
|
|
|
|
luhead = NULL;
|
|
|
|
|
|
|
|
|
|
retval = DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
|
|
|
|
|
|
|
|
|
|
lu = luhead;
|
|
|
|
|
while (lu != NULL)
|
|
|
|
|
{
|
|
|
|
|
use = lu->cellUse;
|
|
|
|
|
if ((*func)(use, arg)) {
|
|
|
|
|
retval = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
lu = lu->cu_next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free this linked cellUse structure */
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
lu = luhead;
|
|
|
|
|
while (lu != NULL)
|
|
|
|
|
{
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1(&mm1, (char *)lu);
|
2017-04-25 14:41:48 +02:00
|
|
|
lu = lu->cu_next;
|
|
|
|
|
}
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1);
|
2017-04-25 14:41:48 +02:00
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
/* Structure used by dbScaleProp() and dbMoveProp() */
|
|
|
|
|
typedef struct _cellpropstruct {
|
|
|
|
|
Point cps_point;
|
|
|
|
|
CellDef *cps_def;
|
|
|
|
|
} CellPropStruct;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbScaleProp --
|
|
|
|
|
*
|
|
|
|
|
* Callback function for dbScaleCell. Finds properties that represent
|
2022-11-30 22:29:37 +01:00
|
|
|
* internal geometry (*_BBOX and MASKHINTS_*) and scale the values
|
2020-12-14 22:16:37 +01:00
|
|
|
* by the numerator / denominator values passed as a pointer to a Point
|
|
|
|
|
* structure, where p_x is the numerator value and p_y is the denominator
|
|
|
|
|
* value.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
int dbScaleProp(name, proprec, cps)
|
2020-12-14 22:16:37 +01:00
|
|
|
char *name;
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
PropertyRecord *proprec;
|
2020-12-14 22:16:37 +01:00
|
|
|
CellPropStruct *cps;
|
|
|
|
|
{
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
int i, scalen, scaled;
|
|
|
|
|
Point p;
|
2020-12-14 22:16:37 +01:00
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
/* Only "dimension" type properties get scaled */
|
|
|
|
|
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
2020-12-14 22:16:37 +01:00
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
/* Scale numerator held in point X value, */
|
|
|
|
|
/* scale denominator held in point Y value */
|
|
|
|
|
scalen = cps->cps_point.p_x;
|
|
|
|
|
scaled = cps->cps_point.p_y;
|
2020-12-14 22:16:37 +01:00
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
for (i = 0; i < proprec->prop_len; i += 2)
|
2021-01-06 17:35:03 +01:00
|
|
|
{
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
if ((i + 1) >= proprec->prop_len) break;
|
2021-01-06 17:35:03 +01:00
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
p.p_x = proprec->prop_value.prop_integer[i];
|
|
|
|
|
p.p_y = proprec->prop_value.prop_integer[i + 1];
|
|
|
|
|
DBScalePoint(&p, scalen, scaled);
|
|
|
|
|
proprec->prop_value.prop_integer[i] = p.p_x;
|
|
|
|
|
proprec->prop_value.prop_integer[i + 1] = p.p_y;
|
2021-01-06 17:35:03 +01:00
|
|
|
}
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
return 0; /* Keep enumerating through properties */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbMoveProp --
|
|
|
|
|
*
|
|
|
|
|
* Callback function for ??. Finds properties that represent
|
2022-11-30 22:29:37 +01:00
|
|
|
* internal geometry (*_BBOX and MASKHINTS_*) and modifies the values
|
2020-12-14 22:16:37 +01:00
|
|
|
* by the X, Y values passed as a pointer to a Point structure in ClientData.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
int dbMoveProp(name, proprec, cps)
|
2020-12-14 22:16:37 +01:00
|
|
|
char *name;
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
PropertyRecord *proprec;
|
2020-12-14 22:16:37 +01:00
|
|
|
CellPropStruct *cps;
|
|
|
|
|
{
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
int i, origx, origy;
|
2020-12-14 22:16:37 +01:00
|
|
|
char *newvalue;
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
Point p;
|
2020-12-14 22:16:37 +01:00
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
/* Only "dimension" type properties get scaled */
|
|
|
|
|
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
2020-12-14 22:16:37 +01:00
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
origx = cps->cps_point.p_x;
|
|
|
|
|
origy = cps->cps_point.p_y;
|
2020-12-14 22:16:37 +01:00
|
|
|
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
for (i = 0; i < proprec->prop_len; i += 2)
|
|
|
|
|
{
|
|
|
|
|
if ((i + 1) >= proprec->prop_len) break;
|
|
|
|
|
|
|
|
|
|
p.p_x = proprec->prop_value.prop_integer[i];
|
|
|
|
|
p.p_y = proprec->prop_value.prop_integer[i + 1];
|
|
|
|
|
DBMovePoint(&p, origx, origy);
|
|
|
|
|
proprec->prop_value.prop_integer[i] = p.p_x;
|
|
|
|
|
proprec->prop_value.prop_integer[i + 1] = p.p_y;
|
2020-12-14 22:16:37 +01:00
|
|
|
}
|
Extended the "property" command and modified the way that properties
are handled. Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy. The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double". All types except "string" can consist of multiple
values. Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted. In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 16:48:47 +01:00
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
return 0; /* Keep enumerating through properties */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbScaleCell --
|
|
|
|
|
*
|
|
|
|
|
* Scaling procedure called on each cell encountered in the search.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbScaleCell(cellDef, scalen, scaled)
|
|
|
|
|
CellDef *cellDef; /* Pointer to CellDef to be saved. This def might
|
|
|
|
|
* be an internal buffer; if so, we ignore it.
|
|
|
|
|
*/
|
|
|
|
|
int scalen, scaled; /* scale numerator and denominator. */
|
|
|
|
|
{
|
2019-03-23 00:58:47 +01:00
|
|
|
int dbCellScaleFunc(), dbCellUseEnumFunc();
|
2017-04-25 14:41:48 +02:00
|
|
|
Label *lab;
|
|
|
|
|
int pNum;
|
|
|
|
|
LinkedTile *lhead, *lt;
|
|
|
|
|
LinkedCellUse *luhead, *lu;
|
|
|
|
|
Plane *newplane;
|
2020-04-03 22:22:56 +02:00
|
|
|
BPlane *cellPlane, *cellPlaneOrig;
|
2020-12-14 22:16:37 +01:00
|
|
|
CellPropStruct cps;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* DBCellEnum() attempts to read unavailable celldefs. We don't */
|
|
|
|
|
/* want to do that here, so check CDAVAILABLE flag first. */
|
|
|
|
|
|
|
|
|
|
if ((cellDef->cd_flags & CDAVAILABLE) == 0)
|
|
|
|
|
goto donecell;
|
|
|
|
|
else
|
|
|
|
|
cellDef->cd_flags |= CDBOXESCHANGED;
|
|
|
|
|
|
|
|
|
|
/* Enumerate all unique cell uses, and scale their position, */
|
|
|
|
|
/* transform, and array information. */
|
|
|
|
|
|
|
|
|
|
luhead = NULL;
|
|
|
|
|
|
|
|
|
|
(void) DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
|
|
|
|
|
|
2020-04-03 22:22:56 +02:00
|
|
|
cellPlane = BPNew();
|
2017-04-25 14:41:48 +02:00
|
|
|
lu = luhead;
|
|
|
|
|
while (lu != NULL)
|
|
|
|
|
{
|
|
|
|
|
CellUse *use;
|
|
|
|
|
Rect *bbox;
|
|
|
|
|
|
|
|
|
|
use = lu->cellUse;
|
|
|
|
|
bbox = &use->cu_bbox;
|
|
|
|
|
|
|
|
|
|
/* TxPrintf("CellUse: BBox is ll (%d, %d), transform [%d %d %d %d %d %d]\n",
|
|
|
|
|
bbox->r_xbot, bbox->r_ybot,
|
|
|
|
|
use->cu_transform.t_a, use->cu_transform.t_b, use->cu_transform.t_c,
|
|
|
|
|
use->cu_transform.t_d, use->cu_transform.t_e, use->cu_transform.t_f); */
|
|
|
|
|
|
|
|
|
|
DBScalePoint(&bbox->r_ll, scalen, scaled);
|
|
|
|
|
DBScalePoint(&bbox->r_ur, scalen, scaled);
|
|
|
|
|
|
|
|
|
|
bbox = &use->cu_extended;
|
|
|
|
|
DBScalePoint(&bbox->r_ll, scalen, scaled);
|
|
|
|
|
DBScalePoint(&bbox->r_ur, scalen, scaled);
|
|
|
|
|
|
|
|
|
|
DBScaleValue(&use->cu_transform.t_c, scalen, scaled);
|
|
|
|
|
DBScaleValue(&use->cu_transform.t_f, scalen, scaled);
|
|
|
|
|
|
|
|
|
|
DBScaleValue(&use->cu_array.ar_xsep, scalen, scaled);
|
|
|
|
|
DBScaleValue(&use->cu_array.ar_ysep, scalen, scaled);
|
|
|
|
|
|
2020-04-03 22:22:56 +02:00
|
|
|
BPAdd(cellPlane, use);
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
lu = lu->cu_next;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 22:22:56 +02:00
|
|
|
/* Swap the CellDef's cell plane */
|
|
|
|
|
cellPlaneOrig = cellDef->cd_cellPlane;
|
|
|
|
|
cellDef->cd_cellPlane = cellPlane;
|
|
|
|
|
BPFree(cellPlaneOrig);
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Free this linked cellUse structure */
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
2017-04-25 14:41:48 +02:00
|
|
|
lu = luhead;
|
|
|
|
|
while (lu != NULL)
|
|
|
|
|
{
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1(&mm1, (char *)lu);
|
2017-04-25 14:41:48 +02:00
|
|
|
lu = lu->cu_next;
|
|
|
|
|
}
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Scale all of the paint tiles in this cell by creating a new plane */
|
|
|
|
|
/* and copying all tiles into the new plane at scaled dimensions. */
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
{
|
|
|
|
|
if (cellDef->cd_planes[pNum] == NULL) continue;
|
|
|
|
|
newplane = DBNewPlane((ClientData) TT_SPACE);
|
|
|
|
|
DBClearPaintPlane(newplane);
|
|
|
|
|
if (dbScalePlane(cellDef->cd_planes[pNum], newplane, pNum,
|
|
|
|
|
scalen, scaled, FALSE))
|
|
|
|
|
cellDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
|
|
|
|
DBFreePaintPlane(cellDef->cd_planes[pNum]);
|
|
|
|
|
TiFreePlane(cellDef->cd_planes[pNum]);
|
|
|
|
|
cellDef->cd_planes[pNum] = newplane;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Also scale the position of all labels. */
|
|
|
|
|
/* If labels are the rendered-font type, scale the size as well */
|
|
|
|
|
|
|
|
|
|
if (cellDef->cd_labels)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
{
|
|
|
|
|
DBScalePoint(&lab->lab_rect.r_ll, scalen, scaled);
|
|
|
|
|
DBScalePoint(&lab->lab_rect.r_ur, scalen, scaled);
|
|
|
|
|
|
|
|
|
|
if (lab->lab_font >= 0)
|
|
|
|
|
{
|
|
|
|
|
DBScalePoint(&lab->lab_offset, scalen, scaled);
|
|
|
|
|
DBScaleValue(&lab->lab_size, scalen, scaled);
|
|
|
|
|
|
|
|
|
|
DBScalePoint(&lab->lab_bbox.r_ll, scalen, scaled);
|
|
|
|
|
DBScalePoint(&lab->lab_bbox.r_ur, scalen, scaled);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
DBScalePoint(&lab->lab_corners[i], scalen, scaled);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
donecell:
|
|
|
|
|
|
|
|
|
|
/* The cellDef bounding box gets expanded to match the new scale. */
|
|
|
|
|
|
|
|
|
|
DBScalePoint(&cellDef->cd_bbox.r_ll, scalen, scaled);
|
|
|
|
|
DBScalePoint(&cellDef->cd_bbox.r_ur, scalen, scaled);
|
|
|
|
|
DBScalePoint(&cellDef->cd_extended.r_ll, scalen, scaled);
|
|
|
|
|
DBScalePoint(&cellDef->cd_extended.r_ur, scalen, scaled);
|
|
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
/* Check all properties for ones with keys beginning with "MASKHINTS_"
|
2022-11-30 22:29:37 +01:00
|
|
|
* or ending with "_BBOX", and scale them by the same amount as all
|
2020-12-14 22:16:37 +01:00
|
|
|
* the geometry.
|
2025-02-09 18:48:22 +01:00
|
|
|
*
|
|
|
|
|
* Note: This would be better handled if there were a special type
|
|
|
|
|
* for properties which are coordinates; currently the only property
|
|
|
|
|
* type is a string, thus requiring the string to be parsed every time
|
|
|
|
|
* the coordinates are needed.
|
2020-12-14 22:16:37 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
cps.cps_point.p_x = scalen;
|
|
|
|
|
cps.cps_point.p_y = scaled;
|
|
|
|
|
cps.cps_def = cellDef;
|
|
|
|
|
DBPropEnum(cellDef, dbScaleProp, &cps);
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbCellDefEnumFunc --
|
|
|
|
|
*
|
|
|
|
|
* Enumeration procedure called on each CellDef encountered in the search of
|
|
|
|
|
* cells in the hierarchy. Adds the CellDef to a linked list of celldefs.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbCellDefEnumFunc(cellDef, arg)
|
|
|
|
|
CellDef *cellDef;
|
|
|
|
|
LinkedCellDef **arg;
|
|
|
|
|
{
|
|
|
|
|
LinkedCellDef *lcd;
|
|
|
|
|
|
|
|
|
|
lcd = (LinkedCellDef *) mallocMagic(sizeof(LinkedCellDef));
|
|
|
|
|
|
|
|
|
|
lcd->cellDef = cellDef;
|
|
|
|
|
lcd->cd_next = (*arg);
|
|
|
|
|
(*arg) = lcd;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbCellUseEnumFunc --
|
|
|
|
|
*
|
|
|
|
|
* Enumeration procedure called on each CellDef encountered in the search of
|
|
|
|
|
* cells in the hierarchy. Adds the CellDef to a linked list of celldefs.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbCellUseEnumFunc(cellUse, arg)
|
|
|
|
|
CellUse *cellUse;
|
|
|
|
|
LinkedCellUse **arg;
|
|
|
|
|
{
|
|
|
|
|
LinkedCellUse *lcu;
|
|
|
|
|
|
|
|
|
|
lcu = (LinkedCellUse *) mallocMagic(sizeof(LinkedCellUse));
|
|
|
|
|
|
|
|
|
|
lcu->cellUse = cellUse;
|
|
|
|
|
lcu->cu_next = (*arg);
|
|
|
|
|
(*arg) = lcu;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2020-03-20 18:40:16 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBMoveCell --
|
|
|
|
|
*
|
|
|
|
|
* Reposition a cell to a different origin. This routine is equivalent to
|
|
|
|
|
* unexpanding all contents of a cell, selecting everything, and issuing a
|
|
|
|
|
* move command. However, for very large layouts this becomes memory- and
|
|
|
|
|
* compute- intensive. The process of reorienting an entire layout to a
|
|
|
|
|
* new position can be done much more efficiently. This routine is
|
|
|
|
|
* essentially a copy of dbScaleCell() but changes only position and not
|
|
|
|
|
* scale.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBMoveCell(cellDef, origx, origy)
|
|
|
|
|
CellDef *cellDef; /* Pointer to CellDef to be saved. This def might
|
|
|
|
|
* be an internal buffer; if so, we ignore it.
|
|
|
|
|
*/
|
|
|
|
|
int origx, origy; /* Internal unit coordinates which will become the new origin */
|
|
|
|
|
{
|
|
|
|
|
int dbCellTileEnumFunc(), dbCellUseEnumFunc();
|
|
|
|
|
Label *lab;
|
|
|
|
|
int pNum;
|
|
|
|
|
LinkedTile *lhead, *lt;
|
|
|
|
|
LinkedCellUse *luhead, *lu;
|
|
|
|
|
Plane *newplane;
|
2020-04-03 22:22:56 +02:00
|
|
|
BPlane *cellPlane, *cellPlaneOrig;
|
2020-12-14 22:16:37 +01:00
|
|
|
CellPropStruct cps;
|
2020-03-20 18:40:16 +01:00
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
/* Unlike dbScaleCell(), this routine is only run on valid edit defs */
|
2020-03-20 18:40:16 +01:00
|
|
|
|
|
|
|
|
cellDef->cd_flags |= CDBOXESCHANGED;
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
/* Enumerate all unique cell uses, and move their position in the */
|
2020-03-20 18:40:16 +01:00
|
|
|
/* bounding box and transform. */
|
|
|
|
|
|
|
|
|
|
luhead = NULL;
|
|
|
|
|
|
|
|
|
|
(void) DBCellEnum(cellDef, dbCellUseEnumFunc, (ClientData) &luhead);
|
|
|
|
|
|
2020-04-03 22:22:56 +02:00
|
|
|
cellPlane = BPNew();
|
2020-03-20 18:40:16 +01:00
|
|
|
lu = luhead;
|
|
|
|
|
while (lu != NULL)
|
|
|
|
|
{
|
|
|
|
|
CellUse *use;
|
|
|
|
|
Rect *bbox;
|
|
|
|
|
|
|
|
|
|
use = lu->cellUse;
|
|
|
|
|
bbox = &use->cu_bbox;
|
|
|
|
|
|
|
|
|
|
/* TxPrintf("CellUse: BBox is ll (%d, %d), transform [%d %d %d %d %d %d]\n",
|
|
|
|
|
bbox->r_xbot, bbox->r_ybot,
|
|
|
|
|
use->cu_transform.t_a, use->cu_transform.t_b, use->cu_transform.t_c,
|
|
|
|
|
use->cu_transform.t_d, use->cu_transform.t_e, use->cu_transform.t_f); */
|
|
|
|
|
|
|
|
|
|
DBMovePoint(&bbox->r_ll, origx, origy);
|
|
|
|
|
DBMovePoint(&bbox->r_ur, origx, origy);
|
|
|
|
|
|
|
|
|
|
bbox = &use->cu_extended;
|
|
|
|
|
DBMovePoint(&bbox->r_ll, origx, origy);
|
|
|
|
|
DBMovePoint(&bbox->r_ur, origx, origy);
|
|
|
|
|
|
|
|
|
|
use->cu_transform.t_c -= origx;
|
|
|
|
|
use->cu_transform.t_f -= origy;
|
|
|
|
|
|
2020-04-03 22:22:56 +02:00
|
|
|
BPAdd(cellPlane, use);
|
|
|
|
|
|
2020-03-20 18:40:16 +01:00
|
|
|
lu = lu->cu_next;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 22:22:56 +02:00
|
|
|
/* Swap the CellDef's cell plane */
|
|
|
|
|
cellPlaneOrig = cellDef->cd_cellPlane;
|
|
|
|
|
cellDef->cd_cellPlane = cellPlane;
|
|
|
|
|
BPFree(cellPlaneOrig);
|
|
|
|
|
|
2020-03-20 18:40:16 +01:00
|
|
|
/* Free this linked cellUse structure */
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
2020-03-20 18:40:16 +01:00
|
|
|
lu = luhead;
|
|
|
|
|
while (lu != NULL)
|
|
|
|
|
{
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1(&mm1, (char *)lu);
|
2020-03-20 18:40:16 +01:00
|
|
|
lu = lu->cu_next;
|
|
|
|
|
}
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1);
|
2020-03-20 18:40:16 +01:00
|
|
|
|
|
|
|
|
/* Move all of the paint tiles in this cell by creating a new plane */
|
|
|
|
|
/* and copying all tiles into the new plane at the new position. */
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
{
|
|
|
|
|
if (cellDef->cd_planes[pNum] == NULL) continue;
|
|
|
|
|
newplane = DBNewPlane((ClientData) TT_SPACE);
|
|
|
|
|
DBClearPaintPlane(newplane);
|
|
|
|
|
if (dbMovePlane(cellDef->cd_planes[pNum], newplane, pNum,
|
2024-10-04 19:37:46 +02:00
|
|
|
origx, origy))
|
2020-03-20 18:40:16 +01:00
|
|
|
cellDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
|
|
|
|
|
DBFreePaintPlane(cellDef->cd_planes[pNum]);
|
|
|
|
|
TiFreePlane(cellDef->cd_planes[pNum]);
|
|
|
|
|
cellDef->cd_planes[pNum] = newplane;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Also move the position of all labels. */
|
|
|
|
|
|
|
|
|
|
if (cellDef->cd_labels)
|
|
|
|
|
{
|
|
|
|
|
for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
{
|
|
|
|
|
DBMovePoint(&lab->lab_rect.r_ll, origx, origy);
|
|
|
|
|
DBMovePoint(&lab->lab_rect.r_ur, origx, origy);
|
|
|
|
|
|
|
|
|
|
if (lab->lab_font >= 0)
|
|
|
|
|
{
|
|
|
|
|
DBMovePoint(&lab->lab_bbox.r_ll, origx, origy);
|
|
|
|
|
DBMovePoint(&lab->lab_bbox.r_ur, origx, origy);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
donecell:
|
|
|
|
|
|
|
|
|
|
/* The cellDef bounding box gets moved to match the new position. */
|
|
|
|
|
|
|
|
|
|
DBMovePoint(&cellDef->cd_bbox.r_ll, origx, origy);
|
|
|
|
|
DBMovePoint(&cellDef->cd_bbox.r_ur, origx, origy);
|
|
|
|
|
DBMovePoint(&cellDef->cd_extended.r_ll, origx, origy);
|
|
|
|
|
DBMovePoint(&cellDef->cd_extended.r_ur, origx, origy);
|
|
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
/* Check all properties for ones with keys beginning with "MASKHINTS_"
|
2022-11-30 22:29:37 +01:00
|
|
|
* or ending with "_BBOX", and move them by the same amount as all
|
2020-12-14 22:16:37 +01:00
|
|
|
* the geometry.
|
|
|
|
|
*/
|
2020-03-20 18:40:16 +01:00
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
cps.cps_point.p_x = origx;
|
|
|
|
|
cps.cps_point.p_y = origy;
|
|
|
|
|
cps.cps_def = cellDef;
|
|
|
|
|
DBPropEnum(cellDef, dbMoveProp, &cps);
|
2020-03-20 18:40:16 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|