/* CIFsee.c -
 *
 *	This file provides procedures for displaying CIF layers on
 *	the screen using the highlight facilities.
 *
 *     ********************************************************************* 
 *     * 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-7.4/cif/CIFsee.c,v 1.1.1.1 2006/04/10 22:02:12 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
#include "cif/CIFint.h"
#include "textio/textio.h"
#include "utils/undo.h"

/* The following variable holds the CellDef into which feedback
 * is to be placed for displaying CIF.
 */

static CellDef *cifSeeDef;

/* Verbosity of warning messages */
global int CIFWarningLevel = CIF_WARN_DEFAULT;

typedef struct {
   char *text;
   int  layer;
   int  style;
} SeeLayerData;

/*
 * ----------------------------------------------------------------------------
 *
 * cifSeeFunc --
 *
 * 	Called once for each tile that is to be displayed as feedback.
 *	This procedure enters the tile as feedback.  Note: the caller
 *	must arrange for cifSeeDef to contain a pointer to the cell
 *	def where feedback is to be displayed.
 *
 * Results:
 *	Always returns 0 to keep the search alive.
 *
 * Side effects:
 *	A new feedback area is created over the tile.  The parameter
 *	"text" is associated with the feedback.
 * ----------------------------------------------------------------------------
 */

int
cifSeeFunc(tile, sld)
    Tile *tile;			/* Tile to be entered as feedback. */
    SeeLayerData *sld;		/* Layer and explanation for the feedback. */
{
    Rect area;

    TiToRect(tile, &area);

    if (((area.r_xbot & 0x1) || (area.r_ybot & 0x1))
                && (CIFWarningLevel == CIF_WARN_ALIGN))
    {
	TxError("Warning: Corner (%.1f, %.1f) has half-lambda placement.\n",
		(float)area.r_xbot / (float)CIFCurStyle->cs_scaleFactor,
		(float)area.r_ybot / (float)CIFCurStyle->cs_scaleFactor);
    }

    DBWFeedbackAdd(&area, sld->text, cifSeeDef, CIFCurStyle->cs_scaleFactor,
#ifdef NONMANHATTAN 
	sld->style |
                (TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
        /* (preserve information about the geometry of a diagonal tile) */
#else
	sld->style);
#endif
    return 0;
}

/*
 * ----------------------------------------------------------------------------
 *
 * CIFSeeLayer --
 *
 * 	Generates CIF over a given area of a given cell, then
 *	highlights a particular CIF layer on the screen.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Highlight information is drawn on the screen.
 *
 * ----------------------------------------------------------------------------
 */

void
CIFSeeLayer(rootDef, area, layer)
    CellDef *rootDef;		/* Cell for which to generate CIF.  Must be
				 * the rootDef of a window.
				 */
    Rect *area;			/* Area in which to generate CIF. */
    char *layer;		/* CIF layer to highlight on the screen. */
{
    int oldCount, i;
    char msg[100];
    SearchContext scx;
    SeeLayerData sld;
    TileTypeBitMask mask;

    /* Make sure the desired layer exists. */

    if (!CIFNameToMask(layer, &mask))
	return;

    /* Flatten the area and generate CIF for it. */

    CIFErrorDef = rootDef;
    CIFInitCells();
    UndoDisable();
    CIFDummyUse->cu_def = rootDef;
    GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
    scx.scx_use = CIFDummyUse;
    scx.scx_trans = GeoIdentityTransform;
    (void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
	cifHierCopyFunc, (ClientData) CIFComponentDef);
    oldCount = DBWFeedbackCount;
    CIFGen(CIFComponentDef, area, CIFPlanes, &DBAllTypeBits, TRUE, TRUE);
    DBCellClearDef(CIFComponentDef);

    /* Report any errors that occurred. */

    if (DBWFeedbackCount != oldCount)
    {
	TxPrintf("%d problems occurred.  See feedback entries.\n",
	    DBWFeedbackCount-oldCount);
    }

    /* Display the chosen layer. */

    (void) sprintf(msg, "CIF layer \"%s\"", layer);
    cifSeeDef = rootDef;
    sld.text = msg;
    for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
    {
	if (!TTMaskHasType(&mask, i)) continue;
	sld.layer = i;
#ifdef THREE_D
	sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle + TECHBEGINSTYLES;
#else
	sld.style = STYLE_PALEHIGHLIGHTS;
#endif
	(void) DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
	    &CIFSolidBits, cifSeeFunc, (ClientData)&sld);
    }
    UndoEnable();
}

/*
 * ----------------------------------------------------------------------------
 *
 * CIFSeeHierLayer --
 *
 * 	This procedure is similar to CIFSeeLayer except that it only
 *	generates hierarchical interaction information.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	CIF information is highlighed on the screen.  If arrays is
 *	TRUE, then CIF that stems from array interactions is displayed.
 *	if subcells is TRUE, then CIF stemming from subcell interactions
 *	is displayed.  If both are TRUE, then both are displayed.
 *
 * ----------------------------------------------------------------------------
 */

