1 package org.opentrafficsim.road.network.lane; 2 3 import java.util.LinkedHashMap; 4 import java.util.LinkedHashSet; 5 import java.util.List; 6 import java.util.Map; 7 import java.util.Set; 8 import java.util.UUID; 9 10 import org.djunits.value.vdouble.scalar.Length; 11 import org.djutils.exceptions.Throw; 12 import org.opentrafficsim.core.geometry.OtsGeometryException; 13 import org.opentrafficsim.core.gtu.GtuType; 14 import org.opentrafficsim.core.network.LateralDirectionality; 15 import org.opentrafficsim.core.network.NetworkException; 16 17 /** 18 * <p> 19 * Copyright (c) 2013-2023 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/averbraeck">Alexander Verbraeck</a> 23 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a> 24 * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a> 25 */ 26 public class Stripe extends CrossSectionElement 27 { 28 /** */ 29 private static final long serialVersionUID = 20141025L; 30 31 /** Type of the stripe, defining default permeability. */ 32 private final Type type; 33 34 /** Type to overrule the normal type, e.g. rush-hour lanes without changing the appearance of the stripe. */ 35 private Type overruleType; 36 37 /** Lateral permeability per GTU type and direction. */ 38 private final Map<GtuType, Set<LateralDirectionality>> permeabilityMap = new LinkedHashMap<>(); 39 40 /** 41 * Constructor allowing difference at start at end. 42 * @param type Type; strip type defining appearance and default permeability. 43 * @param parentLink CrossSectionLink; Cross Section Link to which the element belongs. 44 * @param startCenterPosition Length; the lateral start position compared to the linear geometry of the Cross Section Link 45 * at the start of the road marker. 46 * @param endCenterPosition Length; the lateral end position compared to the linear geometry of the Cross Section Link at 47 * the end of the road marker. 48 * @param beginWidth Length; start width, positioned <i>symmetrically around</i> the lateral start position. 49 * @param endWidth Length; end width, positioned <i>symmetrically around</i> the lateral end position. 50 * @param fixGradualLateralOffset boolean; true if gradualLateralOffset needs to be fixed 51 * @throws OtsGeometryException when creation of the center line or contour geometry fails 52 * @throws NetworkException when id equal to null or not unique 53 */ 54 public Stripe(final Type type, final CrossSectionLink parentLink, final Length startCenterPosition, 55 final Length endCenterPosition, final Length beginWidth, final Length endWidth, 56 final boolean fixGradualLateralOffset) throws OtsGeometryException, NetworkException 57 { 58 super(parentLink, UUID.randomUUID().toString(), startCenterPosition, endCenterPosition, beginWidth, endWidth, 59 fixGradualLateralOffset); 60 Throw.whenNull(type, "Type may not be null."); 61 this.type = type; 62 } 63 64 /** 65 * Constructor for constant properties along the length. 66 * @param type Type; strip type defining appearance and default permeability. 67 * @param parentLink CrossSectionLink; Cross Section Link to which the element belongs. 68 * @param lateralCenterPosition Length; the lateral start position compared to the linear geometry of the Cross Section 69 * Link. 70 * @param width Length; start width, positioned <i>symmetrically around</i> the lateral start position. 71 * @throws OtsGeometryException when creation of the center line or contour geometry fails 72 * @throws NetworkException when id equal to null or not unique 73 */ 74 public Stripe(final Type type, final CrossSectionLink parentLink, final Length lateralCenterPosition, final Length width) 75 throws OtsGeometryException, NetworkException 76 { 77 this(type, parentLink, lateralCenterPosition, lateralCenterPosition, width, width, false); 78 } 79 80 /** 81 * Constructor for elaborate longitudinal property changes. 82 * @param type Type; strip type defining appearance and default permeability. 83 * @param parentLink CrossSectionLink; Cross Section Link to which the element belongs. 84 * @param crossSectionSlices List<CrossSectionSlice>; The offsets and widths at positions along the line, relative to 85 * the design line of the parent link. If there is just one with and offset, there should just be one element in 86 * the list with Length = 0. If there are more slices, the last one should be at the length of the design line. 87 * If not, a NetworkException is thrown. 88 * @throws OtsGeometryException when creation of the center line or contour geometry fails 89 * @throws NetworkException when id equal to null or not unique 90 */ 91 public Stripe(final Type type, final CrossSectionLink parentLink, final List<CrossSectionSlice> crossSectionSlices) 92 throws OtsGeometryException, NetworkException 93 { 94 super(parentLink, UUID.randomUUID().toString(), crossSectionSlices); 95 Throw.whenNull(type, "Type may not be null."); 96 this.type = type; 97 } 98 99 /** 100 * Returns the stripe type. 101 * @return Type; stripe type. 102 */ 103 public Type getType() 104 { 105 return this.type; 106 } 107 108 /** 109 * Sets an overruling stripe type. This can be used for e.g. rush-hour lanes, without changing the appearance of the stripe. 110 * Note that custom set permeabilities (addPermeability()) remain active. 111 * @param overruleType Type; overruling stripe type. 112 */ 113 public void setOverruleType(final Type overruleType) 114 { 115 this.overruleType = overruleType; 116 } 117 118 /** 119 * Clears the overrule type, after which the normal type will hold. 120 */ 121 public void clearOverruleType() 122 { 123 this.overruleType = null; 124 } 125 126 /** 127 * Returns the currently active stripe type. 128 * @return Type; the currently active stripe type. 129 */ 130 private Type activeType() 131 { 132 return this.overruleType == null ? this.type : this.overruleType; 133 } 134 135 /** {@inheritDoc} */ 136 @Override 137 public final double getZ() 138 { 139 return -0.0002; 140 } 141 142 /** 143 * Add lateral permeability for a GTU type in the direction of the design line of the overarching CrossSectionLink. Add NONE 144 * to prevent lane changes relative to the stripe type. Add LEFT or RIGHT, or both in two calls, to enable lane changes 145 * relative to the stripe type. 146 * @param gtuType GtuType; GTU type to add permeability for. 147 * @param lateralDirection LateralDirectionality; direction to add compared to the direction of the design line. 148 */ 149 public void addPermeability(final GtuType gtuType, final LateralDirectionality lateralDirection) 150 { 151 if (!this.permeabilityMap.containsKey(gtuType)) 152 { 153 this.permeabilityMap.put(gtuType, new LinkedHashSet<LateralDirectionality>(2)); 154 } 155 this.permeabilityMap.get(gtuType).add(lateralDirection); 156 } 157 158 /** 159 * Returns whether the given GTU type is allowed to cross the line in the given lateral direction. 160 * @param gtuType GtuType; GTU type to look for. 161 * @param lateralDirection LateralDirectionality; direction to look for (LEFT or RIGHT) compared to the direction of the 162 * design line. 163 * @return whether the road marker is permeable for the GTU type. 164 */ 165 public final boolean isPermeable(final GtuType gtuType, final LateralDirectionality lateralDirection) 166 { 167 Throw.when(lateralDirection.isNone(), RuntimeException.class, 168 "May not request NONE lateral direction for permeability."); 169 for (GtuType testGtuType = gtuType; null != testGtuType; testGtuType = testGtuType.getParent()) 170 { 171 Set<LateralDirectionality> set = this.permeabilityMap.get(testGtuType); 172 if (null != set) 173 { 174 return set.contains(lateralDirection); 175 } 176 } 177 return lateralDirection.isLeft() ? activeType().left() : activeType().right; 178 } 179 180 /** 181 * Defines the visible type of the stripe, and the standard permeability that pertains to it. 182 * <p> 183 * Copyright (c) 2022-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. 184 * <br> 185 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>. 186 * </p> 187 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a> 188 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a> 189 * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a> 190 */ 191 public enum Type 192 { 193 /** Single solid line. */ 194 SOLID(false, false), 195 196 /** Line |¦ allow to go to left, but not to right. */ 197 LEFT(true, false), 198 199 /** Line ¦| allow to go to right, but not to left. */ 200 RIGHT(false, true), 201 202 /** Dashes ¦ allow to cross in both directions. */ 203 DASHED(true, true), 204 205 /** Double solid line ||, don't cross. */ 206 DOUBLE(false, false), 207 208 /** Block : allow to cross in both directions. */ 209 BLOCK(true, true); 210 211 /** Left permeable. */ 212 private final boolean left; 213 214 /** Right permeable. */ 215 private final boolean right; 216 217 /** 218 * Constructor setting permeability. 219 * @param left boolean; left permeability. 220 * @param right boolean; right permeability. 221 */ 222 Type(final boolean left, final boolean right) 223 { 224 this.left = left; 225 this.right = right; 226 } 227 228 /** 229 * Returns the left permeability. 230 * @return boolean; left permeability. 231 */ 232 public boolean left() 233 { 234 return this.left; 235 } 236 237 /** 238 * Returns the right permeability. 239 * @return boolean; right permeability. 240 */ 241 public boolean right() 242 { 243 return this.right; 244 } 245 } 246 247 }