📄 poly.java
字号:
/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Poly.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.database.geometry;import com.sun.electric.database.ImmutableArcInst;import com.sun.electric.database.topology.ArcInst;import com.sun.electric.database.topology.NodeInst;import com.sun.electric.database.variable.DisplayedText;import com.sun.electric.database.variable.EditWindow0;import com.sun.electric.database.variable.ElectricObject;import com.sun.electric.database.variable.TextDescriptor;import com.sun.electric.database.variable.UserInterface;import com.sun.electric.database.variable.Variable;import com.sun.electric.technology.AbstractShapeBuilder;import com.sun.electric.technology.Layer;import com.sun.electric.technology.PrimitiveNode;import com.sun.electric.tool.Job;import java.awt.Font;import java.awt.font.GlyphVector;import java.awt.geom.AffineTransform;import java.awt.geom.Point2D;import java.awt.geom.Rectangle2D;import java.util.ArrayList;import java.util.Iterator;/** * Class to define a polygon of points. */public class Poly extends PolyBase { public static final Poly[] NULL_ARRAY = {}; /** the string (if of type TEXT) */ private String string; /** the text descriptor (if of type TEXT) */ private TextDescriptor descript; /** the ElectricObject/Variable (if of type TEXT) */ private DisplayedText dt; /** * The constructor creates a new Poly given an array of points. * @param points the array of coordinates. */ public Poly(Point2D [] points) { super(points); } /** * The constructor creates a new Poly that describes a rectangle. * @param cX the center X coordinate of the rectangle. * @param cY the center Y coordinate of the rectangle. * @param width the width of the rectangle. * @param height the height of the rectangle. */ public Poly(double cX, double cY, double width, double height) { super(cX, cY, width, height); } /** * The constructor creates a new Poly that describes a rectangle. * @param rect the Rectangle2D of the rectangle. */ public Poly(Rectangle2D rect) { super(rect); } /** * Method to return the String associated with this Poly. * This only applies to text Polys which display a message. * @return the String associated with this Poly. */ public String getString() { return string; } /** * Method to set the String associated with this Poly. * This only applies to text Polys which display a message. * @param string the String associated with this Poly. */ public void setString(String string) { this.string = string; } /** * Method to return the Text Descriptor associated with this Poly. * This only applies to text Polys which display a message. * Only the size, face, italic, bold, and underline fields are relevant. * @return the Text Descriptor associated with this Poly. */ public TextDescriptor getTextDescriptor() { return descript; } /** * Method to set the Text Descriptor associated with this Poly. * This only applies to text Polys which display a message. * Only the size, face, italic, bold, and underline fields are relevant. * @param descript the Text Descriptor associated with this Poly. */ public void setTextDescriptor(TextDescriptor descript) { this.descript = descript; } /** * Method to return the DisplayedText associated with this Poly. * This only applies to text Polys which display a message. * @return the DisplayedText associated with this Poly. */ public DisplayedText getDisplayedText() { return dt; } /** * Method to set the DisplayedText associated with this Poly. * This only applies to text Polys which display a message. * @param dt the DisplayedText associated with this Poly. */ public void setDisplayedText(DisplayedText dt) { this.dt = dt; } /** * Method to transformed the points in this Poly. * @param af transformation to apply. */ public void transform(AffineTransform af) { // Nothing to do if (af.getType() == AffineTransform.TYPE_IDENTITY) return; // special case for text if (getStyle().isText() && descript != null) { // for quadrant rotations, rotate the text angle too if ((af.getType() & AffineTransform.TYPE_QUADRANT_ROTATION) != 0) { double m00 = af.getScaleX(); double m01 = af.getShearX(); double m11 = af.getScaleY(); double m10 = af.getShearY(); if (m00 == 0 && m11 == 0) { // a 90/270 rotation if (m01 > m10) { // 270-degree rotation int ang = descript.getRotation().getAngle(); TextDescriptor.Rotation r = TextDescriptor.Rotation.getRotation((ang + 270) % 360); descript = descript.withRotation(r); } else { // 90-degree rotation int ang = descript.getRotation().getAngle(); TextDescriptor.Rotation r = TextDescriptor.Rotation.getRotation((ang + 90) % 360); descript = descript.withRotation(r); } } } } super.transform(af); } private static final int [] extendFactor = {0, 11459, 5729, 3819, 2864, 2290, 1908, 1635, 1430, 1271, 1143, 1039, 951, 878, 814, 760, 712, 669, 631, 598, 567, 540, 514, 492, 470, 451, 433, 417, 401, 387, 373, 361, 349, 338, 327, 317, 308, 299, 290, 282, 275, 267, 261, 254, 248, 241, 236, 230, 225, 219, 214, 210, 205, 201, 196, 192, 188, 184, 180, 177, 173, 170, 166, 163, 160, 157, 154, 151, 148, 146, 143, 140, 138, 135, 133, 130, 128, 126, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 104, 102, 100}; /** * Method to return the amount that an arc end should extend, given its width and extension factor. * @param width the width of the arc. * @param extend the extension factor (from 0 to 90). * @return the extension (from 0 to half of the width). */ public static double getExtendFactor(double width, int extend) { return extend <= 0 || extend >= 90 ? width*0.5 : width * 50 / extendFactor[extend]; } /** * Method to construct a Poly for an arc with a given length, width, angle, endpoint, and extension. * @param len the length of the arc. * @param wid the width of the arc. * @param angle the angle of the arc. * @param endH the head end of the arc. * @param extendH the head end extension distance of the arc. * @param endT the tail end of the arc. * @param extendT the tail end extension distance of the arc. * @param style the style of the polygon (filled, opened, etc.) * @return a Poly describing the outline of the arc. */ public static Poly makeEndPointPoly(double len, double wid, int angle, Point2D endH, double extendH, Point2D endT, double extendT, Poly.Type style) { double w2 = wid / 2; double x1 = endH.getX(); double y1 = endH.getY(); double x2 = endT.getX(); double y2 = endT.getY(); Point2D.Double [] points = null; // somewhat simpler if rectangle is manhattan if (angle == 900 || angle == 2700) { if (angle == 900)// if (y1 > y2) { double temp = y1; y1 = y2; y2 = temp; temp = extendH; extendH = extendT; extendT = temp; } points = new Point2D.Double[] { new Point2D.Double(x1 - w2, y1 - extendH), new Point2D.Double(x1 + w2, y1 - extendH), new Point2D.Double(x2 + w2, y2 + extendT), new Point2D.Double(x2 - w2, y2 + extendT)}; } else if (angle == 0 || angle == 1800) { if (angle == 0)// if (x1 > x2) { double temp = x1; x1 = x2; x2 = temp; temp = extendH; extendH = extendT; extendT = temp; } points = new Point2D.Double[] { new Point2D.Double(x1 - extendH, y1 - w2), new Point2D.Double(x1 - extendH, y1 + w2), new Point2D.Double(x2 + extendT, y2 + w2), new Point2D.Double(x2 + extendT, y2 - w2)}; } else { // nonmanhattan arcs cannot have zero length so re-compute it if (len == 0) len = endH.distance(endT); double xextra, yextra, xe1, ye1, xe2, ye2; if (len == 0) { double sa = DBMath.sin(angle); double ca = DBMath.cos(angle); xe1 = x1 - ca * extendH; ye1 = y1 - sa * extendH; xe2 = x2 + ca * extendT; ye2 = y2 + sa * extendT; xextra = ca * w2; yextra = sa * w2; } else { // work out all the math for nonmanhattan arcs xe1 = x1 - extendH * (x2-x1) / len; ye1 = y1 - extendH * (y2-y1) / len; xe2 = x2 + extendT * (x2-x1) / len; ye2 = y2 + extendT * (y2-y1) / len; // now compute the corners xextra = w2 * (x2-x1) / len; yextra = w2 * (y2-y1) / len; } points = new Point2D.Double[] { new Point2D.Double(yextra + xe1, ye1 - xextra), new Point2D.Double(xe1 - yextra, xextra + ye1), new Point2D.Double(xe2 - yextra, xextra + ye2), new Point2D.Double(yextra + xe2, ye2 - xextra)}; } if (wid != 0 && style.isOpened()) { points = new Point2D.Double[] {points[0], points[1], points[2], points[3], points[0]}; } Poly poly = new Poly(points); poly.setStyle(style); return poly; } /** * Method to convert text Polys to their precise bounds in a given window. * @param wnd the window. * @param eObj the ElectricObject on which this text resides. * If that ElectricObject is a NodeInst and the node is rotated, it affects the text anchor point. * @return true if the text is too small to display. */ public boolean setExactTextBounds(EditWindow0 wnd, ElectricObject eObj) { if (getString() == null) return true; String theString = getString().trim(); if (theString.length() == 0) return true; int numLines = 1; if (dt != null) { Variable var = dt.getVariable(); if (var != null) { numLines = var.getLength(); if (numLines > 1) { Object [] objList = (Object [])var.getObject(); for(int i=0; i<numLines; i++) { // empty line if (objList[i] == null) continue; String str = objList[i].toString(); if (str.length() > theString.length()) theString = str; } } } } Type style = getStyle(); style = rotateType(style, eObj); Font font = descript != null ? descript.getFont(wnd, 0) : TextDescriptor.getDefaultFont(); if (font == null) { UserInterface ui = Job.getUserInterface(); double size = ui.getDefaultTextSize(); if (descript != null) size = descript.getTrueSize(wnd); size = size/wnd.getScale(); if (size <= 0) size = 1; double cX = getBounds2D().getCenterX(); double cY = getBounds2D().getCenterY(); double sizeIndent = size / 4; double fakeWidth = theString.length() * size * 0.75; Point2D pt = getTextCorner(style, cX, cY, fakeWidth, size); cX = pt.getX(); cY = pt.getY(); points = new Point2D.Double[] { new Point2D.Double(cX, cY+sizeIndent), new Point2D.Double(cX+fakeWidth, cY+sizeIndent), new Point2D.Double(cX+fakeWidth, cY+size-sizeIndent), new Point2D.Double(cX, cY+size-sizeIndent)}; this.bounds = null; return false; } Rectangle2D bounds = getBounds2D(); double lX = bounds.getMinX(); double hX = bounds.getMaxX(); double lY = bounds.getMinY(); double hY = bounds.getMaxY(); GlyphVector gv = TextDescriptor.getGlyphs(theString, font); Rectangle2D glyphBounds = gv.getVisualBounds(); // adjust to place text in the center double textScale = getTextScale(wnd, gv, style, lX, hX, lY, hY); double textWidth = glyphBounds.getWidth(); double textHeight = font.getSize(); double scaledWidth = textWidth * textScale; double scaledHeight = textHeight * textScale; double cX = (lX + hX) / 2; double cY = (lY + hY) / 2; Point2D corner = getTextCorner(style, cX, cY, scaledWidth, scaledHeight);//System.out.println("STRING '"+theString+"' STYLE="+getStyle().name+" ROTSTYLE="+style.name+" FROM ("+cX+","+cY+") HAS CORNER ("+corner.getX()+","+corner.getY()+")"); cX = corner.getX(); cY = corner.getY(); double width = glyphBounds.getWidth() * textScale; double height = font.getSize() * textScale * numLines; switch (descript.getRotation().getIndex()) { case 1: // rotate 90 counterclockwise double saveWidth = width; width = -height; height = saveWidth; break; case 2: // rotate 180 width = -width; height = -height; break; case 3: // rotate 90 clockwise double saveHeight = height; height = -width; width = saveHeight; break; } points = new Point2D.Double[] { new Point2D.Double(cX, cY), new Point2D.Double(cX+width, cY), new Point2D.Double(cX+width, cY+height), new Point2D.Double(cX, cY+height)}; this.bounds = null; gv = null; // for GC and glyphBounds return false; } /** * Method to return the coordinates of the lower-left corner of text in a window. * @param style the anchor information for the text. * @param cX the center X bound of the polygon containing the text. * @param cY the center Y bound of the polygon containing the text. * @param scaledWidth the width of the polygon containing the text. * @param scaledHeight the height of the polygon containing the text. * @return the coordinates of the lower-left corner of the text. */ private Point2D getTextCorner(Poly.Type style, double cX, double cY, double scaledWidth, double scaledHeight) { double offX = 0, offY = 0; if (style == Type.TEXTCENT || style == Type.TEXTBOX) { offX = -scaledWidth/2; offY = -scaledHeight/2; } else if (style == Type.TEXTTOP) { offX = -scaledWidth/2; offY = -scaledHeight; } else if (style == Type.TEXTBOT) { offX = -scaledWidth/2; } else if (style == Type.TEXTLEFT) { offY = -scaledHeight/2; } else if (style == Type.TEXTRIGHT) { offX = -scaledWidth; offY = -scaledHeight/2; } else if (style == Type.TEXTTOPLEFT) { offY = -scaledHeight; } else if (style == Type.TEXTBOTLEFT) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -