/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Artwork.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.technologies;
import com.sun.electric.database.CellBackup;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.ImmutableElectricObject;
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.Poly;
import com.sun.electric.database.id.PrimitiveNodeId;
import com.sun.electric.database.prototype.PortCharacteristic;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.variable.ElectricObject;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.AbstractShapeBuilder;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.EdgeH;
import com.sun.electric.technology.EdgeV;
import com.sun.electric.technology.Foundry;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.PrimitivePort;
import com.sun.electric.technology.TechFactory;
import com.sun.electric.technology.TechPool;
import com.sun.electric.technology.Technology;
import java.awt.geom.Point2D;
/**
* This is the general purpose sketching technology.
*/
public class Artwork extends Technology
{
/**
* Key of Variable holding starting and ending angles.
* As a special case, NodeInst.checkPossibleVariableEffects()
* updates the node when this variable changes.
*/
public static final Variable.Key ART_DEGREES = Variable.newKey("ART_degrees");
/** key of Variable holding message text. */ public static final Variable.Key ART_MESSAGE = Variable.newKey("ART_message");
/** key of Variable holding color information */ public static final Variable.Key ART_COLOR = Variable.newKey("ART_color");
/** key of Variable holding color information */ public static final Variable.Key ART_PATTERN = Variable.newKey("ART_pattern");
/** the Artwork Technology object. */ public static Artwork tech() { return TechPool.getThreadTechPool().getArtwork(); }
/** number of lines in an ellipse */ private static final int ELLIPSEPOINTS = 30;
/** granularity of a spline */ private static final int SPLINEGRAIN = 20;
/** Defines a Pin node. */ public final PrimitiveNode pinNode;
/** Defines a Box node. */ public final PrimitiveNode boxNode;
/** Defines a Crossed-Box node. */ public final PrimitiveNode crossedBoxNode;
/** Defines a Filled-Box node. */ public final PrimitiveNode filledBoxNode;
/** Defines a Circle node. */ public final PrimitiveNode circleNode;
/** Defines a Filled-Circle node. */ public final PrimitiveNode filledCircleNode;
/** Defines a Spline node. */ public final PrimitiveNode splineNode;
/** Defines a Triangle node. */ public final PrimitiveNode triangleNode;
/** Defines a Filled-Triangle node. */ public final PrimitiveNode filledTriangleNode;
/** Defines a Arrow node. */ public final PrimitiveNode arrowNode;
/** Defines a Opened-Polygon node. */ public final PrimitiveNode openedPolygonNode;
/** Defines a Opened-Dotted-Polygon node. */ public final PrimitiveNode openedDottedPolygonNode;
/** Defines a Opened-Dashed-Polygon node. */ public final PrimitiveNode openedDashedPolygonNode;
/** Defines a Opened-Thicker-Polygon node. */ public final PrimitiveNode openedThickerPolygonNode;
/** Defines a Closed-Polygon node. */ public final PrimitiveNode closedPolygonNode;
/** Defines a Filled-Polygon node. */ public final PrimitiveNode filledPolygonNode;
/** Defines a Thick-Circle node. */ public final PrimitiveNode thickCircleNode;
/** Defines a Solid arc. */ public final ArcProto solidArc;
/** Defines a Dotted arc. */ public final ArcProto dottedArc;
/** Defines a Dashed arc. */ public final ArcProto dashedArc;
/** Defines a Thick arc. */ public final ArcProto thickerArc;
/** the layer */ public final Layer defaultLayer;
// -------------------- private and protected methods ------------------------
public Artwork(Generic generic, TechFactory techFactory)
{
super(generic, techFactory);
setTechShortName("Artwork");
setTechDesc("General-purpose artwork components");
setFactoryScale(2000, false); // in nanometers: really 2 micron
setNonStandard();
setNonElectrical();
setNoNegatedArcs();
setStaticTechnology();
//**************************************** LAYERS ****************************************
/** Graphics layer */
defaultLayer = Layer.newInstance(this, "Graphics",
new EGraphics(false, false, null, 0, 0,0,0,0.8,true,
new int[] {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}));
// The layer functions
defaultLayer.setFunction(Layer.Function.ART, Layer.Function.NONELEC); // Graphics
// The DXF names
defaultLayer.setFactoryDXFLayer("OBJECT"); // Graphics
//******************** ARCS ********************
/** Solid arc */
solidArc = newArcProto("Solid", 0, 0, ArcProto.Function.NONELEC,
new Technology.ArcLayer(defaultLayer, 0, Poly.Type.FILLED)
);
solidArc.setFactoryFixedAngle(false);
solidArc.setCurvable();
solidArc.setWipable();
solidArc.setFactoryAngleIncrement(0);
/** Dotted arc */
dottedArc = newArcProto("Dotted", 0, 0, ArcProto.Function.NONELEC,
new Technology.ArcLayer(defaultLayer, 0, Poly.Type.OPENEDT1)
);
dottedArc.setFactoryFixedAngle(false);
dottedArc.setCurvable();
dottedArc.setWipable();
dottedArc.setFactoryAngleIncrement(0);
/** Dashed arc */
dashedArc = newArcProto("Dashed", 0, 0, ArcProto.Function.NONELEC,
new Technology.ArcLayer(defaultLayer, 0, Poly.Type.OPENEDT2)
);
dashedArc.setFactoryFixedAngle(false);
dashedArc.setCurvable();
dashedArc.setWipable();
dashedArc.setFactoryAngleIncrement(0);
/** Thicker arc */
thickerArc = newArcProto("Thicker", 0, 0, ArcProto.Function.NONELEC,
new Technology.ArcLayer(defaultLayer, 0, Poly.Type.OPENEDT3)
);
thickerArc.setFactoryFixedAngle(false);
thickerArc.setCurvable();
thickerArc.setWipable();
thickerArc.setFactoryAngleIncrement(0);
//******************** RECTANGLE DESCRIPTIONS ********************
Technology.TechPoint [] box_1 = new Technology.TechPoint[] {
new Technology.TechPoint(EdgeH.makeLeftEdge(), EdgeV.makeCenter()),
new Technology.TechPoint(EdgeH.makeCenter(), EdgeV.makeTopEdge()),
new Technology.TechPoint(EdgeH.makeRightEdge(), EdgeV.makeBottomEdge()),
new Technology.TechPoint(EdgeH.makeCenter(), EdgeV.makeBottomEdge()),
};
Technology.TechPoint [] box_2 = new Technology.TechPoint[] {
new Technology.TechPoint(EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge()),
new Technology.TechPoint(new EdgeH(-0.125, 0), EdgeV.makeTopEdge()),
new Technology.TechPoint(new EdgeH(0.125, 0), EdgeV.makeBottomEdge()),
new Technology.TechPoint(EdgeH.makeRightEdge(), EdgeV.makeTopEdge()),
};
Technology.TechPoint [] box_4 = new Technology.TechPoint[] {
new Technology.TechPoint(EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge()),
new Technology.TechPoint(EdgeH.makeRightEdge(), EdgeV.makeBottomEdge()),
new Technology.TechPoint(EdgeH.makeCenter(), EdgeV.makeTopEdge()),
};
Technology.TechPoint [] box_6 = new Technology.TechPoint[] {
new Technology.TechPoint(EdgeH.makeCenter(), EdgeV.makeCenter()),
new Technology.TechPoint(EdgeH.makeRightEdge(), EdgeV.makeCenter()),
};
//******************** NODES ********************
/** Pin */
pinNode = PrimitiveNode.newInstance0("Pin", this, 1, 1,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.DISC, Technology.NodeLayer.POINTS, box_6)
});
pinNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, pinNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeCenter(), EdgeV.makeCenter(), EdgeH.makeCenter(), EdgeV.makeCenter())
});
pinNode.setFunction(PrimitiveNode.Function.PIN);
pinNode.setArcsWipe();
pinNode.setArcsShrink();
/** Box */
boxNode = PrimitiveNode.newInstance0("Box", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.CLOSED, Technology.NodeLayer.BOX, Technology.TechPoint.makeFullBox())
});
boxNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, boxNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "box", 180,0, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
boxNode.setFunction(PrimitiveNode.Function.ART);
boxNode.setEdgeSelect();
/** Crossed-Box */
crossedBoxNode = PrimitiveNode.newInstance0("Crossed-Box", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.CROSSED, Technology.NodeLayer.BOX, Technology.TechPoint.makeFullBox())
});
crossedBoxNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, crossedBoxNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "fbox", 180,0, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
crossedBoxNode.setFunction(PrimitiveNode.Function.ART);
/** Filled-Box */
filledBoxNode = PrimitiveNode.newInstance0("Filled-Box", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.FILLED, Technology.NodeLayer.BOX, Technology.TechPoint.makeFullBox())
});
filledBoxNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, filledBoxNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "fbox", 180,0, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
filledBoxNode.setFunction(PrimitiveNode.Function.ART);
filledBoxNode.setEdgeSelect();
/** Circle */
circleNode = PrimitiveNode.newInstance0("Circle", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.CIRCLE, Technology.NodeLayer.POINTS, box_6)
});
circleNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, circleNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
circleNode.setFunction(PrimitiveNode.Function.ART);
circleNode.setEdgeSelect();
/** Filled-Circle */
filledCircleNode = PrimitiveNode.newInstance0("Filled-Circle", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.DISC, Technology.NodeLayer.POINTS, box_6)
});
filledCircleNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, filledCircleNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
filledCircleNode.setFunction(PrimitiveNode.Function.ART);
filledCircleNode.setSquare();
filledCircleNode.setEdgeSelect();
/** Spline */
splineNode = PrimitiveNode.newInstance0("Spline", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.OPENED, Technology.NodeLayer.POINTS, box_2)
});
splineNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, splineNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
splineNode.setFunction(PrimitiveNode.Function.ART);
splineNode.setHoldsOutline();
splineNode.setEdgeSelect();
/** Triangle */
triangleNode = PrimitiveNode.newInstance0("Triangle", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.CLOSED, Technology.NodeLayer.POINTS, box_4)
});
triangleNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, triangleNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "triangle", 180,0, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
triangleNode.setFunction(PrimitiveNode.Function.ART);
triangleNode.setEdgeSelect();
/** Filled-Triangle */
filledTriangleNode = PrimitiveNode.newInstance0("Filled-Triangle", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.FILLED, Technology.NodeLayer.POINTS, box_4)
});
filledTriangleNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, filledTriangleNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "ftriangle", 180,0, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
filledTriangleNode.setFunction(PrimitiveNode.Function.ART);
filledTriangleNode.setEdgeSelect();
/** Arrow */
arrowNode = PrimitiveNode.newInstance0("Arrow", this, 2, 2,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.FILLED, Technology.NodeLayer.POINTS,
new Technology.TechPoint[]
{
new Technology.TechPoint(EdgeH.makeLeftEdge(), EdgeV.makeTopEdge()),
new Technology.TechPoint(EdgeH.makeRightEdge(), EdgeV.makeCenter()),
new Technology.TechPoint(EdgeH.makeCenter(), EdgeV.makeCenter()),
}),
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.FILLED, Technology.NodeLayer.POINTS,
new Technology.TechPoint[]
{
new Technology.TechPoint(EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge()),
new Technology.TechPoint(EdgeH.makeRightEdge(), EdgeV.makeCenter()),
new Technology.TechPoint(EdgeH.makeCenter(), EdgeV.makeCenter()),
})
// new Technology.NodeLayer(defaultLayer, 0, Poly.Type.OPENED, Technology.NodeLayer.POINTS,
// new Technology.TechPoint[]
// {
// new Technology.TechPoint(EdgeH.makeLeftEdge(), EdgeV.makeTopEdge()),
// new Technology.TechPoint(EdgeH.makeRightEdge(), EdgeV.makeCenter()),
// new Technology.TechPoint(EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge()),
// })
});
arrowNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, arrowNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "arrow", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeRightEdge(), EdgeV.makeCenter(), EdgeH.makeRightEdge(), EdgeV.makeCenter())
});
arrowNode.setFunction(PrimitiveNode.Function.ART);
arrowNode.setEdgeSelect();
/** Opened-Polygon */
openedPolygonNode = PrimitiveNode.newInstance0("Opened-Polygon", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.OPENED, Technology.NodeLayer.POINTS, box_2)
});
openedPolygonNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, openedPolygonNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
openedPolygonNode.setFunction(PrimitiveNode.Function.ART);
openedPolygonNode.setHoldsOutline();
openedPolygonNode.setEdgeSelect();
/** Opened-Dotted-Polygon */
openedDottedPolygonNode = PrimitiveNode.newInstance0("Opened-Dotted-Polygon", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.OPENEDT1, Technology.NodeLayer.POINTS, box_2)
});
openedDottedPolygonNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, openedDottedPolygonNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
openedDottedPolygonNode.setFunction(PrimitiveNode.Function.ART);
openedDottedPolygonNode.setHoldsOutline();
openedDottedPolygonNode.setEdgeSelect();
/** Opened-Dashed-Polygon */
openedDashedPolygonNode = PrimitiveNode.newInstance0("Opened-Dashed-Polygon", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.OPENEDT2, Technology.NodeLayer.POINTS, box_2)
});
openedDashedPolygonNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, openedDashedPolygonNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
openedDashedPolygonNode.setFunction(PrimitiveNode.Function.ART);
openedDashedPolygonNode.setHoldsOutline();
openedDashedPolygonNode.setEdgeSelect();
/** Opened-Thicker-Polygon */
openedThickerPolygonNode = PrimitiveNode.newInstance0("Opened-Thicker-Polygon", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.OPENEDT3, Technology.NodeLayer.POINTS, box_2)
});
openedThickerPolygonNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, openedThickerPolygonNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
openedThickerPolygonNode.setFunction(PrimitiveNode.Function.ART);
openedThickerPolygonNode.setHoldsOutline();
openedThickerPolygonNode.setEdgeSelect();
/** Closed-Polygon */
closedPolygonNode = PrimitiveNode.newInstance0("Closed-Polygon", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.CLOSED, Technology.NodeLayer.POINTS, box_1)
});
closedPolygonNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, closedPolygonNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
closedPolygonNode.setFunction(PrimitiveNode.Function.ART);
closedPolygonNode.setHoldsOutline();
closedPolygonNode.setEdgeSelect();
/** Filled-Polygon */
filledPolygonNode = PrimitiveNode.newInstance0("Filled-Polygon", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.FILLED, Technology.NodeLayer.POINTS, box_1)
});
filledPolygonNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, filledPolygonNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
filledPolygonNode.setFunction(PrimitiveNode.Function.ART);
filledPolygonNode.setHoldsOutline();
filledPolygonNode.setEdgeSelect();
/** Thick-Circle */
thickCircleNode = PrimitiveNode.newInstance0("Thick-Circle", this, 6, 6,
new Technology.NodeLayer []
{
new Technology.NodeLayer(defaultLayer, 0, Poly.Type.THICKCIRCLE, Technology.NodeLayer.POINTS, box_6)
});
thickCircleNode.addPrimitivePortsFixed(new PrimitivePort[]
{
PrimitivePort.newInstance(this, thickCircleNode, new ArcProto [] {solidArc, dottedArc, dashedArc, thickerArc}, "site", 0,180, 0, PortCharacteristic.UNKNOWN,
EdgeH.makeLeftEdge(), EdgeV.makeBottomEdge(), EdgeH.makeRightEdge(), EdgeV.makeTopEdge())
});
thickCircleNode.setFunction(PrimitiveNode.Function.ART);
thickCircleNode.setEdgeSelect();
// Foundry
newFoundry(Foundry.Type.NONE, null,
// The GDS names
"Graphics 1");
// noFoundry.setFactoryGDSLayer(defaultLayer, "1");
// defaultLayer.setFactoryGDSLayer("1", Foundry.Type.MOSIS.name()); // Graphics
oldArcNames.put("Dash-1", dottedArc);
oldArcNames.put("Dash-2", dashedArc);
oldArcNames.put("Dash-3", thickerArc);
oldNodeNames.put("Message", generic.invisiblePinNode);
oldNodeNames.put("Centered-Message", generic.invisiblePinNode);
oldNodeNames.put("Left-Message", generic.invisiblePinNode);
oldNodeNames.put("Right-Message", generic.invisiblePinNode);
oldNodeNames.put("Opened-FarDotted-Polygon", openedThickerPolygonNode);
loadFactoryMenuPalette(Artwork.class.getResource("artworkMenu.xml"));
}
/**
* Puts into shape builder s the polygons that describe node "n", given a set of
* NodeLayer objects to use.
* This method is overridden by specific Technologys.
* @param b shape builder where to put polygons
* @param n the ImmutableNodeInst that is being described.
* @param pn proto of the ImmutableNodeInst in this Technology
* @param primLayers an array of NodeLayer objects to convert to Poly objects.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
*/
@Override
protected void genShapeOfNode(AbstractShapeBuilder b, ImmutableNodeInst n, PrimitiveNode pn, Technology.NodeLayer[] primLayers) {
if (b.skipLayer(defaultLayer)) return;
EGraphics graphicsOverride = makeGraphics(n);
if (pn == circleNode || pn == thickCircleNode)
{
double [] angles = n.getArcDegrees();
if (n.size.getGridX() != n.size.getGridY())
{
// handle ellipses
Point2D [] pointList = fillEllipse(EPoint.ORIGIN, n.size.getLambdaX(), n.size.getLambdaY(),
angles[0], angles[1]);
for (Point2D p: pointList)
b.pushPoint(p.getX()*DBMath.GRID, p.getY()*DBMath.GRID);
Poly.Type style = pn == circleNode ? Poly.Type.OPENED : Poly.Type.OPENEDT3;
b.pushPoly(style, defaultLayer, graphicsOverride, null);
return;
}
// if there is arc information here, make it an arc of a circle
if (angles[0] != 0.0 || angles[1] != 0.0)
{
// fill an arc of a circle here
double dist = n.size.getGridX()*0.5;
b.pushPoint(EPoint.ORIGIN);
b.pushPoint(Math.cos(angles[0]+angles[1])*dist, Math.sin(angles[0]+angles[1])*dist);
b.pushPoint(Math.cos(angles[0])*dist, Math.sin(angles[0])*dist);
Poly.Type style = pn == circleNode ? Poly.Type.CIRCLEARC : Poly.Type.THICKCIRCLEARC;
b.pushPoly(style, defaultLayer, graphicsOverride, null);
return;
}
} else if (pn == splineNode)
{
Point2D [] tracePoints = n.getTrace();
if (tracePoints != null)
{
Point2D [] pointList = fillSpline(0, 0, tracePoints);
for (Point2D p: pointList)
b.pushPoint(p.getX()*DBMath.GRID, p.getY()*DBMath.GRID);
b.pushPoly(Poly.Type.OPENED, defaultLayer, graphicsOverride, null);
return;
}
}
b.genShapeOfNode(n, pn, primLayers, graphicsOverride);
}
/**
* Puts into shape builder s the polygons that describe node "n", given a set of
* NodeLayer objects to use.
* This method is overridden by specific Technologys.
* @param b shape builder where to put polygons
* @param n the ImmutableNodeInst that is being described.
* @param pn proto of the ImmutableNodeInst in this Technology
* @param selectPt if not null, it requests a new location on the port,
* away from existing arcs, and close to this point.
* This is useful for "area" ports such as the left side of AND and OR gates.
* The prototype of this NodeInst must be a PrimitiveNode and not a Cell.
*/
@Override
protected void genShapeOfPort(AbstractShapeBuilder b, ImmutableNodeInst n, PrimitiveNode pn, PrimitivePort pp, Point2D selectPt) {
if (pn == pinNode || pn == arrowNode || pn == circleNode || pn == thickCircleNode || pn == filledCircleNode)
{
b.genShapeOfPort(n, pn, pp);
return;
}
if (pn == splineNode)
{
EPoint [] tracePoints = n.getTrace();
if (tracePoints != null)
{
Point2D [] pointList = fillSpline(0, 0, tracePoints);
for (Point2D p: pointList)
b.pushPoint(p.getX()*DBMath.GRID, p.getY()*DBMath.GRID);
b.pushPoly(Poly.Type.OPENED, null, null, null);
return;
}
}
b.genShapeOfNode(n, pn, pn.getNodeLayers(), null);
}
/**
* Fill the polygons that describe arc "a".
* @param b AbstractShapeBuilder to fill polygons.
* @param a the ImmutableArcInst that is being described.
*/
@Override
protected void getShapeOfArc(AbstractShapeBuilder b, ImmutableArcInst a) {
getShapeOfArc(b, a, makeGraphics(a));
}
/**
* Tells if arc can be drawn by simplified algorithm
* Arcs with user-specified color or pattern are not easy
* @param a arc to test
* @param explain if true then print explanation why arc is not easy
* @return true if arc can be drawn by simplified algorithm
*/
@Override
public boolean isEasyShape(ImmutableArcInst a, boolean explain) {
if (a.getVar(Artwork.ART_COLOR) != null) {
if (explain) System.out.println("ART_COLOR");
return false;
}
if (a.getVar(Artwork.ART_PATTERN) != null) {
if (explain) System.out.println("ART_PATTERN");
return false;
}
return super.isEasyShape(a, explain);
}
/**
* Method to return an array of Point2D that describe an ellipse.
* @param center the center coordinate of the ellipse.
* @param sX the X size of the ellipse.
* @param sY the Y size of the ellipse.
* @param startoffset the starting angle of the ellipse, in radians.
* @param endangle the ending angle of the ellipse, in radians.
* If both startoffset and endangle are zero, draw the full ellipse.
* @return an array of points that describes the ellipse.
*/
public static Point2D [] fillEllipse(Point2D center, double sX, double sY, double startoffset, double endangle)
{
// ensure that the polygon can hold the vectors
boolean closed = true;
if (startoffset == 0 && endangle == 0)
{
// full ellipse
endangle = Math.PI * 2.0;
} else
{
// partial ellipse
closed = false;
}
int pts = (int)(endangle * ELLIPSEPOINTS / (Math.PI * 2.0));
if (pts < 3) pts = 3;
if (closed) pts++;
Point2D [] points = new Point2D.Double[pts];
// compute the length of the semi-major and semi-minor axes
double a = sX / 2;
double b = sY / 2;
if (closed)
{
// more efficient algorithm used for full ellipse drawing
double p = 2.0 * Math.PI / (ELLIPSEPOINTS-1);
double c2 = Math.cos(p); double s2 = Math.sin(p);
double c3 = 1.0; double s3 = 0.0;
for(int m=0; m<ELLIPSEPOINTS; m++)
{
points[m] = new Point2D.Double(center.getX() + a * c3, center.getY() + b * s3);
double t1 = c3*c2 - s3*s2;
s3 = s3*c2 + c3*s2;
c3 = t1;
}
} else
{
// less efficient algorithm for partial ellipse drawing
for(int m=0; m<pts; m++)
{
double p = startoffset + m * endangle / (pts-1);
double c2 = Math.cos(p); double s2 = Math.sin(p);
points[m] = new Point2D.Double(center.getX() + a * c2, center.getY() + b * s2);
}
}
return points;
}
/**
* Method to extract an X coordinate from an array.
* @param tracePoints the array of coordinate values.
* @param index the entry in the array to retrieve.
* @param cX an offset value to add to the retrieved value.
* @return the X coordinate value.
*/
private double getTracePointX(Point2D [] tracePoints, int index, double cX)
{
double v = tracePoints[index].getX();
return v + cX;
}
/**
* Method to extract an Y coordinate from an array.
* @param tracePoints the array of coordinate values.
* @param index the entry in the array to retrieve.
* @param cY an offset value to add to the retrieved value.
* @return the Y coordinate value.
*/
private double getTracePointY(Point2D [] tracePoints, int index, double cY)
{
double v = tracePoints[index].getY();
return v + cY;
}
/**
* Method to set default outline information on a NodeInst.
* Very few primitives have default outline information (usually just in the Artwork Technology).
* This method overrides the one in Technology.
* @param ni the NodeInst to load with default outline information.
*/
public void setDefaultOutline(NodeInst ni)
{
if (ni.isCellInstance()) return;
PrimitiveNode np = (PrimitiveNode)ni.getProto();
double x = ni.getAnchorCenterX();
double y = ni.getAnchorCenterY();
if (np == openedPolygonNode || np == openedDottedPolygonNode ||
np == openedDashedPolygonNode || np == openedThickerPolygonNode ||
np == splineNode)
{
EPoint [] outline = new EPoint[4];
outline[0] = new EPoint(x-3, y-3);
outline[1] = new EPoint(x-1, y+3);
outline[2] = new EPoint(x+1, y-3);
outline[3] = new EPoint(x+3, y+3);
ni.setTrace(outline);
}
if (np == closedPolygonNode || np == filledPolygonNode)
{
Point2D [] outline = new EPoint[4];
outline[0] = new EPoint(x+0, y-3);
outline[1] = new EPoint(x-3, y+0);
outline[2] = new EPoint(x+0, y+3);
outline[3] = new EPoint(x+3, y-3);
ni.setTrace(outline);
}
}
/**
* Method to convert the given spline control points into a spline curve.
* @param cX the center X coordinate of the spline.
* @param cY the center Y coordinate of the spline.
* @param tracePoints the array of control point values, alternating X/Y/X/Y.
* @return an array of points that describes the spline.
*/
public Point2D [] fillSpline(double cX, double cY, Point2D [] tracePoints)
{
int steps = SPLINEGRAIN;
int count = tracePoints.length;
int outPoints = (count - 1) * steps + 1;
Point2D [] points = new Point2D.Double[outPoints];
int out = 0;
double splineStep = 1.0 / steps;
double x2 = getTracePointX(tracePoints, 0, cX)*2 - getTracePointX(tracePoints, 1, cX);
double y2 = getTracePointY(tracePoints, 0, cY)*2 - getTracePointY(tracePoints, 1, cY);
double x3 = getTracePointX(tracePoints, 0, cX);
double y3 = getTracePointY(tracePoints, 0, cY);
double x4 = getTracePointX(tracePoints, 1, cX);
double y4 = getTracePointY(tracePoints, 1, cY);
for(int k = 2; k <= count; k++)
{
double x1 = x2; x2 = x3; x3 = x4;
double y1 = y2; y2 = y3; y3 = y4;
if (k == count)
{
x4 = getTracePointX(tracePoints, k-1, cX)*2 - getTracePointX(tracePoints, k-2, cX);
y4 = getTracePointY(tracePoints, k-1, cY)*2 - getTracePointY(tracePoints, k-2, cY);
} else
{
x4 = getTracePointX(tracePoints, k, cX);
y4 = getTracePointY(tracePoints, k, cY);
}
int i=0;
for(double t=0.0; i<steps; i++, t+= splineStep)
{
double tsq = t * t;
double t4 = tsq * t;
double t3 = -3.0*t4 + 3.0*tsq + 3.0*t + 1.0;
double t2 = 3.0*t4 - 6.0*tsq + 4.0;
double t1 = -t4 + 3.0*tsq - 3.0*t + 1.0;
double x = (x1*t1 + x2*t2 + x3*t3 + x4*t4) / 6.0;
double y = (y1*t1 + y2*t2 + y3*t3 + y4*t4) / 6.0;
points[out++] = new Point2D.Double(x, y);
}
}
// close the spline
points[out++] = new Point2D.Double(getTracePointX(tracePoints, count-1, cX),
getTracePointY(tracePoints, count-1, cY));
return points;
}
/**
* Method to create an EGraphics for an ElectricObject with color and pattern Variables.
* @param eObj the ElectricObject with graphics specifications.
* @return a new EGraphics that has the color and pattern.
*/
public EGraphics makeGraphics(ElectricObject eObj) {
return makeGraphics(eObj.getD());
}
/**
* Method to create an EGraphics for an ImmutableElectricObject with color and pattern Variables.
* @param d the ImmutableElectricObject with graphics specifications.
* @return a new EGraphics that has the color and pattern.
*/
private EGraphics makeGraphics(ImmutableElectricObject d)
{
// get the color and pattern information
Integer color = d.getVarValue(ART_COLOR, Integer.class);
Variable patternVar = d.getVar(ART_PATTERN);
if (color == null && patternVar == null) return null;
// make a fake layer with graphics
EGraphics graphics = defaultLayer.getFactoryGraphics();
// set the color if specified
if (color != null)
graphics = graphics.withColorIndex(color.intValue()); // autoboxing
// set the stipple pattern if specified
if (patternVar != null)
{
int len = patternVar.getLength();
if (len != 8 && len != 16 && len != 17)
{
System.out.println("'ART_pattern' length is incorrect");
return null;
}
graphics = graphics.withPatternedOnDisplay(true);
graphics = graphics.withPatternedOnPrinter(true);
graphics = graphics.withOutlined(null);
int [] pattern = new int[16];
Object obj = patternVar.getObject();
if (obj instanceof Integer[])
{
Integer [] pat = (Integer [])obj;
if (len == 17)
{
// the last entry specifies the outline texture
int outlineIndex = pat[16].intValue(); // autoboxing
graphics = graphics.withOutlined(EGraphics.Outline.findOutline(outlineIndex));
len = 16;
}
for(int i=0; i<len; i++)
pattern[i] = pat[i].intValue(); // autoboxing
} else if (obj instanceof Short[])
{
Short [] pat = (Short [])obj;
for(int i=0; i<len; i++)
pattern[i] = pat[i].shortValue();
graphics = graphics.withOutlined(EGraphics.Outline.PAT_S);
}
if (len == 8)
{
for(int i=0; i<8; i++) pattern[i+8] = pattern[i];
}
graphics = graphics.withPattern(pattern);
}
return graphics;
}
// /**
// * Method to set Variables on an ElectricObject to capture information in an EGraphics.
// * @param graphics the EGraphics to store on the ElectricObject.
// * @param eObj the ElectricObject that will have new graphics information.
// */
// public static void setGraphics(EGraphics graphics, ElectricObject eObj)
// {
// // see what is already on the object
// Variable colorVar = eObj.getVar(ART_COLOR, Integer.class);
// Variable patternVar = eObj.getVar(ART_PATTERN);
//
// // set the color if specified
// int transparent = graphics.getTransparentLayer();
// Color newColor = graphics.getColor();
// if (transparent == 0 && newColor == Color.BLACK)
// {
// if (colorVar != null) eObj.delVar(ART_COLOR);
// } else
// {
// int index = 0;
// if (transparent > 0) index = EGraphics.makeIndex(transparent); else
// index = EGraphics.makeIndex(newColor);
// eObj.newVar(ART_COLOR, new Integer(index));
// }
//
// // set the stipple pattern if specified
// if (graphics.isPatternedOnDisplay())
// {
// // set the pattern
// int [] pattern = graphics.getPattern();
// Integer [] pat = new Integer[17];
// for(int i=0; i<16; i++)
// pat[i] = new Integer(pattern[i]);
// pat[16] = new Integer(graphics.getOutlined().getIndex());
// eObj.newVar(ART_PATTERN, pat);
// } else
// {
// if (patternVar != null) eObj.delVar(ART_PATTERN);
// }
// }
//
// /**
// * Method to convert old primitive names to their proper NodeProtos.
// * @param name the name of the old primitive.
// * @return the proper PrimitiveNode to use (or null if none can be determined).
// */
// public PrimitiveNode convertOldNodeName(String name)
// {
// if (name.equals("Message") || name.equals("Centered-Message") ||
// name.equals("Left-Message") || name.equals("Right-Message"))
// return Generic.tech.invisiblePinNode;
// if (name.equals("Opened-FarDotted-Polygon")) return openedThickerPolygonNode;
// return null;
// }
//
// /**
// * Method to convert old primitive names to their proper ArcProtos.
// * @param name the name of the old primitive.
// * @return the proper ArcProto to use (or null if none can be determined).
// */
// public ArcProto convertOldArcName(String name)
// {
// if (name.equals("Dash-1")) return dottedArc;
// if (name.equals("Dash-2")) return dashedArc;
// if (name.equals("Dash-3")) return thickerArc;
// return null;
// }
/**
* Method to determ if ArcProto is an Artwork primitive arc
* @param p ArcProto reference
* @return true if primitive belongs to the Artwork technology
*/
public static boolean isArtworkArc(ArcProto p)
{
return (p == Artwork.tech().solidArc || p == Artwork.tech().dottedArc
|| p == Artwork.tech().dashedArc || p == Artwork.tech().thickerArc);
}
}