LaneDirection.java

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

  2. import java.io.Serializable;
  3. import java.util.LinkedHashSet;
  4. import java.util.Set;

  5. import org.djunits.value.vdouble.scalar.Length;
  6. import org.djutils.exceptions.Try;
  7. import org.djutils.immutablecollections.ImmutableMap;
  8. import org.opentrafficsim.core.geometry.OTSGeometryException;
  9. import org.opentrafficsim.core.gtu.GTUDirectionality;
  10. import org.opentrafficsim.core.network.LateralDirectionality;
  11. import org.opentrafficsim.core.network.LinkDirection;
  12. import org.opentrafficsim.core.network.NetworkException;
  13. import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;

  14. import nl.tudelft.simulation.language.d3.DirectedPoint;

  15. /**
  16.  * Combines a Lane with its GTUDirectionality.
  17.  * <p>
  18.  * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  19.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  20.  * </p>
  21.  * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
  22.  * initial version Mar 30, 2016 <br>
  23.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  24.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  25.  */
  26. public class LaneDirection implements Serializable
  27. {
  28.     /** */
  29.     private static final long serialVersionUID = 20160330L;

  30.     /** The lane. */
  31.     private final Lane lane;

  32.     /** The GTU direction to drive on this lane. */
  33.     private final GTUDirectionality direction;

  34.     /**
  35.      * @param lane Lane; the lane
  36.      * @param direction GTUDirectionality; the direction to drive on this lane
  37.      */
  38.     public LaneDirection(final Lane lane, final GTUDirectionality direction)
  39.     {
  40.         super();
  41.         this.lane = lane;
  42.         this.direction = direction;
  43.     }

  44.     /**
  45.      * @return the lane
  46.      */
  47.     public final Lane getLane()
  48.     {
  49.         return this.lane;
  50.     }

  51.     /**
  52.      * @return the direction to drive on this lane
  53.      */
  54.     public final GTUDirectionality getDirection()
  55.     {
  56.         return this.direction;
  57.     }

  58.     /**
  59.      * Returns the covered distance driven to the given fractional position.
  60.      * @param fraction double; fractional position
  61.      * @return Length; covered distance driven to the given fractional position
  62.      */
  63.     public final Length coveredDistance(final double fraction)
  64.     {
  65.         if (this.direction.isPlus())
  66.         {
  67.             return getLane().getLength().times(fraction);
  68.         }
  69.         return getLane().getLength().times(1.0 - fraction);
  70.     }

  71.     /**
  72.      * Returns the remaining distance to be driven from the given fractional position.
  73.      * @param fraction double; fractional position
  74.      * @return Length; remaining distance to be driven from the given fractional position
  75.      */
  76.     public final Length remainingDistance(final double fraction)
  77.     {
  78.         if (this.direction.isPlus())
  79.         {
  80.             return getLane().getLength().times(1.0 - fraction);
  81.         }
  82.         return getLane().getLength().times(fraction);
  83.     }

  84.     /**
  85.      * Returns the fraction along the design line for having covered the given distance.
  86.      * @param distance Length; covered distance
  87.      * @return double; fraction along the design line for having covered the given distance
  88.      */
  89.     public final double fractionAtCoveredDistance(final Length distance)
  90.     {
  91.         double f = this.lane.fraction(distance);
  92.         if (this.getDirection().isMinus())
  93.         {
  94.             f = 1.0 - f;
  95.         }
  96.         return f;
  97.     }

  98.     /**
  99.      * Returns the next lane and direction.
  100.      * @param gtu LaneBasedGTU; gtu
  101.      * @return LaneDirection; next lane and direction, {@code null} if none
  102.      */
  103.     public final LaneDirection getNextLaneDirection(final LaneBasedGTU gtu)
  104.     {
  105.         ImmutableMap<Lane, GTUDirectionality> next = this.lane.downstreamLanes(this.direction, gtu.getGTUType());
  106.         if (next.isEmpty())
  107.         {
  108.             return null;
  109.         }
  110.         // ask strategical planner
  111.         Set<LaneDirection> set = getNextForRoute(gtu);
  112.         if (set.size() == 1)
  113.         {
  114.             return set.iterator().next();
  115.         }
  116.         // check of the GTU is registered on any
  117.         for (LaneDirection l : set)
  118.         {
  119.             if (l.getLane().getGtuList().contains(gtu))
  120.             {
  121.                 return l;
  122.             }
  123.         }
  124.         // ask tactical planner
  125.         return Try.assign(() -> gtu.getTacticalPlanner().chooseLaneAtSplit(this, set), "Missing parameter.");
  126.     }

  127.     /**
  128.      * Returns a set of {@code LaneDirection}'s that can be followed considering the route.
  129.      * @param gtu LaneBasedGTU; GTU
  130.      * @return set of {@code LaneDirection}'s that can be followed considering the route
  131.      */
  132.     public Set<LaneDirection> getNextForRoute(final LaneBasedGTU gtu)
  133.     {
  134.         ImmutableMap<Lane, GTUDirectionality> next = this.lane.downstreamLanes(this.direction, gtu.getGTUType());
  135.         if (next.isEmpty())
  136.         {
  137.             return null;
  138.         }
  139.         LinkDirection ld;
  140.         try
  141.         {
  142.             ld = gtu.getStrategicalPlanner().nextLinkDirection(this.lane.getParentLink(), this.direction, gtu.getGTUType());
  143.         }
  144.         catch (NetworkException exception)
  145.         {
  146.             throw new RuntimeException("Strategical planner experiences exception on network.", exception);
  147.         }
  148.         Set<LaneDirection> out = new LinkedHashSet<>();
  149.         for (Lane l : next.keySet())
  150.         {
  151.             GTUDirectionality dir = next.get(l);
  152.             if (l.getParentLink().equals(ld.getLink()) && dir.equals(ld.getDirection()))
  153.             {
  154.                 out.add(new LaneDirection(l, dir));
  155.             }
  156.         }
  157.         return out;
  158.     }

  159.     /**
  160.      * Returns the length of the lane.
  161.      * @return Length; length of the lane
  162.      */
  163.     public Length getLength()
  164.     {
  165.         return this.lane.getLength();
  166.     }

  167.     /**
  168.      * Returns a directed point at the given fraction, in the direction of travel (not center line).
  169.      * @param fraction double; fractional position
  170.      * @return directed point at the given fraction, in the direction of travel
  171.      * @throws OTSGeometryException in case the fractional position is not correct
  172.      */
  173.     public DirectedPoint getLocationFraction(final double fraction) throws OTSGeometryException
  174.     {
  175.         DirectedPoint p = this.lane.getCenterLine().getLocationFraction(fraction);
  176.         if (this.direction.isMinus())
  177.         {
  178.             p.setRotZ(p.getRotZ() + Math.PI);
  179.         }
  180.         return p;
  181.     }

  182.     /**
  183.      * Returns the adjacent lane and direction.
  184.      * @param gtu LaneBasedGTU; gtu
  185.      * @param laneChangeDirection LateralDirectionality; lane change direction
  186.      * @return LaneDirection; adjacent lane and direction, {@code null} if none
  187.      */
  188.     public final LaneDirection getAdjacentLaneDirection(final LateralDirectionality laneChangeDirection, final LaneBasedGTU gtu)
  189.     {
  190.         Set<Lane> adjLanes = this.lane.accessibleAdjacentLanesLegal(laneChangeDirection, gtu.getGTUType(), this.direction);
  191.         if (!adjLanes.isEmpty())
  192.         {
  193.             return new LaneDirection(adjLanes.iterator().next(), this.direction);
  194.         }
  195.         return null;
  196.     }

  197.     /** {@inheritDoc} */
  198.     @Override
  199.     public final String toString()
  200.     {
  201.         return "[" + this.lane + (this.direction.isPlus() ? " +]" : " -]");
  202.     }

  203.     /** {@inheritDoc} */
  204.     @Override
  205.     public final int hashCode()
  206.     {
  207.         final int prime = 31;
  208.         int result = 1;
  209.         result = prime * result + ((this.direction == null) ? 0 : this.direction.hashCode());
  210.         result = prime * result + ((this.lane == null) ? 0 : this.lane.hashCode());
  211.         return result;
  212.     }

  213.     /** {@inheritDoc} */
  214.     @Override
  215.     public final boolean equals(final Object obj)
  216.     {
  217.         if (this == obj)
  218.         {
  219.             return true;
  220.         }
  221.         if (obj == null)
  222.         {
  223.             return false;
  224.         }
  225.         if (getClass() != obj.getClass())
  226.         {
  227.             return false;
  228.         }
  229.         LaneDirection other = (LaneDirection) obj;
  230.         if (this.direction != other.direction)
  231.         {
  232.             return false;
  233.         }
  234.         if (this.lane == null)
  235.         {
  236.             if (other.lane != null)
  237.             {
  238.                 return false;
  239.             }
  240.         }
  241.         else if (!this.lane.equals(other.lane))
  242.         {
  243.             return false;
  244.         }
  245.         return true;
  246.     }

  247. }