/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ArcProto.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.EObjectInputStream;
import com.sun.electric.database.EObjectOutputStream;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.geometry.DBMath;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.id.ArcProtoId;
import com.sun.electric.database.id.PrimitiveNodeId;
import com.sun.electric.database.id.PrimitivePortId;
import com.sun.electric.tool.erc.ERCAntenna;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* The ArcProto class defines a type of ArcInst.
* <P>
* Every arc in the database appears as one <I>prototypical</I> object and many <I>instantiative</I> objects.
* Thus, for a ArcProto such as the CMOS Metal-1 there is one object (called a ArcProto)
* that describes the wire prototype and there are many objects (called ArcInsts),
* one for every instance of a Metal-1 wire that appears in a circuit.
* ArcProtos are statically created and placed in the Technology objects.
* <P>
* The basic ArcProto has a name, default width, function, Layers that describes it graphically and more.
*/
public class ArcProto implements Comparable<ArcProto>, Serializable
{
/**
* Function is a typesafe enum class that describes the function of an ArcProto.
* Functions are technology-independent and include different types of metal,
* polysilicon, and other basic wire types.
*/
public static enum Function
{
/** Describes an arc with unknown type. */
UNKNOWN("unknown", 0, 0),
/** Describes an arc on Metal layer 1. */
METAL1("metal-1", 1, 0),
/** Describes an arc on Metal layer 2. */
METAL2("metal-2", 2, 0),
/** Describes an arc on Metal layer 3. */
METAL3("metal-3", 3, 0),
/** Describes an arc on Metal layer 4. */
METAL4("metal-4", 4, 0),
/** Describes an arc on Metal layer 5. */
METAL5("metal-5", 5, 0),
/** Describes an arc on Metal layer 6. */
METAL6("metal-6", 6, 0),
/** Describes an arc on Metal layer 7. */
METAL7("metal-7", 7, 0),
/** Describes an arc on Metal layer 8. */
METAL8("metal-8", 8, 0),
/** Describes an arc on Metal layer 9. */
METAL9("metal-9", 9, 0),
/** Describes an arc on Metal layer 10. */
METAL10("metal-10", 10, 0),
/** Describes an arc on Metal layer 11. */
METAL11("metal-11", 11, 0),
/** Describes an arc on Metal layer 12. */
METAL12("metal-12", 12, 0),
/** Describes an arc on Polysilicon layer 1. */
POLY1("polysilicon-1", 0, 1),
/** Describes an arc on Polysilicon layer 2. */
POLY2("polysilicon-2", 0, 2),
/** Describes an arc on Polysilicon layer 3. */
POLY3("polysilicon-3", 0, 3),
/** Describes an arc on the Diffusion layer. */
DIFF("diffusion", 0, 0),
/** Describes an arc on the P-Diffusion layer. */
DIFFP("p-diffusion", 0, 0),
/** Describes an arc on the N-Diffusion layer. */
DIFFN("n-diffusion", 0, 0),
/** Describes an arc on the Substrate-Diffusion layer. */
DIFFS("substrate-diffusion", 0, 0),
/** Describes an arc on the Well-Diffusion layer. */
DIFFW("well-diffusion", 0, 0),
/** Describes an arc on the Well layer (bias connections). */
WELL("well", 0, 0),
/** Describes a bus arc. */
BUS("bus", 0, 0),
/** Describes an arc that is unrouted (to be replaced by routers). */
UNROUTED("unrouted", 0, 0),
/** Describes an arc that is non-electrical (does not make a circuit connection). */
NONELEC("nonelectrical", 0, 0);
private final String printName;
private final int level;
private final boolean isMetal;
private final boolean isPoly;
private final boolean isDiffusion;
private static final Function[] metalLayers = initMetalLayers(Function.class.getEnumConstants());
private static final Function[] polyLayers = initPolyLayers(Function.class.getEnumConstants());
private Function(String printName, int metalLevel, int polyLevel) {
this.printName = printName;
isMetal = metalLevel != 0;
isPoly = polyLevel != 0;
isDiffusion = name().startsWith("DIFF");
level = isMetal ? metalLevel : isPoly ? polyLevel : 0;
}
/**
* Returns a printable version of this ArcProto.
* @return a printable version of this ArcProto.
*/
public String toString() { return printName; }
/**
* Returns the constant name for this Function.
* Constant names are used when writing Java code, so they must be the same as the actual symbol name.
* @return the constant name for this Function.
*/
public String getConstantName() { return name(); }
/**
* Method to return a List of all ArcProto functions.
* @return a List of all ArcProto functions.
*/
public static List<Function> getFunctions() { return Arrays.asList(Function.class.getEnumConstants()); }
/**
* Method to get the level of this ArcProto.Function.
* The level applies to metal and polysilicon functions, and gives the layer number
* (i.e. Metal-2 is level 2).
* @return the level of this ArcProto.Function.
*/
public int getLevel() { return level; }
/**
* Method to find the Function that corresponds to Metal on a given layer.
* @param level the layer (starting at 1 for Metal-1).
* @return the Function that represents that Metal layer.
*/
public static Function getMetal(int level) {
return level < metalLayers.length ? metalLayers[level] : null;
}
/**
* Method to find the Function that corresponds to Polysilicon on a given layer.
* @param level the layer (starting at 1 for Polysilicon-1).
* @return the Function that represents that Polysilicon layer.
*/
public static Function getPoly(int level) {
return level < polyLayers.length ? polyLayers[level] : null;
}
/**
* Method to find the Function that corresponds to a contact on a given arc.
* @param level the arc (starting at 1 for Contact-1).
* @return the Function that represents that Contact arc.
*/
public static Function getContact(int level)
{
return metalLayers[level];
}
/**
* Method to tell whether this ArcProto.Function is metal.
* @return true if this ArcProto.Function is metal.
*/
public boolean isMetal() { return isMetal; }
/**
* Method to tell whether this ArcProto.Function is polysilicon.
* @return true if this ArcProto.Function is polysilicon.
*/
public boolean isPoly() { return isPoly; }
/**
* Method to tell whether this ArcProto.Function is diffusion.
* @return true if this ArcProto.Function is diffusion.
*/
public boolean isDiffusion() { return isDiffusion; }
private static Function[] initMetalLayers(Function[] allFunctions) {
int maxLevel = -1;
for (Function fun: getFunctions()) {
if (!fun.isMetal()) continue;
maxLevel = Math.max(maxLevel, fun.level);
}
Function[] layers = new Function[maxLevel + 1];
for (Function fun: getFunctions()) {
if (!fun.isMetal()) continue;
assert layers[fun.level] == null;
layers[fun.level] = fun;
}
return layers;
}
private static Function[] initPolyLayers(Function[] allFunctions) {
int maxLevel = -1;
for (Function fun: getFunctions()) {
if (!fun.isPoly()) continue;
maxLevel = Math.max(maxLevel, fun.level);
}
Function[] layers = new Function[maxLevel + 1];
for (Function fun: getFunctions()) {
if (!fun.isPoly()) continue;
assert layers[fun.level] == null;
layers[fun.level] = fun;
}
return layers;
}
}
// ----------------------- private data -------------------------------
/** The name of this ArcProto. */ private final ArcProtoId protoId;
/** The technology in which this ArcProto resides. */ private final Technology tech;
/** The ELIB width offset */ private final double lambdaElibWidthOffset;
/** The base extend of this ArcProto in lambda units. */ private double lambdaBaseExtend;
/** The base extend of this ArcProto in grid units. */ private int gridBaseExtend;
/** The minimum extend among ArcLayers. */ private int minLayerGridExtend;
/** The minimum extend among ArcLayers. */ private int maxLayerGridExtend;
/** Flags bits for this ArcProto. */ private int userBits;
/** The function of this ArcProto. */ final Function function;
/** Layers in this arc */ final Technology.ArcLayer [] layers;
/** Pin for this arc */ PrimitiveNode arcPin;
/** Index of this ArcProto. */ final int primArcIndex;
/** factory default instance */ ImmutableArcInst factoryDefaultInst;
/** factory arc angle increment. */ private int factoryAngleIncrement = 90;
/** Factory value for arc antenna ratio. */ private double factoryAntennaRatio = Double.NaN;
// the meaning of the "userBits" field:
// /** these arcs are fixed-length */ private static final int WANTFIX = 01;
// /** these arcs are fixed-angle */ private static final int WANTFIXANG = 02;
// /** set if arcs should not slide in ports */ private static final int WANTCANTSLIDE = 04;
// /** set if ends do not extend by half width */ private static final int WANTNOEXTEND = 010;
// /** set if arcs should be negated */ private static final int WANTNEGATED = 020;
// /** set if arcs should be directional */ private static final int WANTDIRECTIONAL = 040;
/** set if arcs can wipe wipable nodes */ private static final int CANWIPE = 0100;
/** set if arcs can curve */ private static final int CANCURVE = 0200;
// /** arc function (from efunction.h) */ private static final int AFUNCTION = 017400;
// /** right shift for AFUNCTION */ private static final int AFUNCTIONSH = 8;
// /** angle increment for this type of arc */ private static final int AANGLEINC = 017760000;
// /** right shift for AANGLEINC */ private static final int AANGLEINCSH = 13;
/** set if arc is not selectable in palette */ private static final int ARCSPECIAL = 010000000;
/** set if arc is selectable by edge, not area */ private static final int AEDGESELECT = 020000000;
// /** set if arc is invisible and unselectable */ private static final int AINVISIBLE = 040000000;
/** set if arc is not used */ private static final int ANOTUSED = 020000000000;
/** set if node will be considered in palette */ private static final int SKIPSIZEINPALETTE = 0400;
// ----------------- protected and private methods -------------------------
/**
* The constructor is never called. Use "Technology.newArcProto" instead.
*/
ArcProto(Technology tech, String protoName, double lambdaElibWidthOffset, Function function, Technology.ArcLayer [] layers, int primArcIndex)
{
assert -Integer.MAX_VALUE/8 < gridBaseExtend && gridBaseExtend < Integer.MAX_VALUE/8;
if (!Technology.jelibSafeName(protoName))
System.out.println("ArcProto name " + protoName + " is not safe to write into JELIB");
protoId = tech.getId().newArcProtoId(protoName);
this.tech = tech;
this.userBits = 0;
this.function = function;
this.layers = layers.clone();
this.primArcIndex = primArcIndex;
this.lambdaElibWidthOffset = lambdaElibWidthOffset;
this.gridBaseExtend = layers[0].getGridExtend();
lambdaBaseExtend = DBMath.gridToLambda(gridBaseExtend);
computeLayerGridExtendRange();
PrimitivePortId ppId = protoId.techId.idManager.newTechId("generic").newPrimitiveNodeId("Universal-Pin").newPortId("");
factoryDefaultInst = ImmutableArcInst.newInstance(0, protoId, ImmutableArcInst.BASENAME, null,
0, ppId, EPoint.ORIGIN, 0, ppId, EPoint.ORIGIN, 0, 0, ImmutableArcInst.FACTORY_DEFAULT_FLAGS);
}
private void computeLayerGridExtendRange() {
long min = Long.MAX_VALUE, max = Long.MIN_VALUE;
for (int i = 0; i < layers.length; i++) {
Technology.ArcLayer primLayer = layers[i];
assert indexOf(primLayer.getLayer()) == i; // layers are unique
min = Math.min(min, getLayerGridExtend(i));
max = Math.max(max, getLayerGridExtend(i));
}
assert -Integer.MAX_VALUE/8 < min;
// assert 0 <= min;
assert max < Integer.MAX_VALUE/8 && min <= max;
minLayerGridExtend = (int)min;
maxLayerGridExtend = (int)max;
}
protected Object writeReplace() { return new ArcProtoKey(this); }
private static class ArcProtoKey extends EObjectInputStream.Key<ArcProto> {
public ArcProtoKey() {}
private ArcProtoKey(ArcProto ap) { super(ap); }
@Override
public void writeExternal(EObjectOutputStream out, ArcProto ap) throws IOException {
out.writeObject(ap.getTechnology());
out.writeInt(ap.getId().chronIndex);
}
@Override
public ArcProto readExternal(EObjectInputStream in) throws IOException, ClassNotFoundException {
Technology tech = (Technology)in.readObject();
int chronIndex = in.readInt();
ArcProto ap = tech.getArcProtoByChronIndex(chronIndex);
if (ap == null)
throw new InvalidObjectException("arc proto not found");
return ap;
}
}
// ------------------------ public methods -------------------------------
/**
* Method to return the Id of this ArcProto.
* @return the Id of this ArcProto.
*/
public ArcProtoId getId() { return protoId; }
/**
* Method to return the name of this ArcProto.
* @return the name of this ArcProto.
*/
public String getName() { return protoId.name; }
/**
* Method to return the full name of this ArcProto.
* Full name has format "techName:primName"
* @return the full name of this ArcProto.
*/
public String getFullName() { return protoId.fullName; }
/**
* Method to return the Technology of this ArcProto.
* @return the Technology of this ArcProto.
*/
public Technology getTechnology() { return tech; }
/**
* Method to return the default base width of this ArcProto in lambda units.
* This is the reported/selected width, which means that it does not include the width offset.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* This call returns only the width of the diffusion.
* @return the default base width of this ArcProto in lambda units.
*/
public double getDefaultLambdaBaseWidth() {
return getDefaultLambdaBaseWidth(EditingPreferences.getThreadEditingPreferences());
}
/**
* Method to return the default base width of this ArcProto in lambda units.
* This is the reported/selected width, which means that it does not include the width offset.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* This call returns only the width of the diffusion.
* @param ep EditingPreferences
* @return the default base width of this ArcProto in lambda units.
*/
public double getDefaultLambdaBaseWidth(EditingPreferences ep) {
return DBMath.gridToLambda(getDefaultGridBaseWidth(ep));
}
/**
* Method to return the factory default base width of this ArcProto in lambda units.
* This is the reported/selected width, which means that it does not include the width offset.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* This call returns only the width of the diffusion.
* @return the factory default base width of this ArcProto in lambda units.
*/
public double getFactoryDefaultLambdaBaseWidth() { return DBMath.gridToLambda(getFactoryDefaultGridBaseWidth()); }
/**
* Method to return the default base width of this ArcProto in grid units.
* This is the reported/selected width, which means that it does not include the width offset.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* This call returns only the width of the diffusion.
* @param ep EditingPreferences
* @return the default base width of this ArcProto in grid units.
*/
public long getDefaultGridBaseWidth(EditingPreferences ep) {
return 2*(getDefaultInst(ep).getGridExtendOverMin() + gridBaseExtend);
}
/**
* Method to return the factory default base width of this ArcProto in grid units.
* This is the reported/selected width, which means that it does not include the width offset.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* This call returns only the width of the diffusion.
* @return the factory default base width of this ArcProto in grid units.
*/
public long getFactoryDefaultGridBaseWidth() {
return 2*(factoryDefaultInst.getGridExtendOverMin() + gridBaseExtend);
}
/**
* Method to return the default immutable instance of this PrimitiveNode
* in specified EditingPreferences.
* @param ep specified EditingPreferences
* @return the default immutable instance of this PrimitiveNode
*/
public ImmutableArcInst getDefaultInst(EditingPreferences ep) {
ImmutableArcInst defaultInst = ep.getDefaultArc(protoId);
return defaultInst != null ? defaultInst : factoryDefaultInst;
}
/**
* Method to return the factory default immutable instance of this PrimitiveNode
* @return the factory default immutable instance of this PrimitiveNode
*/
public ImmutableArcInst getFactoryDefaultInst() {
return factoryDefaultInst;
}
/**
* Method to return the base width extend of this ArcProto in lambda units.
* This is the reported/selected width.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* This call returns only the half width of the diffusion of minimal-width arc.
* @return the default base width extend of this ArcProto in lambda units.
*/
public double getLambdaBaseExtend() { return lambdaBaseExtend; }
/**
* Method to return the base width extend of this ArcProto in grid units.
* This is the reported/selected width.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* This call returns only the half width of the diffusion of minimal-width arc.
* @return the default base width extend of this ArcProto in grid units.
*/
public int getGridBaseExtend() { return gridBaseExtend; }
/**
* Method to return the width offset of this ArcProto in lambda units.
* The width offset excludes the surrounding implang material.
* For example, diffusion arcs are always accompanied by a surrounding well and select.
* The offset amount is the difference between the diffusion width and the overall width.
* @return the width offset of this ArcProto in lambda units.
*/
public double getLambdaElibWidthOffset() { return lambdaElibWidthOffset; }
/**
* Method to return the minimal layer extend of this ArcProto in grid units.
* @return the minimal layer extend of this ArcProto in grid units.
*/
public int getMinLayerGridExtend() { return minLayerGridExtend; }
/**
* Method to return the maximal layer extend of this ArcProto in grid units.
* @return the maximal layer extend of this ArcProto in grid units.
*/
public int getMaxLayerGridExtend() { return maxLayerGridExtend; }
/**
* Method to set the factory antenna ratio of this ArcProto.
* Antenna ratios are used in antenna checks that make sure the ratio of the area of a layer is correct.
* @param ratio the antenna ratio of this ArcProto.
*/
public void setFactoryAntennaRatio(double ratio) {
assert Double.isNaN(factoryAntennaRatio);
factoryAntennaRatio = ratio;
}
/**
* Method to tell the default antenna ratio of this ArcProto.
* Antenna ratios are used in antenna checks that make sure the ratio of the area of a layer is correct.
* @return the default antenna ratio of this ArcProto.
*/
public double getFactoryAntennaRatio() { return factoryAntennaRatio; }
/**
* Method to set the "factory default" rigid state of this ArcProto.
* Rigid arcs cannot change length or the angle of their connection to a NodeInst.
* @param rigid true if this ArcProto should be rigid by factory-default.
*/
public void setFactoryRigid(boolean rigid) {
factoryDefaultInst = factoryDefaultInst.withFlag(ImmutableArcInst.RIGID, rigid);
}
/**
* Method to set the "factory default" fixed-angle state of this ArcProto.
* Fixed-angle arcs cannot change their angle, so if one end moves,
* the other may also adjust to keep the arc angle constant.
* @param fixed true if this ArcProto should be fixed-angle by factory-default.
*/
public void setFactoryFixedAngle(boolean fixed) {
factoryDefaultInst = factoryDefaultInst.withFlag(ImmutableArcInst.FIXED_ANGLE, fixed);
}
/**
* Method to set the "factory default" slidability state of this ArcProto.
* Arcs that slide will not move their connected NodeInsts if the arc's end is still within the port area.
* Arcs that cannot slide will force their NodeInsts to move by the same amount as the arc.
* Rigid arcs cannot slide but nonrigid arcs use this state to make a decision.
* @param slidable true if this ArcProto should be slidability by factory-default.
*/
public void setFactorySlidable(boolean slidable) {
factoryDefaultInst = factoryDefaultInst.withFlag(ImmutableArcInst.SLIDABLE, slidable);
}
/**
* Method to set the "factory default" end-extension state of this ArcProto.
* End-extension causes an arc to extend past its endpoint by half of its width.
* Most layout arcs want this so that they make clean connections to orthogonal arcs.
* @param extended true if this ArcProto should be end-extended by factory-default.
*/
public void setFactoryExtended(boolean extended) {
factoryDefaultInst = factoryDefaultInst.
withFlag(ImmutableArcInst.TAIL_EXTENDED, extended).
withFlag(ImmutableArcInst.HEAD_EXTENDED, extended);
}
/**
* Method to set the "factory default" directional state of this ArcProto.
* Directionality causes arrows to be drawn at the head, tail, or center of the arc.
* @param defaultDir has bit 0 set to put arrow on head, bit 1 set to put arrow on tail,
* bit 2 set to put arrow on body.
*/
public void setFactoryDirectional(int defaultDir) {
if ((defaultDir&1) != 0) factoryDefaultInst = factoryDefaultInst.withFlag(ImmutableArcInst.HEAD_ARROWED, true);
if ((defaultDir&2) != 0) factoryDefaultInst = factoryDefaultInst.withFlag(ImmutableArcInst.TAIL_ARROWED, true);
if ((defaultDir&4) != 0) factoryDefaultInst = factoryDefaultInst.withFlag(ImmutableArcInst.BODY_ARROWED, true);
}
/**
* Method to set this ArcProto so that it is not used.
* Unused arcs do not appear in the component menus and cannot be created by the user.
* The state is useful for hiding arcs that the user should not use.
* @param set
*/
public void setNotUsed(boolean set)
{
/* checkChanging();*/
if (set) userBits |= ANOTUSED;
else userBits &= ~ANOTUSED;
if (arcPin != null)
arcPin.setNotUsed(set);
}
/**
* Method to tell if this ArcProto is used.
* Unused arcs do not appear in the component menus and cannot be created by the user.
* The state is useful for hiding arcs that the user should not use.
* @return true if this ArcProto is used.
*/
public boolean isNotUsed() { return (userBits & ANOTUSED) != 0; }
/**
* Method to allow instances of this ArcProto not to be considered in
* tech palette for the calculation of the largest icon.
* Valid for menu display
*/
public void setSkipSizeInPalette() { userBits |= SKIPSIZEINPALETTE; }
/**
* Method to tell if instaces of this ArcProto are special (don't appear in menu).
* Valid for menu display
*/
public boolean isSkipSizeInPalette() { return (userBits & SKIPSIZEINPALETTE) != 0; }
/**
* Method to set this ArcProto so that instances of it can wipe nodes.
* For display efficiency reasons, pins that have arcs connected to them should not bother being drawn.
* Those arc prototypes that can erase their connecting pins have this state set,
* and when instances of these arcs connect to the pins, those pins stop being drawn.
* It is necessary for the pin node prototype to enable wiping (with setArcsWipe).
* A NodeInst that becomes wiped out has "setWiped" called.
*/
public void setWipable() { userBits |= CANWIPE; }
/**
* Method to set this ArcProto so that instances of it cannot wipe nodes.
* For display efficiency reasons, pins that have arcs connected to them should not bother being drawn.
* Those arc prototypes that can erase their connecting pins have this state set,
* and when instances of these arcs connect to the pins, those pins stop being drawn.
* It is necessary for the pin node prototype to enable wiping (with setArcsWipe).
* A NodeInst that becomes wiped out has "setWiped" called.
*/
public void clearWipable() { userBits &= ~CANWIPE; }
/**
* Method to tell if instances of this ArcProto can wipe nodes.
* For display efficiency reasons, pins that have arcs connected to them should not bother being drawn.
* Those arc prototypes that can erase their connecting pins have this state set,
* and when instances of these arcs connect to the pins, those pins stop being drawn.
* It is necessary for the pin node prototype to enable wiping (with setArcsWipe).
* A NodeInst that becomes wiped out has "setWiped" called.
* @return true if instances of this ArcProto can wipe nodes.
*/
public boolean isWipable() { return (userBits & CANWIPE) != 0; }
/**
* Method to set this ArcProto so that instances of it can curve.
* Since arc curvature is complex to draw, arcs with this capability
* must be marked this way.
* A curved arc has the variable "arc_radius" on it with a curvature factor.
*/
public void setCurvable() { userBits |= CANCURVE; }
/**
* Method to set this ArcProto so that instances of it cannot curve.
* Since arc curvature is complex to draw, arcs with this capability
* must be marked this way.
* A curved arc has the variable "arc_radius" on it with a curvature factor.
*/
public void clearCurvable() { userBits &= ~CANCURVE; }
/**
* Method to tell if instances of this ArcProto can curve.
* Since arc curvature is complex to draw, arcs with this capability
* must be marked this way.
* A curved arc has the variable "arc_radius" on it with a curvature factor.
* @return true if instances of this ArcProto can curve.
*/
public boolean isCurvable() { return (userBits & CANCURVE) != 0; }
/**
* Method to set this ArcProto so that instances of it can be selected by their edge.
* Artwork primitives that are not filled-in or are outlines want edge-selection, instead
* of allowing a click anywhere in the bounding box to work.
*/
public void setEdgeSelect() { userBits |= AEDGESELECT; }
/**
* Method to set this ArcProto so that instances of it cannot be selected by their edge.
* Artwork primitives that are not filled-in or are outlines want edge-selection, instead
* of allowing a click anywhere in the bounding box to work.
*/
public void clearEdgeSelect() { userBits &= ~AEDGESELECT; }
/**
* Method to tell if instances of this ArcProto can be selected by their edge.
* Artwork primitives that are not filled-in or are outlines want edge-selection, instead
* of allowing a click anywhere in the bounding box to work.
* @return true if instances of this ArcProto can be selected by their edge.
*/
public boolean isEdgeSelect() { return (userBits & AEDGESELECT) != 0; }
/**
* Method to allow instances of this ArcProto to be special in menu.
* Valid for menu display
*/
public void setSpecialArc() { userBits |= ARCSPECIAL; }
/**
* Method to tell if instaces of this ArcProto are special (don't appear in menu).
* Valid for menu display
*/
public boolean isSpecialArc() { return (userBits & ARCSPECIAL) != 0; }
/**
* Method to return the function of this ArcProto.
* The Function is a technology-independent description of the behavior of this ArcProto.
* @return function the function of this ArcProto.
*/
public ArcProto.Function getFunction() { return function; }
/**
* Method to set the factory-default angle of this ArcProto.
* This is only called from ArcProto during construction.
* @param angle the factory-default angle of this ArcProto.
*/
public void setFactoryAngleIncrement(int angle) { factoryAngleIncrement = angle; }
/**
* Method to get the angle increment on this ArcProto.
* The angle increment is the granularity on placement angle for instances
* of this ArcProto. It is in degrees.
* For example, a value of 90 requests that instances run at 0, 90, 180, or 270 degrees.
* A value of 0 allows arcs to be created at any angle.
* @param ep editing preferences with default increment
* @return the angle increment on this ArcProto.
*/
public int getAngleIncrement(EditingPreferences ep)
{
Integer angleIncrement = ep.getDefaultAngleIncrement(protoId);
return angleIncrement != null ? angleIncrement.intValue() : factoryAngleIncrement;
}
/**
* Method to get the default angle increment on this ArcProto.
* The angle increment is the granularity on placement angle for instances
* of this ArcProto. It is in degrees.
* For example, a value of 90 requests that instances run at 0, 90, 180, or 270 degrees.
* A value of 0 allows arcs to be created at any angle.
* @return the default angle increment on this ArcProto.
*/
public int getFactoryAngleIncrement() { return factoryAngleIncrement; }
/**
* Method to find the PrimitiveNode pin corresponding to this ArcProto type.
* Users can override the pin to use, and this method returns the user setting.
* For example, if this ArcProto is metal-1 then return the Metal-1-pin,
* but the user could set it to Metal-1-Metal-2-Contact.
* @param ep editing preferences with user overrides
* @return the PrimitiveNode pin to use for arc bends.
*/
public PrimitiveNode findOverridablePinProto(EditingPreferences ep)
{
// see if there is a default on this arc proto
PrimitiveNodeId pinId = ep.getDefaultArcPinId(protoId);
if (pinId != null)
{
PrimitiveNode np = tech.getPrimitiveNode(pinId);
if (np != null) return np;
}
return findPinProto();
}
/**
* Method to find the PrimitiveNode pin corresponding to this ArcProto type.
* For example, if this ArcProto is metal-1 then return the Metal-1-pin.
* @return the PrimitiveNode pin to use for arc bends.
*/
public PrimitiveNode findPinProto()
{
if (arcPin != null)
return arcPin;
// search for an appropriate pin
Iterator<PrimitiveNode> it = tech.getNodes();
while (it.hasNext())
{
PrimitiveNode pn = it.next();
if (pn.isPin())
{
if (pn.getNumPorts() > 1)
System.out.println("Missing cases in ArcProto:findPinProto");
PrimitivePort pp = (PrimitivePort) pn.getPorts().next();
if (pp.connectsTo(this)) return pn;
}
}
return null;
}
// public PrimitiveNode makeWipablePin(String pinName, String portName) {
// double defSize = DBMath.round(2*getLambdaBaseExtend() + getLambdaElibWidthOffset());
// return makeWipablePin(pinName, portName, defSize);
// }
public PrimitiveNode makeWipablePin(String pinName, String portName, double defSize, ArcProto ... extraArcs) {
double elibSize0 = DBMath.round(defSize*0.5);
double elibSize1 = DBMath.round(elibSize0 - 0.5*getLambdaElibWidthOffset());
arcPin = PrimitiveNode.makeArcPin(this, pinName, portName, elibSize0, elibSize1, extraArcs);
arcPin.setNotUsed(isNotUsed());
return arcPin;
}
/**
* Method to find the ArcProto with the given name.
* This can be prefixed by a Technology name.
* @param line the name of the ArcProto.
* @return the specified ArcProto, or null if none can be found.
*/
public static ArcProto findArcProto(String line)
{
Technology tech = Technology.getCurrent();
int colon = line.indexOf(':');
String withoutPrefix;
if (colon == -1) withoutPrefix = line; else
{
String prefix = line.substring(0, colon);
Technology t = Technology.findTechnology(prefix);
if (t != null) tech = t;
withoutPrefix = line.substring(colon+1);
}
ArcProto ap = tech.findArcProto(withoutPrefix);
if (ap != null) return ap;
return null;
}
/**
* Method to return the number of layers that comprise this ArcProto.
* @return the number of layers that comprise this ArcProto.
*/
public int getNumArcLayers() { return layers.length; }
/**
* Method to return the list of ArcLayers that comprise this ArcProto..
* @return the list of ArcLayers that comprise this ArcProto.
*/
public Technology.ArcLayer [] getArcLayers() { return layers; }
/**
* Method to return layer that comprises by its index in all layers
* @param arcLayerIndex layer index
* @return specified layer that comprises this ArcProto.
*/
public Layer getLayer(int arcLayerIndex) { return layers[arcLayerIndex].getLayer(); }
/**
* Returns the extend of specified layer that comprise this ArcProto over base arc width in lambda units.
* @param arcLayerIndex layer index
* @return the extend of specified layer that comprise this ArcProto over base arc width in lambda units.
*/
public double getLayerLambdaExtend(int arcLayerIndex) { return DBMath.gridToLambda(getLayerGridExtend(arcLayerIndex)); }
/**
* Returns the extend of specified layer that comprise this ArcProto over base arc width in grid units.
* @param arcLayerIndex layer index
* @return the extend of specified layer that comprise this ArcProto over base arc width in grid units.
*/
public int getLayerGridExtend(int arcLayerIndex) { return layers[arcLayerIndex].getGridExtend(); }
/**
* Returns the Poly.Style of specified layer that comprise this ArcLayer.
* @param arcLayerIndex layer index
* @return the Poly.Style of specified layer that comprise this ArcLayer.
*/
public Poly.Type getLayerStyle(int arcLayerIndex) { return layers[arcLayerIndex].getStyle(); }
/**
* Returns the extend of specified layer that comprise this ArcProto over base arc width in lambda units.
* @param layer specified Layer
* @return the extend of specified layer that comprise this ArcProto over base arc width in lambda units.
* @throws IndexOutOfBoundsException when specified layer diesn't comprise this ArcProto
*/
public double getLayerLambdaExtend(Layer layer) { return getLayerLambdaExtend(indexOf(layer)); }
/**
* Returns the extend of specified layer that comprise this ArcProto over base arc width in grid units.
* @param layer specified Layer
* @return the extend of specified layer that comprise this ArcProto over base arc width in grid units.
* @throws IndexOutOfBoundsException when specified layer diesn't comprise this ArcProto
*/
public long getLayerGridExtend(Layer layer) { return getLayerGridExtend(indexOf(layer)); }
/**
* Returns the Poly.Style of specified layer that comprise this ArcLayer.
* @param layer specified Layer
* @return the Poly.Style of specified layer that comprise this ArcLayer.
* @throws IndexOutOfBoundsException when specified layer diesn't comprise this ArcProto
*/
public Poly.Type getLayerStyle(Layer layer) { return getLayerStyle(indexOf(layer)); }
/**
* Method to return specified layer that comprise this ArcProto.
* @param i layer index
* @return specified layer that comprise this ArcProto.
*/
Technology.ArcLayer getArcLayer(int i) { return layers[i]; }
// /**
// * Method to return the array of layers that comprise this ArcProto.
// * @return the array of layers that comprise this ArcProto.
// */
// public Iterator<Technology.ArcLayer> getArcLayers() { return ArrayIterator.iterator(layers); }
/**
* Method to return an iterator over the layers in this ArcProto.
* @return an iterator over the layers in this ArcProto.
*/
public Iterator<Layer> getLayerIterator()
{
return new LayerIterator(layers);
}
/**
* Iterator for Layers on this ArcProto
*/
private static class LayerIterator implements Iterator<Layer>
{
Technology.ArcLayer [] array;
int pos;
public LayerIterator(Technology.ArcLayer [] a)
{
array = a;
pos = 0;
}
public boolean hasNext()
{
return pos < array.length;
}
public Layer next() throws NoSuchElementException
{
if (pos >= array.length)
throw new NoSuchElementException();
return array[pos++].getLayer();
}
public void remove() throws UnsupportedOperationException, IllegalStateException
{
throw new UnsupportedOperationException();
}
}
// /**
// * Method to find the ArcLayer on this ArcProto with a given Layer.
// * If there are more than 1 with the given Layer, the first is returned.
// * @param layer the Layer to find.
// * @return the ArcLayer that has this Layer.
// */
// public Technology.ArcLayer findArcLayer(Layer layer)
// {
// for(int j=0; j<layers.length; j++)
// {
// Technology.ArcLayer oneLayer = layers[j];
// if (oneLayer.getLayer() == layer) return oneLayer;
// }
// return null;
// }
/**
* Method to find an index of Layer in a list of Layers that comprise this ArcProto.
* If this layer is not in the list, return -1
* @param layer the Layer to find.
* @return an index of Layer in a list of Layers that comprise this ArcProto, or -1.
*/
public int indexOf(Layer layer) {
for (int arcLayerIndex = 0; arcLayerIndex < layers.length; arcLayerIndex++) {
if (layers[arcLayerIndex].getLayer() == layer)
return arcLayerIndex;
}
return -1;
}
/**
* Method to get MinZ and MaxZ of this ArcProto
* @param array array[0] is minZ and array[1] is max
*/
public void getZValues(double [] array)
{
for(int j=0; j<layers.length; j++)
{
Layer layer = layers[j].getLayer();
double distance = layer.getDistance();
double thickness = layer.getThickness();
double z = distance + thickness;
array[0] = (array[0] > distance) ? distance : array[0];
array[1] = (array[1] < z) ? z : array[1];
}
}
/**
* Returns the polygons that describe dummy arc of this ArcProto
* with default width and specified length.
* @param lambdaLength length of dummy arc in lambda units.
* @return an array of Poly objects that describes dummy arc graphically.
*/
public Poly[] getShapeOfDummyArc(double lambdaLength) {
long l2 = DBMath.lambdaToGrid(lambdaLength/2);
// see how many polygons describe this arc
Poly [] polys = new Poly[layers.length];
// Point2D.Double headLocation = new Point2D.Double(lambdaLength/2, 0);
// Point2D.Double tailLocation = new Point2D.Double(-lambdaLength/2, 0);
EditingPreferences ep = EditingPreferences.getThreadEditingPreferences();
long defaultGridExtendOverMin = getDefaultInst(ep).getGridExtendOverMin();
for (int i = 0; i < layers.length; i++) {
long gridWidth = 2*(defaultGridExtendOverMin + getLayerGridExtend(i));
// long gridWidth = getDefaultGridFullWidth() - primLayer.getGridOffset();
Poly.Type style = getLayerStyle(i);
Point2D.Double[] points;
if (gridWidth == 0) {
points = new Point2D.Double[]{ new Point2D.Double(-l2, 0), new Point2D.Double(l2, 0)};
if (style == Poly.Type.FILLED) style = Poly.Type.OPENED;
} else {
long w2 = gridWidth/2;
assert w2 > 0;
points = new Point2D.Double[] {
new Point2D.Double(-l2-w2, w2), new Point2D.Double(-l2-w2, -w2), new Point2D.Double(l2+w2, -w2), new Point2D.Double(l2+w2, w2) };
if (style.isOpened())
points = new Point2D.Double[] { points[0], points[1], points[2], points[3], (Point2D.Double)points[0].clone() };
}
Poly poly = new Poly(points);
poly.gridToLambda();
poly.setStyle(style);
poly.setLayer(getLayer(i));
polys[i] = poly;
}
return polys;
}
/**
* Method to describe this ArcProto as a string.
* Prepends the Technology name if it is
* not from the current technology (for example, "mocmos:Polysilicon-1").
* @return a String describing this ArcProto.
*/
public String describe()
{
String description = "";
Technology tech = getTechnology();
if (Technology.getCurrent() != tech)
description += tech.getTechName() + ":";
description += getName();
return description;
}
/**
* Compares ArcProtos by their Technologies and definition order.
* @param that the other ArcProto.
* @return a comparison between the ArcProto.
*/
public int compareTo(ArcProto that)
{
if (this.tech != that.tech)
{
int cmp = this.tech.compareTo(that.tech);
if (cmp != 0) return cmp;
}
return this.primArcIndex - that.primArcIndex;
}
/**
* Method to finish initialization of this ArcProto.
*/
void finish() {
if (Double.isNaN(factoryAntennaRatio)) {
double ratio = ERCAntenna.DEFPOLYRATIO;
if (function.isMetal()) ratio = ERCAntenna.DEFMETALRATIO;
setFactoryAntennaRatio(ratio);
}
// assert !factoryDefaultInst.isTailArrowed() && !factoryDefaultInst.isHeadArrowed() && !factoryDefaultInst.isBodyArrowed();
assert factoryDefaultInst.isTailExtended() == factoryDefaultInst.isHeadExtended();
assert !factoryDefaultInst.isTailNegated() && !factoryDefaultInst.isHeadNegated();
assert !factoryDefaultInst.isHardSelect();
}
/**
* Returns a printable version of this ArcProto.
* @return a printable version of this ArcProto.
*/
@Override
public String toString()
{
return "arc " + describe();
}
void copyState(ArcProto that) {
assert getId() == that.getId();
setNotUsed(that.isNotUsed());
lambdaBaseExtend = that.lambdaBaseExtend;
gridBaseExtend = that.gridBaseExtend;
minLayerGridExtend = that.minLayerGridExtend;
maxLayerGridExtend = that.maxLayerGridExtend;
assert layers.length == that.layers.length;
for (int i = 0; i < layers.length; i++) {
layers[i].copyState(that.layers[i]);
}
check();
}
void dump(PrintWriter out) {
out.println("ArcProto " + getName() + " " + getFunction());
out.println("\tisWipable=" + isWipable());
out.println("\tisCurvable=" + isCurvable());
out.println("\tisSpecialArc=" + isSpecialArc());
out.println("\tisEdgeSelect=" + isEdgeSelect());
out.println("\tisNotUsed=" + isNotUsed());
out.println("\tisSkipSizeInPalette=" + isSkipSizeInPalette());
Technology.printlnPref(out, 1, "DefaultExtendFor" + getName() + "IN" + tech.getTechName(), new Double(factoryDefaultInst.getLambdaExtendOverMin()));
out.println("\tbaseExtend=" + getLambdaBaseExtend());
out.println("\tdefaultLambdaBaseWidth=" + getFactoryDefaultLambdaBaseWidth());
out.println("\tdiskOffset1=" + DBMath.round(getLambdaBaseExtend() + 0.5*getLambdaElibWidthOffset()));
out.println("\tdiskOffset2=" + getLambdaBaseExtend());
Technology.printlnPref(out, 1, "DefaultAngleFor" + getName() + "IN" + tech.getTechName(), new Integer(factoryAngleIncrement));
Technology.printlnPref(out, 1, "DefaultRigidFor" + getName() + "IN" + tech.getTechName(), Boolean.valueOf(factoryDefaultInst.isRigid()));
Technology.printlnPref(out, 1, "DefaultFixedAngleFor" + getName() + "IN" + tech.getTechName(), Boolean.valueOf(factoryDefaultInst.isFixedAngle()));
Technology.printlnPref(out, 1, "DefaultExtendedFor" + getName() + "IN" + tech.getTechName(), Boolean.valueOf(factoryDefaultInst.isTailExtended()));
Technology.printlnPref(out, 1, "DefaultDirectionalFor" + getName() + "IN" + tech.getTechName(), Boolean.valueOf(factoryDefaultInst.isHeadArrowed()));
for (Technology.ArcLayer arcLayer: layers)
arcLayer.dump(out);
}
Xml.ArcProto makeXml() {
Xml.ArcProto a = new Xml.ArcProto();
a.name = getName();
for (Map.Entry<String,ArcProto> e: tech.getOldArcNames().entrySet()) {
if (e.getValue() != this) continue;
assert a.oldName == null;
a.oldName = e.getKey();
}
a.function = getFunction();
a.wipable = isWipable();
a.curvable = isCurvable();
a.special = isSpecialArc();
a.notUsed = isNotUsed();
a.skipSizeInPalette = isSkipSizeInPalette();
double correction2 = DBMath.round(getLambdaBaseExtend());
double correction1 = DBMath.round(correction2 + 0.5*getLambdaElibWidthOffset());
if (correction1 != correction2)
a.diskOffset.put(Integer.valueOf(1), new Double(correction1));
if (correction2 != 0)
a.diskOffset.put(Integer.valueOf(2), new Double(correction2));
a.extended = factoryDefaultInst.isTailExtended();
a.fixedAngle = factoryDefaultInst.isFixedAngle();
a.angleIncrement = getFactoryAngleIncrement();
a.antennaRatio = getFactoryAntennaRatio();
for (Technology.ArcLayer arcLayer: layers)
a.arcLayers.add(arcLayer.makeXml());
// if (arcPin != null) {
// a.arcPin = new Xml.ArcPin();
// a.arcPin.name = arcPin.getName();
// PrimitivePort port = arcPin.getPort(0);
// a.arcPin.portName = port.getName();
// a.arcPin.elibSize = 2*arcPin.getSizeCorrector(0).getX();
// for (ArcProto cap: port.getConnections()) {
// if (cap.getTechnology() == tech && cap != this)
// a.arcPin.portArcs.add(cap.getName());
// }
//
// }
return a;
}
/**
* Method to check invariants in this ArcProto.
* @exception AssertionError if invariants are not valid
*/
void check() {
assert protoId.techId == tech.getId();
for (Technology.ArcLayer primLayer: layers) {
long gridExtend = getLayerGridExtend(primLayer.getLayer());
assert minLayerGridExtend <= gridExtend && gridExtend <= maxLayerGridExtend;
}
assert lambdaElibWidthOffset >= 0;
assert 0 <= gridBaseExtend && gridBaseExtend <= maxLayerGridExtend;
assert gridBaseExtend == getLayerGridExtend(0);
}
}