Adds a simple auto wire function; closes #274

This commit is contained in:
hneemann 2019-05-09 20:30:39 +02:00
parent 4b60be0808
commit f3f6c7d001
7 changed files with 170 additions and 14 deletions

View File

@ -13,6 +13,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
/**
* A list of pins
*/
@ -90,4 +92,16 @@ public class Pins implements Iterable<Pin> {
public Pin get(int index) {
return allPins.get(index);
}
/**
* @return false if there are two pins next to each other in horizontal direction
*/
boolean autoWireCompatible() {
for (Pin p1 : allPins)
for (Pin p2 : allPins) {
if (p1.getPos().add(SIZE, 0).equals(p2.getPos()))
return false;
}
return true;
}
}

View File

@ -11,6 +11,7 @@ import de.neemann.digital.core.element.*;
import de.neemann.digital.draw.graphics.*;
import de.neemann.digital.draw.shapes.*;
import de.neemann.digital.draw.shapes.Shape;
import de.neemann.digital.draw.shapes.custom.CustomShape;
import de.neemann.digital.gui.components.CircuitComponent;
import de.neemann.gui.Screen;
@ -34,6 +35,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
private transient Element element;
// shape is set to null and recreated if needed if attributes are changed
private transient Shape shape;
private transient Boolean autoWire;
// shapes are recreated if attributes are changed, therefore a factory is necessary and not only a simple shape!
private transient ShapeFactory shapeFactory;
private transient Transform transform;
@ -102,7 +104,12 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
@Override
public void attributeChanged() {
resetShape();
}
private void resetShape() {
shape = null;
autoWire = null;
resetGeometry();
}
@ -182,6 +189,19 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
return shape;
}
/**
* @return true if this shape supports auto wire
*/
public boolean isAutoWireCompatible() {
if (autoWire == null) {
Shape shape = getShape();
autoWire = !(shape instanceof DILShape || shape instanceof CustomShape || shape instanceof LayoutShape);
if (autoWire)
autoWire = shape.getPins().autoWireCompatible();
}
return autoWire;
}
@Override
public void drawTo(Graphic graphic, Style highLight) {
drawShape(graphic, highLight);
@ -196,7 +216,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
}
private void drawShape(Graphic graphic, Style highLight) {
Graphic gr = new GraphicTransform(graphic, createTransform());
Graphic gr = new GraphicTransform(graphic, getTransform());
Shape shape = getShape();
shape.drawTo(gr, highLight);
for (Pin p : shape.getPins())
@ -204,7 +224,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
p.getDirection() == Pin.Direction.input ? Style.WIRE : Style.WIRE_OUT);
}
private Transform createTransform() {
private Transform getTransform() {
if (transform == null) {
int rotate = getRotate();
if (rotate == 0)
@ -293,12 +313,12 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
*/
public Pins getPins() {
Shape shape = getShape();
Transform tr = createTransform();
Transform tr = getTransform();
Pins pins = shape.getPins();
Pins transformed = new Pins();
Pins transformedPins = new Pins();
for (Pin p : pins)
transformed.add(new Pin(tr.transform(p.getPos()), p).setVisualElement(this));
return transformed;
transformedPins.add(new Pin(tr.transform(p.getPos()), p).setVisualElement(this));
return transformedPins;
}
/**
@ -311,7 +331,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
this.ioState = ioState;
if (ioState == null) {
interactor = null;
shape = null;
resetShape();
} else
interactor = getShape().applyStateMonitor(ioState, guiObserver);
}
@ -379,7 +399,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
*/
public boolean elementDragged(CircuitComponent cc, Point pos, Vector posInComponent, SyncAccess modelSync) {
if (interactor != null)
return interactor.dragged(cc, posInComponent, transform, ioState, element, modelSync);
return interactor.dragged(cc, posInComponent, getTransform(), ioState, element, modelSync);
else
return false;
}

View File

@ -21,7 +21,7 @@ public interface Shape extends Drawable, ObservableValueReader {
* Puts the pins name and the pins x-y-position together!
* This information is used to calculate the models connections from the wiring in the circuit.
* Don't create your own {@link de.neemann.digital.core.element.PinInfo} instance! Try to use
* the instances passed to the constructor of the shape via the {@link ShapeFactory}s {@link ShapeFactory#Creator} interface.
* the instances passed to the constructor of the shape via the {@link ShapeFactory}s {@link ShapeFactory.Creator} interface.
*
* @return the pins
*/

View File

@ -250,7 +250,7 @@ public final class ShapeFactory {
}
/**
* creates a new shape
* Creates a new shape
*/
public interface Creator {
/**

View File

@ -15,8 +15,8 @@ import de.neemann.digital.core.io.InValue;
import de.neemann.digital.core.io.Out;
import de.neemann.digital.core.switching.Switch;
import de.neemann.digital.draw.elements.*;
import de.neemann.digital.draw.graphics.*;
import de.neemann.digital.draw.graphics.Vector;
import de.neemann.digital.draw.graphics.*;
import de.neemann.digital.draw.library.ElementLibrary;
import de.neemann.digital.draw.library.ElementNotFoundException;
import de.neemann.digital.draw.library.LibraryListener;
@ -42,8 +42,8 @@ import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.*;
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
import static de.neemann.digital.draw.shapes.GenericShape.SIZE2;
@ -1457,8 +1457,10 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
@Override
void clicked(MouseEvent e) {
if (mouse.isPrimaryClick(e) && !isLocked())
if (mouse.isPrimaryClick(e) && !isLocked()) {
modify(new ModifyInsertElement(element));
insertWires(element);
}
mouseNormal.activate();
focusWasLost = false;
}
@ -1476,6 +1478,37 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
}
private void insertWires(VisualElement element) {
if (element.isAutoWireCompatible()) {
Modifications.Builder wires = new Modifications.Builder(Lang.get("lib_wires"));
for (Pin p : element.getPins())
insertWirePin(p, element.getRotate(), wires);
modify(wires.build());
}
}
private void insertWirePin(Pin p, int rotate, Modifications.Builder wires) {
TransformRotate tr = new TransformRotate(new Vector(0, 0), rotate);
Vector pos = new Vector(-SIZE, 0);
if (p.getDirection() != PinDescription.Direction.input)
pos = new Vector(SIZE, 0);
pos = tr.transform(pos);
pos = pos.add(p.getPos());
boolean found = false;
List<VisualElement> el = circuit.getElementListAt(pos, false);
for (VisualElement ve : el) {
final Pin pinAt = circuit.getPinAt(pos, ve);
if (pinAt != null && pinAt.getPos().equals(pos)) {
found = true;
break;
}
}
if (found)
wires.add(new ModifyInsertWire(new Wire(pos, p.getPos())));
}
private final class MouseControllerMoveElement extends MouseController {
private VisualElement visualElement;
private Vector delta;
@ -1505,8 +1538,10 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
if (!isLocked()) {
visualElement.setPos(raster(visualElement.getPos()));
if (!visualElement.getPos().equals(initialPos)
|| visualElement.getRotate() != initialRot)
|| visualElement.getRotate() != initialRot) {
addModificationAlreadyMade(new ModifyMoveAndRotElement(visualElement, initialPos));
insertWires(visualElement);
}
normalEnd = true;
}
mouseNormal.activate();

View File

@ -338,6 +338,18 @@ public class TestInGUI extends TestCase {
.execute();
}
public void testAutoWire() {
new GuiTester()
.add(new DrawCircuit("dig/autoWire.dig"))
.press("F8")
.delay(500)
.add(new GuiTester.CheckTextInWindow<>(ValueTableDialog.class, Lang.get("msg_test_N_Passed", "")))
.add(new GuiTester.CheckTableRows<>(ValueTableDialog.class, 4))
.add(new GuiTester.CloseTopMost())
.add(new GuiTester.CloseTopMost())
.execute();
}
public void testDraw() {
new GuiTester()
.add(new DrawCircuit("../../main/dig/sequential/JK-MS.dig"))

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes/>
<visualElements>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>A</string>
</entry>
</elementAttributes>
<pos x="380" y="140"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>B</string>
</entry>
</elementAttributes>
<pos x="380" y="180"/>
</visualElement>
<visualElement>
<elementName>Not</elementName>
<elementAttributes/>
<pos x="400" y="140"/>
</visualElement>
<visualElement>
<elementName>Not</elementName>
<elementAttributes/>
<pos x="400" y="180"/>
</visualElement>
<visualElement>
<elementName>And</elementName>
<elementAttributes/>
<pos x="460" y="140"/>
</visualElement>
<visualElement>
<elementName>Not</elementName>
<elementAttributes/>
<pos x="540" y="160"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Y</string>
</entry>
</elementAttributes>
<pos x="600" y="160"/>
</visualElement>
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes>
<entry>
<string>Testdata</string>
<testData>
<dataString>A B Y
0 0 0
0 1 1
1 0 1
1 1 1</dataString>
</testData>
</entry>
</elementAttributes>
<pos x="440" y="220"/>
</visualElement>
</visualElements>
<wires/>
<measurementOrdering/>
</circuit>