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.value.vdouble.scalar.Duration;
22  import org.djunits.value.vdouble.scalar.Time;
23  import org.djutils.exceptions.Throw;
24  import org.djutils.io.URLResource;
25  import org.opentrafficsim.core.dsol.AbstractOTSModel;
26  import org.opentrafficsim.core.dsol.OTSAnimator;
27  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
28  import org.opentrafficsim.core.network.NetworkException;
29  import org.opentrafficsim.demo.trafficcontrol.TrafCODDemo2.TrafCODModel;
30  import org.opentrafficsim.draw.core.OTSDrawingException;
31  import org.opentrafficsim.road.network.OTSRoadNetwork;
32  import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser;
33  import org.opentrafficsim.swing.gui.OTSAnimationPanel;
34  import org.opentrafficsim.swing.gui.OTSSimulationApplication;
35  import org.opentrafficsim.trafficcontrol.TrafficController;
36  import org.opentrafficsim.trafficcontrol.trafcod.TrafCOD;
37  import org.opentrafficsim.xml.generated.CONTROL;
38  import org.opentrafficsim.xml.generated.CONTROL.TRAFCOD;
39  import org.opentrafficsim.xml.generated.OTS;
40  
41  import nl.tudelft.simulation.dsol.SimRuntimeException;
42  import nl.tudelft.simulation.event.EventInterface;
43  import nl.tudelft.simulation.event.EventListenerInterface;
44  import nl.tudelft.simulation.event.EventType;
45  
46  /**
47   * <p>
48   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
49   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
50   * <p>
51   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Dec 06, 2016 <br>
52   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
53   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
54   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
55   */
56  public class TrafCODDemo2 extends OTSSimulationApplication<TrafCODModel>
57  {
58      /** */
59      private static final long serialVersionUID = 20161118L;
60  
61      /**
62       * Create a Trafcod demo.
63       * @param title String; the title of the Frame
64       * @param panel OTSAnimationPanel; the tabbed panel to display
65       * @param model TrafCODModel; the model
66       * @throws OTSDrawingException on animation error
67       */
68      public TrafCODDemo2(final String title, final OTSAnimationPanel panel, final TrafCODModel model) throws OTSDrawingException
69      {
70          super(model, panel);
71      }
72  
73      /**
74       * Main program.
75       * @param args String[]; the command line arguments (not used)
76       * @throws IOException ...
77       */
78      public static void main(final String[] args) throws IOException
79      {
80          demo(true);
81      }
82  
83      /**
84       * Open an URL, read it and store the contents in a string. Adapted from
85       * https://stackoverflow.com/questions/4328711/read-url-to-string-in-few-lines-of-java-code
86       * @param url URL; the URL
87       * @return String
88       * @throws IOException when reading the file fails
89       */
90      public static String readStringFromURL(final URL url) throws IOException
91      {
92          try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.toString()))
93          {
94              scanner.useDelimiter("\\A");
95              return scanner.hasNext() ? scanner.next() : "";
96          }
97      }
98  
99      /**
100      * Start the demo.
101      * @param exitOnClose boolean; when running stand-alone: true; when running as part of a demo: false
102      * @throws IOException when reading the file fails
103      */
104     public static void demo(final boolean exitOnClose) throws IOException
105     {
106         try
107         {
108             OTSAnimator simulator = new OTSAnimator();
109             URL url = URLResource.getResource("/TrafCODDemo2/TrafCODDemo2.xml");
110             System.out.println("url is " + url);
111             String xml = readStringFromURL(url);
112             final TrafCODModel trafcodModel = new TrafCODModel(simulator, "TrafCODModel", "TrafCOD demonstration Model", xml);
113             simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0), trafcodModel);
114             OTSAnimationPanel animationPanel = new OTSAnimationPanel(trafcodModel.getNetwork().getExtent(),
115                     new Dimension(800, 600), simulator, trafcodModel, DEFAULT_COLORER, trafcodModel.getNetwork());
116             TrafCODDemo2control/TrafCODDemo2.html#TrafCODDemo2">TrafCODDemo2 app = new TrafCODDemo2("TrafCOD demo complex crossing", animationPanel, trafcodModel);
117             app.setExitOnClose(exitOnClose);
118         }
119         catch (SimRuntimeException | NamingException | RemoteException | OTSDrawingException exception)
120         {
121             exception.printStackTrace();
122         }
123     }
124 
125     /**
126      * Add tab with trafCOD status.
127      */
128     @Override
129     protected final void addTabs()
130     {
131         JScrollPane scrollPane = new JScrollPane(getModel().getControllerDisplayPanel());
132         JPanel wrapper = new JPanel(new BorderLayout());
133         wrapper.add(scrollPane);
134         getAnimationPanel().getTabbedPane().addTab(getAnimationPanel().getTabbedPane().getTabCount() - 1,
135                 getModel().getTrafCOD().getId(), wrapper);
136     }
137 
138     /**
139      * The simulation model.
140      */
141     public static class TrafCODModel extends AbstractOTSModel implements EventListenerInterface
142     {
143         /** */
144         private static final long serialVersionUID = 20161020L;
145 
146         /** The network. */
147         private OTSRoadNetwork network;
148 
149         /** The TrafCOD controller. */
150         private TrafCOD trafCOD;
151 
152         /** TrafCOD controller display. */
153         private JPanel controllerDisplayPanel = new JPanel(new BorderLayout());
154 
155         /** The XML. */
156         private final String xml;
157 
158         /**
159          * @param simulator OTSSimulatorInterface; the simulator
160          * @param shortName String; name of the model
161          * @param description String; description of the model
162          * @param xml String; the XML string
163          */
164         public TrafCODModel(final OTSSimulatorInterface simulator, final String shortName, final String description,
165                 final String xml)
166         {
167             super(simulator, shortName, description);
168             this.xml = xml;
169         }
170 
171         /** {@inheritDoc} */
172         @Override
173         public void constructModel() throws SimRuntimeException
174         {
175             try
176             {
177                 this.network = new OTSRoadNetwork(getShortName(), true);
178                 OTS ots = XmlNetworkLaneParser.parseXML(new ByteArrayInputStream(this.xml.getBytes(StandardCharsets.UTF_8)));
179                 XmlNetworkLaneParser.build(ots, this.network, getSimulator(), false);
180 
181                 String controllerName = "TrafCOD_complex";
182                 List<CONTROL> trafficControllerList = ots.getCONTROL();
183                 Throw.when(trafficControllerList.size() != 1, NetworkException.class,
184                         "OTS contains wrong number of traffic controllers (should be 1, got %1)", trafficControllerList.size());
185                 CONTROL controller = trafficControllerList.get(0);
186                 List<TRAFCOD> trafCodList = controller.getTRAFCOD();
187                 Throw.when(trafCodList.size() != 1, NetworkException.class, "Controller should contain one TRAFCOD (got %1)",
188                         trafCodList.size());
189                 TRAFCOD trafCod = trafCodList.get(0);
190                 String programString = trafCod.getPROGRAM().getValue();
191                 List<String> program = null == programString ? TrafCOD.loadTextFromURL(new URL(trafCod.getPROGRAMFILE()))
192                         : Arrays.asList(programString.split("\n"));
193                 // Obtain the background image for the TrafCOD controller state display
194                 TRAFCOD.CONSOLE.MAP mapData = trafCod.getCONSOLE().getMAP();
195                 BufferedImage backgroundImage = null;
196                 if (null != mapData)
197                 {
198                     String graphicsType = mapData.getTYPE();
199                     String encoding = mapData.getENCODING();
200                     String encodedData = mapData.getValue();
201                     if (!"base64".contentEquals(encoding))
202                     {
203                         throw new RuntimeException("Unexpected image encoding: " + encoding);
204                     }
205                     byte[] imageBytes = DatatypeConverter.parseBase64Binary(encodedData);
206                     switch (graphicsType)
207                     {
208                         case "PNG":
209                             backgroundImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
210                             // javax.imageio.ImageIO.write(backgroundImage, "png", new File("c:\\temp\\test.png"));
211                             break;
212 
213                         default:
214                             throw new RuntimeException("Unexpected image type: " + graphicsType);
215                     }
216                 }
217                 String objectLocationsString = trafCod.getCONSOLE().getCOORDINATES().getValue();
218                 List<String> displayObjectLocations = null == objectLocationsString
219                         ? TrafCOD.loadTextFromURL(new URL(trafCod.getCONSOLE().getCOORDINATESFILE()))
220                         : Arrays.asList(objectLocationsString.split("\n"));
221                 this.trafCOD = new TrafCOD(controllerName, program, getSimulator(), this.controllerDisplayPanel,
222                         backgroundImage, displayObjectLocations);
223                 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONTROLLER_EVALUATING);
224                 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONTROLLER_WARNING);
225                 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONFLICT_GROUP_CHANGED);
226                 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_STATE_CHANGED);
227                 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_VARIABLE_CREATED);
228                 this.trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_TRACED_VARIABLE_UPDATED);
229                 // Subscribe the TrafCOD machine to trace command events that we emit
230                 addListener(this.trafCOD, TrafficController.TRAFFICCONTROL_SET_TRACING);
231                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 8, true});
232                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "XR1", 11, true});
233                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TD1", 11, true});
234                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TGX", 11, true});
235                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] {controllerName, "TL", 11, true});
236                 // System.out.println("demo: emitting a SET TRACING event for all variables related to stream 11");
237                 // fireEvent(TrafficController.TRAFFICCONTROL_SET_TRACING, new Object[] { controllerName, "", 11, true });
238 
239                 // this.trafCOD.traceVariablesOfStream(TrafficController.NO_STREAM, true);
240                 // this.trafCOD.traceVariablesOfStream(11, true);
241                 // this.trafCOD.traceVariable("MRV", 11, true);
242             }
243             catch (Exception exception)
244             {
245                 exception.printStackTrace();
246             }
247         }
248 
249         /** {@inheritDoc} */
250         @Override
251         public final OTSRoadNetwork getNetwork()
252         {
253             return this.network;
254         }
255 
256         /**
257          * @return trafCOD
258          */
259         public final TrafCOD getTrafCOD()
260         {
261             return this.trafCOD;
262         }
263 
264         /**
265          * @return controllerDisplayPanel
266          */
267         public final JPanel getControllerDisplayPanel()
268         {
269             return this.controllerDisplayPanel;
270         }
271 
272         /** {@inheritDoc} */
273         @Override
274         public void notify(final EventInterface event) throws RemoteException
275         {
276             EventType type = event.getType();
277             Object[] payload = (Object[]) event.getContent();
278             if (TrafficController.TRAFFICCONTROL_CONTROLLER_EVALUATING.equals(type))
279             {
280                 // System.out.println("Evaluation starts at " + getSimulator().getSimulatorTime());
281                 return;
282             }
283             else if (TrafficController.TRAFFICCONTROL_CONFLICT_GROUP_CHANGED.equals(type))
284             {
285                 System.out.println("Conflict group changed from " + ((String) payload[1]) + " to " + ((String) payload[2]));
286             }
287             else if (TrafficController.TRAFFICCONTROL_TRACED_VARIABLE_UPDATED.equals(type))
288             {
289                 System.out.println(String.format("Variable changed %s <- %d   %s", payload[1], payload[4], payload[5]));
290             }
291             else if (TrafficController.TRAFFICCONTROL_CONTROLLER_WARNING.equals(type))
292             {
293                 System.out.println("Warning " + payload[1]);
294             }
295             else
296             {
297                 System.out.print("TrafCODDemo received event of type " + event.getType() + ", payload [");
298                 String separator = "";
299                 for (Object o : payload)
300                 {
301                     System.out.print(separator + o);
302                     separator = ",";
303                 }
304                 System.out.println("]");
305             }
306         }
307 
308     }
309 
310 }