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