Browse Source

working on train movements

lookup-tables
Stephan Richter 5 years ago
parent
commit
cd022ce4a3
  1. 2
      resources/css/style.css
  2. 48
      resources/js/plan.js
  3. 10
      src/main/java/de/srsoftware/web4rail/Application.java
  4. 16
      src/main/java/de/srsoftware/web4rail/Plan.java
  5. 66
      src/main/java/de/srsoftware/web4rail/Route.java
  6. 49
      src/main/java/de/srsoftware/web4rail/moving/Train.java
  7. 23
      src/main/java/de/srsoftware/web4rail/tiles/Block.java
  8. 8
      src/main/java/de/srsoftware/web4rail/tiles/Tile.java

2
resources/css/style.css

@ -174,7 +174,7 @@ svg.left rect,
svg.right rect, svg.right rect,
svg.straight .left, svg.straight .left,
svg.straight .right{ svg.straight .right{
fill: white !important; fill: #ddd !important;
} }
.occupied .block{ .occupied .block{

48
resources/js/plan.js

@ -1,10 +1,10 @@
const ADD = 'add'; const ADD = 'add';
const MOVE = 'move'; const MOVE = 'move';
const SQUARE = 30; const SQUARE = 30;
const BODY = '#plan'; const BODY = 'body';
const DIV = 'DIV'; const DIV = 'DIV';
const SVG = 'svg'; const SVG = 'svg';
const PLAN = 'plan'; const PLAN = '#plan';
const POST = 'POST'; const POST = 'POST';
var selected = null; var selected = null;
var mode = null; var mode = null;
@ -23,23 +23,6 @@ function addTile(x,y){
return request({action:mode,tile:selected.id,x:x,y: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){ function clickTile(x,y){
console.log("clickTile:",x,y); console.log("clickTile:",x,y);
if ($('#tile-'+x+'-'+y).length > 0) request({action:'click',x:x,y:y}); if ($('#tile-'+x+'-'+y).length > 0) request({action:'click',x:x,y:y});
@ -113,10 +96,27 @@ function openRoute(id){
function place(data){ function place(data){
var tag = $(data); var tag = $(data);
$('#'+tag.attr('id')).remove(); $('#'+tag.attr('id')).remove();
$(BODY).append(tag); $(PLAN).append(tag);
return false; 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){ function remove(id){
$('#'+id).remove(); $('#'+id).remove();
return false; return false;
@ -124,14 +124,15 @@ function remove(id){
function request(data){ function request(data){
$.ajax({ $.ajax({
url : PLAN, url : 'plan',
method : POST, method : POST,
data : data, data : data,
success: function(resp){ success: function(resp){
closeWindows(); closeWindows();
if (resp.startsWith('<svg')){ if (resp.startsWith('<svg')){
$('#plan').append($(resp)); $(PLAN).append($(resp));
} else if (resp.startsWith('<')) { } else if (resp.startsWith('<')) {
console.log("appending to body: "+resp.substring(0,10));
$(BODY).append($(resp)); $(BODY).append($(resp));
} else { } else {
addMessage(resp); addMessage(resp);
@ -163,11 +164,10 @@ function stream(ev){
window.onload = function () { window.onload = function () {
var isDragging = false; var isDragging = false;
console.log($(BODY).each(function(){console.log(this)}));
$('.menu > div').click(closeMenu); $('.menu > div').click(closeMenu);
$('.menu .addtile .list svg').click(enableAdding); $('.menu .addtile .list svg').click(enableAdding);
$('.menu .move .list div').click(enableMove); $('.menu .move .list div').click(enableMove);
$('.menu .actions .list > div').click(runAction); $('.menu .actions .list > div').click(runAction);
$(BODY).click(bodyClick); $(PLAN).click(planClick);
(new EventSource("stream")).onmessage = stream; (new EventSource("stream")).onmessage = stream;
} }

10
src/main/java/de/srsoftware/web4rail/Application.java

@ -53,10 +53,16 @@ public class Application {
plan = new Plan(); plan = new Plan();
} }
Locomotive BR110 = new Locomotive("BR110"); Locomotive BR110 = new Locomotive("BR110");
Locomotive BR130 = new Locomotive("BR130");
Vector<Block> blocks = new Vector<>(plan.blocks()); Vector<Block> blocks = new Vector<>(plan.blocks());
Random rand = new Random(); Random rand = new Random();
Block block = blocks.get(rand.nextInt(blocks.size())); Block block1 = blocks.get(rand.nextInt(blocks.size()));
if (block != null) block.train(new Train(BR110)); 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")); Desktop.getDesktop().browse(URI.create("http://localhost:"+config.getInt(PORT)+"/plan"));
} }

16
src/main/java/de/srsoftware/web4rail/Plan.java

@ -66,7 +66,17 @@ import de.srsoftware.web4rail.tiles.TurnoutRW;
public class Plan { public class Plan {
public enum Direction{ 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 { private class Heartbeat extends Thread {
@ -148,7 +158,7 @@ public class Plan {
private String analyze() { private String analyze() {
Vector<Route> routes = new Vector<Route>(); Vector<Route> routes = new Vector<Route>();
for (Block block : blocks) { 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(); this.routes.clear();
for (HashMap<Integer, Tile> column: tiles.values()) { for (HashMap<Integer, Tile> column: tiles.values()) {
@ -279,7 +289,7 @@ public class Plan {
JSONObject pos = (JSONObject) entry; JSONObject pos = (JSONObject) entry;
Tile tile = result.get(pos.getInt("x"),pos.getInt("y"),false); Tile tile = result.get(pos.getInt("x"),pos.getInt("y"),false);
if (route.path().isEmpty()) { if (route.path().isEmpty()) {
route.start((Block) tile); route.start((Block) tile,null);
} else { } else {
route.add(tile, null); route.add(tile, null);
} }

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

@ -45,6 +45,8 @@ public class Route {
private String id; private String id;
public Train train; public Train train;
private Block startBlock = null,endBlock; private Block startBlock = null,endBlock;
public Direction startDirection;
private Direction endDirection;
/** /**
* Route wurde von Zug betreten * Route wurde von Zug betreten
@ -56,7 +58,10 @@ public class Route {
public Tile add(Tile tile, Direction direrction) { public Tile add(Tile tile, Direction direrction) {
if (tile instanceof Shadow) tile = ((Shadow)tile).overlay(); 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); path.add(tile);
if (tile instanceof Contact) contacts.add((Contact) tile); if (tile instanceof Contact) contacts.add((Contact) tile);
if (tile instanceof Signal) { if (tile instanceof Signal) {
@ -67,6 +72,15 @@ public class Route {
return tile; 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) { void addSignal(Signal signal) {
signals.add(signal); signals.add(signal);
} }
@ -78,7 +92,9 @@ public class Route {
protected Route clone() { protected Route clone() {
Route clone = new Route(); Route clone = new Route();
clone.startBlock = startBlock; clone.startBlock = startBlock;
clone.startDirection = startDirection;
clone.endBlock = endBlock; clone.endBlock = endBlock;
clone.endDirection = endDirection;
clone.contacts = new Vector<Contact>(contacts); clone.contacts = new Vector<Contact>(contacts);
clone.signals = new Vector<Signal>(signals); clone.signals = new Vector<Signal>(signals);
clone.turnouts = new HashMap<>(turnouts); clone.turnouts = new HashMap<>(turnouts);
@ -99,23 +115,6 @@ public class Route {
addAction(lastContact, new FinishRoute(this)); addAction(lastContact, new FinishRoute(this));
} }
} }
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 * Kontakt der Route aktivieren
@ -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() { public String id() {
if (id == null) { if (id == null) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -152,8 +158,11 @@ public class Route {
return id; return id;
} }
public boolean inUse() { public boolean free() {
return false; for (int i=1; i<path.size(); i++) {
if (!path.get(i).free()) return false;
}
return true;
} }
@ -213,24 +222,31 @@ public class Route {
public Window properties() { public Window properties() {
Window win = new Window("route-properties",t("Properties of {}",this)); 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()) { if (!signals.isEmpty()) {
new Tag("h4").content(t("Signals")).addTo(win); 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); for (Signal s : signals) Plan.addLink(s,s.toString(),list);
list.addTo(win); list.addTo(win);
} }
if (!contacts.isEmpty()) { if (!contacts.isEmpty()) {
new Tag("h4").content(t("Contacts")).addTo(win); 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); for (Contact c : contacts) Plan.addLink(c,c.toString(),list);
list.addTo(win); list.addTo(win);
} }
if (!turnouts.isEmpty()) { if (!turnouts.isEmpty()) {
new Tag("h4").content(t("Turnouts")).addTo(win); new Tag("h4").content(t("Turnouts")).addTo(win);
Tag list = new Tag("ul"); list = new Tag("ul");
for (Entry<Turnout, State> entry : turnouts.entrySet()) { for (Entry<Turnout, State> entry : turnouts.entrySet()) {
Turnout turnout = entry.getKey(); Turnout turnout = entry.getKey();
Plan.addLink(turnout, turnout+": "+entry.getValue(), list); Plan.addLink(turnout, turnout+": "+entry.getValue(), list);
@ -257,12 +273,14 @@ public class Route {
return form; return form;
} }
public Route start(Block block) { public Route start(Block block,Direction from) {
// add those fields to clone, too!
contacts = new Vector<Contact>(); contacts = new Vector<Contact>();
signals = new Vector<Signal>(); signals = new Vector<Signal>();
path = new Vector<Tile>(); path = new Vector<Tile>();
turnouts = new HashMap<>(); turnouts = new HashMap<>();
startBlock = block; startBlock = block;
startDirection = from;
path.add(block); path.add(block);
return this; return this;
} }

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

@ -11,11 +11,11 @@ import org.slf4j.LoggerFactory;
import de.keawe.tools.translations.Translation; import de.keawe.tools.translations.Translation;
import de.srsoftware.tools.Tag; import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.Application; import de.srsoftware.web4rail.Application;
import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.Route; import de.srsoftware.web4rail.Route;
import de.srsoftware.web4rail.Window; import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.tiles.Block; import de.srsoftware.web4rail.tiles.Block;
import de.srsoftware.web4rail.tiles.Signal; import de.srsoftware.web4rail.tiles.Signal;
import de.srsoftware.web4rail.tiles.Tile;
public class Train { public class Train {
private static final Logger LOG = LoggerFactory.getLogger(Train.class); private static final Logger LOG = LoggerFactory.getLogger(Train.class);
@ -23,8 +23,9 @@ public class Train {
private Vector<Car> cars = new Vector<Car>(); private Vector<Car> cars = new Vector<Car>();
private String name = null; private String name = null;
private Block block = null; private Block block = null;
private Route route; public Route route;
public int speed = 0; public int speed = 0;
private Direction direction;
public Train(Locomotive loco) { public Train(Locomotive loco) {
add(loco); add(loco);
@ -49,12 +50,33 @@ public class Train {
} }
public String name() { 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() { public Tag props() {
Window window = new Window("train-properties",t("Properties of {}",getClass().getSimpleName())); 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; return window;
} }
@ -64,19 +86,23 @@ public class Train {
} }
public String start() throws IOException { 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(); HashSet<Route> routes = block.routes();
Vector<Route> availableRoutes = new Vector<Route>(); Vector<Route> availableRoutes = new Vector<Route>();
for (Route route : routes) { for (Route route : routes) {
Vector<Tile> path = route.path(); if (route.path().firstElement() != block) continue; // route does not start with current location of loco
if (path.firstElement() != block) continue; if (direction != null && route.startDirection != direction) continue;
if (route.inUse()) continue; if (!route.free()) {
LOG.debug("{} is not free!",route);
continue;
}
availableRoutes.add(route); availableRoutes.add(route);
} }
Random rand = new Random();
if (route != null) route.unlock().setSignals(Signal.STOP); 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()); 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); setSpeed(100);
return t("started {}",this); return t("started {}",this);
} }
@ -89,4 +115,9 @@ public class Train {
public String toString() { public String toString() {
return name(); return name();
} }
public Train heading(Direction dir) {
direction = dir;
return this;
}
} }

23
src/main/java/de/srsoftware/web4rail/tiles/Block.java

@ -28,8 +28,11 @@ public abstract class Block extends StretchableTile{
super.configure(config); super.configure(config);
if (config.has(NAME)) name = config.getString(NAME); if (config.has(NAME)) name = config.getString(NAME);
} }
public abstract List<Connector> startPoints(); @Override
public boolean free() {
return train == null && super.free();
}
@Override @Override
public Tag propForm() { public Tag propForm() {
@ -54,6 +57,8 @@ public abstract class Block extends StretchableTile{
return window; return window;
} }
public abstract List<Connector> startPoints();
@Override @Override
public Tag tag(Map<String, Object> replacements) throws IOException { public Tag tag(Map<String, Object> replacements) throws IOException {
if (replacements == null) replacements = new HashMap<String, Object>(); if (replacements == null) replacements = new HashMap<String, Object>();
@ -68,13 +73,6 @@ public abstract class Block extends StretchableTile{
return getClass().getSimpleName()+"("+name+") @ ("+x+","+y+")"; 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 { public void train(Train train) throws IOException {
this.train = train; this.train = train;
if (train != null) train.block(this); if (train != null) train.block(this);
@ -93,4 +91,11 @@ public abstract class Block extends StretchableTile{
plan.stream("dropclass tile-"+x+"-"+y+" locked"); plan.stream("dropclass tile-"+x+"-"+y+" locked");
} else plan.stream("dropclass tile-"+x+"-"+y+" locked occupied"); } 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;
}
} }

8
src/main/java/de/srsoftware/web4rail/tiles/Tile.java

@ -62,6 +62,10 @@ public abstract class Tile {
public void configure(JSONObject config) {} public void configure(JSONObject config) {}
public boolean free() {
return route == null;
}
public int height() { public int height() {
return 1; return 1;
} }
@ -210,4 +214,8 @@ public abstract class Tile {
LOG.debug("{}.update({})",getClass().getSimpleName(),params); LOG.debug("{}.update({})",getClass().getSimpleName(),params);
return this; return this;
} }
public Route route() {
return route;
}
} }

Loading…
Cancel
Save