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.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   * <p>
50   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
51   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
52   * <p>
53   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Dec 06, 2016 <br>
54   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
55   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
56   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
57   */
58  public class TrafCODDemo2 extends OTSSimulationApplication<TrafCODModel>
59  {
60      /** */
61      private static final long serialVersionUID = 20161118L;
62  
63      /**
64       * Create a Trafcod demo.
65       * @param title String; the title of the Frame
66       * @param panel OTSAnimationPanel; the tabbed panel to display
67       * @param model TrafCODModel; the model
68       * @throws OTSDrawingException on animation error
69       */
70      public TrafCODDemo2(final String title, final OTSAnimationPanel panel, final TrafCODModel model) throws OTSDrawingException
71      {
72          super(model, panel);
73      }
74  
75      /**
76       * Main program.
77       * @param args String[]; the command line arguments (not used)
78       * @throws IOException ...
79       */
80      public static void main(final String[] args) throws IOException
81      {
82          demo(true);
83      }
84  
85      /**
86       * Open an URL, read it and store the contents in a string. Adapted from
87       * https://stackoverflow.com/questions/4328711/read-url-to-string-in-few-lines-of-java-code
88       * @param url URL; the URL
89       * @return String
90       * @throws IOException when reading the file fails
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      * Start the demo.
103      * @param exitOnClose boolean; when running stand-alone: true; when running as part of a demo: false
104      * @throws IOException when reading the file fails
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      * Add tab with trafCOD status.
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      * The simulation model.
142      */
143     public static class TrafCODModel extends AbstractOTSModel implements EventListenerInterface
144     {
145         /** */
146         private static final long serialVersionUID = 20161020L;
147 
148         /** The network. */
149         private OTSRoadNetwork network;
150 
151         /** The TrafCOD controller. */
152         private TrafCOD trafCOD;
153 
154         /** TrafCOD controller display. */
155         private JPanel controllerDisplayPanel = new JPanel(new BorderLayout());
156 
157         /** The XML. */
158         private final String xml;
159 
160         /**
161          * @param simulator OTSSimulatorInterface; the simulator
162          * @param shortName String; name of the model
163          * @param description String; description of the model
164          * @param xml String; the XML string
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         /** {@inheritDoc} */
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                 // Obtain the background image for the TrafCOD controller state display
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                             // javax.imageio.ImageIO.write(backgroundImage, "png", new File("c:\\temp\\test.png"));
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                 // Subscribe the TrafCOD machine to trace command events that we emit
232                 addListener(this.trafCOD, TrafficController.TRAFFICCONTROL_SET_TRACING);
233                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 8, true});
234                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "XR1", 11, true});
235                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TD1", 11, true});
236                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 11, true});
237                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TL", 11, true});
238                 // System.out.println("demo: emitting a SET TRACING event for all variables related to stream 11");
239                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] { controllerName, "", 11, true });
240 
241                 // this.trafCOD.traceVariablesOfStream(TrafficController.NO_STREAM, true);
242                 // this.trafCOD.traceVariablesOfStream(11, true);
243                 // this.trafCOD.traceVariable("MRV", 11, true);
244             }
245             catch (Exception exception)
246             {
247                 exception.printStackTrace();
248             }
249         }
250 
251         /** {@inheritDoc} */
252         @Override
253         public final OTSRoadNetwork getNetwork()
254         {
255             return this.network;
256         }
257 
258         /**
259          * @return trafCOD
260          */
261         public final TrafCOD getTrafCOD()
262         {
263             return this.trafCOD;
264         }
265 
266         /**
267          * @return controllerDisplayPanel
268          */
269         public final JPanel getControllerDisplayPanel()
270         {
271             return this.controllerDisplayPanel;
272         }
273 
274         /** {@inheritDoc} */
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                 // System.out.println("Evaluation starts at " + getSimulator().getSimulatorTime());
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         /** {@inheritDoc} */
311         @Override
312         public Serializable getSourceId()
313         {
314             return "TrafCODModel";
315         }
316 
317     }
318 
319 }