diff --git a/pom.xml b/pom.xml
index 185527a..3c89c61 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
de.srsoftware
web4rail
- 1.1.5
+ 1.1.6
Web4Rail
jar
Java Model Railway Control
diff --git a/resources/translations/Application.de.translation b/resources/translations/Application.de.translation
index ec7512e..0aefd35 100644
--- a/resources/translations/Application.de.translation
+++ b/resources/translations/Application.de.translation
@@ -26,23 +26,27 @@ Block {} is free : Block {} ist frei
Block {} is occupied : Block {} ist belegt
Block properties : Block-Eigenschaften
{}bound : nach {}
+BrakeCancel : Bremsvorgang abbrechen
+BrakeStart : Bremsvorgang starten
+BrakeStop : Zug anhalten
Car manager : Waggon-Verwaltung
Cars\: : Waggons:
-Click on a name to edit the entry. : Klicke auf einen Namen, um einen Eintrag zu bearbeiten.
-ConditionalAction : bedingte Aktion
-Conditions : Bedingungen
-Condition type\: : Bedingungs-Typ:
-Control : Steuerung
-Control unit : Zentrale
-Current location\: : Aktueller Ort:
+Click here to select train! : HIer klicken, um Zug auszuwählen!
[Click here to select block!] : [Hier klicken, um Block auszuwählen!]
[Click here to add condition] : [Hier klicken, um Bedingung hinzuzufügen]
[Click here to select display!] : [Hier klicken, um Anzeige auszuwählen!]
[Click here to select train!] : [Hier klicken, um Zug auszuwählen!]
click here to setup contact : Hier klicken, um Kontakt auszuwählen
click here to setup relay : Hier klicken, um Relais einzurichten
+Click on a name to edit the entry. : Klicke auf einen Namen, um einen Eintrag zu bearbeiten.
Command to send to control unit\: : Kommando, welches zur Zentrale gesendet werden soll:
+ConditionalAction : bedingte Aktion
+Conditions : Bedingungen
+Condition type\: : Bedingungs-Typ:
+Control : Steuerung
+Control unit : Zentrale
Create action : Aktion erzeugen
+Current location\: : Aktueller Ort:
Current location : Aufenthaltsort
Current location\: {} : Aufenthaltsort: {}
Current velocity\: {} {} : Aktuelle Geschwindigkeit: {} {}
@@ -64,6 +68,7 @@ Dropped destination of {}. : Ziel von {} verworfen.
EAST : Osten
editable train properties : veränderliche Zug-Eigenschaften
Emergency : Notfall
+Faster (10 {}) : 10 {} schneller
Firing {} : starte {}
FinishRoute : Route abschließen
Found {} routes. : {} Routen gefunden.
@@ -101,6 +106,7 @@ No : keine
No free routes from {} : keine Route von {} frei
NORTH : Norden
{} now heading for {} : {} ist nun unterweg nach {}
+{} now in auto-mode : {} ist nun im Automatikmodus
Occupied area\: : Belegte Abschnitte:
Off : Aus
On : An
@@ -132,6 +138,8 @@ Select relay\: : Relais auswählen:
Select train\: : Zug auswählen:
SendCommand : Kommando senden
Send command "{}" to control unit : Kommando „{}“ an Zentrale senden
+Set {} as context : {} als Kontext setzen
+SetContextTrain : Zug für Folgeaktionen festlegen
SetDisplayText : Anzeige-Text setzen
SetRelay : Relais schalten
SetSignal : Signal stellen
@@ -146,6 +154,7 @@ Setup actions : Vorbereitung-Aktionen
ShowText : Text anzeigen
Signals : Signale
Simulating movement of {}... : Simuliere Fahrt von {}...
+Slower (10 {}) : 10 {} langsamer
SOUTH : Süden
Start actions : Start-Aktionen
Stock ID : Inventarnummer
diff --git a/src/main/java/de/srsoftware/web4rail/Route.java b/src/main/java/de/srsoftware/web4rail/Route.java
index bf916b9..fd0511a 100644
--- a/src/main/java/de/srsoftware/web4rail/Route.java
+++ b/src/main/java/de/srsoftware/web4rail/Route.java
@@ -5,6 +5,7 @@ import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -24,6 +25,8 @@ import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.actions.Action;
import de.srsoftware.web4rail.actions.Action.Context;
import de.srsoftware.web4rail.actions.ActionList;
+import de.srsoftware.web4rail.actions.BrakeStart;
+import de.srsoftware.web4rail.actions.BrakeStop;
import de.srsoftware.web4rail.actions.FinishRoute;
import de.srsoftware.web4rail.actions.PreserveRoute;
import de.srsoftware.web4rail.actions.SetSignal;
@@ -54,6 +57,7 @@ public class Route extends BaseClass implements Comparable{
private static final String ACTIONS = "actions";
private static final String ACTION_LISTS = "action_lists";
+ private static final String BRAKE_TIMES = "brake_times";
private static final String CONDITIONS = "conditions";
private static final String DROP_CONDITION = "drop_condition";
private static final String END_DIRECTION = "direction_end";
@@ -66,9 +70,68 @@ public class Route extends BaseClass implements Comparable{
static final String PATH = "path";
static final String SIGNALS = "signals";
static final String TURNOUTS = "turnouts";
-
+
private static HashMap names = new HashMap(); // maps id to name. needed to keep names during plan.analyze()
+
+ private class BrakeProcessor extends Thread {
+ private int startSpeed;
+ private long timestamp;
+ private int timeStep;
+ private Route route;
+ private Train train;
+ private boolean aborted = false;
+ private static final int ENDSPEED = 5;
+
+ public BrakeProcessor(Route route, Train train, Integer timestep) {
+ startSpeed = train.speed;
+ this.timeStep = isNull(timestep) ? 100 : timestep;
+ this.route = route;
+ this.train = train;
+ start();
+ }
+ public void abort() {
+ aborted = true;
+ train.setSpeed(startSpeed);
+ }
+
+ public void finish() {
+ long timestamp2 = new Date().getTime();
+ //int remainingSpeed = train.speed;
+ train.setSpeed(0);
+ if (aborted) return;
+ long runtime = timestamp2 - timestamp;
+ int newTimeStep = 5*(int) runtime/(startSpeed - ENDSPEED);
+
+ int diff = newTimeStep - timeStep;
+ int absDiff = diff < 0 ? -diff : diff;
+ if (absDiff > timeStep/4) absDiff=timeStep/4;
+ newTimeStep = diff < 0 ? timeStep - absDiff : timeStep + absDiff;
+
+ if (newTimeStep != timeStep) {
+ route.brakeTimes.put(train.brakeId(),newTimeStep);
+ LOG.debug("Corrected brake timestep for {} @ {} from {} to {} ms.",train,route,timeStep,newTimeStep);
+ }
+ }
+
+ @Override
+ public void run() {
+ timestamp = new Date().getTime();
+ if (train.speed == 0) aborted = true;
+ while (train.speed > ENDSPEED) {
+ if (aborted) break;
+ train.setSpeed(train.speed - 5);
+ try {
+ sleep(timeStep);
+ } catch (InterruptedException e) {
+ LOG.warn("BrakeProcessor interrupted!", e);
+ }
+ }
+ }
+ }
+
+ private BrakeProcessor brakeProcessor = null;
+ private HashMap brakeTimes = new HashMap();
private Vector conditions = new Vector();
private Vector contacts;
private boolean disabled = false;
@@ -248,6 +311,7 @@ public class Route extends BaseClass implements Comparable{
newActionList.addActionsFrom(existingActionList);
}
}
+ brakeTimes = new HashMap(existingRoute.brakeTimes);
}
void addSignal(Signal signal) {
@@ -295,6 +359,20 @@ public class Route extends BaseClass implements Comparable{
return this;
}
+ public void brakeCancel() {
+ if (isSet(brakeProcessor)) brakeProcessor.abort();
+ }
+
+ public void brakeStart() {
+ if (isNull(train)) return;
+ Integer brakeTime = brakeTimes.get(train.brakeId());
+ brakeProcessor = new BrakeProcessor(this,train,brakeTime);
+ }
+
+ public void brakeStop() {
+ if (isSet(brakeProcessor)) brakeProcessor.finish();
+ }
+
protected Route clone() {
Route clone = new Route();
clone.startBlock = startBlock;
@@ -305,6 +383,7 @@ public class Route extends BaseClass implements Comparable{
clone.signals = new Vector(signals);
clone.turnouts = new HashMap<>(turnouts);
clone.path = new Vector<>(path);
+ clone.brakeTimes = new HashMap(brakeTimes);
return clone;
}
@@ -317,17 +396,17 @@ public class Route extends BaseClass implements Comparable{
if (contacts.size()>1) { // mindestens 2 Kontakte: erster Kontakt aktiviert Block, vorletzter Kontakt leitet Bremsung ein
Contact nextToLastContact = contacts.get(contacts.size()-2);
String trigger = nextToLastContact.trigger();
- add(trigger,new SetSpeed().to(50));
+ add(trigger,new BrakeStart());
add(trigger,new PreserveRoute());
for (Signal signal : signals) add(trigger,new SetSignal().set(signal).to(Signal.STOP));
}
if (!contacts.isEmpty()) {
Contact lastContact = contacts.lastElement();
- add(lastContact.trigger(), new SetSpeed());
+ add(lastContact.trigger(), new BrakeStop());
add(lastContact.trigger(), new FinishRoute());
}
for (Signal signal : signals) setupActions.add(new SetSignal().set(signal).to(Signal.GO));
- startActions.add(new SetSpeed().to(100));
+ startActions.add(new SetSpeed().to(999));
return this;
}
@@ -456,6 +535,8 @@ public class Route extends BaseClass implements Comparable{
json.put(START_DIRECTION, startDirection);
json.put(END_DIRECTION, endDirection);
+ json.put(BRAKE_TIMES, brakeTimes);
+
JSONArray jConditions = new JSONArray();
for (Condition condition : conditions) jConditions.put(condition.json());
if (!jConditions.isEmpty()) json.put(CONDITIONS, jConditions);
@@ -521,6 +602,10 @@ public class Route extends BaseClass implements Comparable{
if (json.has(SETUP_ACTIONS)) setupActions = ActionList.load(json.getJSONArray(SETUP_ACTIONS));
if (json.has(START_ACTIONS)) startActions = ActionList.load(json.getJSONArray(START_ACTIONS));
if (json.has(DISABLED)) disabled = json.getBoolean(DISABLED);
+ if (json.has(BRAKE_TIMES)) {
+ JSONObject dummy = json.getJSONObject(BRAKE_TIMES);
+ dummy.keySet().forEach(key -> brakeTimes.put(key, dummy.getInt(key)));
+ }
return plan.registerRoute(this);
}
diff --git a/src/main/java/de/srsoftware/web4rail/actions/Action.java b/src/main/java/de/srsoftware/web4rail/actions/Action.java
index d27a3c8..313e01a 100644
--- a/src/main/java/de/srsoftware/web4rail/actions/Action.java
+++ b/src/main/java/de/srsoftware/web4rail/actions/Action.java
@@ -134,12 +134,16 @@ public abstract class Action extends BaseClass {
public static List> list() {
return List.of(
+ BrakeStart.class,
+ BrakeStop.class,
+ BrakeCancel.class,
ConditionalAction.class,
DelayedAction.class,
DetermineTrainInBlock.class,
FinishRoute.class,
PreserveRoute.class,
SendCommand.class,
+ SetContextTrain.class,
SetDisplayText.class,
SetPower.class,
SetRelay.class,
diff --git a/src/main/java/de/srsoftware/web4rail/actions/BrakeCancel.java b/src/main/java/de/srsoftware/web4rail/actions/BrakeCancel.java
new file mode 100644
index 0000000..a3f40d5
--- /dev/null
+++ b/src/main/java/de/srsoftware/web4rail/actions/BrakeCancel.java
@@ -0,0 +1,12 @@
+package de.srsoftware.web4rail.actions;
+
+public class BrakeCancel extends Action {
+
+ @Override
+ public boolean fire(Context context) {
+ if (isNull(context.route)) return false;
+ context.route.brakeCancel();
+ return true;
+ }
+
+}
diff --git a/src/main/java/de/srsoftware/web4rail/actions/BrakeStart.java b/src/main/java/de/srsoftware/web4rail/actions/BrakeStart.java
new file mode 100644
index 0000000..e779f26
--- /dev/null
+++ b/src/main/java/de/srsoftware/web4rail/actions/BrakeStart.java
@@ -0,0 +1,13 @@
+package de.srsoftware.web4rail.actions;
+
+public class BrakeStart extends Action {
+
+ @Override
+ public boolean fire(Context context) {
+ if (isNull(context.route)) return false;
+ context.route.brakeStart();
+ LOG.debug("Started brake process...");
+ return true;
+ }
+
+}
diff --git a/src/main/java/de/srsoftware/web4rail/actions/BrakeStop.java b/src/main/java/de/srsoftware/web4rail/actions/BrakeStop.java
new file mode 100644
index 0000000..81d5b2a
--- /dev/null
+++ b/src/main/java/de/srsoftware/web4rail/actions/BrakeStop.java
@@ -0,0 +1,12 @@
+package de.srsoftware.web4rail.actions;
+
+public class BrakeStop extends Action {
+
+ @Override
+ public boolean fire(Context context) {
+ if (isNull(context.route)) return false;
+ context.route.brakeStop();
+ return true;
+ }
+
+}
diff --git a/src/main/java/de/srsoftware/web4rail/actions/SetContextTrain.java b/src/main/java/de/srsoftware/web4rail/actions/SetContextTrain.java
new file mode 100644
index 0000000..789d974
--- /dev/null
+++ b/src/main/java/de/srsoftware/web4rail/actions/SetContextTrain.java
@@ -0,0 +1,77 @@
+package de.srsoftware.web4rail.actions;
+
+import java.util.HashMap;
+
+import org.json.JSONObject;
+
+import de.srsoftware.web4rail.Window;
+import de.srsoftware.web4rail.moving.Train;
+import de.srsoftware.web4rail.tags.Button;
+import de.srsoftware.web4rail.tags.Form;
+import de.srsoftware.web4rail.tags.Input;
+import de.srsoftware.web4rail.tags.Label;
+import de.srsoftware.web4rail.tags.Select;
+
+public class SetContextTrain extends Action {
+
+ private Train train = null;
+
+ @Override
+ public boolean fire(Context context) {
+ context.train = train;
+ return true;
+ }
+
+ @Override
+ public JSONObject json() {
+ JSONObject json = super.json();
+ if (isSet(train)) json.put(REALM_TRAIN, train.id);
+ return json;
+ }
+
+ @Override
+ public Action load(JSONObject json) {
+ super.load(json);
+ if (json.has(REALM_TRAIN)) {
+ new Thread() { // load asynchronously, as referred tile may not be available,yet
+ public void run() {
+ try {
+ sleep(1000);
+ int trainId = json.getInt(REALM_TRAIN);
+ if (isSet(trainId)) train = Train.get(trainId);
+ } catch (InterruptedException e) {}
+ };
+ }.start();
+ }
+ return this;
+ }
+
+ @Override
+ public Window properties(HashMap params) {
+ Window win = super.properties(params);
+ Form form = new Form("action-prop-form-"+id);
+ new Input(REALM,REALM_ACTIONS).hideIn(form);
+ new Input(ID,params.get(ID)).hideIn(form);
+ new Input(ACTION,ACTION_UPDATE).hideIn(form);
+ new Input(CONTEXT,params.get(CONTEXT)).hideIn(form);
+
+ Select select = Train.selector(train, null);
+ select.addTo(new Label(t("Select train:")+NBSP)).addTo(form);
+
+ new Button(t("Apply"),form).addTo(form).addTo(win);
+ return win;
+ }
+
+ public String toString() {
+ return isSet(train) ? t("Set {} as context",train) : "["+t("Click here to select train!")+"]";
+ };
+
+ @Override
+ protected Object update(HashMap params) {
+ LOG.debug("update: {}",params);
+ String trainId = params.get(Train.class.getSimpleName());
+ if (isSet(trainId)) train = Train.get(Integer.parseInt(trainId));
+ return properties(params);
+ }
+
+}
diff --git a/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java b/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java
index e7ed328..04d83d4 100644
--- a/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java
+++ b/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java
@@ -101,7 +101,7 @@ public class Locomotive extends Car implements Constants,Device{
new Tag("span").content(t("Current velocity: {} {}",speed,speedUnit)).addTo(fieldset);
Tag par = new Tag("p");
- Map.of("Slower (10 steps)",ACTION_SLOWER10,"Faster (10 steps)",ACTION_FASTER10).entrySet().forEach(e -> {
+ Map.of(t("Slower (10 {})",speedUnit),ACTION_SLOWER10,t("Faster (10 {})",speedUnit),ACTION_FASTER10).entrySet().forEach(e -> {
params.put(ACTION, e.getValue());
new Button(t(e.getKey()),params).addTo(par);
});
diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java
index e7d0b36..387ee89 100644
--- a/src/main/java/de/srsoftware/web4rail/moving/Train.java
+++ b/src/main/java/de/srsoftware/web4rail/moving/Train.java
@@ -214,7 +214,7 @@ public class Train extends BaseClass implements Comparable {
TreeSet carIds = new TreeSet();
locos.stream().map(loco -> loco.id()).forEach(carIds::add);
cars.stream().map(car -> car.id()).forEach(carIds::add);
- brakeId = md5sum(carIds);
+ brakeId = md5sum(carIds+":"+direction);
LOG.debug("generated new brake id for {}: {}",brakeId,this);
}
return brakeId;
@@ -598,6 +598,7 @@ public class Train extends BaseClass implements Comparable {
public void reserveNext() {
Context context = new Context(null, route, this, route.endBlock(), route.endDirection);
Route nextRoute = PathFinder.chooseRoute(context);
+ if (isNull(nextRoute)) return;
boolean error = !nextRoute.lockIgnoring(route);
error = error || !nextRoute.setTurnouts();
@@ -608,6 +609,7 @@ public class Train extends BaseClass implements Comparable {
route.lock(); // corrects unlocked tiles of nextRoute
} else {
this.nextRoute = nextRoute;
+ this.route.brakeCancel();
}
}
@@ -775,6 +777,7 @@ public class Train extends BaseClass implements Comparable {
}
if (isSet(route)) {
route.reset();
+ route.brakeCancel();
route = null;
}
diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Block.java b/src/main/java/de/srsoftware/web4rail/tiles/Block.java
index afd3cb0..6a78430 100644
--- a/src/main/java/de/srsoftware/web4rail/tiles/Block.java
+++ b/src/main/java/de/srsoftware/web4rail/tiles/Block.java
@@ -122,7 +122,7 @@ public abstract class Block extends StretchableTile implements Comparable
@Override
public Object click() throws IOException {
- if (isSet(train)) return train.properties();
+ if (isSet(train) && train.currentBlock() == this) return train.properties();
return super.click();
}