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 }