StripeData.java
- package org.opentrafficsim.road.network.lane;
- import java.math.BigInteger;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.LinkedHashMap;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import org.djunits.value.vdouble.scalar.Length;
- import org.djutils.exceptions.Throw;
- import org.opentrafficsim.base.StripeElement;
- import org.opentrafficsim.base.StripeElement.StripeLateralSync;
- import org.opentrafficsim.core.gtu.GtuType;
- import org.opentrafficsim.core.network.LateralDirectionality;
- /**
- * Container for data about stripes, independent from the link and curvature.
- * <p>
- * Copyright (c) 2024-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
- * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
- * </p>
- * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
- */
- public class StripeData
- {
- /** Stripe elements. */
- private List<StripeElement> elements;
- /** Left permeability. */
- private final boolean left;
- /** Right permeability. */
- private final boolean right;
- /** Lateral permeability per GTU type and direction. */
- private final Map<GtuType, Set<LateralDirectionality>> permeabilityMap = new LinkedHashMap<>();
- /** Lateral synchronization. */
- private StripeLateralSync lateralSync = StripeLateralSync.LINK;
- /** Phase synchronization. */
- private StripePhaseSync phaseSync = StripePhaseSync.NONE;
- /** Period based on all stripe elements. */
- private Double period;
- /**
- * Constructor.
- * @param elements list of stripe elements
- * @param left left overall permeability
- * @param right right overall permeability
- */
- public StripeData(final List<StripeElement> elements, final boolean left, final boolean right)
- {
- this.elements = elements;
- this.left = left;
- this.right = right;
- }
- /**
- * Returns the elements.
- * @return elements
- */
- public List<StripeElement> getElements()
- {
- return this.elements;
- }
-
- /**
- * Sets the elements.
- * @param elements elements
- */
- public void setElements(final List<StripeElement> elements)
- {
- this.elements = elements;
- this.period = null;
- }
- /**
- * Add lateral permeability for a GTU type. This overrules overall stripe permeability. Add NONE to prevent lane changes.
- * Add both LEFT and RIGHT in two calls, to enable lane changes. Add LEFT or RIGHT to enable one direction while prohibiting
- * the other.
- * @param gtuType GTU type to add permeability for
- * @param lateralDirection direction to add compared to the direction of the design line
- */
- public void addPermeability(final GtuType gtuType, final LateralDirectionality lateralDirection)
- {
- if (!this.permeabilityMap.containsKey(gtuType))
- {
- this.permeabilityMap.put(gtuType, new LinkedHashSet<LateralDirectionality>(2));
- }
- this.permeabilityMap.get(gtuType).add(lateralDirection);
- }
- /**
- * Returns whether the given GTU type is allowed to cross the line in the given lateral direction.
- * @param gtuType GTU type to look for.
- * @param lateralDirection direction to look for (LEFT or RIGHT) compared to the direction of the design line.
- * @return whether the road marker is permeable for the GTU type.
- */
- public final boolean isPermeable(final GtuType gtuType, final LateralDirectionality lateralDirection)
- {
- Throw.when(lateralDirection.isNone(), RuntimeException.class,
- "May not request NONE lateral direction for permeability.");
- for (GtuType testGtuType = gtuType; null != testGtuType; testGtuType = testGtuType.getParent())
- {
- Set<LateralDirectionality> set = this.permeabilityMap.get(testGtuType);
- if (null != set)
- {
- return set.contains(lateralDirection);
- }
- }
- return lateralDirection.isLeft() ? this.left : this.right;
- }
- /**
- * Sets the lateral synchronization.
- * @param lateralSync lateral synchronization
- */
- public void setLateralSync(final StripeLateralSync lateralSync)
- {
- this.lateralSync = lateralSync;
- }
- /**
- * Returns the lateral synchronization.
- * @return lateral synchronization
- */
- public StripeLateralSync getLateralSync()
- {
- return this.lateralSync;
- }
- /**
- * Sets the phase synchronization.
- * @param phaseSync phase synchronization
- */
- public void setPhaseSync(final StripePhaseSync phaseSync)
- {
- this.phaseSync = phaseSync;
- }
- /**
- * Returns the phase synchronization.
- * @return phase synchronization
- */
- public StripePhaseSync getPhaseSync()
- {
- return this.phaseSync;
- }
- /**
- * Returns the period of the common dash pattern.
- * @return period of the common dash pattern
- */
- public double getPeriod()
- {
- if (this.period == null)
- {
- this.period = getPeriod(this.elements);
- }
- return this.period;
- }
-
- /**
- * Returns the period after which the given line gap-dash patterns repeat as a whole. Lengths are rounded to a precision of
- * 0.0001 to find the greatest common divisor.
- * @param elements elements
- * @return period
- */
- public static double getPeriod(final List<StripeElement> elements)
- {
- List<Double> lineLengths = new ArrayList<>();
- for (StripeElement element : elements)
- {
- if (element.dashes() != null)
- {
- double length = 0.0;
- for (Length gapDash : element.dashes())
- {
- length += gapDash.si;
- }
- lineLengths.add(length);
- }
- }
- return getPeriod(lineLengths);
- }
- /**
- * Returns the period after which the given line gap-dash patterns repeat as a whole. Lengths are rounded to a precision of
- * 0.0001 to find the greatest common divisor.
- * @param lineLengths gap-dash pattern lengths
- * @return period
- */
- private static double getPeriod(final Collection<Double> lineLengths)
- {
- Set<Double> set = new LinkedHashSet<>(lineLengths);
- if (lineLengths.isEmpty())
- {
- return -1.0;
- }
- else if (set.size() == 1)
- {
- return ((long) (lineLengths.iterator().next() * 10000)) / 10000.0;
- }
- long gcd = 1L;
- for (double length : set)
- {
- gcd = BigInteger.valueOf(gcd).gcd(BigInteger.valueOf((long) (length * 10000))).longValue();
- }
- return gcd / 10000.0;
- }
-
- /**
- * Returns the width, which is the sum of stripe elements.
- * @return width
- */
- public Length getWidth()
- {
- Length width = Length.ZERO;
- for (StripeElement element : getElements())
- {
- width = width.plus(element.width());
- }
- return width;
- }
- /**
- * Method of stripe phase synchronization.
- */
- public enum StripePhaseSync
- {
- /** Do not synchronize. */
- NONE(false),
- /** Synchronize phase to upstream stripe. */
- UPSTREAM(true),
- /** Synchronize phase to downstream stripe. */
- DOWNSTREAM(true);
- /** Whether synchronization should be applied. */
- private final boolean sync;
- /**
- * Constructor.
- * @param sync whether synchronization should be applied
- */
- StripePhaseSync(final boolean sync)
- {
- this.sync = sync;
- }
- /**
- * Returns whether synchronization should be applied.
- * @return whether synchronization should be applied
- */
- public boolean isSync()
- {
- return this.sync;
- }
- }
- }