Stripe.java
package org.opentrafficsim.road.network.lane;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.djunits.unit.LengthUnit;
import org.djunits.value.vdouble.scalar.Length;
import org.djutils.draw.line.Polygon2d;
import org.djutils.exceptions.Throw;
import org.opentrafficsim.core.geometry.OtsLine2d;
import org.opentrafficsim.core.gtu.GtuType;
import org.opentrafficsim.core.network.LateralDirectionality;
import org.opentrafficsim.core.network.NetworkException;
/**
* <p>
* Copyright (c) 2013-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/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
*/
public class Stripe extends CrossSectionElement
{
/** */
private static final long serialVersionUID = 20141025L;
/** Type of the stripe, defining default permeability. */
private final Type type;
/** Type to overrule the normal type, e.g. rush-hour lanes without changing the appearance of the stripe. */
private Type overruleType;
/** Lateral permeability per GTU type and direction. */
private final Map<GtuType, Set<LateralDirectionality>> permeabilityMap = new LinkedHashMap<>();
/**
* Constructor specifying geometry.
* @param type Type; stripe type defining appearance and default permeability.
* @param link CrossSectionLink; link.
* @param centerLine OtsLine2d; center line.
* @param contour Polygon2d; contour shape.
* @param crossSectionSlices List<CrossSectionSlice>; cross-section slices.
* @throws NetworkException when no cross-section slice is defined.
*/
public Stripe(final Type type, final CrossSectionLink link, final OtsLine2d centerLine, final Polygon2d contour,
final List<CrossSectionSlice> crossSectionSlices) throws NetworkException
{
super(link, UUID.randomUUID().toString(), centerLine, contour, crossSectionSlices);
Throw.whenNull(type, "Type may not be null.");
this.type = type;
}
/**
* Returns the stripe type.
* @return Type; stripe type.
*/
public Type getType()
{
return this.type;
}
/**
* Sets an overruling stripe type. This can be used for e.g. rush-hour lanes, without changing the appearance of the stripe.
* Note that custom set permeabilities (addPermeability()) remain active.
* @param overruleType Type; overruling stripe type.
*/
public void setOverruleType(final Type overruleType)
{
this.overruleType = overruleType;
}
/**
* Clears the overrule type, after which the normal type will hold.
*/
public void clearOverruleType()
{
this.overruleType = null;
}
/**
* Returns the currently active stripe type.
* @return Type; the currently active stripe type.
*/
private Type activeType()
{
return this.overruleType == null ? this.type : this.overruleType;
}
/**
* Add lateral permeability for a GTU type in the direction of the design line of the overarching CrossSectionLink. Add NONE
* to prevent lane changes relative to the stripe type. Add LEFT or RIGHT, or both in two calls, to enable lane changes
* relative to the stripe type.
* @param gtuType GtuType; GTU type to add permeability for.
* @param lateralDirection LateralDirectionality; 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 GtuType; GTU type to look for.
* @param lateralDirection LateralDirectionality; 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() ? activeType().left() : activeType().right;
}
/**
* Defines the visible type of the stripe, and the standard permeability that pertains to it.
* <p>
* Copyright (c) 2022-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/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
*/
public enum Type
{
/** Single solid line. */
SOLID(false, false),
/** Line |¦ allow to go to left, but not to right. */
LEFT(true, false, new Length(60.0, LengthUnit.CENTIMETER)),
/** Line ¦| allow to go to right, but not to left. */
RIGHT(false, true, new Length(60.0, LengthUnit.CENTIMETER)),
/** Dashes ¦ allow to cross in both directions. */
DASHED(true, true),
/** Double solid line ||, don't cross. */
DOUBLE(false, false, new Length(60.0, LengthUnit.CENTIMETER)),
/** Block : allow to cross in both directions. */
BLOCK(true, true, new Length(40.0, LengthUnit.CENTIMETER));
/** Left permeable. */
private final boolean left;
/** Right permeable. */
private final boolean right;
/** Default width. */
private final Length defaultWidth;
/**
* Constructor setting permeability.
* @param left boolean; left permeability.
* @param right boolean; right permeability.
*/
Type(final boolean left, final boolean right)
{
this(left, right, new Length(20.0, LengthUnit.CENTIMETER));
}
/**
* Constructor setting permeability.
* @param left boolean; left permeability.
* @param right boolean; right permeability.
* @param defaultWidth Length; default width.
*/
Type(final boolean left, final boolean right, final Length defaultWidth)
{
this.left = left;
this.right = right;
this.defaultWidth = defaultWidth;
}
/**
* Returns the left permeability.
* @return boolean; left permeability.
*/
public boolean left()
{
return this.left;
}
/**
* Returns the right permeability.
* @return boolean; right permeability.
*/
public boolean right()
{
return this.right;
}
/**
* Returns the default width.
* @return Length; default width.
*/
public Length defaultWidth()
{
return this.defaultWidth;
}
}
}