/* CIFreadpaint.c - * * This file contains more routines to parse CIF files. In * particular, it contains the routines to handle paint, * including rectangles, wires, flashes, and polygons. * * ********************************************************************* * * 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[] = "$Header: /ufs/repository/magic/cif/CIFrdpt.c,v 1.5 2001/03/29 19:50:04 tim Exp $"; #endif #include #include #include "misc/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "windows/windows.h" #include "main/main.h" #include "cif/CIFint.h" #include "cif/CIFread.h" /* * ---------------------------------------------------------------------------- * * CIFParseBox -- * * This procedure parses a CIF box command. * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * A box is added to the CIF information for this cell. The * box better not have corners that fall on half-unit boundaries. * * Correction: * A box may be centered on a half lambda grid but have width * and height such that the resulting box is entirely on the lambda * grid. So: don't divide by 2 until the last step! * ---Tim Edwards, 4/20/00 * * ---------------------------------------------------------------------------- */ bool CIFParseBox() { int length; int width; Point center; Point direction; Rect rectangle, r2; /* Take the 'B'. */ TAKE(); if (cifReadPlane == NULL) { CIFSkipToSemi(); return FALSE; } if (!CIFParseInteger(&length)) { CIFReadError("box, but no length; ignored.\n"); CIFSkipToSemi(); return FALSE; } length = (length * cifReadScale1 * cifCurReadStyle->crs_divider) / cifReadScale2; if (!CIFParseInteger(&width)) { CIFReadError("box, but no width; ignored.\n"); CIFSkipToSemi(); return FALSE; } width = (width * cifReadScale1 * cifCurReadStyle->crs_divider) / cifReadScale2; if (!CIFParsePoint(¢er, 2)) { CIFReadError("box, but no center; ignored.\n"); CIFSkipToSemi(); return FALSE; } rectangle.r_xbot = -length; rectangle.r_ybot = -width; rectangle.r_xtop = length; rectangle.r_ytop = width; /* Optional direction vector: have to build transform to do rotate. */ if (CIFParseSInteger(&direction.p_x)) { if (!CIFParseSInteger(&direction.p_y)) { CIFReadError("box, direction botched; box ignored.\n"); CIFSkipToSemi(); return FALSE; } GeoTransRect(CIFDirectionToTrans(&direction), &rectangle , &r2); } else r2 = rectangle; /* Offset by center only now that rotation is complete, and divide by two. */ r2.r_xbot = (r2.r_xbot + center.p_x) / 2; r2.r_ybot = (r2.r_ybot + center.p_y) / 2; r2.r_xtop = (r2.r_xtop + center.p_x) / 2; r2.r_ytop = (r2.r_ytop + center.p_y) / 2; DBPaintPlane(cifReadPlane, &r2, CIFPaintTable, (PaintUndoInfo *) NULL); return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFParseFlash -- * * This routine parses and processes a roundflash command. The syntax is: * roundflash ::= R diameter center * * We approximate a roundflash by a box. * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * Paint is added to the current CIF plane. * * Corrections: Incorrectly implemented. Now CIFParsePoint returns the * center coordinate doubled; in this way, the center can be on the * half-lambda grid but the resulting block on-grid, if the diameter * is an odd number. * * ---------------------------------------------------------------------------- */ bool CIFParseFlash() { int diameter; Point center; Rect rectangle; /* Take the 'R'. */ TAKE(); if (cifReadPlane == NULL) { CIFSkipToSemi(); return FALSE; } if (!CIFParseInteger(&diameter)) { CIFReadError("roundflash, but no diameter; ignored.\n"); CIFSkipToSemi(); return FALSE; } diameter = (diameter * cifReadScale1 * cifCurReadStyle->crs_divider) / cifReadScale2; if (!CIFParsePoint(¢er, 2)) { CIFReadError("roundflash, but no center; ignored.\n"); CIFSkipToSemi(); return FALSE; } rectangle.r_xbot = (center.p_x - diameter) / 2; rectangle.r_ybot = (center.p_y - diameter) / 2; rectangle.r_xtop = (center.p_x + diameter) / 2; rectangle.r_ytop = (center.p_y + diameter) / 2; DBPaintPlane(cifReadPlane, &rectangle, CIFPaintTable, (PaintUndoInfo *) NULL); return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFParseWire -- * * This procedure parses CIF wire commands, and adds paint * to the current CIF cell. A wire command consists of * an integer width, then a path. * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * The current CIF planes are modified. * * ---------------------------------------------------------------------------- */ bool CIFParseWire() { int width; CIFPath *pathheadp; CIFPath *pathp; CIFPath *previousp; int xmin; int ymin; int xmax; int ymax; int temp; Rect segment; /* Take the 'W'. */ TAKE(); if (cifReadPlane == NULL) { CIFSkipToSemi(); return FALSE; } if (!CIFParseInteger(&width)) { CIFReadError("wire, but no width; ignored.\n"); CIFSkipToSemi(); return FALSE; } width = (width * cifReadScale1 * cifCurReadStyle->crs_divider) /cifReadScale2; if (!CIFParsePath(&pathheadp, 2)) { CIFReadError("wire, but improper path; ignored.\n"); CIFSkipToSemi(); return FALSE; } previousp = pathp = pathheadp; while (pathp != NULL) { xmin = previousp->cifp_x; xmax = pathp->cifp_x; ymin = previousp->cifp_y; ymax = pathp->cifp_y; /* Sort the points. */ if (xmax < xmin) { temp = xmin; xmin = xmax; xmax = temp; } if (ymax < ymin) { temp = ymin; ymin = ymax; ymax = temp; } /* Build the wire segment. */ segment.r_xbot = (xmin - width) / 2; segment.r_ybot = (ymin - width) / 2; segment.r_xtop = (xmax + width) / 2; segment.r_ytop = (ymax + width) / 2; DBPaintPlane(cifReadPlane, &segment, CIFPaintTable, (PaintUndoInfo *) NULL); previousp = pathp; pathp = pathp->cifp_next; } CIFFreePath(pathheadp); return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFParseLayer -- * * This procedure parses layer changes. The syntax is: * layer ::= L { blank } processchar layerchars * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * Switches the CIF plane where paint is being saved. * * ---------------------------------------------------------------------------- */ bool CIFParseLayer() { #define MAXCHARS 4 char name[MAXCHARS+1]; char c; int i; TileType type; /* Take the 'L'. */ TAKE(); CIFSkipBlanks(); /* Get the layer name. */ for (i=0; i<=MAXCHARS; i++) { c = PEEK(); if (isdigit(c) || isupper(c)) name[i] = TAKE(); else break; } name[i] = '\0'; /* Set current plane for use by the routines that parse geometric * elements. */ type = CIFReadNameToType(name, FALSE); if (type < 0) { cifReadPlane = NULL; cifCurLabelType = TT_SPACE; CIFReadError("layer %s isn't known in the current style.\n", name); } else { cifCurLabelType = cifCurReadStyle->crs_labelLayer[type]; cifReadPlane = cifCurReadPlanes[type]; } CIFSkipToSemi(); return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFParsePoly -- * * This procedure reads and processes a polygon command. The syntax is: * polygon ::= path * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * Paint is added to the current CIF plane. * * ---------------------------------------------------------------------------- */ bool CIFParsePoly() { CIFPath *pathheadp; LinkedRect *rectp; /* Take the 'P'. */ TAKE(); if (cifReadPlane == NULL) { CIFSkipToSemi(); return FALSE; } if (!CIFParsePath(&pathheadp, 1)) { CIFReadError("polygon, but improper path; ignored.\n"); CIFSkipToSemi(); return FALSE; } /* Convert the polygon to rectangles. */ #ifdef NONMANHATTAN rectp = CIFPolyToRects(pathheadp, cifReadPlane); #else rectp = CIFPolyToRects(pathheadp); #endif CIFFreePath(pathheadp); if (rectp == NULL) { /* The non-Manhattan geometry polygon parsing algorithm */ /* typically leaves behind degenerate paths, so they */ /* should not be considered erroneous. */ #ifndef NONMANHATTAN CIFReadError("bad polygon; ignored.\n"); #endif CIFSkipToSemi(); return FALSE; } for (; rectp != NULL ; rectp = rectp->r_next) { DBPaintPlane(cifReadPlane, &rectp->r_r, CIFPaintTable, (PaintUndoInfo *) NULL); freeMagic((char *) rectp); } return TRUE; }