StripeData.java

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

  2. import java.math.BigInteger;
  3. import java.util.ArrayList;
  4. import java.util.Collection;
  5. import java.util.LinkedHashMap;
  6. import java.util.LinkedHashSet;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Set;

  10. import org.djunits.value.vdouble.scalar.Length;
  11. import org.djutils.exceptions.Throw;
  12. import org.opentrafficsim.base.StripeElement;
  13. import org.opentrafficsim.base.StripeElement.StripeLateralSync;
  14. import org.opentrafficsim.core.gtu.GtuType;
  15. import org.opentrafficsim.core.network.LateralDirectionality;

  16. /**
  17.  * Container for data about stripes, independent from the link and curvature.
  18.  * <p>
  19.  * Copyright (c) 2024-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  20.  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  21.  * </p>
  22.  * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
  23.  */
  24. public class StripeData
  25. {

  26.     /** Stripe elements. */
  27.     private List<StripeElement> elements;

  28.     /** Left permeability. */
  29.     private final boolean left;

  30.     /** Right permeability. */
  31.     private final boolean right;

  32.     /** Lateral permeability per GTU type and direction. */
  33.     private final Map<GtuType, Set<LateralDirectionality>> permeabilityMap = new LinkedHashMap<>();

  34.     /** Lateral synchronization. */
  35.     private StripeLateralSync lateralSync = StripeLateralSync.LINK;

  36.     /** Phase synchronization. */
  37.     private StripePhaseSync phaseSync = StripePhaseSync.NONE;

  38.     /** Period based on all stripe elements. */
  39.     private Double period;

  40.     /**
  41.      * Constructor.
  42.      * @param elements list of stripe elements
  43.      * @param left left overall permeability
  44.      * @param right right overall permeability
  45.      */
  46.     public StripeData(final List<StripeElement> elements, final boolean left, final boolean right)
  47.     {
  48.         this.elements = elements;
  49.         this.left = left;
  50.         this.right = right;
  51.     }

  52.     /**
  53.      * Returns the elements.
  54.      * @return elements
  55.      */
  56.     public List<StripeElement> getElements()
  57.     {
  58.         return this.elements;
  59.     }
  60.    
  61.     /**
  62.      * Sets the elements.
  63.      * @param elements elements
  64.      */
  65.     public void setElements(final List<StripeElement> elements)
  66.     {
  67.         this.elements = elements;
  68.         this.period = null;
  69.     }

  70.     /**
  71.      * Add lateral permeability for a GTU type. This overrules overall stripe permeability. Add NONE to prevent lane changes.
  72.      * Add both LEFT and RIGHT in two calls, to enable lane changes. Add LEFT or RIGHT to enable one direction while prohibiting
  73.      * the other.
  74.      * @param gtuType GTU type to add permeability for
  75.      * @param lateralDirection direction to add compared to the direction of the design line
  76.      */
  77.     public void addPermeability(final GtuType gtuType, final LateralDirectionality lateralDirection)
  78.     {
  79.         if (!this.permeabilityMap.containsKey(gtuType))
  80.         {
  81.             this.permeabilityMap.put(gtuType, new LinkedHashSet<LateralDirectionality>(2));
  82.         }
  83.         this.permeabilityMap.get(gtuType).add(lateralDirection);
  84.     }

  85.     /**
  86.      * Returns whether the given GTU type is allowed to cross the line in the given lateral direction.
  87.      * @param gtuType GTU type to look for.
  88.      * @param lateralDirection direction to look for (LEFT or RIGHT) compared to the direction of the design line.
  89.      * @return whether the road marker is permeable for the GTU type.
  90.      */
  91.     public final boolean isPermeable(final GtuType gtuType, final LateralDirectionality lateralDirection)
  92.     {
  93.         Throw.when(lateralDirection.isNone(), RuntimeException.class,
  94.                 "May not request NONE lateral direction for permeability.");
  95.         for (GtuType testGtuType = gtuType; null != testGtuType; testGtuType = testGtuType.getParent())
  96.         {
  97.             Set<LateralDirectionality> set = this.permeabilityMap.get(testGtuType);
  98.             if (null != set)
  99.             {
  100.                 return set.contains(lateralDirection);
  101.             }
  102.         }
  103.         return lateralDirection.isLeft() ? this.left : this.right;
  104.     }

  105.     /**
  106.      * Sets the lateral synchronization.
  107.      * @param lateralSync lateral synchronization
  108.      */
  109.     public void setLateralSync(final StripeLateralSync lateralSync)
  110.     {
  111.         this.lateralSync = lateralSync;
  112.     }

  113.     /**
  114.      * Returns the lateral synchronization.
  115.      * @return lateral synchronization
  116.      */
  117.     public StripeLateralSync getLateralSync()
  118.     {
  119.         return this.lateralSync;
  120.     }

  121.     /**
  122.      * Sets the phase synchronization.
  123.      * @param phaseSync phase synchronization
  124.      */
  125.     public void setPhaseSync(final StripePhaseSync phaseSync)
  126.     {
  127.         this.phaseSync = phaseSync;
  128.     }

  129.     /**
  130.      * Returns the phase synchronization.
  131.      * @return phase synchronization
  132.      */
  133.     public StripePhaseSync getPhaseSync()
  134.     {
  135.         return this.phaseSync;
  136.     }

  137.     /**
  138.      * Returns the period of the common dash pattern.
  139.      * @return period of the common dash pattern
  140.      */
  141.     public double getPeriod()
  142.     {
  143.         if (this.period == null)
  144.         {
  145.             this.period = getPeriod(this.elements);
  146.         }
  147.         return this.period;
  148.     }
  149.    
  150.     /**
  151.      * Returns the period after which the given line gap-dash patterns repeat as a whole. Lengths are rounded to a precision of
  152.      * 0.0001 to find the greatest common divisor.
  153.      * @param elements elements
  154.      * @return period
  155.      */
  156.     public static double getPeriod(final List<StripeElement> elements)
  157.     {
  158.         List<Double> lineLengths = new ArrayList<>();
  159.         for (StripeElement element : elements)
  160.         {
  161.             if (element.dashes() != null)
  162.             {
  163.                 double length = 0.0;
  164.                 for (Length gapDash : element.dashes())
  165.                 {
  166.                     length += gapDash.si;
  167.                 }
  168.                 lineLengths.add(length);
  169.             }
  170.         }
  171.         return getPeriod(lineLengths);
  172.     }

  173.     /**
  174.      * Returns the period after which the given line gap-dash patterns repeat as a whole. Lengths are rounded to a precision of
  175.      * 0.0001 to find the greatest common divisor.
  176.      * @param lineLengths gap-dash pattern lengths
  177.      * @return period
  178.      */
  179.     private static double getPeriod(final Collection<Double> lineLengths)
  180.     {
  181.         Set<Double> set = new LinkedHashSet<>(lineLengths);
  182.         if (lineLengths.isEmpty())
  183.         {
  184.             return -1.0;
  185.         }
  186.         else if (set.size() == 1)
  187.         {
  188.             return ((long) (lineLengths.iterator().next() * 10000)) / 10000.0;
  189.         }
  190.         long gcd = 1L;
  191.         for (double length : set)
  192.         {
  193.             gcd = BigInteger.valueOf(gcd).gcd(BigInteger.valueOf((long) (length * 10000))).longValue();
  194.         }
  195.         return gcd / 10000.0;
  196.     }
  197.    
  198.     /**
  199.      * Returns the width, which is the sum of stripe elements.
  200.      * @return width
  201.      */
  202.     public Length getWidth()
  203.     {
  204.         Length width = Length.ZERO;
  205.         for (StripeElement element : getElements())
  206.         {
  207.             width = width.plus(element.width());
  208.         }
  209.         return width;
  210.     }

  211.     /**
  212.      * Method of stripe phase synchronization.
  213.      */
  214.     public enum StripePhaseSync
  215.     {
  216.         /** Do not synchronize. */
  217.         NONE(false),

  218.         /** Synchronize phase to upstream stripe. */
  219.         UPSTREAM(true),

  220.         /** Synchronize phase to downstream stripe. */
  221.         DOWNSTREAM(true);

  222.         /** Whether synchronization should be applied. */
  223.         private final boolean sync;

  224.         /**
  225.          * Constructor.
  226.          * @param sync whether synchronization should be applied
  227.          */
  228.         StripePhaseSync(final boolean sync)
  229.         {
  230.             this.sync = sync;
  231.         }

  232.         /**
  233.          * Returns whether synchronization should be applied.
  234.          * @return whether synchronization should be applied
  235.          */
  236.         public boolean isSync()
  237.         {
  238.             return this.sync;
  239.         }
  240.     }

  241. }