void
CIFSeeHierLayer(rootDef, area, layer, arrays, subcells)
    CellDef *rootDef;		/* Def in which to compute CIF.  Must be
				 * the root definition of a window.
				 */
    Rect *area;			/* Area in which to generate CIF. */
    char *layer;		/* CIF layer to be highlighted. */
    bool arrays;		/* TRUE means show array interactions. */
    bool subcells;		/* TRUE means show subcell interactions. */
{
    int i, oldCount;
    SeeLayerData sld;
    char msg[100];
    TileTypeBitMask mask;

    /* Check out the CIF layer name. */

    if (!CIFNameToMask(layer, &mask)) return;

    CIFErrorDef = rootDef;
    oldCount = DBWFeedbackCount;
    CIFClearPlanes(CIFPlanes);
    if (subcells)
	CIFGenSubcells(rootDef, area, CIFPlanes);
    if (arrays)
	CIFGenArrays(rootDef, area, CIFPlanes);
    
    /* Report any errors that occurred. */

    if (DBWFeedbackCount != oldCount)
    {
	TxPrintf("%d problems occurred.  See feedback entries.\n",
	    DBWFeedbackCount - oldCount);
    }
    
    (void) sprintf(msg, "CIF layer \"%s\"", layer);
    cifSeeDef = rootDef;
    sld.text = msg;
    for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
    {
	if (!TTMaskHasType(&mask, i)) continue;
	sld.layer = i;
#ifdef THREE_D
	sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle + TECHBEGINSTYLES;
#else
	sld.style = STYLE_PALEHIGHLIGHTS;
#endif
	(void) DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
	    &CIFSolidBits, cifSeeFunc, (ClientData)&sld);
    }
}

/*
 * ----------------------------------------------------------------------------
 *
 * CIFCoverageLayer --
 *
 *	This procedure reports the total area coverage of a CIF layer
 *	within the bounding box of the root CellDef.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Prints results.
 *
 * ----------------------------------------------------------------------------
 */

typedef struct {
   long long coverage;
   Rect bounds;
} coverstats;

void
CIFCoverageLayer(rootDef, area, layer)
    CellDef *rootDef;		/* Def in which to compute CIF coverage */
    Rect *area;			/* Area in which to compute coverage */
    char *layer;		/* CIF layer for coverage computation. */
{
    coverstats cstats;
    int i, scale;
    long long atotal, btotal;
    SearchContext scx;
    TileTypeBitMask mask;
    float fcover;
    int cifCoverageFunc();
    bool doBox = (area != &rootDef->cd_bbox) ? TRUE : FALSE;

    /* Check out the CIF layer name. */

    if (!CIFNameToMask(layer, &mask)) return;

    CIFErrorDef = rootDef;
    CIFInitCells();
    UndoDisable();
    CIFDummyUse->cu_def = rootDef;

    GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);

    scx.scx_use = CIFDummyUse;
    scx.scx_trans = GeoIdentityTransform;
    (void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
	cifHierCopyFunc, (ClientData) CIFComponentDef);
    CIFGen(CIFComponentDef, area, CIFPlanes, &DBAllTypeBits, TRUE, TRUE);
    DBCellClearDef(CIFComponentDef);
    
    cstats.coverage = 0;
    cstats.bounds.r_xbot = cstats.bounds.r_xtop = 0;
    cstats.bounds.r_ybot = cstats.bounds.r_ytop = 0;

    for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
    {
	if (!TTMaskHasType(&mask, i)) continue;
	(void) DBSrPaintArea((Tile *) NULL, CIFPlanes[i], &TiPlaneRect,
		&CIFSolidBits, cifCoverageFunc, (ClientData) &cstats);
    }

    /* Print results */

    scale = CIFCurStyle->cs_scaleFactor;

    btotal = (long long)(area->r_xtop - area->r_xbot);
    btotal *= (long long)(area->r_ytop - area->r_ybot);
    btotal *= (long long)(scale * scale);
    fcover = 0.0;
    if (btotal > 0.0) fcover = (float)cstats.coverage / (float)btotal;

    atotal = (long long)(cstats.bounds.r_xtop - cstats.bounds.r_xbot);
    atotal *= (long long)(cstats.bounds.r_ytop - cstats.bounds.r_ybot);

    TxPrintf("%s Area = %lld CIF units^2\n", doBox ?  "Cursor Box" :
		"Cell", btotal);
    TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
    TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
    TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
		"cell", 100.0 * fcover);
}

int
cifCoverageFunc(tile, arg)
    Tile *tile;
    ClientData *arg;
{
    coverstats *cstats = (coverstats *)arg;
    Rect r;

    TiToRect(tile, &r);
    cstats->coverage += (long long)((r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot));
    GeoInclude(&r, &cstats->bounds);

    return(0);
}
