more consistent moving of fsm elements

This commit is contained in:
hneemann 2018-12-08 13:37:04 +01:00
parent f30b0e362f
commit 6fec5c7023
6 changed files with 146 additions and 52 deletions

View File

@ -25,6 +25,24 @@ import java.util.List;
*/ */
public class FSM { public class FSM {
/**
* The moving state of the fsm.
*/
public enum MovingState {
/**
* no elements are moving
*/
STOP,
/**
* only transitions are moving
*/
TRANSITIONS,
/**
* transitions and states are moving
*/
BOTH
}
private ArrayList<State> states; private ArrayList<State> states;
private ArrayList<Transition> transitions; private ArrayList<Transition> transitions;
private transient boolean modified; private transient boolean modified;
@ -33,6 +51,7 @@ public class FSM {
private transient Transition initialTransition; private transient Transition initialTransition;
private transient int activeState = -1; private transient int activeState = -1;
private transient File file; private transient File file;
private transient MovingState state = MovingState.STOP;
/** /**
* Creates a proper configured XStream instance * Creates a proper configured XStream instance
@ -131,6 +150,30 @@ public class FSM {
add(s); add(s);
} }
/**
* Sets the moving state of this FSM
*
* @param state the state
*/
public void setMovingState(MovingState state) {
if (this.state != state) {
this.state = state;
if (state != MovingState.BOTH)
for (State s : states)
s.toRaster();
}
}
/**
* @return the moving state of this FSM
*/
public MovingState getMovingState() {
if (state == null)
state = MovingState.STOP;
return state;
}
/** /**
* Adds a state to the FSM * Adds a state to the FSM
* *
@ -294,12 +337,12 @@ public class FSM {
* Moved the elements * Moved the elements
* *
* @param dt the time step * @param dt the time step
* @param moveStates if true also states are moved
* @param except element which is fixed * @param except element which is fixed
*/ */
public void move(int dt, boolean moveStates, Movable except) { public void move(int dt, Movable except) {
if (state != MovingState.STOP) {
calculateForces(); calculateForces();
if (moveStates) if (state == MovingState.BOTH)
for (State s : states) for (State s : states)
if (s != except) if (s != except)
s.move(dt); s.move(dt);
@ -307,6 +350,7 @@ public class FSM {
if (t != except) if (t != except)
t.move(dt); t.move(dt);
} }
}
/** /**
* Orders all states in a big circle * Orders all states in a big circle
@ -353,23 +397,31 @@ public class FSM {
* @return the element or null * @return the element or null
*/ */
public Movable getMovable(Vector pos) { public Movable getMovable(Vector pos) {
Movable found = null;
float dist = Float.MAX_VALUE;
for (Transition t : transitions) for (Transition t : transitions)
if (t.matches(pos)) if (t.matches(pos)) {
return t; float d = pos.sub(t.getPos()).len();
if (d < dist) {
for (State s : states) dist = d;
if (s.matches(pos)) found = t;
return s; }
return null;
} }
/** if (found != null)
* Move states to raster return found;
*/
public void toRaster() { dist = Float.MAX_VALUE;
for (State s : states) for (State s : states)
s.toRaster(); if (s.matches(pos)) {
float d = pos.sub(s.getPos()).len();
if (d < dist) {
dist = d;
found = s;
}
}
return found;
} }
/** /**
@ -386,7 +438,7 @@ public class FSM {
*/ */
public void remove(Transition transition) { public void remove(Transition transition) {
transitions.remove(transition); transitions.remove(transition);
wasModified(); wasModified(transition, Movable.Property.REMOVED);
resetInitInitialization(); resetInitInitialization();
} }
@ -398,15 +450,30 @@ public class FSM {
public void remove(State state) { public void remove(State state) {
states.remove(state); states.remove(state);
transitions.removeIf(t -> t.getStartState() == state || t.getTargetState() == state); transitions.removeIf(t -> t.getStartState() == state || t.getTargetState() == state);
wasModified(); wasModified(state, Movable.Property.REMOVED);
resetInitInitialization(); resetInitInitialization();
} }
/** /**
* Marks the fsm as modified * Marks the fsm as modified
*
* @param movable the element changed
* @param prop the property which has changed
*/ */
void wasModified() { void wasModified(Movable movable, Movable.Property prop) {
modified = true; modified = true;
if (movable instanceof State) {
State st = (State) movable;
if (prop == Movable.Property.POS && getMovingState() != MovingState.BOTH)
st.toRaster();
if ((prop == Movable.Property.POS || prop == Movable.Property.MOUSEPOS) && getMovingState() == MovingState.STOP)
for (Transition t : transitions)
if (t.getTargetState() == st || t.getStartState() == st)
t.setPos(t.getPos());
}
if (modifiedListener != null) if (modifiedListener != null)
modifiedListener.modifiedChanged(modified); modifiedListener.modifiedChanged(modified);
} }

View File

@ -13,6 +13,9 @@ import de.neemann.digital.draw.graphics.VectorFloat;
* @param <A> the type of the implementing class * @param <A> the type of the implementing class
*/ */
public class Movable<A extends Movable> { public class Movable<A extends Movable> {
enum Property {POS, REMOVED, CONDITION, NAME, NUMBER, MOUSEPOS, VALUES}
private static final float MASS = 50f; private static final float MASS = 50f;
private static final float FRICTION = 0.8f; private static final float FRICTION = 0.8f;
private static final float MAX_FORCE = 100000f; private static final float MAX_FORCE = 100000f;
@ -23,6 +26,7 @@ public class Movable<A extends Movable> {
private transient VectorFloat speed; private transient VectorFloat speed;
private transient VectorFloat force; private transient VectorFloat force;
private transient FSM fsm; private transient FSM fsm;
private transient Property lastPosProp;
/** /**
* Creates a new instance * Creates a new instance
@ -33,21 +37,35 @@ public class Movable<A extends Movable> {
position = new VectorFloat(0, 0); position = new VectorFloat(0, 0);
} }
/**
* Sets the position by mouse movement
*
* @param position the position
*/
public void setPosByMouse(VectorFloat position) {
setPos(position, Property.MOUSEPOS);
}
/** /**
* Sets the position * Sets the position
* *
* @param position the position * @param position the position
*/ */
public void setPos(VectorFloat position) { public void setPos(VectorFloat position) {
if (!this.position.equals(position)) { setPos(position, Property.POS);
}
private void setPos(VectorFloat position, Property prop) {
if (!this.position.equals(position) || lastPosProp != prop) {
this.position = position; this.position = position;
wasModified(); lastPosProp = prop;
wasModified(prop);
} }
} }
void wasModified() { void wasModified(Property prop) {
if (fsm != null) if (fsm != null)
fsm.wasModified(); fsm.wasModified(this, prop);
} }
/** /**
@ -167,7 +185,7 @@ public class Movable<A extends Movable> {
public A setValues(String values) { public A setValues(String values) {
if (!this.values.equals(values)) { if (!this.values.equals(values)) {
this.values = values; this.values = values;
wasModified(); wasModified(Property.VALUES);
} }
return (A) this; return (A) this;
} }

View File

@ -52,7 +52,7 @@ public class State extends Movable<State> {
public void setName(String name) { public void setName(String name) {
if (!this.name.equals(name)) { if (!this.name.equals(name)) {
this.name = name; this.name = name;
wasModified(); wasModified(Property.NAME);
} }
} }
@ -158,7 +158,7 @@ public class State extends Movable<State> {
public State setNumber(int number) { public State setNumber(int number) {
if (this.number != number) { if (this.number != number) {
this.number = number; this.number = number;
wasModified(); wasModified(Property.NUMBER);
if (getFsm() != null) if (getFsm() != null)
getFsm().resetInitInitialization(); getFsm().resetInitInitialization();
} }

View File

@ -92,8 +92,18 @@ public class Transition extends Movable<Transition> {
return getFsm() != null && getFsm().isInitial(this); return getFsm() != null && getFsm().isInitial(this);
} }
@Override
public void setPosByMouse(VectorFloat position) {
super.setPosByMouse(posConstrain(position));
}
@Override @Override
public void setPos(VectorFloat position) { public void setPos(VectorFloat position) {
super.setPos(posConstrain(position));
}
private VectorFloat posConstrain(VectorFloat position) {
if (fromState != toState) { if (fromState != toState) {
VectorFloat dist = toState.getPos().sub(fromState.getPos()); VectorFloat dist = toState.getPos().sub(fromState.getPos());
if (dist.getXFloat() != 0 || dist.getYFloat() != 0) { if (dist.getXFloat() != 0 || dist.getYFloat() != 0) {
@ -104,11 +114,10 @@ public class Transition extends Movable<Transition> {
VectorFloat p = position.sub(start); VectorFloat p = position.sub(start);
VectorFloat n = dist.getOrthogonal(); VectorFloat n = dist.getOrthogonal();
float l = p.mul(n); float l = p.mul(n);
super.setPos(start.add(end).div(2).add(n.mul(l))); return start.add(end).div(2).add(n.mul(l));
return;
} }
} }
super.setPos(position); return position;
} }
/** /**
@ -198,7 +207,7 @@ public class Transition extends Movable<Transition> {
public void setCondition(String condition) { public void setCondition(String condition) {
if (!this.condition.equals(condition)) { if (!this.condition.equals(condition)) {
this.condition = condition; this.condition = condition;
wasModified(); wasModified(Property.CONDITION);
conditionExpression = null; conditionExpression = null;
if (getFsm() != null) if (getFsm() != null)
getFsm().resetInitInitialization(); getFsm().resetInitInitialization();

View File

@ -91,8 +91,8 @@ public class FSMComponent extends JComponent {
@Override @Override
public void mouseReleased(MouseEvent mouseEvent) { public void mouseReleased(MouseEvent mouseEvent) {
if (elementMoved instanceof State) { if (elementMoved != null) {
((State) elementMoved).toRaster(); elementMoved.setPos(getPosVector(mouseEvent).sub(delta).toFloat());
repaint(); repaint();
} }
elementMoved = null; elementMoved = null;
@ -140,7 +140,7 @@ public class FSMComponent extends JComponent {
repaint(); repaint();
} }
if (elementMoved != null) { if (elementMoved != null) {
elementMoved.setPos(getPosVector(e).sub(delta).toFloat()); elementMoved.setPosByMouse(getPosVector(e).sub(delta).toFloat());
repaint(); repaint();
} }
if (newTransitionFromState != null) if (newTransitionFromState != null)

View File

@ -54,7 +54,6 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
private final Timer timer; private final Timer timer;
private final JComboBox<String> moveControl; private final JComboBox<String> moveControl;
private FSM fsm; private FSM fsm;
private boolean moveStates = false;
private ToolTipAction save; private ToolTipAction save;
private File filename; private File filename;
private File baseFilename; private File baseFilename;
@ -78,10 +77,14 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
timer = new Timer(100, new AbstractAction() { timer = new Timer(100, new AbstractAction() {
@Override @Override
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
if (fsm.getMovingState() == FSM.MovingState.STOP)
timer.stop();
else {
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
fsm.move(10, moveStates, fsmComponent.getElementMoved()); fsm.move(10, fsmComponent.getElementMoved());
repaint(); repaint();
} }
}
}); });
addWindowListener(new ClosingWindowListener(this, this)); addWindowListener(new ClosingWindowListener(this, this));
@ -111,18 +114,15 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
switch (moveControl.getSelectedIndex()) { switch (moveControl.getSelectedIndex()) {
case 0: case 0:
timer.stop(); fsm.setMovingState(FSM.MovingState.STOP);
fsm.toRaster();
fsmComponent.repaint(); fsmComponent.repaint();
break; break;
case 1: case 1:
if (moveStates) fsm.setMovingState(FSM.MovingState.TRANSITIONS);
fsm.toRaster();
moveStates = false;
timer.start(); timer.start();
break; break;
case 2: case 2:
moveStates = true; fsm.setMovingState(FSM.MovingState.BOTH);
timer.start(); timer.start();
break; break;
} }