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