View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.rmi.RemoteException;
4   import java.util.ArrayList;
5   import java.util.Collections;
6   import java.util.Comparator;
7   import java.util.EnumMap;
8   import java.util.HashMap;
9   import java.util.HashSet;
10  import java.util.LinkedHashMap;
11  import java.util.LinkedHashSet;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  
16  import javax.media.j3d.BoundingBox;
17  import javax.media.j3d.Bounds;
18  import javax.vecmath.Point3d;
19  
20  import org.djunits.unit.SpeedUnit;
21  import org.djunits.value.vdouble.scalar.Length;
22  import org.djunits.value.vdouble.scalar.Speed;
23  import org.djutils.exceptions.Throw;
24  import org.opentrafficsim.core.geometry.OTSGeometryException;
25  import org.opentrafficsim.core.gtu.GTUDirectionality;
26  import org.opentrafficsim.core.gtu.GTUType;
27  import org.opentrafficsim.core.math.Draw;
28  import org.opentrafficsim.core.network.Link;
29  import org.opentrafficsim.core.network.LinkDirection;
30  import org.opentrafficsim.core.network.NetworkException;
31  import org.opentrafficsim.core.network.route.Route;
32  import org.opentrafficsim.road.gtu.generator.GeneratorPositions.RoadPosition.BySpeed;
33  import org.opentrafficsim.road.gtu.generator.GeneratorPositions.RoadPosition.ByValue;
34  import org.opentrafficsim.road.network.lane.CrossSectionLink;
35  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
36  import org.opentrafficsim.road.network.lane.Lane;
37  
38  import nl.tudelft.simulation.dsol.animation.Locatable;
39  import nl.tudelft.simulation.jstats.streams.StreamInterface;
40  import nl.tudelft.simulation.language.d3.DirectedPoint;
41  
42  /**
43   * Helper class for vehicle generation which can draw the next GTU position to try to place a GTU. If the GTU can not be placed,
44   * it should be included in a queue. This class requires the number of unplaced GTU's per lane, in order to appropriately divide
45   * traffic over the lanes.
46   * <p>
47   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
48   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
49   * <p>
50   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 22 dec. 2017 <br>
51   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
52   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
53   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
54   */
55  public final class GeneratorPositions implements Locatable
56  {
57  
58      /** Underlying object representing the zone. */
59      private final GeneratorZonePosition position;
60  
61      /** Lane biases per GTU type. */
62      private final LaneBiases biases;
63  
64      /** Stream for random numbers. */
65      private final StreamInterface stream;
66  
67      /** Location. */
68      private final DirectedPoint location;
69  
70      /** Bounds. */
71      private final Bounds bounds;
72  
73      /** Set of all positions. */
74      private final Set<GeneratorLanePosition> allPositions = new HashSet<>();
75  
76      /**
77       * Constructor. Private to facilitate easier creation methods using static factories, and to hide underlying classes.
78       * @param position GeneratorZonePosition; underlying object representing the zone
79       * @param biases LaneBiases; lane biases for GTU types
80       * @param stream StreamInterface; stream for random numbers
81       */
82      @SuppressWarnings("synthetic-access")
83      private GeneratorPositions(final GeneratorZonePosition position, final LaneBiases biases, final StreamInterface stream)
84      {
85          this.position = position;
86          this.biases = biases;
87          this.stream = stream;
88          double x = 0.0;
89          double y = 0.0;
90          double xMin = Double.POSITIVE_INFINITY;
91          double xMax = Double.NEGATIVE_INFINITY;
92          double yMin = Double.POSITIVE_INFINITY;
93          double yMax = Double.NEGATIVE_INFINITY;
94          int n = 0;
95          for (GeneratorLinkPosition linkPosition : position.positions)
96          {
97              for (GeneratorLanePosition lanePosition : linkPosition.positions)
98              {
99                  this.allPositions.add(lanePosition);
100                 for (DirectedLanePosition pos : lanePosition.getPosition())
101                 {
102                     DirectedPoint point;
103                     try
104                     {
105                         point = pos.getLane().getCenterLine().getLocation(pos.getPosition());
106                     }
107                     catch (OTSGeometryException exception)
108                     {
109                         point = new DirectedPoint(0, 0, 0);
110                     }
111                     x += point.x;
112                     y += point.y;
113                     xMin = xMin < point.x ? xMin : point.x;
114                     yMin = yMin < point.y ? yMin : point.y;
115                     xMax = xMax > point.x ? xMax : point.x;
116                     yMax = yMax > point.y ? yMax : point.y;
117                     n++;
118                 }
119             }
120         }
121         this.location = new DirectedPoint(x / n, y / n, 0);
122         this.bounds = new BoundingBox(new Point3d(xMin, yMin, 0.0), new Point3d(xMax, yMax, 0.0));
123     }
124 
125     /**
126      * Create a GeneratorPositions object to draw positions from. The given positions are grouped per link. Lanes are drawn
127      * without bias. Each link receives a weight equal to the number of lanes.
128      * @param positions Set&lt;DirectedLanePosition&gt;; all considered positions, each lane is considered separately
129      * @param stream StreamInterface; stream for random numbers
130      * @return GeneratorPositions; object to draw positions from
131      */
132     public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream)
133     {
134         return create(positions, stream, null, null);
135     }
136 
137     /**
138      * Create a GeneratorPositions object to draw positions from. The given positions are grouped per link. Each link receives a
139      * weight equal to the number of lanes.
140      * @param positions Set&lt;DirectedLanePosition&gt;; all considered positions, each lane is considered separately
141      * @param stream StreamInterface; stream for random numbers
142      * @param biases LaneBiases; lane biases for GTU types
143      * @return GeneratorPositions; object to draw positions from
144      */
145     public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream,
146             final LaneBiases biases)
147     {
148         return create(positions, stream, biases, null);
149     }
150 
151     /**
152      * Create a GeneratorPositions object to draw positions from. The given positions are grouped per link. Lanes are drawn
153      * without bias.
154      * @param positions Set&lt;DirectedLanePosition&gt;; all considered positions, each lane is considered separately
155      * @param stream StreamInterface; stream for random numbers
156      * @param linkWeights Map&lt;CrossSectionLink, Double&gt;; weight per link direction
157      * @return GeneratorPositions; object to draw positions from
158      */
159     public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream,
160             final Map<CrossSectionLink, Double> linkWeights)
161     {
162         return create(positions, stream, null, linkWeights);
163     }
164 
165     /**
166      * Create a GeneratorPositions object to draw positions from. The given positions are grouped per link.
167      * @param positions Set&lt;DirectedLanePosition&gt;; all considered positions, each lane is considered separately
168      * @param stream StreamInterface; stream for random numbers
169      * @param biases LaneBiases; lane biases for GTU types
170      * @param linkWeights Map&lt;CrossSectionLink, Double&gt;; weight per link direction
171      * @return GeneratorPositions; object to draw positions from
172      */
173     public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream,
174             final LaneBiases biases, final Map<CrossSectionLink, Double> linkWeights)
175     {
176 
177         // group directions per link
178         Map<LinkDirection, Set<DirectedLanePosition>> linkSplit = new LinkedHashMap<>();
179         for (DirectedLanePosition position : positions)
180         {
181             if (!linkSplit.containsKey(position.getLinkDirection()))
182             {
183                 linkSplit.put(position.getLinkDirection(), new LinkedHashSet<>());
184             }
185             linkSplit.get(position.getLinkDirection()).add(position);
186         }
187 
188         // create list of GeneratorLinkPositions
189         List<GeneratorLinkPosition> linkPositions = new ArrayList<>();
190         for (LinkDirection linkDirection : linkSplit.keySet())
191         {
192             List<Lane> lanes = ((CrossSectionLink) linkDirection.getLink()).getLanes();
193             // let's sort the lanes by lateral position
194             Collections.sort(lanes, new Comparator<Lane>()
195             {
196                 /** {@inheritDoc} */
197                 @Override
198                 public int compare(final Lane lane1, final Lane lane2)
199                 {
200                     Length lat1 = linkDirection.getDirection().isPlus() ? lane1.getDesignLineOffsetAtBegin()
201                             : lane1.getDesignLineOffsetAtEnd().neg();
202                     Length lat2 = linkDirection.getDirection().isPlus() ? lane2.getDesignLineOffsetAtBegin()
203                             : lane2.getDesignLineOffsetAtEnd().neg();
204                     return lat1.compareTo(lat2);
205                 }
206             });
207             // create list of GeneratorLanePositions
208             List<GeneratorLanePosition> lanePositions = new ArrayList<>();
209             for (DirectedLanePosition lanePosition : linkSplit.get(linkDirection))
210             {
211                 Set<DirectedLanePosition> set = new LinkedHashSet<>();
212                 set.add(lanePosition);
213                 lanePositions.add(new GeneratorLanePosition(lanes.indexOf(lanePosition.getLane()) + 1, set,
214                         (CrossSectionLink) linkDirection.getLink()));
215             }
216             // create the GeneratorLinkPosition
217             CrossSectionLink link = (CrossSectionLink) linkDirection.getLink();
218             if (linkWeights == null)
219             {
220                 linkPositions.add(new GeneratorLinkPosition(lanePositions, link));
221             }
222             else
223             {
224                 Double weight = linkWeights.get(link);
225                 Throw.whenNull(weight, "Using link weights for GTU generation, but no weight for link %s is defined.", link);
226                 linkPositions.add(new GeneratorLinkPosition(lanePositions, link, weight));
227             }
228         }
229 
230         // create the GeneratorZonePosition
231         return new GeneratorPositions(new GeneratorZonePosition(linkPositions), biases, stream);
232 
233     }
234 
235     /**
236      * Draw a new position to generate a GTU. The link is drawn by giving each link a weight equal to the number of accessible
237      * lanes for the GTU type. Next, a lane is drawn using (optionally biased) weights.
238      * @param gtuType GTUType; GTU type
239      * @param unplaced Map&lt;CrossSectionLink, Map&lt;Integer, Integer&gt;&gt;; number of unplaced GTUs per lane. The lane
240      *            number should match with {@code GeneratorLanePosition.getLaneNumber()}, where 1 is the right-most lane.
241      *            Missing lanes are assumed to have no queue.
242      * @param desiredSpeed Speed; desired speed, possibly used to determine the biased road position
243      * @param route Route; route, may be {@code null}
244      * @return GeneratorLanePosition; new position to generate a GTU
245      */
246     public GeneratorLanePosition draw(final GTUType gtuType, final Map<CrossSectionLink, Map<Integer, Integer>> unplaced,
247             final Speed desiredSpeed, final Route route)
248     {
249         return this.position.draw(gtuType, this.stream, this.biases, unplaced, desiredSpeed, route);
250     }
251 
252     /** {@inheritDoc} */
253     @Override
254     public DirectedPoint getLocation() throws RemoteException
255     {
256         return this.location;
257     }
258 
259     /** {@inheritDoc} */
260     @Override
261     public Bounds getBounds() throws RemoteException
262     {
263         return this.bounds;
264     }
265 
266     /**
267      * Returns all underlying positions.
268      * @return all underlying positions
269      */
270     public Set<GeneratorLanePosition> getAllPositions()
271     {
272         return this.allPositions;
273     }
274 
275     /**
276      * Returns the speed limit for the given GTU type, prior to the GTU position being determined.
277      * @param gtuType GTUType; GTU type
278      * @return speed limit for the given GTU type, prior to the GTU position being determined
279      */
280     public Speed speedLimit(final GTUType gtuType)
281     {
282         Speed speedLimit = null;
283         for (GeneratorLanePosition pos : this.allPositions)
284         {
285             for (DirectedLanePosition lane : pos.getPosition())
286             {
287                 try
288                 {
289                     Speed limit = lane.getLane().getSpeedLimit(gtuType);
290                     if (speedLimit == null || limit.lt(speedLimit))
291                     {
292                         speedLimit = limit;
293                     }
294                 }
295                 catch (NetworkException exception)
296                 {
297                     // ignore
298                 }
299             }
300         }
301         Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GTUType %s.",
302                 gtuType);
303         return speedLimit;
304     }
305 
306     /**
307      * Class representing a vehicle generation lane, providing elementary information for randomly drawing links and lanes.
308      * <p>
309      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
310      * <br>
311      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
312      * <p>
313      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 23 dec. 2017 <br>
314      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
315      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
316      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
317      */
318     public static final class GeneratorLanePosition
319     {
320 
321         /** Lane number, where 1 is the right-most lane. */
322         private final int laneNumber;
323 
324         /** Position set, representing a single GTU position on the network. */
325         private final Set<DirectedLanePosition> position;
326 
327         /** Link. */
328         private final CrossSectionLink link;
329 
330         /**
331          * Constructor.
332          * @param laneNumber int; lane number, where 1 is the right-most lane
333          * @param position Set&lt;DirectedLanePosition&gt;; position set, representing a single GTU position on the network
334          * @param link CrossSectionLink; link
335          */
336         GeneratorLanePosition(final int laneNumber, final Set<DirectedLanePosition> position, final CrossSectionLink link)
337         {
338             this.laneNumber = laneNumber;
339             this.position = position;
340             this.link = link;
341         }
342 
343         /**
344          * Returns the lane number, where 1 is the right-most lane.
345          * @return lane number, where 1 is the right-most lane
346          */
347         int getLaneNumber()
348         {
349             return this.laneNumber;
350         }
351 
352         /**
353          * Returns whether this lane is accessible to the GTU type.
354          * @param gtuType GTUType; gtu type
355          * @return boolean; whether this lane is accessible to the GTU type
356          */
357         boolean allows(final GTUType gtuType)
358         {
359             for (DirectedLanePosition pos : this.position)
360             {
361                 if (pos.getLane().getLaneType().isCompatible(gtuType, pos.getGtuDirection()))
362                 {
363                     return true;
364                 }
365             }
366             return false;
367         }
368 
369         /**
370          * Returns the contained position set, representing a single GTU position on the network.
371          * @return Set&lt;DirectedLanePosition&gt;; contained position set, representing a single GTU position on the network
372          */
373         Set<DirectedLanePosition> getPosition()
374         {
375             return this.position;
376         }
377 
378         /**
379          * Returns the link.
380          * @return CrossSectionLink; link
381          */
382         CrossSectionLink getLink()
383         {
384             return this.link;
385         }
386 
387         /**
388          * Returns the direction of travel.
389          * @return GTUDirectionality; direction of travel
390          */
391         GTUDirectionality getDirection()
392         {
393             return this.position.iterator().next().getGtuDirection();
394         }
395 
396         /** {@inheritDoc} */
397         @Override
398         public String toString()
399         {
400             return "GeneratorLanePosition [laneNumber=" + this.laneNumber + ", position=" + this.position + ", link="
401                     + this.link + "]";
402         }
403 
404     }
405 
406     /**
407      * Class representing a vehicle generation link to provide individual generation positions.
408      * <p>
409      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
410      * <br>
411      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
412      * <p>
413      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 23 dec. 2017 <br>
414      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
415      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
416      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
417      */
418     private static final class GeneratorLinkPosition
419     {
420 
421         /** Contained lanes. */
422         private final List<GeneratorLanePosition> positions;
423 
424         /** The link. */
425         private final CrossSectionLink link;
426 
427         /** Weight for drawing this link. */
428         private final double weight;
429 
430         /**
431          * Constructor.
432          * @param positions List&lt;GeneratorLanePosition&gt;; contained lanes
433          * @param link CrossSectionLink; the link
434          */
435         GeneratorLinkPosition(final List<GeneratorLanePosition> positions, final CrossSectionLink link)
436         {
437             this.positions = positions;
438             this.link = link;
439             this.weight = -1;
440         }
441 
442         /**
443          * Constructor.
444          * @param positions List&lt;GeneratorLanePosition&gt;; contained lanes
445          * @param link CrossSectionLink; the link
446          * @param weight double; weight for drawing this link
447          */
448         GeneratorLinkPosition(final List<GeneratorLanePosition> positions, final CrossSectionLink link, final double weight)
449         {
450             this.positions = positions;
451             this.link = link;
452             this.weight = weight;
453         }
454 
455         /**
456          * Return the link.
457          * @return CrossSectionLink; link
458          */
459         CrossSectionLink getLink()
460         {
461             return this.link;
462         }
463 
464         /**
465          * Returns the weight for this link. This is either a predefined weight, or the number of lanes for the GTU type.
466          * @param gtuType GTUType; GTU type
467          * @return double; weight for this link
468          */
469         double getWeight(final GTUType gtuType)
470         {
471             if (this.weight < 0.0)
472             {
473                 return getNumberOfLanes(gtuType);
474             }
475             return this.weight;
476         }
477 
478         /**
479          * Returns the number of accessible lanes for the GTU type.
480          * @param gtuType GTUType; GTU type
481          * @return int; number of accessible lanes for the GTU type
482          */
483         int getNumberOfLanes(final GTUType gtuType)
484         {
485             int numberOfLanes = 0;
486             for (GeneratorLanePosition lanePosition : this.positions)
487             {
488                 if (lanePosition.allows(gtuType))
489                 {
490                     numberOfLanes++;
491                 }
492             }
493             return numberOfLanes;
494         }
495 
496         /**
497          * Draws a specific GeneratorLanePosition utilizing lane biases of GTU types.
498          * @param gtuType GTUType; GTU type
499          * @param stream StreamInterface; stream for random numbers
500          * @param biases LaneBiases; biases for GTU types
501          * @param unplaced Map&lt;Integer, Integer&gt;; number of unplaced GTUs per lane. The lane number should match with
502          *            {@code GeneratorLanePosition.getLaneNumber()}, where 1 is the right-most lane. Missing lanes are assumed
503          *            to have no queue.
504          * @param desiredSpeed Speed; desired speed, possibly used to determine the biased road position
505          * @return GeneratorLanePosition; specific GeneratorLanePosition utilizing lane biases of GTU types
506          */
507         GeneratorLanePosition draw(final GTUType gtuType, final StreamInterface stream, final LaneBiases biases,
508                 final Map<Integer, Integer> unplaced, final Speed desiredSpeed)
509         {
510             Map<GeneratorLanePosition, Double> map = new LinkedHashMap<>();
511             // double[] cumulWeights = new double[this.positions.size()];
512             // double totalWeight = 0.0;
513             for (int i = 0; i < this.positions.size(); i++)
514             {
515                 GeneratorLanePosition lanePosition = this.positions.get(i);
516                 if (lanePosition.allows(gtuType))
517                 {
518                     GTUType type = gtuType;
519                     boolean found = false;
520                     while (biases != null && !found && type != null)
521                     {
522                         if (biases.contains(type))
523                         {
524                             found = true;
525                             int laneNum = lanePosition.getLaneNumber();
526                             int unplacedTemplates = unplaced == null ? 0 : unplaced.getOrDefault(laneNum, 0);
527                             double w = biases.getBias(type).calculateWeight(laneNum, getNumberOfLanes(gtuType),
528                                     unplacedTemplates, desiredSpeed);
529                             map.put(lanePosition, w);
530                             // totalWeight += w;
531                         }
532                         type = type.getParent();
533                     }
534                     if (!found)
535                     {
536                         map.put(lanePosition, 1.0);
537                         // totalWeight += 1.0; // no bias for this GTU type
538                     }
539                     // cumulWeights[i] = totalWeight;
540                 }
541             }
542             return Draw.drawWeighted(map, stream);
543             // double r = totalWeight * stream.nextDouble();
544             // for (int i = 0; i < this.positions.size(); i++)
545             // {
546             // if (r <= cumulWeights[i])
547             // {
548             // return this.positions.get(i);
549             // }
550             // }
551             // return this.positions.get(this.positions.size() - 1);
552         }
553 
554         /**
555          * Returns the direction of travel.
556          * @return GTUDirectionality; direction of travel
557          */
558         GTUDirectionality getDirection()
559         {
560             return this.positions.get(0).getDirection();
561         }
562 
563         /** {@inheritDoc} */
564         @Override
565         public String toString()
566         {
567             return "GeneratorLinkPosition [positions=" + this.positions + "]";
568         }
569 
570     }
571 
572     /**
573      * Class representing a vehicle generation zone to provide individual generation positions.
574      * <p>
575      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
576      * <br>
577      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
578      * <p>
579      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 23 dec. 2017 <br>
580      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
581      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
582      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
583      */
584     private static final class GeneratorZonePosition
585     {
586 
587         /** Contained links. */
588         private final List<GeneratorLinkPosition> positions;
589 
590         /**
591          * Constructor.
592          * @param positions List<GeneratorLinkPosition>; contained links
593          */
594         GeneratorZonePosition(final List<GeneratorLinkPosition> positions)
595         {
596             this.positions = positions;
597         }
598 
599         /**
600          * Draws a GeneratorLinkPosition using number of accessible lanes for the GTUType as weight, and a GeneratorLanePosition
601          * from that.
602          * @param gtuType GTUType; GTU type
603          * @param stream StreamInterface; stream for random numbers
604          * @param biases LaneBiases; biases for GTU types
605          * @param unplaced Map&lt;CrossSectionLink, Map&lt;Integer, Integer&gt;&gt;; number of unplaced GTUs per lane. The lane
606          *            number should match with {@code GeneratorLanePosition.getLaneNumber()}, where 1 is the right-most lane.
607          *            Missing lanes are assumed to have no queue.
608          * @param desiredSpeed Speed; desired speed, possibly used to determine the biased road position
609          * @param route Route; route, may be {@code null}
610          * @return GeneratorLanePosition; draws a LinkPosition using number of accessible lanes for the GTUType as weight, and a
611          *         GeneratorLanePosition from that
612          */
613         GeneratorLanePosition draw(final GTUType gtuType, final StreamInterface stream, final LaneBiases biases,
614                 final Map<CrossSectionLink, Map<Integer, Integer>> unplaced, final Speed desiredSpeed, final Route route)
615         {
616             Map<GeneratorLinkPosition, Double> map = new LinkedHashMap<>();
617             // double[] cumulWeights = new double[this.positions.size()];
618             // double totalWeight = 0.0;
619             for (int i = 0; i < this.positions.size(); i++)
620             {
621                 Link link = this.positions.get(i).getLink();
622                 GTUDirectionality direction = this.positions.get(i).getDirection();
623                 if (route != null)
624                 {
625                     int from = route.indexOf(direction.isPlus() ? link.getStartNode() : link.getEndNode());
626                     int to = route.indexOf(direction.isPlus() ? link.getEndNode() : link.getStartNode());
627                     if (from > -1 && to > -1 && to - from == 1)
628                     {
629                         map.put(this.positions.get(i), this.positions.get(i).getWeight(gtuType));
630                         // totalWeight += this.positions.get(i).getWeight(gtuType); // else, no weight
631                     }
632                 }
633                 else
634                 {
635                     map.put(this.positions.get(i), this.positions.get(i).getWeight(gtuType));
636                     // totalWeight += this.positions.get(i).getWeight(gtuType); // no route, consider all locations
637                 }
638                 // cumulWeights[i] = totalWeight;
639             }
640 
641             GeneratorLinkPosition linkPosition = Draw.drawWeighted(map, stream);
642             return linkPosition.draw(gtuType, stream, biases, unplaced.get(linkPosition.getLink()), desiredSpeed);
643 
644             // double r = totalWeight * stream.nextDouble();
645             // for (int i = 0; i < this.positions.size(); i++)
646             // {
647             // if (r <= cumulWeights[i])
648             // {
649             // GeneratorLinkPosition position = this.positions.get(i);
650             // return position.draw(gtuType, stream, biases, unplaced.get(position.getLink()), desiredSpeed);
651             // }
652             // }
653             // GeneratorLinkPosition position = this.positions.get(this.positions.size() - 1);
654             // return position.draw(gtuType, stream, biases, unplaced.get(position.getLink()), desiredSpeed);
655         }
656 
657         /** {@inheritDoc} */
658         @Override
659         public String toString()
660         {
661             return "GeneratorZonePosition [positions=" + this.positions + "]";
662         }
663 
664     }
665 
666     /**
667      * Set of lane biases per GTU type.
668      * <p>
669      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
670      * <br>
671      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
672      * <p>
673      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 24 dec. 2017 <br>
674      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
675      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
676      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
677      */
678     public static final class LaneBiases
679     {
680 
681         /** Biases per GTU type. */
682         private final Map<GTUType, LaneBias> biases = new HashMap<>();
683 
684         /**
685          * Adds a GTU bias for randomly drawing a lane.
686          * @param gtuType GTUType; gtu type
687          * @param bias LaneBias; bias
688          * @return LaneBiases; lane biases for method chaining
689          */
690         public LaneBiases addBias(final GTUType gtuType, final LaneBias bias)
691         {
692             Throw.whenNull(gtuType, "GTU type may not be null.");
693             Throw.whenNull(bias, "Bias may not be null.");
694             this.biases.put(gtuType, bias);
695             return this;
696         }
697 
698         /**
699          * Whether a bias is defined for the given type.
700          * @param gtuType GTUType; GTU type
701          * @return whether a bias is defined for the given type
702          */
703         public boolean contains(final GTUType gtuType)
704         {
705             return this.biases.containsKey(gtuType);
706         }
707 
708         /**
709          * Returns the bias of given GTU type, or {@code Bias.None} if none defined for the GTU type.
710          * @param gtuType GTUType; GTU type
711          * @return Bias; bias of the GTU type
712          */
713         public LaneBias getBias(final GTUType gtuType)
714         {
715             return this.biases.getOrDefault(gtuType, LaneBias.NONE);
716         }
717 
718         /** {@inheritDoc} */
719         @Override
720         public String toString()
721         {
722             return "LaneBiases [" + this.biases + "]";
723         }
724 
725     }
726 
727     /**
728      * Set of lane biases per GTU type enum, based on the GTU Types that are defined by default.
729      * <p>
730      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
731      * <br>
732      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
733      * <p>
734      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 24 dec. 2017 <br>
735      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
736      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
737      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
738      */
739     public static final class LaneBiasDefaults
740     {
741         /** Biases per GTU type. */
742         private final EnumMap<GTUType.DEFAULTS, LaneBias> biases = new EnumMap<>(GTUType.DEFAULTS.class);
743 
744         /**
745          * Adds a GTU bias for randomly drawing a lane.
746          * @param gtuEnum GTUType.DEFAULTS; gtu type
747          * @param bias LaneBias; bias
748          * @return LaneBiases; lane biases for method chaining
749          */
750         public LaneBiasDefaults addBias(final GTUType.DEFAULTS gtuEnum, final LaneBias bias)
751         {
752             Throw.whenNull(gtuEnum, "GTU type enum may not be null.");
753             Throw.whenNull(bias, "Bias may not be null.");
754             this.biases.put(gtuEnum, bias);
755             return this;
756         }
757 
758         /**
759          * Whether a bias is defined for the given type.
760          * @param gtuEnum GTUType; GTU type enum
761          * @return whether a bias is defined for the given type
762          */
763         public boolean contains(final GTUType.DEFAULTS gtuEnum)
764         {
765             return this.biases.containsKey(gtuEnum);
766         }
767 
768         /**
769          * Returns the bias of given GTU type, or {@code Bias.None} if none defined for the GTU type.
770          * @param gtuEnum GTUType.DEFAULTS; GTU type enum
771          * @return Bias; bias of the GTU type
772          */
773         public LaneBias getBias(final GTUType.DEFAULTS gtuEnum)
774         {
775             return this.biases.getOrDefault(gtuEnum, LaneBias.NONE);
776         }
777 
778         /** {@inheritDoc} */
779         @Override
780         public String toString()
781         {
782             return "LaneBiases [" + this.biases + "]";
783         }
784     }
785 
786     /**
787      * Vehicle generation lateral bias. Includes a lane maximum, e.g. trucks only on 2 right-hand lanes.
788      * <p>
789      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
790      * <br>
791      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
792      * <p>
793      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 22 dec. 2017 <br>
794      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
795      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
796      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
797      */
798     public static final class LaneBias
799     {
800 
801         /** No bias. */
802         public static final LaneBias NONE = new LaneBias(new ByValue(0.0), 0.0, Integer.MAX_VALUE);
803 
804         /** Weak left-hand bias, 2nd left lane contains 50% relative to left most lane, in free traffic. */
805         public static final LaneBias WEAK_LEFT = new LaneBias(new ByValue(1.0), 1.0, Integer.MAX_VALUE);
806 
807         /** Left-hand bias, 2nd left lane contains 25% relative to left most lane, in free traffic. */
808         public static final LaneBias LEFT = new LaneBias(new ByValue(1.0), 2.0, Integer.MAX_VALUE);
809 
810         /** Strong left-hand bias, 2nd left lane contains 3.125% relative to left most lane, in free traffic. */
811         public static final LaneBias STRONG_LEFT = new LaneBias(new ByValue(1.0), 5.0, Integer.MAX_VALUE);
812 
813         /** Weak middle bias, 2nd left lane contains 50% relative to left most lane, in free traffic. */
814         public static final LaneBias WEAK_MIDDLE = new LaneBias(new ByValue(0.5), 1.0, Integer.MAX_VALUE);
815 
816         /** Middle bias, 2nd left lane contains 25% relative to left most lane, in free traffic. */
817         public static final LaneBias MIDDLE = new LaneBias(new ByValue(0.5), 2.0, Integer.MAX_VALUE);
818 
819         /** Strong middle bias, 2nd left lane contains 3.125% relative to left most lane, in free traffic. */
820         public static final LaneBias STRONG_MIDDLE = new LaneBias(new ByValue(0.5), 5.0, Integer.MAX_VALUE);
821 
822         /** Weak right-hand bias, 2nd right lane contains 50% relative to right most lane, in free traffic. */
823         public static final LaneBias WEAK_RIGHT = new LaneBias(new ByValue(0.0), 1.0, Integer.MAX_VALUE);
824 
825         /** Right-hand bias, 2nd right lane contains 25% relative to right most lane, in free traffic. */
826         public static final LaneBias RIGHT = new LaneBias(new ByValue(0.0), 2.0, Integer.MAX_VALUE);
827 
828         /** Strong right-hand bias, 2nd right lane contains 3.125% relative to right most lane, in free traffic. */
829         public static final LaneBias STRONG_RIGHT = new LaneBias(new ByValue(0.0), 5.0, Integer.MAX_VALUE);
830 
831         /** Strong right-hand bias, limited to a maximum of 2 lanes. */
832         public static final LaneBias TRUCK_RIGHT = new LaneBias(new ByValue(0.0), 5.0, 2);
833 
834         /**
835          * Returns a bias by speed with normal extent.
836          * @param leftSpeed Speed; desired speed for full left bias
837          * @param rightSpeed Speed; desired speed for full right bias
838          * @return bias by speed with normal extent
839          */
840         public static LaneBias bySpeed(final Speed leftSpeed, final Speed rightSpeed)
841         {
842             return new LaneBias(new BySpeed(leftSpeed, rightSpeed), 2.0, Integer.MAX_VALUE);
843         }
844 
845         /**
846          * Returns a bias by speed with normal extent. Convenience km/h input.
847          * @param leftSpeedKm double; desired speed for full left bias
848          * @param rightSpeedKm double; desired speed for full right bias
849          * @return bias by speed with normal extent
850          */
851         public static LaneBias bySpeed(final double leftSpeedKm, final double rightSpeedKm)
852         {
853             return bySpeed(new Speed(leftSpeedKm, SpeedUnit.KM_PER_HOUR), new Speed(rightSpeedKm, SpeedUnit.KM_PER_HOUR));
854         }
855 
856         /** Provider of position on the road (0 = full left, 1 = full right). */
857         private final RoadPosition roadPosition;
858 
859         /** Bias extent. */
860         private final double bias;
861 
862         /** Number of lanes to consider in either direction, including the preferred lane. */
863         private final double stickyLanes;
864 
865         /**
866          * Constructor.
867          * @param roadPosition RoadPosition; lateral position on the road (0 = right, 0.5 = middle, 1 = left)
868          * @param bias double; bias extent, lower values create more spread traffic, 0.0 causes no lane preference
869          * @param stickyLanes double; number of lanes to consider in either direction, including the preferred lane
870          */
871         public LaneBias(final RoadPosition roadPosition, final double bias, final double stickyLanes)
872         {
873             Throw.when(bias < 0.0, IllegalArgumentException.class, "Bias should be positive or 0.");
874             Throw.when(stickyLanes < 1.0, IllegalArgumentException.class, "Sticky lanes should be 1.0 or larger.");
875             this.roadPosition = roadPosition;
876             this.bias = bias;
877             this.stickyLanes = stickyLanes;
878         }
879 
880         /**
881          * Returns a random draw weight for given lane. The weight is calculated as:
882          * 
883          * <pre>
884          * weight = { 0,                               d &gt;= number of sticky lanes
885          *          { 1 / ((d + 1)^bias * (m + 1)),    otherwise
886          * 
887          * where,
888          *      d:      lane deviation from lateral bias position
889          *      bias:   bias extent
890          *      m:      number of unplaced GTU's
891          * </pre>
892          * 
893          * The formula makes sure that all lanes have equal weight for <i>bias</i> &#61; 0, given an equal number of unplaced
894          * GTU's <i>m</i>. The bias can be seen to result in this: for each GTU on the 2nd lane, there are 2^(<i>bias</i> - 1)
895          * GTU's on the 1st lane. In numbers: 1 vs. 1 for <i>bias</i> &#61; 0, 1 vs. 2 for <i>bias</i> &#61; 1, 1 vs. 4 for
896          * <i>bias</i> &#61; 2, 1 vs. 8 for <i>bias</i> &#61; 3, etc.<br>
897          * <br>
898          * Division by <i>m</i> + 1 makes sure traffic distributes over the lanes in case of spillback, or otherwise too high
899          * demand on a particular lane. The weight for lanes with more unplaced GTU's simply reduces. This effect balances out
900          * with the bias, meaning that for a strong bias, GTU's are still likely to be generated on the biased lanes. Given a
901          * relatively strong bias of <i>bias</i> &#61; 5, the weight for the 1st and 2nd lane becomes equal if the 2nd lane has
902          * no unplaced GTU's, while the 1st lane has 31 unplaced GTU's.<br>
903          * <br>
904          * Lane deviation <i>d</i> is calculated as <i>d</i> &#61; abs(<i>latBiasLane</i> - <i>laneNumFromRight</i>). Here,
905          * <i>latBiasLane</i> &#61; 1 + <i>roadPosition</i>*(<i>numberOfLanes</i> - 1), i.e. ranging from 1 to 4 on a 4-lane
906          * road. For lanes that are beyond the number of sticky lanes, the weight is always 0.<br>
907          * <br>
908          * @param laneNumFromRight int; number of lane counted from right to left
909          * @param numberOfLanes int; total number of lanes
910          * @param numberOfUnplacedGTUs int; number of GTU's in the generation queue
911          * @param desiredSpeed Speed; desired speed, possibly used to determine the biased road position
912          * @return double; random draw weight for given lane
913          */
914         public double calculateWeight(final int laneNumFromRight, final int numberOfLanes, final int numberOfUnplacedGTUs,
915                 final Speed desiredSpeed)
916         {
917             double d = Math.abs((1.0 + this.roadPosition.getValue(desiredSpeed) * (numberOfLanes - 1.0)) - laneNumFromRight);
918             if (d >= this.stickyLanes)
919             {
920                 return 0.0;
921             }
922             return 1.0 / (Math.pow(d + 1.0, this.bias) * (numberOfUnplacedGTUs + 1.0));
923         }
924 
925         /** {@inheritDoc} */
926         @Override
927         public int hashCode()
928         {
929             final int prime = 31;
930             int result = 1;
931             long temp;
932             temp = Double.doubleToLongBits(this.bias);
933             result = prime * result + (int) (temp ^ (temp >>> 32));
934             result = prime * result + ((this.roadPosition == null) ? 0 : this.roadPosition.hashCode());
935             temp = Double.doubleToLongBits(this.stickyLanes);
936             result = prime * result + (int) (temp ^ (temp >>> 32));
937             return result;
938         }
939 
940         /** {@inheritDoc} */
941         @Override
942         public boolean equals(final Object obj)
943         {
944             if (this == obj)
945             {
946                 return true;
947             }
948             if (obj == null)
949             {
950                 return false;
951             }
952             if (getClass() != obj.getClass())
953             {
954                 return false;
955             }
956             LaneBias other = (LaneBias) obj;
957             if (Double.doubleToLongBits(this.bias) != Double.doubleToLongBits(other.bias))
958             {
959                 return false;
960             }
961             if (this.roadPosition == null)
962             {
963                 if (other.roadPosition != null)
964                 {
965                     return false;
966                 }
967             }
968             else if (!this.roadPosition.equals(other.roadPosition))
969             {
970                 return false;
971             }
972             if (Double.doubleToLongBits(this.stickyLanes) != Double.doubleToLongBits(other.stickyLanes))
973             {
974                 return false;
975             }
976             return true;
977         }
978 
979         /** {@inheritDoc} */
980         @Override
981         public String toString()
982         {
983             return "Bias [roadPosition=" + this.roadPosition + ", bias=" + this.bias + ", stickyLanes=" + this.stickyLanes
984                     + "]";
985         }
986 
987     }
988 
989     /**
990      * Interface for preferred road position for a lane bias.
991      * <p>
992      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
993      * <br>
994      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
995      * <p>
996      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 15 jan. 2018 <br>
997      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
998      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
999      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
1000      */
1001     public interface RoadPosition
1002     {
1003 
1004         /**
1005          * Returns the road position (0.0 = right, 1.0 = left).
1006          * @param desiredSpeed Speed; desired speed at the generator
1007          * @return road position (0.0 = right, 1.0 = left)
1008          */
1009         double getValue(Speed desiredSpeed);
1010 
1011         /**
1012          * Fixed road position.
1013          * <p>
1014          * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights
1015          * reserved. <br>
1016          * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
1017          * <p>
1018          * @version $Revision$, $LastChangedDate$, by $Author$, initial version 15 jan. 2018 <br>
1019          * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
1020          * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
1021          * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
1022          */
1023         public class ByValue implements RoadPosition
1024         {
1025 
1026             /** Road position. */
1027             private double value;
1028 
1029             /**
1030              * Constructor.
1031              * @param value double; road position
1032              */
1033             public ByValue(final double value)
1034             {
1035                 Throw.when(value < 0.0 || value > 1.0, IllegalArgumentException.class,
1036                         "Road position value should be in the range [0...1].");
1037                 this.value = value;
1038             }
1039 
1040             /** {@inheritDoc} */
1041             @Override
1042             public double getValue(final Speed desiredSpeed)
1043             {
1044                 return this.value;
1045             }
1046 
1047             /** {@inheritDoc} */
1048             @Override
1049             public int hashCode()
1050             {
1051                 final int prime = 31;
1052                 int result = 1;
1053                 long temp;
1054                 temp = Double.doubleToLongBits(this.value);
1055                 result = prime * result + (int) (temp ^ (temp >>> 32));
1056                 return result;
1057             }
1058 
1059             /** {@inheritDoc} */
1060             @Override
1061             public boolean equals(final Object obj)
1062             {
1063                 if (this == obj)
1064                 {
1065                     return true;
1066                 }
1067                 if (obj == null)
1068                 {
1069                     return false;
1070                 }
1071                 if (getClass() != obj.getClass())
1072                 {
1073                     return false;
1074                 }
1075                 ByValue other = (ByValue) obj;
1076                 if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value))
1077                 {
1078                     return false;
1079                 }
1080                 return true;
1081             }
1082 
1083         }
1084 
1085         /**
1086          * Road position based on desired speed.
1087          * <p>
1088          * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights
1089          * reserved. <br>
1090          * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
1091          * <p>
1092          * @version $Revision$, $LastChangedDate$, by $Author$, initial version 15 jan. 2018 <br>
1093          * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
1094          * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
1095          * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
1096          */
1097         public class BySpeed implements RoadPosition
1098         {
1099 
1100             /** Desired speed at left side of the road. */
1101             private Speed leftSpeed;
1102 
1103             /** Desired speed at the right side of the road. */
1104             private Speed rightSpeed;
1105 
1106             /**
1107              * Constructor.
1108              * @param leftSpeed Speed; desired speed at left side of the road
1109              * @param rightSpeed Speed; desired speed at right side of the road
1110              */
1111             public BySpeed(final Speed leftSpeed, final Speed rightSpeed)
1112             {
1113                 Throw.when(leftSpeed.eq(rightSpeed), IllegalArgumentException.class,
1114                         "Left speed and right speed may not be equal. Use LaneBias.NONE.");
1115                 this.leftSpeed = leftSpeed;
1116                 this.rightSpeed = rightSpeed;
1117             }
1118 
1119             /** {@inheritDoc} */
1120             @Override
1121             public double getValue(final Speed desiredSpeed)
1122             {
1123                 Throw.whenNull(desiredSpeed,
1124                         "Peeked desired speed from a strategical planner factory is null, while a lane bias depends on desired speed.");
1125                 double value = (desiredSpeed.si - this.rightSpeed.si) / (this.leftSpeed.si - this.rightSpeed.si);
1126                 return value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value);
1127             }
1128 
1129             /** {@inheritDoc} */
1130             @Override
1131             public int hashCode()
1132             {
1133                 final int prime = 31;
1134                 int result = 1;
1135                 result = prime * result + ((this.leftSpeed == null) ? 0 : this.leftSpeed.hashCode());
1136                 result = prime * result + ((this.rightSpeed == null) ? 0 : this.rightSpeed.hashCode());
1137                 return result;
1138             }
1139 
1140             /** {@inheritDoc} */
1141             @Override
1142             public boolean equals(final Object obj)
1143             {
1144                 if (this == obj)
1145                 {
1146                     return true;
1147                 }
1148                 if (obj == null)
1149                 {
1150                     return false;
1151                 }
1152                 if (getClass() != obj.getClass())
1153                 {
1154                     return false;
1155                 }
1156                 BySpeed other = (BySpeed) obj;
1157                 if (this.leftSpeed == null)
1158                 {
1159                     if (other.leftSpeed != null)
1160                     {
1161                         return false;
1162                     }
1163                 }
1164                 else if (!this.leftSpeed.equals(other.leftSpeed))
1165                 {
1166                     return false;
1167                 }
1168                 if (this.rightSpeed == null)
1169                 {
1170                     if (other.rightSpeed != null)
1171                     {
1172                         return false;
1173                     }
1174                 }
1175                 else if (!this.rightSpeed.equals(other.rightSpeed))
1176                 {
1177                     return false;
1178                 }
1179                 return true;
1180             }
1181 
1182         }
1183 
1184     }
1185 
1186 }