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