/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: BoundsBuilder.java * * Copyright (c) 2003 Sun Microsystems and Static Free Software * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.technology; import com.sun.electric.database.CellBackup; import com.sun.electric.database.ImmutableArcInst; import com.sun.electric.database.ImmutableNodeInst; import com.sun.electric.database.geometry.DBMath; import com.sun.electric.database.geometry.EGraphics; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.geometry.ERectangle; import com.sun.electric.database.geometry.GenMath; import com.sun.electric.database.geometry.Poly; import com.sun.electric.database.id.PrimitiveNodeId; import com.sun.electric.technology.technologies.Artwork; import com.sun.electric.technology.technologies.Schematics; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** * A support class to build shapes of arcs and nodes. */ public class BoundsBuilder extends AbstractShapeBuilder { private int intMinX, intMinY, intMaxX, intMaxY; private double doubleMinX, doubleMinY, doubleMaxX, doubleMaxY; private boolean hasIntBounds, hasDoubleBounds; public BoundsBuilder(CellBackup cellBackup) { setup(cellBackup, null, false, true, false, null); clear(); } public void clear() { hasIntBounds = hasDoubleBounds = false; } /** * Generate bounds of this ImmutableArcInst in easy case. * @param a ImmutableArcInst to examine. * @param intCoords integer coords to fill. * @return true if bounds were generated. */ public boolean genBoundsEasy(ImmutableArcInst a, int[] intCoords) { if (getMemoization().isHardArc(a.arcId)) return false; int gridExtendOverMin = (int)a.getGridExtendOverMin(); ArcProto protoType = getTechPool().getArcProto(a.protoId); int minLayerExtend = gridExtendOverMin + protoType.getMinLayerGridExtend(); if (minLayerExtend == 0) { assert protoType.getNumArcLayers() == 1; int x1 = (int)a.tailLocation.getGridX(); int y1 = (int)a.tailLocation.getGridY(); int x2 = (int)a.headLocation.getGridX(); int y2 = (int)a.headLocation.getGridY(); if (x1 <= x2) { intCoords[0] = x1; intCoords[2] = x2; } else { intCoords[0] = x2; intCoords[2] = x1; } if (y1 <= y2) { intCoords[1] = y1; intCoords[3] = y2; } else { intCoords[1] = y2; intCoords[3] = y1; } } else { boolean tailExtended = false; if (a.isTailExtended()) { short shrinkT = getShrinkage().get(a.tailNodeId); if (shrinkT == AbstractShapeBuilder.Shrinkage.EXTEND_90) tailExtended = true; else if (shrinkT != AbstractShapeBuilder.Shrinkage.EXTEND_0) return false; } boolean headExtended = false; if (a.isHeadExtended()) { short shrinkH = getShrinkage().get(a.headNodeId); if (shrinkH == AbstractShapeBuilder.Shrinkage.EXTEND_90) headExtended = true; else if (shrinkH != AbstractShapeBuilder.Shrinkage.EXTEND_0) return false; } a.makeGridBoxInt(intCoords, tailExtended, headExtended, gridExtendOverMin + protoType.getMaxLayerGridExtend()); } return true; } public boolean genBoundsEasy(ImmutableNodeInst n, int[] intCoords) { TechPool techPool = getTechPool(); PrimitiveNode pn = techPool.getPrimitiveNode((PrimitiveNodeId)n.protoId); Technology tech = pn.getTechnology(); ERectangle full = pn.getFullRectangle(); long gridWidth = n.size.getGridX() + full.getGridWidth(); long gridHeight = n.size.getGridY() + full.getGridHeight(); if (gridWidth == 0 && gridHeight == 0) { intCoords[0] = intCoords[2] = (int)n.anchor.getGridX(); intCoords[1] = intCoords[3] = (int)n.anchor.getGridY(); return true; } // special case for arcs of circles if (tech instanceof Artwork && (pn == techPool.getArtwork().circleNode || pn == techPool.getArtwork().thickCircleNode)) { // see if this circle is only a partial one double [] angles = n.getArcDegrees(); if (angles[0] != 0.0 || angles[1] != 0.0) return false; } // schematic bus pins are so complex that only the technology knows their true size if (tech instanceof Schematics && pn == techPool.getSchematics().busPinNode) return false; // special case for pins that become steiner points if (pn.isWipeOn1or2() && !getMemoization().hasExports(n) && getMemoization().pinUseCount(n)) { intCoords[0] = intCoords[2] = (int)n.anchor.getGridX(); intCoords[1] = intCoords[3] = (int)n.anchor.getGridY(); return true; } // special case for polygonally-defined nodes: compute precise geometry if (pn.isHoldsOutline() && n.getTrace() != null) return false; int w2 = (int)(gridWidth >> 1); int h2 = (int)(gridHeight >> 1); if (n.orient.isManhattan()) { intCoords[0] = -w2; intCoords[1] = -h2; intCoords[2] = w2; intCoords[3] = h2; n.orient.rectangleBounds(intCoords); } else { Rectangle2D.Double mbb = new Rectangle2D.Double(); n.orient.rectangleBounds(-w2, -h2, w2, h2, 0, 0, mbb); intCoords[0] = GenMath.floorInt(mbb.getMinX()); intCoords[1] = GenMath.floorInt(mbb.getMinY()); intCoords[2] = -intCoords[0]; intCoords[3] = -intCoords[1]; } intCoords[0] += (int)n.anchor.getGridX(); intCoords[1] += (int)n.anchor.getGridY(); intCoords[2] += (int)n.anchor.getGridX(); intCoords[3] += (int)n.anchor.getGridY(); return true; } public ERectangle makeBounds() { if (!hasDoubleBounds) { if (!hasIntBounds) return null; int iw = intMaxX - intMinX; int ih = intMaxY - intMinY; return ERectangle.fromGrid(intMinX, intMinY, iw >= 0 ? iw : (long)intMaxX - (long)intMinX, ih >= 0 ? ih : (long)intMaxY - (long)intMinY); } if (hasIntBounds) { if (intMinX < doubleMinX) doubleMinX = intMinX; if (intMinY < doubleMinY) doubleMinY = intMinY; if (intMaxX > doubleMaxX) doubleMaxX = intMaxX; if (intMaxY > doubleMaxY) doubleMaxY = intMaxY; hasIntBounds = false; } long longMinX = GenMath.floorLong(doubleMinX); long longMaxX = GenMath.ceilLong(doubleMaxX); long longMinY = GenMath.floorLong(doubleMinY); long longMaxY = GenMath.ceilLong(doubleMaxY); return ERectangle.fromGrid(longMinX, longMinY, longMaxX - longMinX, longMaxY - longMinY); } public boolean makeBounds(EPoint anchor, Rectangle2D.Double visBounds) { double x, y, w, h; if (!hasDoubleBounds) { if (hasIntBounds) { x = intMinX; y = intMinY; int iw = intMaxX - intMinX; w = iw >= 0 ? iw : (long)intMaxX - (long)intMinX; int ih = intMaxY - intMinY; h = ih >= 0 ? ih : (long)intMaxY - (long)intMinY; } else { x = anchor.getGridX(); y = anchor.getGridY(); w = h = 0; } } else { if (hasIntBounds) { if (intMinX < doubleMinX) doubleMinX = intMinX; if (intMinY < doubleMinY) doubleMinY = intMinY; if (intMaxX > doubleMaxX) doubleMaxX = intMaxX; if (intMaxY > doubleMaxY) doubleMaxY = intMaxY; hasIntBounds = false; } x = GenMath.floorLong(doubleMinX); y = GenMath.floorLong(doubleMinY); w = GenMath.ceilLong(doubleMaxX) - x; h = GenMath.ceilLong(doubleMaxY) - y; } x = DBMath.gridToLambda(x); y = DBMath.gridToLambda(y); w = DBMath.gridToLambda(w); h = DBMath.gridToLambda(h); if (x == visBounds.getX() && y == visBounds.getY() && w == visBounds.getWidth() && h == visBounds.getHeight()) return false; visBounds.setRect(x, y, w, h); return true; } @Override public void addDoublePoly(int numPoints, Poly.Type style, Layer layer, EGraphics graphicsOverride, PrimitivePort pp) { if (style == Poly.Type.CIRCLEARC || style == Poly.Type.THICKCIRCLEARC) { Point2D.Double p0 = new Point2D.Double(doubleCoords[0], doubleCoords[1]); Point2D.Double p1 = new Point2D.Double(doubleCoords[2], doubleCoords[3]); Point2D.Double p2 = new Point2D.Double(doubleCoords[4], doubleCoords[5]); Rectangle2D bounds = GenMath.arcBBox(p1, p2, p0); if (!hasDoubleBounds) { doubleMinX = doubleMinY = Double.POSITIVE_INFINITY; doubleMaxX = doubleMaxY = Double.NEGATIVE_INFINITY; hasDoubleBounds = true; } if (bounds.getMinX() < doubleMinX) doubleMinX = bounds.getMinX(); if (bounds.getMaxX() > doubleMaxX) doubleMaxX = bounds.getMaxX(); if (bounds.getMinY() < doubleMinY) doubleMinY = bounds.getMinY(); if (bounds.getMaxY() > doubleMaxY) doubleMaxY = bounds.getMaxY(); return; } if (!hasDoubleBounds) { assert numPoints > 0; doubleMinX = doubleMaxX = doubleCoords[0]; doubleMinY = doubleMaxY = doubleCoords[1]; hasDoubleBounds = true; } if (style == Poly.Type.CIRCLE || style == Poly.Type.THICKCIRCLE || style == Poly.Type.DISC) { double cX = doubleCoords[0]; double cY = doubleCoords[1]; double radius = Point2D.distance(cX, cY, doubleCoords[2], doubleCoords[3]); if (cX - radius < doubleMinX) doubleMinX = cX - radius; if (cX + radius > doubleMaxX) doubleMaxX = cX + radius; if (cY - radius < doubleMinY) doubleMinY = cY - radius; if (cY + radius > doubleMaxY) doubleMaxY = cY + radius; return; } for (int i = 0; i < numPoints; i++) { double x = doubleCoords[i*2]; double y = doubleCoords[i*2 + 1]; if (x < doubleMinX) doubleMinX = x; if (x > doubleMaxX) doubleMaxX = x; if (y < doubleMinY) doubleMinY = y; if (y > doubleMaxY) doubleMaxY = y; } } @Override public void addIntPoly(int numPoints, Poly.Type style, Layer layer, EGraphics graphicsOverride, PrimitivePort pp) { int i = 0; if (!hasIntBounds) { int x = intCoords[0]; int y = intCoords[1]; intMinX = x; intMinY = y; intMaxX = x; intMaxY = y; hasIntBounds = true; i = 1; } while (i < numPoints) { int x = intCoords[i*2]; int y = intCoords[i*2 + 1]; if (x < intMinX) intMinX = x; if (x > intMinY) intMinY = x; if (y < intMinY) intMinY = y; if (y > intMaxY) intMaxY = y; i++; } } @Override public void addIntBox(int[] coords, Layer layer) { if (!hasIntBounds) { intMinX = coords[0]; intMinY = coords[1]; intMaxX = coords[2]; intMaxY = coords[3]; hasIntBounds = true; } else { if (coords[0] < intMinX) intMinX = coords[0]; if (coords[2] > intMaxX) intMaxX = coords[2]; if (coords[1] < intMinY) intMinY = coords[1]; if (coords[3] > intMaxY) intMaxY = coords[3]; } } }