vroious improvements

This commit is contained in:
Stephan Richter
2021-02-12 18:04:28 +01:00
parent 2973bd1432
commit c3242cddcb
10 changed files with 88 additions and 47 deletions

View File

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

View File

@@ -32,8 +32,10 @@
<logger name="de.srsoftware.web4rail" level="INFO" /> <logger name="de.srsoftware.web4rail" level="INFO" />
<logger name="de.srsoftware.web4rail.Application" level="DEBUG" /> <logger name="de.srsoftware.web4rail.Application" level="DEBUG" />
<logger name="de.srsoftware.web4rail.Route" level="DEBUG" /> <logger name="de.srsoftware.web4rail.Route" level="DEBUG" />
<logger name="de.srsoftware.web4rail.actions.Action" level="DEBUG" />
<logger name="de.srsoftware.web4rail.actions.ActionList" level="DEBUG" /> <logger name="de.srsoftware.web4rail.actions.ActionList" level="DEBUG" />
<logger name="de.srsoftware.web4rail.moving.Train" level="DEBUG" /> <logger name="de.srsoftware.web4rail.moving.Train" level="DEBUG" />
<logger name="de.srsoftware.web4rail.tiles.Contact" level="DEBUG" /> <logger name="de.srsoftware.web4rail.tiles.Contact" level="DEBUG" />
<logger name="de.srsoftware.web4rail.tiles.Block" level="DEBUG" />
</configuration> </configuration>

View File

