mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 08:55:05 -04:00
added some editing function
This commit is contained in:
parent
ec1511258d
commit
e83dd45d71
@ -252,4 +252,8 @@ public class Vector implements VectorInterface {
|
||||
return (float) Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VectorFloat toFloat() {
|
||||
return new VectorFloat(x, y);
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,16 @@ public class VectorFloat implements VectorInterface {
|
||||
return new VectorFloat(x * a, y * a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sclar product
|
||||
*
|
||||
* @param p the other vector
|
||||
* @return the scalar procuct
|
||||
*/
|
||||
public float mul(VectorFloat p) {
|
||||
return x * p.x + y * p.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new vector which has the value this/d
|
||||
*
|
||||
@ -131,4 +141,9 @@ public class VectorFloat implements VectorInterface {
|
||||
public float len() {
|
||||
return (float) Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VectorFloat toFloat() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,11 @@ public interface VectorInterface {
|
||||
*/
|
||||
Vector round();
|
||||
|
||||
/**
|
||||
* @return returns a float vector
|
||||
*/
|
||||
VectorFloat toFloat();
|
||||
|
||||
/**
|
||||
* @return the length of the vector
|
||||
*/
|
||||
|
@ -8,11 +8,13 @@ package de.neemann.digital.fsm;
|
||||
import de.neemann.digital.analyse.TruthTable;
|
||||
import de.neemann.digital.analyse.expression.*;
|
||||
import de.neemann.digital.draw.graphics.Graphic;
|
||||
import de.neemann.digital.draw.graphics.Vector;
|
||||
import de.neemann.digital.draw.graphics.VectorFloat;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
@ -42,6 +44,7 @@ public class FSM {
|
||||
* @return this for chained calls
|
||||
*/
|
||||
public FSM add(State state) {
|
||||
if (state.getNumber() < 0)
|
||||
state.setNumber(states.size());
|
||||
states.add(state);
|
||||
return this;
|
||||
@ -101,14 +104,14 @@ public class FSM {
|
||||
for (State s : states)
|
||||
if (s.getName().equals(name))
|
||||
return s;
|
||||
throw new FinitStateMachineException("State " + name + " not found!");
|
||||
throw new FinitStateMachineException(Lang.get("err_fsmState_N_notFound!", name));
|
||||
}
|
||||
|
||||
private State findState(int number) throws FinitStateMachineException {
|
||||
for (State s : states)
|
||||
if (s.getNumber() == number)
|
||||
return s;
|
||||
throw new FinitStateMachineException("State " + number + " not found!");
|
||||
throw new FinitStateMachineException(Lang.get("err_fsmState_N_notFound!", number));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,6 +127,13 @@ public class FSM {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the states
|
||||
*/
|
||||
public List<State> getStates() {
|
||||
return states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the FSM
|
||||
*
|
||||
@ -140,13 +150,18 @@ public class FSM {
|
||||
* Moved the elements
|
||||
*
|
||||
* @param dt the time step
|
||||
* @param moveStates if true also states are moved
|
||||
* @param except element which is fixed
|
||||
*/
|
||||
public void move(int dt) {
|
||||
public void move(int dt, boolean moveStates, Movable except) {
|
||||
calculateForces();
|
||||
if (moveStates)
|
||||
for (State s : states)
|
||||
if (s != except)
|
||||
s.move(dt);
|
||||
for (Transition t : transitions)
|
||||
if (t != except)
|
||||
t.move(dt);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -287,4 +302,21 @@ public class FSM {
|
||||
while ((1 << n) <= maxNumber) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element at the given position
|
||||
* @param pos the position
|
||||
* @return the element or null
|
||||
*/
|
||||
public Movable getMovable(Vector pos) {
|
||||
for (State s : states)
|
||||
if (s.matches(pos))
|
||||
return s;
|
||||
|
||||
for (Transition t : transitions)
|
||||
if (t.matches(pos))
|
||||
return t;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
144
src/main/java/de/neemann/digital/fsm/FSMDemos.java
Normal file
144
src/main/java/de/neemann/digital/fsm/FSMDemos.java
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.fsm;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.parser.Parser;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Not.not;
|
||||
import static de.neemann.digital.analyse.expression.Variable.v;
|
||||
|
||||
/**
|
||||
* Provides some demo fsm's
|
||||
*/
|
||||
public final class FSMDemos {
|
||||
|
||||
private FSMDemos() {
|
||||
}
|
||||
|
||||
private static Expression e(String s) {
|
||||
try {
|
||||
return new Parser(s).parse().get(0);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a debounced rotary switch decoder
|
||||
*
|
||||
* @return the fsm
|
||||
*/
|
||||
public static FSM createRotDecoder() {
|
||||
State top = new State("top");
|
||||
State topSetLeft = new State("topSetLeft").val("L", 1);
|
||||
State topSetRight = new State("topSetRight").val("R", 1);
|
||||
State leftA = new State("leftA");
|
||||
State leftB = new State("leftB");
|
||||
State bottom = new State("bottom");
|
||||
State bottomSetLeft = new State("bottomSetRight").val("R", 1);
|
||||
State bottomSetRight = new State("bottomSetLeft").val("L", 1);
|
||||
State rightA = new State("rightA");
|
||||
State rightB = new State("rightB");
|
||||
return new FSM(top, topSetLeft, leftA, leftB, bottomSetLeft, bottom, bottomSetRight, rightB, rightA, topSetRight)
|
||||
.transition(top, leftA, e("A & !B"))
|
||||
.transition(top, rightA, e("!A & B"))
|
||||
.transition(topSetLeft, top, null)
|
||||
.transition(topSetRight, top, null)
|
||||
|
||||
.transition(rightA, top, e("!A & !B"))
|
||||
.transition(rightB, topSetRight, e("!A & !B"))
|
||||
.transition(leftA, top, e("!A & !B"))
|
||||
.transition(leftB, topSetLeft, e("!A & !B"))
|
||||
|
||||
.transition(bottom, leftB, e("A & !B"))
|
||||
.transition(bottom, rightB, e("!A & B"))
|
||||
.transition(bottomSetLeft, bottom, null)
|
||||
.transition(bottomSetRight, bottom, null)
|
||||
|
||||
.transition(rightB, bottom, e("A & B"))
|
||||
.transition(rightA, bottomSetRight, e("A & B"))
|
||||
.transition(leftB, bottom, e("A & B"))
|
||||
.transition(leftA, bottomSetLeft, e("A & B"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a counter
|
||||
*
|
||||
* @param n the number of states
|
||||
* @return the fsm
|
||||
*/
|
||||
public static FSM counter(int n) {
|
||||
FSM fsm = new FSM();
|
||||
State last = null;
|
||||
for (int i = 0; i < n; i++) {
|
||||
State s = new State(Integer.toString(i)).setNumber(i);
|
||||
fsm.add(s);
|
||||
if (last != null)
|
||||
fsm.transition(last, s, null);
|
||||
last = s;
|
||||
}
|
||||
fsm.transition(last, fsm.getStates().get(0), null);
|
||||
|
||||
return fsm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a traffic light fsm
|
||||
*
|
||||
* @return the fsm
|
||||
*/
|
||||
public static FSM trafficLight() {
|
||||
State red = new State("red").setNumber(0).val("R", 1);
|
||||
State redYellow = new State("red/yellow").setNumber(1).val("R", 1).val("Y", 1);
|
||||
State green = new State("green").setNumber(2).val("G", 1);
|
||||
State yellow = new State("yellow").setNumber(3).val("Y", 1);
|
||||
return new FSM(red, redYellow, green, yellow)
|
||||
.transition(red, redYellow, not(v("Stop")))
|
||||
.transition(redYellow, green, null)
|
||||
.transition(green, yellow, null)
|
||||
.transition(yellow, red, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a traffic light fsm
|
||||
*
|
||||
* @return the fsm
|
||||
*/
|
||||
public static FSM trafficLightMedwedev() {
|
||||
State init = new State("init").setNumber(0);
|
||||
State red = new State("red").setNumber(1).val("R", 1);
|
||||
State redYellow = new State("red/yellow").setNumber(3).val("R", 1).val("Y", 1);
|
||||
State green = new State("green").setNumber(4).val("G", 1);
|
||||
State yellow = new State("yellow").setNumber(2).val("Y", 1);
|
||||
return new FSM(init, red, redYellow, green, yellow)
|
||||
.transition(init, red, null)
|
||||
.transition(red, redYellow, not(v("Stop")))
|
||||
.transition(redYellow, green, null)
|
||||
.transition(green, yellow, null)
|
||||
.transition(yellow, red, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a traffic light fsm
|
||||
*
|
||||
* @return the fsm
|
||||
*/
|
||||
public static FSM selCounter() {
|
||||
State s0 = new State("s0").setNumber(0);
|
||||
State s1 = new State("s1").setNumber(1);
|
||||
State s2 = new State("s2").setNumber(2);
|
||||
State s3 = new State("s3").setNumber(3);
|
||||
return new FSM(s0, s1, s2, s3)
|
||||
.transition(s0, s1, null)
|
||||
.transition(s0, s0, e("!T0 !T1"))
|
||||
.transition(s1, s2, null)
|
||||
.transition(s1, s0, e("T0 !T1"))
|
||||
.transition(s2, s3, null)
|
||||
.transition(s2, s0, e("!T0 T1"))
|
||||
.transition(s3, s0, null);
|
||||
}
|
||||
}
|
@ -117,8 +117,8 @@ public class Movable {
|
||||
* @param dt the time step
|
||||
*/
|
||||
public void move(int dt) {
|
||||
speed = speed.add(force.mul(0.2f));
|
||||
position = position.add(speed);
|
||||
speed = speed.add(force.mul(dt / 200f));
|
||||
setPos(position.add(speed.mul(dt / 1000f)));
|
||||
speed = speed.mul(0.7f);
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,9 @@ import java.util.TreeMap;
|
||||
*/
|
||||
public class State extends Movable {
|
||||
private static final int RAD = 70;
|
||||
private static final float REACH = 500;
|
||||
private static final float REACH = 2000;
|
||||
|
||||
private int number;
|
||||
private int number = -1;
|
||||
private String name;
|
||||
private int radius;
|
||||
private TreeMap<String, Long> values;
|
||||
@ -86,6 +86,10 @@ public class State extends Movable {
|
||||
public void drawTo(Graphic gr) {
|
||||
VectorInterface rad = new Vector(RAD, RAD);
|
||||
gr.drawCircle(getPos().sub(rad), getPos().add(rad), Style.NORMAL);
|
||||
if (number == 0) {
|
||||
VectorInterface rad2 = new Vector(RAD - Style.MAXLINETHICK * 2, RAD - Style.MAXLINETHICK * 2);
|
||||
gr.drawCircle(getPos().sub(rad2), getPos().add(rad2), Style.THIN);
|
||||
}
|
||||
|
||||
Vector delta = new Vector(0, Style.NORMAL.getFontSize());
|
||||
VectorFloat pos = getPos().add(delta.mul(-1));
|
||||
@ -113,9 +117,11 @@ public class State extends Movable {
|
||||
* Sets the number of the state
|
||||
*
|
||||
* @param number the number
|
||||
* @return this for chained calls
|
||||
*/
|
||||
public void setNumber(int number) {
|
||||
public State setNumber(int number) {
|
||||
this.number = number;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,4 +137,14 @@ public class State extends Movable {
|
||||
public TreeMap<String, Long> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the position matches the state
|
||||
*
|
||||
* @param pos the position
|
||||
* @return true if pos inside of the state
|
||||
*/
|
||||
public boolean matches(Vector pos) {
|
||||
return pos.sub(getPos()).len() <= radius;
|
||||
}
|
||||
}
|
||||
|
@ -58,12 +58,14 @@ public class Transition extends Movable {
|
||||
*/
|
||||
public void calcForce(float preferredDist, List<State> states, List<Transition> transitions) {
|
||||
|
||||
if (fromState != toState) {
|
||||
VectorFloat dir = fromState.getPos().sub(toState.getPos());
|
||||
float len = dir.len();
|
||||
float d = len - preferredDist;
|
||||
dir = dir.mul(EXPANSION_TRANS * d);
|
||||
toState.addToForce(dir);
|
||||
fromState.addToForce(dir.mul(-1));
|
||||
}
|
||||
|
||||
resetForce();
|
||||
VectorFloat center = fromState.getPos().add(toState.getPos()).mul(0.5f);
|
||||
@ -74,8 +76,19 @@ public class Transition extends Movable {
|
||||
|
||||
for (Transition t : transitions)
|
||||
if (t != this)
|
||||
addRepulsiveInv(t.getPos(), 1000);
|
||||
addRepulsive(t.getPos(), 400);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPos(VectorFloat position) {
|
||||
if (fromState != toState) {
|
||||
VectorFloat dist = fromState.getPos().sub(toState.getPos());
|
||||
VectorFloat p = position.sub(fromState.getPos());
|
||||
VectorFloat n = new VectorFloat(dist.getYFloat(), -dist.getXFloat()).norm();
|
||||
float l = p.mul(n);
|
||||
super.setPos(fromState.getPos().sub(dist.mul(0.5f)).add(n.mul(l)));
|
||||
} else
|
||||
super.setPos(position);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,11 +97,13 @@ public class Transition extends Movable {
|
||||
* @param gr the Graphic instance to draw to
|
||||
*/
|
||||
public void drawTo(Graphic gr) {
|
||||
VectorFloat difFrom = getPos().sub(fromState.getPos()).norm().mul(fromState.getRadius());
|
||||
VectorFloat difTo = getPos().sub(toState.getPos()).norm().mul(toState.getRadius());
|
||||
VectorFloat difFrom = getPos().sub(fromState.getPos()).norm().mul(fromState.getRadius() + Style.MAXLINETHICK);
|
||||
VectorFloat difTo = getPos().sub(toState.getPos()).norm().mul(toState.getRadius() + Style.MAXLINETHICK + 2);
|
||||
VectorFloat difToTip = getPos().sub(toState.getPos()).norm().mul(toState.getRadius() + Style.MAXLINETHICK);
|
||||
|
||||
final VectorFloat start = fromState.getPos().add(difFrom);
|
||||
final VectorFloat end = toState.getPos().add(difTo);
|
||||
final VectorFloat arrowTip = toState.getPos().add(difToTip);
|
||||
|
||||
Polygon p = new Polygon(false)
|
||||
.add(start)
|
||||
@ -96,13 +111,12 @@ public class Transition extends Movable {
|
||||
final Style arrowStyle = Style.SHAPE_PIN;
|
||||
gr.drawPolygon(p, arrowStyle);
|
||||
|
||||
// gr.drawLine(start, getPos(), Style.THIN);
|
||||
// gr.drawLine(getPos(), end, Style.THIN);
|
||||
|
||||
// arrow
|
||||
VectorFloat lot = new VectorFloat(difTo.getYFloat(), -difTo.getXFloat()).mul(0.5f);
|
||||
gr.drawLine(end, end.add(difTo.add(lot).mul(0.2f)), arrowStyle);
|
||||
gr.drawLine(end, end.add(difTo.sub(lot).mul(0.2f)), arrowStyle);
|
||||
gr.drawPolygon(new Polygon(false)
|
||||
.add(end.add(difTo.add(lot).mul(0.2f)))
|
||||
.add(arrowTip)
|
||||
.add(end.add(difTo.sub(lot).mul(0.2f))), arrowStyle);
|
||||
if (condition != null) {
|
||||
String format;
|
||||
try {
|
||||
@ -142,4 +156,14 @@ public class Transition extends Movable {
|
||||
public State getTargetState() {
|
||||
return toState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives true if the position matches the transition.
|
||||
*
|
||||
* @param pos the position
|
||||
* @return true if pos matches the transition
|
||||
*/
|
||||
public boolean matches(Vector pos) {
|
||||
return pos.sub(getPos()).len() < 50;
|
||||
}
|
||||
}
|
||||
|
@ -5,28 +5,40 @@
|
||||
*/
|
||||
package de.neemann.digital.fsm.gui;
|
||||
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.Key;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.draw.graphics.GraphicMinMax;
|
||||
import de.neemann.digital.draw.graphics.GraphicSwing;
|
||||
import de.neemann.digital.draw.graphics.Style;
|
||||
import de.neemann.digital.draw.graphics.Vector;
|
||||
import de.neemann.digital.fsm.FSM;
|
||||
import de.neemann.digital.fsm.Movable;
|
||||
import de.neemann.digital.fsm.State;
|
||||
import de.neemann.digital.gui.components.AttributeDialog;
|
||||
import de.neemann.gui.Mouse;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The component to show the fsm
|
||||
*/
|
||||
public class FSMComponent extends JComponent {
|
||||
|
||||
private Mouse mouse = Mouse.getMouse();
|
||||
|
||||
private boolean isManualScale;
|
||||
private AffineTransform transform = new AffineTransform();
|
||||
private Movable elementMoved;
|
||||
private FSM fsm;
|
||||
|
||||
/**
|
||||
@ -49,6 +61,55 @@ public class FSMComponent extends JComponent {
|
||||
repaint();
|
||||
});
|
||||
|
||||
MouseAdapter mouseListener = new MouseAdapter() {
|
||||
private Vector delta;
|
||||
private Vector pos;
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
pos = new Vector(e.getX(), e.getY());
|
||||
if (mouse.isPrimaryClick(e)) {
|
||||
final Vector posVector = getPosVector(e);
|
||||
elementMoved = fsm.getMovable(posVector);
|
||||
if (elementMoved != null)
|
||||
delta = posVector.sub(elementMoved.getPos());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent mouseEvent) {
|
||||
elementMoved = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent mouseEvent) {
|
||||
if (mouse.isSecondaryClick(mouseEvent)) {
|
||||
final Vector posVector = getPosVector(mouseEvent);
|
||||
Movable elementClicked = fsm.getMovable(posVector);
|
||||
if (elementClicked == null)
|
||||
createNewState(posVector, new Point(mouseEvent.getX(), mouseEvent.getY()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
if (elementMoved == null) {
|
||||
Vector newPos = new Vector(e.getX(), e.getY());
|
||||
Vector delta = newPos.sub(pos);
|
||||
double s = transform.getScaleX();
|
||||
transform.translate(delta.x / s, delta.y / s);
|
||||
pos = newPos;
|
||||
isManualScale = true;
|
||||
repaint();
|
||||
} else {
|
||||
elementMoved.setPos(getPosVector(e).sub(delta).toFloat());
|
||||
}
|
||||
}
|
||||
};
|
||||
addMouseMotionListener(mouseListener);
|
||||
addMouseListener(mouseListener);
|
||||
|
||||
|
||||
addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent componentEvent) {
|
||||
@ -60,6 +121,26 @@ public class FSMComponent extends JComponent {
|
||||
setPreferredSize(new Dimension(600, 600));
|
||||
}
|
||||
|
||||
private void createNewState(Vector posVector, Point point) {
|
||||
Key<Integer> number = new Key.KeyInteger("stateNum", 0);
|
||||
Key values = new Key<>("stateValues", "");
|
||||
ArrayList<Key> list = new ArrayList<Key>();
|
||||
list.add(Keys.LABEL);
|
||||
list.add(number);
|
||||
list.add(values);
|
||||
ElementAttributes attr = new ElementAttributes();
|
||||
SwingUtilities.convertPointToScreen(point, this);
|
||||
AttributeDialog ad = new AttributeDialog(SwingUtilities.getWindowAncestor(this), point, list, attr);
|
||||
ElementAttributes newAttr = ad.showDialog();
|
||||
if (newAttr!=null) {
|
||||
State s = new State(newAttr.get(Keys.LABEL))
|
||||
.setPosition(posVector.toFloat())
|
||||
.setNumber(newAttr.get(number));
|
||||
fsm.add(s);
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private Vector getPosVector(MouseEvent e) {
|
||||
return getPosVector(e.getX(), e.getY());
|
||||
}
|
||||
@ -104,7 +185,13 @@ public class FSMComponent extends JComponent {
|
||||
transform = newTrans;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the element picked by the mouse
|
||||
*/
|
||||
public Movable getElementMoved() {
|
||||
return elementMoved;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,6 +202,10 @@ public class FSMComponent extends JComponent {
|
||||
graphics.fillRect(0, 0, getWidth(), getHeight());
|
||||
|
||||
Graphics2D gr2 = (Graphics2D) graphics;
|
||||
gr2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
gr2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
gr2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
||||
|
||||
gr2.transform(transform);
|
||||
GraphicSwing gr = new GraphicSwing(gr2, 1);
|
||||
fsm.drawTo(gr);
|
||||
|
@ -5,21 +5,20 @@
|
||||
*/
|
||||
package de.neemann.digital.fsm.gui;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.parser.ParseException;
|
||||
import de.neemann.digital.analyse.parser.Parser;
|
||||
import de.neemann.digital.draw.library.ElementLibrary;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.fsm.FSM;
|
||||
import de.neemann.digital.fsm.State;
|
||||
import de.neemann.digital.fsm.FSMDemos;
|
||||
import de.neemann.digital.gui.components.table.TableDialog;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.gui.ErrorMessage;
|
||||
import de.neemann.gui.ToolTipAction;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The dialog to show the FSM
|
||||
@ -29,20 +28,27 @@ public class FSMDialog extends JDialog {
|
||||
private final FSM fsm;
|
||||
private final FSMComponent fsmComponent;
|
||||
private final Timer timer;
|
||||
private final ElementLibrary library;
|
||||
private boolean moveStates = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param frame the parents frame
|
||||
* @param fsm the fsm to visualize
|
||||
* @param givenFsm the fsm to visualize
|
||||
* @param library the library used to show the table
|
||||
*/
|
||||
public FSMDialog(Frame frame, FSM fsm) {
|
||||
super(frame, "FSM");
|
||||
public FSMDialog(Frame frame, FSM givenFsm, ElementLibrary library) {
|
||||
super(frame, Lang.get("fsm_title"));
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
this.fsm = fsm;
|
||||
this.library = library;
|
||||
if (givenFsm == null)
|
||||
givenFsm = FSMDemos.createRotDecoder();
|
||||
|
||||
this.fsm = givenFsm;
|
||||
|
||||
fsmComponent = new FSMComponent(fsm);
|
||||
getContentPane().add(fsmComponent);
|
||||
getContentPane().add(fsmComponent, BorderLayout.CENTER);
|
||||
pack();
|
||||
setLocationRelativeTo(frame);
|
||||
|
||||
@ -51,8 +57,8 @@ public class FSMDialog extends JDialog {
|
||||
timer = new Timer(100, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
fsm.calculateForces();
|
||||
fsm.move(100);
|
||||
for (int i = 0; i < 100; i++)
|
||||
fsm.move(10, moveStates, fsmComponent.getElementMoved());
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
@ -65,56 +71,53 @@ public class FSMDialog extends JDialog {
|
||||
timer.stop();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuBar bar = new JMenuBar();
|
||||
|
||||
JMenu create = new JMenu(Lang.get("menu_fsm_create"));
|
||||
bar.add(create);
|
||||
create.add(new ToolTipAction(Lang.get("menu_fsm_create_table")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
try {
|
||||
new TableDialog(FSMDialog.this, fsm.createTruthTable(), library, null).setVisible(true);
|
||||
} catch (Exception e) {
|
||||
new ErrorMessage(Lang.get("msg_fsmCantCreateTable")).addCause(e).show(FSMDialog.this);
|
||||
}
|
||||
}
|
||||
}.createJMenuItem());
|
||||
|
||||
JToolBar toolBar = new JToolBar();
|
||||
|
||||
final JCheckBox moveCheck = new JCheckBox(Lang.get("fsm_move"));
|
||||
moveCheck.addActionListener(new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
moveStates = moveCheck.isSelected();
|
||||
}
|
||||
});
|
||||
moveCheck.setSelected(moveStates);
|
||||
toolBar.add(moveCheck);
|
||||
getContentPane().add(toolBar, BorderLayout.PAGE_START);
|
||||
|
||||
|
||||
setJMenuBar(bar);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple test method
|
||||
*
|
||||
* @param args the programs arguments
|
||||
* @throws Exception Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
State top = new State("top");
|
||||
State topSetLeft = new State("topSetLeft").val("L", 1);
|
||||
State topSetRight = new State("topSetRight").val("R", 1);
|
||||
State leftA = new State("leftA");
|
||||
State leftB = new State("leftB");
|
||||
State bottom = new State("bottom");
|
||||
State bottomSetLeft = new State("bottomSetRight").val("R", 1);
|
||||
State bottomSetRight = new State("bottomSetLeft").val("L", 1);
|
||||
State rightA = new State("rightA");
|
||||
State rightB = new State("rightB");
|
||||
FSM fsm = new FSM(top, topSetLeft, leftA, leftB, bottomSetLeft, bottom, bottomSetRight, rightB, rightA, topSetRight)
|
||||
.transition(top, leftA, e("A & !B"))
|
||||
.transition(top, rightA, e("!A & B"))
|
||||
.transition(topSetLeft, top, null)
|
||||
.transition(topSetRight, top, null)
|
||||
public static void main(String[] args) {
|
||||
|
||||
.transition(rightA, top, e("!A & !B"))
|
||||
.transition(rightB, topSetRight, e("!A & !B"))
|
||||
.transition(leftA, top, e("!A & !B"))
|
||||
.transition(leftB, topSetLeft, e("!A & !B"))
|
||||
FSM fsm = FSMDemos.selCounter();
|
||||
|
||||
.transition(bottom, leftB, e("A & !B"))
|
||||
.transition(bottom, rightB, e("!A & B"))
|
||||
.transition(bottomSetLeft, bottom, null)
|
||||
.transition(bottomSetRight, bottom, null)
|
||||
ElementLibrary library = new ElementLibrary();
|
||||
new ShapeFactory(library);
|
||||
|
||||
.transition(rightB, bottom, e("A & B"))
|
||||
.transition(rightA, bottomSetRight, e("A & B"))
|
||||
.transition(leftB, bottom, e("A & B"))
|
||||
.transition(leftA, bottomSetLeft, e("A & B"));
|
||||
new FSMDialog(null, fsm, library).setVisible(true);
|
||||
|
||||
|
||||
ElementLibrary lib = new ElementLibrary();
|
||||
ShapeFactory shapeFactory = new ShapeFactory(lib);
|
||||
new TableDialog(null, fsm.createTruthTable(), lib, shapeFactory, null).setVisible(true);
|
||||
|
||||
//new FSMDialog(null, fsm).setVisible(true);
|
||||
|
||||
}
|
||||
|
||||
private static Expression e(String s) throws IOException, ParseException {
|
||||
return new Parser(s).parse().get(0);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import de.neemann.digital.draw.model.ModelCreator;
|
||||
import de.neemann.digital.draw.model.RealTimeClock;
|
||||
import de.neemann.digital.draw.shapes.Drawable;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.fsm.gui.FSMDialog;
|
||||
import de.neemann.digital.gui.components.*;
|
||||
import de.neemann.digital.gui.components.data.GraphDialog;
|
||||
import de.neemann.digital.gui.components.expression.ExpressionDialog;
|
||||
@ -1094,7 +1095,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
new TableDialog(Main.this,
|
||||
new ModelAnalyser(model).analyse(),
|
||||
library,
|
||||
shapeFactory,
|
||||
getBaseFileName())
|
||||
.setVisible(true);
|
||||
ensureModelIsStopped();
|
||||
@ -1114,7 +1114,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TruthTable tt = new TruthTable(3).addResult();
|
||||
new TableDialog(Main.this, tt, library, shapeFactory, getBaseFileName()).setVisible(true);
|
||||
new TableDialog(Main.this, tt, library, getBaseFileName()).setVisible(true);
|
||||
ensureModelIsStopped();
|
||||
}
|
||||
}
|
||||
@ -1130,6 +1130,15 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
.setToolTip(Lang.get("menu_expression_tt"))
|
||||
.createJMenuItem());
|
||||
|
||||
analyse.add(new ToolTipAction(Lang.get("menu_fsm")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new FSMDialog(Main.this, null, library).setVisible(true);
|
||||
}
|
||||
}
|
||||
.setToolTip(Lang.get("menu_fsm_tt"))
|
||||
.createJMenuItem());
|
||||
|
||||
}
|
||||
|
||||
private void orderMeasurements() {
|
||||
|
@ -96,13 +96,12 @@ public class TableDialog extends JDialog {
|
||||
* @param parent the parent frame
|
||||
* @param truthTable the table to show
|
||||
* @param library the library to use
|
||||
* @param shapeFactory the shape factory
|
||||
* @param filename the file name used to create the names of the created files
|
||||
*/
|
||||
public TableDialog(JFrame parent, TruthTable truthTable, ElementLibrary library, ShapeFactory shapeFactory, File filename) {
|
||||
public TableDialog(Window parent, TruthTable truthTable, ElementLibrary library, File filename) {
|
||||
super(parent, Lang.get("win_table"));
|
||||
this.library = library;
|
||||
this.shapeFactory = shapeFactory;
|
||||
this.shapeFactory = library.getShapeFactory();
|
||||
this.filename = filename;
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
kvMap = new KarnaughMapDialog(this, (boolTable, row) -> model.incValue(boolTable, row));
|
||||
|
Loading…
x
Reference in New Issue
Block a user