Browse Source

overhauled brake time processor

lookup-tables
Stephan Richter 5 years ago
parent
commit
a74070ea80
  1. 2
      pom.xml
  2. 4
      src/main/java/de/srsoftware/web4rail/BaseClass.java
  3. 109
      src/main/java/de/srsoftware/web4rail/Route.java
  4. 14
      src/main/java/de/srsoftware/web4rail/actions/ActionList.java
  5. 8
      src/main/java/de/srsoftware/web4rail/actions/ConditionalAction.java
  6. 4
      src/main/java/de/srsoftware/web4rail/actions/SetSpeed.java
  7. 46
      src/main/java/de/srsoftware/web4rail/moving/Train.java

2
pom.xml

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.srsoftware</groupId>
<artifactId>web4rail</artifactId>
<version>1.3.4</version>
<version>1.3.5</version>
<name>Web4Rail</name>
<packaging>jar</packaging>
<description>Java Model Railway Control</description>

4
src/main/java/de/srsoftware/web4rail/BaseClass.java

@ -502,6 +502,10 @@ public abstract class BaseClass implements Constants{ @@ -502,6 +502,10 @@ public abstract class BaseClass implements Constants{
return Translation.get(Application.class, txt, fills);
}
public static long timestamp() {
return new Date().getTime();
}
public BaseClass unregister() {
return registry.remove(this.id());
}

109
src/main/java/de/srsoftware/web4rail/Route.java

@ -4,7 +4,6 @@ import java.io.BufferedWriter; @@ -4,7 +4,6 @@ import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -77,27 +76,31 @@ public class Route extends BaseClass { @@ -77,27 +76,31 @@ public class Route extends BaseClass {
private static final String ROUTE_SETUP = "route_setup";
private int startSpeed;
private static HashMap<Id, String> names = new HashMap<Id, String>(); // maps id to name. needed to keep names during plan.analyze()
private int startSpeed;
private static HashMap<Id, String> names = new HashMap<Id, String>(); // maps id to name. needed to keep names during plan.analyze()
private class BrakeProcessor extends Thread {
private class BrakeProcessor extends Thread {
private long timestamp;
private static final int SPEED_STEP = 5;
private Integer timeStep;
private Route route;
private Train train;
private boolean aborted = false;
private String brakeId;
private long estimatedDistance; // Unit: s*km/h "km/h-Sekunden"
public BrakeProcessor(Route route, Train train) {
this.train = train;
this.route = route;
startSpeed = train.speed;
estimatedDistance = 0;
brakeId = train.brakeId();
startSpeed = train.speed;
timeStep = brakeTimes.get(brakeId);
// if no brake time is available for this train, use the fastest brake time already known for this route:
if (isNull(timeStep)) timeStep = route.brakeTimes.values().stream().min(Integer::compare).orElse(100);
if (isNull(timeStep)) timeStep = 100;
start();
}
@ -106,19 +109,35 @@ public class Route extends BaseClass { @@ -106,19 +109,35 @@ public class Route extends BaseClass {
train.setSpeed(startSpeed);
}
private long calcDistance(Integer ts) {
long dist = 0;
int s = startSpeed;
while (s > endSpeed) {
s -= SPEED_STEP;
dist += s*ts;
}
LOG.debug("Estimated distamce with {} ms timestep: {}",ts,dist);
return dist;
}
/**
* This is called from route.finish when train came to stop
*/
public void finish() {
long timestamp2 = new Date().getTime();
//int remainingSpeed = train.speed;
LOG.debug("BrakeProcessor.finish(){}",aborted?" got aborted":"");
if (aborted) return;
long runtime = timestamp2 - timestamp;
int quotient = startSpeed - endSpeed;
if (quotient<1) quotient = 1;
int newTimeStep = 5*(int) runtime/quotient;
int diff = newTimeStep - timeStep;
int absDiff = diff < 0 ? -diff : diff;
if (absDiff > timeStep/4) absDiff=timeStep/4;
newTimeStep = diff < 0 ? timeStep - absDiff : timeStep + absDiff;
long runtime = BaseClass.timestamp() - timestamp;
estimatedDistance += train.speed * runtime;
train.setSpeed(0);
LOG.debug("Estimated distance: {}",estimatedDistance);
Integer newTimeStep = timeStep;
while (calcDistance(newTimeStep) < estimatedDistance) {
newTimeStep += 1+newTimeStep/8;
}
while (calcDistance(newTimeStep) > estimatedDistance) {
newTimeStep -= 1+newTimeStep/16;
}
if (newTimeStep != timeStep) {
route.brakeTimes.put(brakeId,newTimeStep);
@ -128,12 +147,29 @@ public class Route extends BaseClass { @@ -128,12 +147,29 @@ public class Route extends BaseClass {
@Override
public void run() {
timestamp = new Date().getTime();
timestamp = timestamp();
Integer nextRouteSpeed = null;
if (train.speed == 0) aborted = true;
while (train.speed > endSpeed) {
if (aborted || train.nextRoutePrepared()) break;
if (train.nextRoutePrepared()) {
if (isNull(nextRouteSpeed)) nextRouteSpeed = train.nextRoute().startSpeed(); // get the starting speed of the next route
if (isNull(nextRouteSpeed)) {
LOG.warn("Train has prepared next route, but that route seems to have no start speed!?");
nextRouteSpeed = 0; // assume starting speed of zero
}
if (train.speed < nextRouteSpeed) { // train already is slower: stop braking, set train speed to next route's start speed
train.setSpeed(nextRouteSpeed);
abort();
}
// if train is still faster than starting speed for next route: continue braking
}
if (aborted) break;
LOG.debug("BrakeProcessor({}) setting Speed of {}.",route,train);
train.setSpeed(Math.max(train.speed - 5,endSpeed));
long runtime = BaseClass.timestamp() - timestamp;
timestamp = timestamp+runtime;
estimatedDistance += train.speed * runtime;
train.setSpeed(Math.max(train.speed - SPEED_STEP,endSpeed));
try {
sleep(timeStep);
} catch (InterruptedException e) {
@ -320,7 +356,8 @@ public class Route extends BaseClass { @@ -320,7 +356,8 @@ public class Route extends BaseClass {
}
public void brakeCancel() {
if (isSet(brakeProcessor)) brakeProcessor.abort();
if (isSet(brakeProcessor)) brakeProcessor.abort();
brakeProcessor = null;
}
public void brakeStart() {
@ -427,19 +464,30 @@ public class Route extends BaseClass { @@ -427,19 +464,30 @@ public class Route extends BaseClass {
return context.clone();
}
public void dropBraketimes(String...brakeIds) {
for (String brakeId : brakeIds) brakeTimes.remove(brakeId);
}
public Block endBlock() {
return endBlock;
}
public void finish() {
LOG.debug("{}.finish()",this);
if (isSet(train)) {
if (train.nextRoutePrepared()) {
LOG.debug("{} has prepared next route: {}",train,train.nextRoute());
if (isSet(brakeProcessor)) brakeProcessor.abort();
} else {
train.setSpeed(0);
if (isSet(brakeProcessor)) brakeProcessor.finish();
LOG.debug("{} has no next route.",train);
if (isSet(brakeProcessor)) {
brakeProcessor.finish();
} else {
train.setSpeed(0);
}
}
}
}
brakeProcessor = null;
context.clear(); // prevent delayed actions from firing after route has finished
setSignals(Signal.RED);
@ -911,7 +959,14 @@ public class Route extends BaseClass { @@ -911,7 +959,14 @@ public class Route extends BaseClass {
public Block startBlock() {
return startBlock;
}
}
public Integer startSpeed() {
ActionList startActions = triggeredActions.get(ROUTE_START);
Context context = new Context(this);
return isSet(startActions) ? startActions.getSpeed(context) : null;
}
protected static String t(String txt, Object...fills) {
return Translation.get(Application.class, txt, fills);
@ -968,4 +1023,8 @@ public class Route extends BaseClass { @@ -968,4 +1023,8 @@ public class Route extends BaseClass {
}
return properties();
}
public Integer brakeTime(String brakeId) {
return brakeTimes.get(brakeId);
}
}

14
src/main/java/de/srsoftware/web4rail/actions/ActionList.java

@ -93,6 +93,20 @@ public class ActionList extends Action implements Iterable<Action>{ @@ -93,6 +93,20 @@ public class ActionList extends Action implements Iterable<Action>{
return true;
}
public Integer getSpeed(Context context) {
Integer speed = null;
for (Action action : this) {
if (action instanceof SetSpeed) {
speed = ((SetSpeed)action).getSpeed();
}
if (action instanceof ActionList) {
Integer listSpeed = ((ActionList)action).getSpeed(context);
if (isSet(listSpeed)) speed = listSpeed;
}
}
return speed;
}
@Override
public Iterator<Action> iterator() {
return actions.iterator();

8
src/main/java/de/srsoftware/web4rail/actions/ConditionalAction.java

@ -34,6 +34,14 @@ public class ConditionalAction extends ActionList { @@ -34,6 +34,14 @@ public class ConditionalAction extends ActionList {
return super.fire(context.clone()); // actions, that happen within the conditional action list must not modify the global context.
}
@Override
public Integer getSpeed(Context context) {
for (Condition condition : conditions) {
if (!condition.fulfilledBy(context)) return null;
}
return super.getSpeed(context);
}
@Override
public JSONObject json() {
JSONObject json = super.json();

4
src/main/java/de/srsoftware/web4rail/actions/SetSpeed.java

@ -51,6 +51,10 @@ public class SetSpeed extends Action{ @@ -51,6 +51,10 @@ public class SetSpeed extends Action{
return super.properties(preForm, formInputs, postForm);
}
public int getSpeed() {
return speed;
}
@Override
public String toString() {
return t("Set speed to {} {}",speed,speedUnit);

46
src/main/java/de/srsoftware/web4rail/moving/Train.java

@ -174,6 +174,8 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -174,6 +174,8 @@ public class Train extends BaseClass implements Comparable<Train> {
return train.start();
case ACTION_STOP:
return train.stopNow();
case ACTION_TIMES:
return train.removeBrakeTimes();
case ACTION_TURN:
return train.turn();
case ACTION_UPDATE:
@ -237,6 +239,25 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -237,6 +239,25 @@ public class Train extends BaseClass implements Comparable<Train> {
return brakeId;
}
private Fieldset brakeTimes() {
Fieldset fieldset = new Fieldset(t("Brake time table"));
Table timeTable = new Table();
timeTable.addRow(t("forward"),t("backward"),t("Route"));
List<Route> routes = BaseClass.listElements(Route.class);
Collections.sort(routes, (r1,r2)->r1.name().compareTo(r2.name()));
String forwardId = brakeId(false);
String backwardId = brakeId(true);
for (Route route: routes) {
Integer forwardTime = route.brakeTime(forwardId);
Integer reverseTime = route.brakeTime(backwardId);
timeTable.addRow(isSet(forwardTime)?forwardTime+" ms":"-",isSet(reverseTime)?reverseTime+" ms":"-",route.name());
}
timeTable.addTo(fieldset);
this.button(t("Drop brake times"),Map.of(ACTION,ACTION_TIMES)).addTo(fieldset);
return fieldset;
}
private Tag carList() {
Tag locoProp = new Tag("li").content(t("Locomotives and cars")+":");
Tag carList = new Tag("ul").clazz("carlist");
@ -506,6 +527,11 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -506,6 +527,11 @@ public class Train extends BaseClass implements Comparable<Train> {
this.name = newName;
return this;
}
public Route nextRoute() {
return nextRoute;
}
public boolean nextRoutePrepared() {
return isSet(nextRoute) && nextRoute.state() == Route.State.PREPARED;
@ -518,7 +544,7 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -518,7 +544,7 @@ public class Train extends BaseClass implements Comparable<Train> {
@Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
Fieldset otherTrainProsps = new Fieldset(t("other train properties"));
Fieldset otherTrainProps = new Fieldset(t("other train properties"));
Tag propList = new Tag("ul").clazz("proplist");
@ -558,14 +584,15 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -558,14 +584,15 @@ public class Train extends BaseClass implements Comparable<Train> {
ul.addTo(li).addTo(propList);
}
propList.addTo(otherTrainProsps);
propList.addTo(otherTrainProps);
formInputs.add(t("Name"), new Input(NAME,name));
formInputs.add(t("Push-pull train"),new Checkbox(PUSH_PULL, t("Push-pull train"), pushPull));
formInputs.add(t("Tags"), new Input(TAGS,String.join(", ", tags)));
preForm.add(Locomotive.cockpit(this));
postForm.add(otherTrainProsps);
postForm.add(otherTrainProps);
postForm.add(brakeTimes());
return super.properties(preForm, formInputs, postForm);
}
@ -583,6 +610,12 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -583,6 +610,12 @@ public class Train extends BaseClass implements Comparable<Train> {
} else return t("autopilot not active.");
}
private Window removeBrakeTimes() {
List<Route> routes = BaseClass.listElements(Route.class);
for (Route route: routes) route.dropBraketimes(brakeId(false),brakeId(true));
return properties();
}
@Override
public void removeChild(BaseClass child) {
LOG.debug("{}.removeChild({})",this,child);
@ -715,7 +748,6 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -715,7 +748,6 @@ public class Train extends BaseClass implements Comparable<Train> {
public void setSpeed(int newSpeed) {
LOG.debug("{}.setSpeed({})",this,newSpeed);
if (speed == 0 && newSpeed > 0) Thread.dumpStack();
speed = Math.min(newSpeed,maxSpeed());
if (speed < 0) speed = 0;
cars.stream().filter(c -> c instanceof Locomotive).forEach(car -> ((Locomotive)car).setSpeed(speed));
@ -834,16 +866,12 @@ public class Train extends BaseClass implements Comparable<Train> { @@ -834,16 +866,12 @@ public class Train extends BaseClass implements Comparable<Train> {
public Object stopNow() {
quitAutopilot();
setSpeed(0);
if (isSet(nextRoute)) {
nextRoute.reset();
nextRoute = null;
}
if (isSet(route)) {
route.brakeCancel();
route.reset();
route = null;
}
setSpeed(0);
return properties();
}

Loading…
Cancel
Save