diff --git a/src/main/java/de/neemann/digital/analyse/expression/VariableVisitor.java b/src/main/java/de/neemann/digital/analyse/expression/VariableVisitor.java index f291648ac..3c909e0d3 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/VariableVisitor.java +++ b/src/main/java/de/neemann/digital/analyse/expression/VariableVisitor.java @@ -1,7 +1,7 @@ package de.neemann.digital.analyse.expression; import java.util.Collection; -import java.util.HashSet; +import java.util.TreeSet; /** * Visitor to collect all used variables in an expression @@ -10,13 +10,13 @@ import java.util.HashSet; */ public class VariableVisitor implements ExpressionVisitor { - private final HashSet variables; + private final TreeSet variables; /** * Creates a new instance */ public VariableVisitor() { - variables = new HashSet<>(); + variables = new TreeSet<>(); } @Override diff --git a/src/main/java/de/neemann/digital/draw/builder/Builder.java b/src/main/java/de/neemann/digital/draw/builder/Builder.java index d76969bb5..8d869f3a7 100644 --- a/src/main/java/de/neemann/digital/draw/builder/Builder.java +++ b/src/main/java/de/neemann/digital/draw/builder/Builder.java @@ -1,11 +1,10 @@ package de.neemann.digital.draw.builder; -import de.neemann.digital.analyse.expression.Expression; -import de.neemann.digital.analyse.expression.Not; -import de.neemann.digital.analyse.expression.Operation; -import de.neemann.digital.analyse.expression.Variable; +import de.neemann.digital.analyse.expression.*; import de.neemann.digital.core.basic.And; import de.neemann.digital.core.basic.Or; +import de.neemann.digital.core.element.Keys; +import de.neemann.digital.core.io.Out; import de.neemann.digital.draw.elements.Circuit; import de.neemann.digital.draw.graphics.Vector; import de.neemann.digital.draw.library.ElementLibrary; @@ -15,26 +14,38 @@ import de.neemann.digital.gui.Main; import javax.swing.*; import java.util.ArrayList; +import static de.neemann.digital.draw.shapes.GenericShape.SIZE; + /** * @author hneemann */ public class Builder { - private final Expression expression; - private ShapeFactory shapeFactory; + private final Circuit circuit; + private final VariableVisitor variableVisitor; + private final ShapeFactory shapeFactory; + private int pos; - public Builder(Expression expression, ShapeFactory shapeFactory) { - this.expression = expression; + public Builder(ShapeFactory shapeFactory) { this.shapeFactory = shapeFactory; + circuit = new Circuit(); + variableVisitor = new VariableVisitor(); } - public Circuit createCircuit() { + public Builder addCircuit(String name, Expression expression) { Fragment fr = createFragment(expression); + + fr = new FragmentExpression(fr, new FragmentVisualElement(Out.DESCRIPTION, shapeFactory).setAttr(Keys.LABEL, name)); + fr.setPos(new Vector(0, 0)); - fr.doLayout(); - Circuit circuit = new Circuit(); - fr.addToCircuit(new Vector(0, 0), circuit); - return circuit; + Box b = fr.doLayout(); + + fr.addToCircuit(new Vector(0, pos), circuit); + pos += b.getHeight() + SIZE; + + expression.traverse(variableVisitor); + + return this; } private Fragment createFragment(Expression expression) { @@ -52,23 +63,33 @@ public class Builder { throw new RuntimeException("nyi"); } else if (expression instanceof Not) { Not n = (Not) expression; - ArrayList frags = new ArrayList<>(); - frags.add(createFragment(n.getExpression())); - return new FragmentExpression(frags, new FragmentVisualElement(de.neemann.digital.core.basic.Not.DESCRIPTION, frags.size(), shapeFactory)); + return new FragmentExpression(createFragment(n.getExpression()), new FragmentVisualElement(de.neemann.digital.core.basic.Not.DESCRIPTION, shapeFactory)); } else if (expression instanceof Variable) { return new FragmentVariable(((Variable) expression)); } else throw new RuntimeException("nyi"); } + public Circuit getCircuit() { + return circuit; + } + public static void main(String[] args) { Variable a = new Variable("A"); Variable b = new Variable("B"); Variable c = new Variable("C"); - Expression e = Operation.or(Not.not(Operation.and(a, Not.not(b), c)), Operation.and(a, Not.not(c)), Operation.and(b, Not.not(c))); - Builder builder = new Builder(e, new ShapeFactory(new ElementLibrary())); + Expression y = Operation.or(Not.not(Operation.and(a, Not.not(b), c)), Operation.and(Not.not(a), c), Operation.and(b, Not.not(c))); + Expression y1 = Operation.or(Not.not(Operation.and(a, Not.not(b), c)), Operation.and(Not.not(a), c), Operation.and(b, Not.not(c)), Operation.and(b, Not.not(c))); - Circuit circuit = builder.createCircuit(); + Expression l = Operation.and(y, y1, a); + + Builder builder = new Builder(new ShapeFactory(new ElementLibrary())); + + Circuit circuit = builder + .addCircuit("L", l) + .addCircuit("Y", y) + .getCircuit(); SwingUtilities.invokeLater(() -> new Main(null, circuit).setVisible(true)); } + } diff --git a/src/main/java/de/neemann/digital/draw/builder/Fragment.java b/src/main/java/de/neemann/digital/draw/builder/Fragment.java index 341ed1ff4..59430104b 100644 --- a/src/main/java/de/neemann/digital/draw/builder/Fragment.java +++ b/src/main/java/de/neemann/digital/draw/builder/Fragment.java @@ -3,16 +3,21 @@ package de.neemann.digital.draw.builder; import de.neemann.digital.draw.elements.Circuit; import de.neemann.digital.draw.graphics.Vector; +import java.util.List; + /** * @author hneemann */ public interface Fragment { - Vector output(); - Box doLayout(); void setPos(Vector pos); void addToCircuit(Vector pos, Circuit circuit); + + List getInputs(); + + List getOutputs(); + } diff --git a/src/main/java/de/neemann/digital/draw/builder/FragmentExpression.java b/src/main/java/de/neemann/digital/draw/builder/FragmentExpression.java index 193ed5179..346992044 100644 --- a/src/main/java/de/neemann/digital/draw/builder/FragmentExpression.java +++ b/src/main/java/de/neemann/digital/draw/builder/FragmentExpression.java @@ -1,9 +1,12 @@ package de.neemann.digital.draw.builder; import de.neemann.digital.draw.elements.Circuit; +import de.neemann.digital.draw.elements.Wire; import de.neemann.digital.draw.graphics.Vector; import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import static de.neemann.digital.draw.shapes.GenericShape.SIZE; @@ -16,6 +19,16 @@ public class FragmentExpression implements Fragment { private final Fragment merger; private Vector pos; + private static ArrayList createList(Fragment fragment) { + ArrayList f = new ArrayList<>(); + f.add(fragment); + return f; + } + + public FragmentExpression(Fragment fragment, Fragment merger) { + this(createList(fragment), merger); + } + public FragmentExpression(ArrayList frags, Fragment merger) { this.merger = merger; fragments = new ArrayList<>(); @@ -23,33 +36,47 @@ public class FragmentExpression implements Fragment { fragments.add(new FragmentHolder(fr)); } - @Override - public Vector output() { - return new Vector(0, 0); - } - @Override public Box doLayout() { + int centerHeight = 0; int height = 0; int width = 0; - for (FragmentHolder fr : fragments) { + int centerIndex = fragments.size() / 2; + for (int i = 0; i < fragments.size(); i++) { + FragmentHolder fr = fragments.get(i); fr.fragment.setPos(new Vector(0, height)); fr.box = fr.fragment.doLayout(); + if (i == centerIndex) + centerHeight = height; + height += fr.box.getHeight(); int w = fr.box.getWidth(); if (w > width) width = w; - height += SIZE*2; + height += SIZE * 2; } - height -= SIZE*2; + height -= SIZE * 2; Box mergerBox = merger.doLayout(); - width += SIZE; + if (isLong()) + if (fragments.size() > 3) + width += SIZE * 3; + else + width += SIZE * 2; + else + width += SIZE; - merger.setPos(new Vector(width, raster((height - mergerBox.getHeight()) / 2))); + if ((fragments.size() & 1) == 0) { + // even number of inputs + merger.setPos(new Vector(width, raster((height - mergerBox.getHeight()) / 2))); + } else { + // odd number of inputs + int y = fragments.get(centerIndex).fragment.getOutputs().get(0).y - centerIndex * SIZE; + merger.setPos(new Vector(width, y)); + } width += mergerBox.getWidth(); @@ -69,12 +96,52 @@ public class FragmentExpression implements Fragment { public void addToCircuit(Vector offset, Circuit circuit) { Vector p = pos.add(offset); merger.addToCircuit(p, circuit); + Iterator inputs = merger.getInputs().iterator(); for (FragmentHolder fr : fragments) { fr.fragment.addToCircuit(p, circuit); + + Vector pin = fr.fragment.getOutputs().get(0); + + Vector start = pin.add(p); + Vector end = inputs.next().add(p); + if (isLong()) { + int dx = end.x - start.x - SIZE; + if (fragments.size() > 3) + dx -= SIZE; + + Vector inter1 = start.add(dx, 0); + Vector inter2 = end.add(-SIZE, 0); + circuit.add(new Wire(start, inter1)); + circuit.add(new Wire(inter1, inter2)); + circuit.add(new Wire(inter2, end)); + } else { + circuit.add(new Wire(start, end)); + } + p.add(0, fr.box.getHeight() + SIZE); } } + @Override + public List getInputs() { + ArrayList pins = new ArrayList<>(); + Vector p = new Vector(pos); + for (FragmentHolder fr : fragments) { + pins.addAll(Vector.add(fr.fragment.getInputs(), p)); + p.add(0, fr.box.getHeight() + SIZE); + } + return pins; + } + + @Override + public List getOutputs() { + return Vector.add(merger.getOutputs(), pos); + } + + public boolean isLong() { + return fragments.size() > 1; + } + private class FragmentHolder { private final Fragment fragment; private Box box; diff --git a/src/main/java/de/neemann/digital/draw/builder/FragmentVariable.java b/src/main/java/de/neemann/digital/draw/builder/FragmentVariable.java index 5c8028330..d35342721 100644 --- a/src/main/java/de/neemann/digital/draw/builder/FragmentVariable.java +++ b/src/main/java/de/neemann/digital/draw/builder/FragmentVariable.java @@ -4,6 +4,9 @@ import de.neemann.digital.analyse.expression.Variable; import de.neemann.digital.draw.elements.Circuit; import de.neemann.digital.draw.graphics.Vector; +import java.util.ArrayList; +import java.util.List; + /** * @author hneemann */ @@ -15,11 +18,6 @@ public class FragmentVariable implements Fragment { this.variable = variable; } - @Override - public Vector output() { - return new Vector(0, 0); - } - @Override public Box doLayout() { return new Box(0, 0); @@ -33,4 +31,16 @@ public class FragmentVariable implements Fragment { @Override public void addToCircuit(Vector pos, Circuit circuit) { } + + @Override + public List getInputs() { + return new ArrayList<>(); + } + + @Override + public List getOutputs() { + ArrayList o = new ArrayList<>(); + o.add(pos); + return o; + } } diff --git a/src/main/java/de/neemann/digital/draw/builder/FragmentVisualElement.java b/src/main/java/de/neemann/digital/draw/builder/FragmentVisualElement.java index 4d04239cc..ac3e54a42 100644 --- a/src/main/java/de/neemann/digital/draw/builder/FragmentVisualElement.java +++ b/src/main/java/de/neemann/digital/draw/builder/FragmentVisualElement.java @@ -1,6 +1,7 @@ package de.neemann.digital.draw.builder; import de.neemann.digital.core.element.ElementTypeDescription; +import de.neemann.digital.core.element.Key; import de.neemann.digital.core.element.Keys; import de.neemann.digital.core.element.PinDescription; import de.neemann.digital.draw.elements.Circuit; @@ -12,17 +13,22 @@ import de.neemann.digital.draw.graphics.Vector; import de.neemann.digital.draw.shapes.ShapeFactory; import java.util.ArrayList; +import java.util.List; /** * @author hneemann */ public class FragmentVisualElement implements Fragment { - private final ArrayList inputs; - private final ArrayList outputs; + private final ArrayList inputs; + private final ArrayList outputs; private final VisualElement visualElement; private Vector pos; + public FragmentVisualElement(ElementTypeDescription description, ShapeFactory shapeFactory) { + this(description, 1, shapeFactory); + } + public FragmentVisualElement(ElementTypeDescription description, int inputCount, ShapeFactory shapeFactory) { visualElement = new VisualElement(description.getName()).setShapeFactory(shapeFactory); visualElement.getElementAttributes().set(Keys.INPUT_COUNT, inputCount); @@ -32,24 +38,24 @@ public class FragmentVisualElement implements Fragment { outputs = new ArrayList<>(); for (Pin p : pins) { if (p.getDirection().equals(PinDescription.Direction.input)) - inputs.add(p); + inputs.add(p.getPos()); else - outputs.add(p); + outputs.add(p.getPos()); } } - @Override - public Vector output() { - return outputs.get(0).getPos(); + public FragmentVisualElement setAttr(Key key, VALUE value) { + visualElement.getElementAttributes().set(key, value); + return this; } @Override public Box doLayout() { GraphicMinMax mm = new GraphicMinMax(); - for (Pin p : inputs) - mm.check(p.getPos()); - for (Pin p : outputs) - mm.check(p.getPos()); + for (Vector p : inputs) + mm.check(p); + for (Vector p : outputs) + mm.check(p); Vector delta = mm.getMax().sub(mm.getMin()); return new Box(delta.x, delta.y); } @@ -61,8 +67,17 @@ public class FragmentVisualElement implements Fragment { @Override public void addToCircuit(Vector offset, Circuit circuit) { - System.out.println(visualElement.getElementName() + ", " + pos + ", " + offset); visualElement.setPos(pos.add(offset)); circuit.add(visualElement); } + + @Override + public List getInputs() { + return Vector.add(inputs, pos); + } + + @Override + public List getOutputs() { + return Vector.add(outputs, pos); + } } diff --git a/src/main/java/de/neemann/digital/draw/graphics/Vector.java b/src/main/java/de/neemann/digital/draw/graphics/Vector.java index 41f4d296c..5b0547c47 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/Vector.java +++ b/src/main/java/de/neemann/digital/draw/graphics/Vector.java @@ -1,5 +1,8 @@ package de.neemann.digital.draw.graphics; +import java.util.ArrayList; +import java.util.List; + /** * Represents a 2D Vector * @@ -191,4 +194,18 @@ public class Vector { float l = (float) Math.sqrt(x * x + y * y); return new Vector(Math.round(x * 128 / l), Math.round(y * 128 / l)); } + + /** + * Adds a offset to every vector in the given list + * + * @param vectors the original vectors + * @param offs the offset + * @return the new list + */ + public static List add(List vectors, Vector offs) { + ArrayList newVec = new ArrayList<>(); + for (Vector v : vectors) + newVec.add(v.add(offs)); + return newVec; + } }