1 package org.opentrafficsim.demo.trafficcontrol;
2
3 import java.awt.BorderLayout;
4 import java.awt.Dimension;
5 import java.awt.image.BufferedImage;
6 import java.io.ByteArrayInputStream;
7 import java.io.IOException;
8 import java.io.Serializable;
9 import java.net.URL;
10 import java.nio.charset.StandardCharsets;
11 import java.rmi.RemoteException;
12 import java.util.Arrays;
13 import java.util.List;
14 import java.util.Scanner;
15
16 import javax.imageio.ImageIO;
17 import javax.naming.NamingException;
18 import javax.swing.JPanel;
19 import javax.swing.JScrollPane;
20 import javax.xml.bind.DatatypeConverter;
21
22 import org.djunits.value.vdouble.scalar.Duration;
23 import org.djunits.value.vdouble.scalar.Time;
24 import org.djutils.event.EventInterface;
25 import org.djutils.event.EventListenerInterface;
26 import org.djutils.event.EventType;
27 import org.djutils.exceptions.Throw;
28 import org.djutils.io.URLResource;
29 import org.opentrafficsim.core.dsol.AbstractOTSModel;
30 import org.opentrafficsim.core.dsol.OTSAnimator;
31 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
32 import org.opentrafficsim.core.network.NetworkException;
33 import org.opentrafficsim.demo.trafficcontrol.TrafCODDemo2.TrafCODModel;
34 import org.opentrafficsim.draw.core.OTSDrawingException;
35 import org.opentrafficsim.road.network.OTSRoadNetwork;
36 import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser;
37 import org.opentrafficsim.swing.gui.OTSAnimationPanel;
38 import org.opentrafficsim.swing.gui.OTSSimulationApplication;
39 import org.opentrafficsim.trafficcontrol.TrafficController;
40 import org.opentrafficsim.trafficcontrol.trafcod.TrafCOD;
41 import org.opentrafficsim.xml.generated.CONTROL;
42 import org.opentrafficsim.xml.generated.CONTROL.TRAFCOD;
43 import org.opentrafficsim.xml.generated.OTS;
44
45 import nl.tudelft.simulation.dsol.SimRuntimeException;
46 import nl.tudelft.simulation.language.DSOLException;
47
48
49
50
51
52
53
54
55
56
57
58 public class TrafCODDemo2 extends OTSSimulationApplication<TrafCODModel>
59 {
60
61 private static final long serialVersionUID = 20161118L;
62
63
64
65
66
67
68
69
70 public TrafCODDemo2(final String title, final OTSAnimationPanel panel, final TrafCODModel model) throws OTSDrawingException
71 {
72 super(model, panel);
73 }
74
75
76
77
78
79
80 public static void main(final String[] args) throws IOException
81 {
82 demo(true);
83 }
84
85
86
87
88
89
90
91
92 public static String readStringFromURL(final URL url) throws IOException
93 {
94 try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.toString()))
95 {
96 scanner.useDelimiter("\\A");
97 return scanner.hasNext() ? scanner.next() : "";
98 }
99 }
100
101
102
103
104
105
106 public static void demo(final boolean exitOnClose) throws IOException
107 {
108 try
109 {
110 OTSAnimator simulator = new OTSAnimator("TrafCODDemo2");
111 URL url = URLResource.getResource("/TrafCODDemo2/TrafCODDemo2.xml");
112 System.out.println("url is " + url);
113 String xml = readStringFromURL(url);
114 final TrafCODModel trafcodModel = new TrafCODModel(simulator, "TrafCODModel", "TrafCOD demonstration Model", xml);
115 simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0), trafcodModel);
116 OTSAnimationPanel animationPanel = new OTSAnimationPanel(trafcodModel.getNetwork().getExtent(),
117 new Dimension(800, 600), simulator, trafcodModel, DEFAULT_COLORER, trafcodModel.getNetwork());
118 TrafCODDemo2control/TrafCODDemo2.html#TrafCODDemo2">TrafCODDemo2 app = new TrafCODDemo2("TrafCOD demo complex crossing", animationPanel, trafcodModel);
119 app.setExitOnClose(exitOnClose);
120 }
121 catch (SimRuntimeException | NamingException | RemoteException | OTSDrawingException | DSOLException exception)
122 {
123 exception.printStackTrace();
124 }
125 }
126
127
128
129
130 @Override
131 protected final void addTabs()
132 {
133 JScrollPane scrollPane = new JScrollPane(getModel().getControllerDisplayPanel());
134 JPanel wrapper = new JPanel(new BorderLayout());
135 wrapper.add(scrollPane);
136 getAnimationPanel().getTabbedPane().addTab(getAnimationPanel().getTabbedPane().getTabCount() - 1,
137 getModel().getTrafCOD().getId(), wrapper);
138 }
139
140
141
142
143 public static class TrafCODModel extends AbstractOTSModel implements EventListenerInterface
144 {
145
146 private static final long serialVersionUID = 20161020L;
147
148
149 private OTSRoadNetwork network;
150
151
152 private TrafCOD trafCOD;
153
154
155 private JPanel controllerDisplayPanel = new JPanel(new BorderLayout());
156
157
158 private final String xml;
159
160
161
162
163
164
165
166 public TrafCODModel(final OTSSimulatorInterface simulator, final String shortName, final String description,
167 final String xml)
168 {
169 super(simulator, shortName, description);
170 this.xml = xml;
171 }
172
173
174 @Override
175 public void constructModel() throws SimRuntimeException
176 {
177 try
178 {
179 this.network = new OTSRoadNetwork(getShortName(), true);
180 OTS ots = XmlNetworkLaneParser.parseXML(new ByteArrayInputStream(this.xml.getBytes(StandardCharsets.UTF_8)));
181 XmlNetworkLaneParser.build(ots, this.network, getSimulator(), false);
182
183 String controllerName = "TrafCOD_complex";
184 List<CONTROL> trafficControllerList = ots.getCONTROL();
185 Throw.when(trafficControllerList.size() != 1, NetworkException.class,
186 "OTS contains wrong number of traffic controllers (should be 1, got %1)", trafficControllerList.size());
187 CONTROL controller = trafficControllerList.get(0);
188 List<TRAFCOD> trafCodList = controller.getTRAFCOD();
189 Throw.when(trafCodList.size() != 1, NetworkException.class, "Controller should contain one TRAFCOD (got %1)",
190 trafCodList.size());
191 TRAFCOD trafCod = trafCodList.get(0);
192 String programString = trafCod.getPROGRAM().getValue();
193 List<String> program = null == programString ? TrafCOD.loadTextFromURL(new URL(trafCod.getPROGRAMFILE()))
194 : Arrays.asList(programString.split("\n"));
195
196 TRAFCOD.CONSOLE.MAP mapData = trafCod.getCONSOLE().getMAP();
197 BufferedImage backgroundImage = null;
198 if (null != mapData)
199 {
200 String graphicsType = mapData.getTYPE();
201 String encoding = mapData.getENCODING();
202 String encodedData = mapData.getValue();
203 if (!"base64".contentEquals(encoding))
204 {
205 throw new RuntimeException("Unexpected image encoding: " + encoding);
206 }
207 byte[] imageBytes = DatatypeConverter.parseBase64Binary(encodedData);
208 switch (graphicsType)
209 {
210 case "PNG":
211 backgroundImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
212
213 break;
214
215 default:
216 throw new RuntimeException("Unexpected image type: " + graphicsType);
217 }
218 }
219 String objectLocationsString = trafCod.getCONSOLE().getCOORDINATES().getValue();
220 List<String> displayObjectLocations = null == objectLocationsString
221 ? TrafCOD.loadTextFromURL(new URL(trafCod.getCONSOLE().getCOORDINATESFILE()))
222 : Arrays.asList(objectLocationsString.split("\n"));
223 this.trafCOD = new TrafCOD(controllerName, program, getSimulator(), this.controllerDisplayPanel,
224 backgroundImage, displayObjectLocations);
225 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONTROLLER_EVALUATING);
226 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONTROLLER_WARNING);
227 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONFLICT_GROUP_CHANGED);
228 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_STATE_CHANGED);
229 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_VARIABLE_CREATED);
230 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_TRACED_VARIABLE_UPDATED);
231
232 addListener(this.trafCOD, TrafficController.TRAFFICCONTROL_SET_TRACING);
233
234
235
236
237
238
239
240
241
242
243
244 }
245 catch (Exception exception)
246 {
247 exception.printStackTrace();
248 }
249 }
250
251
252 @Override
253 public final OTSRoadNetwork getNetwork()
254 {
255 return this.network;
256 }
257
258
259
260
261 public final TrafCOD getTrafCOD()
262 {
263 return this.trafCOD;
264 }
265
266
267
268
269 public final JPanel getControllerDisplayPanel()
270 {
271 return this.controllerDisplayPanel;
272 }
273
274
275 @Override
276 public void notify(final EventInterface event) throws RemoteException
277 {
278 EventType type = event.getType();
279 Object[] payload = (Object[]) event.getContent();
280 if (TrafficController.TRAFFICCONTROL_CONTROLLER_EVALUATING.equals(type))
281 {
282
283 return;
284 }
285 else if (TrafficController.TRAFFICCONTROL_CONFLICT_GROUP_CHANGED.equals(type))
286 {
287 System.out.println("Conflict group changed from " + ((String) payload[1]) + " to " + ((String) payload[2]));
288 }
289 else if (TrafficController.TRAFFICCONTROL_TRACED_VARIABLE_UPDATED.equals(type))
290 {
291 System.out.println(String.format("Variable changed %s <- %d %s", payload[1], payload[4], payload[5]));
292 }
293 else if (TrafficController.TRAFFICCONTROL_CONTROLLER_WARNING.equals(type))
294 {
295 System.out.println("Warning " + payload[1]);
296 }
297 else
298 {
299 System.out.print("TrafCODDemo received event of type " + event.getType() + ", payload [");
300 String separator = "";
301 for (Object o : payload)
302 {
303 System.out.print(separator + o);
304 separator = ",";
305 }
306 System.out.println("]");
307 }
308 }
309
310
311 @Override
312 public Serializable getSourceId()
313 {
314 return "TrafCODModel";
315 }
316
317 }
318
319 }