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