@@ -89,7 +89,7 @@ public class Route extends BaseClass {
private String brakeId; private String brakeId;
private long estimatedDistance; // Unit: s*km/h "km/h-Sekunden" private long estimatedDistance; // Unit: s*km/h "km/h-Sekunden"
private int startSpeed,endSpeed; private int startSpeed,endSpeed;
private boolean aborted,modified; private boolean aborted,modified,finished;
public BrakeProcessor(Route route, Train train) { public BrakeProcessor(Route route, Train train) {
this.train = train; this.train = train;
@@ -97,14 +97,14 @@ public class Route extends BaseClass {
aborted = false; aborted = false;
modified = false; modified = false;
estimatedDistance = 0; finished = false;
brakeId = train.brakeId(); brakeId = train.brakeId();
startSpeed = train.speed; startSpeed = train.speed;
endSpeed = defaultEndSpeed; endSpeed = defaultEndSpeed;
timeStep = brakeTimes.get(brakeId); timeStep = brakeTimes.get(brakeId);
if (isNull(timeStep)) timeStep = 100; // if no brake time is available for this train if (isNull(timeStep)) timeStep = 256; // if no brake time is available for this train
Application.threadPool.execute(this); Application.threadPool.execute(this);
} }
@@ -123,58 +123,84 @@ public class Route extends BaseClass {
return dist; return dist;
} }
private void checkNextRoute() {
Route nextRoute = train.nextRoute();
if (isSet(nextRoute) && nextRoute.state == Route.State.PREPARED) { // auf Startgeschwindigkeit der Nachfolgeroute bremsen
Integer nextRouteStartSpeed = nextRoute.startSpeed();
if (isSet(nextRouteStartSpeed)) {
LOG.debug("updating target velocity from {} to {}!",endSpeed,nextRouteStartSpeed);
endSpeed = nextRouteStartSpeed;
modified = true;
if (endSpeed > train.speed) train.setSpeed(endSpeed);
}
}
}
/** /**
* This is called from route.finish when train came to stop * This is called from route.finish when train came to stop
*/ */
public void finish() { public void finish() {
LOG.debug("BrakeProcessor.finish()"); LOG.debug("BrakeProcessor.finish()");
finished = true;
if (aborted || modified) return; if (aborted || modified) return;
increaseDistance(); increaseDistance();
train.setSpeed(0); train.setSpeed(0);
LOG.debug("Estimated distance: {}",estimatedDistance); LOG.debug("Estimated distance: {}",estimatedDistance);
if (startSpeed <= endSpeed) return; if (startSpeed <= endSpeed) return;
if (timeStep<0) timeStep = 100;
Integer newTimeStep = timeStep; Integer newTimeStep = timeStep;
while (calcDistance(newTimeStep) < estimatedDistance) newTimeStep += (1+newTimeStep/8); // zu schnell gebremst: pasue verlängern long calculated;
while (calcDistance(newTimeStep) > estimatedDistance) newTimeStep -= 1+(newTimeStep/16); // zu langsam gebremst: pasue verkürzen int step = 32*newTimeStep;
for (int i=0; i<20; i++) {
step = step/2;
if (step<1) step = 1;
calculated = calcDistance(newTimeStep);
LOG.debug("Calculated distance for step = {} ms: {}",newTimeStep,calculated);
LOG.debug("Update step: {}",step);
newTimeStep = newTimeStep + (calculated > estimatedDistance ? -step : step);
}
if (newTimeStep != timeStep) { if (!newTimeStep.equals(timeStep)) {
route.brakeTimes.put(brakeId,newTimeStep); route.brakeTimes.put(brakeId,newTimeStep);
calculated = calcDistance(newTimeStep);
LOG.debug("Corrected brake timestep for {} @ {} from {} to {} ms.",train,route,timeStep,newTimeStep); LOG.debug("Corrected brake timestep for {} @ {} from {} to {} ms.",train,route,timeStep,newTimeStep);
LOG.debug("Differemce from estimated distance: {} ({}%)",estimatedDistance-calculated,100*(estimatedDistance-calculated)/(float)estimatedDistance);
} }
} }
private void increaseDistance(){ private void increaseDistance(){
long tick = timestamp(); long tick = timestamp();
estimatedDistance += train.speed * (tick-latestTick); estimatedDistance += train.speed * (5+tick-latestTick);
latestTick = tick; latestTick = tick;
} }
@Override @Override
public void run() { public void run() {
LOG.debug("started BrakeProcessor ({} → {}) for {} with timestep = {} ms.",train.speed,endSpeed,train,timeStep); LOG.debug("started BrakeProcessor ({} → {}) for {} with timestep = {} ms.",train.speed,endSpeed,train,timeStep);
estimatedDistance = 0;
latestTick = timestamp(); latestTick = timestamp();
while (train.speed > endSpeed) { while (train.speed > endSpeed) {
LOG.debug("BrakeProcessor({}) setting Speed of {}.",route,train); if (finished) return;
increaseDistance(); increaseDistance();
LOG.debug("BrakeProcessor({}) setting Speed of {}.",route,train);
train.setSpeed(Math.max(train.speed - SPEED_STEP,endSpeed)); train.setSpeed(Math.max(train.speed - SPEED_STEP,endSpeed));
if (!modified) checkNextRoute();
try { try {
sleep(timeStep); sleep(timeStep);
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.warn("BrakeProcessor interrupted!", e); LOG.warn("BrakeProcessor interrupted!", e);
} }
}
Route nextRoute = train.nextRoute();
if (!modified && isSet(nextRoute) && nextRoute.state == Route.State.PREPARED) { // auf Startgeschwindigkeit der Nachfolgeroute bremsen while (!finished && !aborted && !modified) {
Integer nrsp = nextRoute.startSpeed(); try {
if (isSet(nrsp)) { sleep(1000);
LOG.debug("updating target velocity from {} to {}!",endSpeed,nrsp); } catch (InterruptedException e) {
endSpeed = nrsp; LOG.warn("BrakeProcessor interrupted!", e);
modified = true; }
} checkNextRoute();
}
} }
if (endSpeed > train.speed) train.setSpeed(endSpeed);
} }
public void setEndSpeed(Integer newEndSpeed) { public void setEndSpeed(Integer newEndSpeed) {
@@ -511,11 +537,11 @@ public class Route extends BaseClass {
tile.unset(this); tile.unset(this);
} catch (IllegalArgumentException e) {} } catch (IllegalArgumentException e) {}
Tile lastTile = path.lastElement(); /* Tile lastTile = path.lastElement();
if (lastTile instanceof Contact) { if (lastTile instanceof Contact) {
lastTile.setTrain(null); lastTile.setTrain(null);
if (isSet(train)) train.removeChild(lastTile); if (isSet(train)) train.removeChild(lastTile);
} }*/
} }
private String generateName() { private String generateName() {
@@ -780,7 +806,8 @@ public class Route extends BaseClass {
private void moveTrainToEndBlock() { private void moveTrainToEndBlock() {
if (isNull(train)) return; if (isNull(train)) return;
LOG.debug("{}.moveTrainToEndBlock()",this);
train.set(endBlock); train.set(endBlock);
train.heading(endDirection); train.heading(endDirection);
@@ -788,7 +815,9 @@ public class Route extends BaseClass {
train.destination(null); // unset old destination train.destination(null); // unset old destination
String destTag = train.destinationTag(); String destTag = train.destinationTag();
if (isSet(destTag)) { if (isSet(destTag)) {
LOG.debug("destination tag: {}",destTag);
String[] parts = destTag.split(Train.DESTINATION_PREFIX); String[] parts = destTag.split(Train.DESTINATION_PREFIX);
for (int i=0; i<parts.length;i++) LOG.debug(" part {}: {}",i+1,parts[i]);
String destId = parts[1]; String destId = parts[1];
boolean turn = false; boolean turn = false;
@@ -1014,6 +1043,7 @@ public class Route extends BaseClass {
} }
public Integer startSpeed() { public Integer startSpeed() {
LOG.debug("{}.startSpeed()",this);
ActionList startActions = triggeredActions.get(ROUTE_START); ActionList startActions = triggeredActions.get(ROUTE_START);
Context context = new Context(this); Context context = new Context(this);
return isSet(startActions) ? startActions.getSpeed(context) : null; return isSet(startActions) ? startActions.getSpeed(context) : null;

View File

@@ -81,12 +81,12 @@ public class ActionList extends Action implements Iterable<Action>{
} }
public boolean fire(Context context) { public boolean fire(Context context) {
LOG.debug("{}.fire({})",this,context);
if (context.invalidated()) { if (context.invalidated()) {
LOG.debug("Context has been invalidated, aborting {}",this); LOG.debug("Context has been invalidated, aborting {}",this);
return false; return false;
} }
if (!isEmpty()) LOG.debug(t("Firing {}"),actions);
if (!isEmpty()) LOG.debug("{}.fire({})",this,context);
for (Action action : actions) { for (Action action : actions) {
if (!action.fire(context)) return false; if (!action.fire(context)) return false;
} }
@@ -94,12 +94,11 @@ public class ActionList extends Action implements Iterable<Action>{
} }
public Integer getSpeed(Context context) { public Integer getSpeed(Context context) {
LOG.debug("{}.getSpeed({})",this,context);
Integer speed = null; Integer speed = null;
for (Action action : this) { for (Action action : this) {
if (action instanceof SetSpeed) { if (action instanceof SetSpeed) speed = ((SetSpeed)action).getSpeed();
speed = ((SetSpeed)action).getSpeed(); if (isNull(speed) && action instanceof ActionList) {
}
if (action instanceof ActionList) {
Integer listSpeed = ((ActionList)action).getSpeed(context); Integer listSpeed = ((ActionList)action).getSpeed(context);
if (isSet(listSpeed)) speed = listSpeed; if (isSet(listSpeed)) speed = listSpeed;
} }

View File

@@ -34,8 +34,9 @@ public class DelayedAction extends ActionList {
Application.threadPool.execute(new Thread() { Application.threadPool.execute(new Thread() {
public void run() { public void run() {
try { try {
Thread.sleep(min_delay + (min_delay < max_delay ? random.nextInt(max_delay - min_delay) : 0)); int delay = min_delay + (min_delay < max_delay ? random.nextInt(max_delay - min_delay) : 0);
LOG.debug("{} ms passed by, firing actions:",min_delay); Thread.sleep(delay);
LOG.debug("{} ms passed by, firing actions:",delay);
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.warn("Interrupted Exception thrown while waiting:",e); LOG.warn("Interrupted Exception thrown while waiting:",e);
} }

View File

@@ -4,6 +4,7 @@ import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Range; import de.srsoftware.web4rail.Range;
import de.srsoftware.web4rail.Route; import de.srsoftware.web4rail.Route;
import de.srsoftware.web4rail.moving.Train; import de.srsoftware.web4rail.moving.Train;
import de.srsoftware.web4rail.tiles.Block;
public class PreserveRoute extends Action { public class PreserveRoute extends Action {
@@ -21,11 +22,12 @@ public class PreserveRoute extends Action {
// These are NOT errors: // These are NOT errors:
if (!train.usesAutopilot()) return true; // do not reserve routes, when not in auto-mode if (!train.usesAutopilot()) return true; // do not reserve routes, when not in auto-mode
if (train.destination() == route.endBlock()) return true; // do not reserve routes, when destination has been reached Block endBlock = route.endBlock();
if (train.destination() == endBlock) return true; // do not reserve routes, when destination has been reached
Range waitTime = route.endBlock().getWaitTime(train,route.endDirection); Range waitTime = endBlock.getWaitTime(train,route.endDirection);
if (waitTime.max > 0) { if (waitTime.max > 0) {
LOG.debug("Not preserving route, as train needs to stop in following block!"); LOG.debug("Not preserving route, as train needs to stop for {} ms at {}!",waitTime,endBlock);
return true; // train is expected to wait in next block. return true; // train is expected to wait in next block.
} }

View File

@@ -2,6 +2,7 @@ package de.srsoftware.web4rail.actions;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.json.JSONObject; import org.json.JSONObject;
@@ -41,7 +42,7 @@ public class TriggerContact extends Action {
@Override @Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) { protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
formInputs.add(t("Select contact"),Contact.selector(contact)); formInputs.add(t("Select contact")+": "+(isNull(contact) ? t("unset") : contact),button(t("Select from plan"),Map.of(ACTION,ACTION_UPDATE,ASSIGN,CONTACT)));
return super.properties(preForm, formInputs, postForm); return super.properties(preForm, formInputs, postForm);
} }

View File

@@ -93,6 +93,7 @@ public class Train extends BaseClass implements Comparable<Train> {
private static final String SHUNTING = "shunting"; private static final String SHUNTING = "shunting";
private boolean shunting = false; private boolean shunting = false;
private boolean reserving; // used to prevent recursive calls of reserveNext
private class Autopilot extends Thread{ private class Autopilot extends Thread{
boolean stop = false; boolean stop = false;
@@ -109,8 +110,8 @@ public class Train extends BaseClass implements Comparable<Train> {
if (stop) return; if (stop) return;
if (isNull(route)) { // may have been set by start action in between if (isNull(route)) { // may have been set by start action in between
Object o = Train.this.start(); Object o = Train.this.start();
LOG.debug("{}.start called, route now is {}",Train.this,route);
if (isSet(route)) { if (isSet(route)) {
LOG.debug("{}.start called, route now is {}",Train.this,route);
if (o instanceof String) plan.stream((String)o); if (o instanceof String) plan.stream((String)o);
//if (isSet(destination)) Thread.sleep(1000); // limit load on PathFinder //if (isSet(destination)) Thread.sleep(1000); // limit load on PathFinder
} else waitTime = 1000; // limit load on PathFinder } else waitTime = 1000; // limit load on PathFinder
@@ -383,6 +384,7 @@ public class Train extends BaseClass implements Comparable<Train> {
if (isNull(destination)) { if (isNull(destination)) {
String destTag = destinationTag(); String destTag = destinationTag();
if (isSet(destTag)) { if (isSet(destTag)) {
destTag = destTag.split(DESTINATION_PREFIX)[1];
for (int i=destTag.length()-1; i>0; i--) { for (int i=destTag.length()-1; i>0; i--) {
switch (destTag.charAt(i)) { switch (destTag.charAt(i)) {
case FLAG_SEPARATOR: case FLAG_SEPARATOR:
@@ -409,10 +411,7 @@ public class Train extends BaseClass implements Comparable<Train> {
public String destinationTag() { public String destinationTag() {
for (String tag : tags()) { // check, if endBlock is in train's destinations for (String tag : tags()) { // check, if endBlock is in train's destinations
if (tag.startsWith(DESTINATION_PREFIX)) { if (tag.startsWith(DESTINATION_PREFIX)) return tag;
String[] parts = tag.split(DESTINATION_PREFIX);
return parts[1];
}
} }
return null; return null;
} }
@@ -751,15 +750,17 @@ public class Train extends BaseClass implements Comparable<Train> {
return tags().iterator(); return tags().iterator();
} }
public void reserveNext() { public void reserveNext() {
if (reserving) return;
LOG.debug("{}.reserveNext()",this); LOG.debug("{}.reserveNext()",this);
Context context = new Context(this).route(route).block(route.endBlock()).direction(route.endDirection); Context context = new Context(this).route(route).block(route.endBlock()).direction(route.endDirection);
Route newRoute = PathFinder.chooseRoute(context); Route newRoute = PathFinder.chooseRoute(context);
if (isNull(newRoute)) { if (isNull(newRoute)) {
LOG.debug("{}.reserveNext() found no available route!",this); LOG.debug("{}.reserveNext() found no available route!",this);
return; return;
} }
reserving = true;
LOG.debug("next route: {}",newRoute);
newRoute.set(context); newRoute.set(context);
boolean error = !newRoute.lockIgnoring(route); boolean error = !newRoute.lockIgnoring(route);
error = error || !newRoute.prepare(); error = error || !newRoute.prepare();
@@ -772,6 +773,7 @@ public class Train extends BaseClass implements Comparable<Train> {
nextRoute = newRoute; nextRoute = newRoute;
LOG.debug("prepared next route: {}",nextRoute); LOG.debug("prepared next route: {}",nextRoute);
} }
reserving = false;
} }
/** /**
@@ -808,8 +810,6 @@ public class Train extends BaseClass implements Comparable<Train> {
return this; return this;
} }
public static void saveAll(String filename) throws IOException { public static void saveAll(String filename) throws IOException {
BufferedWriter file = new BufferedWriter(new FileWriter(filename)); BufferedWriter file = new BufferedWriter(new FileWriter(filename));
for (Train train:BaseClass.listElements(Train.class)) file.write(train.json()+"\n"); for (Train train:BaseClass.listElements(Train.class)) file.write(train.json()+"\n");

View File

@@ -12,6 +12,8 @@ import java.util.Vector;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.srsoftware.tools.Tag; import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.BaseClass; import de.srsoftware.web4rail.BaseClass;
@@ -33,6 +35,7 @@ import de.srsoftware.web4rail.tags.Window;
* *
*/ */
public abstract class Block extends StretchableTile{ public abstract class Block extends StretchableTile{
protected static Logger LOG = LoggerFactory.getLogger(Block.class);
private static final String ALLOW_TURN = "allowTurn"; private static final String ALLOW_TURN = "allowTurn";
private static final String NAME = "name"; private static final String NAME = "name";
private static final String NO_TAG = "[default]"; private static final String NO_TAG = "[default]";
@@ -211,12 +214,15 @@ public abstract class Block extends StretchableTile{
} }
public Range getWaitTime(Train train,Direction dir) { public Range getWaitTime(Train train,Direction dir) {
LOG.debug("{}.getWaitTime({},{})",this,train,dir);
for (WaitTime wt : waitTimes) { for (WaitTime wt : waitTimes) {
LOG.debug("examinig {}",wt);
if (train.tags().contains(wt.tag)) { if (train.tags().contains(wt.tag)) {
LOG.info(t("{} @ {} using rule for \"{}\".",train,this,wt.tag)); LOG.info(t("{} @ {} using rule for \"{}\".",train,this,wt.tag));
return wt.get(train.direction()); return wt.get(dir);
} }
} }
LOG.info(t("{} @ {} using rule for \"[default]\".",train,this));
return getWaitTime(NO_TAG).get(dir); return getWaitTime(NO_TAG).get(dir);
} }

View File

@@ -371,7 +371,7 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
} }
public Tile setTrain(Train newTrain) { public Tile setTrain(Train newTrain) {
Route.LOG.debug("{}.setTrain({})",this,newTrain); LOG.debug("{}.setTrain({})",this,newTrain);
if (newTrain == train) return this; // nothing to update if (newTrain == train) return this; // nothing to update
this.train = newTrain; this.train = newTrain;
return plan.place(this); return plan.place(this);