Enhancements to Gates library: Maximum inputs now 32, added third option on gate size, improved drawing of OR gates for Shaped and DIN shapes, size option on controlled inverter, Control Line Location attribute on controlled buffer/inverter.

git-svn-id: https://circuit.svn.sourceforge.net/svnroot/circuit/trunk@28 70edf91d-0b9e-4248-82e7-2488d7716404
This commit is contained in:
Carl Burch 2010-09-01 18:11:46 +00:00
parent 2cf5450027
commit 9f22bf89c8
6 changed files with 230 additions and 61 deletions

View File

@ -465,17 +465,29 @@ abstract class AbstractGate extends InstanceFactory {
int skipStart;
int skipDist;
int skipLowerEven = 10;
if (inputs <= 3) {
if (size < 40) {
skipStart = -5;
skipDist = 10;
} else {
skipLowerEven = 10;
} else if (size < 60 || inputs <= 2) {
skipStart = -10;
skipDist = 20;
skipLowerEven = 20;
} else {
skipStart = -15;
skipDist = 30;
skipLowerEven = 30;
}
} else if (inputs == 4 && size >= 60) {
skipStart = -5;
skipDist = 20;
skipLowerEven = 0;
} else {
skipStart = -5;
skipDist = 10;
skipLowerEven = 10;
}
int dy;
@ -483,7 +495,7 @@ abstract class AbstractGate extends InstanceFactory {
dy = skipStart * (inputs - 1) + skipDist * index;
} else {
dy = skipStart * inputs + skipDist * index;
if (index >= inputs / 2) dy += skipDist;
if (index >= inputs / 2) dy += skipLowerEven;
}
int dx = axisLength;

View File

@ -11,7 +11,9 @@ import javax.swing.Icon;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeOption;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Attributes;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Direction;
@ -31,6 +33,14 @@ import com.cburch.logisim.util.GraphicsUtil;
import com.cburch.logisim.util.Icons;
class ControlledBuffer extends InstanceFactory {
private static final AttributeOption RIGHT_HANDED
= new AttributeOption("right", Strings.getter("controlledRightHanded"));
private static final AttributeOption LEFT_HANDED
= new AttributeOption("left", Strings.getter("controlledLeftHanded"));
private static final Attribute<AttributeOption> ATTR_CONTROL
= Attributes.forOption("control", Strings.getter("controlledControlOption"),
new AttributeOption[] { RIGHT_HANDED, LEFT_HANDED });
public static ComponentFactory FACTORY_BUFFER = new ControlledBuffer(false);
public static ComponentFactory FACTORY_INVERTER = new ControlledBuffer(true);
@ -44,15 +54,24 @@ class ControlledBuffer extends InstanceFactory {
isInverter ? Strings.getter("controlledInverterComponent")
: Strings.getter("controlledBufferComponent"));
this.isInverter = isInverter;
setAttributes(new Attribute[] { StdAttr.FACING, StdAttr.WIDTH },
new Object[] { Direction.EAST, BitWidth.ONE });
if (isInverter) {
setAttributes(new Attribute[] { StdAttr.FACING, StdAttr.WIDTH, NotGate.ATTR_SIZE, ATTR_CONTROL },
new Object[] { Direction.EAST, BitWidth.ONE, NotGate.SIZE_WIDE, RIGHT_HANDED });
} else {
setAttributes(new Attribute[] { StdAttr.FACING, StdAttr.WIDTH, ATTR_CONTROL },
new Object[] { Direction.EAST, BitWidth.ONE, RIGHT_HANDED });
}
setFacingAttribute(StdAttr.FACING);
setKeyConfigurator(new BitWidthConfigurator(StdAttr.WIDTH));
}
@Override
public Bounds getOffsetBounds(AttributeSet attrs) {
int w = isInverter ? 30 : 20;
int w = 20;
if(isInverter &&
!NotGate.SIZE_NARROW.equals(attrs.getValue(NotGate.ATTR_SIZE))) {
w = 30;
}
Direction facing = attrs.getValue(StdAttr.FACING);
if (facing == Direction.NORTH) return Bounds.create(-10, 0, 20, w);
if (facing == Direction.SOUTH) return Bounds.create(-10, -w, 20, w);
@ -95,7 +114,12 @@ class ControlledBuffer extends InstanceFactory {
// draw control wire
GraphicsUtil.switchToWidth(g, 3);
Location pt0 = painter.getInstance().getPortLocation(2);
Location pt1 = pt0.translate(face, 0, -6);
Location pt1;
if (painter.getAttributeValue(ATTR_CONTROL) == LEFT_HANDED) {
pt1 = pt0.translate(face, 0, 6);
} else {
pt1 = pt0.translate(face, 0, -6);
}
if (painter.getShowState()) {
g.setColor(painter.getPort(2).getColor());
}
@ -125,12 +149,16 @@ class ControlledBuffer extends InstanceFactory {
((Graphics2D) g).rotate(rotate);
}
GraphicsUtil.switchToWidth(g, 2);
int d = isInverter ? 10 : 0;
int[] xp = new int[] { -d, -19 - d, -19 - d, -d };
int[] yp = new int[] { 0, -7, 7, 0 };
g.drawPolyline(xp, yp, 4);
if (isInverter) g.drawOval(-9, -4, 9, 9);
if (isInverter) {
PainterShaped.paintNot(painter);
} else {
GraphicsUtil.switchToWidth(g, 2);
int d = isInverter ? 10 : 0;
int[] xp = new int[] { -d, -19 - d, -19 - d, -d };
int[] yp = new int[] { 0, -7, 7, 0 };
g.drawPolyline(xp, yp, 4);
// if (isInverter) g.drawOval(-9, -4, 9, 9);
}
if (rotate != 0.0) {
((Graphics2D) g).rotate(-rotate);
@ -149,18 +177,26 @@ class ControlledBuffer extends InstanceFactory {
@Override
protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) {
if (attr == StdAttr.FACING) {
if (attr == StdAttr.FACING || attr == NotGate.ATTR_SIZE) {
instance.recomputeBounds();
configurePorts(instance);
} else if (attr == ATTR_CONTROL) {
configurePorts(instance);
}
}
private void configurePorts(Instance instance) {
Direction facing = instance.getAttributeValue(StdAttr.FACING);
int d = isInverter ? 10 : 0;
Bounds bds = getOffsetBounds(instance.getAttributeSet());
int d = Math.max(bds.getWidth(), bds.getHeight()) - 20;
Location loc0 = Location.create(0, 0);
Location loc1 = loc0.translate(facing.reverse(), 20 + d);
Location loc2 = loc0.translate(facing.reverse(), 10 + d, -10);
Location loc2;
if (instance.getAttributeValue(ATTR_CONTROL) == LEFT_HANDED) {
loc2 = loc0.translate(facing.reverse(), 10 + d, 10);
} else {
loc2 = loc0.translate(facing.reverse(), 10 + d, -10);
}
Port[] ports = new Port[3];
ports[0] = new Port(0, 0, Port.OUTPUT, StdAttr.WIDTH);

View File

@ -14,22 +14,25 @@ import com.cburch.logisim.data.Direction;
import com.cburch.logisim.instance.StdAttr;
class GateAttributes extends AbstractAttributeSet {
static final int MAX_INPUTS = 16;
static final int MAX_INPUTS = 32;
static final int DELAY = 1;
static final AttributeOption SIZE_NARROW
= new AttributeOption(Integer.valueOf(30),
Strings.getter("gateSizeNarrowOpt"));
static final AttributeOption SIZE_WIDE
static final AttributeOption SIZE_MEDIUM
= new AttributeOption(Integer.valueOf(50),
Strings.getter("gateSizeNormalOpt"));
static final AttributeOption SIZE_WIDE
= new AttributeOption(Integer.valueOf(70),
Strings.getter("gateSizeWideOpt"));
public static final Attribute<AttributeOption> ATTR_SIZE
= Attributes.forOption("size", Strings.getter("gateSizeAttr"),
new AttributeOption[] { SIZE_NARROW, SIZE_WIDE });
new AttributeOption[] { SIZE_NARROW, SIZE_MEDIUM, SIZE_WIDE });
public static final Attribute<Integer> ATTR_INPUTS
= Attributes.forIntegerRange("inputs", Strings.getter("gateInputsAttr"),
2, 16);
2, MAX_INPUTS);
static final AttributeOption XOR_ONE
= new AttributeOption("1", Strings.getter("xorBehaviorOne"));
@ -42,7 +45,7 @@ class GateAttributes extends AbstractAttributeSet {
Direction facing = Direction.EAST;
BitWidth width = BitWidth.ONE;
AttributeOption size = SIZE_WIDE;
AttributeOption size = SIZE_MEDIUM;
int inputs = 5;
int negated = 0;
AttributeOption xorBehave;

View File

@ -7,6 +7,7 @@ import java.awt.Color;
import java.awt.Graphics;
import java.util.HashMap;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.data.Value;
import com.cburch.logisim.instance.InstancePainter;
import com.cburch.logisim.util.GraphicsUtil;
@ -28,7 +29,6 @@ class PainterDin {
static void paintOr(InstancePainter painter, int width, int height,
boolean drawBubble) {
paintOrLines(painter, width, height, true);
paint(painter, width, height, drawBubble, OR);
}
@ -56,7 +56,7 @@ class PainterDin {
if (dinType == AND) {
; // nothing to do
} else if (dinType == OR) {
// TODO
paintOrLines(painter, width, height, drawBubble);
} else if (dinType == XOR || dinType == XNOR) {
int elen = Math.min(diam / 2 - 10, 20);
int ex0 = xMid + (diam / 2 - elen) / 2;
@ -99,49 +99,43 @@ class PainterDin {
private static void paintOrLines(InstancePainter painter,
int width, int height, boolean hasBubble) {
Integer inObj = painter.getAttributeValue(GateAttributes.ATTR_INPUTS);
int inputs = inObj == null ? 1 : inObj.intValue();
int rx = 0;
int x0 = rx - width;
if (hasBubble) {
rx -= 4;
width -= 8;
}
GateAttributes baseAttrs = (GateAttributes) painter.getAttributeSet();
int inputs = baseAttrs.inputs;
GateAttributes attrs = (GateAttributes) OrGate.FACTORY.createAttributeSet();
attrs.inputs = inputs;
attrs.size = baseAttrs.size;
Graphics g = painter.getGraphics();
// draw state if appropriate
// ignore lines if in print view
int dy = (height - 10) / (inputs - 1);
int r = Math.min(height / 2, width);
Integer hash = Integer.valueOf(r << 4 | inputs);
int[] lens = orLenArrays.get(hash);
if (lens == null) {
lens = new int[inputs];
orLenArrays.put(hash, lens);
int y = -height / 2 + 5;
if (height <= 2 * r) {
for (int i = 0; i < inputs; i++) {
int a = y;
lens[i] = (int) (Math.sqrt(r * r - a * a) + 0.5);
y += dy;
}
} else {
for (int i = 0; i < inputs; i++) {
int yCurveStart = height / 2 - r;
for (int i = 0; i < inputs; i++) {
int y = OrGate.FACTORY.getInputOffset(attrs, i).getY();
if (y < 0) y = -y;
if (y <= yCurveStart) {
lens[i] = r;
}
int yy0 = -height / 2 + r;
for (int i = 0; y < yy0; i++, y += dy) {
int a = y - yy0;
lens[i] = (int) (Math.sqrt(r * r - a * a) + 0.5);
lens[lens.length - 1 - i] = lens[i];
} else {
int dy = y - yCurveStart;
lens[i] = (int) (Math.sqrt(r * r - dy * dy) + 0.5);
}
}
}
AbstractGate factory = hasBubble ? NorGate.FACTORY : OrGate.FACTORY;
boolean printView = painter.isPrintView() && painter.getInstance() != null;
GraphicsUtil.switchToWidth(g, 2);
int y = -height / 2 + 5;
for (int i = 0; i < inputs; i++, y += dy) {
for (int i = 0; i < inputs; i++) {
if (!printView || painter.isPortConnected(i)) {
g.drawLine(x0, y, x0 + lens[i], y);
Location loc = factory.getInputOffset(attrs, i);
int x = loc.getX();
int y = loc.getY();
g.drawLine(x, y, x + lens[i], y);
}
}
}

View File

@ -5,6 +5,9 @@ package com.cburch.logisim.std.gates;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.util.HashMap;
import com.cburch.logisim.data.Direction;
@ -13,7 +16,50 @@ import com.cburch.logisim.data.Value;
import com.cburch.logisim.instance.InstancePainter;
import com.cburch.logisim.util.GraphicsUtil;
public class PainterShaped {
public class PainterShaped {
private static final GeneralPath PATH_NARROW;
private static final GeneralPath PATH_MEDIUM;
private static final GeneralPath PATH_WIDE;
private static final GeneralPath SHIELD_NARROW;
private static final GeneralPath SHIELD_MEDIUM;
private static final GeneralPath SHIELD_WIDE;
static {
PATH_NARROW = new GeneralPath();
PATH_NARROW.moveTo(0, 0);
PATH_NARROW.quadTo(-10, -15, -30, -15);
PATH_NARROW.quadTo(-22, 0, -30, 15);
PATH_NARROW.quadTo(-10, 15, 0, 0);
PATH_NARROW.closePath();
PATH_MEDIUM = new GeneralPath();
PATH_MEDIUM.moveTo(0, 0);
PATH_MEDIUM.quadTo(-20, -25, -50, -25);
PATH_MEDIUM.quadTo(-37, 0, -50, 25);
PATH_MEDIUM.quadTo(-20, 25, 0, 0);
PATH_MEDIUM.closePath();
PATH_WIDE = new GeneralPath();
PATH_WIDE.moveTo(0, 0);
PATH_WIDE.quadTo(-25, -35, -70, -35);
PATH_WIDE.quadTo(-50, 0, -70, 35);
PATH_WIDE.quadTo(-25, 35, 0, 0);
PATH_WIDE.closePath();
SHIELD_NARROW = new GeneralPath();
SHIELD_NARROW.moveTo(-30, -15);
SHIELD_NARROW.quadTo(-22, 0, -30, 15);
SHIELD_MEDIUM = new GeneralPath();
SHIELD_MEDIUM.moveTo(-50, -25);
SHIELD_MEDIUM.quadTo(-37, 0, -50, 25);
SHIELD_WIDE = new GeneralPath();
SHIELD_WIDE.moveTo(-70, -35);
SHIELD_WIDE.quadTo(-50, 0, -70, 35);
}
private PainterShaped() { }
private static HashMap<Integer,int[]> INPUT_LENGTHS = new HashMap<Integer,int[]>();
@ -34,14 +80,33 @@ public class PainterShaped {
static void paintOr(InstancePainter painter, int width, int height) {
Graphics g = painter.getGraphics();
GraphicsUtil.switchToWidth(g, 2);
if (width == 30) {
/* The following, used previous to version 2.5.1, didn't use GeneralPath
g.setColor(Color.LIGHT_GRAY);
if (width < 40) {
GraphicsUtil.drawCenteredArc(g, -30, -21, 36, -90, 53);
GraphicsUtil.drawCenteredArc(g, -30, 21, 36, 90, -53);
} else {
} else if (width < 60) {
GraphicsUtil.drawCenteredArc(g, -50, -37, 62, -90, 53);
GraphicsUtil.drawCenteredArc(g, -50, 37, 62, 90, -53);
} else {
GraphicsUtil.drawCenteredArc(g, -70, -50, 85, -90, 53);
GraphicsUtil.drawCenteredArc(g, -70, 50, 85, 90, -53);
}
paintShield(g, -width, 0, width, height);
*/
GeneralPath path;
if (width < 40) {
path = PATH_NARROW;
} else if (width < 60) {
path = PATH_MEDIUM;
} else {
path = PATH_WIDE;
}
((Graphics2D) g).draw(path);
if (height > width) {
paintShield(g, 0, width, height);
}
}
static void paintNot(InstancePainter painter) {
@ -72,20 +137,25 @@ public class PainterShaped {
static void paintXor(InstancePainter painter, int width, int height) {
Graphics g = painter.getGraphics();
paintOr(painter, width - 10, width - 10);
paintShield(g, -width, 0, width - 10, height);
paintShield(g, -10, width - 10, height);
}
private static void paintShield(Graphics g, int x, int y,
private static void paintShield(Graphics g, int xlate,
int width, int height) {
GraphicsUtil.switchToWidth(g, 2);
if (width == 30) {
g.translate(xlate, 0);
((Graphics2D) g).draw(computeShield(width, height));
g.translate(-xlate, 0);
/* The following, used previous to version 2.5.1, didn't use GeneralPath
if (width < 40) {
GraphicsUtil.drawCenteredArc(g, x - 26, y, 30, -30, 60);
} else {
} else if (width < 60) {
GraphicsUtil.drawCenteredArc(g, x - 43, y, 50, -30, 60);
} else {
GraphicsUtil.drawCenteredArc(g, x - 60, y, 70, -30, 60);
}
if (height > width) {
int extra = (height - width) / 2;
int dx = (int) Math.round(extra * (Math.sqrt(3) / 2));
if (height > width) { // we need to draw the shield
GraphicsUtil.drawCenteredArc(g,
x - dx, y - (width + extra) / 2,
extra, -30, 60);
@ -93,6 +163,32 @@ public class PainterShaped {
x - dx, y + (width + extra) / 2,
extra, -30, 60);
}
*/
}
private static GeneralPath computeShield(int width, int height) {
GeneralPath base;
if (width < 40) {
base = SHIELD_NARROW;
} else if (width < 60) {
base = SHIELD_MEDIUM;
} else {
base = SHIELD_WIDE;
}
if (height <= width) { // no wings
return base;
} else { // we need to add wings
int wingHeight = (height - width) / 2;
int dx = Math.min(20, wingHeight / 4);
GeneralPath path = new GeneralPath();
path.moveTo(-width, -height / 2);
path.quadTo(-width + dx, -(width + height) / 4, -width, -width / 2);
path.append(base, true);
path.quadTo(-width + dx, (width + height) / 4, -width, height / 2);
return path;
}
}
static void paintInputLines(InstancePainter painter, AbstractGate factory) {
@ -151,11 +247,34 @@ public class PainterShaped {
return (int[]) ret;
}
Direction facing = attrs.facing;
if (facing != Direction.EAST) {
attrs = (GateAttributes) attrs.clone();
attrs.facing = Direction.EAST;
}
int[] lengths = new int[inputs];
INPUT_LENGTHS.put(key, lengths);
Location loc0 = factory.getInputOffset(attrs, 0);
Location locn = factory.getInputOffset(attrs, inputs - 1);
int width = mainHeight;
Location loc0 = OrGate.FACTORY.getInputOffset(attrs, 0);
Location locn = OrGate.FACTORY.getInputOffset(attrs, inputs - 1);
int totalHeight = 10 + loc0.manhattanDistanceTo(locn);
if (totalHeight < width) totalHeight = width;
GeneralPath path = computeShield(width, totalHeight);
for (int i = 0; i < inputs; i++) {
Location loci = OrGate.FACTORY.getInputOffset(attrs, i);
Point2D p = new Point2D.Float(loci.getX() + 1, loci.getY());
int iters = 0;
while (path.contains(p) && iters < 15) {
iters++;
p.setLocation(p.getX() + 1, p.getY());
}
if (iters >= 15) iters = 0;
lengths[i] = iters;
}
/* used prior to 2.5.1, when moved to GeneralPath
int wingHeight = (totalHeight - mainHeight) / 2;
double wingCenterX = wingHeight * Math.sqrt(3) / 2;
double mainCenterX = mainHeight * Math.sqrt(3) / 2;
@ -176,6 +295,7 @@ public class PainterShaped {
}
lengths[i] = (int) (dx - 0.5);
}
*/
return lengths;
}
}

View File

@ -93,6 +93,7 @@ tunnelComponent = Tunnel
gatesLibrary = Gates
gateSizeAttr = Gate Size
gateSizeNarrowOpt = Narrow
gateSizeNormalOpt = Medium
gateSizeWideOpt = Wide
gateNegateAttr = Negate %s
gateInputsAttr = Number Of Inputs
@ -125,6 +126,9 @@ evenParityComponent = Even Parity
# std/ControlledBuffer.java
controlledBufferComponent = Controlled Buffer
controlledInverterComponent = Controlled Inverter
controlledControlOption = Control Line Location
controlledLeftHanded = Left-Handed
controlledRightHanded = Right-Handed
#
# std/Memory.java
#