diff --git a/resources/css/style.css b/resources/css/style.css index d453432..32d362f 100644 --- a/resources/css/style.css +++ b/resources/css/style.css @@ -174,7 +174,7 @@ svg.left rect, svg.right rect, svg.straight .left, svg.straight .right{ - fill: white !important; + fill: #ddd !important; } .occupied .block{ diff --git a/resources/js/plan.js b/resources/js/plan.js index 72aa1c4..542051b 100644 --- a/resources/js/plan.js +++ b/resources/js/plan.js @@ -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(' 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; } diff --git a/src/main/java/de/srsoftware/web4rail/Application.java b/src/main/java/de/srsoftware/web4rail/Application.java index b175718..b756339 100644 --- a/src/main/java/de/srsoftware/web4rail/Application.java +++ b/src/main/java/de/srsoftware/web4rail/Application.java @@ -53,10 +53,16 @@ public class Application { plan = new Plan(); } Locomotive BR110 = new Locomotive("BR110"); + Locomotive BR130 = new Locomotive("BR130"); Vector 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")); } diff --git a/src/main/java/de/srsoftware/web4rail/Plan.java b/src/main/java/de/srsoftware/web4rail/Plan.java index 4487348..e285a5a 100644 --- a/src/main/java/de/srsoftware/web4rail/Plan.java +++ b/src/main/java/de/srsoftware/web4rail/Plan.java @@ -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 routes = new Vector(); 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 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); } diff --git a/src/main/java/de/srsoftware/web4rail/Route.java b/src/main/java/de/srsoftware/web4rail/Route.java index afaacb9..7e9ab26 100644 --- a/src/main/java/de/srsoftware/web4rail/Route.java +++ b/src/main/java/de/srsoftware/web4rail/Route.java @@ -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 actions = triggers.get(trigger); + if (actions == null) { + actions = new Vector(); + 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(contacts); clone.signals = new Vector(signals); clone.turnouts = new HashMap<>(turnouts); @@ -99,23 +115,6 @@ public class Route { addAction(lastContact, new FinishRoute(this)); } } - - private void addAction(Object trigger, Action action) { - // TODO Auto-generated method stub - Vector actions = triggers.get(trigger); - if (actions == null) { - actions = new Vector(); - triggers.put(trigger, actions); - } - actions.add(action); - } - - public void finish() throws IOException { - startBlock.train(null); - endBlock.train(train); - unlock(); - } - /** * 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() { 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 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(); signals = new Vector(); path = new Vector(); turnouts = new HashMap<>(); startBlock = block; + startDirection = from; path.add(block); return this; } diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java index 84d63a9..1514753 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Train.java +++ b/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.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 cars = new Vector(); 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 routes = block.routes(); Vector availableRoutes = new Vector(); for (Route route : routes) { - Vector 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; + } } diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Block.java b/src/main/java/de/srsoftware/web4rail/tiles/Block.java index 805a1b3..5679f6d 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Block.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Block.java @@ -28,8 +28,11 @@ public abstract class Block extends StretchableTile{ super.configure(config); if (config.has(NAME)) name = config.getString(NAME); } - - public abstract List 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 startPoints(); + @Override public Tag tag(Map replacements) throws IOException { if (replacements == null) replacements = new HashMap(); @@ -68,13 +73,6 @@ public abstract class Block extends StretchableTile{ return getClass().getSimpleName()+"("+name+") @ ("+x+","+y+")"; } - @Override - public Tile update(HashMap 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 params) { + super.update(params); + if (params.containsKey(NAME)) name=params.get(NAME); + return this; + } } diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java index 55543d3..bb45360 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java @@ -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; + } }