View Javadoc
1   package org.opentrafficsim.imb.transceiver.urbanstrategy;
2   
3   import java.io.IOException;
4   import java.util.ArrayList;
5   import java.util.List;
6   
7   import org.djunits.value.vdouble.scalar.Duration;
8   import org.opentrafficsim.core.network.Network;
9   import org.opentrafficsim.graphs.AbstractOTSPlot;
10  import org.opentrafficsim.graphs.ContourPlot;
11  import org.opentrafficsim.graphs.TrajectoryPlot;
12  import org.opentrafficsim.imb.IMBException;
13  import org.opentrafficsim.imb.connector.Connector;
14  import org.opentrafficsim.imb.connector.Connector.IMBEventType;
15  import org.opentrafficsim.imb.transceiver.AbstractTransceiver;
16  import org.opentrafficsim.road.network.lane.Lane;
17  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
18  
19  import nl.tudelft.simulation.dsol.SimRuntimeException;
20  
21  /**
22   * OTS can publish graphs to IMB, e.g. trajectory graphs, flow graphs and density graphs.<br>
23   * When a graph is published for the first time, a NEW message is sent to IMB to identify the graph, the image resolution, and
24   * the lane(s) for which the graph is created. The CHANGE message is posted whenever an updated graph is posted. When a Graph is
25   * no longer published, a DELETE event is posted. The Graph NEW messages are posted after the Network NEW, Node NEW, Link NEW,
26   * and Lane NEW messages are posted, as it has to be able to identify Lanes.
27   * <p>
28   * <style>table,th,td {border:1px solid grey; border-style:solid; text-align:left; border-collapse: collapse;}</style>
29   * <h2>NEW</h2>
30   * <table summary="" style="width:800px;">
31   * <thead>
32   * <tr>
33   * <th style="width:25%;">Variable</th>
34   * <th style="width:15%;">Type</th>
35   * <th style="width:60%;">Comments</th>
36   * </tr>
37   * </thead><tbody>
38   * <tr>
39   * <td>timestamp</td>
40   * <td>double</td>
41   * <td>time of the event, in simulation time seconds</td>
42   * </tr>
43   * <tr>
44   * <td>graphId</td>
45   * <td>String</td>
46   * <td>a unique id for the graph, e.g. a UUID string</td>
47   * </tr>
48   * <tr>
49   * <td>width</td>
50   * <td>int</td>
51   * <td>width of the graph in pixels</td>
52   * </tr>
53   * <tr>
54   * <td>height</td>
55   * <td>int</td>
56   * <td>height of the graph in pixels</td>
57   * </tr>
58   * <tr>
59   * <td>description</td>
60   * <td>String</td>
61   * <td>textual description of the graph</td>
62   * </tr>
63   * <tr>
64   * <td>graphType</td>
65   * <td>String</td>
66   * <td>type of graph; one of TRAJECTORY, SPEED_CONTOUR, ACCELERATION_CONTOUR, DENSITY_CONTOUR, FLOW_CONTOUR,
67   * FUNDAMENTAL_DIAGRAM</td>
68   * </tr>
69   * <tr>
70   * <td>time_resolution</td>
71   * <td>double</td>
72   * <td>For the four types of contour graphs, and the trajectory graph, it provides the aggregation in seconds. 0.0 for other
73   * types of graphs. When the value is 0.0 for the trajectory graph, the graph is updated on the basis of events from the
74   * GTU.</td>
75   * </tr>
76   * <tr>
77   * <td>value_resolution</td>
78   * <td>double</td>
79   * <td>For the four types of contour graphs, it provides the aggregation in the SI unit of the value. 0.0 for other types of
80   * graphs</td>
81   * </tr>
82   * <tr>
83   * <td>networkId</td>
84   * <td>String</td>
85   * <td>id of the Network for which the Graph is made</td>
86   * </tr>
87   * <tr>
88   * <td>numberOfLanes</td>
89   * <td>int</td>
90   * <td>number of Link-Lane combinations for this Graph</td>
91   * </tr>
92   * <tr>
93   * <td>linkId_1</td>
94   * <td>String</td>
95   * <td>id of the first Link; unique within the Network</td>
96   * </tr>
97   * <tr>
98   * <td>laneId_1</td>
99   * <td>String</td>
100  * <td>id of the first Lane, unique within the Link</td>
101  * </tr>
102  * <tr>
103  * <td>...</td>
104  * <td>&nbsp;</td>
105  * <td>&nbsp;</td>
106  * </tr>
107  * <tr>
108  * <td>linkId_n</td>
109  * <td>String</td>
110  * <td>id of the last Link; unique within the Network</td>
111  * </tr>
112  * <tr>
113  * <td>laneId_n</td>
114  * <td>String</td>
115  * <td>id of the last Lane, unique within the Link</td>
116  * </tr>
117  * <tr>
118  * <td>transmissionInterval</td>
119  * <td>double</td>
120  * <td>transmission interval of the graph in seconds</td>
121  * </tr>
122  * </tbody>
123  * </table>
124  * </p>
125  * <p>
126  * <h2>CHANGE</h2>
127  * <table summary="" style="width:800px;">
128  * <thead>
129  * <tr>
130  * <th style="width:25%;">Variable</th>
131  * <th style="width:15%;">Type</th>
132  * <th style="width:60%;">Comments</th>
133  * </tr>
134  * </thead><tbody>
135  * <tr>
136  * <td>timestamp</td>
137  * <td>double</td>
138  * <td>time of the event, in simulation time seconds</td>
139  * </tr>
140  * <tr>
141  * <td>graphId</td>
142  * <td>String</td>
143  * <td>the unique id for the graph, e.g. a UUID string</td>
144  * </tr>
145  * <tr>
146  * <td>width</td>
147  * <td>int</td>
148  * <td>width of the graph in pixels</td>
149  * </tr>
150  * <tr>
151  * <td>height</td>
152  * <td>int</td>
153  * <td>height of the graph in pixels</td>
154  * </tr>
155  * <tr>
156  * <td>image data</td>
157  * <td>byte[]</td>
158  * <td>image in PNG format; starts with the standard 8-byte signature 89 50 4E 47 0D 0A 1A 0A.</td>
159  * </tr>
160  * </tbody>
161  * </table>
162  * </p>
163  * <p>
164  * <h2>DELETE</h2>
165  * <table summary="" style="width:800px;">
166  * <thead>
167  * <tr>
168  * <th style="width:25%;">Variable</th>
169  * <th style="width:15%;">Type</th>
170  * <th style="width:60%;">Comments</th>
171  * </tr>
172  * </thead><tbody>
173  * <tr>
174  * <td>timestamp</td>
175  * <td>double</td>
176  * <td>time of the event, in simulation time seconds</td>
177  * </tr>
178  * <tr>
179  * <td>graphId</td>
180  * <td>String</td>
181  * <td>the unique id for the graph that is removed</td>
182  * </tr>
183  * <tr>
184  * <td>width</td>
185  * <td>int</td>
186  * <td>width of the graph in pixels</td>
187  * </tr>
188  * <tr>
189  * <td>height</td>
190  * <td>int</td>
191  * <td>height of the graph in pixels</td>
192  * </tr>
193  * </tbody>
194  * </table>
195  * <br>
196  * Note: when two resolutions for the same graph are sent over the network, they have the same graphId but a different width
197  * and/or height. This means that the combination of graphId, width, and height creates a unique key for the graph.
198  * </p>
199  * <p>
200  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
201  * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
202  * <p>
203  * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 16, 2016 <br>
204  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
205  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
206  */
207 public class GraphTransceiver extends AbstractTransceiver
208 {
209     /** */
210     private static final long serialVersionUID = 20160919L;
211 
212     /** The Network for which the graph is made. */
213     private final Network network;
214 
215     /** The width of the graph, in pixels. */
216     private final int width;
217 
218     /** The height of the graph, in pixels. */
219     private final int height;
220 
221     /** The interval between generation of graphs. */
222     private final Duration transmissionInterval;
223 
224     // TODO handle the DELETE message
225 
226     /**
227      * Construct a new GraphTransceiver.
228      * @param connector Connector; the IMB connector
229      * @param simulator SimpleSimulatorInterface; the simulator
230      * @param network Network; the network
231      * @param width int; the width of the graph, in pixels
232      * @param height int; the height of the graph, in pixels
233      * @param plot AbstractOTSPlot; the graph
234      * @param transmissionInterval Duration; the interval between generation of graphs
235      * @throws IMBException when the message cannot be posted, or the scheduling of the publish event fails
236      */
237     public GraphTransceiver(final Connector connector, SimpleSimulatorInterface simulator, Network network, final int width,
238             final int height, final AbstractOTSPlot plot, final Duration transmissionInterval) throws IMBException
239     {
240         super("Graph", connector, simulator);
241         this.network = network;
242         this.width = width;
243         this.height = height;
244         this.transmissionInterval = transmissionInterval;
245 
246         List<Object> newMessage = new ArrayList<>();
247         newMessage.add(getSimulator().getSimulatorTime().getTime().si);
248         newMessage.add(plot.getId());
249         newMessage.add(width);
250         newMessage.add(height);
251         newMessage.add(plot.getCaption());
252         newMessage.add(plot.getGraphType().toString());
253         if (plot instanceof TrajectoryPlot)
254         {
255             Duration interval = ((TrajectoryPlot) plot).getSampleInterval();
256             newMessage.add(interval == null ? 0.0d : interval.si);
257         }
258         else if (plot instanceof ContourPlot)
259         {
260             newMessage.add(((ContourPlot) plot).getXAxis().getCurrentGranularity());
261         }
262         else
263         {
264             newMessage.add(0.0d);
265         }
266         newMessage.add(plot instanceof ContourPlot ? ((ContourPlot) plot).getYAxis().getCurrentGranularity() : 0.0d);
267         newMessage.add(this.network.getId());
268         newMessage.add(plot.getPath().size());
269         for (Lane lane : plot.getPath())
270         {
271             newMessage.add(lane.getParentLink().getId());
272             newMessage.add(lane.getId());
273         }
274         newMessage.add(transmissionInterval.si);
275 
276         getConnector().postIMBMessage("Graph", IMBEventType.NEW, newMessage.toArray());
277 
278         try
279         {
280             simulator.scheduleEventRel(this.transmissionInterval, this, this, "makePNG", new Object[] { plot });
281         }
282         catch (SimRuntimeException exception)
283         {
284             throw new IMBException(exception);
285         }
286     }
287 
288     /**
289      * @param plot the plot to generate the PNG for
290      * @throws IOException when the creation of the PNG has failed
291      * @throws IMBException when the transmission of the IMB message fails
292      * @throws SimRuntimeException when the scheduling of the next publish event fails
293      */
294     public void makePNG(final AbstractOTSPlot plot) throws IOException, IMBException, SimRuntimeException
295     {
296         byte[] png = plot.generatePNG(this.width, this.height);
297         getConnector().postIMBMessage("Graph", IMBEventType.CHANGE,
298                 new Object[] { getSimulator().getSimulatorTime().getTime().si, plot.getId(), this.width, this.height, png });
299         getSimulator().scheduleEventRel(this.transmissionInterval, this, this, "makePNG", new Object[] { plot });
300     }
301 }