1 package org.opentrafficsim.core.gtu.lane;
2
3 import java.rmi.RemoteException;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import javax.media.j3d.Bounds;
13 import javax.naming.NamingException;
14 import javax.vecmath.Point3d;
15
16 import nl.tudelft.simulation.dsol.SimRuntimeException;
17 import nl.tudelft.simulation.language.d3.BoundingBox;
18 import nl.tudelft.simulation.language.d3.DirectedPoint;
19
20 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
21 import org.opentrafficsim.core.gtu.AbstractGTU;
22 import org.opentrafficsim.core.gtu.GTUException;
23 import org.opentrafficsim.core.gtu.GTUType;
24 import org.opentrafficsim.core.gtu.RelativePosition;
25 import org.opentrafficsim.core.gtu.following.AccelerationStep;
26 import org.opentrafficsim.core.gtu.following.GTUFollowingModel;
27 import org.opentrafficsim.core.gtu.following.HeadwayGTU;
28 import org.opentrafficsim.core.gtu.lane.changing.LaneChangeModel;
29 import org.opentrafficsim.core.gtu.lane.changing.LaneMovementStep;
30 import org.opentrafficsim.core.network.LateralDirectionality;
31 import org.opentrafficsim.core.network.Link;
32 import org.opentrafficsim.core.network.NetworkException;
33 import org.opentrafficsim.core.network.lane.CrossSectionElement;
34 import org.opentrafficsim.core.network.lane.CrossSectionLink;
35 import org.opentrafficsim.core.network.lane.Lane;
36 import org.opentrafficsim.core.unit.AccelerationUnit;
37 import org.opentrafficsim.core.unit.LengthUnit;
38 import org.opentrafficsim.core.unit.SpeedUnit;
39 import org.opentrafficsim.core.unit.TimeUnit;
40 import org.opentrafficsim.core.value.conversions.Calc;
41 import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;
42 import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar.Rel;
43
44 import com.vividsolutions.jts.geom.Coordinate;
45 import com.vividsolutions.jts.geom.LineString;
46 import com.vividsolutions.jts.linearref.LengthIndexedLine;
47
48
49
50
51
52
53
54
55
56
57
58 public abstract class AbstractLaneBasedGTU<ID> extends AbstractGTU<ID> implements LaneBasedGTU<ID>
59 {
60
61 private static final long serialVersionUID = 20140822L;
62
63
64 private DoubleScalar.Abs<TimeUnit> lastEvaluationTime;
65
66
67 private DoubleScalar.Abs<TimeUnit> nextEvaluationTime;
68
69
70
71
72
73
74 private final Map<Link<?, ?>, Double> fractionalLinkPositions = new HashMap<>();
75
76
77
78
79
80
81
82 private final List<Lane> lanes = new ArrayList<>();
83
84
85
86
87 public final List<Lane> getLanes()
88 {
89 return this.lanes;
90 }
91
92
93 private DoubleScalar.Abs<SpeedUnit> speed;
94
95
96 private DoubleScalar.Abs<SpeedUnit> lateralVelocity;
97
98
99 private DoubleScalar.Abs<AccelerationUnit> acceleration = new DoubleScalar.Abs<AccelerationUnit>(0,
100 AccelerationUnit.METER_PER_SECOND_2);
101
102
103 private final GTUFollowingModel gtuFollowingModel;
104
105
106 private final LaneChangeModel laneChangeModel;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 public AbstractLaneBasedGTU(final ID id, final GTUType<?> gtuType, final GTUFollowingModel gtuFollowingModel,
122 final LaneChangeModel laneChangeModel, final Map<Lane, DoubleScalar.Rel<LengthUnit>> initialLongitudinalPositions,
123 final DoubleScalar.Abs<SpeedUnit> initialSpeed, final OTSDEVSSimulatorInterface simulator) throws RemoteException,
124 NetworkException, SimRuntimeException
125 {
126 super(id, gtuType);
127 this.gtuFollowingModel = gtuFollowingModel;
128 this.laneChangeModel = laneChangeModel;
129 this.lateralVelocity = new DoubleScalar.Abs<SpeedUnit>(0.0, SpeedUnit.METER_PER_SECOND);
130
131
132 for (Lane lane : initialLongitudinalPositions.keySet())
133 {
134 this.lanes.add(lane);
135 this.fractionalLinkPositions.put(lane.getParentLink(), lane.fraction(initialLongitudinalPositions.get(lane)));
136 lane.addGTU(this, initialLongitudinalPositions.get(lane));
137 }
138
139
140 this.lastEvaluationTime = new DoubleScalar.Abs<TimeUnit>(simulator.getSimulatorTime().get());
141 this.speed = new DoubleScalar.Abs<SpeedUnit>(initialSpeed);
142 this.nextEvaluationTime = new DoubleScalar.Abs<TimeUnit>(simulator.getSimulatorTime().get());
143
144
145 simulator.scheduleEventNow(this, this, "move", null);
146 }
147
148
149 @Override
150 public final DoubleScalar.Abs<SpeedUnit> getLongitudinalVelocity(final DoubleScalar.Abs<TimeUnit> when)
151 {
152 DoubleScalar.Rel<TimeUnit> dT = DoubleScalar.minus(when, this.lastEvaluationTime).immutable();
153 return DoubleScalar.plus(this.speed, Calc.accelerationTimesTime(this.getAcceleration(when), dT)).immutable();
154 }
155
156
157 @Override
158 public final DoubleScalar.Abs<SpeedUnit> getLongitudinalVelocity() throws RemoteException
159 {
160 return getLongitudinalVelocity(getSimulator().getSimulatorTime().get());
161 }
162
163
164 @Override
165 public final DoubleScalar.Abs<TimeUnit> getLastEvaluationTime()
166 {
167 return new DoubleScalar.Abs<TimeUnit>(this.lastEvaluationTime);
168 }
169
170
171 @Override
172 public final DoubleScalar.Abs<TimeUnit> getNextEvaluationTime()
173 {
174 return this.nextEvaluationTime;
175 }
176
177
178 @Override
179 public final DoubleScalar.Abs<AccelerationUnit> getAcceleration(final DoubleScalar.Abs<TimeUnit> when)
180 {
181
182 return new DoubleScalar.Abs<AccelerationUnit>(this.acceleration);
183 }
184
185
186 @Override
187 public final DoubleScalar.Abs<AccelerationUnit> getAcceleration() throws RemoteException
188 {
189 return getAcceleration(getSimulator().getSimulatorTime().get());
190 }
191
192
193 @Override
194 public final DoubleScalar.Abs<SpeedUnit> getLateralVelocity()
195 {
196 return new DoubleScalar.Abs<SpeedUnit>(this.lateralVelocity);
197 }
198
199 @Override
200 public final void addFrontToSubsequentLane(final Lane lane) throws RemoteException, NetworkException
201 {
202 Lane prevLane = this.lanes.get(0);
203 double positionPrevTimeStepSI = position(prevLane, getReference(), this.lastEvaluationTime).getSI();
204 double positionNowSI = position(prevLane, getReference()).getSI();
205 DoubleScalar.Rel<LengthUnit> position =
206 new DoubleScalar.Rel<>(positionPrevTimeStepSI - positionNowSI
207 - (getFront().getDx().getSI() - getReference().getDx().getSI()), LengthUnit.SI);
208 addLane(lane, position);
209 }
210
211
212 @Override
213 public final void addLane(final Lane lane, final DoubleScalar.Rel<LengthUnit> position) throws NetworkException
214 {
215 if (this.lanes.contains(lane))
216 {
217 throw new NetworkException("GTU " + toString() + " is already registered on this lane: " + lane);
218 }
219
220
221 if (!this.fractionalLinkPositions.containsKey(lane.getParentLink()))
222 {
223 this.fractionalLinkPositions.put(lane.getParentLink(), lane.fraction(position));
224 }
225 this.lanes.add(lane);
226 }
227
228
229 @Override
230 public final void removeLane(final Lane lane)
231 {
232 this.lanes.remove(lane);
233
234 boolean found = false;
235 for (Lane l : this.lanes)
236 {
237 if (l.getParentLink().equals(lane.getParentLink()))
238 {
239 found = true;
240 }
241 }
242 if (!found)
243 {
244 this.fractionalLinkPositions.remove(lane.getParentLink());
245 }
246 }
247
248
249
250
251
252
253
254
255 private void setState(final AccelerationStep cfmr) throws RemoteException, NetworkException, SimRuntimeException
256 {
257 if (cfmr.getAcceleration().getSI() < -9999)
258 {
259 System.out.println("Problem");
260 }
261
262
263
264 for (int i = this.lanes.size() - 1; i >= 0; i--)
265 {
266 Lane lane = this.lanes.get(i);
267 this.fractionalLinkPositions.put(lane.getParentLink(), lane.fraction(position(lane, getReference(),
268 this.nextEvaluationTime)));
269 }
270
271 this.speed = getLongitudinalVelocity(this.nextEvaluationTime);
272
273 this.lastEvaluationTime = this.nextEvaluationTime;
274 this.nextEvaluationTime = cfmr.getValidUntil();
275 this.acceleration = cfmr.getAcceleration();
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 for (Lane lane : this.lanes)
308 {
309 lane.sample(this);
310 }
311
312 }
313
314
315
316
317
318
319
320 protected final void move() throws RemoteException, NamingException, NetworkException, GTUException, SimRuntimeException
321 {
322
323
324
325
326
327
328 if (getSimulator().getSimulatorTime().get().getSI() != getNextEvaluationTime().getSI())
329 {
330 throw new Error("move called at wrong time: expected time " + getNextEvaluationTime() + " simulator time is : "
331 + getSimulator().getSimulatorTime().get());
332 }
333
334
335 if (this.lanes.isEmpty())
336 {
337 return;
338 }
339 DoubleScalar.Rel<LengthUnit> maximumForwardHeadway = new DoubleScalar.Rel<LengthUnit>(500.0, LengthUnit.METER);
340
341 DoubleScalar.Rel<LengthUnit> maximumReverseHeadway = new DoubleScalar.Rel<LengthUnit>(-200.0, LengthUnit.METER);
342
343 DoubleScalar.Abs<SpeedUnit> speedLimit = new DoubleScalar.Abs<SpeedUnit>(100.0, SpeedUnit.KM_PER_HOUR);
344
345 if (null != this.laneChangeModel)
346 {
347 Collection<HeadwayGTU> sameLaneTraffic = new ArrayList<HeadwayGTU>();
348 HeadwayGTU leader = headway(maximumForwardHeadway);
349 if (null != leader.getOtherGTU())
350 {
351 sameLaneTraffic.add(leader);
352 }
353 HeadwayGTU follower = headway(maximumReverseHeadway);
354 if (null != follower.getOtherGTU())
355 {
356 sameLaneTraffic.add(new HeadwayGTU(follower.getOtherGTU(), -follower.getDistanceSI()));
357 }
358 DoubleScalar.Abs<TimeUnit> now = getSimulator().getSimulatorTime().get();
359 Collection<HeadwayGTU> leftLaneTraffic =
360 collectNeighborLaneTraffic(LateralDirectionality.LEFT, now, maximumForwardHeadway, maximumReverseHeadway);
361 Collection<HeadwayGTU> rightLaneTraffic =
362 collectNeighborLaneTraffic(LateralDirectionality.RIGHT, now, maximumForwardHeadway, maximumReverseHeadway);
363 LaneMovementStep lcmr =
364 this.laneChangeModel.computeLaneChangeAndAcceleration(this, sameLaneTraffic, rightLaneTraffic,
365 leftLaneTraffic, speedLimit, new DoubleScalar.Rel<AccelerationUnit>(0.3,
366 AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Rel<AccelerationUnit>(0.1,
367 AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Rel<AccelerationUnit>(-0.3,
368 AccelerationUnit.METER_PER_SECOND_2));
369
370 setState(lcmr.getGfmr());
371
372
373
374 if (lcmr.getLaneChange() != null)
375 {
376 synchronized (this.lanes)
377 {
378
379 Collection<Lane> oldLaneSet = new ArrayList<Lane>(this.lanes);
380 Collection<Lane> newLaneSet = adjacentLanes(lcmr.getLaneChange());
381
382 Map<Lane, Double> oldFractionalPositions = new HashMap<Lane, Double>();
383 for (Lane l : this.lanes)
384 {
385 oldFractionalPositions.put(l, fractionalPosition(l, getReference(), getLastEvaluationTime()));
386 this.fractionalLinkPositions.remove(l.getParentLink());
387 }
388 for (Lane l : oldFractionalPositions.keySet())
389 {
390 l.removeGTU(this);
391 removeLane(l);
392 }
393 ArrayList<Lane> replacementLanes = new ArrayList<Lane>();
394
395
396 for (Lane newLane : newLaneSet)
397 {
398 Double fractionalPosition = null;
399
400 for (Lane oldLane : oldLaneSet)
401 {
402 if (oldLane.accessibleAdjacentLanes(lcmr.getLaneChange(), getGTUType()).contains(newLane))
403 {
404 fractionalPosition = oldFractionalPositions.get(oldLane);
405 break;
406 }
407 }
408 if (null == fractionalPosition)
409 {
410 throw new Error("Program error: Cannot find an oldLane that has newLane " + newLane + " as "
411 + lcmr.getLaneChange() + " neighbor");
412 }
413 newLane.addGTU(this, fractionalPosition);
414 addLane(newLane, (Rel<LengthUnit>) newLane.getLength().mutable().multiply(fractionalPosition)
415 .immutable());
416 replacementLanes.add(newLane);
417 }
418 System.out.println("GTU " + this + " changed lanes from: " + oldLaneSet + " to " + replacementLanes);
419 checkConsistency();
420 }
421 }
422
423 else
424 {
425
426
427
428
429
430
431
432
433
434
435 }
436
437 scheduleTriggers();
438 getSimulator().scheduleEventAbs(this.getNextEvaluationTime(), this, this, "move", null);
439 }
440 }
441
442
443
444
445 private void checkConsistency()
446 {
447 for (Lane l : this.lanes)
448 {
449 if (!this.fractionalLinkPositions.containsKey(l.getParentLink()))
450 {
451 System.err.println("GTU " + this + "XXXXXXXX");
452 }
453 }
454 for (Link<?, ?> csl : this.fractionalLinkPositions.keySet())
455 {
456 boolean found = false;
457 for (Lane l : this.lanes)
458 {
459 if (l.getParentLink().equals(csl))
460 {
461 found = true;
462 break;
463 }
464 }
465 if (!found)
466 {
467 System.err.println("GTU " + this + "YYYYYYYYY");
468 }
469 }
470 }
471
472
473
474
475
476
477
478 private void scheduleTriggers() throws NetworkException, RemoteException, SimRuntimeException
479 {
480
481
482 for (Lane lane : this.lanes)
483 {
484 double frontPosSI = position(lane, getFront(), this.lastEvaluationTime).getSI();
485 double frontPosAtNextEvalSI = position(lane, getFront(), this.nextEvaluationTime).getSI();
486 double remainingDistanceSI = lane.getLength().getSI() - frontPosSI;
487
488 double moveSI = frontPosAtNextEvalSI - frontPosSI;
489 if (lane.fractionSI(frontPosSI) <= 1.0 && lane.fractionSI(frontPosAtNextEvalSI) > 1.0)
490 {
491 for (Lane nextLane : lane.nextLanes())
492 {
493
494 if (!this.lanes.contains(nextLane)
495 && (this.getRoute() == null || this.getRoute() != null
496 && this.getRoute().containsLink(nextLane.getParentLink())))
497 {
498 nextLane.scheduleTriggers(this, -remainingDistanceSI - getFront().getDx().getSI(), moveSI);
499 }
500 }
501 }
502
503 lane.scheduleTriggers(this, lane.positionSI(this.fractionalLinkPositions.get(lane.getParentLink())), moveSI);
504 }
505
506
507
508
509
510
511
512
513
514 }
515
516
517
518
519
520
521
522
523
524
525
526
527 private Collection<HeadwayGTU> collectNeighborLaneTraffic(final LateralDirectionality directionality,
528 final DoubleScalar.Abs<TimeUnit> when, final DoubleScalar.Rel<LengthUnit> maximumForwardHeadway,
529 final DoubleScalar.Rel<LengthUnit> maximumReverseHeadway) throws RemoteException, NetworkException
530 {
531 Collection<HeadwayGTU> result = new HashSet<HeadwayGTU>();
532 for (LaneBasedGTU<?> p : parallel(directionality, when))
533 {
534 result.add(new HeadwayGTU(p, Double.NaN));
535 }
536 for (Lane adjacentLane : adjacentLanes(directionality))
537 {
538 HeadwayGTU leader = headway(adjacentLane, maximumForwardHeadway);
539 if (null != leader.getOtherGTU() && !result.contains(leader))
540 {
541 result.add(leader);
542 }
543 HeadwayGTU follower = headway(adjacentLane, maximumReverseHeadway);
544 if (null != follower.getOtherGTU() && !result.contains(follower))
545 {
546 result.add(new HeadwayGTU(follower.getOtherGTU(), -follower.getDistanceSI()));
547 }
548 }
549 return result;
550 }
551
552
553 @Override
554 public final Map<Lane, DoubleScalar.Rel<LengthUnit>> positions(final RelativePosition relativePosition)
555 throws NetworkException, RemoteException
556 {
557 return positions(relativePosition, getSimulator().getSimulatorTime().get());
558 }
559
560
561 @Override
562 public final Map<Lane, DoubleScalar.Rel<LengthUnit>> positions(final RelativePosition relativePosition,
563 final DoubleScalar.Abs<TimeUnit> when) throws NetworkException
564 {
565 Map<Lane, DoubleScalar.Rel<LengthUnit>> positions = new HashMap<>();
566 for (Lane lane : this.lanes)
567 {
568 positions.put(lane, position(lane, relativePosition, when));
569 }
570 return positions;
571 }
572
573
574 @Override
575 public final DoubleScalar.Rel<LengthUnit> position(final Lane lane, final RelativePosition relativePosition)
576 throws NetworkException, RemoteException
577 {
578 return position(lane, relativePosition, getSimulator().getSimulatorTime().get());
579 }
580
581
582 public final DoubleScalar.Rel<LengthUnit> projectedPosition(final Lane projectionLane,
583 final RelativePosition relativePosition, final DoubleScalar.Abs<TimeUnit> when) throws NetworkException
584 {
585 CrossSectionLink<?, ?> link = projectionLane.getParentLink();
586 for (CrossSectionElement cse : link.getCrossSectionElementList())
587 {
588 if (cse instanceof Lane)
589 {
590 Lane cseLane = (Lane) cse;
591 if (this.lanes.contains(cseLane))
592 {
593 double fractionalPosition = fractionalPosition(cseLane, relativePosition, when);
594 return new DoubleScalar.Rel<LengthUnit>(projectionLane.getLength().getSI() * fractionalPosition,
595 LengthUnit.SI);
596 }
597 }
598 }
599 throw new NetworkException("GTU " + this + " is not on any lane of Link " + link);
600 }
601
602
603 @Override
604 public final DoubleScalar.Rel<LengthUnit> position(final Lane lane, final RelativePosition relativePosition,
605 final DoubleScalar.Abs<TimeUnit> when) throws NetworkException
606 {
607 if (null == lane)
608 {
609 throw new NetworkException("lane is null");
610 }
611 if (!this.lanes.contains(lane))
612 {
613 throw new NetworkException("GTU is not on lane " + lane.toString());
614 }
615 if (!this.fractionalLinkPositions.containsKey(lane.getParentLink()))
616 {
617 throw new NetworkException("GTU does not have a fractional position on " + lane.toString());
618 }
619 DoubleScalar.Rel<LengthUnit> longitudinalPosition =
620 lane.position(this.fractionalLinkPositions.get(lane.getParentLink()));
621 if (longitudinalPosition == null)
622 {
623 throw new NetworkException("GetPosition: GTU " + toString() + " not in lane " + lane);
624 }
625 DoubleScalar.Rel<TimeUnit> dT = DoubleScalar.minus(when, this.lastEvaluationTime).immutable();
626 DoubleScalar.Rel<LengthUnit> loc =
627 DoubleScalar.plus(
628 DoubleScalar.plus(DoubleScalar.plus(longitudinalPosition, Calc.speedTimesTime(this.speed, dT)).immutable(),
629 Calc.accelerationTimesTimeSquaredDiv2(this.getAcceleration(when), dT)).immutable(),
630 relativePosition.getDx()).immutable();
631 if (Double.isNaN(loc.getSI()))
632 {
633 System.out.println("loc is NaN");
634 }
635 return loc;
636 }
637
638
639 @Override
640 public final Map<Lane, Double> fractionalPositions(final RelativePosition relativePosition) throws NetworkException,
641 RemoteException
642 {
643 return fractionalPositions(relativePosition, getSimulator().getSimulatorTime().get());
644 }
645
646
647 @Override
648 public final Map<Lane, Double> fractionalPositions(final RelativePosition relativePosition,
649 final DoubleScalar.Abs<TimeUnit> when) throws NetworkException
650 {
651 Map<Lane, Double> positions = new HashMap<>();
652 for (Lane lane : this.lanes)
653 {
654 positions.put(lane, fractionalPosition(lane, relativePosition, when));
655 }
656 return positions;
657 }
658
659
660 @Override
661 public final double fractionalPosition(final Lane lane, final RelativePosition relativePosition,
662 final DoubleScalar.Abs<TimeUnit> when) throws NetworkException
663 {
664 return position(lane, relativePosition, when).getSI() / lane.getLength().getSI();
665 }
666
667
668 @Override
669 public final double fractionalPosition(final Lane lane, final RelativePosition relativePosition)
670 throws NetworkException, RemoteException
671 {
672 return position(lane, relativePosition).getSI() / lane.getLength().getSI();
673 }
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688 private HeadwayGTU headwayRecursiveForwardSI(final Lane lane, final double lanePositionSI, final double cumDistanceSI,
689 final double maxDistanceSI, final DoubleScalar.Abs<TimeUnit> when) throws RemoteException, NetworkException
690 {
691 LaneBasedGTU<?> otherGTU =
692 lane.getGtuAfter(new DoubleScalar.Rel<LengthUnit>(lanePositionSI, LengthUnit.METER), RelativePosition.REAR, when);
693 if (otherGTU != null)
694 {
695 double distanceM = cumDistanceSI + otherGTU.position(lane, otherGTU.getRear(), when).getSI() - lanePositionSI;
696 if (distanceM > 0 && distanceM <= maxDistanceSI)
697 {
698 return new HeadwayGTU(otherGTU, distanceM);
699 }
700 return new HeadwayGTU(null, Double.MAX_VALUE);
701 }
702
703
704 if (cumDistanceSI + lane.getLength().getSI() - lanePositionSI < maxDistanceSI)
705 {
706
707 Set<Lane> nextLanes = lane.nextLanes();
708 if (nextLanes.size() > 0)
709 {
710 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
711 for (Lane nextLane : nextLanes)
712 {
713
714 if (this.getRoute() == null || this.getRoute() != null
715 && this.getRoute().containsLink(lane.getParentLink()))
716 {
717 double traveledDistanceSI = cumDistanceSI + lane.getLength().getSI() - lanePositionSI;
718 HeadwayGTU closest =
719 headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
720 if (closest.getDistanceSI() < maxDistanceSI
721 && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
722 {
723 foundMaxGTUDistanceSI = closest;
724 }
725 }
726 }
727 return foundMaxGTUDistanceSI;
728 }
729 }
730
731
732 return new HeadwayGTU(null, Double.MAX_VALUE);
733 }
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751 private HeadwayGTU headwayRecursiveBackwardSI(final Lane lane, final double lanePositionSI, final double cumDistanceSI,
752 final double maxDistanceSI, final DoubleScalar.Abs<TimeUnit> when) throws RemoteException, NetworkException
753 {
754 LaneBasedGTU<?> otherGTU =
755 lane.getGtuBefore(new DoubleScalar.Rel<LengthUnit>(lanePositionSI, LengthUnit.METER), RelativePosition.FRONT,
756 when);
757 if (otherGTU != null)
758 {
759 double distanceM = cumDistanceSI + lanePositionSI - otherGTU.position(lane, otherGTU.getFront(), when).getSI();
760 if (distanceM > 0 && distanceM <= maxDistanceSI)
761 {
762 return new HeadwayGTU(otherGTU, distanceM);
763 }
764 return new HeadwayGTU(null, Double.MAX_VALUE);
765 }
766
767
768 if (cumDistanceSI + lanePositionSI < maxDistanceSI)
769 {
770
771 Set<Lane> prevLanes = lane.prevLanes();
772 if (prevLanes.size() > 0)
773 {
774 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
775 for (Lane prevLane : prevLanes)
776 {
777
778 double traveledDistanceSI = cumDistanceSI + lanePositionSI;
779 HeadwayGTU closest =
780 headwayRecursiveBackwardSI(prevLane, prevLane.getLength().getSI(), traveledDistanceSI,
781 maxDistanceSI, when);
782 if (closest.getDistanceSI() < maxDistanceSI
783 && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
784 {
785 foundMaxGTUDistanceSI = closest;
786 }
787 }
788 return foundMaxGTUDistanceSI;
789 }
790 }
791
792
793 return new HeadwayGTU(null, Double.MAX_VALUE);
794 }
795
796
797
798
799
800
801
802
803 private HeadwayGTU headwayGTUSI(final double maxDistanceSI) throws RemoteException, NetworkException
804 {
805 DoubleScalar.Abs<TimeUnit> when = getSimulator().getSimulatorTime().get();
806 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, Double.MAX_VALUE);
807
808 if (maxDistanceSI > 0.0)
809 {
810
811 for (Lane lane : positions(getFront()).keySet())
812 {
813 HeadwayGTU closest =
814 headwayRecursiveForwardSI(lane, this.position(lane, this.getFront(), when).getSI(), 0.0, maxDistanceSI,
815 when);
816 if (closest.getDistanceSI() < maxDistanceSI
817 && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
818 {
819 foundMaxGTUDistanceSI = closest;
820 }
821 }
822 }
823 else
824 {
825
826 for (Lane lane : positions(getRear()).keySet())
827 {
828 HeadwayGTU closest =
829 headwayRecursiveBackwardSI(lane, this.position(lane, this.getRear(), when).getSI(), 0.0, -maxDistanceSI,
830 when);
831 if (closest.getDistanceSI() < -maxDistanceSI
832 && closest.getDistanceSI() < foundMaxGTUDistanceSI.getDistanceSI())
833 {
834 foundMaxGTUDistanceSI = closest;
835 }
836 }
837 }
838 return foundMaxGTUDistanceSI;
839 }
840
841
842 @Override
843 public final HeadwayGTU headway(final DoubleScalar.Rel<LengthUnit> maxDistance) throws RemoteException, NetworkException
844 {
845 return headwayGTUSI(maxDistance.getSI());
846 }
847
848
849 @Override
850 public final HeadwayGTU headway(final Lane lane, final DoubleScalar.Rel<LengthUnit> maxDistance) throws RemoteException,
851 NetworkException
852 {
853 DoubleScalar.Abs<TimeUnit> when = getSimulator().getSimulatorTime().get();
854 if (maxDistance.getSI() > 0.0)
855 {
856 return headwayRecursiveForwardSI(lane, this.projectedPosition(lane, this.getFront(), when).getSI(), 0.0,
857 maxDistance.getSI(), when);
858 }
859 else
860 {
861 return headwayRecursiveBackwardSI(lane, this.projectedPosition(lane, this.getRear(), when).getSI(), 0.0,
862 -maxDistance.getSI(), when);
863 }
864 }
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880 private double headwayRecursiveForwardSI(final Lane lane, final double lanePositionSI, final LaneBasedGTU<?> otherGTU,
881 final double cumDistanceSI, final double maxDistanceSI, final DoubleScalar.Abs<TimeUnit> when)
882 throws RemoteException, NetworkException
883 {
884 if (lane.getGtuList().contains(otherGTU))
885 {
886 double distanceM = cumDistanceSI + otherGTU.position(lane, otherGTU.getRear(), when).getSI() - lanePositionSI;
887 if (distanceM > 0 && distanceM <= maxDistanceSI)
888 {
889 return distanceM;
890 }
891 return Double.MAX_VALUE;
892 }
893
894
895 if (cumDistanceSI + lane.getLength().getSI() - lanePositionSI < maxDistanceSI)
896 {
897
898 Set<Lane> nextLanes = lane.nextLanes();
899 if (nextLanes.size() > 0)
900 {
901 for (Lane nextLane : nextLanes)
902 {
903
904 if (this.getRoute() == null || this.getRoute() != null
905 && this.getRoute().containsLink(lane.getParentLink()))
906 {
907 double traveledDistanceSI = cumDistanceSI + lane.getLength().getSI() - lanePositionSI;
908 double headwaySuccessor =
909 headwayRecursiveForwardSI(nextLane, 0.0, otherGTU, traveledDistanceSI, maxDistanceSI, when);
910 if (headwaySuccessor < maxDistanceSI)
911 {
912 return headwaySuccessor;
913 }
914 }
915 }
916 }
917 }
918
919
920 return Double.MAX_VALUE;
921 }
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938 private double headwayRecursiveBackwardSI(final Lane lane, final double lanePositionSI, final LaneBasedGTU<?> otherGTU,
939 final double cumDistanceSI, final double maxDistanceSI, final DoubleScalar.Abs<TimeUnit> when)
940 throws RemoteException, NetworkException
941 {
942 if (lane.getGtuList().contains(otherGTU))
943 {
944 double distanceM = cumDistanceSI + lanePositionSI - otherGTU.position(lane, otherGTU.getFront(), when).getSI();
945 if (distanceM > 0 && distanceM <= maxDistanceSI)
946 {
947 return distanceM;
948 }
949 return Double.MAX_VALUE;
950 }
951
952
953 if (cumDistanceSI + lanePositionSI < maxDistanceSI)
954 {
955
956 Set<Lane> prevLanes = lane.prevLanes();
957 if (prevLanes.size() > 0)
958 {
959 for (Lane prevLane : prevLanes)
960 {
961
962 double traveledDistanceSI = cumDistanceSI + lanePositionSI;
963 double headwayPredecessor =
964 headwayRecursiveForwardSI(prevLane, prevLane.getLength().getSI(), otherGTU, traveledDistanceSI,
965 maxDistanceSI, when);
966 if (headwayPredecessor < maxDistanceSI)
967 {
968 return headwayPredecessor;
969 }
970 }
971 }
972 }
973
974
975 return Double.MAX_VALUE;
976 }
977
978
979 @Override
980 public final Set<LaneBasedGTU<?>> parallel(final Lane lane, final DoubleScalar.Abs<TimeUnit> when)
981 throws RemoteException, NetworkException
982 {
983 Set<LaneBasedGTU<?>> gtuSet = new HashSet<LaneBasedGTU<?>>();
984 for (Lane l : this.lanes)
985 {
986
987 if (l.getParentLink().equals(lane.getParentLink()))
988 {
989
990 double posFractionFront = Math.max(0.0, this.fractionalPosition(l, getFront(), when));
991 double posFractionRear = Math.min(1.0, this.fractionalPosition(l, getRear(), when));
992 for (LaneBasedGTU<?> gtu : lane.getGtuList())
993 {
994 if (!gtu.equals(this))
995 {
996 double gtuFractionFront = Math.max(0.0, gtu.fractionalPosition(lane, gtu.getFront(), when));
997 double gtuFractionRear = Math.min(1.0, gtu.fractionalPosition(lane, gtu.getRear(), when));
998 if (gtuFractionFront >= posFractionRear && gtuFractionRear <= posFractionFront)
999 {
1000 gtuSet.add(gtu);
1001 }
1002 }
1003 }
1004 }
1005 }
1006 return gtuSet;
1007 }
1008
1009
1010
1011
1012
1013
1014 private Set<Lane> adjacentLanes(final LateralDirectionality lateralDirection)
1015 {
1016 Set<Lane> result = new HashSet<Lane>();
1017 for (Lane lane : this.lanes)
1018 {
1019 result.addAll(lane.accessibleAdjacentLanes(lateralDirection, getGTUType()));
1020 }
1021 return result;
1022 }
1023
1024
1025 @Override
1026 public final Set<LaneBasedGTU<?>> parallel(final LateralDirectionality lateralDirection,
1027 final DoubleScalar.Abs<TimeUnit> when) throws RemoteException, NetworkException
1028 {
1029 Set<Lane> adjacentLanes = adjacentLanes(lateralDirection);
1030
1031
1032
1033
1034
1035
1036 Set<LaneBasedGTU<?>> gtuSet = new HashSet<LaneBasedGTU<?>>();
1037 for (Lane adjacentLane : adjacentLanes)
1038 {
1039 gtuSet.addAll(parallel(adjacentLane, when));
1040 }
1041 return gtuSet;
1042 }
1043
1044
1045 public final DoubleScalar.Abs<TimeUnit> timeAtDistance(final DoubleScalar.Rel<LengthUnit> distance)
1046 {
1047 Double result = solveTimeForDistance(distance);
1048 if (null == result)
1049 {
1050 return null;
1051 }
1052 return new DoubleScalar.Abs<TimeUnit>(this.lastEvaluationTime.getSI() + result, TimeUnit.SECOND);
1053 }
1054
1055
1056 public final DoubleScalar.Rel<TimeUnit> deltaTimeForDistance(final DoubleScalar.Rel<LengthUnit> distance)
1057 {
1058 Double result = solveTimeForDistance(distance);
1059 if (null == result)
1060 {
1061 return null;
1062 }
1063 return new DoubleScalar.Rel<TimeUnit>(result, TimeUnit.SECOND);
1064 }
1065
1066
1067 @Override
1068 @SuppressWarnings("checkstyle:designforextension")
1069 public void destroy()
1070 {
1071 while (!this.lanes.isEmpty())
1072 {
1073 Lane lane = this.lanes.get(0);
1074 removeLane(lane);
1075 lane.removeGTU(this);
1076 }
1077 }
1078
1079
1080
1081
1082
1083
1084
1085 private Double solveTimeForDistance(final DoubleScalar.Rel<LengthUnit> distance)
1086 {
1087
1088
1089
1090
1091 double c = -distance.getSI();
1092 double a = this.acceleration.getSI() / 2;
1093 double b = this.speed.getSI();
1094 if (0 == a)
1095 {
1096 if (b > 0)
1097 {
1098 return -c / b;
1099 }
1100 return null;
1101 }
1102
1103 double discriminant = b * b - 4 * a * c;
1104 if (discriminant < 0)
1105 {
1106 return null;
1107 }
1108
1109 double solution1 = (-b - Math.sqrt(discriminant)) / 2 / a;
1110 double solution2 = (-b + Math.sqrt(discriminant)) / 2 / a;
1111 if (solution1 < 0 && solution2 < 0)
1112 {
1113 return null;
1114 }
1115 if (solution1 < 0)
1116 {
1117 return solution2;
1118 }
1119 if (solution2 < 0)
1120 {
1121 return solution1;
1122 }
1123
1124 if (solution1 < solution2)
1125 {
1126 return solution1;
1127 }
1128 return solution2;
1129 }
1130
1131
1132
1133
1134
1135 public final GTUFollowingModel getGTUFollowingModel()
1136 {
1137 return this.gtuFollowingModel;
1138 }
1139
1140
1141 @Override
1142 public final DirectedPoint getLocation() throws RemoteException
1143 {
1144 synchronized (this.lanes)
1145 {
1146 try
1147 {
1148 if (this.lanes.size() == 0)
1149 {
1150 if (getSimulator().isRunning())
1151 {
1152
1153 System.out.println("GTU " + this.getId() + " is not on any lane");
1154 }
1155
1156 return new DirectedPoint(Double.MAX_VALUE, Double.MAX_VALUE, 0);
1157 }
1158 Lane lane = this.lanes.get(0);
1159
1160 DoubleScalar.Rel<LengthUnit> longitudinalPos = position(lane, getReference());
1161 double fraction = (longitudinalPos.getSI() + getLength().getSI() / 2.0) / lane.getLength().getSI();
1162 LineString line = lane.getCenterLine();
1163 LengthIndexedLine lil = new LengthIndexedLine(line);
1164
1165
1166
1167
1168 double useFraction = fraction;
1169 if (fraction < 0)
1170 {
1171 useFraction = 0;
1172 }
1173 if (fraction > 0.99)
1174 {
1175 useFraction = 0.99;
1176 }
1177
1178 Coordinate c = new Coordinate(lil.extractPoint(useFraction * line.getLength()));
1179 c.z = 0d;
1180 Coordinate cb = lil.extractPoint((useFraction + 0.01) * line.getLength());
1181 double angle = Math.atan2(cb.y - c.y, cb.x - c.x);
1182
1183 if (fraction != useFraction)
1184 {
1185 c =
1186 new Coordinate(c.x + (fraction - useFraction) * 100 * (cb.x - c.x), c.y + (fraction - useFraction)
1187 * 100 * (cb.y - c.y), c.z);
1188 }
1189 if (Double.isNaN(c.x))
1190 {
1191 System.out.println("Bad");
1192 }
1193 return new DirectedPoint(c.x, c.y, c.z + 0.01 , 0.0, 0.0,
1194 angle);
1195 }
1196 catch (Exception ne)
1197 {
1198 System.err.println(this.getId());
1199 ne.printStackTrace();
1200 return new DirectedPoint(0, 0, 0);
1201 }
1202 }
1203 }
1204
1205
1206 @Override
1207 public final Bounds getBounds() throws RemoteException
1208 {
1209 double dx = 0.5 * getLength().doubleValue();
1210 double dy = 0.5 * getWidth().doubleValue();
1211 return new BoundingBox(new Point3d(-dx, -dy, 0.0), new Point3d(dx, dy, 0.0));
1212 }
1213
1214
1215
1216
1217
1218
1219
1220 public final String toString(final Lane lane, final DoubleScalar.Abs<TimeUnit> when)
1221 {
1222 double pos = Double.NaN;
1223 try
1224 {
1225 pos = this.position(lane, getFront(), when).getSI();
1226 }
1227 catch (NetworkException exception)
1228 {
1229
1230 }
1231
1232 return String.format("Car %5d lastEval %6.1fs, nextEval %6.1fs, % 9.3fm, v % 6.3fm/s, a % 6.3fm/s^2", getId(),
1233 this.lastEvaluationTime.getSI(), getNextEvaluationTime().getSI(), pos, this.getLongitudinalVelocity(when)
1234 .getSI(), this.getAcceleration(when).getSI());
1235 }
1236
1237 }