2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* DBlabel2.c --
|
|
|
|
|
*
|
|
|
|
|
* Label searching primitives.
|
|
|
|
|
*
|
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/DBlabel2.c,v 1.3 2010/09/12 20:32:31 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "database/databaseInt.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following structure is used to pass data between DBNearestLabel
|
|
|
|
|
* and its search function.
|
|
|
|
|
*/
|
|
|
|
|
struct nldata
|
|
|
|
|
{
|
|
|
|
|
int nld_distance; /* Square of distance to nearest
|
|
|
|
|
* label seen so far.
|
|
|
|
|
*/
|
|
|
|
|
Point *nld_point; /* Reference: find nearest label to this */
|
|
|
|
|
Rect *nld_labelArea; /* Fill in with area of nearest label */
|
|
|
|
|
char *nld_name; /* Fill in with name of nearest label */
|
|
|
|
|
bool nld_gotLabel; /* TRUE means some label was found */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following structure is used to pass the arguments of
|
|
|
|
|
* DBSearchLabel down to the filter function.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define MAXLABPATHSIZE 256
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
char *labSrPattern; /* Pattern for matching. */
|
|
|
|
|
int (*labSrFunc)(); /* Function to apply to each label found */
|
|
|
|
|
ClientData labSrArg; /* Client data of caller */
|
|
|
|
|
} labSrStruct;
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
|
|
|
|
|
|
extern void DBTreeFindUse();
|
|
|
|
|
|
|
|
|
|
bool dbParseArray();
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBSearchLabel --
|
|
|
|
|
*
|
|
|
|
|
* Search for all occurrences of a point label matching the pattern in the
|
|
|
|
|
* region rect in the indicated cell and all of its children. On each label
|
|
|
|
|
* matching the pattern found in the area, the supplied procedure is invoked.
|
|
|
|
|
*
|
|
|
|
|
* The supplied procedure should be of the form
|
|
|
|
|
* int
|
|
|
|
|
* func(scx, label, tpath, cdarg)
|
|
|
|
|
* SearchContext *scx;
|
|
|
|
|
* Label *label;
|
|
|
|
|
* TerminalPath *tpath;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* In the above, scx is a search context specifying the cell use whose
|
|
|
|
|
* def was found to contain the label, and label is a pointer to the
|
|
|
|
|
* Label structure itself. The transform specified in scx is from
|
|
|
|
|
* coordinates of the def of the cell containing the label to "root"
|
|
|
|
|
* coordinates. Func should normally return 0. If it returns 1 then
|
|
|
|
|
* the search is aborted.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* If the search terminates normally, 0 is returned. 1 is
|
|
|
|
|
* returned if the search was aborted.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Applies the supplied procedure to each tile containing a label
|
|
|
|
|
* matching the pattern.
|
|
|
|
|
*
|
|
|
|
|
* WARNING: because of the way regex(3) works, it is possible to be
|
|
|
|
|
* searching for at most one pattern at a time.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBSearchLabel(scx, mask, xMask, pattern, func, cdarg)
|
|
|
|
|
SearchContext *scx; /* Search context: specifies CellUse,
|
|
|
|
|
* transform to "root" coordinates, and
|
|
|
|
|
* an area to search.
|
|
|
|
|
*/
|
|
|
|
|
TileTypeBitMask *mask; /* Only search for labels on these layers */
|
|
|
|
|
int xMask; /* Expansion state mask for searching. Cell
|
|
|
|
|
* uses are only considered to be expanded
|
|
|
|
|
* when their expand masks have all the bits
|
|
|
|
|
* of xMask set.
|
|
|
|
|
*/
|
|
|
|
|
char *pattern; /* Pattern for which to search */
|
|
|
|
|
int (*func)(); /* Function to apply to each match */
|
|
|
|
|
ClientData cdarg; /* Argument to pass to function */
|
|
|
|
|
{
|
|
|
|
|
TerminalPath tpath;
|
|
|
|
|
int dbSrLabelFunc();
|
|
|
|
|
labSrStruct labsr;
|
|
|
|
|
char labSrStr[MAXLABPATHSIZE]; /* String buffer in which the full pathname
|
|
|
|
|
* of each label is assembled for handing
|
|
|
|
|
* to the filter function.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
labsr.labSrPattern = pattern;
|
|
|
|
|
labsr.labSrFunc = func;
|
|
|
|
|
labsr.labSrArg = cdarg;
|
|
|
|
|
tpath.tp_first = tpath.tp_next = labSrStr;
|
|
|
|
|
tpath.tp_last = &(labSrStr[sizeof(labSrStr) - 2]);
|
|
|
|
|
|
|
|
|
|
if (DBTreeSrLabels(scx, mask, xMask, &tpath, TF_LABEL_ATTACH,
|
|
|
|
|
dbSrLabelFunc, (ClientData) &labsr))
|
|
|
|
|
return 1;
|
|
|
|
|
else return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbSrLabelFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter procedure applied to all labels by DBTreeSrLabels(). For
|
|
|
|
|
* each label that matches the pattern set by DBSearchLabel(), the
|
|
|
|
|
* filter function (*cdarg->lsa_func)() is applied.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always return 0 to keep the search going.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Applies the supplied procedure to each label matching the pattern.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbSrLabelFunc(scx, label, tpath, labsr)
|
|
|
|
|
SearchContext *scx; /* Contains pointer to use in which label
|
|
|
|
|
* occurred, and transform back to root
|
|
|
|
|
* coordinates.
|
|
|
|
|
*/
|
|
|
|
|
Label *label; /* Label itself */
|
|
|
|
|
TerminalPath *tpath; /* Full pathname of the terminal */
|
|
|
|
|
labSrStruct *labsr; /* Information passed to this routine */
|
|
|
|
|
{
|
|
|
|
|
if (Match(labsr->labSrPattern, label->lab_text))
|
|
|
|
|
if ((*labsr->labSrFunc)(scx, label, tpath, labsr->labSrArg))
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBSrLabelLoc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure finds the locations of all labels with a given
|
|
|
|
|
* hierarchical name. For each label found, a client-supplied
|
|
|
|
|
* search function is called. The search function has the form:
|
|
|
|
|
*
|
|
|
|
|
* int
|
|
|
|
|
* func(rect, name, label, cdarg)
|
|
|
|
|
* Rect *rect;
|
|
|
|
|
* char *name;
|
|
|
|
|
* Label *label;
|
|
|
|
|
* ClientData cdarg;
|
|
|
|
|
*
|
|
|
|
|
* Rect is the location of the label, in the coordinates of rootUse->cu_def,
|
|
|
|
|
* name is the label's hierarchical name (just the parameter passed to us),
|
|
|
|
|
* label is a pointer to the label, and cdarg is the client data passed in
|
|
|
|
|
* to us by the client. Note that there can be more than one label with the
|
|
|
|
|
* same name. Func should normally return 0. If it returns 1, then the
|
|
|
|
|
* search is aborted.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is 0, unless func returned a non-zero value,
|
|
|
|
|
* in which case the return value is 1.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Whatever the search function does.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
DBSrLabelLoc(rootUse, name, func, cdarg)
|
|
|
|
|
CellUse *rootUse; /* Cell in which to search. */
|
|
|
|
|
char *name; /* A hierarchical label name consisting of zero or more
|
|
|
|
|
* use-ids followed by a label name (fields separated
|
|
|
|
|
* with slashes).
|
|
|
|
|
*/
|
|
|
|
|
int (*func)(); /* Applied to each instance of the label name */
|
|
|
|
|
ClientData cdarg; /* Data to pass through to (*func)() */
|
|
|
|
|
{
|
|
|
|
|
CellDef *def;
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
char *cp;
|
|
|
|
|
Label *lab;
|
|
|
|
|
char csave;
|
|
|
|
|
Rect r;
|
|
|
|
|
|
2024-10-04 18:19:27 +02:00
|
|
|
if ((cp = strrchr(name, '/')))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
csave = *cp;
|
|
|
|
|
*cp = '\0';
|
|
|
|
|
DBTreeFindUse(name, rootUse, &scx);
|
|
|
|
|
*cp = csave;
|
|
|
|
|
if (scx.scx_use == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
cp++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
scx.scx_use = rootUse;
|
|
|
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
|
|
|
cp = name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def = scx.scx_use->cu_def;
|
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
if (lab->lab_text[0] == *cp && strcmp(lab->lab_text, cp) == 0)
|
|
|
|
|
{
|
|
|
|
|
GeoTransRect(&scx.scx_trans, &lab->lab_rect, &r);
|
|
|
|
|
if ((*func)(&r, name, lab, cdarg))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBTreeFindUse --
|
|
|
|
|
*
|
|
|
|
|
* This procedure finds the cell use with the given hierarchical name.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Sets scx->scx_use to the cell use found, with scx->scx_trans
|
|
|
|
|
* and scx->scx_x, scx->scx_y also valid. If the cell was not
|
|
|
|
|
* found, leaves scx->scx_use set to NULL.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBTreeFindUse(name, use, scx)
|
|
|
|
|
char *name;
|
|
|
|
|
CellUse *use;
|
|
|
|
|
SearchContext *scx;
|
|
|
|
|
{
|
|
|
|
|
char *cp;
|
|
|
|
|
HashEntry *he;
|
|
|
|
|
CellDef *def;
|
|
|
|
|
char csave;
|
|
|
|
|
|
|
|
|
|
def = use->cu_def;
|
|
|
|
|
scx->scx_use = (CellUse *) NULL;
|
|
|
|
|
scx->scx_trans = GeoIdentityTransform;
|
|
|
|
|
scx->scx_x = scx->scx_y = 0;
|
|
|
|
|
while (*name)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Make sure that the cell whose children are being searched
|
|
|
|
|
* is read in from disk.
|
|
|
|
|
*/
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
(void) DBCellRead(def, TRUE, TRUE, NULL);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2019-09-03 20:02:27 +02:00
|
|
|
cp = name;
|
2017-04-25 14:41:48 +02:00
|
|
|
he = HashLookOnly(&def->cd_idHash, name);
|
|
|
|
|
if (he == NULL || HashGetValue(he) == NULL)
|
2019-08-20 16:37:12 +02:00
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Pull off the next component of path up to but not including
|
|
|
|
|
* any array subscripts.
|
|
|
|
|
* NOTE: This should check the array bounds and only remove
|
|
|
|
|
* array components that are expected, not array components
|
|
|
|
|
* embedded in the name.
|
|
|
|
|
*/
|
2019-09-03 20:02:27 +02:00
|
|
|
for (; *cp && *cp != '[' && *cp != '/'; cp++)
|
2019-08-20 16:37:12 +02:00
|
|
|
/* Nothing */;
|
|
|
|
|
csave = *cp;
|
|
|
|
|
*cp = '\0';
|
|
|
|
|
he = HashLookOnly(&def->cd_idHash, name);
|
|
|
|
|
*cp = csave;
|
|
|
|
|
if (he == NULL || HashGetValue(he) == NULL)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
use = (CellUse *) HashGetValue(he);
|
|
|
|
|
def = use->cu_def;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Pull off array subscripts and build next stage in transform.
|
|
|
|
|
* Return NULL if the number of subscripts specified doesn't
|
|
|
|
|
* match the number that are implied by the array, if use is
|
|
|
|
|
* an array.
|
|
|
|
|
*/
|
|
|
|
|
if (!dbParseArray(cp, use, scx))
|
|
|
|
|
{
|
|
|
|
|
/* Allow non-indexed match of array */
|
|
|
|
|
if (strcmp(name, use->cu_id)) return;
|
|
|
|
|
/* Check for both 1- and 2-dimensional arrays */
|
|
|
|
|
if (!dbParseArray("[0][0]", use, scx))
|
|
|
|
|
if (!dbParseArray("[0]", use, scx))
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
while (*cp && *cp++ != '/')
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
name = cp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ensure that the leaf cell is read in */
|
|
|
|
|
def = use->cu_def;
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
DBCellRead(def, TRUE, TRUE, NULL);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
scx->scx_use = use;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbParseArray --
|
|
|
|
|
*
|
|
|
|
|
* Pull off the array subscripts starting at 'cp' (there may be none),
|
|
|
|
|
* checking to ensure that there are the correct number for 'use' and that
|
|
|
|
|
* they are in range. Store these in scx->scx_x and scx->scx_y, and use them
|
|
|
|
|
* to update scx->scx_trans to be use->cu_trans (as adjusted for the indicated
|
|
|
|
|
* array element) followed by the old value of scx->scx_trans.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns TRUE on success, FALSE on error.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* See above.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
dbParseArray(cp, use, scx)
|
|
|
|
|
char *cp;
|
|
|
|
|
CellUse *use;
|
|
|
|
|
SearchContext *scx;
|
|
|
|
|
{
|
|
|
|
|
int xdelta, ydelta, i1, i2, indexCount;
|
|
|
|
|
Transform trans, trans2;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The transform stuff is a little tricky because if there
|
|
|
|
|
* was only one index given we don't know whether it's the
|
|
|
|
|
* x- or y-index. Make sure the number of indices specified
|
|
|
|
|
* matches the number of dimensions in an array, and that
|
|
|
|
|
* the indices are in range.
|
|
|
|
|
*/
|
|
|
|
|
indexCount = 0;
|
|
|
|
|
if (*cp == '[')
|
|
|
|
|
{
|
|
|
|
|
if (sscanf(cp, "[%d][%d]", &i1, &i2) == 2)
|
|
|
|
|
{
|
|
|
|
|
indexCount = 2;
|
|
|
|
|
while (*cp++ != ']') /* Nothing */;
|
|
|
|
|
while (*cp++ != ']') /* Nothing */;
|
|
|
|
|
}
|
|
|
|
|
else if (sscanf(cp, "[%d,%d]", &i1, &i2) == 2)
|
|
|
|
|
{
|
|
|
|
|
indexCount = 2;
|
|
|
|
|
while (*cp++ != ']') /* Nothing */;
|
|
|
|
|
}
|
|
|
|
|
else if (sscanf(cp, "[%d]", &i1) == 1)
|
|
|
|
|
{
|
|
|
|
|
indexCount = 1;
|
|
|
|
|
while (*cp++ != ']') /* Nothing */;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (indexCount && *cp != '\0' && *cp != '/')
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (indexCount)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
if (use->cu_xlo != use->cu_xhi || use->cu_ylo != use->cu_yhi)
|
|
|
|
|
return FALSE;
|
|
|
|
|
scx->scx_x = use->cu_xlo;
|
|
|
|
|
scx->scx_y = use->cu_ylo;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if (use->cu_xlo == use->cu_xhi)
|
|
|
|
|
{
|
|
|
|
|
scx->scx_x = use->cu_xlo;
|
|
|
|
|
scx->scx_y = i1;
|
|
|
|
|
}
|
|
|
|
|
else if (use->cu_ylo == use->cu_yhi)
|
|
|
|
|
{
|
|
|
|
|
scx->scx_x = i1;
|
|
|
|
|
scx->scx_y = use->cu_ylo;
|
|
|
|
|
}
|
|
|
|
|
else return FALSE;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (use->cu_xlo == use->cu_xhi || use->cu_ylo == use->cu_yhi)
|
|
|
|
|
return FALSE;
|
|
|
|
|
scx->scx_y = i1;
|
|
|
|
|
scx->scx_x = i2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (use->cu_xhi > use->cu_xlo)
|
|
|
|
|
{
|
|
|
|
|
if (scx->scx_x < use->cu_xlo || scx->scx_x > use->cu_xhi)
|
|
|
|
|
return FALSE;
|
|
|
|
|
xdelta = use->cu_xsep * (scx->scx_x - use->cu_xlo);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (scx->scx_x > use->cu_xlo || scx->scx_x < use->cu_xhi)
|
|
|
|
|
return FALSE;
|
|
|
|
|
xdelta = use->cu_xsep * (use->cu_xlo - scx->scx_x);
|
|
|
|
|
}
|
|
|
|
|
if (use->cu_yhi > use->cu_ylo)
|
|
|
|
|
{
|
|
|
|
|
if (scx->scx_y < use->cu_ylo || scx->scx_y > use->cu_yhi)
|
|
|
|
|
return FALSE;
|
|
|
|
|
ydelta = use->cu_ysep * (scx->scx_y - use->cu_ylo);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (scx->scx_y > use->cu_ylo || scx->scx_y < use->cu_yhi)
|
|
|
|
|
return FALSE;
|
|
|
|
|
ydelta = use->cu_ysep * (use->cu_ylo - scx->scx_y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GeoTransTranslate(xdelta, ydelta, &use->cu_transform, &trans);
|
|
|
|
|
GeoTransTrans(&trans, &scx->scx_trans, &trans2);
|
|
|
|
|
scx->scx_trans = trans2;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBNearestLabel --
|
|
|
|
|
*
|
|
|
|
|
* This procedure finds the nearest label to a given point
|
|
|
|
|
* and returns its hierarchical name and location.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Area is searched in cellUse to find the nearest label
|
|
|
|
|
* to point. TRUE is returned if any label was found.
|
|
|
|
|
* If there is no label in the given area, FALSE is
|
|
|
|
|
* returned.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The parameter labelArea is filled in with the location of
|
|
|
|
|
* the label, if one was found. LabelName is filled in with
|
|
|
|
|
* the hierarchical name of the label.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
DBNearestLabel(cellUse, area, point, xMask, labelArea, labelName, length)
|
|
|
|
|
CellUse *cellUse; /* Start search at this cell. */
|
|
|
|
|
Rect *area; /* Search this area of cellUse. */
|
|
|
|
|
Point *point; /* Find nearest label to this point. */
|
|
|
|
|
int xMask; /* Recursively search subcells as long
|
|
|
|
|
* as their expand masks, when anded with
|
|
|
|
|
* xMask, are equal to xMask. 0 means search
|
|
|
|
|
* all the way down through the hierarchy.
|
|
|
|
|
*/
|
|
|
|
|
Rect *labelArea; /* To be filled in with area of closest
|
|
|
|
|
* label. NULL means ignore.
|
|
|
|
|
*/
|
|
|
|
|
char *labelName; /* Fill this in with name of label, unless
|
|
|
|
|
* NULL.
|
|
|
|
|
*/
|
|
|
|
|
int length; /* This gives the maximum number of chars
|
|
|
|
|
* that may be used in labelName, including
|
|
|
|
|
* the NULL character to terminate.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
TerminalPath tPath, *tp;
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
char *name;
|
|
|
|
|
struct nldata funcData;
|
|
|
|
|
extern int dbNearestLabelFunc();
|
|
|
|
|
|
|
|
|
|
/* Allocate space to generate a label name, and set up information
|
|
|
|
|
* for the DBTreeSrLabels call.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (labelName == NULL) tp = NULL, name = NULL;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
name = (char *) mallocMagic((unsigned) (length));
|
|
|
|
|
tPath.tp_first = name;
|
|
|
|
|
tPath.tp_next = name;
|
|
|
|
|
tPath.tp_last = name + length - 1;
|
|
|
|
|
tp = &tPath;
|
|
|
|
|
}
|
|
|
|
|
scx.scx_use = cellUse;
|
|
|
|
|
scx.scx_area = *area;
|
|
|
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
|
|
|
|
|
|
|
|
funcData.nld_point = point;
|
|
|
|
|
funcData.nld_labelArea = labelArea;
|
|
|
|
|
funcData.nld_name = labelName;
|
|
|
|
|
funcData.nld_gotLabel = FALSE;
|
|
|
|
|
|
|
|
|
|
(void) DBTreeSrLabels(&scx, &DBAllTypeBits, xMask, tp, TF_LABEL_ATTACH,
|
|
|
|
|
dbNearestLabelFunc, (ClientData) &funcData);
|
|
|
|
|
|
|
|
|
|
if (name) freeMagic(name);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!funcData.nld_gotLabel) return FALSE;
|
|
|
|
|
else return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* dbNearestLabelFunc --
|
|
|
|
|
*
|
|
|
|
|
* This function is called by DBTreeSrLabels for each label
|
|
|
|
|
* found as part of DBNearestLabel.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to continue the search.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If this is the closest label seen so far, update the information
|
|
|
|
|
* passed via funcData.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbNearestLabelFunc(scx, label, tpath, funcData)
|
|
|
|
|
SearchContext *scx; /* Describes state of search. */
|
|
|
|
|
Label *label; /* Label found. */
|
|
|
|
|
TerminalPath *tpath; /* Name of label. */
|
|
|
|
|
struct nldata *funcData; /* Parameters to DBNearestLabel (passed as
|
|
|
|
|
* ClientData).
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int x, y, distance, left, used;
|
|
|
|
|
Rect area;
|
|
|
|
|
char *src, *dst;
|
|
|
|
|
|
|
|
|
|
GeoTransRect(&scx->scx_trans, &label->lab_rect, &area);
|
|
|
|
|
x = (area.r_xtop + area.r_xbot)/2 - funcData->nld_point->p_x;
|
|
|
|
|
y = (area.r_ytop + area.r_ybot)/2 - funcData->nld_point->p_y;
|
|
|
|
|
distance = x*x + y*y;
|
|
|
|
|
if ((funcData->nld_gotLabel) && (distance > funcData->nld_distance))
|
|
|
|
|
return 0;
|
|
|
|
|
funcData->nld_distance = distance;
|
|
|
|
|
funcData->nld_gotLabel = TRUE;
|
|
|
|
|
|
|
|
|
|
if (funcData->nld_labelArea != NULL)
|
|
|
|
|
*(funcData->nld_labelArea) = area;
|
|
|
|
|
if (funcData->nld_name != NULL)
|
|
|
|
|
{
|
|
|
|
|
left = tpath->tp_last - tpath->tp_next;
|
|
|
|
|
used = tpath->tp_next - tpath->tp_first;
|
|
|
|
|
(void) strncpy(funcData->nld_name, tpath->tp_first, used);
|
|
|
|
|
dst = funcData->nld_name + used;
|
|
|
|
|
src = label->lab_text;
|
|
|
|
|
for ( ; left > 0; left -= 1)
|
|
|
|
|
{
|
|
|
|
|
if (*src == 0) break;
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
}
|
|
|
|
|
*dst = 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|