1 package org.opentrafficsim.road.gtu.generator;
2
3 import java.io.Serializable;
4 import java.rmi.RemoteException;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import javax.media.j3d.BoundingBox;
13 import javax.media.j3d.Bounds;
14 import javax.vecmath.Point3d;
15
16 import org.djunits.unit.DurationUnit;
17 import org.djunits.unit.LengthUnit;
18 import org.djunits.unit.SpeedUnit;
19 import org.djunits.value.vdouble.scalar.Acceleration;
20 import org.djunits.value.vdouble.scalar.Duration;
21 import org.djunits.value.vdouble.scalar.Length;
22 import org.djunits.value.vdouble.scalar.Speed;
23 import org.djunits.value.vdouble.scalar.Time;
24 import org.opentrafficsim.core.geometry.OTSGeometryException;
25 import org.opentrafficsim.core.gtu.GTUDirectionality;
26 import org.opentrafficsim.core.gtu.GTUException;
27 import org.opentrafficsim.core.gtu.GTUType;
28 import org.opentrafficsim.core.gtu.RelativePosition;
29 import org.opentrafficsim.core.gtu.animation.GTUColorer;
30 import org.opentrafficsim.core.network.NetworkException;
31 import org.opentrafficsim.core.network.OTSNetwork;
32 import org.opentrafficsim.core.network.route.RouteGenerator;
33 import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
34 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
35 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
36 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
37 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU.LaneBasedIndividualCarBuilder;
38 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
39 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayDistance;
40 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
41 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
42 import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
43 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
44 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
45 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
46 import org.opentrafficsim.road.network.lane.Lane;
47
48 import nl.tudelft.simulation.dsol.SimRuntimeException;
49 import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
50 import nl.tudelft.simulation.language.d3.DirectedPoint;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public abstract class AbstractGTUGenerator implements Serializable, GTUGenerator
68 {
69
70 private static final long serialVersionUID = 20150202L;
71
72
73 private final String name;
74
75
76 private final GTUType gtuType;
77
78
79 private final Class<?> gtuClass;
80
81
82 private final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist;
83
84
85 private final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist;
86
87
88 private long generatedGTUs = 0;
89
90
91 private final long maxGTUs;
92
93
94 private final Time startTime;
95
96
97 private final Time endTime;
98
99
100 private final Lane lane;
101
102
103 private final Length position;
104
105
106 private final GTUDirectionality direction;
107
108
109 private final GTUColorer gtuColorer;
110
111
112 private final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory;
113
114
115 private final RouteGenerator routeGenerator;
116
117
118 private final OTSNetwork network;
119
120
121 private List<LaneBasedIndividualCarBuilder> carBuilderList = new ArrayList<>();
122
123
124 @SuppressWarnings("checkstyle:visibilitymodifier")
125 protected long numberGTUs = 0;
126
127
128 private final Bounds bounds;
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 @SuppressWarnings("checkstyle:parameternumber")
150 public AbstractGTUGenerator(final String name, final DEVSSimulatorInterface.TimeDoubleUnit simulator, final GTUType gtuType,
151 final Class<?> gtuClass, final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist,
152 final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist, final long maxGTUs,
153 final Time startTime, final Time endTime, final Lane lane, final Length position, final GTUDirectionality direction,
154 final GTUColorer gtuColorer,
155 final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory,
156 final RouteGenerator routeGenerator, final OTSNetwork network) throws SimRuntimeException
157 {
158 super();
159 this.name = name;
160 this.gtuType = gtuType;
161 this.gtuClass = gtuClass;
162 this.initialSpeedDist = initialSpeedDist;
163 this.interarrivelTimeDist = interarrivelTimeDist;
164 this.maxGTUs = maxGTUs;
165 this.startTime = startTime;
166 this.endTime = endTime;
167 this.lane = lane;
168 this.position = position;
169 this.direction = direction;
170 this.gtuColorer = gtuColorer;
171 this.strategicalPlannerFactory = strategicalPlannerFactory;
172 this.routeGenerator = routeGenerator;
173 this.network = network;
174 DirectedPoint p;
175 try
176 {
177 p = this.getLocation();
178 this.bounds = new BoundingBox(new Point3d(p.x - 1, p.y - 1, 0.0), new Point3d(p.x + 1, p.y + 1, 0.0));
179 }
180 catch (@SuppressWarnings("unused") RemoteException exception)
181 {
182 throw new RuntimeException("Bounds for generator cannot be determined.");
183 }
184 simulator.scheduleEventAbs(startTime, this, this, "generate", null);
185 }
186
187
188
189
190
191 protected final void generate() throws Exception
192 {
193
194 if (getSimulator().getSimulatorTime().gt(this.endTime))
195 {
196 return;
197 }
198
199
200 if (this.generatedGTUs >= this.maxGTUs)
201 {
202 return;
203 }
204
205
206 this.numberGTUs++;
207 String id = this.name + ":" + this.numberGTUs;
208
209
210 if (LaneBasedIndividualGTU.class.isAssignableFrom(getGtuClass()))
211 {
212 LaneBasedIndividualCarBuilder carBuilder = new LaneBasedIndividualCarBuilder();
213 carBuilder.setId(id);
214 carBuilder.setGtuType(getGtuType());
215 Length carLength = getLengthDist().draw();
216 carBuilder.setLength(carLength);
217 carBuilder.setFront(carLength.multiplyBy(0.75));
218 carBuilder.setWidth(getWidthDist().draw());
219 carBuilder.setMaximumSpeed(getMaximumSpeedDist().draw());
220 carBuilder.setInitialSpeed(getInitialSpeedDist().draw());
221 carBuilder.setSimulator(getSimulator());
222 Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
223 initialLongitudinalPositions.add(new DirectedLanePosition(this.lane, this.position, this.direction));
224 carBuilder.setInitialLongitudinalPositions(initialLongitudinalPositions);
225 carBuilder.setAnimationClass(DefaultCarAnimation.class);
226 carBuilder.setGtuColorer(this.gtuColorer);
227 carBuilder.setNetwork(this.network);
228 carBuilder.setMaximumAcceleration(Acceleration.createSI(3.0));
229 carBuilder.setMaximumDeceleration(Acceleration.createSI(-8.0));
230 this.generatedGTUs++;
231
232 if (enoughSpace(carBuilder))
233 {
234 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
235 }
236 else
237 {
238
239 this.carBuilderList.add(carBuilder);
240
241 if (this.carBuilderList.size() == 1)
242 {
243
244 getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList",
245 null);
246 }
247 }
248 }
249 else
250 {
251 throw new GTUException("GTU class " + getGtuClass().getName() + ": cannot instantiate, no builder.");
252 }
253
254
255 Time nextTime = getSimulator().getSimulatorTime().plus(this.interarrivelTimeDist.draw());
256 if (nextTime.le(this.endTime))
257 {
258 getSimulator().scheduleEventAbs(nextTime, this, this, "generate", null);
259 }
260 }
261
262
263
264
265
266
267
268
269
270 protected final boolean enoughSpace(final LaneBasedIndividualCarBuilder carBuilder) throws NetworkException, GTUException
271 {
272 DirectedLanePosition directedLanePosition = carBuilder.getInitialLongitudinalPositions().iterator().next();
273 Lane generatorLane = directedLanePosition.getLane();
274 double genPosSI = directedLanePosition.getPosition().getSI();
275
276
277 double lengthSI = generatorLane.getLength().getSI();
278 double frontNew = (genPosSI + carBuilder.getLength().getSI()) / lengthSI;
279 double rearNew = genPosSI / lengthSI;
280
281
282 for (LaneBasedGTU gtu : generatorLane.getGtuList())
283 {
284 double frontGTU = gtu.fractionalPosition(generatorLane, gtu.getFront());
285 double rearGTU = gtu.fractionalPosition(generatorLane, gtu.getRear());
286 if ((frontNew >= rearGTU && frontNew <= frontGTU) || (rearNew >= rearGTU && rearNew <= frontGTU)
287 || (frontGTU >= rearNew && frontGTU <= frontNew) || (rearGTU >= rearNew && rearGTU <= frontNew))
288 {
289
290 return false;
291 }
292 }
293
294
295 GTUFollowingModelOld followingModel = new IDMPlusOld();
296
297
298 Headway headway = headway(new Length(250.0, LengthUnit.METER), generatorLane);
299 Length minimumHeadway = new Length(0.0, LengthUnit.METER);
300 if (headway.getObjectType().isGtu())
301 {
302 minimumHeadway = followingModel.minimumHeadway(carBuilder.getInitialSpeed(), headway.getSpeed(),
303 new Length(1.0, LengthUnit.CENTIMETER), new Length(250.0, LengthUnit.METER),
304 generatorLane.getSpeedLimit(carBuilder.getGtuType()), carBuilder.getMaximumSpeed());
305
306 double acc = followingModel.computeAcceleration(carBuilder.getInitialSpeed(), carBuilder.getMaximumSpeed(),
307 headway.getSpeed(), headway.getDistance(), carBuilder.getMaximumSpeed()).getSI();
308 if (acc < 0)
309 {
310
311
312
313 return false;
314 }
315 }
316
317
318
319 return headway.getDistance().ge(minimumHeadway);
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333
334 private Headway headwayRecursiveForwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
335 final double maxDistanceSI, final Time when) throws GTUException
336 {
337
338 LaneBasedGTU otherGTU = theLane.getGtuAhead(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
339 RelativePosition.REAR, when);
340 if (otherGTU != null)
341 {
342 double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getRear(), when).getSI() - lanePositionSI;
343 if (distanceM > 0 && distanceM <= maxDistanceSI)
344 {
345 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
346 otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
347 }
348 return new HeadwayDistance(Double.MAX_VALUE);
349 }
350
351
352 if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
353 {
354
355 if (theLane.nextLanes(this.gtuType).size() > 0)
356 {
357 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
358 for (Lane nextLane : theLane.nextLanes(this.gtuType).keySet())
359 {
360
361
362
363
364 {
365 double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
366 Headway closest = headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
367 if (closest.getDistance().si < maxDistanceSI
368 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
369 {
370 foundMaxGTUDistanceSI = closest;
371 }
372 }
373 }
374 return foundMaxGTUDistanceSI;
375 }
376 }
377
378
379 return new HeadwayDistance(Double.MAX_VALUE);
380 }
381
382
383
384
385
386
387
388
389
390
391
392
393
394 private Headway headwayRecursiveBackwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
395 final double maxDistanceSI, final Time when) throws GTUException
396 {
397
398 LaneBasedGTU otherGTU = theLane.getGtuBehind(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
399 RelativePosition.FRONT, when);
400 if (otherGTU != null)
401 {
402 double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getFront(), when).getSI() - lanePositionSI;
403 if (distanceM > 0 && distanceM <= maxDistanceSI)
404 {
405 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
406 otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
407 }
408 return new HeadwayDistance(Double.MAX_VALUE);
409 }
410
411
412 if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
413 {
414
415 if (theLane.prevLanes(this.gtuType).size() > 0)
416 {
417 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
418 for (Lane prevLane : theLane.prevLanes(this.gtuType).keySet())
419 {
420
421
422
423
424 {
425 double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
426 Headway closest = headwayRecursiveBackwardSI(prevLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
427 if (closest.getDistance().si < maxDistanceSI
428 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
429 {
430 foundMaxGTUDistanceSI = closest;
431 }
432 }
433 }
434 return foundMaxGTUDistanceSI;
435 }
436 }
437
438
439 return new HeadwayDistance(Double.MAX_VALUE);
440 }
441
442
443
444
445
446
447
448
449
450 private Headway headwayGTUSIForward(final double maxDistanceSI, final Lane generatorLane) throws GTUException
451 {
452 Time when = getSimulator().getSimulatorTime();
453 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
454
455 Headway closest;
456 if (this.direction.equals(GTUDirectionality.DIR_PLUS))
457 {
458 closest = headwayRecursiveForwardSI(this.lane, 0.0, 0.0, maxDistanceSI, when);
459 }
460 else
461 {
462 closest = headwayRecursiveBackwardSI(this.lane, generatorLane.getLength().getSI(), 0.0, maxDistanceSI, when);
463 }
464 if (closest.getDistance().si < maxDistanceSI && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
465 {
466 foundMaxGTUDistanceSI = closest;
467 }
468 return foundMaxGTUDistanceSI;
469 }
470
471
472
473
474
475
476
477
478 public final Headway headway(final Length maxDistance, final Lane generatorLane) throws GTUException
479 {
480 return headwayGTUSIForward(maxDistance.getSI(), generatorLane);
481 }
482
483
484
485
486
487 protected final void checkCarBuilderList() throws Exception
488 {
489 if (!this.carBuilderList.isEmpty())
490 {
491 LaneBasedIndividualCarBuilder carBuilder = this.carBuilderList.get(0);
492 if (enoughSpace(carBuilder))
493 {
494 this.carBuilderList.remove(0);
495 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
496 }
497 }
498
499
500 if (!this.carBuilderList.isEmpty())
501 {
502 getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList", null);
503 }
504 }
505
506
507 public abstract DEVSSimulatorInterface.TimeDoubleUnit getSimulator();
508
509
510 public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getLengthDist();
511
512
513 public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getWidthDist();
514
515
516 public abstract ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getMaximumSpeedDist();
517
518
519
520
521 public final String getName()
522 {
523 return this.name;
524 }
525
526
527
528
529 public final GTUType getGtuType()
530 {
531 return this.gtuType;
532 }
533
534
535
536
537 public final Class<?> getGtuClass()
538 {
539 return this.gtuClass;
540 }
541
542
543
544
545 public final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getInitialSpeedDist()
546 {
547 return this.initialSpeedDist;
548 }
549
550
551
552
553 public final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> getInterarrivelTimeDist()
554 {
555 return this.interarrivelTimeDist;
556 }
557
558
559
560
561 public final long getMaxGTUs()
562 {
563 return this.maxGTUs;
564 }
565
566
567
568
569 public final Time getStartTime()
570 {
571 return this.startTime;
572 }
573
574
575
576
577 public final Time getEndTime()
578 {
579 return this.endTime;
580 }
581
582
583
584
585 public final GTUColorer getGtuColorer()
586 {
587 return this.gtuColorer;
588 }
589
590
591
592
593 public final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> getStrategicalPlannerFactory()
594 {
595 return this.strategicalPlannerFactory;
596 }
597
598
599 @Override
600 public DirectedPoint getLocation() throws RemoteException
601 {
602 try
603 {
604 return this.lane.getCenterLine().getLocation(this.position);
605 }
606 catch (@SuppressWarnings("unused") OTSGeometryException exception)
607 {
608 return this.lane.getLocation();
609 }
610 }
611
612
613 @Override
614 public Bounds getBounds() throws RemoteException
615 {
616 return this.bounds;
617 }
618
619
620 @Override
621 public Map<DirectedPoint, Integer> getQueueLengths()
622 {
623 Map<DirectedPoint, Integer> map = new HashMap<>();
624 try
625 {
626 map.put(getLocation(), this.carBuilderList.size());
627 }
628 catch (@SuppressWarnings("unused") RemoteException exception)
629 {
630 throw new RuntimeException("Locartion for generator queue cannot be determined.");
631 }
632 return map;
633 }
634
635 }