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.unit.LengthUnit;
11 import org.djunits.value.vdouble.scalar.Length;
12 import org.djutils.draw.line.Polygon2d;
13 import org.djutils.exceptions.Throw;
14 import org.opentrafficsim.core.geometry.OtsLine2d;
15 import org.opentrafficsim.core.gtu.GtuType;
16 import org.opentrafficsim.core.network.LateralDirectionality;
17 import org.opentrafficsim.core.network.NetworkException;
18
19 /**
20 * <p>
21 * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
22 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
23 * </p>
24 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
25 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
26 * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
27 */
28 public class Stripe extends CrossSectionElement
29 {
30 /** */
31 private static final long serialVersionUID = 20141025L;
32
33 /** Type of the stripe, defining default permeability. */
34 private final Type type;
35
36 /** Type to overrule the normal type, e.g. rush-hour lanes without changing the appearance of the stripe. */
37 private Type overruleType;
38
39 /** Lateral permeability per GTU type and direction. */
40 private final Map<GtuType, Set<LateralDirectionality>> permeabilityMap = new LinkedHashMap<>();
41
42 /**
43 * Constructor specifying geometry.
44 * @param type Type; stripe type defining appearance and default permeability.
45 * @param link CrossSectionLink; link.
46 * @param centerLine OtsLine2d; center line.
47 * @param contour Polygon2d; contour shape.
48 * @param crossSectionSlices List<CrossSectionSlice>; cross-section slices.
49 * @throws NetworkException when no cross-section slice is defined.
50 */
51 public Stripe(final Type type, final CrossSectionLink link, final OtsLine2d centerLine, final Polygon2d contour,
52 final List<CrossSectionSlice> crossSectionSlices) throws NetworkException
53 {
54 super(link, UUID.randomUUID().toString(), centerLine, contour, crossSectionSlices);
55 Throw.whenNull(type, "Type may not be null.");
56 this.type = type;
57 }
58
59 /**
60 * Returns the stripe type.
61 * @return Type; stripe type.
62 */
63 public Type getType()
64 {
65 return this.type;
66 }
67
68 /**
69 * Sets an overruling stripe type. This can be used for e.g. rush-hour lanes, without changing the appearance of the stripe.
70 * Note that custom set permeabilities (addPermeability()) remain active.
71 * @param overruleType Type; overruling stripe type.
72 */
73 public void setOverruleType(final Type overruleType)
74 {
75 this.overruleType = overruleType;
76 }
77
78 /**
79 * Clears the overrule type, after which the normal type will hold.
80 */
81 public void clearOverruleType()
82 {
83 this.overruleType = null;
84 }
85
86 /**
87 * Returns the currently active stripe type.
88 * @return Type; the currently active stripe type.
89 */
90 private Type activeType()
91 {
92 return this.overruleType == null ? this.type : this.overruleType;
93 }
94
95 /**
96 * Add lateral permeability for a GTU type in the direction of the design line of the overarching CrossSectionLink. Add NONE
97 * to prevent lane changes relative to the stripe type. Add LEFT or RIGHT, or both in two calls, to enable lane changes
98 * relative to the stripe type.
99 * @param gtuType GtuType; GTU type to add permeability for.
100 * @param lateralDirection LateralDirectionality; direction to add compared to the direction of the design line.
101 */
102 public void addPermeability(final GtuType gtuType, final LateralDirectionality lateralDirection)
103 {
104 if (!this.permeabilityMap.containsKey(gtuType))
105 {
106 this.permeabilityMap.put(gtuType, new LinkedHashSet<LateralDirectionality>(2));
107 }
108 this.permeabilityMap.get(gtuType).add(lateralDirection);
109 }
110
111 /**
112 * Returns whether the given GTU type is allowed to cross the line in the given lateral direction.
113 * @param gtuType GtuType; GTU type to look for.
114 * @param lateralDirection LateralDirectionality; direction to look for (LEFT or RIGHT) compared to the direction of the
115 * design line.
116 * @return whether the road marker is permeable for the GTU type.
117 */
118 public final boolean isPermeable(final GtuType gtuType, final LateralDirectionality lateralDirection)
119 {
120 Throw.when(lateralDirection.isNone(), RuntimeException.class,
121 "May not request NONE lateral direction for permeability.");
122 for (GtuType testGtuType = gtuType; null != testGtuType; testGtuType = testGtuType.getParent())
123 {
124 Set<LateralDirectionality> set = this.permeabilityMap.get(testGtuType);
125 if (null != set)
126 {
127 return set.contains(lateralDirection);
128 }
129 }
130 return lateralDirection.isLeft() ? activeType().left() : activeType().right;
131 }
132
133 /**
134 * Defines the visible type of the stripe, and the standard permeability that pertains to it.
135 * <p>
136 * Copyright (c) 2022-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
137 * <br>
138 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
139 * </p>
140 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
141 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
142 * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
143 */
144 public enum Type
145 {
146 /** Single solid line. */
147 SOLID(false, false),
148
149 /** Line |¦ allow to go to left, but not to right. */
150 LEFT(true, false, new Length(60.0, LengthUnit.CENTIMETER)),
151
152 /** Line ¦| allow to go to right, but not to left. */
153 RIGHT(false, true, new Length(60.0, LengthUnit.CENTIMETER)),
154
155 /** Dashes ¦ allow to cross in both directions. */
156 DASHED(true, true),
157
158 /** Double solid line ||, don't cross. */
159 DOUBLE(false, false, new Length(60.0, LengthUnit.CENTIMETER)),
160
161 /** Block : allow to cross in both directions. */
162 BLOCK(true, true, new Length(40.0, LengthUnit.CENTIMETER));
163
164 /** Left permeable. */
165 private final boolean left;
166
167 /** Right permeable. */
168 private final boolean right;
169
170 /** Default width. */
171 private final Length defaultWidth;
172
173 /**
174 * Constructor setting permeability.
175 * @param left boolean; left permeability.
176 * @param right boolean; right permeability.
177 */
178 Type(final boolean left, final boolean right)
179 {
180 this(left, right, new Length(20.0, LengthUnit.CENTIMETER));
181 }
182
183 /**
184 * Constructor setting permeability.
185 * @param left boolean; left permeability.
186 * @param right boolean; right permeability.
187 * @param defaultWidth Length; default width.
188 */
189 Type(final boolean left, final boolean right, final Length defaultWidth)
190 {
191 this.left = left;
192 this.right = right;
193 this.defaultWidth = defaultWidth;
194 }
195
196 /**
197 * Returns the left permeability.
198 * @return boolean; left permeability.
199 */
200 public boolean left()
201 {
202 return this.left;
203 }
204
205 /**
206 * Returns the right permeability.
207 * @return boolean; right permeability.
208 */
209 public boolean right()
210 {
211 return this.right;
212 }
213
214 /**
215 * Returns the default width.
216 * @return Length; default width.
217 */
218 public Length defaultWidth()
219 {
220 return this.defaultWidth;
221 }
222 }
223
224 }