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 * Conflicts deal with traffic on different links/roads that need to consider each other as their paths may be in conflict
44 * spatially. A single {@code Conflict} represents the one-sided consideration of a conflicting situation. I.e., what is
45 * considered <i>a single conflict in traffic theory, is represented by two {@code Conflict}s</i>, one on each of the
46 * conflicting {@code Lane}s.<br>
47 * <br>
48 * This class provides easy access to upstream and downstream GTUs through {@code PerceptionIterable}s using methods
49 * {@code getUpstreamGtus} and {@code getDownstreamGtus}. These methods are efficient in that they reuse underlying data
50 * structures if the GTUs are requested at the same time by another GTU.
51 * <p>
52 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
53 * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
54 * <p>
55 * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 7, 2016 <br>
56 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
57 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
58 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
59 */
60 public final class Conflict extends AbstractLaneBasedObject
61 {
62
63 /** */
64 private static final long serialVersionUID = 20160915L;
65
66 /** Conflict type, i.e. crossing, merge or split. */
67 private final ConflictType conflictType;
68
69 /** Conflict rule, i.e. priority, give way, stop or all-stop. */
70 private final ConflictRule conflictRule;
71
72 /** Accompanying other conflict. */
73 private Conflict otherConflict;
74
75 /** The length of the conflict along the lane centerline. */
76 private final Length length;
77
78 /** GTU direction. */
79 private final GTUDirectionality direction;
80
81 /** Simulator for animation and timed events. */
82 private final SimulatorInterface.TimeDoubleUnit simulator;
83
84 /** GTU type. */
85 private final GTUType gtuType;
86
87 /** Whether the conflict is a permitted conflict in traffic light control. */
88 private final boolean permitted;
89
90 /** Lock object for cloning a pair of conflicts. */
91 private final Object cloneLock;
92
93 /////////////////////////////////////////////////////////////////
94 // Properties regarding upstream and downstream GTUs provision //
95 /////////////////////////////////////////////////////////////////
96
97 /** Root for GTU search. */
98 private final LaneDirectionRecord root;
99
100 /** Position on the root. */
101 private final Length rootPosition;
102
103 /** Current upstream GTUs provider. */
104 private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> upstreamGtus;
105
106 /** Upstream GTUs update time. */
107 private Time upstreamTime;
108
109 /** Current downstream GTUs provider. */
110 private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> downstreamGtus;
111
112 /** Downstream GTUs update time. */
113 private Time downstreamTime;
114
115 /** Headway type for the provided GTUs. */
116 private final HeadwayGtuType conflictGtuType = new ConflictGtuType();
117
118 /** Distance within which upstreamGTUs are provided (is automatically enlarged). */
119 private Length maxUpstreamVisibility = Length.ZERO;
120
121 /** Distance within which downstreamGTUs are provided (is automatically enlarged). */
122 private Length maxDownstreamVisibility = Length.ZERO;
123
124 /////////////////////////////////////////////////////////////////
125
126 /**
127 * @param lane lane where this conflict starts
128 * @param longitudinalPosition position of start of conflict on lane
129 * @param length length of the conflict along the lane centerline
130 * @param direction GTU direction
131 * @param geometry geometry of conflict
132 * @param conflictRule conflict rule, i.e. determines priority, give way, stop or all-stop
133 * @param conflictType conflict type, i.e. crossing, merge or split
134 * @param simulator the simulator for animation and timed events
135 * @param permitted whether the conflict is permitted in traffic light control
136 * @param gtuType gtu type
137 * @param cloneLock lock object for cloning a pair of conflicts
138 * @throws NetworkException when the position on the lane is out of bounds
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 // Create conflict end
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 // does not happen
181 throw new RuntimeException("Could not create dummy geometry for ConflictEnd.", exception);
182 }
183 }
184
185 // Lane record for GTU provision
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 * Make sure the conflict can provide the given upstream visibility.
192 * @param visibility Length; visibility to guarantee
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 * Make sure the conflict can provide the given downstream visibility.
206 * @param visibility Length; visibility to guarantee
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 * Provides the upstream GTUs.
220 * @param perceivingGtu LaneBasedGTU; perceiving GTU
221 * @param headwayGtuType HeadwayGtuType; headway GTU type to use
222 * @param visibility Length; distance over which GTU's are provided
223 * @return PerceptionIterable<HeadwayGtU>; iterable over the upstream GTUs
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 // setup a base iterable to provide the GTUs
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 // return iterable that uses the base iterable
239 return new ConflictGtuIterable(perceivingGtu, headwayGtuType, visibility, false, this.upstreamGtus);
240 }
241
242 /**
243 * Provides the downstream GTUs.
244 * @param perceivingGtu LaneBasedGTU; perceiving GTU
245 * @param headwayGtuType HeadwayGtuType; headway GTU type to use
246 * @param visibility Length; distance over which GTU's are provided
247 * @return PerceptionIterable<HeadwayGtU>; iterable over the downstream GTUs
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 // setup a base iterable to provide the GTUs
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 // return iterable that uses the base iterable
264 return new ConflictGtuIterable(perceivingGtu, new OverlapHeadway(headwayGtuType), visibility, true,
265 this.downstreamGtus);
266 }
267
268 /**
269 * @return conflictType.
270 */
271 public ConflictType getConflictType()
272 {
273 return this.conflictType;
274 }
275
276 /**
277 * @return conflictRule.
278 */
279 public ConflictRule getConflictRule()
280 {
281 return this.conflictRule;
282 }
283
284 /**
285 * @return conflictPriority.
286 */
287 public ConflictPriority conflictPriority()
288 {
289 return this.conflictRule.determinePriority(this);
290 }
291
292 /**
293 * @return length.
294 */
295 public Length getLength()
296 {
297 return this.length;
298 }
299
300 /**
301 * @return otherConflict.
302 */
303 public Conflict getOtherConflict()
304 {
305 return this.otherConflict;
306 }
307
308 /**
309 * @return gtuType.
310 */
311 public GTUType getGtuType()
312 {
313 return this.gtuType;
314 }
315
316 /**
317 * If permitted, traffic upstream of traffic lights may not be ignored, as these can have green light.
318 * @return permitted.
319 */
320 public boolean isPermitted()
321 {
322 return this.permitted;
323 }
324
325 /**
326 * Creates a pair of conflicts.
327 * @param conflictType conflict type, i.e. crossing, merge or split
328 * @param conflictRule conflict rule
329 * @param permitted whether the conflict is permitted in traffic light control
330 * @param lane1 lane of conflict 1
331 * @param longitudinalPosition1 longitudinal position of conflict 1
332 * @param length1 {@code Length} of conflict 1
333 * @param direction1 GTU direction of conflict 1
334 * @param geometry1 geometry of conflict 1
335 * @param gtuType1 gtu type of conflict 1
336 * @param lane2 lane of conflict 2
337 * @param longitudinalPosition2 longitudinal position of conflict 2
338 * @param length2 {@code Length} of conflict 2
339 * @param direction2 GTU direction of conflict 2
340 * @param geometry2 geometry of conflict 2
341 * @param gtuType2 gtu type of conflict 2
342 * @param simulator the simulator for animation and timed events
343 * @throws NetworkException if the combination of conflict type and both conflict rules is not correct
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 // lane, longitudinalPosition, length and geometry are checked in AbstractLaneBasedObject
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 /** {@inheritDoc} */
366 @Override
367 public String toString()
368 {
369 return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
370 }
371
372 /**
373 * Clone of other conflict.
374 */
375 private Conflict otherClone;
376
377 /** {@inheritDoc} */
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 // couple both clones
391 if (this.otherClone == null || this.otherClone.simulator != newSimulator)
392 {
393 // other clone will do it
394 this.otherConflict.otherClone = out;
395 }
396 else
397 {
398 out.otherConflict = this.otherClone;
399 this.otherClone.otherConflict = out;
400 }
401 // reset successful clone of pair, or remove otherClone from other simulator (or was already null)
402 this.otherClone = null;
403 }
404 return out;
405 }
406
407 /**
408 * Light-weight lane based object to indicate the end of a conflict. It is used to perceive conflicts when a GTU is on the
409 * conflict area, and hence the conflict lane based object is usptream.
410 * <p>
411 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
412 * <br>
413 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
414 * <p>
415 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 dec. 2016 <br>
416 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
417 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
418 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
419 */
420 public class ConflictEnd extends AbstractLaneBasedObject
421 {
422 /** */
423 private static final long serialVersionUID = 20161214L;
424
425 /** Conflict. */
426 private final Conflict conflict;
427
428 /**
429 * @param conflict conflict
430 * @param lane lane
431 * @param direction valid direction
432 * @param longitudinalPosition position
433 * @throws NetworkException on network exception
434 * @throws OTSGeometryException does not happen
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 * @return conflict
446 */
447 public final Conflict getConflict()
448 {
449 return this.conflict;
450 }
451
452 /** {@inheritDoc} */
453 @Override
454 public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE, final SimulatorInterface.TimeDoubleUnit newSimulator,
455 final boolean animation) throws NetworkException
456 {
457 // Constructor of Conflict creates these.
458 return null;
459 }
460
461 /** {@inheritDoc} */
462 @Override
463 public final String toString()
464 {
465 return "ConflictEnd [conflict=" + this.conflict + "]";
466 }
467 }
468
469 /**
470 * HeadwayGTU that is returned by base iterators for upstream and downstream GTUs. This class is used with both
471 * {@code UpstreamNeighborsIterable} and {@code DownstreamNeighborsIterable} which work with HeadwayGTU. The role of this
472 * class is however to simply provide the GTU itself such that other specific HeadwayGTU types can be created with it.
473 * Therefore, it extends HeadwayGTUReal which simply wraps the GTU. As the HeadwayGTUReal class has the actual GTU hidden,
474 * this class can provide it.
475 * <p>
476 * FIXME: why not create a getter for the gtu in the super class?
477 * <p>
478 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
479 * <br>
480 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
481 * <p>
482 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
483 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
484 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
485 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
486 */
487 private class ConflictGtu extends HeadwayGTUReal
488 {
489 /** */
490 private static final long serialVersionUID = 20180221L;
491
492 /** Visible pointer to the GTU (which HeadwayGTUReal has not). */
493 private final LaneBasedGTU gtu;
494
495 /**
496 * Constructor.
497 * @param gtu LaneBasedGTU; gtu
498 * @param overlapFront Length; front overlap
499 * @param overlap Length; overlap
500 * @param overlapRear Length; rear overlap
501 * @throws GTUException on exception
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 * Constructor.
512 * @param gtu LaneBasedGTU; gtu
513 * @param distance Length; distance
514 * @throws GTUException on exception
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 * HeadwayGtuType that generates ConflictGtu's, for use within the base iterators for upstream and downstream neighbors.
525 * This result is used by secondary iterators (ConflictGtuIterable) to provide the requested specific HeadwatGtuType.
526 * <p>
527 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
528 * <br>
529 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
530 * <p>
531 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
532 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
533 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
534 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
535 */
536 private class ConflictGtuType implements HeadwayGtuType
537 {
538 /** Constructor. */
539 ConflictGtuType()
540 {
541 //
542 }
543
544 /** {@inheritDoc} */
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 /** {@inheritDoc} */
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 * HeadwayGtuType that changes a negative headway in to an overlapping headway, by forwarding the request to a wrapped
563 * HeadwayGtuType. This is used for downstream GTUs of the conflict, accounting also for the length of the conflict. Hence,
564 * overlap information concerns the conflict and a downstream GTU (downstream of the start of the conflict).
565 * <p>
566 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
567 * <br>
568 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
569 * <p>
570 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
571 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
572 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
573 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
574 */
575 private class OverlapHeadway implements HeadwayGtuType
576 {
577 /** Wrapped headway type. */
578 private HeadwayGtuType wrappedType;
579
580 /**
581 * Constructor.
582 * @param wrappedType HeadwayGtuType; wrapped headway type
583 */
584 OverlapHeadway(final HeadwayGtuType wrappedType)
585 {
586 this.wrappedType = wrappedType;
587 }
588
589 /** {@inheritDoc} */
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 // GTU fully downstream of the conflict
597 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
598 }
599 else
600 {
601 Length overlapRear = dist;
602 Length overlap = getLength(); // start with conflict length
603 Length overlapFront = dist.plus(perceivedGtu.getLength()).minus(getLength());
604 if (overlapFront.lt0())
605 {
606 overlap = overlap.plus(overlapFront); // subtract front being before the conflict end
607 }
608 if (overlapRear.gt0())
609 {
610 overlap = overlap.minus(overlapRear); // subtract rear being past the conflict start
611 }
612 return createHeadwayGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
613 }
614 }
615
616 /** {@inheritDoc} */
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 * Iterable for upstream and downstream GTUs of a conflict, which uses a base iterable.
627 * <p>
628 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
629 * <br>
630 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
631 * <p>
632 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
633 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
634 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
635 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
636 */
637 private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
638 {
639 /** HeadwayGTU type. */
640 private final HeadwayGtuType headwayGtuType;
641
642 /** Guaranteed visibility. */
643 private final Length visibility;
644
645 /** Downstream (or upstream) neighbors. */
646 private final boolean downstream;
647
648 /** Base iterator of the base iterable. */
649 private final Iterator<HeadwayGTU> baseIterator;
650
651 /**
652 * @param perceivingGtu LaneBasedGTU; perceiving GTU
653 * @param headwayGtuType HeadwayGtuType; HeadwayGTU type
654 * @param visibility Length; guaranteed visibility
655 * @param downstream boolean; downstream (or upstream) neighbors
656 * @param base AbstractPerceptionIterable; base iterable from the conflict
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 /** {@inheritDoc} */
670 @Override
671 protected Iterator<PrimaryIteratorEntry> primaryIterator()
672 {
673 /**
674 * Iterator that iterates over PrimaryIteratorEntry objects.
675 */
676 class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
677 {
678 /** Next entry. */
679 private PrimaryIteratorEntry next;
680
681 /** {@inheritDoc} */
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 // ConflictGtuIterable is a private class, only used with ConflictGtuType
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 /** {@inheritDoc} */
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 /** {@inheritDoc} */
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 }