added CoupleTrain action,

improved Destination functions,
fixed bug in AddRemoveTag,
improved CarOrientation functions
This commit is contained in:
Stephan Richter
2021-01-16 19:33:59 +01:00
parent 0e6069a5a1
commit e00e6f8124
11 changed files with 205 additions and 33 deletions

View File

@@ -75,6 +75,11 @@ public class Route extends BaseClass {
private static final String ROUTE_START = "route_start";
private static final String ROUTE_SETUP = "route_setup";
public static final String DESTINATION_PREFIX = "@";
public static final char TURN_FLAG = '±';
public static final char FLAG_SEPARATOR = '+';
public static final char SHUNTING_FLAG = '¥';
private int startSpeed;
private static HashMap<Id, String> names = new HashMap<Id, String>(); // maps id to name. needed to keep names during plan.analyze()
@@ -508,7 +513,7 @@ public class Route extends BaseClass {
if (endBlock == train.destination()) {
String destTag = null;
for (String tag : train.tags()) {
if (tag.startsWith("@")) {
if (tag.startsWith(DESTINATION_PREFIX)) {
destTag = tag;
break;
}
@@ -517,8 +522,19 @@ public class Route extends BaseClass {
if (isSet(destTag)) {
String[] parts = destTag.split("@");
String destId = parts[1];
boolean turn = destId.endsWith("+turn");
if (turn) destId = destId.substring(0,destId.length()-5);
boolean turn = false;
for (int i=destId.length()-1; i>0; i--) {
switch (destId.charAt(i)) {
case FLAG_SEPARATOR:
destId = destId.substring(0,i);
i=0;
break;
case TURN_FLAG:
turn = true;
break;
}
}
if (destId.equals(endBlock.id().toString())) {
if (turn) train.turn();
train.removeTag(destTag);

View File

@@ -47,6 +47,7 @@ public abstract class Action extends BaseClass {
BrakeCancel.class,
BrakeStart.class,
ConditionalAction.class,
CoupleTrain.class,
DelayedAction.class,
DetermineTrainInBlock.class,
DisableEnableBlock.class,

View File

@@ -10,6 +10,7 @@ import org.json.JSONObject;
import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.Application;
import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Route;
import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.moving.Train;
import de.srsoftware.web4rail.tags.Checkbox;
@@ -20,8 +21,10 @@ import de.srsoftware.web4rail.tiles.Tile;
public class AddDestination extends Action {
private static final String TURN = "turn";
private static final String SHUNTING = "shunting";
private Block destination;
private boolean turnAtDestination;
private boolean shunting;
public AddDestination(BaseClass parent) {
super(parent);
@@ -39,9 +42,12 @@ public class AddDestination extends Action {
}
return true;
}
String dest = "@"+destination.id()+(turnAtDestination?"+turn":"");
String flags = "+";
if (turnAtDestination) flags += Route.TURN_FLAG;
if (shunting) flags += Route.SHUNTING_FLAG;
String dest = Route.DESTINATION_PREFIX+destination.id() + (flags.length()>1 ? flags : "");
for (String tag: train.tags()) {
if (tag.startsWith("@")) {
if (tag.startsWith(Route.DESTINATION_PREFIX)) {
train.removeTag(tag);
dest = tag+dest;
break;
@@ -56,12 +62,14 @@ public class AddDestination extends Action {
JSONObject json = super.json();
if (isSet(destination)) json.put(Train.DESTINATION,destination.id().toString());
if (turnAtDestination) json.put(TURN,true);
if (shunting) json.put(SHUNTING, true);
return json;
}
@Override
public Action load(JSONObject json) {
if (json.has(TURN)) turnAtDestination = json.getBoolean(TURN);
if (json.has(SHUNTING)) shunting = json.getBoolean(SHUNTING);
if (json.has(Train.DESTINATION)) {
Id blockId = new Id(json.getString(Train.DESTINATION));
destination = BaseClass.get(blockId);
@@ -89,6 +97,7 @@ public class AddDestination extends Action {
button(t("Clear destinations"),Map.of(ACTION,ACTION_UPDATE,Train.DESTINATION,"0")).addTo(span);
formInputs.add(t("Destination")+": "+(isNull(destination) ? t("Clear destinations") : destination),span);
formInputs.add(t("Turn at destination"),new Checkbox(TURN, t("Turn"), turnAtDestination));
formInputs.add(t("Shunting"),new Checkbox(SHUNTING, t("Shunting"), shunting));
return super.properties(preForm, formInputs, postForm);
}
@@ -113,6 +122,7 @@ public class AddDestination extends Action {
}
}
turnAtDestination = "on".equals(params.get(TURN));
shunting = "on".equals(params.get(SHUNTING));
return context().properties();
}
}

View File

@@ -21,15 +21,15 @@ public class AddRemoveTag extends Action{
}
private String tag = "test";
private boolean add = true;
private boolean remove = false;
@Override
public boolean fire(Context context) {
if (isNull(context.train())) return false;
if (add) {
context.train().tags().add(tag);
if (remove) {
context.train().removeTag(tag);
} else {
context.train().tags().remove(tag);
context.train().addTag(tag);
}
return true;
}
@@ -38,13 +38,15 @@ public class AddRemoveTag extends Action{
public JSONObject json() {
JSONObject json = super.json();
json.put(TAG, tag);
if (remove) json.put(ACTION_DROP, true);
return json;
}
@Override
public Action load(JSONObject json) {
super.load(json);
tag = json.getString(TAG);
if (json.has(TAG)) tag = json.getString(TAG);
if (json.has(ACTION_DROP)) remove = json.getBoolean(ACTION_DROP);
return this;
}
@@ -52,21 +54,21 @@ public class AddRemoveTag extends Action{
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
formInputs.add(t("Tag"),new Input(TAG, tag));
Tag div = new Tag("div");
new Radio(TYPE, ACTION_ADD, t("add"), add).addTo(div);
new Radio(TYPE, ACTION_DROP, t("delete"), !add).addTo(div);
new Radio(TYPE, ACTION_ADD, t("add"), !remove).addTo(div);
new Radio(TYPE, ACTION_DROP, t("delete"), remove).addTo(div);
formInputs.add(t("Action"),div);
return super.properties(preForm, formInputs, postForm);
}
@Override
public String toString() {
return add ? t("Add tag \"{}\" to train",tag) : t("Remove tag \"{}\" from train",tag);
return remove ? t("Remove tag \"{}\" from train",tag) : t("Add tag \"{}\" to train",tag);
}
@Override
protected Object update(HashMap<String, String> params) {
tag = params.get(TAG);
add = ACTION_ADD.equals(params.get(TYPE));
remove = ACTION_DROP.equals(params.get(TYPE));
return super.update(params);
}
}

View File

@@ -0,0 +1,71 @@
package de.srsoftware.web4rail.actions;
import java.util.HashMap;
import java.util.List;
import org.json.JSONObject;
import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.moving.Train;
import de.srsoftware.web4rail.tags.Checkbox;
import de.srsoftware.web4rail.tags.Fieldset;
import de.srsoftware.web4rail.tiles.Block;
public class CoupleTrain extends Action {
private static final String LAST = "last";
private static final String SWAP = "swap";
private boolean last = false;
private boolean swap = false;
public CoupleTrain(BaseClass parent) {
super(parent);
}
@Override
public boolean fire(Context context) {
Train train = context.train();
if (isNull(train)) return false;
Block block = train.currentBlock();
if (isNull(block)) return false;
Train parkingTrain = block.parkedTrains(last);
if (isNull(parkingTrain)) return false;
train.coupleWith(parkingTrain,swap);
return true;
}
@Override
public JSONObject json() {
JSONObject json = super.json();
if (last) json.put(LAST, last);
if (swap) json.put(SWAP, swap);
return json;
}
@Override
public Action load(JSONObject json) {
if (json.has(LAST)) last = json.getBoolean(LAST);
if (json.has(SWAP)) swap = json.getBoolean(SWAP);
return super.load(json);
}
@Override
public String toString() {
return last ? t("Couple last parked train") : t("Couple first parked train");
}
@Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
formInputs.add(t("Couple"),new Checkbox(LAST, t("last parked train"), last));
formInputs.add(t("Swap order"),new Checkbox(SWAP, t("Swap order of trains"), swap));
return super.properties(preForm, formInputs, postForm);
}
@Override
protected Object update(HashMap<String, String> params) {
last = "on".equals(params.get(LAST));
swap = "on".equals(params.get(SWAP));
return super.update(params);
}
}

View File

@@ -9,25 +9,44 @@ import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.moving.Car;
import de.srsoftware.web4rail.moving.Train;
import de.srsoftware.web4rail.tags.Fieldset;
import de.srsoftware.web4rail.tags.Input;
import de.srsoftware.web4rail.tags.Radio;
public class CarOrientation extends Condition {
private static final String ORIENTATION = "orientation";
private static final String CAR = "car";
private static final String POSITION = "position";
private boolean orientation = Car.FORWARD;
private int position = 1;
private Car car;
@Override
public boolean fulfilledBy(Context context) {
Car car = this.car;
if (isNull(car)) {
Train train = context.train();
if (position == 0 || isNull(train)) return false;
List<Car> cars = train.cars();
if (position > 0) {
if (position>cars.size()) return false;
car = cars.get(position-1);
} else {
if (-position>cars.size()) return false;
car = cars.get(cars.size()+position);
}
}
if (isNull(car)) return false;
return inverted ? car.orientation() != orientation : car.orientation() == orientation;
}
@Override
public JSONObject json() {
JSONObject json = super.json().put(ORIENTATION, orientation);
if (isSet(car)) json.put(CAR, car.id().toString());
if (isSet(car)) json.put(CAR, car.id().toString());
json.put(POSITION,position);
return json;
}
@@ -35,23 +54,26 @@ public class CarOrientation extends Condition {
super.load(json);
if (json.has(CAR)) car = BaseClass.get(new Id(json.getString(CAR)));
if (json.has(ORIENTATION)) orientation = json.getBoolean(ORIENTATION);
if (json.has(POSITION)) position = json.getInt(POSITION);
return this;
}
@Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
formInputs.add(t("Select car"),Car.selector(car, null));
formInputs.add(t("Select car"),Car.selector(isSet(car) ? car : t("Car of train"), null));
formInputs.add(t("If car of train: inspect car number"),new Input(POSITION, position).numeric().addTo(new Tag("span")).content(NBSP+"("+t("Use negative number to count from end.")+")"));
Tag radioGroup = new Tag("span");
new Radio(ORIENTATION, "f", t("forward"), orientation).addTo(radioGroup);
new Radio(ORIENTATION, "r", t("revers"), !orientation).addTo(radioGroup);
return super.properties(preForm, formInputs, postForm);
}
@Override
public String toString() {
return t("{} is oriented {}",car,inverted ? t("backward") : t("forward"));
String c = isSet(car) ? car.toString() : t("Car {} of train",position);
return t("{} is oriented {}",c,inverted ? t("backward") : t("forward"));
}
@Override
@@ -67,6 +89,7 @@ public class CarOrientation extends Condition {
}
String carId = params.get(Car.class.getSimpleName());
if (isSet(carId)) car = BaseClass.get(new Id(carId));
if (params.containsKey(POSITION)) position = Integer.parseInt(params.get(POSITION));
return super.update(params);
}
}

View File

@@ -247,6 +247,7 @@ public class Car extends BaseClass implements Comparable<Car>{
new Input(MAX_SPEED_REVERSE, maxSpeedReverse).numeric().addTo(new Tag("p")).content(NBSP+speedUnit+NBSP+t("backward")).addTo(div);
formInputs.add(t("Maximum Speed"),div);
if (train != null) formInputs.add(t("Train"), train.link());
formInputs.add(t("Current orientation"),new Tag("span").content(orientation ? t("forward") : t("reverse")));
return super.properties(preForm,formInputs,postForm);
}
@@ -309,10 +310,12 @@ public class Car extends BaseClass implements Comparable<Car>{
return t("Reversed {}.",this);
}
public static Select selector(Car preselected,Collection<Car> exclude) {
public static Select selector(Object preset,Collection<Car> exclude) {
Car preselected = preset instanceof Car ? (Car) preset : null;
String firstEntry = preset instanceof String ? (String) preset : t("unset");
if (isNull(exclude)) exclude = new Vector<Car>();
Select select = new Select(Car.class.getSimpleName());
new Tag("option").attr("value","0").content(t("unset")).addTo(select);
new Tag("option").attr("value","0").content(firstEntry).addTo(select);
List<Car> cars = BaseClass.listElements(Car.class);
cars.sort((c1,c2) -> {
if (isSet(c1.stockId)) return c1.stockId.compareTo(c2.stockId);

View File

@@ -318,6 +318,16 @@ public class Train extends BaseClass implements Comparable<Train> {
return name().compareTo(o.toString());
}
public void coupleWith(Train parkingTrain,boolean swap) {
if (isSet(direction) && isSet(parkingTrain.direction) && parkingTrain.direction != direction) parkingTrain.turn();
if (swap) {
Vector<Car> dummy = new Vector<Car>(parkingTrain.cars);
dummy.addAll(cars);
cars = dummy;
} else cars.addAll(parkingTrain.cars);
parkingTrain.remove();
}
private static Object create(HashMap<String, String> params, Plan plan) {
String locoId = params.get(Train.LOCO_ID);
if (isNull(locoId)) return t("Need loco id to create new train!");
@@ -336,18 +346,30 @@ public class Train extends BaseClass implements Comparable<Train> {
public Block destination() {
if (isNull(destination)) {
String destTag = null;
String destId = null;
for (String tag : tags) {
if (tag.startsWith("@")) {
destTag = tag;
if (tag.startsWith(Route.DESTINATION_PREFIX)) {
destId = tag;
break;
}
}
if (isSet(destTag)) {
String[] parts = destTag.split("@");
destTag = parts[1];
if (destTag.endsWith("+turn")) destTag = destTag.substring(0,destTag.length()-5);
BaseClass object = BaseClass.get(new Id(destTag));
if (isSet(destId)) {
String[] parts = destId.split(Route.DESTINATION_PREFIX);
destId = parts[1];
for (int i=destId.length()-1; i>0; i--) {
switch (destId.charAt(i)) {
case Route.FLAG_SEPARATOR:
destId = destId.substring(0,i);
i=0;
break;
case Route.SHUNTING_FLAG:
shunting = true;
break;
}
}
BaseClass object = BaseClass.get(new Id(destId));
if (object instanceof Block) destination = (Block) object;
}
}
@@ -876,12 +898,17 @@ public class Train extends BaseClass implements Comparable<Train> {
Car car = cars.remove(position);
LOG.debug("Moving {} from {} to {}",car,this,remaining);
remaining.add(car);
if (isNull(remaining.name)) {
remaining.name = car.name();
} else if (remaining.name.length()+car.name().length()<20){
remaining.name += ", "+car.name();
}
} else {
LOG.debug("Skipping {}",cars.get(i));
}
}
if (remaining.cars.isEmpty()) return false;
remaining.name = this.name;
remaining.direction = this.direction;
this.name = null;
currentBlock.add(remaining);
remaining.currentBlock = currentBlock;

View File

@@ -213,7 +213,7 @@ public abstract class Block extends StretchableTile{
public Range getWaitTime(Train train,Direction dir) {
for (WaitTime wt : waitTimes) {
if (train.tags().contains(wt.tag)) {
LOG.info(t("{} using rule for \"{}\".",train,wt.tag));
LOG.info(t("{} @ {} using rule for \"{}\".",train,this,wt.tag));
return wt.get(train.direction());
}
}
@@ -308,6 +308,12 @@ public abstract class Block extends StretchableTile{
return fieldset;
}
public Train parkedTrains(boolean last) {
if (parkedTrains.isEmpty()) return null;
return last ? parkedTrains.lastElement() : parkedTrains.firstElement();
}
@Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
formInputs.add(t("Name"),new Input(NAME, name));
@@ -372,7 +378,7 @@ public abstract class Block extends StretchableTile{
Vector<String> trainNames = new Vector<String>();
if (isSet(train)) trainNames.add(train.directedName());
for (Train t:parkedTrains) {
if (isSet(t)) trainNames.add(t.name());
if (isSet(t)) trainNames.add(t.directedName());
}
if (!trainNames.isEmpty())replacements.put("%text%",String.join(" | ", trainNames));
Tag tag = super.tag(replacements);