View Javadoc
1   package org.opentrafficsim.imb.transceiver.urbanstrategy;
2   
3   import java.rmi.RemoteException;
4   import java.util.ArrayList;
5   import java.util.List;
6   
7   import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
8   import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
9   import org.opentrafficsim.core.geometry.OTSGeometryException;
10  import org.opentrafficsim.core.geometry.OTSPoint3D;
11  import org.opentrafficsim.core.gtu.GTU;
12  import org.opentrafficsim.core.network.Link;
13  import org.opentrafficsim.core.network.Network;
14  import org.opentrafficsim.core.network.OTSNetwork;
15  import org.opentrafficsim.imb.IMBException;
16  import org.opentrafficsim.imb.connector.Connector;
17  import org.opentrafficsim.imb.connector.Connector.IMBEventType;
18  import org.opentrafficsim.imb.transceiver.AbstractTransceiver;
19  import org.opentrafficsim.road.network.lane.CrossSectionLink;
20  
21  import nl.tudelft.simulation.event.EventInterface;
22  import nl.tudelft.simulation.event.EventType;
23  import nl.tudelft.simulation.event.TimedEvent;
24  
25  /**
26   * OTS publishes events about the links to IMB, e.g. to know about the number of vehicles on a link.<br>
27   * At the start of the OTS simulation, or when a Link is added later, a NEW message is sent to IMB to identify the link, the
28   * coordinates of its design line, and the start and end nodes of the link. The CHANGE message is posted whenever a vehicle
29   * enters or leaves a link. When a Link is removed from the network, a DELETE event is posted. The Link NEW messages are posted
30   * after the Network NEW and Node NEW messages are posted.
31   * <p>
32   * <style>table,th,td {border:1px solid grey; border-style:solid; text-align:left; border-collapse: collapse;}</style>
33   * <h2>NEW</h2>
34   * <table summary="" style="width:800px;">
35   * <thead>
36   * <tr>
37   * <th style="width:25%;">Variable</th>
38   * <th style="width:15%;">Type</th>
39   * <th style="width:60%;">Comments</th>
40   * </tr>
41   * </thead><tbody>
42   * <tr>
43   * <td>timestamp</td>
44   * <td>double</td>
45   * <td>time of the event, in simulation time seconds</td>
46   * </tr>
47   * <tr>
48   * <td>networkId</td>
49   * <td>String</td>
50   * <td>Id of the Network where the Link resides</td>
51   * </tr>
52   * <tr>
53   * <td>linkId</td>
54   * <td>String</td>
55   * <td>id of the Link; unique within the Network</td>
56   * </tr>
57   * <tr>
58   * <td>startNodeId</td>
59   * <td>String</td>
60   * <td>id of the start node, provided in a Node NEW message</td>
61   * </tr>
62   * <tr>
63   * <td>endNodeId</td>
64   * <td>String</td>
65   * <td>id of the end node, provided in a Node NEW message</td>
66   * </tr>
67   * <tr>
68   * <td>designLine.numberOfPoints</td>
69   * <td>int</td>
70   * <td>number of points for the design line of the Link. The number of doubles that follow is 3 times this number</td>
71   * </tr>
72   * <tr>
73   * <td>designLine.x1</td>
74   * <td>double</td>
75   * <td>x-coordinate of the first point of the design line</td>
76   * </tr>
77   * <tr>
78   * <td>designLine.y1</td>
79   * <td>double</td>
80   * <td>y-coordinate of the first point of the design line</td>
81   * </tr>
82   * <tr>
83   * <td>designLine.z1</td>
84   * <td>double</td>
85   * <td>z-coordinate of the first point of the design line</td>
86   * </tr>
87   * <tr>
88   * <td>...</td>
89   * <td></td>
90   * <td></td>
91   * </tr>
92   * <tr>
93   * <td>designLine.xn</td>
94   * <td>double</td>
95   * <td>x-coordinate of the last point of the design line</td>
96   * </tr>
97   * <tr>
98   * <td>designLine.yn</td>
99   * <td>double</td>
100  * <td>y-coordinate of the last point of the design line</td>
101  * </tr>
102  * <tr>
103  * <td>designLine.zn</td>
104  * <td>double</td>
105  * <td>z-coordinate of the last point of the design line</td>
106  * </tr>
107  * </tbody>
108  * </table>
109  * </p>
110  * <p>
111  * <h2>CHANGE</h2>
112  * <table summary="" style="width:800px;">
113  * <thead>
114  * <tr>
115  * <th style="width:25%;">Variable</th>
116  * <th style="width:15%;">Type</th>
117  * <th style="width:60%;">Comments</th>
118  * </tr>
119  * </thead><tbody>
120  * <tr>
121  * <td>timestamp</td>
122  * <td>double</td>
123  * <td>time of the event, in simulation time seconds</td>
124  * </tr>
125  * <tr>
126  * <td>networkId</td>
127  * <td>String</td>
128  * <td>Id of the Network where the Link resides</td>
129  * </tr>
130  * <tr>
131  * <td>linkId</td>
132  * <td>String</td>
133  * <td>id of the Link</td>
134  * </tr>
135  * <tr>
136  * <td>isVehicleAdded</td>
137  * <td>boolean</td>
138  * <td>true if vehicle added, false if vehicle removed</td>
139  * </tr>
140  * <tr>
141  * <td>gtuId</td>
142  * <td>String</td>
143  * <td>id of the gtu that was added or removed from the Link</td>
144  * </tr>
145  * <tr>
146  * <td>countAfterEvent</td>
147  * <td>int</td>
148  * <td>the number of vehicles on the link after the event</td>
149  * </tr>
150  * </tbody>
151  * </table>
152  * </p>
153  * <p>
154  * <h2>DELETE</h2>
155  * <table summary="" style="width:800px;">
156  * <thead>
157  * <tr>
158  * <th style="width:25%;">Variable</th>
159  * <th style="width:15%;">Type</th>
160  * <th style="width:60%;">Comments</th>
161  * </tr>
162  * </thead><tbody>
163  * <tr>
164  * <td>timestamp</td>
165  * <td>double</td>
166  * <td>time of the event, in simulation time seconds</td>
167  * </tr>
168  * <tr>
169  * <td>networkId</td>
170  * <td>String</td>
171  * <td>Id of the Network where the Link resides</td>
172  * </tr>
173  * <tr>
174  * <td>linkId</td>
175  * <td>String</td>
176  * <td>id of the Link that is removed from the Network</td>
177  * </tr>
178  * </tbody>
179  * </table>
180  * </p>
181  * <p>
182  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
183  * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
184  * </p>
185  * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 13, 2016 <br>
186  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
187  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
188  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
189  */
190 public class LinkGTUTransceiver extends AbstractTransceiver
191 {
192     /** */
193     private static final long serialVersionUID = 20160913L;
194 
195     /** the OTS network on which Links are registered. */
196     private final OTSNetwork network;
197 
198     /**
199      * Construct a new LinkGTUTransceiver.
200      * @param connector Connector; the IMB connector through which this transceiver communicates
201      * @param simulator OTSDEVSSimulatorInterface; the simulator to schedule the incoming notifications on
202      * @param network OTSNetwork; the OTS network on which Links are registered
203      * @throws IMBException when the registration of one of the channels fails
204      * @throws NullPointerException in case one of the arguments is null.
205      */
206     public LinkGTUTransceiver(final Connector connector, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
207             throws IMBException
208     {
209         super("Link_GTU", connector, simulator);
210         this.network = network;
211 
212         // listen on network changes and register the listener to all the Links
213         addListeners();
214     }
215 
216     /**
217      * Ensure that we get notified about newly created and destroyed Links instrument all currently existing Links.
218      * @throws IMBException in case notification of existing Lanes fails
219      */
220     private void addListeners() throws IMBException
221     {
222         // Subscribe to all future link creation and removal events.
223         this.network.addListener(this, Network.LINK_ADD_EVENT);
224         this.network.addListener(this, Network.LINK_REMOVE_EVENT);
225 
226         // For already existing links, post ourselves a LINK_ADD_EVENT
227         for (Link link : this.network.getLinkMap().values())
228         {
229             try
230             {
231                 this.notify(new TimedEvent<OTSSimTimeDouble>(Network.LINK_ADD_EVENT, this.network, link.getId(),
232                         getSimulator().getSimulatorTime()));
233             }
234             catch (RemoteException exception)
235             {
236                 throw new IMBException(exception);
237             }
238         }
239     }
240 
241     /** {@inheritDoc} */
242     @Override
243     public void notify(final EventInterface event) throws RemoteException
244     {
245         EventType type = event.getType();
246         if (type.equals(Network.LINK_ADD_EVENT))
247         {
248             Link link = this.network.getLink((String) event.getContent());
249             if (!(link instanceof CrossSectionLink))
250             {
251                 System.err.println("LinkGTUTransceiver.notify NEW - Don't know how to handle a non-CrossSectionLink");
252                 return;
253             }
254             CrossSectionLink csl = (CrossSectionLink) link;
255 
256             // post the Link_GTU message to register the link on the IMB bus
257             try
258             {
259                 getConnector().postIMBMessage("Link_GTU", IMBEventType.NEW, transformNew(event));
260             }
261             catch (IMBException exception)
262             {
263                 System.err.println("LinkGTUTransceiver.notify NEW - IMBException: " + exception.getMessage());
264                 return;
265             }
266 
267             csl.addListener(this, Link.GTU_ADD_EVENT);
268             csl.addListener(this, Link.GTU_REMOVE_EVENT);
269 
270             // Post ourselves a GTU_ADD_EVENT for every GTU currently on the link
271             int gtuCount = link.getGTUs().size();
272             for (GTU gtu : link.getGTUs())
273             {
274                 try
275                 {
276                     this.notify(new TimedEvent<OTSSimTimeDouble>(Link.GTU_ADD_EVENT, link,
277                             new Object[] { gtu.getId(), gtu, gtuCount }, getSimulator().getSimulatorTime()));
278                 }
279                 catch (RemoteException exception)
280                 {
281                     System.err.println("LinkGTUTransceiver.notify NEW - RemoteException: " + exception.getMessage());
282                     return;
283                 }
284             }
285         }
286 
287         else if (type.equals(Network.LINK_REMOVE_EVENT))
288         {
289             Link link = this.network.getLink((String) event.getContent());
290             if (!(link instanceof CrossSectionLink))
291             {
292                 System.err.println("LinkGTUTransceiver.notify DELETE - Don't know how to handle a non-CrossSectionLink");
293                 return;
294             }
295             CrossSectionLink csl = (CrossSectionLink) link;
296             csl.removeListener(this, Link.GTU_ADD_EVENT);
297             csl.removeListener(this, Link.GTU_REMOVE_EVENT);
298 
299             // post the Node message to de-register the link from the IMB bus
300             try
301             {
302                 getConnector().postIMBMessage("Link_GTU", IMBEventType.DELETE, transformDelete(event));
303             }
304             catch (IMBException exception)
305             {
306                 System.err.println("LinkGTUTransceiver.notify DELETE - IMBException: " + exception.getMessage());
307                 return;
308             }
309         }
310 
311         else if (type.equals(Link.GTU_ADD_EVENT) || type.equals(Link.GTU_REMOVE_EVENT))
312         {
313             try
314             {
315                 getConnector().postIMBMessage("Link_GTU", IMBEventType.CHANGE, transformChange(event));
316             }
317             catch (IMBException exception)
318             {
319                 System.err.println("LinkGTUTransceiver.notify CHANGE - IMBException: " + exception.getMessage());
320                 return;
321             }
322         }
323 
324         else
325         {
326             System.err.println("LinkGTUTransceiver.notify - Unhandled event: " + event);
327         }
328     }
329 
330     /**
331      * Transform the addition of a link to the network to a corresponding IMB message.
332      * @param event the event to transform to a NEW message.
333      * @return the NEW payload
334      */
335     public Object[] transformNew(final EventInterface event)
336     {
337         if (Network.LINK_ADD_EVENT.equals(event.getType()))
338         {
339             String linkId = (String) event.getContent();
340             Link link = this.network.getLink(linkId);
341             double timestamp = getSimulator().getSimulatorTime().getTime().si;
342             List<Object> resultList = new ArrayList<>();
343             resultList.add(timestamp);
344             resultList.add(this.network.getId());
345             resultList.add(linkId);
346             resultList.add(link.getStartNode().getId());
347             resultList.add(link.getEndNode().getId());
348             resultList.add(link.getDesignLine().size());
349             for (int i = 0; i < link.getDesignLine().size(); i++)
350             {
351                 try
352                 {
353                     OTSPoint3D p = link.getDesignLine().get(i);
354                     resultList.add(p.x);
355                     resultList.add(p.y);
356                     resultList.add(p.z);
357                 }
358                 catch (OTSGeometryException exception)
359                 {
360                     exception.printStackTrace();
361                     resultList.add(0.0d);
362                     resultList.add(0.0d);
363                     resultList.add(0.0d);
364                 }
365             }
366             return resultList.toArray();
367         }
368         System.err.println("LinkGTUTransceiver.transformNew: Don't know how to transform event " + event);
369         return new Object[] {};
370     }
371 
372     /**
373      * Transform the GTU added or removed event content to a corresponding IMB message.
374      * @param event the event to transform to a CHANGE message.
375      * @return the CHANGE payload
376      */
377     public Object[] transformChange(final EventInterface event)
378     {
379         Object[] gtuInfo = (Object[]) event.getContent();
380         String gtuId = (String) gtuInfo[0];
381         int countAfterEvent = (Integer) gtuInfo[2];
382         Link link = (Link) event.getSource();
383         double timestamp = getSimulator().getSimulatorTime().getTime().si;
384         if (Link.GTU_ADD_EVENT.equals(event.getType()))
385         {
386             return new Object[] { timestamp, link.getNetwork().getId(), link.getId(), true, gtuId, countAfterEvent };
387         }
388         else if (Link.GTU_REMOVE_EVENT.equals(event.getType()))
389         {
390             return new Object[] { timestamp, link.getNetwork().getId(), link.getId(), false, gtuId, countAfterEvent };
391         }
392         System.err.println("LinkGTUTransceiver.transformChange: Don't know how to transform event " + event);
393         return new Object[] {};
394     }
395 
396     /**
397      * Transform the removal of a link to the network to a corresponding IMB message.
398      * @param event the event to transform to a DELETE message.
399      * @return the DELETE payload
400      */
401     public Object[] transformDelete(final EventInterface event)
402     {
403         if (Network.LINK_REMOVE_EVENT.equals(event.getType()))
404         {
405             String linkId = (String) event.getContent();
406             double timestamp = getSimulator().getSimulatorTime().getTime().si;
407             return new Object[] { timestamp, this.network.getId(), linkId };
408         }
409         System.err.println("LinkGTUTransceiver.transformDelete: Don't know how to transform event " + event);
410         return new Object[] {};
411     }
412 
413 }