mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-12 22:36:02 -04:00
Allows to select the angle at which the init state marker is drawn with the mouse.
This commit is contained in:
parent
4e83b437d8
commit
45e0d68168
@ -301,7 +301,7 @@ public class FSM {
|
|||||||
* @param dt the time step
|
* @param dt the time step
|
||||||
* @param except element which is fixed
|
* @param except element which is fixed
|
||||||
*/
|
*/
|
||||||
public void move(int dt, Movable except) {
|
public void move(int dt, MouseMovable except) {
|
||||||
if (state != MovingState.STOP) {
|
if (state != MovingState.STOP) {
|
||||||
calculateForces();
|
calculateForces();
|
||||||
if (state == MovingState.BOTH)
|
if (state == MovingState.BOTH)
|
||||||
@ -377,8 +377,8 @@ public class FSM {
|
|||||||
* @param pos the position
|
* @param pos the position
|
||||||
* @return the element or null
|
* @return the element or null
|
||||||
*/
|
*/
|
||||||
public Movable getMovable(Vector pos) {
|
public MouseMovable getMovable(Vector pos) {
|
||||||
Movable found = null;
|
Movable<?> found = null;
|
||||||
float dist = Float.MAX_VALUE;
|
float dist = Float.MAX_VALUE;
|
||||||
for (Transition t : transitions)
|
for (Transition t : transitions)
|
||||||
if (t.matches(pos)) {
|
if (t.matches(pos)) {
|
||||||
@ -400,7 +400,8 @@ public class FSM {
|
|||||||
dist = d;
|
dist = d;
|
||||||
found = s;
|
found = s;
|
||||||
}
|
}
|
||||||
}
|
} else if (s.matchesInitial(pos))
|
||||||
|
return s.getInitialMarkerMovable();
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
@ -439,7 +440,7 @@ public class FSM {
|
|||||||
* @param movable the element changed
|
* @param movable the element changed
|
||||||
* @param prop the property which has changed
|
* @param prop the property which has changed
|
||||||
*/
|
*/
|
||||||
void wasModified(Movable movable, Movable.Property prop) {
|
void wasModified(Movable<?> movable, Movable.Property prop) {
|
||||||
modified = true;
|
modified = true;
|
||||||
|
|
||||||
if (movable instanceof State) {
|
if (movable instanceof State) {
|
||||||
|
35
src/main/java/de/neemann/digital/fsm/MouseMovable.java
Normal file
35
src/main/java/de/neemann/digital/fsm/MouseMovable.java
Normal 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);
|
||||||
|
}
|
@ -12,9 +12,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<?>> 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 MASS = 50f;
|
||||||
private static final float FRICTION = 0.8f;
|
private static final float FRICTION = 0.8f;
|
||||||
|
@ -99,9 +99,7 @@ public class State extends Movable<State> {
|
|||||||
|
|
||||||
if (isInitial) {
|
if (isInitial) {
|
||||||
Vector initRad = new Vector(INIT_RAD, INIT_RAD);
|
Vector initRad = new Vector(INIT_RAD, INIT_RAD);
|
||||||
int r = radius + INIT_RAD * 6;
|
VectorInterface pos = getInitialMarkerPos();
|
||||||
double angle = 2 * Math.PI / 32 * initialAngle;
|
|
||||||
VectorInterface pos = getPos().add(new VectorFloat((float) (Math.cos(angle) * r), -(float) (Math.sin(angle) * r)));
|
|
||||||
gr.drawCircle(pos.sub(initRad), pos.add(initRad), Style.FILLED);
|
gr.drawCircle(pos.sub(initRad), pos.add(initRad), Style.FILLED);
|
||||||
VectorInterface delta = getPos().sub(pos).norm();
|
VectorInterface delta = getPos().sub(pos).norm();
|
||||||
VectorInterface a0 = pos.add(delta.mul(INIT_RAD + Style.FILLED.getThickness()));
|
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
|
* @return the radius of the state
|
||||||
*/
|
*/
|
||||||
@ -176,6 +183,18 @@ public class State extends Movable<State> {
|
|||||||
return pos.sub(getPos()).len() <= radius;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (name != null && name.length() > 0)
|
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() {
|
public MouseMovable getInitialMarkerMovable() {
|
||||||
return initialAngle;
|
return new MouseMovable() {
|
||||||
}
|
@Override
|
||||||
|
public VectorInterface getPos() {
|
||||||
|
return getInitialMarkerPos();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the angle of the initial marker
|
public void setPosByMouse(VectorFloat pos) {
|
||||||
*
|
VectorInterface delta = pos.sub(State.this.getPos());
|
||||||
* @param angle the angle
|
double angle = Math.atan2(-delta.getYFloat(), delta.getXFloat()) / Math.PI * 16;
|
||||||
*/
|
if (angle < 0)
|
||||||
public void setInitialAngle(Integer angle) {
|
angle += 32;
|
||||||
initialAngle = angle;
|
int ia = (int) Math.round(angle);
|
||||||
|
if (initialAngle != ia) {
|
||||||
|
initialAngle = ia;
|
||||||
|
wasModified(Property.INITIAL_ANGLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPos(VectorFloat pos) {
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,7 @@ import de.neemann.digital.core.element.Key;
|
|||||||
import de.neemann.digital.core.element.Keys;
|
import de.neemann.digital.core.element.Keys;
|
||||||
import de.neemann.digital.draw.graphics.*;
|
import de.neemann.digital.draw.graphics.*;
|
||||||
import de.neemann.digital.draw.graphics.Polygon;
|
import de.neemann.digital.draw.graphics.Polygon;
|
||||||
import de.neemann.digital.fsm.FSM;
|
import de.neemann.digital.fsm.*;
|
||||||
import de.neemann.digital.fsm.Movable;
|
|
||||||
import de.neemann.digital.fsm.State;
|
|
||||||
import de.neemann.digital.fsm.Transition;
|
|
||||||
import de.neemann.digital.gui.components.AttributeDialog;
|
import de.neemann.digital.gui.components.AttributeDialog;
|
||||||
import de.neemann.digital.lang.Lang;
|
import de.neemann.digital.lang.Lang;
|
||||||
import de.neemann.gui.Mouse;
|
import de.neemann.gui.Mouse;
|
||||||
@ -34,12 +31,6 @@ import static de.neemann.digital.gui.components.CircuitComponent.ICON_DELETE;
|
|||||||
public class FSMComponent extends JComponent {
|
public class FSMComponent extends JComponent {
|
||||||
private static final Key<Integer> KEY_NUMBER = new Key.KeyInteger("stateNum", 0);
|
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<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_VALUES = new Key<>("stateValues", "");
|
||||||
private static final Key<String> KEY_CONDITION = new Key<>("transCond", "");
|
private static final Key<String> KEY_CONDITION = new Key<>("transCond", "");
|
||||||
private static final Key<Integer> KEY_RADIUS = new Key.KeyInteger("transRad", 70)
|
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 boolean isManualScale;
|
||||||
private AffineTransform transform = new AffineTransform();
|
private AffineTransform transform = new AffineTransform();
|
||||||
private Movable<?> elementMoved;
|
private MouseMovable elementMoved;
|
||||||
private FSM fsm;
|
private FSM fsm;
|
||||||
private Vector lastMousePos;
|
private Vector lastMousePos;
|
||||||
private State newTransitionFromState;
|
private State newTransitionFromState;
|
||||||
@ -87,7 +78,7 @@ public class FSMComponent extends JComponent {
|
|||||||
if (elementMoved != null)
|
if (elementMoved != null)
|
||||||
delta = posVector.sub(elementMoved.getPos());
|
delta = posVector.sub(elementMoved.getPos());
|
||||||
} else if (mouse.isSecondaryClick(e)) {
|
} else if (mouse.isSecondaryClick(e)) {
|
||||||
Movable<?> st = fsm.getMovable(posVector);
|
MouseMovable st = fsm.getMovable(posVector);
|
||||||
if (st instanceof State) {
|
if (st instanceof State) {
|
||||||
newTransitionStartPos = posVector;
|
newTransitionStartPos = posVector;
|
||||||
newTransitionFromState = (State) st;
|
newTransitionFromState = (State) st;
|
||||||
@ -107,7 +98,7 @@ public class FSMComponent extends JComponent {
|
|||||||
if (newTransitionFromState != null) {
|
if (newTransitionFromState != null) {
|
||||||
final Vector posVector = getPosVector(mouseEvent);
|
final Vector posVector = getPosVector(mouseEvent);
|
||||||
if (newTransitionStartPos.sub(posVector).len() > MIN_NEW_TRANS_DIST) {
|
if (newTransitionStartPos.sub(posVector).len() > MIN_NEW_TRANS_DIST) {
|
||||||
Movable<?> target = fsm.getMovable(posVector);
|
MouseMovable target = fsm.getMovable(posVector);
|
||||||
if (target instanceof State)
|
if (target instanceof State)
|
||||||
fsm.add(new Transition(newTransitionFromState, (State) target, lastCondition));
|
fsm.add(new Transition(newTransitionFromState, (State) target, lastCondition));
|
||||||
}
|
}
|
||||||
@ -119,7 +110,7 @@ public class FSMComponent extends JComponent {
|
|||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent mouseEvent) {
|
public void mouseClicked(MouseEvent mouseEvent) {
|
||||||
final Vector posVector = getPosVector(mouseEvent);
|
final Vector posVector = getPosVector(mouseEvent);
|
||||||
Movable<?> elementClicked = fsm.getMovable(posVector);
|
MouseMovable elementClicked = fsm.getMovable(posVector);
|
||||||
if (mouse.isSecondaryClick(mouseEvent)) {
|
if (mouse.isSecondaryClick(mouseEvent)) {
|
||||||
if (elementClicked == null)
|
if (elementClicked == null)
|
||||||
createNewState(posVector, new Point(mouseEvent.getX(), mouseEvent.getY()));
|
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) {
|
ToolTipAction deleteAction = new ToolTipAction(Lang.get("menu_delete"), ICON_DELETE) {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent actionEvent) {
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
Movable<?> element = fsm.getMovable(lastMousePos);
|
MouseMovable element = fsm.getMovable(lastMousePos);
|
||||||
if (element instanceof State) {
|
if (element instanceof State) {
|
||||||
fsm.remove((State) element);
|
fsm.remove((State) element);
|
||||||
repaint();
|
repaint();
|
||||||
@ -188,7 +179,7 @@ public class FSMComponent extends JComponent {
|
|||||||
setPreferredSize(new Dimension(600, 600));
|
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) {
|
private void createNewState(Vector posVector, Point point) {
|
||||||
ElementAttributes attr = new ElementAttributes();
|
ElementAttributes attr = new ElementAttributes();
|
||||||
@ -216,7 +207,6 @@ public class FSMComponent extends JComponent {
|
|||||||
ElementAttributes attr = new ElementAttributes()
|
ElementAttributes attr = new ElementAttributes()
|
||||||
.set(KEY_NUMBER, state.getNumber())
|
.set(KEY_NUMBER, state.getNumber())
|
||||||
.set(KEY_INITIAL, state.isInitial())
|
.set(KEY_INITIAL, state.isInitial())
|
||||||
.set(KEY_INITIAL_ANGLE, state.getInitialAngle())
|
|
||||||
.set(KEY_VALUES, state.getValues())
|
.set(KEY_VALUES, state.getValues())
|
||||||
.set(KEY_RADIUS, state.getVisualRadius())
|
.set(KEY_RADIUS, state.getVisualRadius())
|
||||||
.set(Keys.LABEL, state.getName());
|
.set(Keys.LABEL, state.getName());
|
||||||
@ -228,7 +218,6 @@ public class FSMComponent extends JComponent {
|
|||||||
if (newAttr != null) {
|
if (newAttr != null) {
|
||||||
state.setNumber(newAttr.get(KEY_NUMBER));
|
state.setNumber(newAttr.get(KEY_NUMBER));
|
||||||
state.setInitial(newAttr.get(KEY_INITIAL));
|
state.setInitial(newAttr.get(KEY_INITIAL));
|
||||||
state.setInitialAngle(newAttr.get(KEY_INITIAL_ANGLE));
|
|
||||||
state.setValues(newAttr.get(KEY_VALUES));
|
state.setValues(newAttr.get(KEY_VALUES));
|
||||||
state.setRadius(newAttr.get(KEY_RADIUS));
|
state.setRadius(newAttr.get(KEY_RADIUS));
|
||||||
state.setName(newAttr.get(Keys.LABEL));
|
state.setName(newAttr.get(Keys.LABEL));
|
||||||
@ -318,7 +307,7 @@ public class FSMComponent extends JComponent {
|
|||||||
/**
|
/**
|
||||||
* @return the element picked by the mouse
|
* @return the element picked by the mouse
|
||||||
*/
|
*/
|
||||||
Movable<?> getElementMoved() {
|
MouseMovable getElementMoved() {
|
||||||
return elementMoved;
|
return elementMoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
<string name="key_isInitialState_tt">Wenn gesetzt, ist dies der Initialzustand, in welchem der Automat gestartet
|
||||||
wird.
|
wird.
|
||||||
</string>
|
</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">Ausgänge</string>
|
||||||
<string name="key_stateValues_tt">Legt Ausgangswerte fest.
|
<string name="key_stateValues_tt">Legt Ausgangswerte fest.
|
||||||
Mit einfachen Zuweisungen wie "A=1, B=0" können Ausgänge gesetzt werden.
|
Mit einfachen Zuweisungen wie "A=1, B=0" können Ausgänge gesetzt werden.
|
||||||
|
@ -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_stateNum_tt">The number which represents this state.</string>
|
||||||
<string name="key_isInitialState">Initial 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_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">Outputs</string>
|
||||||
<string name="key_stateValues_tt">Defines the output values.
|
<string name="key_stateValues_tt">Defines the output values.
|
||||||
With simple assignments like "A=1, B=0" outputs can be set.
|
With simple assignments like "A=1, B=0" outputs can be set.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user