/* touchingtypes.c --
 *
 *     *********************************************************************
 *     * 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.    *
 *     *********************************************************************
 *		      Lawrence Livermore National Laboratory
 *		      All rights reserved.
 *
 * Function to return mask of all tiletypes touching a given point.
 */

#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/touchtypes.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 "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"

/* ----------------------- Structs local to this file ------------------- */

typedef struct touchingfuncparms
{
    Point 		tfp_point;
    TileTypeBitMask	tfp_types;
} TouchingFuncParms;


/*
 * ----------------------------------------------------------------------------
 *
 * TouchingTypes --
 *
 * Generate mask of all types touching or covering a given point.
 *
 * Results:
 *	Mask of all types touching or covering a given point in cellUse or
 *      expanded subcell.  If an unexpanded subcell is
 *      covering or touching point TT_SUBCELL is included in the result as
 *	well.
 *
 * Side effects:
 *	None.
 *
 * ----------------------------------------------------------------------------
 */
TileTypeBitMask
TouchingTypes(
    CellUse *cellUse,
    int expansionMask,
    Point *point)
{
    int touchingTypesFunc();
    int touchingSubcellsFunc();
    TouchingFuncParms parms;

    /* Search unit radius rectangle around point for paint tiles
     * (in cellUse or subcells expanded in cmd window) containing or
     * touching point
     */
    {
	SearchContext scx;

	scx.scx_area.r_ll = *point;
	scx.scx_area.r_ur = *point;
	scx.scx_area.r_ll.p_x -= 1;
	scx.scx_area.r_ll.p_y -= 1;
	scx.scx_area.r_ur.p_x += 1;
	scx.scx_area.r_ur.p_y += 1;

	scx.scx_trans = GeoIdentityTransform;
	scx.scx_use = cellUse;

	parms.tfp_point = *point;
	TTMaskZero(&(parms.tfp_types));

	DBTreeSrTiles(
		      &scx,
		      &DBAllButSpaceAndDRCBits,
		      expansionMask,
		      touchingTypesFunc,
		      (ClientData) &parms);
    }

    /* Now check for presence of unexpanded subcells */
    {
	SearchContext scx;

	scx.scx_area.r_ll = *point;
	scx.scx_area.r_ur = *point;
	scx.scx_area.r_ll.p_x -= 1;
	scx.scx_area.r_ll.p_y -= 1;
	scx.scx_area.r_ur.p_x += 1;
	scx.scx_area.r_ur.p_y += 1;

	scx.scx_trans = GeoIdentityTransform;
	scx.scx_use = cellUse;

	DBTreeSrCells(
		      &scx,
		      expansionMask,
		      touchingSubcellsFunc,
		      (ClientData) &parms);
    }

    return(parms.tfp_types);
}


/*
 * ---------------------------------------------------------------------
 *
 * touchingTypesFunc --
 *
 * Called by DBTreeSrTiles on behalf of touchingTypes above, to check if
 * tile touches point.
 *
 * Results:
 *      Returns 0 to continue search.
 *
 * Side effects:
 *	Sets tile type in mask if tile touches point.
 *
 * ---------------------------------------------------------------------
 */

int
touchingTypesFunc(
    Tile *tile,
    TileType dinfo,	/* (unused, but should be handled) */
    TreeContext *cxp)
{
    SearchContext *scx = cxp->tc_scx;
    Rect r, rDest;
    TouchingFuncParms *parms = (TouchingFuncParms *) (cxp->tc_filter->tf_arg);

    /* Transform to result coordinates */
    TITORECT(tile, &r);
    GEOCLIP(&r, &scx->scx_area);
    GEOTRANSRECT(&scx->scx_trans, &r, &rDest);

    if(GEO_ENCLOSE(&(parms->tfp_point), &rDest))
        TTMaskSetType(&(parms->tfp_types),TiGetType(tile));

    /* return 0 to continue search */
    return(0);
}


/*
 * ---------------------------------------------------------------------
 *
 * touchingSubcellsFunc --
 *
 * Called by DBTreeSrCells on behalf of touchingTypes above, to check if
 * subcell touches point.
 *
 * Results:
 *      Returns 0 if subcell doesn't touch point (to continue search)
 *	Returns 1 on match (to terminate search)
 *
 * Side effects:
 *	Sets TT_SUBCELL in mask if subcell touches point.
 *
 * ---------------------------------------------------------------------
 */

int
touchingSubcellsFunc(
    SearchContext *scx,
    ClientData cdarg)
{
    Rect r, rDest;
    TouchingFuncParms *parms = (TouchingFuncParms *) cdarg;

    /* Transform bounding box to result coordinates */
    r = scx->scx_use->cu_def->cd_bbox;
    GEOTRANSRECT(&scx->scx_trans, &r, &rDest);

    if(GEO_ENCLOSE(&(parms->tfp_point), &rDest))
    {
	/* touching subcell found, mark in types mask, and terminate search */
        TTMaskSetType(&(parms->tfp_types),TT_SUBCELL);
	return 1;	/* 1 = abort search */
    }
    else
    {
        /* subcell doesn't touch point after all, continue search */
        return 0;	/* 0 = continue search */
    }
}
