1 package org.opentrafficsim.road.network.lane.conflict;
2
3 import java.util.Iterator;
4 import java.util.NoSuchElementException;
5 import java.util.UUID;
6
7 import org.djunits.value.vdouble.scalar.Length;
8 import org.djunits.value.vdouble.scalar.Time;
9 import org.djutils.exceptions.Throw;
10 import org.opentrafficsim.base.parameters.ParameterException;
11 import org.opentrafficsim.core.geometry.OTSGeometryException;
12 import org.opentrafficsim.core.geometry.OTSLine3D;
13 import org.opentrafficsim.core.geometry.OTSPoint3D;
14 import org.opentrafficsim.core.gtu.GTUDirectionality;
15 import org.opentrafficsim.core.gtu.GTUException;
16 import org.opentrafficsim.core.gtu.GTUType;
17 import org.opentrafficsim.core.gtu.RelativePosition;
18 import org.opentrafficsim.core.network.LongitudinalDirectionality;
19 import org.opentrafficsim.core.network.NetworkException;
20 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
21 import org.opentrafficsim.road.gtu.lane.perception.AbstractPerceptionIterable;
22 import org.opentrafficsim.road.gtu.lane.perception.AbstractPerceptionReiterable;
23 import org.opentrafficsim.road.gtu.lane.perception.DownstreamNeighborsIterable;
24 import org.opentrafficsim.road.gtu.lane.perception.LaneDirectionRecord;
25 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
26 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
27 import org.opentrafficsim.road.gtu.lane.perception.UpstreamNeighborsIterable;
28 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
29 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
30 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUReal;
31 import org.opentrafficsim.road.network.lane.CrossSectionElement;
32 import org.opentrafficsim.road.network.lane.Lane;
33 import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
34
35 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
36 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public final class Conflict extends AbstractLaneBasedObject
57 {
58
59
60 private static final long serialVersionUID = 20160915L;
61
62
63 private final ConflictType conflictType;
64
65
66 private final ConflictRule conflictRule;
67
68
69 private Conflict otherConflict;
70
71
72 private final Length length;
73
74
75 private final GTUDirectionality direction;
76
77
78 private final SimulatorInterface.TimeDoubleUnit simulator;
79
80
81 private final GTUType gtuType;
82
83
84 private final boolean permitted;
85
86
87 private final Object cloneLock;
88
89
90
91
92
93
94 private final LaneDirectionRecord root;
95
96
97 private final Length rootPosition;
98
99
100 private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> upstreamGtus;
101
102
103 private Time upstreamTime;
104
105
106 private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> downstreamGtus;
107
108
109 private Time downstreamTime;
110
111
112 private final HeadwayGtuType conflictGtuType = new ConflictGtuType();
113
114
115 private Length maxUpstreamVisibility = Length.ZERO;
116
117
118 private Length maxDownstreamVisibility = Length.ZERO;
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 @SuppressWarnings("checkstyle:parameternumber")
137 private Conflict(final Lane lane, final Length longitudinalPosition, final Length length, final GTUDirectionality direction,
138 final OTSLine3D geometry, final ConflictType conflictType, final ConflictRule conflictRule,
139 final SimulatorInterface.TimeDoubleUnit simulator, final GTUType gtuType, final boolean permitted,
140 final Object cloneLock) throws NetworkException
141 {
142 super(UUID.randomUUID().toString(), lane, Throw.whenNull(direction, "Direction may not be null.").isPlus()
143 ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS, longitudinalPosition, geometry);
144 this.length = length;
145 this.direction = direction;
146 this.conflictType = conflictType;
147 this.conflictRule = conflictRule;
148 this.simulator = simulator;
149 this.gtuType = gtuType;
150 this.permitted = permitted;
151 this.cloneLock = cloneLock;
152
153
154 if (conflictType.equals(ConflictType.SPLIT) || conflictType.equals(ConflictType.MERGE))
155 {
156 Length position =
157 conflictType.equals(ConflictType.SPLIT) ? (direction.isPlus() ? length : lane.getLength().minus(length))
158 : (direction.isPlus() ? lane.getLength() : Length.ZERO);
159 try
160 {
161 new ConflictEnd(this, lane,
162 direction.isPlus() ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS,
163 position);
164 }
165 catch (OTSGeometryException exception)
166 {
167
168 throw new RuntimeException("Could not create dummy geometry for ConflictEnd.", exception);
169 }
170 }
171
172
173 this.rootPosition = direction.isPlus() ? longitudinalPosition : lane.getLength().minus(longitudinalPosition);
174 this.root = new LaneDirectionRecord(lane, direction, this.rootPosition.neg(), GTUType.VEHICLE);
175 }
176
177
178
179
180
181 private void provideUpstreamVisibility(final Length visibility)
182 {
183 if (visibility.gt(this.maxUpstreamVisibility))
184 {
185 this.maxUpstreamVisibility = visibility;
186 this.upstreamTime = null;
187 this.downstreamTime = null;
188 }
189 }
190
191
192
193
194
195 private void provideDownstreamVisibility(final Length visibility)
196 {
197 if (visibility.gt(this.maxDownstreamVisibility))
198 {
199 this.maxDownstreamVisibility = visibility;
200 this.upstreamTime = null;
201 this.downstreamTime = null;
202 }
203 }
204
205
206
207
208
209
210
211
212 public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getUpstreamGtus(final LaneBasedGTU perceivingGtu,
213 final HeadwayGtuType headwayGtuType, final Length visibility)
214 {
215 provideUpstreamVisibility(visibility);
216 Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
217 if (this.upstreamTime == null || !time.eq(this.upstreamTime))
218 {
219
220 this.upstreamGtus =
221 new UpstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition, this.maxUpstreamVisibility,
222 RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT);
223 this.upstreamTime = time;
224 }
225
226 return new ConflictGtuIterable(perceivingGtu, headwayGtuType, visibility, false, this.upstreamGtus);
227 }
228
229
230
231
232
233
234
235
236 public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getDownstreamGtus(final LaneBasedGTU perceivingGtu,
237 final HeadwayGtuType headwayGtuType, final Length visibility)
238 {
239 provideDownstreamVisibility(visibility);
240 Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
241 if (this.downstreamTime == null || !time.eq(this.downstreamTime))
242 {
243
244 boolean ignoreIfUpstream = false;
245 this.downstreamGtus = new DownstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition,
246 this.maxDownstreamVisibility, RelativePosition.REFERENCE_POSITION, this.conflictGtuType, null,
247 RelativeLane.CURRENT, ignoreIfUpstream);
248 this.downstreamTime = time;
249 }
250
251 return new ConflictGtuIterable(perceivingGtu, new OverlapHeadway(headwayGtuType), visibility, true,
252 this.downstreamGtus);
253 }
254
255
256
257
258 public ConflictType getConflictType()
259 {
260 return this.conflictType;
261 }
262
263
264
265
266 public ConflictRule getConflictRule()
267 {
268 return this.conflictRule;
269 }
270
271
272
273
274 public ConflictPriority conflictPriority()
275 {
276 return this.conflictRule.determinePriority(this);
277 }
278
279
280
281
282 public Length getLength()
283 {
284 return this.length;
285 }
286
287
288
289
290 public Conflict getOtherConflict()
291 {
292 return this.otherConflict;
293 }
294
295
296
297
298 public GTUType getGtuType()
299 {
300 return this.gtuType;
301 }
302
303
304
305
306
307 public boolean isPermitted()
308 {
309 return this.permitted;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332 @SuppressWarnings("checkstyle:parameternumber")
333 public static void generateConflictPair(final ConflictType conflictType, final ConflictRule conflictRule,
334 final boolean permitted, final Lane lane1, final Length longitudinalPosition1, final Length length1,
335 final GTUDirectionality direction1, final OTSLine3D geometry1, final GTUType gtuType1, final Lane lane2,
336 final Length longitudinalPosition2, final Length length2, final GTUDirectionality direction2,
337 final OTSLine3D geometry2, final GTUType gtuType2, final DEVSSimulatorInterface.TimeDoubleUnit simulator)
338 throws NetworkException
339 {
340
341 Throw.whenNull(conflictType, "Conflict type may not be null.");
342
343 Object cloneLock = new Object();
344 Conflict conf1 = new Conflict(lane1, longitudinalPosition1, length1, direction1, geometry1, conflictType, conflictRule,
345 simulator, gtuType1, permitted, cloneLock);
346 Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule,
347 simulator, gtuType2, permitted, cloneLock);
348 conf1.otherConflict = conf2;
349 conf2.otherConflict = conf1;
350 }
351
352
353 @Override
354 public String toString()
355 {
356 return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
357 }
358
359
360
361
362 private Conflict otherClone;
363
364
365 @Override
366 public Conflict clone(final CrossSectionElement newCSE, final SimulatorInterface.TimeDoubleUnit newSimulator)
367 throws NetworkException
368 {
369 Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
370 Throw.when(!(newSimulator instanceof DEVSSimulatorInterface.TimeDoubleUnit), NetworkException.class,
371 "simulator should be a DEVSSimulator");
372 Conflict out = new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, this.direction, getGeometry(),
373 this.conflictType, this.conflictRule.clone(newSimulator), newSimulator, this.gtuType, this.permitted,
374 this.cloneLock);
375 synchronized (this.cloneLock)
376 {
377
378 if (this.otherClone == null || this.otherClone.simulator != newSimulator)
379 {
380
381 this.otherConflict.otherClone = out;
382 }
383 else
384 {
385 out.otherConflict = this.otherClone;
386 this.otherClone.otherConflict = out;
387 }
388
389 this.otherClone = null;
390 }
391 return out;
392 }
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407 public class ConflictEnd extends AbstractLaneBasedObject
408 {
409
410 private static final long serialVersionUID = 20161214L;
411
412
413 private final Conflict conflict;
414
415
416
417
418
419
420
421
422
423 ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
424 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
425 {
426 super(conflict.getId() + "End", lane, direction, longitudinalPosition,
427 new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
428 this.conflict = conflict;
429 }
430
431
432
433
434 public final Conflict getConflict()
435 {
436 return this.conflict;
437 }
438
439
440 @Override
441 public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE,
442 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NetworkException
443 {
444
445 return null;
446 }
447
448
449 @Override
450 public final String toString()
451 {
452 return "ConflictEnd [conflict=" + this.conflict + "]";
453 }
454 }
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474 private class ConflictGtu extends HeadwayGTUReal
475 {
476
477 private static final long serialVersionUID = 20180221L;
478
479
480 private final LaneBasedGTU gtu;
481
482
483
484
485
486
487
488
489
490 ConflictGtu(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear)
491 throws GTUException
492 {
493 super(gtu, overlapFront, overlap, overlapRear, true);
494 this.gtu = gtu;
495 }
496
497
498
499
500
501
502
503 ConflictGtu(final LaneBasedGTU gtu, final Length distance) throws GTUException
504 {
505 super(gtu, distance, true);
506 this.gtu = gtu;
507 }
508 }
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523 private class ConflictGtuType implements HeadwayGtuType
524 {
525
526 ConflictGtuType()
527 {
528
529 }
530
531
532 @Override
533 public ConflictGtu createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
534 final Length distance, final boolean downstream) throws GTUException
535 {
536 return new ConflictGtu(perceivedGtu, distance);
537 }
538
539
540 @Override
541 public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
542 final Length distance) throws GTUException, ParameterException
543 {
544 return new ConflictGtu(perceivedGtu, distance);
545 }
546
547
548 @Override
549 public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
550 final Length distance) throws GTUException, ParameterException
551 {
552 return new ConflictGtu(perceivedGtu, distance);
553 }
554
555
556 @Override
557 public ConflictGtu createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
558 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
559 {
560 throw new UnsupportedOperationException("ConflictGtuType is a pass-through type, no actual perception is allowed.");
561 }
562 }
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578 private class OverlapHeadway implements HeadwayGtuType
579 {
580
581 private HeadwayGtuType wrappedType;
582
583
584
585
586
587 OverlapHeadway(final HeadwayGtuType wrappedType)
588 {
589 this.wrappedType = wrappedType;
590 }
591
592
593 @Override
594 public HeadwayGTU createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu, final Length dist,
595 final boolean downstream) throws GTUException, ParameterException
596 {
597 if (dist.ge(getLength()))
598 {
599
600 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
601 }
602 else
603 {
604 Length overlapRear = dist;
605 Length overlap = getLength();
606 Length overlapFront = dist.plus(perceivedGtu.getLength()).minus(getLength());
607 if (overlapFront.lt0())
608 {
609 overlap = overlap.plus(overlapFront);
610 }
611 if (overlapRear.gt0())
612 {
613 overlap = overlap.minus(overlapRear);
614 }
615 return createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
616 }
617 }
618
619
620 @Override
621 public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
622 final Length distance) throws GTUException, ParameterException
623 {
624 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
625 }
626
627
628 @Override
629 public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
630 final Length distance) throws GTUException, ParameterException
631 {
632 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
633 }
634
635
636 @Override
637 public HeadwayGTU createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
638 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
639 {
640 return this.wrappedType.createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
641 }
642 }
643
644
645
646
647
648
649
650
651
652
653
654
655
656 private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
657 {
658
659 private final HeadwayGtuType headwayGtuType;
660
661
662 private final Length visibility;
663
664
665 private final boolean downstream;
666
667
668 private final Iterator<HeadwayGTU> baseIterator;
669
670
671
672
673
674
675
676
677 ConflictGtuIterable(final LaneBasedGTU perceivingGtu, final HeadwayGtuType headwayGtuType, final Length visibility,
678 final boolean downstream, final AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> base)
679 {
680 super(perceivingGtu);
681 this.headwayGtuType = headwayGtuType;
682 this.visibility = visibility;
683 this.downstream = downstream;
684 this.baseIterator = base.iterator();
685 }
686
687
688 @Override
689 protected Iterator<PrimaryIteratorEntry> primaryIterator()
690 {
691
692
693
694 class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
695 {
696
697 private PrimaryIteratorEntry next;
698
699
700 @SuppressWarnings("synthetic-access")
701 @Override
702 public boolean hasNext()
703 {
704 if (this.next == null)
705 {
706 if (ConflictGtuIterable.this.baseIterator.hasNext())
707 {
708
709 ConflictGtu gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
710 if (gtu.getDistance() == null || gtu.getDistance().le(ConflictGtuIterable.this.visibility))
711 {
712 this.next = new PrimaryIteratorEntry(gtu.gtu, gtu.getDistance());
713 }
714 }
715 }
716 return this.next != null;
717 }
718
719
720 @Override
721 public PrimaryIteratorEntry next()
722 {
723 if (hasNext())
724 {
725 PrimaryIteratorEntry out = this.next;
726 this.next = null;
727 return out;
728 }
729 throw new NoSuchElementException();
730 }
731 }
732 return new ConflictGtuIterator();
733 }
734
735
736 @Override
737 protected HeadwayGTU perceive(final LaneBasedGTU perceivingGtu, final LaneBasedGTU object, final Length distance)
738 throws GTUException, ParameterException
739 {
740 return this.headwayGtuType.createHeadwayGtu(perceivingGtu, object, distance, this.downstream);
741 }
742 }
743
744 }