mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-31 18:25:50 +02:00
Added a ARG_UNUSED macro in utils/magic.h, which produces a simple cast to void to silence the warnings. The reasons this is used as opposed to an attribute is that most compilers should support this. Besides this, the macro can be easily searched for in the future to potentially remove (where possible) the unused parameters.
342 lines
8.6 KiB
C
342 lines
8.6 KiB
C
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/maxrect.c,v 1.4 2010/09/24 19:53:20 tim Exp $";
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <string.h> /* for memcpy() */
|
|
|
|
#include "utils/maxrect.h"
|
|
#include "utils/malloc.h"
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* genCanonicalMaxwidth - checks to see that at least one dimension of a
|
|
* rectangular region does not exceed some amount. Searches on all
|
|
* tiles of types in "mask", unless mask is NULL, in which case it
|
|
* searches over all tiles whose client record matches that of the
|
|
* start tile.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
MaxRectsData *
|
|
genCanonicalMaxwidth(bbox, starttile, plane, mask)
|
|
Rect *bbox; /* Bounding box of geometry to search */
|
|
Tile *starttile; /* Any point in the geometry to search */
|
|
Plane *plane; /* Plane being searched */
|
|
TileTypeBitMask *mask; /* Mask of types to check */
|
|
{
|
|
TileTypeBitMask wrongtypes;
|
|
static MaxRectsData *mrd = (MaxRectsData *)NULL;
|
|
Rect boundorig;
|
|
|
|
/* Generate an initial array size of 8 for rlist and swap. */
|
|
if (mrd == (MaxRectsData *)NULL)
|
|
{
|
|
mrd = (MaxRectsData *)mallocMagic(sizeof(MaxRectsData));
|
|
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
|
|
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
|
|
mrd->listdepth = 8;
|
|
}
|
|
if (mask == NULL)
|
|
mrd->match = TiGetClient(starttile);
|
|
else
|
|
mrd->match = CLIENTDEFAULT;
|
|
|
|
mrd->rlist[0] = *bbox;
|
|
boundorig = *bbox;
|
|
|
|
/* Do an area search on boundrect to find all materials not */
|
|
/* in oktypes. Each such tile clips or subdivides */
|
|
/* boundrect. Due to the way FindMaxRects is written for */
|
|
/* the DRC maxwidth rule, maxdist = 1 is required to avoid */
|
|
/* creating degenerate (zero size) areas. */
|
|
|
|
mrd->entries = 1;
|
|
mrd->maxdist = 1;
|
|
if (mask != NULL)
|
|
TTMaskCom2(&wrongtypes, mask);
|
|
else
|
|
TTMaskSetMask(&wrongtypes, &DBAllTypeBits);
|
|
|
|
DBSrPaintArea(starttile, plane, &boundorig, &wrongtypes, FindMaxRects, mrd);
|
|
if (mrd->entries == 0)
|
|
return NULL;
|
|
else
|
|
return (MaxRectsData *)mrd;
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* FindMaxRects ---
|
|
*
|
|
* Procedure used to split an area up into multiple sets of possible
|
|
* convex rectangles.
|
|
*
|
|
* Results:
|
|
* Return 0 to keep the search going.
|
|
*
|
|
* Side effects:
|
|
* Adds data to structure mrd; possibly expanding its memory allocation.
|
|
*
|
|
* Notes:
|
|
* This routine does *not* handle non-Manhattan geometry.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
FindMaxRects(tile, mrd)
|
|
Tile *tile;
|
|
MaxRectsData *mrd;
|
|
{
|
|
Rect area;
|
|
Rect *rlist, *sr, *tmp;
|
|
int s, entries;
|
|
|
|
if (mrd->match != CLIENTDEFAULT)
|
|
if (TiGetClient(tile) == mrd->match)
|
|
return 0;
|
|
|
|
entries = 0;
|
|
TiToRect(tile, &area);
|
|
|
|
rlist = mrd->swap;
|
|
for (s = 0; s < mrd->entries; s++)
|
|
{
|
|
/* Watch out for (M)INFINITY values! */
|
|
|
|
sr = &(mrd->rlist[s]);
|
|
if (GEO_OVERLAP(sr, &area))
|
|
{
|
|
/* Top */
|
|
if (area.r_ytop < INFINITY - 2)
|
|
if (sr->r_ytop >= area.r_ytop + mrd->maxdist)
|
|
{
|
|
rlist[entries] = *sr;
|
|
rlist[entries].r_ybot = area.r_ytop;
|
|
entries++;
|
|
}
|
|
/* Bottom */
|
|
if (area.r_ybot > MINFINITY + 2)
|
|
if (sr->r_ybot <= area.r_ybot - mrd->maxdist)
|
|
{
|
|
rlist[entries] = *sr;
|
|
rlist[entries].r_ytop = area.r_ybot;
|
|
entries++;
|
|
}
|
|
/* Left */
|
|
if (area.r_xbot > MINFINITY + 2)
|
|
if (sr->r_xbot <= area.r_xbot - mrd->maxdist)
|
|
{
|
|
rlist[entries] = *sr;
|
|
rlist[entries].r_xtop = area.r_xbot;
|
|
entries++;
|
|
}
|
|
/* Right */
|
|
if (area.r_xtop < INFINITY - 2)
|
|
if (sr->r_xtop >= area.r_xtop + mrd->maxdist)
|
|
{
|
|
rlist[entries] = *sr;
|
|
rlist[entries].r_xbot = area.r_xtop;
|
|
entries++;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
/* Copy sr to the new list */
|
|
rlist[entries] = *sr;
|
|
entries++;
|
|
}
|
|
|
|
/* If we have more rectangles than we allocated space for, */
|
|
/* double the list size and continue. */
|
|
|
|
if (entries > (mrd->listdepth - 4)) // was entries == mrd->listdepth
|
|
{
|
|
Rect *newrlist;
|
|
|
|
mrd->listdepth <<= 1; /* double the list size */
|
|
|
|
newrlist = (Rect *)mallocMagic(mrd->listdepth * sizeof(Rect));
|
|
memcpy((void *)newrlist, (void *)mrd->rlist,
|
|
(size_t)mrd->entries * sizeof(Rect));
|
|
// for (s = 0; s < entries; s++)
|
|
// newrlist[s] = mrd->rlist[s];
|
|
freeMagic(mrd->rlist);
|
|
mrd->rlist = newrlist;
|
|
|
|
newrlist = (Rect *)mallocMagic(mrd->listdepth * sizeof(Rect));
|
|
memcpy((void *)newrlist, (void *)mrd->swap,
|
|
(size_t)entries * sizeof(Rect));
|
|
// for (s = 0; s < entries; s++)
|
|
// newrlist[s] = mrd->swap[s];
|
|
freeMagic(mrd->swap);
|
|
mrd->swap = newrlist;
|
|
|
|
rlist = mrd->swap;
|
|
}
|
|
}
|
|
|
|
/* Sort areas and remove areas enclosed by other areas */
|
|
/* Is this routine too time-consuming (short answer: yes)? */
|
|
|
|
/*
|
|
for (s = 0; s < entries - 1; s++)
|
|
{
|
|
int r, t;
|
|
for (t = s + 1, r = 0; t < entries; t++)
|
|
{
|
|
if (GEO_SURROUND(&rlist[t], &rlist[s]))
|
|
{
|
|
rlist[s] = rlist[t];
|
|
r++;
|
|
}
|
|
else if (GEO_SURROUND(&rlist[s], &rlist[t]))
|
|
r++;
|
|
else if (r > 0)
|
|
rlist[t - r] = rlist[t];
|
|
}
|
|
entries -= r;
|
|
}
|
|
*/
|
|
|
|
/* copy rlist back to mrd by swapping "rlist" and "swap" */
|
|
mrd->entries = entries;
|
|
tmp = mrd->rlist;
|
|
mrd->rlist = rlist;
|
|
mrd->swap = tmp;
|
|
|
|
if (entries > 0)
|
|
return 0; /* keep the search going */
|
|
else
|
|
return 1; /* no more max size areas; stop the search */
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* FindMaxRectangle ---
|
|
*
|
|
* This is a general-purpose routine to be called from anywhere
|
|
* that expands an area to the largest area rectangle containing
|
|
* tiles connected to the given types list. It can be called, for
|
|
* example, from the router code to expand a point label into the
|
|
* maximum size rectangular terminal.
|
|
*
|
|
* If expandtypes is NULL, then searching is done over tiles that
|
|
* match by the ClientData record instead of types.
|
|
*
|
|
* Results:
|
|
* Pointer to a rectangle containing the maximum size area found.
|
|
* This pointer should not be deallocated!
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
Rect *
|
|
FindMaxRectangle(bbox, startpoint, plane, expandtypes)
|
|
Rect *bbox; /* bounding box of area searched */
|
|
Point *startpoint;
|
|
Plane *plane; /* plane of types to expand */
|
|
TileTypeBitMask *expandtypes; /* types to expand in */
|
|
{
|
|
ARG_UNUSED(expandtypes);
|
|
MaxRectsData *mrd;
|
|
Tile *starttile;
|
|
int rectArea;
|
|
int maxarea = 0;
|
|
int s, sidx = -1;
|
|
|
|
/* Find tile in def that surrounds or touches startpoint */
|
|
starttile = PlaneGetHint(plane);
|
|
GOTOPOINT(starttile, startpoint);
|
|
mrd = genCanonicalMaxwidth(bbox, starttile, plane, NULL);
|
|
|
|
/* Return only the largest rectangle found */
|
|
|
|
for (s = 0; s < mrd->entries; s++)
|
|
{
|
|
rectArea = (mrd->rlist[s].r_xtop - mrd->rlist[s].r_xbot) *
|
|
(mrd->rlist[s].r_ytop - mrd->rlist[s].r_ybot);
|
|
if (rectArea > maxarea)
|
|
{
|
|
maxarea = rectArea;
|
|
sidx = s;
|
|
}
|
|
}
|
|
|
|
if (sidx < 0)
|
|
{
|
|
Rect origrect;
|
|
|
|
TiToRect(starttile, &origrect);
|
|
sidx = 0;
|
|
mrd->rlist[0] = origrect;
|
|
}
|
|
return &(mrd->rlist[sidx]);
|
|
}
|
|
|
|
/*
|
|
*-------------------------------------------------------------------------
|
|
*
|
|
* FindMaxRectangle2 ---
|
|
*
|
|
* This routine differs from FindMaxRectangle in passing a starting
|
|
* tile to the routine.
|
|
*
|
|
* Results:
|
|
* Pointer to a rectangle containing the maximum size area found.
|
|
* This pointer should not be deallocated!
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
Rect *
|
|
FindMaxRectangle2(bbox, starttile, plane, expandtypes)
|
|
Rect *bbox; /* bounding box of area searched */
|
|
Tile *starttile; /* use this tile to start */
|
|
Plane *plane; /* plane of types to expand */
|
|
TileTypeBitMask *expandtypes; /* types to expand in, may be NULL */
|
|
{
|
|
MaxRectsData *mrd;
|
|
int rectArea;
|
|
int maxarea = 0;
|
|
int s, sidx = -1;
|
|
|
|
/* Find tile in def that surrounds or touches startpoint */
|
|
mrd = genCanonicalMaxwidth(bbox, starttile, plane, expandtypes);
|
|
|
|
/* Return only the largest rectangle found */
|
|
|
|
for (s = 0; s < mrd->entries; s++)
|
|
{
|
|
rectArea = (mrd->rlist[s].r_xtop - mrd->rlist[s].r_xbot) *
|
|
(mrd->rlist[s].r_ytop - mrd->rlist[s].r_ybot);
|
|
if (rectArea > maxarea)
|
|
{
|
|
maxarea = rectArea;
|
|
sidx = s;
|
|
}
|
|
}
|
|
|
|
if (sidx < 0)
|
|
{
|
|
Rect origrect;
|
|
|
|
TiToRect(starttile, &origrect);
|
|
sidx = 0;
|
|
mrd->rlist[0] = origrect;
|
|
}
|
|
return &(mrd->rlist[sidx]);
|
|
}
|
|
|