View Javadoc
1   package org.opentrafficsim.imb.transceiver.urbanstrategy;
2   
3   import java.awt.Color;
4   import java.rmi.RemoteException;
5   
6   import org.djunits.value.vdouble.scalar.Acceleration;
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.djunits.value.vdouble.scalar.Speed;
9   import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
10  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
11  import org.opentrafficsim.core.gtu.GTU;
12  import org.opentrafficsim.core.gtu.GTUException;
13  import org.opentrafficsim.core.gtu.TurnIndicatorStatus;
14  import org.opentrafficsim.core.network.Network;
15  import org.opentrafficsim.core.network.OTSNetwork;
16  import org.opentrafficsim.imb.IMBException;
17  import org.opentrafficsim.imb.connector.Connector;
18  import org.opentrafficsim.imb.transceiver.AbstractTransceiver;
19  import org.opentrafficsim.imb.transceiver.OTSToIMBTransformer;
20  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
21  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
22  import org.opentrafficsim.road.network.lane.Lane;
23  
24  import nl.tudelft.simulation.event.EventInterface;
25  import nl.tudelft.simulation.event.TimedEvent;
26  import nl.tudelft.simulation.language.d3.DirectedPoint;
27  
28  /**
29   * The GTUTransceiver publishes the following information on the IMB bus:
30   * <ol>
31   * <li>LaneBasedGTU.LANEBASED_INIT_EVENT as an IMB NEW event for a GTU entering the network. This also is done for GTUs that
32   * have been registered at the start of the simulation.</li>
33   * <li>LaneBasedGTU.LANEBASED_MOVE_EVENT as an IMB CHANGE event for a GTU that moves on the network.</li>
34   * <li>LaneBasedGTU.LANEBASED_DESTROY_EVENT as an IMB DELETE event for a GTU that leaves the network.</li>
35   * </ol>
36   * GTUs are identified by their gtuId.
37   * <p>
38   * OTS publishes events about GTUs (vehicles) to IMB, e.g. to calculate statistics or emissions from the vehicles or to display
39   * them in the US animation.
40   * </p>
41   * <p>
42   * When a GTU is created, a NEW message is sent to IMB to identify the GTU and its initial characteristics, including the lane
43   * on which it resides with its reference point, and the position on the lane. The CHANGE message is posted whenever a vehicle
44   * initiates a new OperationalPlan, which coincides with a MOVE Event in OTS. When a GTU is removed from the network, a DELETE
45   * event is posted. The GTU NEW messages are posted after the Network NEW, Node NEW, Link NEW, and Lane NEW messages are posted
46   * to ensure the Lane on which the GTU resides is known.
47   * </p>
48   * <p>
49   * The longitudinal position of a GTU on a lane is the (projected) position on the center line of the lane, in meters. The
50   * zero-point is chosen at the start of the center line of the lane that has been provided in the Lane_GTU NEW message.
51   * </p>
52   * <p>
53   * <style>table,th,td {border:1px solid grey; border-style:solid; text-align:left; border-collapse: collapse;}</style>
54   * <h2>NEW</h2>
55   * <table summary="" style="width:800px;">
56   * <thead>
57   * <tr>
58   * <th style="width:25%;">Variable</th>
59   * <th style="width:15%;">Type</th>
60   * <th style="width:60%;">Comments</th>
61   * </tr>
62   * </thead><tbody>
63   * <tr>
64   * <td>timestamp</td>
65   * <td>double</td>
66   * <td>time of the event, in simulation time seconds</td>
67   * </tr>
68   * <tr>
69   * <td>gtuId</td>
70   * <td>String</td>
71   * <td>id of the GTU that has been added to the simulation</td>
72   * </tr>
73   * <tr>
74   * <td>position.x</td>
75   * <td>double</td>
76   * <td>x-coordinate of the gtu position in (gis) coordinates</td>
77   * </tr>
78   * <tr>
79   * <td>position.y</td>
80   * <td>double</td>
81   * <td>y-coordinate of the gtu position in (gis) coordinates</td>
82   * </tr>
83   * <tr>
84   * <td>position.z</td>
85   * <td>double</td>
86   * <td>z-coordinate of the gtu position in (gis) coordinates</td>
87   * </tr>
88   * <tr>
89   * <td>position.rotZ</td>
90   * <td>double</td>
91   * <td>angle in the x-y plane of the gtu</td>
92   * </tr>
93   * <tr>
94   * <td>networkId</td>
95   * <td>String</td>
96   * <td>Id of the Network where the gtu's reference point is</td>
97   * </tr>
98   * <tr>
99   * <td>linkId</td>
100  * <td>String</td>
101  * <td>id of the Link; unique within the Network</td>
102  * </tr>
103  * <tr>
104  * <td>laneId</td>
105  * <td>String</td>
106  * <td>id of the Lane, unique within the Link</td>
107  * </tr>
108  * <tr>
109  * <td>longitudinalPosition</td>
110  * <td>double</td>
111  * <td>gtu position on the center line of the lane, in meters</td>
112  * </tr>
113  * <tr>
114  * <td>length</td>
115  * <td>double</td>
116  * <td>length of the gtu, in meters</td>
117  * </tr>
118  * <tr>
119  * <td>width</td>
120  * <td>double</td>
121  * <td>width of the gtu, in meters</td>
122  * </tr>
123  * <tr>
124  * <td>baseColor.R</td>
125  * <td>byte</td>
126  * <td>R-component of the gtu's base color</td>
127  * </tr>
128  * <tr>
129  * <td>baseColor.G</td>
130  * <td>byte</td>
131  * <td>G-component of the gtu's base color</td>
132  * </tr>
133  * <tr>
134  * <td>baseColor.B</td>
135  * <td>byte</td>
136  * <td>B-component of the gtu's base color</td>
137  * </tr>
138  * </tbody>
139  * </table>
140  * </p>
141  * <p>
142  * <h2>CHANGE</h2>
143  * <table summary="" style="width:800px;">
144  * <thead>
145  * <tr>
146  * <th style="width:25%;">Variable</th>
147  * <th style="width:15%;">Type</th>
148  * <th style="width:60%;">Comments</th>
149  * </tr>
150  * </thead><tbody>
151  * <tr>
152  * <td>timestamp</td>
153  * <td>double</td>
154  * <td>time of the event, in simulation time seconds</td>
155  * </tr>
156  * <tr>
157  * <td>gtuId</td>
158  * <td>String</td>
159  * <td>id of the vehicle that has a new position</td>
160  * </tr>
161  * <tr>
162  * <td>position.x</td>
163  * <td>double</td>
164  * <td>x-coordinate of the gtu position at the timestamp</td>
165  * </tr>
166  * <tr>
167  * <td>position.y</td>
168  * <td>double</td>
169  * <td>y-coordinate of the gtu position at the timestamp</td>
170  * </tr>
171  * <tr>
172  * <td>position.z</td>
173  * <td>double</td>
174  * <td>z-coordinate of the gtu position at the timestamp</td>
175  * </tr>
176  * <tr>
177  * <td>position.rotZ</td>
178  * <td>double</td>
179  * <td>angle in the x-y plane of the gtu</td>
180  * </tr>
181  * <tr>
182  * <td>networkId</td>
183  * <td>String</td>
184  * <td>Id of the Network where the gtu's reference point is</td>
185  * </tr>
186  * <tr>
187  * <td>linkId</td>
188  * <td>String</td>
189  * <td>id of the Link; unique within the Network</td>
190  * </tr>
191  * <tr>
192  * <td>laneId</td>
193  * <td>String</td>
194  * <td>id of the Lane, unique within the Link</td>
195  * </tr>
196  * <tr>
197  * <td>longitudinalPosition</td>
198  * <td>double</td>
199  * <td>gtu position on the center line of the lane, in meters</td>
200  * </tr>
201  * <tr>
202  * <td>speed</td>
203  * <td>double</td>
204  * <td>current speed of the gtu, in m/s</td>
205  * </tr>
206  * <tr>
207  * <td>acceleration</td>
208  * <td>double</td>
209  * <td>current acceleration of the gtu, in m/s2</td>
210  * </tr>
211  * <tr>
212  * <td>turnIndicatorStatus</td>
213  * <td>String</td>
214  * <td>one of {NONE, LEFT, RIGHT, HAZARD, NOTPRESENT}</td>
215  * </tr>
216  * <tr>
217  * <td>brakingLights</td>
218  * <td>boolean</td>
219  * <td>braking lights on or off</td>
220  * </tr>
221  * <tr>
222  * <td>odometer</td>
223  * <td>double</td>
224  * <td>odometer reading of the GTU, in meters</td>
225  * </tr>
226  * </tbody>
227  * </table>
228  * </p>
229  * <p>
230  * <h2>DELETE</h2>
231  * <table summary="" style="width:800px;">
232  * <thead>
233  * <tr>
234  * <th style="width:25%;">Variable</th>
235  * <th style="width:15%;">Type</th>
236  * <th style="width:60%;">Comments</th>
237  * </tr>
238  * </thead><tbody>
239  * <tr>
240  * <td>timestamp</td>
241  * <td>double</td>
242  * <td>time of the event, in simulation time seconds</td>
243  * </tr>
244  * <tr>
245  * <td>gtuId</td>
246  * <td>String</td>
247  * <td>id of the GTU that that is removed from the simulation</td>
248  * </tr>
249  * <tr>
250  * <td>lastPosition.x</td>
251  * <td>double</td>
252  * <td>x-coordinate of the gtu position at removal</td>
253  * </tr>
254  * <tr>
255  * <td>lastPosition.y</td>
256  * <td>double</td>
257  * <td>y-coordinate of the gtu position at removal</td>
258  * </tr>
259  * <tr>
260  * <td>lastPosition.z</td>
261  * <td>double</td>
262  * <td>z-coordinate of the gtu position at removal</td>
263  * </tr>
264  * <tr>
265  * <td>position.rotZ</td>
266  * <td>double</td>
267  * <td>angle in the x-y plane of the gtu</td>
268  * </tr>
269  * <tr>
270  * <td>lastNetworkId</td>
271  * <td>String</td>
272  * <td>Id of the Network where the Link resides</td>
273  * </tr>
274  * <tr>
275  * <td>lastLinkId</td>
276  * <td>String</td>
277  * <td>id of the Link where the GTU was destroyed</td>
278  * </tr>
279  * <tr>
280  * <td>lastLaneId</td>
281  * <td>String</td>
282  * <td>id of the Lane in the Link where the GTU was destroyed</td>
283  * </tr>
284  * <tr>
285  * <td>lastLongitudinalPosition</td>
286  * <td>double</td>
287  * <td>gtu position on the center line of the lane, in meters</td>
288  * </tr>
289  * <tr>
290  * <td>odometer</td>
291  * <td>double</td>
292  * <td>final odometer reading of the GTU, in meters</td>
293  * </tr>
294  * </tbody>
295  * </table>
296  * </p>
297  * <p>
298  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
299  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
300  * </p>
301  * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
302  * initial version Sep 11, 2016 <br>
303  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
304  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
305  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
306  */
307 public class GTUTransceiver extends AbstractTransceiver
308 {
309     /** */
310     private static final long serialVersionUID = 20160911L;
311 
312     /** the OTS network on which GTUs are registered. */
313     private final OTSNetwork network;
314 
315     /**
316      * Construct a new GTUTransceiver.
317      * @param connector Connector; the IMB connector through which this transceiver communicates
318      * @param simulator OTSDEVSSimulatorInterface; the simulator to schedule the incoming notifications on
319      * @param network OTSNetwork; the OTS network on which GTUs are registered
320      * @throws IMBException when the registration of one of the channels fails
321      * @throws NullPointerException in case one of the arguments is null.
322      */
323     public GTUTransceiver(final Connector connector, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
324             throws IMBException
325     {
326         super("GTU", connector, simulator);
327         this.network = network;
328 
329         // listen on network changes and register the listeners to the GTUs
330         addListeners();
331     }
332 
333     /**
334      * Ensure that we get notified about newly created and destroyed GTUs and for each already existing GTU generate a
335      * GTU_ADD_EVENT.
336      * @throws IMBException in case notification of existing GTU fails
337      */
338     private void addListeners() throws IMBException
339     {
340         this.network.addListener(this, Network.GTU_ADD_EVENT);
341         this.network.addListener(this, Network.GTU_REMOVE_EVENT);
342 
343         // Also add all GTUs that were instantiated when the model was constructed, and re-send their INIT event...
344         for (GTU gtu : this.network.getGTUs())
345         {
346             try
347             {
348                 this.notify(new TimedEvent<OTSSimTimeDouble>(Network.GTU_ADD_EVENT, this.network, gtu.getId(),
349                         gtu.getSimulator().getSimulatorTime()));
350                 LaneBasedGTU laneBasedGTU = (LaneBasedGTU) gtu;
351                 DirectedLanePosition dlp = laneBasedGTU.getReferencePosition();
352                 this.notify(new TimedEvent<OTSSimTimeDouble>(LaneBasedGTU.LANEBASED_INIT_EVENT, gtu,
353                         new Object[] { gtu.getId(), gtu.getLocation(), gtu.getLength(), gtu.getWidth(), gtu.getBaseColor(),
354                                 dlp.getLane(), dlp.getGtuDirection() },
355                         gtu.getSimulator().getSimulatorTime()));
356             }
357             catch (RemoteException | GTUException exception)
358             {
359                 exception.printStackTrace();
360             }
361         }
362     }
363 
364     /** {@inheritDoc} */
365     @Override
366     public void notify(final EventInterface event) throws RemoteException
367     {
368         try
369         {
370             // do not call super.notify(event); we will do that only when needed.
371 
372             if (event.getType().equals(Network.GTU_ADD_EVENT))
373             {
374                 String gtuId = event.getContent().toString();
375                 GTU gtu = this.network.getGTU(gtuId);
376                 gtu.addListener(this, LaneBasedGTU.LANEBASED_INIT_EVENT, true);
377                 gtu.addListener(this, LaneBasedGTU.LANEBASED_MOVE_EVENT, true);
378                 gtu.addListener(this, LaneBasedGTU.LANEBASED_DESTROY_EVENT, true);
379             }
380 
381             else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
382             {
383                 String gtuId = event.getContent().toString();
384                 GTU gtu = this.network.getGTU(gtuId);
385                 gtu.removeListener(this, LaneBasedGTU.LANEBASED_INIT_EVENT);
386                 gtu.removeListener(this, LaneBasedGTU.LANEBASED_MOVE_EVENT);
387                 gtu.removeListener(this, LaneBasedGTU.LANEBASED_DESTROY_EVENT);
388             }
389 
390             else if (event.getType().equals(LaneBasedGTU.LANEBASED_INIT_EVENT))
391             {
392                 // register the IMB channel for this GTU, and send NEW payload
393                 getConnector().postIMBMessage("GTU", Connector.IMBEventType.NEW, transformNew(event));
394             }
395 
396             else if (event.getType().equals(LaneBasedGTU.LANEBASED_MOVE_EVENT))
397             {
398                 // send CHANGE payload
399                 // TODO -- does not work because GTU is registered only once
400                 // super.notify(event);
401                 getConnector().postIMBMessage("GTU", Connector.IMBEventType.CHANGE, transformChange(event));
402             }
403 
404             else if (event.getType().equals(LaneBasedGTU.LANEBASED_DESTROY_EVENT))
405             {
406                 // send DELETE payload
407                 getConnector().postIMBMessage("GTU", Connector.IMBEventType.DELETE, transformDelete(event));
408             }
409         }
410         catch (IMBException exception)
411         {
412             // TODO implement proper error handling
413             exception.printStackTrace();
414         }
415     }
416 
417     /**
418      * Transform the addition of a GTU to the network to a corresponding IMB message.
419      * @param event the event to transform to a NEW message.
420      * @return the NEW payload
421      */
422     private Object[] transformNew(final EventInterface event)
423     {
424         if (LaneBasedGTU.LANEBASED_INIT_EVENT.equals(event.getType()))
425         {
426             // content contains: [String gtuId, DirectedPoint initialPosition, Length length, Length width, Color
427             // gtuBaseColor,
428             // Lane referenceLane, Length positionOnReferenceLane]
429             Object[] content = (Object[]) event.getContent();
430             double timestamp = getSimulator().getSimulatorTime().getTime().si;
431             String gtuId = content[0].toString();
432             DirectedPoint location = (DirectedPoint) content[1];
433             Lane lane = (Lane) content[5];
434             double longitudinalPosition = ((Length) content[6]).si;
435             double length = ((Length) content[2]).si;
436             double width = ((Length) content[3]).si;
437             Color color = (Color) content[4];
438             return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(),
439                     lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition,
440                     length, width, (byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue() };
441         }
442         System.err.println("LaneGTUTransceiver.transformNew: Don't know how to transform event " + event);
443         return new Object[] {};
444     }
445 
446     /**
447      * Transform the deletion of a GTU from the network to a corresponding IMB message.
448      * @param event the event to transform to a DELETE message.
449      * @return the DELETE payload
450      */
451     private Object[] transformDelete(final EventInterface event)
452     {
453         if (LaneBasedGTU.LANEBASED_DESTROY_EVENT.equals(event.getType()))
454         {
455             // content contains: [String gtuId, DirectedPoint lastPosition, Length odometer, Lane referenceLane,
456             // Length positionOnReferenceLane]
457             Object[] content = (Object[]) event.getContent();
458             double timestamp = getSimulator().getSimulatorTime().getTime().si;
459             String gtuId = content[0].toString();
460             DirectedPoint location = (DirectedPoint) content[1];
461             double odometer = ((Length) content[2]).si;
462             Lane lane = (Lane) content[3];
463             double longitudinalPosition = ((Length) content[4]).si;
464             return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(),
465                     lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition,
466                     odometer };
467         }
468         System.err.println("LaneGTUTransceiver.transformNew: Don't know how to transform event " + event);
469         return new Object[] {};
470     }
471 
472     /**
473      * Transform the move of a GTU in the network to a corresponding IMB message.
474      * @param event the event to transform to a CHANGE message.
475      * @return the CHANGE payload
476      */
477     private Object[] transformChange(final EventInterface event)
478     {
479         // moveInfo contains: {String gtuId, DirectedPoint position, Speed speed, Acceleration acceleration,
480         // TurnIndicatorStatus turnIndicatorStatus, Length odometer, Lane referenceLane, Length positionOnReferenceLane}
481         Object[] moveInfo = (Object[]) event.getContent();
482         String gtuId = moveInfo[0].toString();
483         DirectedPoint location = (DirectedPoint) moveInfo[1];
484         LaneBasedGTU gtu = (LaneBasedGTU) event.getSource();
485         Lane lane = (Lane) moveInfo[6];
486         double longitudinalPosition = ((Length) moveInfo[7]).si;
487         double speed = ((Speed) moveInfo[2]).si;
488         double acceleration = ((Acceleration) moveInfo[3]).si;
489         double timestamp = gtu.getSimulator().getSimulatorTime().getTime().si;
490         String turnIndicatorStatus = ((TurnIndicatorStatus) moveInfo[4]).toString();
491         double odometer = ((Length) moveInfo[5]).si;
492         boolean brakingLights = acceleration < 0.0; // TODO proper function for isBraking()
493         return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(),
494                 lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition,
495                 speed, acceleration, turnIndicatorStatus, brakingLights, odometer };
496     }
497 
498     /**
499      * Transform the LaneBasedGTU.LANEBASED_MOVE_EVENT content to a corresponding IMB message.
500      * <p>
501      * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
502      * <br>
503      * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
504      * </p>
505      * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
506      * initial version Sep 11, 2016 <br>
507      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
508      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
509      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
510      */
511     static class GTUTransformerChange implements OTSToIMBTransformer
512     {
513         /** {@inheritDoc} */
514         @Override
515         public Object[] transform(final EventInterface event)
516         {
517             // moveInfo contains: {String gtuId, DirectedPoint position, Speed speed, Acceleration acceleration,
518             // TurnIndicatorStatus turnIndicatorStatus, Length odometer, Lane referenceLane, Length positionOnReferenceLane}
519             Object[] moveInfo = (Object[]) event.getContent();
520             String gtuId = moveInfo[0].toString();
521             DirectedPoint location = (DirectedPoint) moveInfo[1];
522             LaneBasedGTU gtu = (LaneBasedGTU) event.getSource();
523             Lane lane = (Lane) moveInfo[6];
524             double longitudinalPosition = ((Length) moveInfo[7]).si;
525             double speed = ((Speed) moveInfo[2]).si;
526             double acceleration = ((Acceleration) moveInfo[3]).si;
527             double timestamp = gtu.getSimulator().getSimulatorTime().getTime().si;
528             String turnIndicatorStatus = ((TurnIndicatorStatus) moveInfo[4]).toString();
529             double odometer = ((Length) moveInfo[5]).si;
530             boolean brakingLights = acceleration < 0.0; // TODO proper function for isBraking()
531             return new Object[] { timestamp, gtuId, location.x, location.y, location.z, location.getRotZ(),
532                     lane.getParentLink().getNetwork().getId(), lane.getParentLink().getId(), lane.getId(), longitudinalPosition,
533                     speed, acceleration, turnIndicatorStatus, brakingLights, odometer };
534         }
535     }
536 }