package org.opentrafficsim.imb.transceiver.urbanstrategy; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.djunits.value.vdouble.scalar.Duration; import org.opentrafficsim.core.network.Network; import org.opentrafficsim.graphs.AbstractOTSPlot; import org.opentrafficsim.graphs.ContourPlot; import org.opentrafficsim.graphs.TrajectoryPlot; import org.opentrafficsim.imb.IMBException; import org.opentrafficsim.imb.connector.Connector; import org.opentrafficsim.imb.connector.Connector.IMBEventType; import org.opentrafficsim.imb.transceiver.AbstractTransceiver; import org.opentrafficsim.road.network.lane.Lane; import org.opentrafficsim.simulationengine.SimpleSimulatorInterface; import nl.tudelft.simulation.dsol.SimRuntimeException; /** * OTS can publish graphs to IMB, e.g. trajectory graphs, flow graphs and density graphs.
* When a graph is published for the first time, a NEW message is sent to IMB to identify the graph, the image resolution, and * the lane(s) for which the graph is created. The CHANGE message is posted whenever an updated graph is posted. When a Graph is * no longer published, a DELETE event is posted. The Graph NEW messages are posted after the Network NEW, Node NEW, Link NEW, * and Lane NEW messages are posted, as it has to be able to identify Lanes. *

* *

NEW

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
VariableTypeComments
timestampdoubletime of the event, in simulation time seconds
graphIdStringa unique id for the graph, e.g. a UUID string
widthintwidth of the graph in pixels
heightintheight of the graph in pixels
descriptionStringtextual description of the graph
graphTypeStringtype of graph; one of TRAJECTORY, SPEED_CONTOUR, ACCELERATION_CONTOUR, DENSITY_CONTOUR, FLOW_CONTOUR, * FUNDAMENTAL_DIAGRAM
time_resolutiondoubleFor the four types of contour graphs, and the trajectory graph, it provides the aggregation in seconds. 0.0 for other * types of graphs. When the value is 0.0 for the trajectory graph, the graph is updated on the basis of events from the * GTU.
value_resolutiondoubleFor the four types of contour graphs, it provides the aggregation in the SI unit of the value. 0.0 for other types of * graphs
networkIdStringid of the Network for which the Graph is made
numberOfLanesintnumber of Link-Lane combinations for this Graph
linkId_1Stringid of the first Link; unique within the Network
laneId_1Stringid of the first Lane, unique within the Link
...  
linkId_nStringid of the last Link; unique within the Network
laneId_nStringid of the last Lane, unique within the Link
transmissionIntervaldoubletransmission interval of the graph in seconds
*

*

*

CHANGE

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
VariableTypeComments
timestampdoubletime of the event, in simulation time seconds
graphIdStringthe unique id for the graph, e.g. a UUID string
widthintwidth of the graph in pixels
heightintheight of the graph in pixels
image databyte[]image in PNG format; starts with the standard 8-byte signature 89 50 4E 47 0D 0A 1A 0A.
*

*

*

DELETE

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
VariableTypeComments
timestampdoubletime of the event, in simulation time seconds
graphIdStringthe unique id for the graph that is removed
widthintwidth of the graph in pixels
heightintheight of the graph in pixels
*
* Note: when two resolutions for the same graph are sent over the network, they have the same graphId but a different width * and/or height. This means that the combination of graphId, width, and height creates a unique key for the graph. *

*

* Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License. *

* @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 16, 2016
* @author Alexander Verbraeck * @author Peter Knoppers */ public class GraphTransceiver extends AbstractTransceiver { /** */ private static final long serialVersionUID = 20160919L; /** The Network for which the graph is made. */ private final Network network; /** The width of the graph, in pixels. */ private final int width; /** The height of the graph, in pixels. */ private final int height; /** The interval between generation of graphs. */ private final Duration transmissionInterval; // TODO handle the DELETE message /** * Construct a new GraphTransceiver. * @param connector Connector; the IMB connector * @param simulator SimpleSimulatorInterface; the simulator * @param network Network; the network * @param width int; the width of the graph, in pixels * @param height int; the height of the graph, in pixels * @param plot AbstractOTSPlot; the graph * @param transmissionInterval Duration; the interval between generation of graphs * @throws IMBException when the message cannot be posted, or the scheduling of the publish event fails */ public GraphTransceiver(final Connector connector, SimpleSimulatorInterface simulator, Network network, final int width, final int height, final AbstractOTSPlot plot, final Duration transmissionInterval) throws IMBException { super("Graph", connector, simulator); this.network = network; this.width = width; this.height = height; this.transmissionInterval = transmissionInterval; List newMessage = new ArrayList<>(); newMessage.add(getSimulator().getSimulatorTime().getTime().si); newMessage.add(plot.getId()); newMessage.add(width); newMessage.add(height); newMessage.add(plot.getCaption()); newMessage.add(plot.getGraphType().toString()); if (plot instanceof TrajectoryPlot) { Duration interval = ((TrajectoryPlot) plot).getSampleInterval(); newMessage.add(interval == null ? 0.0d : interval.si); } else if (plot instanceof ContourPlot) { newMessage.add(((ContourPlot) plot).getXAxis().getCurrentGranularity()); } else { newMessage.add(0.0d); } newMessage.add(plot instanceof ContourPlot ? ((ContourPlot) plot).getYAxis().getCurrentGranularity() : 0.0d); newMessage.add(this.network.getId()); newMessage.add(plot.getPath().size()); for (Lane lane : plot.getPath()) { newMessage.add(lane.getParentLink().getId()); newMessage.add(lane.getId()); } newMessage.add(transmissionInterval.si); getConnector().postIMBMessage("Graph", IMBEventType.NEW, newMessage.toArray()); try { simulator.scheduleEventRel(this.transmissionInterval, this, this, "makePNG", new Object[] { plot }); } catch (SimRuntimeException exception) { throw new IMBException(exception); } } /** * @param plot the plot to generate the PNG for * @throws IOException when the creation of the PNG has failed * @throws IMBException when the transmission of the IMB message fails * @throws SimRuntimeException when the scheduling of the next publish event fails */ public void makePNG(final AbstractOTSPlot plot) throws IOException, IMBException, SimRuntimeException { byte[] png = plot.generatePNG(this.width, this.height); getConnector().postIMBMessage("Graph", IMBEventType.CHANGE, new Object[] { getSimulator().getSimulatorTime().getTime().si, plot.getId(), this.width, this.height, png }); getSimulator().scheduleEventRel(this.transmissionInterval, this, this, "makePNG", new Object[] { plot }); } }