1 package org.opentrafficsim.road.network;
2
3 import java.math.BigInteger;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.LinkedHashMap;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import org.djunits.value.vdouble.scalar.Length;
13 import org.djutils.exceptions.Throw;
14 import org.opentrafficsim.base.OtsRuntimeException;
15 import org.opentrafficsim.base.StripeElement;
16 import org.opentrafficsim.base.StripeElement.StripeLateralSync;
17 import org.opentrafficsim.core.gtu.GtuType;
18 import org.opentrafficsim.core.network.LateralDirectionality;
19
20
21
22
23
24
25
26
27
28 public class StripeData
29 {
30
31
32 private List<StripeElement> elements;
33
34
35 private final boolean left;
36
37
38 private final boolean right;
39
40
41 private final Map<GtuType, Set<LateralDirectionality>> permeabilityMap = new LinkedHashMap<>();
42
43
44 private StripeLateralSync lateralSync = StripeLateralSync.LINK;
45
46
47 private StripePhaseSync phaseSync = StripePhaseSync.NONE;
48
49
50 private Double period;
51
52
53
54
55
56
57
58 public StripeData(final List<StripeElement> elements, final boolean left, final boolean right)
59 {
60 this.elements = elements;
61 this.left = left;
62 this.right = right;
63 }
64
65
66
67
68
69
70
71 public StripeData copy()
72 {
73 StripeData out = new StripeData(new ArrayList<>(), this.left, this.right);
74 out.elements.addAll(this.elements);
75 out.permeabilityMap.putAll(this.permeabilityMap);
76 out.lateralSync = this.lateralSync;
77 out.phaseSync = this.phaseSync;
78 out.period = this.period;
79 return out;
80 }
81
82
83
84
85
86 public List<StripeElement> getElements()
87 {
88 return this.elements;
89 }
90
91
92
93
94
95 public void setElements(final List<StripeElement> elements)
96 {
97 this.elements = elements;
98 this.period = null;
99 }
100
101
102
103
104
105
106
107
108 public void addPermeability(final GtuType gtuType, final LateralDirectionality lateralDirection)
109 {
110 if (!this.permeabilityMap.containsKey(gtuType))
111 {
112 this.permeabilityMap.put(gtuType, new LinkedHashSet<LateralDirectionality>(2));
113 }
114 this.permeabilityMap.get(gtuType).add(lateralDirection);
115 }
116
117
118
119
120
121
122
123 public final boolean isPermeable(final GtuType gtuType, final LateralDirectionality lateralDirection)
124 {
125 Throw.when(lateralDirection.isNone(), OtsRuntimeException.class,
126 "May not request NONE lateral direction for permeability.");
127 for (GtuType testGtuType = gtuType; testGtuType != null; testGtuType = testGtuType.getParent().orElse(null))
128 {
129 Set<LateralDirectionality> set = this.permeabilityMap.get(testGtuType);
130 if (null != set)
131 {
132 return set.contains(lateralDirection);
133 }
134 }
135 return lateralDirection.isLeft() ? this.left : this.right;
136 }
137
138
139
140
141
142 public void setLateralSync(final StripeLateralSync lateralSync)
143 {
144 this.lateralSync = lateralSync;
145 }
146
147
148
149
150
151 public StripeLateralSync getLateralSync()
152 {
153 return this.lateralSync;
154 }
155
156
157
158
159
160 public void setPhaseSync(final StripePhaseSync phaseSync)
161 {
162 this.phaseSync = phaseSync;
163 }
164
165
166
167
168
169 public StripePhaseSync getPhaseSync()
170 {
171 return this.phaseSync;
172 }
173
174
175
176
177
178 public double getPeriod()
179 {
180 if (this.period == null)
181 {
182 this.period = getPeriod(this.elements);
183 }
184 return this.period;
185 }
186
187
188
189
190
191
192
193 public static double getPeriod(final List<StripeElement> elements)
194 {
195 List<Double> lineLengths = new ArrayList<>();
196 for (StripeElement element : elements)
197 {
198 if (element.dashes() != null)
199 {
200 double length = 0.0;
201 for (Length gapDash : element.dashes())
202 {
203 length += gapDash.si;
204 }
205 lineLengths.add(length);
206 }
207 }
208 return getPeriod(lineLengths);
209 }
210
211
212
213
214
215
216
217 private static double getPeriod(final Collection<Double> lineLengths)
218 {
219 Set<Double> set = new LinkedHashSet<>(lineLengths);
220 if (lineLengths.isEmpty())
221 {
222 return -1.0;
223 }
224 else if (set.size() == 1)
225 {
226 return ((long) (lineLengths.iterator().next() * 10000)) / 10000.0;
227 }
228 long gcd = 1L;
229 for (double length : set)
230 {
231 gcd = BigInteger.valueOf(gcd).gcd(BigInteger.valueOf((long) (length * 10000))).longValue();
232 }
233 return gcd / 10000.0;
234 }
235
236
237
238
239
240 public Length getWidth()
241 {
242 return Length.ofSI(this.elements.stream().mapToDouble((e) -> e.width().si).sum());
243 }
244
245
246
247
248 public enum StripePhaseSync
249 {
250
251 NONE(false),
252
253
254 UPSTREAM(true),
255
256
257 DOWNSTREAM(true);
258
259
260 private final boolean sync;
261
262
263
264
265
266 StripePhaseSync(final boolean sync)
267 {
268 this.sync = sync;
269 }
270
271
272
273
274
275 public boolean isSync()
276 {
277 return this.sync;
278 }
279 }
280
281 }