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