package org.opentrafficsim.road.gtu.lane;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.naming.NamingException;
import org.djunits.unit.AccelerationUnit;
import org.djunits.unit.LengthUnit;
import org.djunits.value.vdouble.scalar.Acceleration;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.opentrafficsim.core.dsol.OTSAnimatorInterface;
import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
import org.opentrafficsim.core.geometry.OTSGeometryException;
import org.opentrafficsim.core.gtu.GTUException;
import org.opentrafficsim.core.gtu.GTUType;
import org.opentrafficsim.core.gtu.RelativePosition;
import org.opentrafficsim.core.gtu.RelativePosition.TYPE;
import org.opentrafficsim.core.gtu.animation.GTUColorer;
import org.opentrafficsim.core.network.NetworkException;
import org.opentrafficsim.core.network.OTSNetwork;
import org.opentrafficsim.core.network.route.Route;
import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
import org.opentrafficsim.road.network.lane.DirectedLanePosition;
import nl.tudelft.simulation.dsol.SimRuntimeException;
import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
import nl.tudelft.simulation.immutablecollections.Immutable;
import nl.tudelft.simulation.immutablecollections.ImmutableHashSet;
import nl.tudelft.simulation.immutablecollections.ImmutableLinkedHashMap;
import nl.tudelft.simulation.immutablecollections.ImmutableMap;
import nl.tudelft.simulation.immutablecollections.ImmutableSet;
import nl.tudelft.simulation.language.reflection.ClassUtil;
/**
* Augments the AbstractLaneBasedIndividualGTU with a LaneBasedIndividualCarBuilder and animation support
*
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* @version $Revision: 1401 $, $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, by $Author: averbraeck $,
* initial version Oct 22, 2014
* @author Alexander Verbraeck
* @author Peter Knoppers
*/
public class LaneBasedIndividualGTU extends AbstractLaneBasedIndividualGTU
{
/** */
private static final long serialVersionUID = 20141025L;
/** The animation. */
private Renderable2D animation;
/** Sensing positions. */
private final Map relativePositions = new HashMap<>();
/** cached front. */
private final RelativePosition frontPos;
/** cached rear. */
private final RelativePosition rearPos;
/** contour points. */
private final Set contourPoints = new HashSet<>();
/**
* Construct a new LaneBasedIndividualCar.
* @param id ID; the id of the GTU
* @param gtuType GTUTYpe; the type of GTU, e.g. TruckType, CarType, BusType
* @param length Length; the maximum length of the GTU (parallel with driving direction)
* @param width Length; the maximum width of the GTU (perpendicular to driving direction)
* @param maximumSpeed Speed;the maximum speed of the GTU (in the driving direction)
* @param simulator OTSDEVSSimulatorInterface; the simulator
* @param network the network that the GTU is initially registered in
* @throws NamingException if an error occurs when adding the animation handler
* @throws GTUException when a parameter is invalid
*/
@SuppressWarnings("checkstyle:parameternumber")
public LaneBasedIndividualGTU(final String id, final GTUType gtuType, final Length length, final Length width,
final Speed maximumSpeed, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
throws NamingException, GTUException
{
super(id, gtuType, length, width, maximumSpeed, simulator, network);
// sensor positions.
// We take the rear position of the Car to be the reference point. So the front is the length
// of the Car away from the reference point in the positive (driving) X-direction.
Length dx2 = new Length(getLength().getSI() / 2.0, LengthUnit.METER);
Length dy2 = new Length(getWidth().getSI() / 2.0, LengthUnit.METER);
this.frontPos = new RelativePosition(dx2, Length.ZERO, Length.ZERO, RelativePosition.FRONT);
this.relativePositions.put(RelativePosition.FRONT, this.frontPos);
this.rearPos = new RelativePosition(dx2.neg(), Length.ZERO, Length.ZERO, RelativePosition.REAR);
this.relativePositions.put(RelativePosition.REAR, this.rearPos);
this.relativePositions.put(RelativePosition.REFERENCE, RelativePosition.REFERENCE_POSITION);
this.relativePositions.put(RelativePosition.CENTER,
new RelativePosition(Length.ZERO, Length.ZERO, Length.ZERO, RelativePosition.CENTER));
// Contour positions. For now, a rectangle with the four corners.
for (int i = -1; i <= 1; i += 2)
{
for (int j = -1; j <= 1; j += 2)
{
this.contourPoints
.add(new RelativePosition(dx2.multiplyBy(i), dy2.multiplyBy(j), Length.ZERO, RelativePosition.CONTOUR));
}
}
setMaximumAcceleration(new Acceleration(1.8, AccelerationUnit.METER_PER_SECOND_2));
setMaximumDeceleration(new Acceleration(-3.5, AccelerationUnit.METER_PER_SECOND_2));
}
/**
* @param strategicalPlanner the strategical planner (e.g., route determination) to use
* @param initialLongitudinalPositions the initial positions of the car on one or more lanes with their directions
* @param initialSpeed the initial speed of the car on the lane
* @param animationClass Class<? extends Renderable2D>; the class for animation or null if no animation
* @param gtuColorer GTUColorer; the GTUColorer that will be linked from the animation to determine the color (may be null
* in which case a default will be used)
* @throws NetworkException when the GTU cannot be placed on the given lane
* @throws SimRuntimeException when the move method cannot be scheduled
* @throws GTUException when initial values are not correct
* @throws OTSGeometryException when the initial path is wrong
*/
public final void initWithAnimation(final LaneBasedStrategicalPlanner strategicalPlanner,
final Set initialLongitudinalPositions, final Speed initialSpeed,
final Class extends Renderable2D> animationClass, final GTUColorer gtuColorer)
throws NetworkException, SimRuntimeException, GTUException, OTSGeometryException
{
super.init(strategicalPlanner, initialLongitudinalPositions, initialSpeed);
// animation
if (getSimulator() instanceof OTSAnimatorInterface && animationClass != null)
{
try
{
Constructor> constructor;
if (null == gtuColorer)
{
constructor = ClassUtil.resolveConstructor(animationClass, new Object[] { this, getSimulator() });
this.animation = (Renderable2D) constructor.newInstance(this, getSimulator());
}
else
{
constructor =
ClassUtil.resolveConstructor(animationClass, new Object[] { this, getSimulator(), gtuColorer });
this.animation = (Renderable2D) constructor.newInstance(this, getSimulator(), gtuColorer);
}
}
catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException
| IllegalArgumentException | InvocationTargetException exception)
{
throw new GTUException("Could not instantiate car animation of type " + animationClass.getName(), exception);
}
}
}
/** {@inheritDoc} */
@Override
public final RelativePosition getFront()
{
return this.frontPos;
}
/** {@inheritDoc} */
@Override
public final RelativePosition getRear()
{
return this.rearPos;
}
/** {@inheritDoc} */
@Override
public final RelativePosition getCenter()
{
return this.relativePositions.get(RelativePosition.CENTER);
}
/** {@inheritDoc} */
@Override
public final ImmutableMap getRelativePositions()
{
return new ImmutableLinkedHashMap<>(this.relativePositions, Immutable.WRAP);
}
/** {@inheritDoc} */
@Override
public final ImmutableSet getContourPoints()
{
return new ImmutableHashSet<>(this.contourPoints, Immutable.WRAP);
}
/** {@inheritDoc} */
@Override
public final void destroy()
{
if (this.animation != null)
{
try
{
this.animation.destroy();
this.animation = null;
}
catch (Exception e)
{
System.err.println("Error when destroying the animation of car: " + this.getId());
}
}
super.destroy();
}
/** {@inheritDoc} */
@Override
public final String toString()
{
return "LaneBasedIndividualGTU [id=" + getId() + "]";
}
/**
* Build an individual car and use easy setter methods to instantiate the car. Typical use looks like:
*
*
* LaneBasedIndividualCar<String> car = new LaneBasedIndividualCarBuilder<String>().setId("Car:"+nr)
* .setLength(new Length(4.0, METER))....build();
*
* or
*
* LaneBasedIndividualCarBuilder<String> carBuilder = new LaneBasedIndividualCarBuilder<String>();
* carBuilder.setId("Car:"+nr);
* carBuilder.setLength(new Length(4.0, METER));
* carBuilder.setWidth(new Length(1.8, METER));
* ...
* LaneBasedIndividualCar<String> car = carBuilder.build();
*
*
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands.
* All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* @version $Revision: 1401 $, $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, by $Author: averbraeck $,
* initial Feb 3, 2015
* @author Alexander Verbraeck
*/
@SuppressWarnings("checkstyle:hiddenfield")
public static class LaneBasedIndividualCarBuilder implements Serializable
{
/** */
private static final long serialVersionUID = 20160000L;
/** The id of the GTU. */
private String id = null;
/** The type of GTU, e.g. TruckType, CarType, BusType. */
private GTUType gtuType = null;
/** The initial positions of the car on one or more lanes. */
private Set initialLongitudinalPositions = null;
/** The initial speed of the car on the lane. */
private Speed initialSpeed = null;
/** The length of the GTU (parallel with driving direction). */
private Length length = null;
/** The width of the GTU (perpendicular to driving direction). */
private Length width = null;
/** The maximum speed of the GTU (in the driving direction). */
private Speed maximumSpeed = null;
/** The simulator. */
private OTSDEVSSimulatorInterface simulator = null;
/** Animation. */
private Class extends Renderable2D> animationClass = null;
/** GTUColorer. */
private GTUColorer gtuColorer = null;
/** Network. */
private OTSNetwork network = null;
/**
* @param id set id
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setId(final String id)
{
this.id = id;
return this;
}
/**
* @param gtuType set gtuType
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setGtuType(final GTUType gtuType)
{
this.gtuType = gtuType;
return this;
}
/**
* @param initialLongitudinalPositions set initialLongitudinalPositions
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setInitialLongitudinalPositions(
final Set initialLongitudinalPositions)
{
this.initialLongitudinalPositions = initialLongitudinalPositions;
return this;
}
/**
* @param initialSpeed set initialSpeed
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setInitialSpeed(final Speed initialSpeed)
{
this.initialSpeed = initialSpeed;
return this;
}
/**
* @param length set length
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setLength(final Length length)
{
this.length = length;
return this;
}
/**
* @param width set width
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setWidth(final Length width)
{
this.width = width;
return this;
}
/**
* @param maximumSpeed set maximumSpeed
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setMaximumSpeed(final Speed maximumSpeed)
{
this.maximumSpeed = maximumSpeed;
return this;
}
/**
* @param simulator set simulator
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setSimulator(final OTSDEVSSimulatorInterface simulator)
{
this.simulator = simulator;
return this;
}
/**
* @param animationClass set animation class
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setAnimationClass(final Class extends Renderable2D> animationClass)
{
this.animationClass = animationClass;
return this;
}
/**
* @param gtuColorer set gtuColorer.
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setGtuColorer(final GTUColorer gtuColorer)
{
this.gtuColorer = gtuColorer;
return this;
}
/**
* @param network set network
* @return the class itself for chaining the setters
*/
public final LaneBasedIndividualCarBuilder setNetwork(final OTSNetwork network)
{
this.network = network;
return this;
}
/**
* @return id.
*/
public final String getId()
{
return this.id;
}
/**
* @return gtuType.
*/
public final GTUType getGtuType()
{
return this.gtuType;
}
/**
* @return initialLongitudinalPositions.
*/
public final Set getInitialLongitudinalPositions()
{
return this.initialLongitudinalPositions;
}
/**
* @return initialSpeed.
*/
public final Speed getInitialSpeed()
{
return this.initialSpeed;
}
/**
* @return length.
*/
public final Length getLength()
{
return this.length;
}
/**
* @return width.
*/
public final Length getWidth()
{
return this.width;
}
/**
* @return maximumSpeed.
*/
public final Speed getMaximumSpeed()
{
return this.maximumSpeed;
}
/**
* @return simulator.
*/
public final OTSDEVSSimulatorInterface getSimulator()
{
return this.simulator;
}
/**
* @return animationClass.
*/
public final Class extends Renderable2D> getAnimationClass()
{
return this.animationClass;
}
/**
* @return gtuColorer.
*/
public final GTUColorer getGtuColorer()
{
return this.gtuColorer;
}
/**
* @return network
*/
public final OTSNetwork getNetwork()
{
return this.network;
}
/**
* Build one LaneBasedIndividualCar.
* @param laneBasedStrategicalPlannerFactory factory for the strategical planner
* @param route route
* @return the built Car with the set properties
* @throws Exception when not all required values have been set
*/
public final LaneBasedIndividualGTU build(
final LaneBasedStrategicalPlannerFactory extends LaneBasedStrategicalPlanner> laneBasedStrategicalPlannerFactory,
final Route route) throws Exception
{
if (null == this.id || null == this.gtuType || null == this.initialLongitudinalPositions
|| null == this.initialSpeed || null == this.length || null == this.width || null == this.maximumSpeed
|| null == this.simulator || null == this.network)
{
// TODO Should throw a more specific Exception type
throw new GTUException("factory settings incomplete");
}
LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU(this.id, this.gtuType, this.length, this.width,
this.maximumSpeed, this.simulator, this.network);
gtu.initWithAnimation(laneBasedStrategicalPlannerFactory.create(gtu, route), this.initialLongitudinalPositions,
this.initialSpeed, this.animationClass, this.gtuColorer);
return gtu;
}
/** {@inheritDoc} */
@Override
public final String toString()
{
return "LaneBasedIndividualCarBuilder [id=" + this.id + ", gtuType=" + this.gtuType
+ ", initialLongitudinalPositions=" + this.initialLongitudinalPositions + ", initialSpeed="
+ this.initialSpeed + ", length=" + this.length + ", width=" + this.width + ", maximumSpeed="
+ this.maximumSpeed + ", strategicalPlanner=" + "]";
}
}
}