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(),
175 lane.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE));
176 }
177
178
179
180
181
182 private void provideUpstreamVisibility(final Length visibility)
183 {
184 if (visibility.gt(this.maxUpstreamVisibility))
185 {
186 this.maxUpstreamVisibility = visibility;
187 this.upstreamTime = null;
188 this.downstreamTime = null;
189 }
190 }
191
192
193
194
195
196 private void provideDownstreamVisibility(final Length visibility)
197 {
198 if (visibility.gt(this.maxDownstreamVisibility))
199 {
200 this.maxDownstreamVisibility = visibility;
201 this.upstreamTime = null;
202 this.downstreamTime = null;
203 }
204 }
205
206
207
208
209
210
211
212
213 public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getUpstreamGtus(final LaneBasedGTU perceivingGtu,
214 final HeadwayGtuType headwayGtuType, final Length visibility)
215 {
216 provideUpstreamVisibility(visibility);
217 Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
218 if (this.upstreamTime == null || !time.eq(this.upstreamTime))
219 {
220
221 this.upstreamGtus =
222 new UpstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition, this.maxUpstreamVisibility,
223 RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT);
224 this.upstreamTime = time;
225 }
226
227 return new ConflictGtuIterable(perceivingGtu, headwayGtuType, visibility, false, this.upstreamGtus);
228 }
229
230
231
232
233
234
235
236
237 public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getDownstreamGtus(final LaneBasedGTU perceivingGtu,
238 final HeadwayGtuType headwayGtuType, final Length visibility)
239 {
240 provideDownstreamVisibility(visibility);
241 Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
242 if (this.downstreamTime == null || !time.eq(this.downstreamTime))
243 {
244
245 boolean ignoreIfUpstream = false;
246 this.downstreamGtus = new DownstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition,
247 this.maxDownstreamVisibility, RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT,
248 ignoreIfUpstream);
249 this.downstreamTime = time;
250 }
251
252 return new ConflictGtuIterable(perceivingGtu, new OverlapHeadway(headwayGtuType), visibility, true,
253 this.downstreamGtus);
254 }
255
256
257
258
259 public ConflictType getConflictType()
260 {
261 return this.conflictType;
262 }
263
264
265
266
267 public ConflictRule getConflictRule()
268 {
269 return this.conflictRule;
270 }
271
272
273
274
275 public ConflictPriority conflictPriority()
276 {
277 return this.conflictRule.determinePriority(this);
278 }
279
280
281
282
283 public Length getLength()
284 {
285 return this.length;
286 }
287
288
289
290
291 public Conflict getOtherConflict()
292 {
293 return this.otherConflict;
294 }
295
296
297
298
299 public GTUType getGtuType()
300 {
301 return this.gtuType;
302 }
303
304
305
306
307
308 public boolean isPermitted()
309 {
310 return this.permitted;
311 }
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 @SuppressWarnings("checkstyle:parameternumber")
334 public static void generateConflictPair(final ConflictType conflictType, final ConflictRule conflictRule,
335 final boolean permitted, final Lane lane1, final Length longitudinalPosition1, final Length length1,
336 final GTUDirectionality direction1, final OTSLine3D geometry1, final GTUType gtuType1, final Lane lane2,
337 final Length longitudinalPosition2, final Length length2, final GTUDirectionality direction2,
338 final OTSLine3D geometry2, final GTUType gtuType2, final DEVSSimulatorInterface.TimeDoubleUnit simulator)
339 throws NetworkException
340 {
341
342 Throw.whenNull(conflictType, "Conflict type may not be null.");
343
344 Object cloneLock = new Object();
345 Conflict conf1 = new Conflict(lane1, longitudinalPosition1, length1, direction1, geometry1, conflictType, conflictRule,
346 simulator, gtuType1, permitted, cloneLock);
347 Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule,
348 simulator, gtuType2, permitted, cloneLock);
349 conf1.otherConflict = conf2;
350 conf2.otherConflict = conf1;
351 }
352
353
354 @Override
355 public String toString()
356 {
357 return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
358 }
359
360
361
362
363 private Conflict otherClone;
364
365
366 @Override
367 public Conflict clone(final CrossSectionElement newCSE, final SimulatorInterface.TimeDoubleUnit newSimulator)
368 throws NetworkException
369 {
370 Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
371 Throw.when(!(newSimulator instanceof DEVSSimulatorInterface.TimeDoubleUnit), NetworkException.class,
372 "simulator should be a DEVSSimulator");
373 Conflict out = new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, this.direction, getGeometry(),
374 this.conflictType, this.conflictRule.clone(newSimulator), newSimulator, this.gtuType, this.permitted,
375 this.cloneLock);
376 synchronized (this.cloneLock)
377 {
378
379 if (this.otherClone == null || this.otherClone.simulator != newSimulator)
380 {
381
382 this.otherConflict.otherClone = out;
383 }
384 else
385 {
386 out.otherConflict = this.otherClone;
387 this.otherClone.otherConflict = out;
388 }
389
390 this.otherClone = null;
391 }
392 return out;
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408 public class ConflictEnd extends AbstractLaneBasedObject
409 {
410
411 private static final long serialVersionUID = 20161214L;
412
413
414 private final Conflict conflict;
415
416
417
418
419
420
421
422
423
424 ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
425 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
426 {
427 super(conflict.getId() + "End", lane, direction, longitudinalPosition,
428 new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
429 this.conflict = conflict;
430 }
431
432
433
434
435 public final Conflict getConflict()
436 {
437 return this.conflict;
438 }
439
440
441 @Override
442 public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE,
443 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NetworkException
444 {
445
446 return null;
447 }
448
449
450 @Override
451 public final String toString()
452 {
453 return "ConflictEnd [conflict=" + this.conflict + "]";
454 }
455 }
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475 private class ConflictGtu extends HeadwayGTUReal
476 {
477
478 private static final long serialVersionUID = 20180221L;
479
480
481 private final LaneBasedGTU gtu;
482
483
484
485
486
487
488
489
490
491 ConflictGtu(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear)
492 throws GTUException
493 {
494 super(gtu, overlapFront, overlap, overlapRear, true);
495 this.gtu = gtu;
496 }
497
498
499
500
501
502
503
504 ConflictGtu(final LaneBasedGTU gtu, final Length distance) throws GTUException
505 {
506 super(gtu, distance, true);
507 this.gtu = gtu;
508 }
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524 private class ConflictGtuType implements HeadwayGtuType
525 {
526
527 ConflictGtuType()
528 {
529
530 }
531
532
533 @Override
534 public ConflictGtu createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
535 final Length distance, final boolean downstream) throws GTUException
536 {
537 return new ConflictGtu(perceivedGtu, distance);
538 }
539
540
541 @Override
542 public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
543 final Length distance) throws GTUException, ParameterException
544 {
545 return new ConflictGtu(perceivedGtu, distance);
546 }
547
548
549 @Override
550 public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
551 final Length distance) throws GTUException, ParameterException
552 {
553 return new ConflictGtu(perceivedGtu, distance);
554 }
555
556
557 @Override
558 public ConflictGtu createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
559 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
560 {
561 throw new UnsupportedOperationException("ConflictGtuType is a pass-through type, no actual perception is allowed.");
562 }
563 }
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579 private class OverlapHeadway implements HeadwayGtuType
580 {
581
582 private HeadwayGtuType wrappedType;
583
584
585
586
587
588 OverlapHeadway(final HeadwayGtuType wrappedType)
589 {
590 this.wrappedType = wrappedType;
591 }
592
593
594 @Override
595 public HeadwayGTU createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu, final Length dist,
596 final boolean downstream) throws GTUException, ParameterException
597 {
598 if (dist.ge(getLength()))
599 {
600
601 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
602 }
603 else
604 {
605 Length overlapRear = dist;
606 Length overlap = getLength();
607 Length overlapFront = dist.plus(perceivedGtu.getLength()).minus(getLength());
608 if (overlapFront.lt0())
609 {
610 overlap = overlap.plus(overlapFront);
611 }
612 if (overlapRear.gt0())
613 {
614 overlap = overlap.minus(overlapRear);
615 }
616 return createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
617 }
618 }
619
620
621 @Override
622 public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
623 final Length distance) throws GTUException, ParameterException
624 {
625 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
626 }
627
628
629 @Override
630 public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
631 final Length distance) throws GTUException, ParameterException
632 {
633 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
634 }
635
636
637 @Override
638 public HeadwayGTU createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
639 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
640 {
641 return this.wrappedType.createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
642 }
643 }
644
645
646
647
648
649
650
651
652
653
654
655
656
657 private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
658 {
659
660 private final HeadwayGtuType headwayGtuType;
661
662
663 private final Length visibility;
664
665
666 private final boolean downstream;
667
668
669 private final Iterator<HeadwayGTU> baseIterator;
670
671
672
673
674
675
676
677
678 ConflictGtuIterable(final LaneBasedGTU perceivingGtu, final HeadwayGtuType headwayGtuType, final Length visibility,
679 final boolean downstream, final AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> base)
680 {
681 super(perceivingGtu);
682 this.headwayGtuType = headwayGtuType;
683 this.visibility = visibility;
684 this.downstream = downstream;
685 this.baseIterator = base.iterator();
686 }
687
688
689 @Override
690 protected Iterator<PrimaryIteratorEntry> primaryIterator()
691 {
692
693
694
695 class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
696 {
697
698 private PrimaryIteratorEntry next;
699
700
701 @SuppressWarnings("synthetic-access")
702 @Override
703 public boolean hasNext()
704 {
705 if (this.next == null)
706 {
707 if (ConflictGtuIterable.this.baseIterator.hasNext())
708 {
709
710 ConflictGtu gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
711 if (gtu.getDistance() == null || gtu.getDistance().le(ConflictGtuIterable.this.visibility))
712 {
713 this.next = new PrimaryIteratorEntry(gtu.gtu, gtu.getDistance());
714 }
715 }
716 }
717 return this.next != null;
718 }
719
720
721 @Override
722 public PrimaryIteratorEntry next()
723 {
724 if (hasNext())
725 {
726 PrimaryIteratorEntry out = this.next;
727 this.next = null;
728 return out;
729 }
730 throw new NoSuchElementException();
731 }
732 }
733 return new ConflictGtuIterator();
734 }
735
736
737 @Override
738 protected HeadwayGTU perceive(final LaneBasedGTU perceivingGtu, final LaneBasedGTU object, final Length distance)
739 throws GTUException, ParameterException
740 {
741 return this.headwayGtuType.createHeadwayGtu(perceivingGtu, object, distance, this.downstream);
742 }
743 }
744
745 }