package org.opentrafficsim.imb.transceiver.urbanstrategy;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
import org.opentrafficsim.core.geometry.OTSGeometryException;
import org.opentrafficsim.core.geometry.OTSPoint3D;
import org.opentrafficsim.core.gtu.GTU;
import org.opentrafficsim.core.network.Link;
import org.opentrafficsim.core.network.Network;
import org.opentrafficsim.core.network.OTSNetwork;
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.CrossSectionLink;
import nl.tudelft.simulation.event.EventInterface;
import nl.tudelft.simulation.event.EventType;
import nl.tudelft.simulation.event.TimedEvent;
/**
* OTS publishes events about the links to IMB, e.g. to know about the number of vehicles on a link.
* 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
* coordinates of its design line, and the start and end nodes of the link. The CHANGE message is posted whenever a vehicle
* enters or leaves a link. When a Link is removed from the network, a DELETE event is posted. The Link NEW messages are posted
* after the Network NEW and Node NEW messages are posted.
*
*
*
NEW
*
*
*
*
Variable
*
Type
*
Comments
*
*
*
*
timestamp
*
double
*
time of the event, in simulation time seconds
*
*
*
networkId
*
String
*
Id of the Network where the Link resides
*
*
*
linkId
*
String
*
id of the Link; unique within the Network
*
*
*
startNodeId
*
String
*
id of the start node, provided in a Node NEW message
*
*
*
endNodeId
*
String
*
id of the end node, provided in a Node NEW message
*
*
*
designLine.numberOfPoints
*
int
*
number of points for the design line of the Link. The number of doubles that follow is 3 times this number
*
*
*
designLine.x1
*
double
*
x-coordinate of the first point of the design line
*
*
*
designLine.y1
*
double
*
y-coordinate of the first point of the design line
*
*
*
designLine.z1
*
double
*
z-coordinate of the first point of the design line
*
*
*
...
*
*
*
*
*
designLine.xn
*
double
*
x-coordinate of the last point of the design line
*
*
*
designLine.yn
*
double
*
y-coordinate of the last point of the design line
*
*
*
designLine.zn
*
double
*
z-coordinate of the last point of the design line
*
*
*
*
*
*
CHANGE
*
*
*
*
Variable
*
Type
*
Comments
*
*
*
*
timestamp
*
double
*
time of the event, in simulation time seconds
*
*
*
networkId
*
String
*
Id of the Network where the Link resides
*
*
*
linkId
*
String
*
id of the Link
*
*
*
isVehicleAdded
*
boolean
*
true if vehicle added, false if vehicle removed
*
*
*
gtuId
*
String
*
id of the gtu that was added or removed from the Link
*
*
*
countAfterEvent
*
int
*
the number of vehicles on the link after the event
*
*
*
*
*
*
DELETE
*
*
*
*
Variable
*
Type
*
Comments
*
*
*
*
timestamp
*
double
*
time of the event, in simulation time seconds
*
*
*
networkId
*
String
*
Id of the Network where the Link resides
*
*
*
linkId
*
String
*
id of the Link that is removed from the Network
*
*
*
*
*
* 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 13, 2016
* @author Alexander Verbraeck
* @author Peter Knoppers
* @author Wouter Schakel
*/
public class LinkGTUTransceiver extends AbstractTransceiver
{
/** */
private static final long serialVersionUID = 20160913L;
/** the OTS network on which Links are registered. */
private final OTSNetwork network;
/**
* Construct a new LinkGTUTransceiver.
* @param connector Connector; the IMB connector through which this transceiver communicates
* @param simulator OTSDEVSSimulatorInterface; the simulator to schedule the incoming notifications on
* @param network OTSNetwork; the OTS network on which Links are registered
* @throws IMBException when the registration of one of the channels fails
* @throws NullPointerException in case one of the arguments is null.
*/
public LinkGTUTransceiver(final Connector connector, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
throws IMBException
{
super("Link_GTU", connector, simulator);
this.network = network;
// listen on network changes and register the listener to all the Links
addListeners();
}
/**
* Ensure that we get notified about newly created and destroyed Links instrument all currently existing Links.
* @throws IMBException in case notification of existing Lanes fails
*/
private void addListeners() throws IMBException
{
// Subscribe to all future link creation and removal events.
this.network.addListener(this, Network.LINK_ADD_EVENT);
this.network.addListener(this, Network.LINK_REMOVE_EVENT);
// For already existing links, post ourselves a LINK_ADD_EVENT
for (Link link : this.network.getLinkMap().values())
{
try
{
this.notify(new TimedEvent(Network.LINK_ADD_EVENT, this.network, link.getId(),
getSimulator().getSimulatorTime()));
}
catch (RemoteException exception)
{
throw new IMBException(exception);
}
}
}
/** {@inheritDoc} */
@Override
public void notify(final EventInterface event) throws RemoteException
{
EventType type = event.getType();
if (type.equals(Network.LINK_ADD_EVENT))
{
Link link = this.network.getLink((String) event.getContent());
if (!(link instanceof CrossSectionLink))
{
System.err.println("LinkGTUTransceiver.notify NEW - Don't know how to handle a non-CrossSectionLink");
return;
}
CrossSectionLink csl = (CrossSectionLink) link;
// post the Link_GTU message to register the link on the IMB bus
try
{
getConnector().postIMBMessage("Link_GTU", IMBEventType.NEW, transformNew(event));
}
catch (IMBException exception)
{
System.err.println("LinkGTUTransceiver.notify NEW - IMBException: " + exception.getMessage());
return;
}
csl.addListener(this, Link.GTU_ADD_EVENT);
csl.addListener(this, Link.GTU_REMOVE_EVENT);
// Post ourselves a GTU_ADD_EVENT for every GTU currently on the link
int gtuCount = link.getGTUs().size();
for (GTU gtu : link.getGTUs())
{
try
{
this.notify(new TimedEvent(Link.GTU_ADD_EVENT, link,
new Object[] { gtu.getId(), gtu, gtuCount }, getSimulator().getSimulatorTime()));
}
catch (RemoteException exception)
{
System.err.println("LinkGTUTransceiver.notify NEW - RemoteException: " + exception.getMessage());
return;
}
}
}
else if (type.equals(Network.LINK_REMOVE_EVENT))
{
Link link = this.network.getLink((String) event.getContent());
if (!(link instanceof CrossSectionLink))
{
System.err.println("LinkGTUTransceiver.notify DELETE - Don't know how to handle a non-CrossSectionLink");
return;
}
CrossSectionLink csl = (CrossSectionLink) link;
csl.removeListener(this, Link.GTU_ADD_EVENT);
csl.removeListener(this, Link.GTU_REMOVE_EVENT);
// post the Node message to de-register the link from the IMB bus
try
{
getConnector().postIMBMessage("Link_GTU", IMBEventType.DELETE, transformDelete(event));
}
catch (IMBException exception)
{
System.err.println("LinkGTUTransceiver.notify DELETE - IMBException: " + exception.getMessage());
return;
}
}
else if (type.equals(Link.GTU_ADD_EVENT) || type.equals(Link.GTU_REMOVE_EVENT))
{
try
{
getConnector().postIMBMessage("Link_GTU", IMBEventType.CHANGE, transformChange(event));
}
catch (IMBException exception)
{
System.err.println("LinkGTUTransceiver.notify CHANGE - IMBException: " + exception.getMessage());
return;
}
}
else
{
System.err.println("LinkGTUTransceiver.notify - Unhandled event: " + event);
}
}
/**
* Transform the addition of a link to the network to a corresponding IMB message.
* @param event the event to transform to a NEW message.
* @return the NEW payload
*/
public Object[] transformNew(final EventInterface event)
{
if (Network.LINK_ADD_EVENT.equals(event.getType()))
{
String linkId = (String) event.getContent();
Link link = this.network.getLink(linkId);
double timestamp = getSimulator().getSimulatorTime().getTime().si;
List