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