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.Node;
30 import org.opentrafficsim.core.network.route.Route;
31 import org.opentrafficsim.road.gtu.generator.GeneratorPositions.RoadPosition.BySpeed;
32 import org.opentrafficsim.road.gtu.generator.GeneratorPositions.RoadPosition.ByValue;
33 import org.opentrafficsim.road.gtu.strategical.route.RouteGeneratorOD;
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
44
45
46
47
48
49
50
51
52
53
54
55 public final class GeneratorPositions implements Locatable
56 {
57
58
59 private final GeneratorZonePosition position;
60
61
62 private final StreamInterface stream;
63
64
65 private final DirectedPoint location;
66
67
68 private final Bounds bounds;
69
70
71 private final Set<GeneratorLanePosition> allPositions = new LinkedHashSet<>();
72
73
74
75
76
77
78
79 @SuppressWarnings("synthetic-access")
80 private GeneratorPositions(final GeneratorZonePosition position, final LaneBiases biases, final StreamInterface stream)
81 {
82 this.position = position;
83 for (GeneratorLinkPosition glp : this.position.positions)
84 {
85 if (glp.getDirection().equals(GTUDirectionality.DIR_MINUS))
86 {
87 System.out.println("Hmm... GTUDirectionality is DIR_MINUS: " + glp);
88 }
89 }
90 this.stream = stream;
91 double x = 0.0;
92 double y = 0.0;
93 double xMin = Double.POSITIVE_INFINITY;
94 double xMax = Double.NEGATIVE_INFINITY;
95 double yMin = Double.POSITIVE_INFINITY;
96 double yMax = Double.NEGATIVE_INFINITY;
97 int n = 0;
98 for (GeneratorLinkPosition linkPosition : position.positions)
99 {
100 for (GeneratorLanePosition lanePosition : linkPosition.positions)
101 {
102 this.allPositions.add(lanePosition);
103 for (DirectedLanePosition pos : lanePosition.getPosition())
104 {
105 DirectedPoint point;
106 try
107 {
108 point = pos.getLane().getCenterLine().getLocation(pos.getPosition());
109 }
110 catch (OTSGeometryException exception)
111 {
112 point = new DirectedPoint(0, 0, 0);
113 }
114 x += point.x;
115 y += point.y;
116 xMin = xMin < point.x ? xMin : point.x;
117 yMin = yMin < point.y ? yMin : point.y;
118 xMax = xMax > point.x ? xMax : point.x;
119 yMax = yMax > point.y ? yMax : point.y;
120 n++;
121 }
122 }
123 }
124 this.location = new DirectedPoint(x / n, y / n, 0);
125 this.bounds = new BoundingBox(new Point3d(xMin, yMin, 0.0), new Point3d(xMax, yMax, 0.0));
126 }
127
128
129
130
131
132
133
134
135 public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream)
136 {
137 return create(positions, stream, null, null, null);
138 }
139
140
141
142
143
144
145
146
147
148 public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream,
149 final LaneBiases biases)
150 {
151 return create(positions, stream, biases, null, null);
152 }
153
154
155
156
157
158
159
160
161
162
163 public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream,
164 final Map<CrossSectionLink, Double> linkWeights, final Map<CrossSectionLink, Node> viaNodes)
165 {
166 return create(positions, stream, null, linkWeights, viaNodes);
167 }
168
169
170
171
172
173
174
175
176
177
178 public static GeneratorPositions create(final Set<DirectedLanePosition> positions, final StreamInterface stream,
179 final LaneBiases laneBiases, final Map<CrossSectionLink, Double> linkWeights,
180 final Map<CrossSectionLink, Node> viaNodes)
181 {
182
183
184 Map<LinkDirection, Set<DirectedLanePosition>> linkSplit = new LinkedHashMap<>();
185 for (DirectedLanePosition position : positions)
186 {
187 if (!linkSplit.containsKey(position.getLinkDirection()))
188 {
189 linkSplit.put(position.getLinkDirection(), new LinkedHashSet<>());
190 }
191 linkSplit.get(position.getLinkDirection()).add(position);
192 }
193
194
195 List<GeneratorLinkPosition> linkPositions = new ArrayList<>();
196 for (LinkDirection linkDirection : linkSplit.keySet())
197 {
198 List<Lane> lanes = ((CrossSectionLink) linkDirection.getLink()).getLanes();
199
200 Collections.sort(lanes, new Comparator<Lane>()
201 {
202
203 @Override
204 public int compare(final Lane/network/lane/Lane.html#Lane">Lane lane1, final Lane lane2)
205 {
206 Length lat1 = linkDirection.getDirection().isPlus() ? lane1.getDesignLineOffsetAtBegin() : lane1
207 .getDesignLineOffsetAtEnd().neg();
208 Length lat2 = linkDirection.getDirection().isPlus() ? lane2.getDesignLineOffsetAtBegin() : lane2
209 .getDesignLineOffsetAtEnd().neg();
210 return lat1.compareTo(lat2);
211 }
212 });
213
214 List<GeneratorLanePosition> lanePositions = new ArrayList<>();
215 for (DirectedLanePosition lanePosition : linkSplit.get(linkDirection))
216 {
217 Set<DirectedLanePosition> set = new LinkedHashSet<>();
218 set.add(lanePosition);
219 lanePositions.add(new GeneratorLanePosition(lanes.indexOf(lanePosition.getLane()) + 1, set,
220 (CrossSectionLink) linkDirection.getLink()));
221 }
222
223 CrossSectionLink/../../org/opentrafficsim/road/network/lane/CrossSectionLink.html#CrossSectionLink">CrossSectionLink link = (CrossSectionLink) linkDirection.getLink();
224 if (linkWeights == null)
225 {
226 linkPositions.add(new GeneratorLinkPosition(lanePositions, link, stream, laneBiases));
227 }
228 else
229 {
230 Double weight = linkWeights.get(link);
231 Throw.whenNull(weight, "Using link weights for GTU generation, but no weight for link %s is defined.", link);
232 linkPositions.add(new GeneratorLinkPosition(lanePositions, link, stream, laneBiases, weight, viaNodes.get(
233 link)));
234 }
235 }
236
237
238 return new GeneratorPositions(new GeneratorZonePosition(linkPositions), laneBiases, stream);
239
240 }
241
242
243
244
245
246
247
248
249
250 public GeneratorLinkPosition draw(final GTUType gtuType, final Node destination, final Route route)
251 {
252 return this.position.draw(gtuType, this.stream, destination, route);
253 }
254
255
256 @Override
257 public DirectedPoint getLocation() throws RemoteException
258 {
259 return this.location;
260 }
261
262
263 @Override
264 public Bounds getBounds() throws RemoteException
265 {
266 return this.bounds;
267 }
268
269
270
271
272
273 public Set<GeneratorLanePosition> getAllPositions()
274 {
275 return this.allPositions;
276 }
277
278
279
280
281
282
283 public Speed speedLimit(final GTUType gtuType)
284 {
285 Speed speedLimit = null;
286 for (GeneratorLanePosition pos : this.allPositions)
287 {
288 for (DirectedLanePosition lane : pos.getPosition())
289 {
290 try
291 {
292 Speed limit = lane.getLane().getSpeedLimit(gtuType);
293 if (speedLimit == null || limit.lt(speedLimit))
294 {
295 speedLimit = limit;
296 }
297 }
298 catch (NetworkException exception)
299 {
300
301 }
302 }
303 }
304 Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GTUType %s.",
305 gtuType);
306 return speedLimit;
307 }
308
309
310
311
312
313
314
315
316
317
318
319
320
321 public static final class GeneratorLanePosition
322 {
323
324
325 private final int laneNumber;
326
327
328 private final Set<DirectedLanePosition> position;
329
330
331 private final CrossSectionLink link;
332
333
334
335
336
337
338
339 GeneratorLanePosition(final int laneNumber, final Set<DirectedLanePosition> position, final CrossSectionLink link)
340 {
341 this.laneNumber = laneNumber;
342 this.position = position;
343 this.link = link;
344 }
345
346
347
348
349
350 int getLaneNumber()
351 {
352 return this.laneNumber;
353 }
354
355
356
357
358
359
360 boolean allows(final GTUType gtuType)
361 {
362 for (DirectedLanePosition pos : this.position)
363 {
364 if (pos.getLane().getLaneType().isCompatible(gtuType, pos.getGtuDirection()))
365 {
366 return true;
367 }
368 }
369 return false;
370 }
371
372
373
374
375
376 Set<DirectedLanePosition> getPosition()
377 {
378 return this.position;
379 }
380
381
382
383
384
385 CrossSectionLink getLink()
386 {
387 return this.link;
388 }
389
390
391
392
393
394 GTUDirectionality getDirection()
395 {
396 return this.position.iterator().next().getGtuDirection();
397 }
398
399
400 @Override
401 public String toString()
402 {
403 return "GeneratorLanePosition [laneNumber=" + this.laneNumber + ", position=" + this.position + ", link="
404 + this.link + "]";
405 }
406
407 }
408
409
410
411
412
413
414
415
416
417
418
419
420
421 public static final class GeneratorLinkPosition
422 {
423
424
425 private final List<GeneratorLanePosition> positions;
426
427
428 private final CrossSectionLink link;
429
430
431 private final StreamInterface stream;
432
433
434 private final LaneBiases laneBiases;
435
436
437 private final double weight;
438
439
440 private final Node viaNode;
441
442
443
444
445
446
447
448
449 GeneratorLinkPosition(final List<GeneratorLanePosition> positions, final CrossSectionLink link,
450 final StreamInterface stream, final LaneBiases laneBiases)
451 {
452 this.positions = positions;
453 this.link = link;
454 this.stream = stream;
455 this.laneBiases = laneBiases;
456 this.weight = -1;
457 this.viaNode = null;
458 }
459
460
461
462
463
464
465
466
467
468
469 GeneratorLinkPosition(final List<GeneratorLanePosition> positions, final CrossSectionLink link,
470 final StreamInterface stream, final LaneBiases laneBiases, final double weight, final Node viaNode)
471 {
472 this.positions = positions;
473 this.link = link;
474 this.stream = stream;
475 this.laneBiases = laneBiases;
476 this.weight = weight;
477 this.viaNode = viaNode;
478 }
479
480
481
482
483
484 CrossSectionLink getLink()
485 {
486 return this.link;
487 }
488
489
490
491
492
493
494 double getWeight(final GTUType gtuType)
495 {
496 if (this.weight < 0.0)
497 {
498 return getNumberOfLanes(gtuType);
499 }
500 return this.weight;
501 }
502
503
504
505
506
507 Node getViaNode()
508 {
509 return this.viaNode;
510 }
511
512
513
514
515
516
517 int getNumberOfLanes(final GTUType gtuType)
518 {
519 int numberOfLanes = 0;
520 for (GeneratorLanePosition lanePosition : this.positions)
521 {
522 if (lanePosition.allows(gtuType))
523 {
524 numberOfLanes++;
525 }
526 }
527 return numberOfLanes;
528 }
529
530
531
532
533
534
535
536
537
538
539 GeneratorLanePosition draw(final GTUType gtuType, final Map<Integer, Integer> unplaced, final Speed desiredSpeed)
540 {
541 Map<GeneratorLanePosition, Double> map = new LinkedHashMap<>();
542 for (int i = 0; i < this.positions.size(); i++)
543 {
544 GeneratorLanePosition lanePosition = this.positions.get(i);
545 if (lanePosition.allows(gtuType))
546 {
547 GTUType type = gtuType;
548 boolean found = false;
549 while (this.laneBiases != null && !found && type != null)
550 {
551 if (this.laneBiases.contains(type))
552 {
553 found = true;
554 int laneNum = lanePosition.getLaneNumber();
555 int unplacedTemplates = unplaced == null ? 0 : unplaced.getOrDefault(laneNum, 0);
556 double w = this.laneBiases.getBias(type).calculateWeight(laneNum, getNumberOfLanes(gtuType),
557 unplacedTemplates, desiredSpeed);
558 map.put(lanePosition, w);
559 }
560 type = type.getParent();
561 }
562 if (!found)
563 {
564 map.put(lanePosition, 1.0);
565 }
566 }
567 }
568 if (0 == map.size())
569 {
570 System.err.println("This really, really can't work...");
571 }
572 return Draw.drawWeighted(map, this.stream);
573 }
574
575
576
577
578
579 GTUDirectionality getDirection()
580 {
581 return this.positions.get(0).getDirection();
582 }
583
584
585 @Override
586 public String toString()
587 {
588 return "GeneratorLinkPosition [positions=" + this.positions + "]";
589 }
590
591
592
593
594
595 public Speed speedLimit(final GTUType gtuType)
596 {
597 Speed speedLimit = null;
598 for (GeneratorLanePosition pos : this.positions)
599 {
600 for (DirectedLanePosition lane : pos.getPosition())
601 {
602 try
603 {
604 Speed limit = lane.getLane().getSpeedLimit(gtuType);
605 if (speedLimit == null || limit.lt(speedLimit))
606 {
607 speedLimit = limit;
608 }
609 }
610 catch (NetworkException exception)
611 {
612
613 }
614 }
615 }
616 Throw.when(speedLimit == null, IllegalStateException.class, "No speed limit could be determined for GTUType %s.",
617 gtuType);
618 return speedLimit;
619 }
620
621 }
622
623
624
625
626
627
628
629
630
631
632
633
634
635 private static final class GeneratorZonePosition
636 {
637
638
639 private final List<GeneratorLinkPosition> positions;
640
641
642
643
644
645 GeneratorZonePosition(final List<GeneratorLinkPosition> positions)
646 {
647 this.positions = positions;
648 }
649
650
651
652
653
654
655
656
657
658
659
660 GeneratorLinkPosition draw(final GTUType gtuType, final StreamInterface stream, final Node destination,
661 final Route route)
662 {
663 Map<GeneratorLinkPosition, Double> map = new LinkedHashMap<>();
664 for (int i = 0; i < this.positions.size(); i++)
665 {
666 GeneratorLinkPosition glp = this.positions.get(i);
667 Link link = glp.getLink();
668 GTUDirectionality direction = glp.getDirection();
669 if (route != null)
670 {
671 int from = route.indexOf(direction.isPlus() ? link.getStartNode() : link.getEndNode());
672 int to = route.indexOf(direction.isPlus() ? link.getEndNode() : link.getStartNode());
673 if (from > -1 && to > -1 && to - from == 1)
674 {
675 map.put(glp, glp.getWeight(gtuType));
676 }
677 }
678 else
679 {
680
681 if (glp.getViaNode() != null)
682 {
683
684 Route r = RouteGeneratorOD.getDefaultRouteSupplier(stream).getRoute(glp.getViaNode(), destination,
685 gtuType);
686 if (r != null)
687 {
688 map.put(glp, glp.getWeight(gtuType));
689 }
690 }
691 else
692 {
693 map.put(glp, glp.getWeight(gtuType));
694 }
695 }
696 }
697 return Draw.drawWeighted(map, stream);
698 }
699
700
701 @Override
702 public String toString()
703 {
704 return "GeneratorZonePosition [positions=" + this.positions + "]";
705 }
706
707 }
708
709
710
711
712
713
714
715
716
717
718
719
720
721 public static final class LaneBiases
722 {
723
724
725 private final Map<GTUType, LaneBias> biases = new LinkedHashMap<>();
726
727
728
729
730
731
732
733 public LaneBiases addBias(final GTUType gtuType, final LaneBias bias)
734 {
735 Throw.whenNull(gtuType, "GTU type may not be null.");
736 Throw.whenNull(bias, "Bias may not be null.");
737 this.biases.put(gtuType, bias);
738 return this;
739 }
740
741
742
743
744
745
746 public boolean contains(final GTUType gtuType)
747 {
748 return this.biases.containsKey(gtuType);
749 }
750
751
752
753
754
755
756 public LaneBias getBias(final GTUType gtuType)
757 {
758 return this.biases.getOrDefault(gtuType, LaneBias.NONE);
759 }
760
761
762 @Override
763 public String toString()
764 {
765 return "LaneBiases [" + this.biases + "]";
766 }
767
768 }
769
770
771
772
773
774
775
776
777
778
779
780
781
782 public static final class LaneBiasDefaults
783 {
784
785 private final EnumMap<GTUType.DEFAULTS, LaneBias> biases = new EnumMap<>(GTUType.DEFAULTS.class);
786
787
788
789
790
791
792
793 public LaneBiasDefaults addBias(final GTUType.DEFAULTS gtuEnum, final LaneBias bias)
794 {
795 Throw.whenNull(gtuEnum, "GTU type enum may not be null.");
796 Throw.whenNull(bias, "Bias may not be null.");
797 this.biases.put(gtuEnum, bias);
798 return this;
799 }
800
801
802
803
804
805
806 public boolean contains(final GTUType.DEFAULTS gtuEnum)
807 {
808 return this.biases.containsKey(gtuEnum);
809 }
810
811
812
813
814
815
816 public LaneBias getBias(final GTUType.DEFAULTS gtuEnum)
817 {
818 return this.biases.getOrDefault(gtuEnum, LaneBias.NONE);
819 }
820
821
822 @Override
823 public String toString()
824 {
825 return "LaneBiases [" + this.biases + "]";
826 }
827 }
828
829
830
831
832
833
834
835
836
837
838
839
840
841 public static final class LaneBias
842 {
843
844
845 public static final LaneBias NONE = new LaneBias(new ByValue(0.0), 0.0, Integer.MAX_VALUE);
846
847
848 public static final LaneBias WEAK_LEFT = new LaneBias(new ByValue(1.0), 1.0, Integer.MAX_VALUE);
849
850
851 public static final LaneBias LEFT = new LaneBias(new ByValue(1.0), 2.0, Integer.MAX_VALUE);
852
853
854 public static final LaneBias STRONG_LEFT = new LaneBias(new ByValue(1.0), 5.0, Integer.MAX_VALUE);
855
856
857 public static final LaneBias WEAK_MIDDLE = new LaneBias(new ByValue(0.5), 1.0, Integer.MAX_VALUE);
858
859
860 public static final LaneBias MIDDLE = new LaneBias(new ByValue(0.5), 2.0, Integer.MAX_VALUE);
861
862
863 public static final LaneBias STRONG_MIDDLE = new LaneBias(new ByValue(0.5), 5.0, Integer.MAX_VALUE);
864
865
866 public static final LaneBias WEAK_RIGHT = new LaneBias(new ByValue(0.0), 1.0, Integer.MAX_VALUE);
867
868
869 public static final LaneBias RIGHT = new LaneBias(new ByValue(0.0), 2.0, Integer.MAX_VALUE);
870
871
872 public static final LaneBias STRONG_RIGHT = new LaneBias(new ByValue(0.0), 5.0, Integer.MAX_VALUE);
873
874
875 public static final LaneBias TRUCK_RIGHT = new LaneBias(new ByValue(0.0), 5.0, 2);
876
877
878
879
880
881
882
883 public static LaneBias bySpeed(final Speed leftSpeed, final Speed rightSpeed)
884 {
885 return new LaneBias(new BySpeed(leftSpeed, rightSpeed), 2.0, Integer.MAX_VALUE);
886 }
887
888
889
890
891
892
893
894 public static LaneBias bySpeed(final double leftSpeedKm, final double rightSpeedKm)
895 {
896 return bySpeed(new Speed(leftSpeedKm, SpeedUnit.KM_PER_HOUR), new Speed(rightSpeedKm, SpeedUnit.KM_PER_HOUR));
897 }
898
899
900 private final RoadPosition roadPosition;
901
902
903 private final double bias;
904
905
906 private final double stickyLanes;
907
908
909
910
911
912
913
914 public LaneBias(final RoadPosition roadPosition, final double bias, final double stickyLanes)
915 {
916 Throw.when(bias < 0.0, IllegalArgumentException.class, "Bias should be positive or 0.");
917 Throw.when(stickyLanes < 1.0, IllegalArgumentException.class, "Sticky lanes should be 1.0 or larger.");
918 this.roadPosition = roadPosition;
919 this.bias = bias;
920 this.stickyLanes = stickyLanes;
921 }
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957 public double calculateWeight(final int laneNumFromRight, final int numberOfLanes, final int numberOfUnplacedGTUs,
958 final Speed desiredSpeed)
959 {
960 double d = Math.abs((1.0 + this.roadPosition.getValue(desiredSpeed) * (numberOfLanes - 1.0)) - laneNumFromRight);
961 if (d >= this.stickyLanes)
962 {
963 return 0.0;
964 }
965 return 1.0 / (Math.pow(d + 1.0, this.bias) * (numberOfUnplacedGTUs + 1.0));
966 }
967
968
969 @Override
970 public int hashCode()
971 {
972 final int prime = 31;
973 int result = 1;
974 long temp;
975 temp = Double.doubleToLongBits(this.bias);
976 result = prime * result + (int) (temp ^ (temp >>> 32));
977 result = prime * result + ((this.roadPosition == null) ? 0 : this.roadPosition.hashCode());
978 temp = Double.doubleToLongBits(this.stickyLanes);
979 result = prime * result + (int) (temp ^ (temp >>> 32));
980 return result;
981 }
982
983
984 @Override
985 public boolean equals(final Object obj)
986 {
987 if (this == obj)
988 {
989 return true;
990 }
991 if (obj == null)
992 {
993 return false;
994 }
995 if (getClass() != obj.getClass())
996 {
997 return false;
998 }
999 LaneBias other = (LaneBias) obj;
1000 if (Double.doubleToLongBits(this.bias) != Double.doubleToLongBits(other.bias))
1001 {
1002 return false;
1003 }
1004 if (this.roadPosition == null)
1005 {
1006 if (other.roadPosition != null)
1007 {
1008 return false;
1009 }
1010 }
1011 else if (!this.roadPosition.equals(other.roadPosition))
1012 {
1013 return false;
1014 }
1015 if (Double.doubleToLongBits(this.stickyLanes) != Double.doubleToLongBits(other.stickyLanes))
1016 {
1017 return false;
1018 }
1019 return true;
1020 }
1021
1022
1023 @Override
1024 public String toString()
1025 {
1026 return "Bias [roadPosition=" + this.roadPosition + ", bias=" + this.bias + ", stickyLanes=" + this.stickyLanes
1027 + "]";
1028 }
1029
1030 }
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 public interface RoadPosition
1045 {
1046
1047
1048
1049
1050
1051
1052 double getValue(Speed desiredSpeed);
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066 public class ByValue implements RoadPosition
1067 {
1068
1069
1070 private double value;
1071
1072
1073
1074
1075
1076 public ByValue(final double value)
1077 {
1078 Throw.when(value < 0.0 || value > 1.0, IllegalArgumentException.class,
1079 "Road position value should be in the range [0...1].");
1080 this.value = value;
1081 }
1082
1083
1084 @Override
1085 public double getValue(final Speed desiredSpeed)
1086 {
1087 return this.value;
1088 }
1089
1090
1091 @Override
1092 public int hashCode()
1093 {
1094 final int prime = 31;
1095 int result = 1;
1096 long temp;
1097 temp = Double.doubleToLongBits(this.value);
1098 result = prime * result + (int) (temp ^ (temp >>> 32));
1099 return result;
1100 }
1101
1102
1103 @Override
1104 public boolean equals(final Object obj)
1105 {
1106 if (this == obj)
1107 {
1108 return true;
1109 }
1110 if (obj == null)
1111 {
1112 return false;
1113 }
1114 if (getClass() != obj.getClass())
1115 {
1116 return false;
1117 }
1118 ByValue other = (ByValue) obj;
1119 if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value))
1120 {
1121 return false;
1122 }
1123 return true;
1124 }
1125
1126 }
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140 class BySpeed implements RoadPosition
1141 {
1142
1143
1144 private Speed leftSpeed;
1145
1146
1147 private Speed rightSpeed;
1148
1149
1150
1151
1152
1153
1154 public BySpeed(final Speed leftSpeed, final Speed rightSpeed)
1155 {
1156 Throw.when(leftSpeed.eq(rightSpeed), IllegalArgumentException.class,
1157 "Left speed and right speed may not be equal. Use LaneBias.NONE.");
1158 this.leftSpeed = leftSpeed;
1159 this.rightSpeed = rightSpeed;
1160 }
1161
1162
1163 @Override
1164 public double getValue(final Speed desiredSpeed)
1165 {
1166 Throw.whenNull(desiredSpeed,
1167 "Peeked desired speed from a strategical planner factory is null, while a lane bias depends on desired speed.");
1168 double value = (desiredSpeed.si - this.rightSpeed.si) / (this.leftSpeed.si - this.rightSpeed.si);
1169 return value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value);
1170 }
1171
1172
1173 @Override
1174 public int hashCode()
1175 {
1176 final int prime = 31;
1177 int result = 1;
1178 result = prime * result + ((this.leftSpeed == null) ? 0 : this.leftSpeed.hashCode());
1179 result = prime * result + ((this.rightSpeed == null) ? 0 : this.rightSpeed.hashCode());
1180 return result;
1181 }
1182
1183
1184 @Override
1185 public boolean equals(final Object obj)
1186 {
1187 if (this == obj)
1188 {
1189 return true;
1190 }
1191 if (obj == null)
1192 {
1193 return false;
1194 }
1195 if (getClass() != obj.getClass())
1196 {
1197 return false;
1198 }
1199 BySpeed other = (BySpeed) obj;
1200 if (this.leftSpeed == null)
1201 {
1202 if (other.leftSpeed != null)
1203 {
1204 return false;
1205 }
1206 }
1207 else if (!this.leftSpeed.equals(other.leftSpeed))
1208 {
1209 return false;
1210 }
1211 if (this.rightSpeed == null)
1212 {
1213 if (other.rightSpeed != null)
1214 {
1215 return false;
1216 }
1217 }
1218 else if (!this.rightSpeed.equals(other.rightSpeed))
1219 {
1220 return false;
1221 }
1222 return true;
1223 }
1224
1225 }
1226
1227 }
1228
1229 }