Allows to select the angle at which the init state marker is drawn with the mouse.

This commit is contained in:
hneemann 2020-05-31 20:29:05 +02:00
parent 4e83b437d8
commit 45e0d68168
7 changed files with 97 additions and 48 deletions

View File

@ -301,7 +301,7 @@ public class FSM {
* @param dt the time step
* @param except element which is fixed
*/
public void move(int dt, Movable except) {
public void move(int dt, MouseMovable except) {
if (state != MovingState.STOP) {
calculateForces();
if (state == MovingState.BOTH)
@ -377,8 +377,8 @@ public class FSM {
* @param pos the position
* @return the element or null
*/
public Movable getMovable(Vector pos) {
Movable found = null;
public MouseMovable getMovable(Vector pos) {
Movable<?> found = null;
float dist = Float.MAX_VALUE;
for (Transition t : transitions)
if (t.matches(pos)) {
@ -400,7 +400,8 @@ public class FSM {
dist = d;
found = s;
}
}
} else if (s.matchesInitial(pos))
return s.getInitialMarkerMovable();
return found;
}
@ -439,7 +440,7 @@ public class FSM {
* @param movable the element changed
* @param prop the property which has changed
*/
void wasModified(Movable movable, Movable.Property prop) {
void wasModified(Movable<?> movable, Movable.Property prop) {
modified = true;
if (movable instanceof State) {

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 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.draw.graphics.VectorFloat;
import de.neemann.digital.draw.graphics.VectorInterface;
/**
* Element which can be moved by the mouse
*/
public interface MouseMovable {
/**
* @return the position
*/
VectorInterface getPos();
/**
* Sets the position by the mouse.
* Is called while dragging.
*
* @param pos the position
*/
void setPosByMouse(VectorFloat pos);
/**
* Sets the position by the mouse.
* Is called if mouse button is released.
*
* @param pos the position
*/
void setPos(VectorFloat pos);
}

View File

@ -12,9 +12,9 @@ import de.neemann.digital.draw.graphics.VectorFloat;
*
* @param <A> the type of the implementing class
*/
public class Movable<A extends Movable> {
public class Movable<A extends Movable<?>> implements MouseMovable {
enum Property {POS, REMOVED, CONDITION, NAME, NUMBER, MOUSEPOS, VALUES, INITIAL, ADDED}
enum Property {POS, REMOVED, CONDITION, NAME, NUMBER, MOUSEPOS, VALUES, INITIAL, ADDED, INITIAL_ANGLE}
private static final float MASS = 50f;
private static final float FRICTION = 0.8f;

View File

@ -99,9 +99,7 @@ public class State extends Movable<State> {
if (isInitial) {
Vector initRad = new Vector(INIT_RAD, INIT_RAD);
int r = radius + INIT_RAD * 6;
double angle = 2 * Math.PI / 32 * initialAngle;
VectorInterface pos = getPos().add(new VectorFloat((float) (Math.cos(angle) * r), -(float) (Math.sin(angle) * r)));
VectorInterface pos = getInitialMarkerPos();
gr.drawCircle(pos.sub(initRad), pos.add(initRad), Style.FILLED);
VectorInterface delta = getPos().sub(pos).norm();
VectorInterface a0 = pos.add(delta.mul(INIT_RAD + Style.FILLED.getThickness()));
@ -122,6 +120,15 @@ public class State extends Movable<State> {
}
}
/**
* @return the initial marker position
*/
VectorInterface getInitialMarkerPos() {
int r = radius + INIT_RAD * 6;
double angle = 2 * Math.PI / 32 * initialAngle;
return getPos().add(new VectorFloat((float) (Math.cos(angle) * r), -(float) (Math.sin(angle) * r)));
}
/**
* @return the radius of the state
*/
@ -176,6 +183,18 @@ public class State extends Movable<State> {
return pos.sub(getPos()).len() <= radius;
}
/**
* Returns true if the position matches the states initial marker
*
* @param pos the position
* @return true if pos inside of the states initial marker
*/
public boolean matchesInitial(Vector pos) {
if (!isInitial)
return false;
return pos.sub(getInitialMarkerPos()).len() <= INIT_RAD;
}
@Override
public String toString() {
if (name != null && name.length() > 0)
@ -221,18 +240,31 @@ public class State extends Movable<State> {
}
/**
* @return the angle of the initial marker
* @return a movable that represents the initial marker.
*/
public int getInitialAngle() {
return initialAngle;
}
public MouseMovable getInitialMarkerMovable() {
return new MouseMovable() {
@Override
public VectorInterface getPos() {
return getInitialMarkerPos();
}
/**
* Sets the angle of the initial marker
*
* @param angle the angle
*/
public void setInitialAngle(Integer angle) {
initialAngle = angle;
@Override
public void setPosByMouse(VectorFloat pos) {
VectorInterface delta = pos.sub(State.this.getPos());
double angle = Math.atan2(-delta.getYFloat(), delta.getXFloat()) / Math.PI * 16;
if (angle < 0)
angle += 32;
int ia = (int) Math.round(angle);
if (initialAngle != ia) {
initialAngle = ia;
wasModified(Property.INITIAL_ANGLE);
}
}
@Override
public void setPos(VectorFloat pos) {
}
};
}
}

View File

@ -10,10 +10,7 @@ import de.neemann.digital.core.element.Key;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.draw.graphics.*;
import de.neemann.digital.draw.graphics.Polygon;
import de.neemann.digital.fsm.FSM;
import de.neemann.digital.fsm.Movable;
import de.neemann.digital.fsm.State;
import de.neemann.digital.fsm.Transition;
import de.neemann.digital.fsm.*;
import de.neemann.digital.gui.components.AttributeDialog;
import de.neemann.digital.lang.Lang;
import de.neemann.gui.Mouse;
@ -34,12 +31,6 @@ import static de.neemann.digital.gui.components.CircuitComponent.ICON_DELETE;
public class FSMComponent extends JComponent {
private static final Key<Integer> KEY_NUMBER = new Key.KeyInteger("stateNum", 0);
private static final Key<Boolean> KEY_INITIAL = new Key<>("isInitialState", false);
private static final Key<Integer> KEY_INITIAL_ANGLE = new Key.KeyInteger("initialAngle", 12)
.setComboBoxValues(4, 12, 20, 28)
.setMin(0)
.setMax(31)
.setDependsOn(KEY_INITIAL)
.setSecondary();
private static final Key<String> KEY_VALUES = new Key<>("stateValues", "");
private static final Key<String> KEY_CONDITION = new Key<>("transCond", "");
private static final Key<Integer> KEY_RADIUS = new Key.KeyInteger("transRad", 70)
@ -51,7 +42,7 @@ public class FSMComponent extends JComponent {
private boolean isManualScale;
private AffineTransform transform = new AffineTransform();
private Movable<?> elementMoved;
private MouseMovable elementMoved;
private FSM fsm;
private Vector lastMousePos;
private State newTransitionFromState;
@ -87,7 +78,7 @@ public class FSMComponent extends JComponent {
if (elementMoved != null)
delta = posVector.sub(elementMoved.getPos());
} else if (mouse.isSecondaryClick(e)) {
Movable<?> st = fsm.getMovable(posVector);
MouseMovable st = fsm.getMovable(posVector);
if (st instanceof State) {
newTransitionStartPos = posVector;
newTransitionFromState = (State) st;
@ -107,7 +98,7 @@ public class FSMComponent extends JComponent {
if (newTransitionFromState != null) {
final Vector posVector = getPosVector(mouseEvent);
if (newTransitionStartPos.sub(posVector).len() > MIN_NEW_TRANS_DIST) {
Movable<?> target = fsm.getMovable(posVector);
MouseMovable target = fsm.getMovable(posVector);
if (target instanceof State)
fsm.add(new Transition(newTransitionFromState, (State) target, lastCondition));
}
@ -119,7 +110,7 @@ public class FSMComponent extends JComponent {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
final Vector posVector = getPosVector(mouseEvent);
Movable<?> elementClicked = fsm.getMovable(posVector);
MouseMovable elementClicked = fsm.getMovable(posVector);
if (mouse.isSecondaryClick(mouseEvent)) {
if (elementClicked == null)
createNewState(posVector, new Point(mouseEvent.getX(), mouseEvent.getY()));
@ -161,7 +152,7 @@ public class FSMComponent extends JComponent {
ToolTipAction deleteAction = new ToolTipAction(Lang.get("menu_delete"), ICON_DELETE) {
@Override
public void actionPerformed(ActionEvent actionEvent) {
Movable<?> element = fsm.getMovable(lastMousePos);
MouseMovable element = fsm.getMovable(lastMousePos);
if (element instanceof State) {
fsm.remove((State) element);
repaint();
@ -188,7 +179,7 @@ public class FSMComponent extends JComponent {
setPreferredSize(new Dimension(600, 600));
}
private static final Key<?>[] STATE_EDIT_KEYS = {Keys.LABEL, KEY_NUMBER, KEY_INITIAL, KEY_INITIAL_ANGLE, KEY_VALUES, KEY_RADIUS};
private static final Key<?>[] STATE_EDIT_KEYS = {Keys.LABEL, KEY_NUMBER, KEY_INITIAL, KEY_VALUES, KEY_RADIUS};
private void createNewState(Vector posVector, Point point) {
ElementAttributes attr = new ElementAttributes();
@ -216,7 +207,6 @@ public class FSMComponent extends JComponent {
ElementAttributes attr = new ElementAttributes()
.set(KEY_NUMBER, state.getNumber())
.set(KEY_INITIAL, state.isInitial())
.set(KEY_INITIAL_ANGLE, state.getInitialAngle())
.set(KEY_VALUES, state.getValues())
.set(KEY_RADIUS, state.getVisualRadius())
.set(Keys.LABEL, state.getName());
@ -228,7 +218,6 @@ public class FSMComponent extends JComponent {
if (newAttr != null) {
state.setNumber(newAttr.get(KEY_NUMBER));
state.setInitial(newAttr.get(KEY_INITIAL));
state.setInitialAngle(newAttr.get(KEY_INITIAL_ANGLE));
state.setValues(newAttr.get(KEY_VALUES));
state.setRadius(newAttr.get(KEY_RADIUS));
state.setName(newAttr.get(Keys.LABEL));
@ -318,7 +307,7 @@ public class FSMComponent extends JComponent {
/**
* @return the element picked by the mouse
*/
Movable<?> getElementMoved() {
MouseMovable getElementMoved() {
return elementMoved;
}

View File

@ -2080,10 +2080,6 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z
<string name="key_isInitialState_tt">Wenn gesetzt, ist dies der Initialzustand, in welchem der Automat gestartet
wird.
</string>
<string name="key_initialAngle">Winkel Initial-Marker</string>
<string name="key_initialAngle_tt">Winkel bei dem der Marker des Initialzustandes gezeichnet werden soll.
Ist ein Wert zwischen 0 und 31.
</string>
<string name="key_stateValues">Ausgänge</string>
<string name="key_stateValues_tt">Legt Ausgangswerte fest.
Mit einfachen Zuweisungen wie "A=1, B=0" können Ausgänge gesetzt werden.

View File

@ -2035,10 +2035,6 @@ Therefore, the signal 'D_out' is also available to check the value in this case.
<string name="key_stateNum_tt">The number which represents this state.</string>
<string name="key_isInitialState">Initial State</string>
<string name="key_isInitialState_tt">If set, this state is the initial state.</string>
<string name="key_initialAngle">Angle Initial Marker</string>
<string name="key_initialAngle_tt">Angle at which the marker of the initial state should be drawn.
Is a value between 0 and 31.
</string>
<string name="key_stateValues">Outputs</string>
<string name="key_stateValues_tt">Defines the output values.
With simple assignments like "A=1, B=0" outputs can be set.