mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-15 07:48:29 -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 {
|
||||
|
||||
/**
|
||||
* 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<Transition> transitions;
|
||||
private transient boolean modified;
|
||||
@ -33,6 +51,7 @@ public class FSM {
|
||||
private transient Transition initialTransition;
|
||||
private transient int activeState = -1;
|
||||
private transient File file;
|
||||
private transient MovingState state = MovingState.STOP;
|
||||
|
||||
/**
|
||||
* Creates a proper configured XStream instance
|
||||
@ -131,6 +150,30 @@ public class FSM {
|
||||
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
|
||||
*
|
||||
@ -293,19 +336,20 @@ 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
|
||||
* @param dt the time step
|
||||
* @param except element which is fixed
|
||||
*/
|
||||
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);
|
||||
public void move(int dt, Movable except) {
|
||||
if (state != MovingState.STOP) {
|
||||
calculateForces();
|
||||
if (state == MovingState.BOTH)
|
||||
for (State s : states)
|
||||
if (s != except)
|
||||
s.move(dt);
|
||||
for (Transition t : transitions)
|
||||
if (t != except)
|
||||
t.move(dt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,23 +397,31 @@ public class FSM {
|
||||
* @return the element or null
|
||||
*/
|
||||
public Movable getMovable(Vector pos) {
|
||||
Movable found = null;
|
||||
float dist = Float.MAX_VALUE;
|
||||
for (Transition t : transitions)
|
||||
if (t.matches(pos))
|
||||
return t;
|
||||
if (t.matches(pos)) {
|
||||
float d = pos.sub(t.getPos()).len();
|
||||
if (d < dist) {
|
||||
dist = d;
|
||||
found = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != null)
|
||||
return found;
|
||||
|
||||
dist = Float.MAX_VALUE;
|
||||
for (State s : states)
|
||||
if (s.matches(pos))
|
||||
return s;
|
||||
if (s.matches(pos)) {
|
||||
float d = pos.sub(s.getPos()).len();
|
||||
if (d < dist) {
|
||||
dist = d;
|
||||
found = s;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move states to raster
|
||||
*/
|
||||
public void toRaster() {
|
||||
for (State s : states)
|
||||
s.toRaster();
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -386,7 +438,7 @@ public class FSM {
|
||||
*/
|
||||
public void remove(Transition transition) {
|
||||
transitions.remove(transition);
|
||||
wasModified();
|
||||
wasModified(transition, Movable.Property.REMOVED);
|
||||
resetInitInitialization();
|
||||
}
|
||||
|
||||
@ -398,15 +450,30 @@ public class FSM {
|
||||
public void remove(State state) {
|
||||
states.remove(state);
|
||||
transitions.removeIf(t -> t.getStartState() == state || t.getTargetState() == state);
|
||||
wasModified();
|
||||
wasModified(state, Movable.Property.REMOVED);
|
||||
resetInitInitialization();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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)
|
||||
modifiedListener.modifiedChanged(modified);
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ import de.neemann.digital.draw.graphics.VectorFloat;
|
||||
* @param <A> the type of the implementing class
|
||||
*/
|
||||
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 FRICTION = 0.8f;
|
||||
private static final float MAX_FORCE = 100000f;
|
||||
@ -23,6 +26,7 @@ public class Movable<A extends Movable> {
|
||||
private transient VectorFloat speed;
|
||||
private transient VectorFloat force;
|
||||
private transient FSM fsm;
|
||||
private transient Property lastPosProp;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
@ -33,21 +37,35 @@ public class Movable<A extends Movable> {
|
||||
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
|
||||
*
|
||||
* @param position the 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;
|
||||
wasModified();
|
||||
lastPosProp = prop;
|
||||
wasModified(prop);
|
||||
}
|
||||
}
|
||||
|
||||
void wasModified() {
|
||||
void wasModified(Property prop) {
|
||||
if (fsm != null)
|
||||
fsm.wasModified();
|
||||
fsm.wasModified(this, prop);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,7 +185,7 @@ public class Movable<A extends Movable> {
|
||||
public A setValues(String values) {
|
||||
if (!this.values.equals(values)) {
|
||||
this.values = values;
|
||||
wasModified();
|
||||
wasModified(Property.VALUES);
|
||||
}
|
||||
return (A) this;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public class State extends Movable<State> {
|
||||
public void setName(String name) {
|
||||
if (!this.name.equals(name)) {
|
||||
this.name = name;
|
||||
wasModified();
|
||||
wasModified(Property.NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ public class State extends Movable<State> {
|
||||
public State setNumber(int number) {
|
||||
if (this.number != number) {
|
||||
this.number = number;
|
||||
wasModified();
|
||||
wasModified(Property.NUMBER);
|
||||
if (getFsm() != null)
|
||||
getFsm().resetInitInitialization();
|
||||
}
|
||||
|
@ -92,8 +92,18 @@ public class Transition extends Movable<Transition> {
|
||||
return getFsm() != null && getFsm().isInitial(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setPosByMouse(VectorFloat position) {
|
||||
super.setPosByMouse(posConstrain(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPos(VectorFloat position) {
|
||||
super.setPos(posConstrain(position));
|
||||
}
|
||||
|
||||
private VectorFloat posConstrain(VectorFloat position) {
|
||||
if (fromState != toState) {
|
||||
VectorFloat dist = toState.getPos().sub(fromState.getPos());
|
||||
if (dist.getXFloat() != 0 || dist.getYFloat() != 0) {
|
||||
@ -104,11 +114,10 @@ public class Transition extends Movable<Transition> {
|
||||
VectorFloat p = position.sub(start);
|
||||
VectorFloat n = dist.getOrthogonal();
|
||||
float l = p.mul(n);
|
||||
super.setPos(start.add(end).div(2).add(n.mul(l)));
|
||||
return;
|
||||
return start.add(end).div(2).add(n.mul(l));
|
||||
}
|
||||
}
|
||||
super.setPos(position);
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,7 +207,7 @@ public class Transition extends Movable<Transition> {
|
||||
public void setCondition(String condition) {
|
||||
if (!this.condition.equals(condition)) {
|
||||
this.condition = condition;
|
||||
wasModified();
|
||||
wasModified(Property.CONDITION);
|
||||
conditionExpression = null;
|
||||
if (getFsm() != null)
|
||||
getFsm().resetInitInitialization();
|
||||
|
@ -91,8 +91,8 @@ public class FSMComponent extends JComponent {
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent mouseEvent) {
|
||||
if (elementMoved instanceof State) {
|
||||
((State) elementMoved).toRaster();
|
||||
if (elementMoved != null) {
|
||||
elementMoved.setPos(getPosVector(mouseEvent).sub(delta).toFloat());
|
||||
repaint();
|
||||
}
|
||||
elementMoved = null;
|
||||
@ -140,7 +140,7 @@ public class FSMComponent extends JComponent {
|
||||
repaint();
|
||||
}
|
||||
if (elementMoved != null) {
|
||||
elementMoved.setPos(getPosVector(e).sub(delta).toFloat());
|
||||
elementMoved.setPosByMouse(getPosVector(e).sub(delta).toFloat());
|
||||
repaint();
|
||||
}
|
||||
if (newTransitionFromState != null)
|
||||
|
@ -54,7 +54,6 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
private final Timer timer;
|
||||
private final JComboBox<String> moveControl;
|
||||
private FSM fsm;
|
||||
private boolean moveStates = false;
|
||||
private ToolTipAction save;
|
||||
private File filename;
|
||||
private File baseFilename;
|
||||
@ -78,9 +77,13 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
timer = new Timer(100, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
for (int i = 0; i < 100; i++)
|
||||
fsm.move(10, moveStates, fsmComponent.getElementMoved());
|
||||
repaint();
|
||||
if (fsm.getMovingState() == FSM.MovingState.STOP)
|
||||
timer.stop();
|
||||
else {
|
||||
for (int i = 0; i < 100; i++)
|
||||
fsm.move(10, fsmComponent.getElementMoved());
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -111,18 +114,15 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
switch (moveControl.getSelectedIndex()) {
|
||||
case 0:
|
||||
timer.stop();
|
||||
fsm.toRaster();
|
||||
fsm.setMovingState(FSM.MovingState.STOP);
|
||||
fsmComponent.repaint();
|
||||
break;
|
||||
case 1:
|
||||
if (moveStates)
|
||||
fsm.toRaster();
|
||||
moveStates = false;
|
||||
fsm.setMovingState(FSM.MovingState.TRANSITIONS);
|
||||
timer.start();
|
||||
break;
|
||||
case 2:
|
||||
moveStates = true;
|
||||
fsm.setMovingState(FSM.MovingState.BOTH);
|
||||
timer.start();
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user