1 package org.opentrafficsim.road.network.lane.conflict;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Map.Entry;
8 import java.util.SortedSet;
9 import java.util.TreeSet;
10
11 import org.djunits.value.vdouble.scalar.Length;
12 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
13 import org.opentrafficsim.core.geometry.OTSGeometryException;
14 import org.opentrafficsim.core.geometry.OTSLine3D;
15 import org.opentrafficsim.core.geometry.OTSPoint3D;
16 import org.opentrafficsim.core.gtu.GTUDirectionality;
17 import org.opentrafficsim.core.gtu.GTUType;
18 import org.opentrafficsim.core.network.Link;
19 import org.opentrafficsim.core.network.NetworkException;
20 import org.opentrafficsim.core.network.OTSNetwork;
21 import org.opentrafficsim.road.network.lane.CrossSectionElement;
22 import org.opentrafficsim.road.network.lane.CrossSectionLink;
23 import org.opentrafficsim.road.network.lane.CrossSectionLink.Priority;
24 import org.opentrafficsim.road.network.lane.Lane;
25
26 import nl.tudelft.simulation.immutablecollections.ImmutableMap;
27 import nl.tudelft.simulation.language.d3.DirectedPoint;
28
29
30
31
32
33
34
35
36
37
38
39
40 public final class ConflictBuilder
41 {
42
43
44 public static final DefaultWidthGenerator DEFAULT_WIDTH_GENERATOR = new DefaultWidthGenerator();
45
46
47
48
49 private ConflictBuilder()
50 {
51
52 }
53
54
55
56
57
58
59
60
61
62 public static void buildConflicts(final OTSNetwork network, final GTUType gtuType,
63 final OTSDEVSSimulatorInterface simulator, final WidthGenerator widthGenerator) throws OTSGeometryException
64 {
65 buildConflicts(network, gtuType, simulator, widthGenerator, new LaneCombinationList(), new LaneCombinationList());
66 }
67
68
69
70
71
72
73
74
75
76
77
78 public static void buildConflicts(final OTSNetwork network, final GTUType gtuType,
79 final OTSDEVSSimulatorInterface simulator, final WidthGenerator widthGenerator,
80 final LaneCombinationList ignoreList, final LaneCombinationList permittedList) throws OTSGeometryException
81 {
82
83 ImmutableMap<String, Link> links = network.getLinkMap();
84 List<Lane> lanes = new ArrayList<>();
85 for (String linkId : links.keySet())
86 {
87 Link link = links.get(linkId);
88 if (link instanceof CrossSectionLink)
89 {
90 for (CrossSectionElement element : ((CrossSectionLink) link).getCrossSectionElementList())
91 {
92 if (element instanceof Lane)
93 {
94 lanes.add((Lane) element);
95 }
96 }
97 }
98 }
99 buildConflicts(lanes, gtuType, simulator, widthGenerator, ignoreList, permittedList);
100 }
101
102
103
104
105
106
107
108
109
110 public static void buildConflicts(final List<Lane> lanes, final GTUType gtuType, final OTSDEVSSimulatorInterface simulator,
111 final WidthGenerator widthGenerator) throws OTSGeometryException
112 {
113 buildConflicts(lanes, gtuType, simulator, widthGenerator, new LaneCombinationList(), new LaneCombinationList());
114 }
115
116
117
118
119
120
121
122
123
124
125
126 public static void buildConflicts(final List<Lane> lanes, final GTUType gtuType, final OTSDEVSSimulatorInterface simulator,
127 final WidthGenerator widthGenerator, final LaneCombinationList ignoreList, final LaneCombinationList permittedList)
128 throws OTSGeometryException
129 {
130
131 for (int i = 0; i < lanes.size(); i++)
132 {
133 Lane lane1 = lanes.get(i);
134 GTUDirectionality[] dirs1;
135 if (lane1.getDirectionality(gtuType).isForward())
136 {
137 dirs1 = new GTUDirectionality[] { GTUDirectionality.DIR_PLUS };
138 }
139 else if (lane1.getDirectionality(gtuType).isBackward())
140 {
141 dirs1 = new GTUDirectionality[] { GTUDirectionality.DIR_MINUS };
142 }
143 else
144 {
145 dirs1 = new GTUDirectionality[] { GTUDirectionality.DIR_PLUS, GTUDirectionality.DIR_MINUS };
146 }
147 for (GTUDirectionality dir1 : dirs1)
148 {
149 Map<Lane, GTUDirectionality> down1 = lane1.downstreamLanes(dir1, gtuType);
150 Map<Lane, GTUDirectionality> up1 = lane1.upstreamLanes(dir1, gtuType);
151
152 for (int j = i + 1; j < lanes.size(); j++)
153 {
154
155 Lane lane2 = lanes.get(j);
156 if (ignoreList.contains(lane1, lane2))
157 {
158 continue;
159 }
160 boolean permitted = permittedList.contains(lane1, lane2);
161
162 GTUDirectionality[] dirs2;
163 if (lane2.getDirectionality(gtuType).isForward())
164 {
165 dirs2 = new GTUDirectionality[] { GTUDirectionality.DIR_PLUS };
166 }
167 else if (lane2.getDirectionality(gtuType).isBackward())
168 {
169 dirs2 = new GTUDirectionality[] { GTUDirectionality.DIR_MINUS };
170 }
171 else
172 {
173 dirs2 = new GTUDirectionality[] { GTUDirectionality.DIR_PLUS, GTUDirectionality.DIR_MINUS };
174 }
175 for (GTUDirectionality dir2 : dirs2)
176 {
177 Map<Lane, GTUDirectionality> down2 = lane2.downstreamLanes(dir2, gtuType);
178 Map<Lane, GTUDirectionality> up2 = lane2.upstreamLanes(dir2, gtuType);
179
180 try
181 {
182 buildConflicts(lane1, dir1, down1, up1, lane2, dir2, down2, up2, gtuType, permitted, simulator,
183 widthGenerator);
184 }
185 catch (NetworkException ne)
186 {
187 throw new RuntimeException("Conflict build with bad combination of types / rules.", ne);
188 }
189 }
190 }
191 }
192 }
193
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207 @SuppressWarnings("checkstyle:parameternumber")
208 public static void buildConflicts(final Lane lane1, final GTUDirectionality dir1, final Lane lane2,
209 final GTUDirectionality dir2, final GTUType gtuType, final OTSDEVSSimulatorInterface simulator,
210 final WidthGenerator widthGenerator) throws OTSGeometryException
211 {
212 buildConflicts(lane1, dir1, lane2, dir2, gtuType, simulator, widthGenerator, false);
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226
227 @SuppressWarnings("checkstyle:parameternumber")
228 public static void buildConflicts(final Lane lane1, final GTUDirectionality dir1, final Lane lane2,
229 final GTUDirectionality dir2, final GTUType gtuType, final OTSDEVSSimulatorInterface simulator,
230 final WidthGenerator widthGenerator, final boolean permitted) throws OTSGeometryException
231 {
232 Map<Lane, GTUDirectionality> down1 = lane1.downstreamLanes(dir1, gtuType);
233 Map<Lane, GTUDirectionality> up1 = lane1.upstreamLanes(dir1, gtuType);
234 Map<Lane, GTUDirectionality> down2 = lane2.downstreamLanes(dir2, gtuType);
235 Map<Lane, GTUDirectionality> up2 = lane2.upstreamLanes(dir2, gtuType);
236 try
237 {
238 buildConflicts(lane1, dir1, down1, up1, lane2, dir2, down2, up2, gtuType, permitted, simulator, widthGenerator);
239 }
240 catch (NetworkException ne)
241 {
242 throw new RuntimeException("Conflict build with bad combination of types / rules.", ne);
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263 @SuppressWarnings("checkstyle:parameternumber")
264 private static void buildConflicts(final Lane lane1, final GTUDirectionality dir1, final Map<Lane, GTUDirectionality> down1,
265 final Map<Lane, GTUDirectionality> up1, final Lane lane2, final GTUDirectionality dir2,
266 final Map<Lane, GTUDirectionality> down2, final Map<Lane, GTUDirectionality> up2, final GTUType gtuType,
267 final boolean permitted, final OTSDEVSSimulatorInterface simulator, final WidthGenerator widthGenerator)
268 throws OTSGeometryException, NetworkException
269 {
270
271
272
273
274 OTSLine3D line1 = lane1.getCenterLine();
275 OTSLine3D line2 = lane2.getCenterLine();
276 OTSLine3D left1 = line1.offsetLine(widthGenerator.getWidth(lane1, 0.0) / 2, widthGenerator.getWidth(lane1, 1.0) / 2);
277 OTSLine3D right1 = line1.offsetLine(-widthGenerator.getWidth(lane1, 0.0) / 2, -widthGenerator.getWidth(lane1, 1.0) / 2);
278 OTSLine3D left2 = line2.offsetLine(widthGenerator.getWidth(lane2, 0.0) / 2, widthGenerator.getWidth(lane2, 1.0) / 2);
279 OTSLine3D right2 = line2.offsetLine(-widthGenerator.getWidth(lane2, 0.0) / 2, -widthGenerator.getWidth(lane2, 1.0) / 2);
280
281
282 SortedSet<Intersection> intersections = Intersection.getIntersectionList(left1, left2, 0);
283 intersections.addAll(Intersection.getIntersectionList(left1, right2, 1));
284 intersections.addAll(Intersection.getIntersectionList(right1, left2, 2));
285 intersections.addAll(Intersection.getIntersectionList(right1, right2, 3));
286
287
288 Iterator<Entry<Lane, GTUDirectionality>> iterator1 = down1.entrySet().iterator();
289 Iterator<Entry<Lane, GTUDirectionality>> iterator2 = down2.entrySet().iterator();
290 boolean merge = false;
291 while (iterator1.hasNext() && !merge)
292 {
293 Entry<Lane, GTUDirectionality> next1 = iterator1.next();
294 while (iterator2.hasNext() && !merge)
295 {
296 Entry<Lane, GTUDirectionality> next2 = iterator2.next();
297 if (next1.equals(next2))
298 {
299
300 double fraction1 = Double.NaN;
301 double fraction2 = Double.NaN;
302 for (Intersection intersection : intersections)
303 {
304
305 if (intersection.getCombo() == 1 || intersection.getCombo() == 2)
306 {
307 fraction1 = intersection.getFraction1();
308 fraction2 = intersection.getFraction2();
309 }
310 }
311
312 Iterator<Intersection> iterator = intersections.iterator();
313 while (iterator.hasNext())
314 {
315 if (iterator.next().getFraction1() >= fraction1)
316 {
317 iterator.remove();
318 }
319 }
320
321 buildMergeConflict(lane1, dir1, fraction1, lane2, dir2, fraction2, gtuType, simulator, widthGenerator,
322 permitted);
323
324 merge = true;
325 }
326 }
327 }
328
329
330 iterator1 = up1.entrySet().iterator();
331 iterator2 = up2.entrySet().iterator();
332 boolean split = false;
333 while (iterator1.hasNext() && !split)
334 {
335 Entry<Lane, GTUDirectionality> prev1 = iterator1.next();
336 while (iterator2.hasNext() && !split)
337 {
338 Entry<Lane, GTUDirectionality> prev2 = iterator2.next();
339 if (prev1.equals(prev2))
340 {
341
342 double fraction1 = Double.NaN;
343 double fraction2 = Double.NaN;
344 for (Intersection intersection : intersections)
345 {
346
347 if (intersection.getCombo() == 1 || intersection.getCombo() == 2)
348 {
349 fraction1 = intersection.getFraction1();
350 fraction2 = intersection.getFraction2();
351 break;
352 }
353 }
354
355 Iterator<Intersection> iterator = intersections.iterator();
356 while (iterator.hasNext())
357 {
358 if (iterator.next().getFraction1() <= fraction1)
359 {
360 iterator.remove();
361 }
362 else
363 {
364
365 break;
366 }
367 }
368
369 buildSplitConflict(lane1, dir1, fraction1, lane2, dir2, fraction2, gtuType, simulator, widthGenerator);
370
371 split = true;
372 }
373 }
374 }
375
376
377 boolean[] crossed = new boolean[4];
378 Iterator<Intersection> iterator = intersections.iterator();
379 double f1Start = Double.NaN;
380 double f2Start = Double.NaN;
381 while (iterator.hasNext())
382 {
383 Intersection intersection = iterator.next();
384
385 if (Double.isNaN(f1Start))
386 {
387 f1Start = intersection.getFraction1();
388 f2Start = intersection.getFraction2();
389 }
390
391 crossed[intersection.getCombo()] = !crossed[intersection.getCombo()];
392
393 if ((crossed[0] && crossed[1] && crossed[2] && crossed[3])
394 || (!crossed[0] && !crossed[1] && !crossed[2] && !crossed[3]))
395 {
396 buildCrossingConflict(lane1, dir1, f1Start, intersection.getFraction1(), lane2, dir2, f2Start,
397 intersection.getFraction2(), gtuType, simulator, widthGenerator, permitted);
398 f1Start = Double.NaN;
399 f2Start = Double.NaN;
400 }
401 }
402
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 @SuppressWarnings("checkstyle:parameternumber")
421 private static void buildMergeConflict(final Lane lane1, final GTUDirectionality dir1, final double f1start,
422 final Lane lane2, final GTUDirectionality dir2, final double f2start, final GTUType gtuType,
423 final OTSDEVSSimulatorInterface simulator, final WidthGenerator widthGenerator, final boolean permitted)
424 throws NetworkException, OTSGeometryException
425 {
426
427
428 double f1end = dir1.isPlus() ? 1.0 : 0.0;
429 double f2end = dir2.isPlus() ? 1.0 : 0.0;
430
431
432 Length longitudinalPosition1 = lane1.getLength().multiplyBy(f1start);
433 Length longitudinalPosition2 = lane2.getLength().multiplyBy(f2start);
434 Length length1 = lane1.getLength().multiplyBy(Math.abs(f1end - f1start));
435 Length length2 = lane2.getLength().multiplyBy(Math.abs(f2end - f2start));
436
437
438 OTSLine3D geometry1 = getGeometry(lane1, f1start, f1end, widthGenerator);
439 OTSLine3D geometry2 = getGeometry(lane2, f2start, f2end, widthGenerator);
440
441
442 ConflictRule[] conflictRules =
443 getConflictRules(lane1, longitudinalPosition1, lane2, longitudinalPosition2, ConflictType.MERGE);
444
445
446 Conflict.generateConflictPair(ConflictType.MERGE, permitted, lane1, longitudinalPosition1, length1, dir1, geometry1,
447 conflictRules[0], gtuType, lane2, longitudinalPosition2, length2, dir2, geometry2, conflictRules[1], gtuType,
448 simulator);
449 }
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465 @SuppressWarnings("checkstyle:parameternumber")
466 private static void buildSplitConflict(final Lane lane1, final GTUDirectionality dir1, final double f1end, final Lane lane2,
467 final GTUDirectionality dir2, final double f2end, final GTUType gtuType, final OTSDEVSSimulatorInterface simulator,
468 final WidthGenerator widthGenerator) throws NetworkException, OTSGeometryException
469 {
470
471
472 double f1start = dir1.isPlus() ? 0.0 : 1.0;
473 double f2start = dir2.isPlus() ? 0.0 : 1.0;
474
475
476 Length longitudinalPosition1 = lane1.getLength().multiplyBy(f1start);
477 Length longitudinalPosition2 = lane2.getLength().multiplyBy(f2start);
478 Length length1 = lane1.getLength().multiplyBy(Math.abs(f1end - f1start));
479 Length length2 = lane2.getLength().multiplyBy(Math.abs(f2end - f2start));
480
481
482 OTSLine3D geometry1 = getGeometry(lane1, f1start, f1end, widthGenerator);
483 OTSLine3D geometry2 = getGeometry(lane2, f2start, f2end, widthGenerator);
484
485
486 Conflict.generateConflictPair(ConflictType.SPLIT, false, lane1, longitudinalPosition1, length1, dir1, geometry1,
487 ConflictRule.SPLIT, gtuType, lane2, longitudinalPosition2, length2, dir2, geometry2, ConflictRule.SPLIT,
488 gtuType, simulator);
489 }
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508 @SuppressWarnings("checkstyle:parameternumber")
509 private static void buildCrossingConflict(final Lane lane1, final GTUDirectionality dir1, final double f1start,
510 final double f1end, final Lane lane2, final GTUDirectionality dir2, final double f2start, final double f2end,
511 final GTUType gtuType, final OTSDEVSSimulatorInterface simulator, final WidthGenerator widthGenerator,
512 final boolean permitted) throws NetworkException, OTSGeometryException
513 {
514
515
516
517 double f1startDirected;
518 double f2startDirected;
519 if ((dir1.isPlus() && f1end < f1start) || (dir1.isMinus() && f1end > f1start))
520 {
521 f1startDirected = f1end;
522 }
523 else
524 {
525 f1startDirected = f1start;
526 }
527 if ((dir2.isPlus() && f2end < f2start) || (dir2.isMinus() && f2end > f2start))
528 {
529 f2startDirected = f2end;
530 }
531 else
532 {
533 f2startDirected = f2start;
534 }
535
536
537 Length longitudinalPosition1 = lane1.getLength().multiplyBy(f1startDirected);
538 Length longitudinalPosition2 = lane2.getLength().multiplyBy(f2startDirected);
539 Length length1 = lane1.getLength().multiplyBy(Math.abs(f1end - f1start));
540 Length length2 = lane2.getLength().multiplyBy(Math.abs(f2end - f2start));
541
542
543 OTSLine3D geometry1 = getGeometry(lane1, f1start, f1end, widthGenerator);
544 OTSLine3D geometry2 = getGeometry(lane2, f2start, f2end, widthGenerator);
545
546
547 ConflictRule[] conflictRules =
548 getConflictRules(lane1, longitudinalPosition1, lane2, longitudinalPosition2, ConflictType.CROSSING);
549
550
551 Conflict.generateConflictPair(ConflictType.CROSSING, permitted, lane1, longitudinalPosition1, length1, dir1, geometry1,
552 conflictRules[0], gtuType, lane2, longitudinalPosition2, length2, dir2, geometry2, conflictRules[1], gtuType,
553 simulator);
554 }
555
556
557
558
559
560
561
562
563
564
565 private static OTSLine3D getGeometry(final Lane lane, final double fStart, final double fEnd,
566 final WidthGenerator widthGenerator) throws OTSGeometryException
567 {
568
569 double f1;
570 double f2;
571 if (fEnd > fStart)
572 {
573 f1 = fStart;
574 f2 = fEnd;
575 }
576 else
577 {
578 f1 = fEnd;
579 f2 = fStart;
580 }
581 OTSLine3D centerLine = lane.getCenterLine().extractFractional(f1, f2);
582 OTSLine3D left = centerLine.offsetLine(widthGenerator.getWidth(lane, f1) / 2, widthGenerator.getWidth(lane, f2) / 2);
583 OTSLine3D right =
584 centerLine.offsetLine(-widthGenerator.getWidth(lane, f1) / 2, -widthGenerator.getWidth(lane, f2) / 2).reverse();
585 OTSPoint3D[] points = new OTSPoint3D[left.size() + right.size()];
586 System.arraycopy(left.getPoints(), 0, points, 0, left.size());
587 System.arraycopy(right.getPoints(), 0, points, left.size(), right.size());
588 return new OTSLine3D(points);
589 }
590
591
592
593
594
595
596
597
598
599
600
601 private static ConflictRule[] getConflictRules(final Lane lane1, final Length longitudinalPosition1, final Lane lane2,
602 final Length longitudinalPosition2, final ConflictType conflictType) throws OTSGeometryException
603 {
604
605 ConflictRule[] conflictRules = new ConflictRule[2];
606 Priority priority1 = lane1.getParentLink().getPriority();
607 Priority priority2 = lane2.getParentLink().getPriority();
608 if (conflictType.equals(ConflictType.SPLIT))
609 {
610 conflictRules[0] = ConflictRule.SPLIT;
611 conflictRules[1] = ConflictRule.SPLIT;
612 }
613 else if (priority1.isAllStop() && priority2.isAllStop())
614 {
615 conflictRules[0] = ConflictRule.ALL_STOP;
616 conflictRules[1] = ConflictRule.ALL_STOP;
617 }
618 else if (priority1.equals(priority2))
619 {
620
621 DirectedPoint p1 = lane1.getCenterLine().getLocation(longitudinalPosition1);
622 DirectedPoint p2 = lane2.getCenterLine().getLocation(longitudinalPosition2);
623 double diff = p2.getRotZ() - p1.getRotZ();
624 while (diff > Math.PI)
625 {
626 diff -= 2 * Math.PI;
627 }
628 while (diff < -Math.PI)
629 {
630 diff += 2 * Math.PI;
631 }
632 if (diff > 0.0)
633 {
634
635 conflictRules[0] = priority1.isStop() ? ConflictRule.STOP : ConflictRule.GIVE_WAY;
636 conflictRules[1] = ConflictRule.PRIORITY;
637 }
638 else
639 {
640
641 conflictRules[0] = ConflictRule.PRIORITY;
642 conflictRules[1] = priority2.isStop() ? ConflictRule.STOP : ConflictRule.GIVE_WAY;
643 }
644 }
645 else if (priority1.isPriority() && (priority2.isNone() || priority2.isStop()))
646 {
647 conflictRules[0] = ConflictRule.PRIORITY;
648 conflictRules[1] = priority2.isStop() ? ConflictRule.STOP : ConflictRule.GIVE_WAY;
649 }
650 else if (priority2.isPriority() && (priority1.isNone() || priority1.isStop()))
651 {
652 conflictRules[0] = priority1.isStop() ? ConflictRule.STOP : ConflictRule.GIVE_WAY;
653 conflictRules[1] = ConflictRule.PRIORITY;
654 }
655 else if (priority1.isNone() && priority2.isStop())
656 {
657 conflictRules[0] = ConflictRule.PRIORITY;
658 conflictRules[1] = ConflictRule.STOP;
659 }
660 else if (priority2.isNone() && priority1.isStop())
661 {
662 conflictRules[0] = ConflictRule.STOP;
663 conflictRules[1] = ConflictRule.PRIORITY;
664 }
665 else
666 {
667 throw new RuntimeException("Could not sort out priority from priorities " + priority1 + " and " + priority2);
668 }
669 return conflictRules;
670 }
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685 private static class Intersection implements Comparable<Intersection>
686 {
687
688
689 private final double fraction1;
690
691
692 private final double fraction2;
693
694
695 private final int combo;
696
697
698
699
700
701
702 Intersection(final double fraction1, final double fraction2, final int combo)
703 {
704 this.fraction1 = fraction1;
705 this.fraction2 = fraction2;
706 this.combo = combo;
707 }
708
709
710
711
712 public final double getFraction1()
713 {
714 return this.fraction1;
715 }
716
717
718
719
720 public final double getFraction2()
721 {
722 return this.fraction2;
723 }
724
725
726
727
728 public final int getCombo()
729 {
730 return this.combo;
731 }
732
733
734 @Override
735 public int compareTo(final Intersection o)
736 {
737 int out = Double.compare(this.fraction1, o.fraction1);
738 if (out != 0)
739 {
740 return out;
741 }
742 out = Double.compare(this.fraction2, o.fraction2);
743 if (out != 0)
744 {
745 return out;
746 }
747 return Integer.compare(this.combo, o.combo);
748 }
749
750
751 @Override
752 public int hashCode()
753 {
754 final int prime = 31;
755 int result = 1;
756 result = prime * result + this.combo;
757 long temp;
758 temp = Double.doubleToLongBits(this.fraction1);
759 result = prime * result + (int) (temp ^ (temp >>> 32));
760 temp = Double.doubleToLongBits(this.fraction2);
761 result = prime * result + (int) (temp ^ (temp >>> 32));
762 return result;
763 }
764
765
766 @Override
767 public boolean equals(final Object obj)
768 {
769 if (this == obj)
770 {
771 return true;
772 }
773 if (obj == null)
774 {
775 return false;
776 }
777 if (getClass() != obj.getClass())
778 {
779 return false;
780 }
781 Intersection other = (Intersection) obj;
782 if (this.combo != other.combo)
783 {
784 return false;
785 }
786 if (Double.doubleToLongBits(this.fraction1) != Double.doubleToLongBits(other.fraction1))
787 {
788 return false;
789 }
790 if (Double.doubleToLongBits(this.fraction2) != Double.doubleToLongBits(other.fraction2))
791 {
792 return false;
793 }
794 return true;
795 }
796
797
798
799
800
801
802
803
804
805 public static SortedSet<Intersection> getIntersectionList(final OTSLine3D line1, final OTSLine3D line2, final int combo)
806 throws OTSGeometryException
807 {
808 SortedSet<Intersection> out = new TreeSet<>();
809
810 double cumul1 = 0.0;
811 OTSPoint3D start1 = null;
812 OTSPoint3D end1 = line1.get(0);
813 for (int i = 0; i < line1.size() - 1; i++)
814 {
815 start1 = end1;
816 end1 = line1.get(i + 1);
817
818 double cumul2 = 0.0;
819 OTSPoint3D start2 = null;
820 OTSPoint3D end2 = line2.get(0);
821
822 for (int j = 0; j < line2.size() - 1; j++)
823 {
824 start2 = end2;
825 end2 = line2.get(j + 1);
826
827 OTSPoint3D p = OTSPoint3D.intersectionOfLineSegments(start1, end1, start2, end2);
828 if (p != null)
829 {
830
831 double dx = p.x - start1.x;
832 double dy = p.y - start1.y;
833 double length1 = cumul1 + Math.sqrt(dx * dx + dy * dy);
834 dx = p.x - start2.x;
835 dy = p.y - start2.y;
836 double length2 = cumul2 + Math.sqrt(dx * dx + dy * dy);
837 out.add(new Intersection(length1 / line1.getLengthSI(), length2 / line2.getLengthSI(), combo));
838 }
839
840 double dx = end2.x - start2.x;
841 double dy = end2.y - start2.y;
842 cumul2 += Math.sqrt(dx * dx + dy * dy);
843 }
844
845 double dx = end1.x - start1.x;
846 double dy = end1.y - start1.y;
847 cumul1 += Math.sqrt(dx * dx + dy * dy);
848 }
849
850 return out;
851 }
852
853
854 @Override
855 public String toString()
856 {
857 return "Intersection [fraction1=" + this.fraction1 + ", fraction2=" + this.fraction2 + ", combo=" + this.combo
858 + "]";
859 }
860
861 }
862
863
864
865
866
867
868
869
870
871
872
873
874
875 public interface WidthGenerator
876 {
877
878
879
880
881
882
883
884 default double getWidth(final Lane lane, final double fraction)
885 {
886 return lane.getWidth(fraction).si;
887 }
888
889 }
890
891
892
893
894
895
896
897
898
899
900
901
902
903 public static class DefaultWidthGenerator implements WidthGenerator
904 {
905
906 }
907
908
909
910
911
912
913
914
915
916
917
918
919
920 public static class FixedWidthGenerator implements WidthGenerator
921 {
922
923
924 private final double width;
925
926
927
928
929
930 public FixedWidthGenerator(final Length width)
931 {
932 this.width = width.si;
933 }
934
935
936 @Override
937 public final double getWidth(final Lane lane, final double fraction)
938 {
939 return this.width;
940 }
941
942 }
943
944
945
946
947
948
949
950
951
952
953
954
955
956 public static class RelativeWidthGenerator implements WidthGenerator
957 {
958
959
960 private final double factor;
961
962
963
964
965
966 public RelativeWidthGenerator(final double factor)
967 {
968 this.factor = factor;
969 }
970
971
972 @Override
973 public final double getWidth(final Lane lane, final double fraction)
974 {
975 return lane.getWidth(fraction).si * this.factor;
976 }
977
978 }
979
980 }