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