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