mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 17:04:42 -04:00
more consistent moving of fsm elements
This commit is contained in:
parent
f30b0e362f
commit
6fec5c7023
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user