working on train movements
This commit is contained in:
@@ -174,7 +174,7 @@ svg.left rect,
|
||||
svg.right rect,
|
||||
svg.straight .left,
|
||||
svg.straight .right{
|
||||
fill: white !important;
|
||||
fill: #ddd !important;
|
||||
}
|
||||
|
||||
.occupied .block{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const ADD = 'add';
|
||||
const MOVE = 'move';
|
||||
const SQUARE = 30;
|
||||
const BODY = '#plan';
|
||||
const BODY = 'body';
|
||||
const DIV = 'DIV';
|
||||
const SVG = 'svg';
|
||||
const PLAN = 'plan';
|
||||
const PLAN = '#plan';
|
||||
const POST = 'POST';
|
||||
var selected = null;
|
||||
var mode = null;
|
||||
@@ -23,23 +23,6 @@ function addTile(x,y){
|
||||
return request({action:mode,tile:selected.id,x:x,y:y});
|
||||
}
|
||||
|
||||
function bodyClick(ev){
|
||||
//console.log('bodyClick:',ev);
|
||||
var x = Math.floor(ev.clientX/SQUARE);
|
||||
var y = Math.floor(ev.clientY/SQUARE);
|
||||
|
||||
switch (mode){
|
||||
case undefined:
|
||||
case null:
|
||||
return clickTile(x,y);
|
||||
case ADD:
|
||||
return addTile(x,y);
|
||||
case MOVE:
|
||||
return moveTile(x,y);
|
||||
}
|
||||
console.log('unknown action "'+mode+'" @ ('+ev.clientX+','+ev.clientY+')');
|
||||
}
|
||||
|
||||
function clickTile(x,y){
|
||||
console.log("clickTile:",x,y);
|
||||
if ($('#tile-'+x+'-'+y).length > 0) request({action:'click',x:x,y:y});
|
||||
@@ -113,10 +96,27 @@ function openRoute(id){
|
||||
function place(data){
|
||||
var tag = $(data);
|
||||
$('#'+tag.attr('id')).remove();
|
||||
$(BODY).append(tag);
|
||||
$(PLAN).append(tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
function planClick(ev){
|
||||
//console.log('bodyClick:',ev);
|
||||
var x = Math.floor(ev.clientX/SQUARE);
|
||||
var y = Math.floor(ev.clientY/SQUARE);
|
||||
|
||||
switch (mode){
|
||||
case undefined:
|
||||
case null:
|
||||
return clickTile(x,y);
|
||||
case ADD:
|
||||
return addTile(x,y);
|
||||
case MOVE:
|
||||
return moveTile(x,y);
|
||||
}
|
||||
console.log('unknown action "'+mode+'" @ ('+ev.clientX+','+ev.clientY+')');
|
||||
}
|
||||
|
||||
function remove(id){
|
||||
$('#'+id).remove();
|
||||
return false;
|
||||
@@ -124,14 +124,15 @@ function remove(id){
|
||||
|
||||
function request(data){
|
||||
$.ajax({
|
||||
url : PLAN,
|
||||
url : 'plan',
|
||||
method : POST,
|
||||
data : data,
|
||||
success: function(resp){
|
||||
closeWindows();
|
||||
if (resp.startsWith('<svg')){
|
||||
$('#plan').append($(resp));
|
||||
$(PLAN).append($(resp));
|
||||
} else if (resp.startsWith('<')) {
|
||||
console.log("appending to body: "+resp.substring(0,10));
|
||||
$(BODY).append($(resp));
|
||||
} else {
|
||||
addMessage(resp);
|
||||
@@ -163,11 +164,10 @@ function stream(ev){
|
||||
|
||||
window.onload = function () {
|
||||
var isDragging = false;
|
||||
console.log($(BODY).each(function(){console.log(this)}));
|
||||
$('.menu > div').click(closeMenu);
|
||||
$('.menu .addtile .list svg').click(enableAdding);
|
||||
$('.menu .move .list div').click(enableMove);
|
||||
$('.menu .actions .list > div').click(runAction);
|
||||
$(BODY).click(bodyClick);
|
||||
$(PLAN).click(planClick);
|
||||
(new EventSource("stream")).onmessage = stream;
|
||||
}
|
||||
|
||||
@@ -53,10 +53,16 @@ public class Application {
|
||||
plan = new Plan();
|
||||
}
|
||||
Locomotive BR110 = new Locomotive("BR110");
|
||||
Locomotive BR130 = new Locomotive("BR130");
|
||||
Vector<Block> blocks = new Vector<>(plan.blocks());
|
||||
Random rand = new Random();
|
||||
Block block = blocks.get(rand.nextInt(blocks.size()));
|
||||
if (block != null) block.train(new Train(BR110));
|
||||
Block block1 = blocks.get(rand.nextInt(blocks.size()));
|
||||
if (block1 != null) block1.train(new Train(BR110));
|
||||
Block block2 = null;
|
||||
do {
|
||||
block2 = blocks.get(rand.nextInt(blocks.size()));
|
||||
} while (block2 == block1);
|
||||
if (block2 != null) block2.train(new Train(BR130));
|
||||
Desktop.getDesktop().browse(URI.create("http://localhost:"+config.getInt(PORT)+"/plan"));
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,17 @@ import de.srsoftware.web4rail.tiles.TurnoutRW;
|
||||
|
||||
public class Plan {
|
||||
public enum Direction{
|
||||
NORTH, SOUTH, EAST, WEST
|
||||
NORTH, SOUTH, EAST, WEST;
|
||||
|
||||
Direction inverse() {
|
||||
switch (this) {
|
||||
case NORTH: return SOUTH;
|
||||
case SOUTH: return NORTH;
|
||||
case EAST: return WEST;
|
||||
case WEST: return EAST;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class Heartbeat extends Thread {
|
||||
@@ -148,7 +158,7 @@ public class Plan {
|
||||
private String analyze() {
|
||||
Vector<Route> routes = new Vector<Route>();
|
||||
for (Block block : blocks) {
|
||||
for (Connector con : block.startPoints()) routes.addAll(follow(new Route().start(block),con));
|
||||
for (Connector con : block.startPoints()) routes.addAll(follow(new Route().start(block,con.from.inverse()),con));
|
||||
}
|
||||
this.routes.clear();
|
||||
for (HashMap<Integer, Tile> column: tiles.values()) {
|
||||
@@ -279,7 +289,7 @@ public class Plan {
|
||||
JSONObject pos = (JSONObject) entry;
|
||||
Tile tile = result.get(pos.getInt("x"),pos.getInt("y"),false);
|
||||
if (route.path().isEmpty()) {
|
||||
route.start((Block) tile);
|
||||
route.start((Block) tile,null);
|
||||
} else {
|
||||
route.add(tile, null);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ public class Route {
|
||||
private String id;
|
||||
public Train train;
|
||||
private Block startBlock = null,endBlock;
|
||||
public Direction startDirection;
|
||||
private Direction endDirection;
|
||||
|
||||
/**
|
||||
* Route wurde von Zug betreten
|
||||
@@ -56,7 +58,10 @@ public class Route {
|
||||
|
||||
public Tile add(Tile tile, Direction direrction) {
|
||||
if (tile instanceof Shadow) tile = ((Shadow)tile).overlay();
|
||||
if (tile instanceof Block) endBlock = (Block) tile;
|
||||
if (tile instanceof Block) {
|
||||
endBlock = (Block) tile;
|
||||
endDirection = direrction;
|
||||
}
|
||||
path.add(tile);
|
||||
if (tile instanceof Contact) contacts.add((Contact) tile);
|
||||
if (tile instanceof Signal) {
|
||||
@@ -67,6 +72,15 @@ public class Route {
|
||||
return tile;
|
||||
}
|
||||
|
||||
private void addAction(Object trigger, Action action) {
|
||||
Vector<Action> actions = triggers.get(trigger);
|
||||
if (actions == null) {
|
||||
actions = new Vector<Action>();
|
||||
triggers.put(trigger, actions);
|
||||
}
|
||||
actions.add(action);
|
||||
}
|
||||
|
||||
void addSignal(Signal signal) {
|
||||
signals.add(signal);
|
||||
}
|
||||
@@ -78,7 +92,9 @@ public class Route {
|
||||
protected Route clone() {
|
||||
Route clone = new Route();
|
||||
clone.startBlock = startBlock;
|
||||
clone.startDirection = startDirection;
|
||||
clone.endBlock = endBlock;
|
||||
clone.endDirection = endDirection;
|
||||
clone.contacts = new Vector<Contact>(contacts);
|
||||
clone.signals = new Vector<Signal>(signals);
|
||||
clone.turnouts = new HashMap<>(turnouts);
|
||||
@@ -100,23 +116,6 @@ public class Route {
|
||||
}
|
||||
}
|
||||
|
||||
private void addAction(Object trigger, Action action) {
|
||||
// TODO Auto-generated method stub
|
||||
Vector<Action> actions = triggers.get(trigger);
|
||||
if (actions == null) {
|
||||
actions = new Vector<Action>();
|
||||
triggers.put(trigger, actions);
|
||||
}
|
||||
actions.add(action);
|
||||
}
|
||||
|
||||
public void finish() throws IOException {
|
||||
startBlock.train(null);
|
||||
endBlock.train(train);
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Kontakt der Route aktivieren
|
||||
* @param contact
|
||||
@@ -134,6 +133,13 @@ public class Route {
|
||||
}
|
||||
}
|
||||
|
||||
public void finish() throws IOException {
|
||||
startBlock.train(null);
|
||||
endBlock.train(train.heading(endDirection.inverse()));
|
||||
train.route = null;
|
||||
unlock();
|
||||
}
|
||||
|
||||
public String id() {
|
||||
if (id == null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -152,8 +158,11 @@ public class Route {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean inUse() {
|
||||
return false;
|
||||
public boolean free() {
|
||||
for (int i=1; i<path.size(); i++) {
|
||||
if (!path.get(i).free()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,23 +223,30 @@ public class Route {
|
||||
public Window properties() {
|
||||
Window win = new Window("route-properties",t("Properties of {}",this));
|
||||
|
||||
new Tag("h4").content(t("Origin and destination")).addTo(win);
|
||||
Tag list = new Tag("ul");
|
||||
Plan.addLink(startBlock, t("Origin: {} to {}",startBlock.name,startDirection), list);
|
||||
Plan.addLink(endBlock, t("Destination: {} from {}",endBlock.name,endDirection), list);
|
||||
list.addTo(win);
|
||||
|
||||
|
||||
if (!signals.isEmpty()) {
|
||||
new Tag("h4").content(t("Signals")).addTo(win);
|
||||
Tag list = new Tag("ul");
|
||||
list = new Tag("ul");
|
||||
for (Signal s : signals) Plan.addLink(s,s.toString(),list);
|
||||
list.addTo(win);
|
||||
}
|
||||
|
||||
if (!contacts.isEmpty()) {
|
||||
new Tag("h4").content(t("Contacts")).addTo(win);
|
||||
Tag list = new Tag("ul");
|
||||
list = new Tag("ul");
|
||||
for (Contact c : contacts) Plan.addLink(c,c.toString(),list);
|
||||
list.addTo(win);
|
||||
}
|
||||
|
||||
if (!turnouts.isEmpty()) {
|
||||
new Tag("h4").content(t("Turnouts")).addTo(win);
|
||||
Tag list = new Tag("ul");
|
||||
list = new Tag("ul");
|
||||
for (Entry<Turnout, State> entry : turnouts.entrySet()) {
|
||||
Turnout turnout = entry.getKey();
|
||||
Plan.addLink(turnout, turnout+": "+entry.getValue(), list);
|
||||
@@ -257,12 +273,14 @@ public class Route {
|
||||
return form;
|
||||
}
|
||||
|
||||
public Route start(Block block) {
|
||||
public Route start(Block block,Direction from) {
|
||||
// add those fields to clone, too!
|
||||
contacts = new Vector<Contact>();
|
||||
signals = new Vector<Signal>();
|
||||
path = new Vector<Tile>();
|
||||
turnouts = new HashMap<>();
|
||||
startBlock = block;
|
||||
startDirection = from;
|
||||
path.add(block);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ import org.slf4j.LoggerFactory;
|
||||
import de.keawe.tools.translations.Translation;
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.Plan.Direction;
|
||||
import de.srsoftware.web4rail.Route;
|
||||
import de.srsoftware.web4rail.Window;
|
||||
import de.srsoftware.web4rail.tiles.Block;
|
||||
import de.srsoftware.web4rail.tiles.Signal;
|
||||
import de.srsoftware.web4rail.tiles.Tile;
|
||||
|
||||
public class Train {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Train.class);
|
||||
@@ -23,8 +23,9 @@ public class Train {
|
||||
private Vector<Car> cars = new Vector<Car>();
|
||||
private String name = null;
|
||||
private Block block = null;
|
||||
private Route route;
|
||||
public Route route;
|
||||
public int speed = 0;
|
||||
private Direction direction;
|
||||
|
||||
public Train(Locomotive loco) {
|
||||
add(loco);
|
||||
@@ -49,12 +50,33 @@ public class Train {
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name != null ? name : locos.firstElement().name();
|
||||
String result = (name != null ? name : locos.firstElement().name());
|
||||
if (direction == null) return result;
|
||||
switch (direction) {
|
||||
case NORTH:
|
||||
case WEST:
|
||||
return '←'+result;
|
||||
case SOUTH:
|
||||
case EAST:
|
||||
return result+'→';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Tag props() {
|
||||
Window window = new Window("train-properties",t("Properties of {}",getClass().getSimpleName()));
|
||||
|
||||
Tag list = new Tag("ul");
|
||||
Tag locos = new Tag("li").content(t("Locomotives:"));
|
||||
Tag l2 = new Tag("ul");
|
||||
for (Locomotive loco : this.locos) new Tag("li").content(loco.name()).addTo(l2);
|
||||
l2.addTo(locos).addTo(list);
|
||||
|
||||
new Tag("li").content(t("Current location: {}",block)).addTo(list);
|
||||
new Tag("li").content(t("Direction: heading {}",direction)).addTo(list);
|
||||
|
||||
new Tag("li").clazz("link").attr("onclick","train("+block.x+","+block.y+",'start')").content(t("start")).addTo(list).addTo(window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -64,19 +86,23 @@ public class Train {
|
||||
}
|
||||
|
||||
public String start() throws IOException {
|
||||
if (block == null) return t("{] not in a block",this);
|
||||
if (block == null) return t("{} not in a block",this);
|
||||
HashSet<Route> routes = block.routes();
|
||||
Vector<Route> availableRoutes = new Vector<Route>();
|
||||
for (Route route : routes) {
|
||||
Vector<Tile> path = route.path();
|
||||
if (path.firstElement() != block) continue;
|
||||
if (route.inUse()) continue;
|
||||
if (route.path().firstElement() != block) continue; // route does not start with current location of loco
|
||||
if (direction != null && route.startDirection != direction) continue;
|
||||
if (!route.free()) {
|
||||
LOG.debug("{} is not free!",route);
|
||||
continue;
|
||||
}
|
||||
availableRoutes.add(route);
|
||||
}
|
||||
Random rand = new Random();
|
||||
if (route != null) route.unlock().setSignals(Signal.STOP);
|
||||
Random rand = new Random();
|
||||
if (availableRoutes.isEmpty()) return t("No free routes from {}",block);
|
||||
int sel = rand.nextInt(availableRoutes.size());
|
||||
route = availableRoutes.get(sel).lock(this).setSignals(null);
|
||||
this.route = availableRoutes.get(sel).lock(this).setSignals(null);
|
||||
setSpeed(100);
|
||||
return t("started {}",this);
|
||||
}
|
||||
@@ -89,4 +115,9 @@ public class Train {
|
||||
public String toString() {
|
||||
return name();
|
||||
}
|
||||
|
||||
public Train heading(Direction dir) {
|
||||
direction = dir;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ public abstract class Block extends StretchableTile{
|
||||
if (config.has(NAME)) name = config.getString(NAME);
|
||||
}
|
||||
|
||||
public abstract List<Connector> startPoints();
|
||||
@Override
|
||||
public boolean free() {
|
||||
return train == null && super.free();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag propForm() {
|
||||
@@ -54,6 +57,8 @@ public abstract class Block extends StretchableTile{
|
||||
return window;
|
||||
}
|
||||
|
||||
public abstract List<Connector> startPoints();
|
||||
|
||||
@Override
|
||||
public Tag tag(Map<String, Object> replacements) throws IOException {
|
||||
if (replacements == null) replacements = new HashMap<String, Object>();
|
||||
@@ -68,13 +73,6 @@ public abstract class Block extends StretchableTile{
|
||||
return getClass().getSimpleName()+"("+name+") @ ("+x+","+y+")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile update(HashMap<String, String> params) {
|
||||
super.update(params);
|
||||
if (params.containsKey(NAME)) name=params.get(NAME);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void train(Train train) throws IOException {
|
||||
this.train = train;
|
||||
if (train != null) train.block(this);
|
||||
@@ -93,4 +91,11 @@ public abstract class Block extends StretchableTile{
|
||||
plan.stream("dropclass tile-"+x+"-"+y+" locked");
|
||||
} else plan.stream("dropclass tile-"+x+"-"+y+" locked occupied");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile update(HashMap<String, String> params) {
|
||||
super.update(params);
|
||||
if (params.containsKey(NAME)) name=params.get(NAME);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,10 @@ public abstract class Tile {
|
||||
|
||||
public void configure(JSONObject config) {}
|
||||
|
||||
public boolean free() {
|
||||
return route == null;
|
||||
}
|
||||
|
||||
public int height() {
|
||||
return 1;
|
||||
}
|
||||
@@ -210,4 +214,8 @@ public abstract class Tile {
|
||||
LOG.debug("{}.update({})",getClass().getSimpleName(),params);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Route route() {
|
||||
return route;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user