magic/tiles/search2.c

235 lines
7.3 KiB
C
Raw Normal View History

/*
* search2.c --
*
* Area searching.
*
* *********************************************************************
* * 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. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/tiles/search2.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/signals.h"
/* -------------------- Local function headers ------------------------ */
int tiSrAreaEnum();
/*
* --------------------------------------------------------------------
*
* TiSrArea --
*
* Find all tiles contained in or incident upon a given area.
* Applies the given procedure to all tiles found. The procedure
* should be of the following form:
*
* int
* func(tile, cdata)
* Tile *tile;
* ClientData cdata;
* {
* }
*
* Func normally should return 0. If it returns 1 then the search
* will be aborted.
*
* THIS PROCEDURE IS OBSOLETE EXCEPT FOR THE SUBCELL PLANE. USE
* DBSrPaintArea() IF YOU WANT TO SEARCH FOR PAINT TILES.
*
* Results:
* 0 is returned if the search completed normally. 1 is returned
* if it aborted.
*
* Side effects:
* Whatever side effects result from application of the
* supplied procedure.
*
* NOTE:
* The procedure called is free to do anything it wishes to tiles
* which have already been visited in the area search, but it must
* not affect anything about tiles not visited other than possibly
* corner stitches to tiles already visited.
*
* *************************************************************************
* *************************************************************************
* **** ****
* **** WARNING ****
* **** ****
* **** This code is INCREDIBLY sensitive to modification! ****
* **** Change it only with the utmost caution, or you'll ****
* **** be verrry sorry! ****
* **** ****
* *************************************************************************
* *************************************************************************
*
* --------------------------------------------------------------------
*/
int
TiSrArea(hintTile, plane, rect, func, arg)
Tile *hintTile; /* Tile at which to begin search, if not NULL.
* If this is NULL, use the hint tile supplied
* with plane.
*/
Plane *plane; /* Plane in which tiles lie. This is used to
* provide a hint tile in case hintTile == NULL.
* The hint tile in the plane is updated to be
* the last tile visited in the area enumeration.
*/
Rect *rect;/* Area to search */
int (*func)(); /* Function to apply at each tile */
ClientData arg; /* Additional argument to pass to (*func)() */
{
Point here;
Tile *tp, *enumTR, *enumTile;
int enumRight, enumBottom;
/*
* We will scan from top to bottom along the left hand edge
* of the search area, searching for tiles. Each tile we
* find in this search will be enumerated.
*/
here.p_x = rect->r_xbot;
here.p_y = rect->r_ytop - 1;
enumTile = hintTile ? hintTile : plane->pl_hint;
GOTOPOINT(enumTile, &here);
plane->pl_hint = enumTile;
while (here.p_y >= rect->r_ybot)
{
if (SigInterruptPending) return 1;
/*
* Find the tile (tp) immediately below the one to be
* enumerated (enumTile). This must be done before we enumerate
* the tile, as the filter function applied to enumerate
* it can result in its deallocation or modification in
* some other way.
*/
here.p_y = BOTTOM(enumTile) - 1;
tp = enumTile;
GOTOPOINT(tp, &here);
plane->pl_hint = tp;
enumRight = RIGHT(enumTile);
enumBottom = BOTTOM(enumTile);
enumTR = TR(enumTile);
if ((*func)(enumTile, arg)) return 1;
/*
* If the right boundary of the tile being enumerated is
* inside of the search area, recursively enumerate
* tiles to its right.
*/
if (enumRight < rect->r_xtop)
if (tiSrAreaEnum(enumTR, enumBottom, rect, func, arg))
return 1;
enumTile = tp;
}
return 0;
}
/*
* --------------------------------------------------------------------
*
* tiSrAreaEnum --
*
* Perform the recursive edge search of the tile which has just been
* enumerated in an area search. The arguments passed are the RT
* corner stitch and bottom coordinate of the tile just enumerated.
*
* Results:
* 0 is returned if the search completed normally, 1 if
* it was aborted.
*
* Side effects:
* Attempts to enumerate recursively each tile found in walking
* along the right edge of the tile just enumerated. Whatever
* side effects occur result from the application of the client's
* filter function.
*
* --------------------------------------------------------------------
*/
int
tiSrAreaEnum(enumRT, enumBottom, rect, func, arg)
Tile *enumRT; /* TR corner stitch of tile just enumerated */
int enumBottom; /* Bottom coordinate of tile just enumerated */
Rect *rect; /* Area to search */
int (*func)(); /* Function to apply at each tile */
ClientData arg; /* Additional argument to pass to (*func)() */
{
Tile *tp, *tpLB, *tpTR;
int tpRight, tpNextTop, tpBottom, srchBottom;
int atBottom = (enumBottom <= rect->r_ybot);
/*
* Begin examination of tiles along right edge.
* A tile to the right of the one being enumerated is enumerable if:
* - its bottom lies at or above that of the tile being enumerated, or,
* - the bottom of the tile being enumerated lies at or below the
* bottom of the search rectangle.
*/
if ((srchBottom = enumBottom) < rect->r_ybot)
srchBottom = rect->r_ybot;
for (tp = enumRT, tpNextTop = TOP(tp); tpNextTop > srchBottom; tp = tpLB)
{
if (SigInterruptPending) return 1;
/*
* Since the client's filter function may result in this tile
* being deallocated or otherwise modified, we must extract
* all the information we will need from the tile before we
* apply the filter function.
*/
tpLB = LB(tp);
tpNextTop = TOP(tpLB); /* Since TOP(tpLB) comes from tp */
if (BOTTOM(tp) < rect->r_ytop && (atBottom || BOTTOM(tp) >= enumBottom))
{
/*
* We extract more information from the tile, which we will use
* after applying the filter function.
*/
tpRight = RIGHT(tp);
tpBottom = BOTTOM(tp);
tpTR = TR(tp);
if ((*func)(tp, arg)) return 1;
/*
* If the right boundary of the tile being enumerated is
* inside of the search area, recursively enumerate
* tiles to its right.
*/
if (tpRight < rect->r_xtop)
if (tiSrAreaEnum(tpTR, tpBottom, rect, func, arg))
return 1;
}
}
return 0;
}