/* * CalmaReadpaint.c -- * * Input of Calma GDS-II stream format. * Processing of paint (paths, boxes, and boundaries) and text. * * ********************************************************************* * * 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/calma/CalmaRdpt.c,v 1.5 2001/07/23 17:49:49 tim Exp $"; #endif #include #include #include "misc/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/utils.h" #include "utils/hash.h" #include "database/database.h" #include "database/databaseInt.h" #include "utils/malloc.h" #include "tech/tech.h" #include "cif/cif.h" #include "cif/CIFint.h" #include "cif/CIFread.h" #include "signals/signals.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "misc/styles.h" #include "textio/textio.h" #include "calma/calmaInt.h" extern int calmaNonManhattan; /* * ---------------------------------------------------------------------------- * * calmaElementBoundary -- * * Read a polygon. * * Results: * None. * * Side effects: * Paints one or more rectangles into one of the CIF planes. * * ---------------------------------------------------------------------------- */ Void calmaElementBoundary() { int dt, layer, ciftype; CIFPath *pathheadp; LinkedRect *rp; Plane *plane; /* Skip CALMA_ELFLAGS, CALMA_PLEX */ calmaSkipSet(calmaElementIgnore); /* Read layer and data type */ if (!calmaReadI2Record(CALMA_LAYER, &layer) || !calmaReadI2Record(CALMA_DATATYPE, &dt)) { calmaReadError("Missing layer or datatype in boundary/box.\n"); return; } /* Set current plane */ ciftype = CIFCalmaLayerToCifLayer(layer, dt, cifCurReadStyle); if (ciftype < 0) { plane = NULL; calmaLayerError("Unknown layer/datatype in boundary", layer, dt); } else plane = cifCurReadPlanes[ciftype]; /* Read the path itself, building up a path structure */ if (!calmaReadPath(&pathheadp)) { calmaReadError("Error while reading path for boundary/box; ignored.\n"); return; } /* Convert the polygon to rectangles. */ #ifdef NONMANHATTAN rp = CIFPolyToRects(pathheadp, plane); #else rp = CIFPolyToRects(pathheadp); #endif CIFFreePath(pathheadp); if (rp == NULL) { /* The non-Manhattan geometry polygon parsing algorithm */ /* typically leaves behind degenerate paths, so they */ /* should not be considered erroneous. */ #ifndef NONMANHATTAN calmaReadError("Can't convert boundary/box into rects; ignored.\n"); #endif return; } /* Paint the rectangles */ for (; rp != NULL ; rp = rp->r_next) { if (plane) DBPaintPlane(plane, &rp->r_r, CIFPaintTable, (PaintUndoInfo *)NULL); FREE((char *) rp); } } /* * ---------------------------------------------------------------------------- * * calmaElementBox -- * * Read a box. * This is an optimized version of calmaElementBoundary * that handles rectangular polygons. These polygons each * have five vertex points, with the first and last point * being the same, and all sides parallel to one of the two * coordinate axes. * * Results: * None. * * Side effects: * Paints one rectangle into one of the CIF planes. * * ---------------------------------------------------------------------------- */ Void calmaElementBox() { int nbytes, rtype, npoints; int dt, layer, ciftype; Plane *plane; Point p; Rect r; /* Skip CALMA_ELFLAGS, CALMA_PLEX */ calmaSkipSet(calmaElementIgnore); /* Read layer and data type */ if (!calmaReadI2Record(CALMA_LAYER, &layer) || !calmaReadI2Record(CALMA_BOXTYPE, &dt)) { calmaReadError("Missing layer or datatype in boundary/box.\n"); return; } /* Set current plane */ ciftype = CIFCalmaLayerToCifLayer(layer, dt, cifCurReadStyle); if (ciftype < 0) { calmaLayerError("Unknown layer/datatype in box", layer, dt); return; } else plane = cifCurReadPlanes[ciftype]; /* * Read the path itself. * Since it is Manhattan, we can build our rectangle directly. */ r.r_xbot = r.r_ybot = INFINITY; r.r_xtop = r.r_ytop = MINFINITY; /* Read the record header */ READRH(nbytes, rtype); if (nbytes < 0) { calmaReadError("EOF when reading box.\n"); return; } if (rtype != CALMA_XY) { calmaUnexpected(CALMA_XY, rtype); return; } /* Read this many points (pairs of four-byte integers) */ npoints = (nbytes - CALMAHEADERLENGTH) / 8; if (npoints != 5) { calmaReadError("Box doesn't have 5 points.\n"); (void) calmaSkipBytes(nbytes - CALMAHEADERLENGTH); return; } while (npoints-- > 0) { READPOINT(&p); if (p.p_x < r.r_xbot) r.r_xbot = p.p_x; if (p.p_y < r.r_ybot) r.r_ybot = p.p_y; if (p.p_x > r.r_xtop) r.r_xtop = p.p_x; if (p.p_y > r.r_ytop) r.r_ytop = p.p_y; } /* Paint the rectangle */ DBPaintPlane(plane, &r, CIFPaintTable, (PaintUndoInfo *)NULL); } /* * ---------------------------------------------------------------------------- * * calmaElementPath -- * * Read a centerline wire. * * Results: * None. * * Side effects: * May paint rectangles into CIF planes. * * ---------------------------------------------------------------------------- */ Void calmaElementPath() { static int ignore[] = { CALMA_BGNEXTN, CALMA_ENDEXTN, -1 }; int nbytes, rtype; int layer, dt, width, halfwidth, pathtype, ciftype; int xmin, ymin, xmax, ymax, temp; CIFPath *pathheadp, *pathp, *previousp; Rect segment; Plane *plane; int first,last; /* Skip CALMA_ELFLAGS, CALMA_PLEX */ calmaSkipSet(calmaElementIgnore); /* Grab layer and datatype */ if (!calmaReadI2Record(CALMA_LAYER, &layer)) return; if (!calmaReadI2Record(CALMA_DATATYPE, &dt)) return; /* Describes the shape of the ends of the path */ pathtype = CALMAPATH_SQUAREFLUSH; PEEKRH(nbytes, rtype); if (nbytes > 0 && rtype == CALMA_PATHTYPE) if (!calmaReadI2Record(CALMA_PATHTYPE, &pathtype)) return; if (pathtype == CALMAPATH_ROUND) calmaReadError("Warning: pathtype %d unsupported.\n", pathtype); /* * Width of this path. * Allow zero-width paths; we will ignore them later. */ width = 0; PEEKRH(nbytes, rtype) if (nbytes > 0 && rtype == CALMA_WIDTH) { if (!calmaReadI4Record(CALMA_WIDTH, &width)) { calmaReadError("Error in reading WIDTH in calmaElementPath()\n") ; return; } } halfwidth = (width * calmaReadScale1)/(calmaReadScale2 * 2); /* Skip BGNEXTN, ENDEXTN */ calmaSkipSet(ignore); /* Read the points in the path */ if (!calmaReadPath(&pathheadp)) { calmaReadError("Improper path; ignored.\n"); return; } /* Don't process zero-width paths any further */ if (width <= 0) goto freeit; /* Make sure we know about this type */ ciftype = CIFCalmaLayerToCifLayer(layer, dt, cifCurReadStyle); if (ciftype < 0) { calmaLayerError("Unknown layer/datatype in path", layer, dt); goto freeit; } plane = cifCurReadPlanes[ciftype]; for (previousp = pathheadp,pathp=pathheadp->cifp_next,first=TRUE,last=FALSE; pathp != NULL; pathp = pathp->cifp_next) { if (pathp->cifp_next == NULL) last = TRUE; xmin = previousp->cifp_x; xmax = pathp->cifp_x; ymin = previousp->cifp_y; ymax = pathp->cifp_y; if (xmin != xmax && ymin != ymax) { calmaReadError("Non-orthgonal path; ignored.\n"); return; } if (first == FALSE && last == FALSE) { /* middle segment; expand the endpoints */ if (xmax < xmin) temp = xmin, xmin = xmax, xmax = temp; if (ymax < ymin) temp = ymin, ymin = ymax, ymax = temp; segment.r_xbot = xmin-halfwidth; segment.r_ybot = ymin-halfwidth; segment.r_xtop = xmax+halfwidth; segment.r_ytop = ymax+halfwidth; } else { if (xmin == xmax) /* vertical wire */ { segment.r_xbot = xmin-halfwidth; segment.r_xtop = xmax+halfwidth; if (ymax < ymin) { segment.r_ybot = ymax; segment.r_ytop = ymin; if (first == FALSE|| pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_ytop += halfwidth; } if (last == FALSE || pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_ybot -= halfwidth; } } else { segment.r_ytop = ymax; segment.r_ybot = ymin; if (first == FALSE|| pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_ybot -= halfwidth; } if (last == FALSE|| pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_ytop += halfwidth; } } } if (ymin == ymax) /* horiz wire */ { segment.r_ybot = ymin-halfwidth; segment.r_ytop = ymax+halfwidth; if (xmax < xmin) { segment.r_xbot = xmax; segment.r_xtop = xmin; if (first == FALSE|| pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_xtop += halfwidth; } if (last == FALSE|| pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_xbot -= halfwidth; } } else { segment.r_xtop = xmax; segment.r_xbot = xmin; if (first == FALSE|| pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_xbot -= halfwidth; } if (last == FALSE || pathtype != CALMAPATH_SQUAREFLUSH) { segment.r_xtop += halfwidth; } } } } DBPaintPlane(plane, &segment, CIFPaintTable, (PaintUndoInfo *)NULL); previousp = pathp; first = FALSE; } /* All done */ freeit: CIFFreePath(pathheadp); } /* * ---------------------------------------------------------------------------- * * calmaElementText -- * * Read labels. * CURRENTLY UNIMPLEMENTED. * * Results: * None. * * Side effects: * Currently, none. * Eventually, may add labels to our label list. * * ---------------------------------------------------------------------------- */ bool calmaElementText() { static int ignore[] = { CALMA_PRESENTATION, CALMA_PATHTYPE, CALMA_WIDTH, CALMA_STRANS, CALMA_MAG, CALMA_ANGLE, -1 }; char *textbody = NULL; int nbytes, rtype; int layer, textt, cifnum; TileType type; Rect r; /* Skip CALMA_ELFLAGS, CALMA_PLEX */ calmaSkipSet(calmaElementIgnore); /* Grab layer and texttype */ if (!calmaReadI2Record(CALMA_LAYER, &layer)) return; if (!calmaReadI2Record(CALMA_TEXTTYPE, &textt)) return; cifnum = CIFCalmaLayerToCifLayer(layer, textt, cifCurReadStyle); if (cifnum < 0) { if(cifCurReadStyle->crs_flags & CRF_IGNORE_UNKNOWNLAYER_LABELS) type = -1; else { calmaLayerError("Label on unknown layer/datatype", layer, textt); type = TT_SPACE; } } else type = cifCurReadStyle->crs_labelLayer[cifnum]; /* Skip presentation, pathtype, width, and transform */ calmaSkipSet(ignore); /* Coordinates of text */ READRH(nbytes, rtype) if (nbytes < 0) return; if (rtype != CALMA_XY) { calmaUnexpected(CALMA_XY, rtype); return; } nbytes -= CALMAHEADERLENGTH; if (nbytes < 8) { calmaReadError("Not enough bytes in point record.\n"); } else { READPOINT(&r.r_ll); nbytes -= 8; } if (!calmaSkipBytes(nbytes)) return; r.r_ll.p_x /= cifCurReadStyle->crs_scaleFactor; r.r_ll.p_y /= cifCurReadStyle->crs_scaleFactor; r.r_ur = r.r_ll; /* String itself */ if (!calmaReadStringRecord(CALMA_STRING, &textbody)) return; /* Eliminate strange characters. */ { static bool algmsg = FALSE; bool changed = FALSE; char *cp; for (cp = textbody; *cp; cp++) { if (*cp <= ' ' | *cp > '~') { changed = TRUE; if (*cp == '\r' && *(cp+1) == '\0') *cp = '\0'; else if (*cp == '\r') *cp = '_'; else if (*cp == ' ') *cp = '_'; else *cp = '?'; } } if (changed) { TxError("Warning: weird characters fixed in label '%s'\n", textbody); if (!algmsg) { algmsg = TRUE; TxError(" (algorithm used: trailing dropped, and ' ' changed to '_', \n other non-printables changed to '?')\n"); } } } /* Place the label */ if (type >= 0) { (void) DBPutLabel(cifReadCellDef, &r, -1, textbody, type); } /* done with textbody */ if (textbody != NULL) freeMagic(textbody); } /* * ---------------------------------------------------------------------------- * * calmaReadPath -- * * This procedure parses a Calma path, which is an XY record * containing one or more points. * * Results: * TRUE is returned if the path was parsed successfully, * FALSE otherwise. * * Side effects: * Modifies the parameter pathheadpp to point to the path * that is constructed. * * ---------------------------------------------------------------------------- */ bool calmaReadPath(pathheadpp) CIFPath **pathheadpp; { CIFPath path, *pathtailp, *newpathp; int nbytes, rtype, npoints; bool nonManhattan = FALSE; *pathheadpp = (CIFPath *) NULL; pathtailp = (CIFPath *) NULL; path.cifp_next = (CIFPath *) NULL; /* Read the record header */ READRH(nbytes, rtype); if (nbytes < 0) { calmaReadError("EOF when reading path.\n"); return (FALSE); } if (rtype != CALMA_XY) { calmaUnexpected(CALMA_XY, rtype); return (FALSE); } /* Read this many points (pairs of four-byte integers) */ npoints = (nbytes - CALMAHEADERLENGTH) / 8; while (npoints--) { READPOINT(&path.cifp_point); if (ABS(path.cifp_x) > 5000000 || ABS(path.cifp_y) > 5000000) { TxError("Warning: Very large point in path: (%d, %d)\n", path.cifp_x, path.cifp_y); } if (feof(calmaInputFile)) { CIFFreePath(*pathheadpp); return (FALSE); } MALLOC(CIFPath *, newpathp, sizeof (CIFPath)); *newpathp = path; if (*pathheadpp) { /* * Check that this segment is Manhattan. If not, remember the * fact and later introduce extra stair-steps to make the path * Manhattan. We don't do the stair-step introduction here for * two reasons: first, the same code is also used by the Calma * module, and second, it is important to know which side of * the polygon is the outside when generating the stair steps. */ if (pathtailp->cifp_x != newpathp->cifp_x && pathtailp->cifp_y != (newpathp->cifp_y)) { if (!nonManhattan) { #ifndef NONMANHATTAN calmaNonManhattan++; #endif nonManhattan = TRUE; } } pathtailp->cifp_next = newpathp; } else *pathheadpp = newpathp; pathtailp = newpathp; } #ifndef NONMANHATTAN if (nonManhattan) CIFMakeManhattanPath(*pathheadpp); #endif return (*pathheadpp != NULL); } /* * ---------------------------------------------------------------------------- * * calmaLayerError -- * * This procedure is called when (layer, dt) doesn't map to a valid * Calma layer. The first time this procedure is called for a given * (layer, dt) pair, we print an error message; on subsequent times, * no error message is printed. * * Results: * None. * * Side effects: * An error message is printed if the first time for this (layer, dt). * Adds an entry to the HashTable calmaLayerHash if one is not * already present for this (layer, dt) pair. * * ---------------------------------------------------------------------------- */ Void calmaLayerError(mesg, layer, dt) char *mesg; int layer; int dt; { CalmaLayerType clt; HashEntry *he; clt.clt_layer = layer; clt.clt_type = dt; he = HashFind(&calmaLayerHash, (char *) &clt); if (HashGetValue(he) == (ClientData) NULL) { HashSetValue(he, (ClientData) 1); calmaReadError("%s, layer=%d type=%d\n", mesg, layer, dt); } }