View Javadoc
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   * <p>
54   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
55   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
56   * <p>
57   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Nov 18, 2016 <br>
58   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
59   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
60   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
61   */
62  public class TrafCODDemo1 extends OTSSimulationApplication<TrafCODModel>
63  {
64      /** */
65      private static final long serialVersionUID = 20161118L;
66  
67      /**
68       * Create a Trafcod demo.
69       * @param title String; the title of the Frame
70       * @param panel OTSAnimationPanel; the tabbed panel to display
71       * @param model TrafCODModel; the model
72       * @throws OTSDrawingException on animation error
73       */
74      public TrafCODDemo1(final String title, final OTSAnimationPanel panel, final TrafCODModel model) throws OTSDrawingException
75      {
76          super(model, panel);
77      }
78  
79      /**
80       * Main program.
81       * @param args String[]; the command line arguments (not used)
82       * @throws IOException ...
83       */
84      public static void main(final String[] args) throws IOException
85      {
86          demo(true);
87      }
88  
89      /**
90       * Open an URL, read it and store the contents in a string. Adapted from
91       * https://stackoverflow.com/questions/4328711/read-url-to-string-in-few-lines-of-java-code
92       * @param url URL; the URL
93       * @return String
94       * @throws IOException when reading the file fails
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      * Start the demo.
107      * @param exitOnClose boolean; when running stand-alone: true; when running as part of a demo: false
108      * @throws IOException when reading the file fails 
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      * Add tab with trafCOD status.
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      * The simulation model.
145      */
146     public static class TrafCODModel extends AbstractOTSModel implements EventListenerInterface
147     {
148         /** */
149         private static final long serialVersionUID = 20161020L;
150 
151         /** The network. */
152         private OTSRoadNetwork network;
153 
154         /** The TrafCOD controller. */
155         private TrafCOD trafCOD;
156 
157         /** TrafCOD controller display. */
158         private JPanel controllerDisplayPanel = new JPanel(new BorderLayout());
159 
160         /** The XML. */
161         private final String xml;
162 
163         /**
164          * @param simulator OTSSimulatorInterface; the simulator
165          * @param shortName String; name of the model
166          * @param description String; description of the model
167          * @param xml String; the XML string
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         /** {@inheritDoc} */
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                             // javax.imageio.ImageIO.write(backgroundImage, "png", new File("c:\\temp\\test.png"));
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                 // Subscribe the TrafCOD machine to trace command events that we emit
262                 addListener(this.trafCOD, TrafficController.TRAFFICCONTROL_SET_TRACING);
263                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 8, true});
264                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "XR1", 11, true});
265                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TD1", 11, true});
266                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 11, true});
267                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TL", 11, true});
268                 // System.out.println("demo: emitting a SET TRACING event for all variables related to stream 11");
269                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] { controllerName, "", 11, true });
270 
271                 // this.trafCOD.traceVariablesOfStream(TrafficController.NO_STREAM, true);
272                 // this.trafCOD.traceVariablesOfStream(11, true);
273                 // this.trafCOD.traceVariable("MRV", 11, true);
274             }
275             catch (Exception exception)
276             {
277                 exception.printStackTrace();
278             }
279         }
280 
281         /** {@inheritDoc} */
282         @Override
283         public final OTSRoadNetwork getNetwork()
284         {
285             return this.network;
286         }
287 
288         /**
289          * @return trafCOD
290          */
291         public final TrafCOD getTrafCOD()
292         {
293             return this.trafCOD;
294         }
295 
296         /**
297          * @return controllerDisplayPanel
298          */
299         public final JPanel getControllerDisplayPanel()
300         {
301             return this.controllerDisplayPanel;
302         }
303 
304         /** {@inheritDoc} */
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                 // System.out.println("Evalution starts at " + getSimulator().getSimulatorTime());
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 }