1 package org.opentrafficsim.road.gtu.lane.perception.object;
2
3 import java.util.Optional;
4
5 import org.djunits.unit.LengthUnit;
6 import org.djunits.value.ValueRuntimeException;
7 import org.djunits.value.vdouble.scalar.Length;
8 import org.djunits.value.vdouble.scalar.Speed;
9 import org.djunits.value.vdouble.vector.LengthVector;
10 import org.djutils.exceptions.Throw;
11 import org.opentrafficsim.base.OtsRuntimeException;
12 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
13 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
14 import org.opentrafficsim.road.network.lane.CrossSectionLink;
15 import org.opentrafficsim.road.network.lane.Lane;
16 import org.opentrafficsim.road.network.lane.conflict.ConflictPriority;
17 import org.opentrafficsim.road.network.lane.conflict.ConflictRule;
18 import org.opentrafficsim.road.network.lane.conflict.ConflictType;
19
20
21
22
23
24
25
26
27
28
29
30 public class PerceivedConflictFull extends PerceivedLaneBasedObjectBase implements PerceivedConflict
31 {
32
33
34 private final ConflictType conflictType;
35
36
37 private final ConflictPriority conflictPriority;
38
39
40 private final Length conflictingLength;
41
42
43
44
45
46 private final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> upstreamConflictingGTUs;
47
48
49
50
51
52 private final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> downstreamConflictingGTUs;
53
54
55 private final Length conflictingVisibility;
56
57
58 private final Speed conflictingSpeedLimit;
59
60
61 private final CrossSectionLink conflictingLink;
62
63
64 private final PerceivedObject stopLine;
65
66
67 private final PerceivedObject conflictingStopLine;
68
69
70 private final Class<? extends ConflictRule> conflictRuleType;
71
72
73 private Length conflictingTrafficLightDistance = null;
74
75
76 private boolean permitted = false;
77
78
79 private final Width width;
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 @SuppressWarnings("parameternumber")
101 public PerceivedConflictFull(final String id, final Length distance, final Length length, final ConflictType conflictType,
102 final ConflictPriority conflictPriority, final Class<? extends ConflictRule> conflictRuleType,
103 final Length conflictingLength, final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> upstreamConflictingGTUs,
104 final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> downstreamConflictingGTUs,
105 final Length conflictingVisibility, final Speed conflictingSpeedLimit, final CrossSectionLink conflictingLink,
106 final Width width, final PerceivedObject stopLine, final PerceivedObject conflictingStopLine, final Lane lane)
107 {
108 super(id, ObjectType.CONFLICT, length, Kinematics.staticAhead(distance), lane);
109 Throw.whenNull(conflictType, "Conflict type may not be null.");
110 Throw.whenNull(conflictPriority, "Conflict priority may not be null.");
111 Throw.whenNull(conflictRuleType, "Conflict rule type may not be null.");
112 Throw.whenNull(conflictingLength, "Conflict length may not be null.");
113 Throw.whenNull(upstreamConflictingGTUs, "Upstreaem conflicting GTU's may not be null.");
114 Throw.whenNull(downstreamConflictingGTUs, "Downstream conflicting GTU's may not be null.");
115 Throw.whenNull(width, "Width may not be null.");
116 Throw.whenNull(conflictingVisibility, "Conflict visibility may not be null.");
117 Throw.whenNull(conflictingSpeedLimit, "Conflict speed limit may not be null.");
118 this.conflictType = conflictType;
119 this.conflictPriority = conflictPriority;
120 this.conflictRuleType = conflictRuleType;
121 this.conflictingLength = conflictingLength;
122 this.upstreamConflictingGTUs = upstreamConflictingGTUs;
123 this.downstreamConflictingGTUs = downstreamConflictingGTUs;
124 this.conflictingVisibility = conflictingVisibility;
125 this.conflictingSpeedLimit = conflictingSpeedLimit;
126 this.conflictingLink = conflictingLink;
127 this.width = width;
128 this.stopLine = stopLine;
129 this.conflictingStopLine = conflictingStopLine;
130 }
131
132
133
134
135
136 @Override
137 public ConflictType getConflictType()
138 {
139 return this.conflictType;
140 }
141
142
143
144
145
146 @Override
147 public boolean isCrossing()
148 {
149 return this.conflictType.equals(ConflictType.CROSSING);
150 }
151
152
153
154
155
156 @Override
157 public boolean isMerge()
158 {
159 return this.conflictType.equals(ConflictType.MERGE);
160 }
161
162
163
164
165
166 @Override
167 public boolean isSplit()
168 {
169 return this.conflictType.equals(ConflictType.SPLIT);
170 }
171
172
173
174
175
176 @Override
177 public ConflictPriority getConflictPriority()
178 {
179 return this.conflictPriority;
180 }
181
182
183
184
185
186 @Override
187 public Length getConflictingLength()
188 {
189 return this.conflictingLength;
190 }
191
192
193
194
195
196 @Override
197 public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getUpstreamConflictingGTUs()
198 {
199 return this.upstreamConflictingGTUs;
200 }
201
202
203
204
205
206
207
208 @Override
209 public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getDownstreamConflictingGTUs()
210 {
211 return this.downstreamConflictingGTUs;
212 }
213
214
215
216
217
218
219
220 @Override
221 public Length getConflictingVisibility()
222 {
223 return this.conflictingVisibility;
224 }
225
226
227
228
229
230 @Override
231 public Speed getConflictingSpeedLimit()
232 {
233 return this.conflictingSpeedLimit;
234 }
235
236
237
238
239
240 @Override
241 public CrossSectionLink getConflictingLink()
242 {
243 return this.conflictingLink;
244 }
245
246
247
248
249
250 @Override
251 public PerceivedObject getStopLine()
252 {
253 return this.stopLine;
254 }
255
256
257
258
259
260 @Override
261 public PerceivedObject getConflictingStopLine()
262 {
263 return this.conflictingStopLine;
264 }
265
266
267
268
269
270 @Override
271 public Class<? extends ConflictRule> getConflictRuleType()
272 {
273 return this.conflictRuleType;
274 }
275
276
277
278
279
280 @Override
281 public Optional<Length> getConflictingTrafficLightDistance()
282 {
283 return Optional.of(this.conflictingTrafficLightDistance);
284 }
285
286
287
288
289
290 @Override
291 public boolean isPermitted()
292 {
293 return this.permitted;
294 }
295
296
297
298
299
300
301 public void setConflictingTrafficLight(final Length trafficLightDistance, final boolean permittedConflict)
302 {
303 this.conflictingTrafficLightDistance = trafficLightDistance;
304 this.permitted = permittedConflict;
305 }
306
307
308
309
310
311
312 @Override
313 public Length getWidthAtFraction(final double fraction)
314 {
315 try
316 {
317 return this.width.getWidth(fraction);
318 }
319 catch (ValueRuntimeException exception)
320 {
321 throw new OtsRuntimeException("Unexpected exception: fraction could not be interpolated.", exception);
322 }
323 }
324
325
326
327
328
329
330
331
332
333
334
335
336 public static class Width
337 {
338
339
340 private final double[] fractions;
341
342
343 private final LengthVector width;
344
345
346
347
348
349
350 public Width(final double[] fractions, final LengthVector width)
351 {
352 Throw.whenNull(fractions, "Fractions may not be null.");
353 Throw.whenNull(width, "Width may not be null.");
354 Throw.when(fractions.length != width.size(), IllegalArgumentException.class,
355 "Array and vector are not of equal length.");
356 Throw.when(fractions.length < 2, IllegalArgumentException.class, "Input should at least contain 2 values.");
357 Throw.when(fractions[0] != 0.0 || fractions[fractions.length - 1] != 1.0, IllegalArgumentException.class,
358 "Fractions should range from 0 to 1.");
359 for (int i = 1; i < fractions.length; i++)
360 {
361 Throw.when(fractions[i] <= fractions[i - 1], IllegalArgumentException.class, "Fractions are not increasing.");
362 }
363 this.fractions = fractions;
364 this.width = width;
365 }
366
367
368
369
370
371
372
373 public Length getWidth(final double fraction) throws ValueRuntimeException
374 {
375 Throw.when(fraction < 0.0 || fraction > 1.0, IllegalArgumentException.class, "Fraction should be between 0 and 1.");
376 if (fraction == 1.0)
377 {
378 return this.width.get(this.width.size() - 1);
379 }
380 for (int i = 0; i < this.fractions.length - 1; i++)
381 {
382 if (this.fractions[i] <= fraction && this.fractions[i + 1] > fraction)
383 {
384 double r = (fraction - this.fractions[i]) / (this.fractions[i + 1] - this.fractions[i]);
385 return Length.interpolate(this.width.get(i), this.width.get(i + 1), r);
386 }
387 }
388 throw new OtsRuntimeException("Unexpected exception: fraction could not be interpolated.");
389 }
390
391
392
393
394
395
396
397 public static Width linear(final Length startWidth, final Length endWidth)
398 {
399 Throw.whenNull(startWidth, "Start width may not be null.");
400 Throw.whenNull(endWidth, "End width may not be null.");
401 try
402 {
403 return new Width(new double[] {0.0, 1.0}, new LengthVector(new Length[] {startWidth, endWidth}, LengthUnit.SI));
404 }
405 catch (ValueRuntimeException exception)
406 {
407 throw new OtsRuntimeException("Unexpected exception: widths could not be put in a vector.", exception);
408 }
409 }
410
411 }
412
413 @Override
414 public final String toString()
415 {
416 return String.format("Headway %s to object %s of type %s", getKinematics().getDistance(), getId(), getObjectType());
417 }
418
419 }