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