AbstractSensor.java

  1. package org.opentrafficsim.road.network.lane.object.sensor;

  2. import org.djunits.value.vdouble.scalar.Length;
  3. import org.djutils.exceptions.Throw;
  4. import org.opentrafficsim.core.compatibility.Compatible;
  5. import org.opentrafficsim.core.geometry.OTSGeometryException;
  6. import org.opentrafficsim.core.geometry.OTSLine3D;
  7. import org.opentrafficsim.core.geometry.OTSPoint3D;
  8. import org.opentrafficsim.core.gtu.GTUDirectionality;
  9. import org.opentrafficsim.core.gtu.GTUType;
  10. import org.opentrafficsim.core.gtu.RelativePosition;
  11. import org.opentrafficsim.core.network.NetworkException;
  12. import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
  13. import org.opentrafficsim.road.network.lane.CrossSectionElement;
  14. import org.opentrafficsim.road.network.lane.Lane;
  15. import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;

  16. import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
  17. import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
  18. import nl.tudelft.simulation.language.d3.DirectedPoint;

  19. /**
  20.  * <p>
  21.  * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  22.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  23.  * <p>
  24.  * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
  25.  * initial version Dec 31, 2014 <br>
  26.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  27.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  28.  */
  29. public abstract class AbstractSensor extends AbstractLaneBasedObject implements SingleSensor
  30. {
  31.     /** */
  32.     private static final long serialVersionUID = 20141231L;

  33.     /** The relative position of the vehicle that triggers the sensor. */
  34.     private final RelativePosition.TYPE positionType;

  35.     /** The simulator for being able to generate an animation. */
  36.     private final DEVSSimulatorInterface.TimeDoubleUnit simulator;

  37.     /** The GTU types and driving directions that this sensor will trigger on. */
  38.     private final Compatible detectedGTUTypes;

  39.     /**
  40.      * Create a sensor on a lane at a position on that lane.
  41.      * @param id String; the id of the sensor.
  42.      * @param lane Lane; the lane for which this is a sensor.
  43.      * @param longitudinalPosition Length; the position (between 0.0 and the length of the Lane) of the sensor on the design
  44.      *            line of the lane.
  45.      * @param positionType RelativePosition.TYPE; the relative position type (e.g., FRONT, BACK) of the vehicle that triggers
  46.      *            the sensor.
  47.      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator (needed to generate the animation).
  48.      * @param geometry OTSLine3D; the geometry of the object, which provides its location and bounds as well
  49.      * @param elevation Length; elevation of the sensor
  50.      * @param detectedGTUTypes Compatible; The GTU types will trigger this sensor
  51.      * @throws NetworkException when the position on the lane is out of bounds
  52.      */
  53.     @SuppressWarnings("checkstyle:parameternumber")
  54.     public AbstractSensor(final String id, final Lane lane, final Length longitudinalPosition,
  55.             final RelativePosition.TYPE positionType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
  56.             final OTSLine3D geometry, final Length elevation, final Compatible detectedGTUTypes) throws NetworkException
  57.     {
  58.         super(id, lane, longitudinalPosition, geometry, elevation);
  59.         Throw.when(simulator == null, NullPointerException.class, "simulator is null");
  60.         Throw.when(positionType == null, NullPointerException.class, "positionType is null");
  61.         Throw.when(id == null, NullPointerException.class, "id is null");
  62.         this.positionType = positionType;
  63.         this.simulator = simulator;
  64.         this.detectedGTUTypes = detectedGTUTypes;
  65.        
  66.         init();
  67.        
  68.         getLane().addSensor(this); // Implements OTS-218
  69.     }

  70.     /**
  71.      * Create a sensor on a lane at a position on that lane at elevation <code>Sensor.DEFAULT_SENSOR_ELEVATION</code>.
  72.      * @param id String; the id of the sensor.
  73.      * @param lane Lane; the lane for which this is a sensor.
  74.      * @param longitudinalPosition Length; the position (between 0.0 and the length of the Lane) of the sensor on the design
  75.      *            line of the lane.
  76.      * @param positionType RelativePosition.TYPE; the relative position type (e.g., FRONT, BACK) of the vehicle that triggers
  77.      *            the sensor.
  78.      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator (needed to generate the animation).
  79.      * @param geometry OTSLine3D; the geometry of the object, which provides its location and bounds as well
  80.      * @param detectedGTUTypes Compatible; The GTU types will trigger this sensor
  81.      * @throws NetworkException when the position on the lane is out of bounds
  82.      */
  83.     public AbstractSensor(final String id, final Lane lane, final Length longitudinalPosition,
  84.             final RelativePosition.TYPE positionType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
  85.             final OTSLine3D geometry, final Compatible detectedGTUTypes) throws NetworkException
  86.     {
  87.         this(id, lane, longitudinalPosition, positionType, simulator, geometry, DEFAULT_SENSOR_ELEVATION, detectedGTUTypes);
  88.     }

  89.     /**
  90.      * Create a new AbstractSensor on a lane at a position on that lane at elevation
  91.      * <code>Sensor.DEFAULT_SENSOR_ELEVATION</code> and default geometry.
  92.      * @param id String; the id of the new AbstractSensor
  93.      * @param lane Lane; the lane on which the new AbstractSensor is positioned
  94.      * @param longitudinalPosition Length; the position (between 0.0 and the length of the Lane) of the sensor on the design
  95.      *            line of the lane
  96.      * @param positionType RelativePosition.TYPE; the relative position type (e.g., FRONT, BACK) of the vehicle that triggers
  97.      *            the sensor.
  98.      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator (needed to generate the animation).
  99.      * @param detectedGTUTypes Compatible; The GTU types will trigger this sensor
  100.      * @throws NetworkException when the position on the lane is out of bounds
  101.      */
  102.     public AbstractSensor(final String id, final Lane lane, final Length longitudinalPosition,
  103.             final RelativePosition.TYPE positionType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
  104.             final Compatible detectedGTUTypes) throws NetworkException
  105.     {
  106.         this(id, lane, longitudinalPosition, positionType, simulator, makeGeometry(lane, longitudinalPosition, 0.9),
  107.                 detectedGTUTypes);
  108.     }

  109.     /**
  110.      * Make a geometry perpendicular to the center line of the lane with a length of 90% of the width of the lane.
  111.      * @param lane Lane; the lane for which to make a perpendicular geometry
  112.      * @param longitudinalPosition Length; the position on the lane
  113.      * @param relativeWidth double; lane width to use
  114.      * @return an OTSLine3D that describes the line
  115.      * @throws NetworkException in case the sensor point on the center line of the lane cannot be found
  116.      */
  117.     protected static OTSLine3D makeGeometry(final Lane lane, final Length longitudinalPosition, final double relativeWidth)
  118.             throws NetworkException
  119.     {
  120.         try
  121.         {
  122.             double w50 = lane.getWidth(longitudinalPosition).si * 0.5 * relativeWidth;
  123.             DirectedPoint c = lane.getCenterLine().getLocation(longitudinalPosition);
  124.             double a = c.getRotZ();
  125.             OTSPoint3D p1 = new OTSPoint3D(c.x + w50 * Math.cos(a + Math.PI / 2), c.y - w50 * Math.sin(a + Math.PI / 2), c.z);
  126.             OTSPoint3D p2 = new OTSPoint3D(c.x - w50 * Math.cos(a + Math.PI / 2), c.y + w50 * Math.sin(a + Math.PI / 2), c.z);
  127.             return new OTSLine3D(p1, p2);
  128.         }
  129.         catch (OTSGeometryException exception)
  130.         {
  131.             throw new NetworkException(exception);
  132.         }
  133.     }

  134.     /** {@inheritDoc} */
  135.     @Override
  136.     public final void trigger(final LaneBasedGTU gtu)
  137.     {
  138.         fireTimedEvent(SingleSensor.SENSOR_TRIGGER_EVENT, new Object[] { getId(), this, gtu, this.positionType },
  139.                 getSimulator().getSimulatorTime());
  140.         triggerResponse(gtu);
  141.     }

  142.     /**
  143.      * Implementation of the response to a trigger of this sensor by a GTU.
  144.      * @param gtu LaneBasedGTU; the lane based GTU that triggered this sensor.
  145.      */
  146.     protected abstract void triggerResponse(LaneBasedGTU gtu);

  147.     /** {@inheritDoc} */
  148.     @Override
  149.     public final RelativePosition.TYPE getPositionType()
  150.     {
  151.         return this.positionType;
  152.     }

  153.     /** {@inheritDoc} */
  154.     @Override
  155.     public final DEVSSimulatorInterface.TimeDoubleUnit getSimulator()
  156.     {
  157.         return this.simulator;
  158.     }

  159.     /** {@inheritDoc} */
  160.     @SuppressWarnings("checkstyle:designforextension")
  161.     @Override
  162.     public int hashCode()
  163.     {
  164.         final int prime = 31;
  165.         int result = 1;
  166.         result = prime * result + ((getLane() == null) ? 0 : getLane().hashCode());
  167.         long temp;
  168.         temp = Double.doubleToLongBits(getLongitudinalPosition().si);
  169.         result = prime * result + (int) (temp ^ (temp >>> 32));
  170.         result = prime * result + ((this.positionType == null) ? 0 : this.positionType.hashCode());
  171.         return result;
  172.     }

  173.     /** {@inheritDoc} */
  174.     @SuppressWarnings({ "checkstyle:needbraces", "checkstyle:designforextension" })
  175.     @Override
  176.     public boolean equals(final Object obj)
  177.     {
  178.         if (this == obj)
  179.             return true;
  180.         if (obj == null)
  181.             return false;
  182.         if (getClass() != obj.getClass())
  183.             return false;
  184.         AbstractSensor other = (AbstractSensor) obj;
  185.         if (this.getLane() == null)
  186.         {
  187.             if (other.getLane() != null)
  188.                 return false;
  189.         }
  190.         else if (!this.getLane().equals(other.getLane()))
  191.             return false;
  192.         if (Double.doubleToLongBits(this.getLongitudinalPosition().si) != Double
  193.                 .doubleToLongBits(other.getLongitudinalPosition().si))
  194.             return false;
  195.         if (this.positionType == null)
  196.         {
  197.             if (other.positionType != null)
  198.                 return false;
  199.         }
  200.         else if (!this.positionType.equals(other.positionType))
  201.             return false;
  202.         return true;
  203.     }

  204.     /** {@inheritDoc} */
  205.     @SuppressWarnings("checkstyle:designforextension")
  206.     @Override
  207.     public int compareTo(final SingleSensor o)
  208.     {
  209.         if (this.getLane() != o.getLane())
  210.         {
  211.             return this.getLane().hashCode() < o.getLane().hashCode() ? -1 : 1;
  212.         }
  213.         if (this.getLongitudinalPosition().si != o.getLongitudinalPosition().si)
  214.         {
  215.             return this.getLongitudinalPosition().si < o.getLongitudinalPosition().si ? -1 : 1;
  216.         }
  217.         if (!this.positionType.equals(o.getPositionType()))
  218.         {
  219.             return this.positionType.hashCode() < o.getPositionType().hashCode() ? -1 : 1;
  220.         }
  221.         if (!this.equals(o))
  222.         {
  223.             return this.hashCode() < o.hashCode() ? -1 : 1;
  224.         }
  225.         return 0;
  226.     }

  227.     /** {@inheritDoc} */
  228.     @Override
  229.     @SuppressWarnings("checkstyle:designforextension")
  230.     public String toString()
  231.     {
  232.         return "Sensor[" + getId() + "]";
  233.     }

  234.     /** {@inheritDoc} */
  235.     @Override
  236.     public abstract AbstractSensor clone(CrossSectionElement newCSE, SimulatorInterface.TimeDoubleUnit newSimulator)
  237.             throws NetworkException;

  238.     /** {@inheritDoc} */
  239.     @Override
  240.     public final boolean isCompatible(final GTUType gtuType, final GTUDirectionality directionality)
  241.     {
  242.         return this.detectedGTUTypes.isCompatible(gtuType, directionality);
  243.     }

  244.     /**
  245.      * Retrieve the object that decides if a particular GTU type is detected when passing in a particular direction.
  246.      * @return Compatible; the object that decides if a particular GTU type is detected when passing in a particular direction
  247.      */
  248.     public final Compatible getDetectedGTUTypes()
  249.     {
  250.         return this.detectedGTUTypes;
  251.     }

  252. }