1 package org.opentrafficsim.road.gtu.lane;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.EnumMap;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.LinkedHashMap;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13
14 import javax.media.j3d.Bounds;
15 import javax.vecmath.Point3d;
16
17 import nl.tudelft.simulation.dsol.SimRuntimeException;
18 import nl.tudelft.simulation.language.d3.BoundingBox;
19 import nl.tudelft.simulation.language.d3.DirectedPoint;
20
21 import org.djunits.unit.AccelerationUnit;
22 import org.djunits.unit.LengthUnit;
23 import org.djunits.unit.SpeedUnit;
24 import org.djunits.unit.TimeUnit;
25 import org.djunits.value.ValueException;
26 import org.djunits.value.vdouble.vector.DoubleVector;
27 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
28 import org.opentrafficsim.core.gtu.AbstractGTU;
29 import org.opentrafficsim.core.gtu.GTUException;
30 import org.opentrafficsim.core.gtu.GTUType;
31 import org.opentrafficsim.core.gtu.RelativePosition;
32 import org.opentrafficsim.core.network.LateralDirectionality;
33 import org.opentrafficsim.core.network.Link;
34 import org.opentrafficsim.core.network.NetworkException;
35 import org.opentrafficsim.core.network.Node;
36 import org.opentrafficsim.road.gtu.animation.LaneChangeUrgeGTUColorer;
37 import org.opentrafficsim.road.gtu.following.GTUFollowingModel;
38 import org.opentrafficsim.road.gtu.following.HeadwayGTU;
39 import org.opentrafficsim.road.gtu.lane.changing.LaneChangeModel;
40 import org.opentrafficsim.road.gtu.lane.changing.LaneMovementStep;
41 import org.opentrafficsim.road.network.lane.CrossSectionElement;
42 import org.opentrafficsim.road.network.lane.CrossSectionLink;
43 import org.opentrafficsim.road.network.lane.Lane;
44 import org.opentrafficsim.road.network.route.AbstractLaneBasedRouteNavigator;
45 import org.opentrafficsim.road.network.route.LaneBasedRouteNavigator;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public abstract class AbstractLaneBasedGTU extends AbstractGTU implements LaneBasedGTU
73 {
74
75 private static final long serialVersionUID = 20140822L;
76
77
78 private Time.Abs lastEvaluationTime;
79
80
81 private Time.Abs nextEvaluationTime;
82
83
84 private Length.Abs odometer = new Length.Abs(0, LengthUnit.SI);
85
86
87 private LaneChangeUrgeGTUColorer.LaneChangeDistanceAndDirection lastLaneChangeDistanceAndDirection =
88 new LaneChangeUrgeGTUColorer.LaneChangeDistanceAndDirection(new Length.Rel(Double.MAX_VALUE, LengthUnit.SI), null);
89
90
91
92
93
94
95 private final Map<Link, Double> fractionalLinkPositions = new LinkedHashMap<>();
96
97
98
99
100
101
102
103 private final List<Lane> lanes = new ArrayList<>();
104
105
106
107
108
109 private final Map<Lane, EnumMap<LateralDirectionality, Set<Lane>>> accessibleAdjacentLanes = new HashMap<>();
110
111
112 private Speed.Abs speed;
113
114
115 private Speed.Abs lateralVelocity;
116
117
118 private Acceleration.Abs acceleration = new Acceleration.Abs(0, METER_PER_SECOND_2);
119
120
121 private final GTUFollowingModel gtuFollowingModel;
122
123
124 private final LaneChangeModel laneChangeModel;
125
126
127 private final LaneBasedRouteNavigator routeNavigator;
128
129
130 private Object lock = new Object();
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 @SuppressWarnings("checkstyle:parameternumber")
147 public AbstractLaneBasedGTU(final String id, final GTUType gtuType, final GTUFollowingModel gtuFollowingModel,
148 final LaneChangeModel laneChangeModel, final Map<Lane, Length.Rel> initialLongitudinalPositions,
149 final Speed.Abs initialSpeed, final LaneBasedRouteNavigator routeNavigator,
150 final OTSDEVSSimulatorInterface simulator) throws NetworkException, SimRuntimeException, GTUException
151 {
152 super(id, gtuType, routeNavigator);
153 this.routeNavigator = routeNavigator;
154 if (null == gtuFollowingModel)
155 {
156 throw new GTUException("gtuFollowingModel may not be null");
157 }
158
159 this.gtuFollowingModel = gtuFollowingModel;
160 this.laneChangeModel = laneChangeModel;
161 this.lateralVelocity = new Speed.Abs(0.0, METER_PER_SECOND);
162
163
164 for (Lane lane : initialLongitudinalPositions.keySet())
165 {
166 this.lanes.add(lane);
167 addAccessibleAdjacentLanes(lane);
168 this.fractionalLinkPositions.put(lane.getParentLink(), lane.fraction(initialLongitudinalPositions.get(lane)));
169 lane.addGTU(this, initialLongitudinalPositions.get(lane));
170 }
171
172 this.lastEvaluationTime = simulator.getSimulatorTime().getTime();
173 this.speed = initialSpeed;
174 this.nextEvaluationTime = this.lastEvaluationTime;
175
176
177 simulator.scheduleEventNow(this, this, "move", null);
178 }
179
180
181 private static final Speed.Abs DRIFTINGSPEED = new Speed.Abs(1E-10, SpeedUnit.SI);
182
183
184 @Override
185 public final Speed.Abs getLongitudinalVelocity(final Time.Abs when)
186 {
187 Time.Rel dT = when.minus(this.lastEvaluationTime);
188 Speed.Abs velocity = this.speed.plus(this.getAcceleration(when).toRel().multiplyBy(dT));
189 if (velocity.abs().lt(DRIFTINGSPEED))
190 {
191 velocity = new Speed.Abs(0.0, SpeedUnit.SI);
192 }
193 return velocity;
194 }
195
196
197 @Override
198 public final Speed.Abs getLongitudinalVelocity()
199 {
200 return getLongitudinalVelocity(getSimulator().getSimulatorTime().getTime());
201 }
202
203
204 @Override
205 public final Speed.Abs getVelocity()
206 {
207 return getLongitudinalVelocity();
208 }
209
210
211 @Override
212 public final Time.Abs getLastEvaluationTime()
213 {
214 return this.lastEvaluationTime;
215 }
216
217
218 @Override
219 public final Time.Abs getNextEvaluationTime()
220 {
221 return this.nextEvaluationTime;
222 }
223
224
225 @Override
226 public final Acceleration.Abs getAcceleration(final Time.Abs when)
227 {
228
229 return this.acceleration;
230 }
231
232
233 @Override
234 public final Acceleration.Abs getAcceleration()
235 {
236 return getAcceleration(getSimulator().getSimulatorTime().getTime());
237 }
238
239
240 @Override
241 public final Length.Abs getOdometer()
242 {
243 return this.odometer.plus(deltaX(getSimulator().getSimulatorTime().getTime()));
244 }
245
246
247 @Override
248 public final Speed.Abs getLateralVelocity()
249 {
250 return this.lateralVelocity;
251 }
252
253
254 @Override
255 public final void enterLane(final Lane lane, final Length.Rel position) throws NetworkException
256 {
257 if (this.lanes.contains(lane))
258 {
259 System.err.println("GTU " + toString() + " is already registered on this lane: " + lane);
260 return;
261 }
262
263
264 if (!this.fractionalLinkPositions.containsKey(lane.getParentLink()))
265 {
266 this.fractionalLinkPositions.put(lane.getParentLink(), lane.fraction(position));
267 }
268 this.lanes.add(lane);
269 addAccessibleAdjacentLanes(lane);
270 lane.addGTU(this, position);
271 }
272
273
274 @Override
275 public final void leaveLane(final Lane lane)
276 {
277 leaveLane(lane, false);
278 }
279
280
281
282
283
284
285 public final void leaveLane(final Lane lane, final boolean beingDestroyed)
286 {
287
288 this.lanes.remove(lane);
289 removeAccessibleAdjacentLanes(lane);
290
291 boolean found = false;
292 for (Lane l : this.lanes)
293 {
294 if (l.getParentLink().equals(lane.getParentLink()))
295 {
296 found = true;
297 }
298 }
299 if (!found)
300 {
301 this.fractionalLinkPositions.remove(lane.getParentLink());
302 }
303 lane.removeGTU(this);
304 if (this.lanes.size() == 0 && !beingDestroyed)
305 {
306 System.err.println("lanes.size() = 0 for GTU " + getId());
307 }
308 }
309
310
311
312
313 public final List<Lane> getLanes()
314 {
315 return this.lanes;
316 }
317
318
319 private static final Acceleration.Rel STAYINCURRENTLANEINCENTIVE = new Acceleration.Rel(0.1, METER_PER_SECOND_2);
320
321
322 private static final Acceleration.Rel PREFERREDLANEINCENTIVE = new Acceleration.Rel(0.3, METER_PER_SECOND_2);
323
324
325 private static final Acceleration.Rel NONPREFERREDLANEINCENTIVE = new Acceleration.Rel(-0.3, METER_PER_SECOND_2);
326
327
328 private static final Time.Rel TIMEHORIZON = new Time.Rel(90, SECOND);
329
330
331
332
333
334
335
336
337 protected final void move() throws NetworkException, GTUException, SimRuntimeException, ValueException
338 {
339 if (getLongitudinalVelocity().getSI() < 0)
340 {
341 System.out.println("negative velocity: " + this + " " + getLongitudinalVelocity().getSI() + "m/s");
342 }
343
344
345 if (getSimulator().getSimulatorTime().getTime().getSI() != getNextEvaluationTime().getSI())
346 {
347 throw new Error("move called at wrong time: expected time " + getNextEvaluationTime() + " simulator time is : "
348 + getSimulator().getSimulatorTime().getTime());
349 }
350
351
352 if (this.lanes.isEmpty())
353 {
354 destroy();
355 return;
356 }
357 Length.Rel maximumForwardHeadway = new Length.Rel(500.0, METER);
358
359 Length.Rel maximumReverseHeadway = new Length.Rel(200.0, METER);
360
361 Speed.Abs speedLimit = this.getMaximumVelocity();
362 for (Lane lane : this.lanes)
363 {
364 if (lane.getSpeedLimit(getGTUType()).lt(speedLimit))
365 {
366 speedLimit = lane.getSpeedLimit(getGTUType());
367 }
368 }
369 if (null == this.laneChangeModel)
370 {
371 throw new GTUException("LaneBasedGTUs MUST have a LaneChangeModel");
372 }
373
374
375 Collection<HeadwayGTU> sameLaneTraffic = new ArrayList<HeadwayGTU>();
376 HeadwayGTU leader = headway(maximumForwardHeadway);
377 if (null != leader.getOtherGTU())
378 {
379 sameLaneTraffic.add(leader);
380 }
381 HeadwayGTU follower = headway(maximumReverseHeadway);
382 if (null != follower.getOtherGTU())
383 {
384 sameLaneTraffic.add(new HeadwayGTU(follower.getOtherGTU(), -follower.getDistanceSI()));
385 }
386 Time.Abs now = getSimulator().getSimulatorTime().getTime();
387 Collection<HeadwayGTU> leftLaneTraffic =
388 collectNeighborLaneTraffic(LateralDirectionality.LEFT, now, maximumForwardHeadway, maximumReverseHeadway);
389 Collection<HeadwayGTU> rightLaneTraffic =
390 collectNeighborLaneTraffic(LateralDirectionality.RIGHT, now, maximumForwardHeadway, maximumReverseHeadway);
391
392 final LateralDirectionality preferred = LateralDirectionality.RIGHT;
393 final Acceleration.Rel defaultLeftLaneIncentive =
394 LateralDirectionality.LEFT == preferred ? PREFERREDLANEINCENTIVE : NONPREFERREDLANEINCENTIVE;
395 final Acceleration.Rel defaultRightLaneIncentive =
396 LateralDirectionality.RIGHT == preferred ? PREFERREDLANEINCENTIVE : NONPREFERREDLANEINCENTIVE;
397 DoubleVector.Rel.Dense<AccelerationUnit> defaultLaneIncentives =
398 new DoubleVector.Rel.Dense<AccelerationUnit>(new double[] { defaultLeftLaneIncentive.getSI(),
399 STAYINCURRENTLANEINCENTIVE.getSI(), defaultRightLaneIncentive.getSI() }, AccelerationUnit.SI);
400 DoubleVector.Rel.Dense<AccelerationUnit> laneIncentives = laneIncentives(defaultLaneIncentives);
401 LaneMovementStep lcmr =
402 this.laneChangeModel.computeLaneChangeAndAcceleration(this, sameLaneTraffic, rightLaneTraffic, leftLaneTraffic,
403 speedLimit, new Acceleration.Rel(laneIncentives.get(preferred == LateralDirectionality.RIGHT ? 2 : 0)),
404 new Acceleration.Rel(laneIncentives.get(1)),
405 new Acceleration.Rel(laneIncentives.get(preferred == LateralDirectionality.RIGHT ? 0 : 2)));
406
407 if (lcmr.getGfmr().getAcceleration().getSI() < -9999)
408 {
409 System.out.println("Problem");
410 }
411
412
413
414
415
416
417 synchronized (this.lock)
418 {
419 for (int i = this.lanes.size() - 1; i >= 0; i--)
420 {
421 Lane lane = this.lanes.get(i);
422 this.fractionalLinkPositions.put(lane.getParentLink(),
423 lane.fraction(position(lane, getReference(), this.nextEvaluationTime)));
424 }
425
426 this.odometer = this.odometer.plus(deltaX(this.nextEvaluationTime));
427
428 this.speed = getLongitudinalVelocity(this.nextEvaluationTime);
429
430 this.lastEvaluationTime = this.nextEvaluationTime;
431
432 this.nextEvaluationTime = lcmr.getGfmr().getValidUntil();
433
434 this.acceleration = lcmr.getGfmr().getAcceleration();
435
436 for (Lane lane : this.lanes)
437 {
438 lane.sample(this);
439 }
440
441 if (lcmr.getLaneChange() != null)
442 {
443
444 Collection<Lane> oldLaneSet = new HashSet<Lane>(this.lanes);
445 Collection<Lane> newLaneSet = new HashSet<Lane>(2);
446
447
448 Map<Lane, Double> oldFractionalPositions = new LinkedHashMap<Lane, Double>();
449 for (Lane l : this.lanes)
450 {
451 oldFractionalPositions.put(l, fractionalPosition(l, getReference(), getLastEvaluationTime()));
452 this.fractionalLinkPositions.remove(l.getParentLink());
453 newLaneSet.addAll(this.accessibleAdjacentLanes.get(l).get(lcmr.getLaneChange()));
454 }
455
456
457 for (Lane newLane : newLaneSet)
458 {
459 Double fractionalPosition = null;
460
461 for (Lane oldLane : oldLaneSet)
462 {
463 if (this.accessibleAdjacentLanes.get(oldLane).get(lcmr.getLaneChange()).contains(newLane))
464 {
465 fractionalPosition = oldFractionalPositions.get(oldLane);
466 break;
467 }
468 }
469 if (null == fractionalPosition)
470 {
471 throw new Error("Program error: Cannot find an oldLane that has newLane " + newLane + " as "
472 + lcmr.getLaneChange() + " neighbor");
473 }
474 enterLane(newLane, newLane.getLength().multiplyBy(fractionalPosition));
475 }
476
477
478
479 for (Lane l : oldFractionalPositions.keySet())
480 {
481 leaveLane(l);
482 }
483
484 checkConsistency();
485 }
486
487
488
489 scheduleTriggers();
490 }
491
492 getSimulator().scheduleEventAbs(this.getNextEvaluationTime(), this, this, "move", null);
493 }
494
495
496
497
498
499
500
501
502
503
504 private DoubleVector.Rel.Dense<AccelerationUnit> laneIncentives(
505 final DoubleVector.Rel.Dense<AccelerationUnit> defaultLaneIncentives) throws NetworkException, ValueException
506 {
507 Length.Rel leftSuitability = suitability(LateralDirectionality.LEFT);
508 Length.Rel currentSuitability = suitability(null);
509 Length.Rel rightSuitability = suitability(LateralDirectionality.RIGHT);
510 if (currentSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED)
511 {
512 this.lastLaneChangeDistanceAndDirection =
513 new LaneChangeUrgeGTUColorer.LaneChangeDistanceAndDirection(currentSuitability, null);
514 }
515 else
516 {
517 this.lastLaneChangeDistanceAndDirection =
518 new LaneChangeUrgeGTUColorer.LaneChangeDistanceAndDirection(currentSuitability,
519 rightSuitability.getSI() == 0 ? false : leftSuitability.gt(rightSuitability));
520 }
521 if ((leftSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED || leftSuitability == AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW)
522 && currentSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED
523 && (rightSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED || rightSuitability == AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW))
524 {
525 return checkLaneDrops(defaultLaneIncentives);
526 }
527 if (currentSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED)
528 {
529 return new DoubleVector.Rel.Dense<AccelerationUnit>(new double[] { acceleration(leftSuitability),
530 defaultLaneIncentives.get(1).getSI(), acceleration(rightSuitability) }, AccelerationUnit.SI);
531 }
532 return new DoubleVector.Rel.Dense<AccelerationUnit>(new double[] { acceleration(leftSuitability),
533 acceleration(currentSuitability), acceleration(rightSuitability) }, AccelerationUnit.SI);
534 }
535
536
537
538
539
540
541
542
543
544
545 private DoubleVector.Rel.Dense<AccelerationUnit> checkLaneDrops(
546 final DoubleVector.Rel.Dense<AccelerationUnit> defaultLaneIncentives) throws NetworkException, ValueException
547 {
548 Length.Rel leftSuitability = laneDrop(LateralDirectionality.LEFT);
549 Length.Rel currentSuitability = laneDrop(null);
550 Length.Rel rightSuitability = laneDrop(LateralDirectionality.RIGHT);
551
552 if ((leftSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED
553 || leftSuitability == AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW)
554 && currentSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED
555 && (rightSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED
556 || rightSuitability == AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW))
557 {
558 return defaultLaneIncentives;
559 }
560
561 if (currentSuitability == AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED)
562 {
563 return new DoubleVector.Rel.Dense<AccelerationUnit>(new double[] { acceleration(leftSuitability),
564 defaultLaneIncentives.get(1).getSI(), acceleration(rightSuitability) }, AccelerationUnit.SI);
565 }
566 if (currentSuitability.le(leftSuitability))
567 {
568 return new DoubleVector.Rel.Dense<AccelerationUnit>(new double[] { PREFERREDLANEINCENTIVE.getSI(),
569 NONPREFERREDLANEINCENTIVE.getSI(), AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW.getSI() },
570 AccelerationUnit.SI);
571 }
572 if (currentSuitability.le(rightSuitability))
573 {
574 return new DoubleVector.Rel.Dense<AccelerationUnit>(new double[] {
575 AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW.getSI(), NONPREFERREDLANEINCENTIVE.getSI(),
576 PREFERREDLANEINCENTIVE.getSI() }, AccelerationUnit.SI);
577 }
578 return new DoubleVector.Rel.Dense<AccelerationUnit>(new double[] { acceleration(leftSuitability),
579 acceleration(currentSuitability), acceleration(rightSuitability) }, AccelerationUnit.SI);
580 }
581
582
583
584
585
586
587
588
589
590
591
592 private Length.Rel laneDrop(final LateralDirectionality direction) throws NetworkException
593 {
594 Lane lane = null;
595 Length.Rel longitudinalPosition = null;
596 Map<Lane, Length.Rel> positions = positions(RelativePosition.REFERENCE_POSITION);
597 if (null == direction)
598 {
599 for (Lane l : getLanes())
600 {
601 if (l.getLaneType().isCompatible(getGTUType()))
602 {
603 lane = l;
604 }
605 }
606 if (null == lane)
607 {
608 throw new NetworkException("GTU " + this + " is not on any compatible lane");
609 }
610 longitudinalPosition = positions.get(lane);
611 }
612 else
613 {
614 lane = positions.keySet().iterator().next();
615 longitudinalPosition = positions.get(lane);
616 lane = bestAccessibleAdjacentLane(lane, direction, longitudinalPosition);
617 }
618 if (null == lane)
619 {
620 return AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW;
621 }
622 double remainingLength = lane.getLength().getSI() - longitudinalPosition.getSI();
623 double remainingTimeSI = TIMEHORIZON.getSI() - remainingLength / lane.getSpeedLimit(getGTUType()).getSI();
624 while (remainingTimeSI >= 0)
625 {
626
627 int branching = lane.nextLanes(getGTUType()).size();
628 if (branching == 0)
629 {
630 return new Length.Rel(remainingLength, LengthUnit.SI);
631 }
632 if (branching > 1)
633 {
634 return AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED;
635 }
636 lane = lane.nextLanes(getGTUType()).iterator().next();
637 remainingTimeSI -= lane.getLength().getSI() / lane.getSpeedLimit(getGTUType()).getSI();
638 remainingLength += lane.getLength().getSI();
639 }
640 return AbstractLaneBasedRouteNavigator.NOLANECHANGENEEDED;
641 }
642
643
644
645
646
647
648 private double acceleration(final Length.Rel stopDistance)
649 {
650
651
652 double v = getLongitudinalVelocity().getSI();
653 double a = -v * v / 2 / stopDistance.getSI();
654 return a;
655 }
656
657
658
659
660
661
662
663
664 private Length.Rel suitability(final LateralDirectionality direction) throws NetworkException
665 {
666 Lane lane = null;
667 Length.Rel longitudinalPosition = null;
668 Map<Lane, Length.Rel> positions = positions(RelativePosition.REFERENCE_POSITION);
669 if (null == direction)
670 {
671 for (Lane l : getLanes())
672 {
673 if (l.getLaneType().isCompatible(getGTUType()))
674 {
675 lane = l;
676 }
677 }
678 if (null == lane)
679 {
680 throw new NetworkException("GTU " + this + " is not on any compatible lane");
681 }
682 longitudinalPosition = positions.get(lane);
683 }
684 else
685 {
686 lane = positions.keySet().iterator().next();
687 longitudinalPosition = positions.get(lane);
688 lane = bestAccessibleAdjacentLane(lane, direction, longitudinalPosition);
689 }
690 if (null == lane)
691 {
692 return AbstractLaneBasedRouteNavigator.GETOFFTHISLANENOW;
693 }
694 return this.routeNavigator.suitability(lane, longitudinalPosition, getGTUType(), TIMEHORIZON);
695 }
696
697
698
699
700 private void checkConsistency()
701 {
702 for (Lane l : this.lanes)
703 {
704 if (!this.fractionalLinkPositions.containsKey(l.getParentLink()))
705 {
706 System.err.println("GTU " + this + " is in lane " + l
707 + " but that GTU has no fractional position on the link of that lane");
708 }
709 }
710 for (Link csl : this.fractionalLinkPositions.keySet())
711 {
712 boolean found = false;
713 for (Lane l : this.lanes)
714 {
715 if (l.getParentLink().equals(csl))
716 {
717 found = true;
718 break;
719 }
720 }
721 if (!found)
722 {
723 System.err.println("GTU " + this + " has a fractional position " + this.fractionalLinkPositions.get(csl)
724 + " on link " + csl + " but this GTU is not on any lane(s) of that link");
725 }
726 }
727 }
728
729
730
731
732
733
734
735
736
737 private void scheduleTriggers() throws NetworkException, SimRuntimeException, GTUException
738 {
739
740
741
742 double timestep = this.nextEvaluationTime.getSI() - this.lastEvaluationTime.getSI();
743 double moveSI = getVelocity().getSI() * timestep + 0.5 * getAcceleration().getSI() * timestep * timestep;
744 for (Lane lane : new ArrayList<Lane>(this.lanes))
745 {
746
747 double referenceStartSI = this.fractionalLinkPositions.get(lane.getParentLink()) * lane.getLength().getSI();
748 lane.scheduleTriggers(this, referenceStartSI, moveSI);
749
750
751
752
753 double frontPosSI = referenceStartSI + getFront().getDx().getSI();
754 double moveFrontOnNextLane = moveSI - (lane.getLength().getSI() - frontPosSI);
755 if (frontPosSI < lane.getLength().getSI() && moveFrontOnNextLane > 0)
756 {
757 Lane nextLane = determineNextLane(lane);
758 if (!this.lanes.contains(nextLane))
759 {
760
761
762 Length.Rel refPosAtLastTimestep =
763 new Length.Rel(-(lane.getLength().getSI() - frontPosSI) - getFront().getDx().getSI(), LengthUnit.SI);
764
765
766
767
768
769 enterLane(nextLane, refPosAtLastTimestep);
770
771 nextLane.scheduleTriggers(this, refPosAtLastTimestep.getSI(), moveSI);
772 }
773 }
774 }
775
776
777 for (Lane lane : this.lanes)
778 {
779
780
781
782 double referenceStartSI = this.fractionalLinkPositions.get(lane.getParentLink()) * lane.getLength().getSI();
783 double rearPosSI = referenceStartSI + getRear().getDx().getSI();
784 if (rearPosSI < lane.getLength().getSI() && rearPosSI + moveSI > lane.getLength().getSI())
785 {
786 getSimulator().scheduleEventRel(new Time.Rel(timestep - Math.ulp(timestep), TimeUnit.SI), this, this,
787 "leaveLane", new Object[] { lane, new Boolean(true) });
788 }
789 }
790 }
791
792
793
794
795
796
797
798 private Lane determineNextLane(final Lane lane) throws NetworkException, GTUException
799 {
800 Lane nextLane = null;
801 if (lane.nextLanes(getGTUType()).size() == 0)
802 {
803 throw new NetworkException(this + " - lane " + lane + " does not have a successor");
804 }
805 if (lane.nextLanes(getGTUType()).size() == 1)
806 {
807 nextLane = lane.nextLanes(getGTUType()).iterator().next();
808 }
809 else
810 {
811 if (null == this.getRouteNavigator())
812 {
813 throw new GTUException(this + " reaches branch but has no route navigator");
814 }
815 Node nextNode = this.routeNavigator.nextNodeToVisit();
816 if (null == nextNode)
817 {
818 throw new GTUException(this + " reaches branch and the route returns null as nextNodeToVisit");
819 }
820 int continuingLaneCount = 0;
821 for (Lane candidateLane : lane.nextLanes(getGTUType()))
822 {
823 if (this.lanes.contains(candidateLane))
824 {
825 continue;
826 }
827 if (nextNode == candidateLane.getParentLink().getEndNode())
828 {
829 nextLane = candidateLane;
830 continuingLaneCount++;
831 }
832 }
833 if (continuingLaneCount == 0)
834 {
835 throw new NetworkException(this + " reached branch and the route specifies a nextNodeToVisit (" + nextNode
836 + ") that is not a next node " + "at this branch at (" + lane.getParentLink().getEndNode() + ")");
837 }
838 if (continuingLaneCount > 1)
839 {
840 throw new NetworkException(this
841 + " reached branch and the route specifies multiple lanes to continue on at this branch ("
842 + lane.getParentLink().getEndNode() + "). This is not yet supported");
843 }
844 }
845 return nextLane;
846 }
847
848
849
850
851
852
853
854
855
856
857
858 private Collection<HeadwayGTU> collectNeighborLaneTraffic(final LateralDirectionality directionality, final Time.Abs when,
859 final Length.Rel maximumForwardHeadway, final Length.Rel maximumReverseHeadway) throws NetworkException
860 {
861 Collection<HeadwayGTU> result = new HashSet<HeadwayGTU>();
862 for (LaneBasedGTU p : parallel(directionality, when))
863 {
864 result.add(new HeadwayGTU(p, Double.NaN));
865 }
866 for (Lane lane : this.lanes)
867 {
868 for (Lane adjacentLane : this.accessibleAdjacentLanes.get(lane).get(directionality))
869 {
870 HeadwayGTU leader = headway(adjacentLane, maximumForwardHeadway);
871 if (null != leader.getOtherGTU() && !result.contains(leader))
872 {
873 result.add(leader);
874 }
875 HeadwayGTU follower = headway(adjacentLane, maximumReverseHeadway);
876 if (null != follower.getOtherGTU() && !result.contains(follower))
877 {
878 result.add(new HeadwayGTU(follower.getOtherGTU(), -follower.getDistanceSI()));
879 }
880 }
881 }
882 return result;
883 }
884
885
886 @Override
887 public final Map<Lane, Length.Rel> positions(final RelativePosition relativePosition) throws NetworkException
888 {
889 return positions(relativePosition, getSimulator().getSimulatorTime().getTime());
890 }
891
892
893 @Override
894 public final Map<Lane, Length.Rel> positions(final RelativePosition relativePosition, final Time.Abs when)
895 throws NetworkException
896 {
897 Map<Lane, Length.Rel> positions = new LinkedHashMap<>();
898 for (Lane lane : this.lanes)
899 {
900 positions.put(lane, position(lane, relativePosition, when));
901 }
902 return positions;
903 }
904
905
906 @Override
907 public final Length.Rel position(final Lane lane, final RelativePosition relativePosition) throws NetworkException
908 {
909 return position(lane, relativePosition, getSimulator().getSimulatorTime().getTime());
910 }
911
912
913 public final Length.Rel projectedPosition(final Lane projectionLane, final RelativePosition relativePosition,
914 final Time.Abs when) throws NetworkException
915 {
916 CrossSectionLink link = projectionLane.getParentLink();
917 for (CrossSectionElement cse : link.getCrossSectionElementList())
918 {
919 if (cse instanceof Lane)
920 {
921 Lane cseLane = (Lane) cse;
922 if (this.lanes.contains(cseLane))
923 {
924 double fractionalPosition = fractionalPosition(cseLane, relativePosition, when);
925 return new Length.Rel(projectionLane.getLength().getSI() * fractionalPosition, LengthUnit.SI);
926 }
927 }
928 }
929 throw new NetworkException("GTU " + this + " is not on any lane of Link " + link);
930 }
931
932
933 @Override
934 public final Length.Rel position(final Lane lane, final RelativePosition relativePosition, final Time.Abs when)
935 throws NetworkException
936 {
937 if (null == lane)
938 {
939 throw new NetworkException("lane is null");
940 }
941 synchronized (this.lock)
942 {
943 if (!this.lanes.contains(lane))
944 {
945 throw new NetworkException("position() : GTU " + toString() + " is not on lane " + lane);
946 }
947 if (!this.fractionalLinkPositions.containsKey(lane.getParentLink()))
948 {
949
950 throw new NetworkException("GTU " + getId() + " does not have a fractional position on " + lane.toString());
951 }
952 Length.Rel longitudinalPosition = lane.position(this.fractionalLinkPositions.get(lane.getParentLink()));
953 if (longitudinalPosition == null)
954 {
955
956 throw new NetworkException("position(): GTU " + toString() + " no position for lane " + lane);
957 }
958 Length.Rel loc = longitudinalPosition.plus(deltaX(when)).plus(relativePosition.getDx());
959 if (Double.isNaN(loc.getSI()))
960 {
961 System.out.println("loc is NaN");
962 }
963 return loc;
964 }
965 }
966
967
968 @Override
969 public final Map<Lane, Double> fractionalPositions(final RelativePosition relativePosition) throws NetworkException
970 {
971 return fractionalPositions(relativePosition, getSimulator().getSimulatorTime().getTime());
972 }
973
974
975 @Override
976 public final Map<Lane, Double> fractionalPositions(final RelativePosition relativePosition, final Time.Abs when)
977 throws NetworkException
978 {
979 Map<Lane, Double> positions = new LinkedHashMap<>();
980 for (Lane lane : this.lanes)
981 {
982 positions.put(lane, fractionalPosition(lane, relativePosition, when));
983 }
984 return positions;
985 }
986
987
988 @Override
989 public final double fractionalPosition(final Lane lane, final RelativePosition relativePosition, final Time.Abs when)
990 throws NetworkException
991 {
992 return position(lane, relativePosition, when).getSI() / lane.getLength().getSI();
993 }
994
995
996 @Override
997 public final double fractionalPosition(final Lane lane, final RelativePosition relativePosition) throws NetworkException
998 {
999 return position(lane, relativePosition).getSI() / lane.getLength().getSI();
1000 }
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014 private HeadwayGTU headwayRecursiveForwardSI(final Lane lane, final double lanePositionSI, final double cumDistanceSI,
1015 final double maxDistanceSI, final Time.Abs when) throws NetworkException
1016 {
1017 LaneBasedGTU otherGTU = lane.getGtuAfter(new Length.Rel(lanePositionSI, METER), RelativePosition.REAR, when);
1018 if (otherGTU != null)
1019 {
1020 double distanceM = cumDistanceSI + otherGTU.position(lane, otherGTU.getRear(), when).getSI() - lanePositionSI;
1021 if (distanceM > 0 && distanceM <= maxDistanceSI)
1022 {
1023 return new HeadwayGTU(otherGTU, distanceM);
1024 }
1025 return new HeadwayGTU(null, Double.MAX_VALUE);
1026 }
1027
1028
1029 if (cumDistanceSI + lane.getLength().getSI() - lanePositionSI < maxDistanceSI)
1030 {
1031
1032 if (lane.nextLanes(getGTUType()).size() > 0)
1033 {
1034 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
1035 for (Lane nextLane : lane.nextLanes(getGTUType()))
1036 {
1037
1038
1039
1040
1041 {
1042 double traveledDistanceSI = cumDistanceSI + lane.getLength().getSI() - lanePositionSI;
1043 HeadwayGTU closest = headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
1044 if (closest.getDistanceSI() < maxDistanceSI
1045 && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
1046 {
1047 foundMaxGTUDistanceSI = closest;
1048 }
1049 }
1050 }
1051 return foundMaxGTUDistanceSI;
1052 }
1053 }
1054
1055
1056 return new HeadwayGTU(null, Double.MAX_VALUE);
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074 private HeadwayGTU headwayRecursiveBackwardSI(final Lane lane, final double lanePositionSI, final double cumDistanceSI,
1075 final double maxDistanceSI, final Time.Abs when) throws NetworkException
1076 {
1077 LaneBasedGTU otherGTU = lane.getGtuBefore(new Length.Rel(lanePositionSI, METER), RelativePosition.FRONT, when);
1078 if (otherGTU != null)
1079 {
1080 double distanceM = cumDistanceSI + lanePositionSI - otherGTU.position(lane, otherGTU.getFront(), when).getSI();
1081 if (distanceM > 0 && distanceM <= maxDistanceSI)
1082 {
1083 return new HeadwayGTU(otherGTU, distanceM);
1084 }
1085 return new HeadwayGTU(null, Double.MAX_VALUE);
1086 }
1087
1088
1089 if (cumDistanceSI + lanePositionSI < maxDistanceSI)
1090 {
1091
1092 if (lane.prevLanes(getGTUType()).size() > 0)
1093 {
1094 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
1095 for (Lane prevLane : lane.prevLanes(getGTUType()))
1096 {
1097
1098 double traveledDistanceSI = cumDistanceSI + lanePositionSI;
1099 HeadwayGTU closest =
1100 headwayRecursiveBackwardSI(prevLane, prevLane.getLength().getSI(), traveledDistanceSI,
1101 maxDistanceSI, when);
1102 if (closest.getDistanceSI() < maxDistanceSI
1103 && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
1104 {
1105 foundMaxGTUDistanceSI = closest;
1106 }
1107 }
1108 return foundMaxGTUDistanceSI;
1109 }
1110 }
1111
1112
1113 return new HeadwayGTU(null, Double.MAX_VALUE);
1114 }
1115
1116
1117
1118
1119
1120
1121
1122 private HeadwayGTU headwayGTUSI(final double maxDistanceSI) throws NetworkException
1123 {
1124 Time.Abs when = getSimulator().getSimulatorTime().getTime();
1125 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
1126
1127 if (maxDistanceSI > 0.0)
1128 {
1129
1130 for (Lane lane : positions(getFront()).keySet())
1131 {
1132 HeadwayGTU closest =
1133 headwayRecursiveForwardSI(lane, this.position(lane, this.getFront(), when).getSI(), 0.0, maxDistanceSI,
1134 when);
1135 if (closest.getDistanceSI() < maxDistanceSI && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
1136 {
1137 foundMaxGTUDistanceSI = closest;
1138 }
1139 }
1140 }
1141 else
1142 {
1143
1144 for (Lane lane : positions(getRear()).keySet())
1145 {
1146 HeadwayGTU closest =
1147 headwayRecursiveBackwardSI(lane, this.position(lane, this.getRear(), when).getSI(), 0.0,
1148 -maxDistanceSI, when);
1149 if (closest.getDistanceSI() < -maxDistanceSI && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
1150 {
1151 foundMaxGTUDistanceSI = closest;
1152 }
1153 }
1154 }
1155 return foundMaxGTUDistanceSI;
1156 }
1157
1158
1159 @Override
1160 public final HeadwayGTU headway(final Length.Rel maxDistance) throws NetworkException
1161 {
1162 return headwayGTUSI(maxDistance.getSI());
1163 }
1164
1165
1166 @Override
1167 public final HeadwayGTU headway(final Lane lane, final Length.Rel maxDistance) throws NetworkException
1168 {
1169 Time.Abs when = getSimulator().getSimulatorTime().getTime();
1170 if (maxDistance.getSI() > 0.0)
1171 {
1172 return headwayRecursiveForwardSI(lane, this.projectedPosition(lane, this.getFront(), when).getSI(), 0.0,
1173 maxDistance.getSI(), when);
1174 }
1175 else
1176 {
1177 return headwayRecursiveBackwardSI(lane, this.projectedPosition(lane, this.getRear(), when).getSI(), 0.0,
1178 -maxDistance.getSI(), when);
1179 }
1180 }
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195 private double headwayRecursiveForwardSI(final Lane lane, final double lanePositionSI, final LaneBasedGTU otherGTU,
1196 final double cumDistanceSI, final double maxDistanceSI, final Time.Abs when) throws NetworkException
1197 {
1198 if (lane.getGtuList().contains(otherGTU))
1199 {
1200 double distanceM = cumDistanceSI + otherGTU.position(lane, otherGTU.getRear(), when).getSI() - lanePositionSI;
1201 if (distanceM > 0 && distanceM <= maxDistanceSI)
1202 {
1203 return distanceM;
1204 }
1205 return Double.MAX_VALUE;
1206 }
1207
1208
1209 if (cumDistanceSI + lane.getLength().getSI() - lanePositionSI < maxDistanceSI)
1210 {
1211
1212 for (Lane nextLane : lane.nextLanes(getGTUType()))
1213 {
1214
1215
1216
1217 {
1218 double traveledDistanceSI = cumDistanceSI + lane.getLength().getSI() - lanePositionSI;
1219 double headwaySuccessor =
1220 headwayRecursiveForwardSI(nextLane, 0.0, otherGTU, traveledDistanceSI, maxDistanceSI, when);
1221 if (headwaySuccessor < maxDistanceSI)
1222 {
1223 return headwaySuccessor;
1224 }
1225 }
1226 }
1227 }
1228
1229
1230 return Double.MAX_VALUE;
1231 }
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247 private double headwayRecursiveBackwardSI(final Lane lane, final double lanePositionSI, final LaneBasedGTU otherGTU,
1248 final double cumDistanceSI, final double maxDistanceSI, final Time.Abs when) throws NetworkException
1249 {
1250 if (lane.getGtuList().contains(otherGTU))
1251 {
1252 double distanceM = cumDistanceSI + lanePositionSI - otherGTU.position(lane, otherGTU.getFront(), when).getSI();
1253 if (distanceM > 0 && distanceM <= maxDistanceSI)
1254 {
1255 return distanceM;
1256 }
1257 return Double.MAX_VALUE;
1258 }
1259
1260
1261 if (cumDistanceSI + lanePositionSI < maxDistanceSI)
1262 {
1263
1264 for (Lane prevLane : lane.prevLanes(getGTUType()))
1265 {
1266
1267 double traveledDistanceSI = cumDistanceSI + lanePositionSI;
1268
1269
1270
1271
1272 double headwayPredecessor =
1273 headwayRecursiveBackwardSI(prevLane, prevLane.getLength().getSI(), otherGTU, traveledDistanceSI,
1274 maxDistanceSI, when);
1275 if (headwayPredecessor < maxDistanceSI)
1276 {
1277 return headwayPredecessor;
1278 }
1279 }
1280 }
1281
1282
1283 return Double.MAX_VALUE;
1284 }
1285
1286
1287
1288
1289
1290 private void addAccessibleAdjacentLanes(final Lane lane)
1291 {
1292 EnumMap<LateralDirectionality, Set<Lane>> adjacentMap = new EnumMap<>(LateralDirectionality.class);
1293 for (LateralDirectionality lateralDirection : LateralDirectionality.values())
1294 {
1295 Set<Lane> adjacentLanes = new HashSet<Lane>(1);
1296 adjacentLanes.addAll(lane.accessibleAdjacentLanes(lateralDirection, getGTUType()));
1297 adjacentMap.put(lateralDirection, adjacentLanes);
1298 }
1299 this.accessibleAdjacentLanes.put(lane, adjacentMap);
1300 }
1301
1302
1303
1304
1305
1306 private void removeAccessibleAdjacentLanes(final Lane lane)
1307 {
1308 this.accessibleAdjacentLanes.remove(lane);
1309 }
1310
1311
1312 @Override
1313 public final Lane bestAccessibleAdjacentLane(final Lane currentLane, final LateralDirectionality lateralDirection,
1314 final Length.Rel longitudinalPosition)
1315 {
1316 Set<Lane> candidates = this.accessibleAdjacentLanes.get(currentLane).get(lateralDirection);
1317 if (candidates.isEmpty())
1318 {
1319 return null;
1320 }
1321 if (candidates.size() == 1)
1322 {
1323 return candidates.iterator().next();
1324 }
1325
1326 Lane bestLane = null;
1327 double widthM = -1.0;
1328 for (Lane lane : candidates)
1329 {
1330 if (lane.getWidth(longitudinalPosition).getSI() > widthM)
1331 {
1332 widthM = lane.getWidth(longitudinalPosition).getSI();
1333 bestLane = lane;
1334 }
1335 }
1336 return bestLane;
1337 }
1338
1339
1340 @Override
1341 public final Set<LaneBasedGTU> parallel(final Lane lane, final Time.Abs when) throws NetworkException
1342 {
1343 Set<LaneBasedGTU> gtuSet = new LinkedHashSet<LaneBasedGTU>();
1344 for (Lane l : this.lanes)
1345 {
1346
1347 if (l.getParentLink().equals(lane.getParentLink()))
1348 {
1349
1350 double posFractionFront = Math.max(0.0, this.fractionalPosition(l, getFront(), when));
1351 double posFractionRear = Math.min(1.0, this.fractionalPosition(l, getRear(), when));
1352 for (LaneBasedGTU gtu : lane.getGtuList())
1353 {
1354 if (!gtu.equals(this))
1355 {
1356 double gtuFractionFront = Math.max(0.0, gtu.fractionalPosition(lane, gtu.getFront(), when));
1357 double gtuFractionRear = Math.min(1.0, gtu.fractionalPosition(lane, gtu.getRear(), when));
1358
1359
1360 if (gtuFractionFront >= posFractionRear && gtuFractionRear <= posFractionFront)
1361 {
1362 gtuSet.add(gtu);
1363 }
1364 }
1365 }
1366 }
1367 }
1368 return gtuSet;
1369 }
1370
1371
1372 @Override
1373 public final Set<LaneBasedGTU> parallel(final LateralDirectionality lateralDirection, final Time.Abs when)
1374 throws NetworkException
1375 {
1376 Set<LaneBasedGTU> gtuSet = new LinkedHashSet<LaneBasedGTU>();
1377 for (Lane lane : this.lanes)
1378 {
1379 for (Lane adjacentLane : this.accessibleAdjacentLanes.get(lane).get(lateralDirection))
1380 {
1381 gtuSet.addAll(parallel(adjacentLane, when));
1382 }
1383 }
1384 return gtuSet;
1385 }
1386
1387
1388 public final Time.Abs timeAtDistance(final Length.Rel distance)
1389 {
1390 Double result = solveTimeForDistance(distance);
1391 if (null == result)
1392 {
1393 return null;
1394 }
1395 return new Time.Abs(this.lastEvaluationTime.getSI() + result, SECOND);
1396 }
1397
1398
1399 public final Time.Rel deltaTimeForDistance(final Length.Rel distance)
1400 {
1401 Double result = solveTimeForDistance(distance);
1402 if (null == result)
1403 {
1404 return null;
1405 }
1406 return new Time.Rel(result, SECOND);
1407 }
1408
1409
1410 @Override
1411 @SuppressWarnings("checkstyle:designforextension")
1412 public void destroy()
1413 {
1414 synchronized (this.lock)
1415 {
1416 while (!this.lanes.isEmpty())
1417 {
1418 Lane lane = this.lanes.get(0);
1419 leaveLane(lane, true);
1420 }
1421 }
1422 }
1423
1424
1425
1426
1427
1428
1429 private Length.Rel deltaX(final Time.Abs when)
1430 {
1431 Time.Rel dT = when.minus(this.lastEvaluationTime);
1432 return this.speed.toRel().multiplyBy(dT).plus(this.getAcceleration().toRel().multiplyBy(dT).multiplyBy(dT).divideBy(2));
1433
1434
1435
1436
1437 }
1438
1439
1440
1441
1442
1443
1444
1445 private Double solveTimeForDistance(final Length.Rel distance)
1446 {
1447 return solveTimeForDistanceSI(distance.getSI());
1448 }
1449
1450
1451
1452
1453
1454
1455
1456 private Double solveTimeForDistanceSI(final double distanceSI)
1457 {
1458
1459
1460
1461
1462 double c = -distanceSI;
1463 double a = this.acceleration.getSI() / 2;
1464 double b = this.speed.getSI();
1465 if (Math.abs(a) < 0.001)
1466 {
1467 if (b > 0)
1468 {
1469 return -c / b;
1470 }
1471 return null;
1472 }
1473
1474 double discriminant = b * b - 4 * a * c;
1475 if (discriminant < 0)
1476 {
1477 return null;
1478 }
1479
1480 double solution1 = (-b - Math.sqrt(discriminant)) / (2 * a);
1481 double solution2 = (-b + Math.sqrt(discriminant)) / (2 * a);
1482 if (solution1 < 0 && solution2 < 0)
1483 {
1484 return null;
1485 }
1486 if (solution1 < 0)
1487 {
1488 return solution2;
1489 }
1490 if (solution2 < 0)
1491 {
1492 return solution1;
1493 }
1494
1495 if (solution1 < solution2)
1496 {
1497 return solution1;
1498 }
1499 return solution2;
1500 }
1501
1502
1503
1504
1505
1506 public final GTUFollowingModel getGTUFollowingModel()
1507 {
1508 return this.gtuFollowingModel;
1509 }
1510
1511
1512 @Override
1513 public final DirectedPoint getLocation()
1514 {
1515 synchronized (this.lock)
1516 {
1517 try
1518 {
1519 if (this.lanes.size() == 0)
1520 {
1521
1522 return new DirectedPoint(0, 0, 0);
1523 }
1524 Lane lane = this.lanes.get(0);
1525 DirectedPoint location = lane.getCenterLine().getLocationExtended(position(lane, getReference()));
1526 location.z += 0.01;
1527 return location;
1528 }
1529 catch (NetworkException exception)
1530 {
1531 return null;
1532 }
1533 }
1534 }
1535
1536
1537 @Override
1538 public final Bounds getBounds()
1539 {
1540 double dx = 0.5 * getLength().doubleValue();
1541 double dy = 0.5 * getWidth().doubleValue();
1542 return new BoundingBox(new Point3d(-dx, -dy, 0.0), new Point3d(dx, dy, 0.0));
1543 }
1544
1545 public LaneChangeUrgeGTUColorer.LaneChangeDistanceAndDirection getLaneChangeDistanceAndDirection()
1546 {
1547 return this.lastLaneChangeDistanceAndDirection;
1548 }
1549
1550
1551
1552
1553
1554
1555
1556 public final String toString(final Lane lane, final Time.Abs when)
1557 {
1558 double pos;
1559 try
1560 {
1561 pos = this.position(lane, getFront(), when).getSI();
1562 }
1563 catch (NetworkException exception)
1564 {
1565 pos = Double.NaN;
1566 }
1567
1568 return String.format("Car %5d lastEval %6.1fs, nextEval %6.1fs, % 9.3fm, v % 6.3fm/s, a % 6.3fm/s^2", getId(),
1569 this.lastEvaluationTime.getSI(), getNextEvaluationTime().getSI(), pos, this.getLongitudinalVelocity(when)
1570 .getSI(), this.getAcceleration(when).getSI());
1571 }
1572
1573 }