1   package org.opentrafficsim.road.network.lane.conflict;
2   
3   import java.util.ArrayList;
4   import java.util.Iterator;
5   import java.util.LinkedHashMap;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.Set;
9   import java.util.SortedSet;
10  import java.util.TreeSet;
11  import java.util.concurrent.Executors;
12  import java.util.concurrent.ThreadPoolExecutor;
13  import java.util.concurrent.atomic.AtomicInteger;
14  
15  import org.djunits.value.vdouble.scalar.Length;
16  import org.djutils.exceptions.Throw;
17  import org.djutils.immutablecollections.ImmutableIterator;
18  import org.djutils.immutablecollections.ImmutableMap;
19  import org.djutils.immutablecollections.ImmutableMap.ImmutableEntry;
20  import org.opentrafficsim.core.geometry.OTSGeometryException;
21  import org.opentrafficsim.core.geometry.OTSLine3D;
22  import org.opentrafficsim.core.geometry.OTSPoint3D;
23  import org.opentrafficsim.core.gtu.GTUDirectionality;
24  import org.opentrafficsim.core.gtu.GTUType;
25  import org.opentrafficsim.core.network.Link;
26  import org.opentrafficsim.core.network.NetworkException;
27  import org.opentrafficsim.road.network.OTSRoadNetwork;
28  import org.opentrafficsim.road.network.lane.CrossSectionElement;
29  import org.opentrafficsim.road.network.lane.CrossSectionLink;
30  import org.opentrafficsim.road.network.lane.Lane;
31  import org.pmw.tinylog.Level;
32  
33  import nl.tudelft.simulation.dsol.logger.SimLogger;
34  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  public final class ConflictBuilder
48  {
49      
50      private static AtomicInteger numberMergeConflicts = new AtomicInteger(0);
51  
52      
53      private static AtomicInteger numberSplitConflicts = new AtomicInteger(0);
54  
55      
56      private static AtomicInteger numberCrossConflicts = new AtomicInteger(0);
57  
58      
59      public static final WidthGenerator DEFAULT_WIDTH_GENERATOR = new RelativeWidthGenerator(0.8);
60  
61      
62  
63  
64      private ConflictBuilder()
65      {
66          
67      }
68  
69      
70  
71  
72  
73  
74  
75  
76  
77      public static void buildConflicts(final OTSRoadNetwork network, final GTUType gtuType,
78              final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator)
79              throws OTSGeometryException
80      {
81          buildConflicts(network, gtuType, simulator, widthGenerator, new LaneCombinationListrk/lane/conflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList(), new LaneCombinationList());
82      }
83  
84      
85  
86  
87  
88  
89  
90  
91  
92  
93  
94      public static void buildConflicts(final OTSRoadNetwork network, final GTUType gtuType,
95              final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
96              final LaneCombinationListflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList ignoreList, final LaneCombinationList permittedList) throws OTSGeometryException
97      {
98          
99          ImmutableMap<String, Link> links = network.getLinkMap();
100         List<Lane> lanes = new ArrayList<>();
101         for (String linkId : links.keySet())
102         {
103             Link link = links.get(linkId);
104             if (link instanceof CrossSectionLink)
105             {
106                 for (CrossSectionElement element : ((CrossSectionLink) link).getCrossSectionElementList())
107                 {
108                     if (element instanceof Lane)
109                     {
110                         lanes.add((Lane) element);
111                     }
112                 }
113             }
114         }
115         buildConflicts(lanes, gtuType, simulator, widthGenerator, ignoreList, permittedList);
116     }
117 
118     
119 
120 
121 
122 
123 
124 
125 
126     public static void buildConflicts(final List<Lane> lanes, final GTUType gtuType,
127             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator)
128             throws OTSGeometryException
129     {
130         buildConflicts(lanes, gtuType, simulator, widthGenerator, new LaneCombinationListrk/lane/conflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList(), new LaneCombinationList());
131     }
132 
133     
134 
135 
136 
137 
138 
139 
140 
141 
142 
143     public static void buildConflicts(final List<Lane> lanes, final GTUType gtuType,
144             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
145             final LaneCombinationListflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList ignoreList, final LaneCombinationList permittedList) throws OTSGeometryException
146     {
147         
148         long totalCombinations = ((long) lanes.size()) * ((long) lanes.size() - 1) / 2;
149         SimLogger.always().debug("GENERATING CONFLICTS (NON-PARALLEL MODE). {} COMBINATIONS", totalCombinations);
150         long lastReported = 0;
151         Map<Lane, OTSLine3D> leftEdges = new LinkedHashMap<>();
152         Map<Lane, OTSLine3D> rightEdges = new LinkedHashMap<>();
153 
154         for (int i = 0; i < lanes.size(); i++)
155         {
156             long combinationsDone = totalCombinations - ((long) (lanes.size() - i)) * ((long) (lanes.size() - i)) / 2;
157             if (combinationsDone / 100000000 > lastReported)
158             {
159                 SimLogger.always()
160                         .debug(String.format(
161                                 "generating conflicts at %.0f%% (generated %d merge conflicts, %d split "
162                                         + "conflicts, %d crossing conflicts)",
163                                 100.0 * combinationsDone / totalCombinations, numberMergeConflicts.get(),
164                                 numberSplitConflicts.get(), numberCrossConflicts.get()));
165                 lastReported = combinationsDone / 100000000;
166             }
167             Lane lane1 = lanes.get(i);
168             for (GTUDirectionality dir1 : lane1.getLaneType().getDirectionality(gtuType).getDirectionalities())
169             {
170                 ImmutableMap<Lane, GTUDirectionality> down1 = lane1.downstreamLanes(dir1, gtuType);
171                 ImmutableMap<Lane, GTUDirectionality> up1 = lane1.upstreamLanes(dir1, gtuType);
172 
173                 for (int j = i + 1; j < lanes.size(); j++)
174                 {
175                     Lane lane2 = lanes.get(j);
176                     if (ignoreList.contains(lane1, lane2))
177                     {
178                         continue;
179                     }
180                     boolean permitted = permittedList.contains(lane1, lane2);
181 
182                     for (GTUDirectionality dir2 : lane2.getLaneType().getDirectionality(gtuType).getDirectionalities())
183                     {
184                         ImmutableMap<Lane, GTUDirectionality> down2 = lane2.downstreamLanes(dir2, gtuType);
185                         ImmutableMap<Lane, GTUDirectionality> up2 = lane2.upstreamLanes(dir2, gtuType);
186                         
187                         try
188                         {
189                             buildConflicts(lane1, dir1, down1, up1, lane2, dir2, down2, up2, gtuType, permitted, simulator,
190                                     widthGenerator, leftEdges, rightEdges, true);
191                         }
192                         catch (NetworkException ne)
193                         {
194                             throw new RuntimeException("Conflict build with bad combination of types / rules.", ne);
195                         }
196                     }
197                 }
198             }
199         }
200         SimLogger.always()
201                 .debug(String.format(
202                         "generating conflicts complete (generated %d merge conflicts, %d split "
203                                 + "conflicts, %d crossing conflicts)",
204                         numberMergeConflicts.get(), numberSplitConflicts.get(), numberCrossConflicts.get()));
205     }
206 
207     
208 
209 
210 
211 
212 
213 
214 
215 
216 
217 
218     @SuppressWarnings("checkstyle:parameternumber")
219     public static void buildConflicts(final Lane lane1, Lane_keyword">final GTUDirectionality dir1, final Lane lane2,
220             final GTUDirectionality dir2, final GTUType gtuType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
221             final WidthGenerator widthGenerator) throws OTSGeometryException
222     {
223         buildConflicts(lane1, dir1, lane2, dir2, gtuType, simulator, widthGenerator, false);
224     }
225 
226     
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238     @SuppressWarnings("checkstyle:parameternumber")
239     public static void buildConflicts(final Lane lane1, Lane_keyword">final GTUDirectionality dir1, final Lane lane2,
240             final GTUDirectionality dir2, final GTUType gtuType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
241             final WidthGenerator widthGenerator, final boolean permitted) throws OTSGeometryException
242     {
243         ImmutableMap<Lane, GTUDirectionality> down1 = lane1.downstreamLanes(dir1, gtuType);
244         ImmutableMap<Lane, GTUDirectionality> up1 = lane1.upstreamLanes(dir1, gtuType);
245         ImmutableMap<Lane, GTUDirectionality> down2 = lane2.downstreamLanes(dir2, gtuType);
246         ImmutableMap<Lane, GTUDirectionality> up2 = lane2.upstreamLanes(dir2, gtuType);
247         try
248         {
249             buildConflicts(lane1, dir1, down1, up1, lane2, dir2, down2, up2, gtuType, permitted, simulator, widthGenerator,
250                     new LinkedHashMap<>(), new LinkedHashMap<>(), true);
251         }
252         catch (NetworkException ne)
253         {
254             throw new RuntimeException("Conflict build with bad combination of types / rules.", ne);
255         }
256     }
257 
258     
259 
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 
270 
271 
272 
273 
274 
275 
276 
277 
278     @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:methodlength"})
279     static void buildConflicts(final Lane lane1, final GTUDirectionality dir1,
280             final ImmutableMap<Lane, GTUDirectionality> down1, final ImmutableMap<Lane, GTUDirectionality> up1,
281             final Lane lane2, final GTUDirectionality dir2, final ImmutableMap<Lane, GTUDirectionality> down2,
282             final ImmutableMap<Lane, GTUDirectionality> up2, final GTUType gtuType, final boolean permitted,
283             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
284             final Map<Lane, OTSLine3D> leftEdges, final Map<Lane, OTSLine3D> rightEdges, final boolean intersectionCheck)
285             throws OTSGeometryException, NetworkException
286     {
287         
288         if (intersectionCheck)
289         {
290             if (!lane1.getContour().intersects(lane2.getContour()))
291             {
292                 return;
293             }
294         }
295 
296         
297 
298         
299         OTSLine3D left1;
300         OTSLine3D right1;
301         synchronized (lane1)
302         {
303             left1 = leftEdges.get(lane1);
304             right1 = rightEdges.get(lane1);
305             OTSLine3D line1 = lane1.getCenterLine();
306             if (null == left1)
307             {
308                 left1 = line1.offsetLine(widthGenerator.getWidth(lane1, 0.0) / 2, widthGenerator.getWidth(lane1, 1.0) / 2);
309                 leftEdges.put(lane1, left1);
310             }
311             if (null == right1)
312             {
313                 right1 = line1.offsetLine(-widthGenerator.getWidth(lane1, 0.0) / 2, -widthGenerator.getWidth(lane1, 1.0) / 2);
314                 rightEdges.put(lane1, right1);
315             }
316         }
317 
318         OTSLine3D left2;
319         OTSLine3D right2;
320         synchronized (lane2)
321         {
322             left2 = leftEdges.get(lane2);
323             right2 = rightEdges.get(lane2);
324             OTSLine3D line2 = lane2.getCenterLine();
325             if (null == left2)
326             {
327                 left2 = line2.offsetLine(widthGenerator.getWidth(lane2, 0.0) / 2, widthGenerator.getWidth(lane2, 1.0) / 2);
328                 leftEdges.put(lane2, left2);
329             }
330             if (null == right2)
331             {
332                 right2 = line2.offsetLine(-widthGenerator.getWidth(lane2, 0.0) / 2, -widthGenerator.getWidth(lane2, 1.0) / 2);
333                 rightEdges.put(lane2, right2);
334             }
335         }
336 
337         
338         SortedSet<Intersection> intersections = Intersection.getIntersectionList(left1, left2, 0);
339         intersections.addAll(Intersection.getIntersectionList(left1, right2, 1));
340         intersections.addAll(Intersection.getIntersectionList(right1, left2, 2));
341         intersections.addAll(Intersection.getIntersectionList(right1, right2, 3));
342 
343         
344         ImmutableIterator<ImmutableEntry<Lane, GTUDirectionality>> iterator1 = down1.entrySet().iterator();
345         ImmutableIterator<ImmutableEntry<Lane, GTUDirectionality>> iterator2 = down2.entrySet().iterator();
346         boolean merge = false;
347         while (iterator1.hasNext() && !merge)
348         {
349             ImmutableEntry<Lane, GTUDirectionality> next1 = iterator1.next();
350             while (iterator2.hasNext() && !merge)
351             {
352                 ImmutableEntry<Lane, GTUDirectionality> next2 = iterator2.next();
353                 if (next1.equals(next2))
354                 {
355                     
356                     double fraction1 = Double.NaN;
357                     double fraction2 = Double.NaN;
358                     for (Intersection intersection : intersections)
359                     {
360                         
361                         if (intersection.getCombo() == 1 || intersection.getCombo() == 2)
362                         {
363                             fraction1 = intersection.getFraction1();
364                             fraction2 = intersection.getFraction2();
365                         }
366                     }
367                     
368                     Iterator<Intersection> iterator = intersections.iterator();
369                     while (iterator.hasNext())
370                     {
371                         if (iterator.next().getFraction1() >= fraction1)
372                         {
373                             iterator.remove();
374                         }
375                     }
376                     if (Double.isNaN(fraction1))
377                     {
378                         SimLogger.always().warn("Fixing fractions of merge conflict");
379                         fraction1 = 0;
380                         fraction2 = 0;
381                     }
382                     
383                     buildMergeConflict(lane1, dir1, fraction1, lane2, dir2, fraction2, gtuType, simulator, widthGenerator,
384                             permitted);
385                     
386                     merge = true;
387                 }
388             }
389         }
390 
391         
392         iterator1 = up1.entrySet().iterator();
393         iterator2 = up2.entrySet().iterator();
394         boolean split = false;
395         while (iterator1.hasNext() && !split)
396         {
397             ImmutableEntry<Lane, GTUDirectionality> prev1 = iterator1.next();
398             while (iterator2.hasNext() && !split)
399             {
400                 ImmutableEntry<Lane, GTUDirectionality> prev2 = iterator2.next();
401                 if (prev1.equals(prev2))
402                 {
403                     
404                     double fraction1 = Double.NaN;
405                     double fraction2 = Double.NaN;
406                     for (Intersection intersection : intersections)
407                     {
408                         
409                         if (intersection.getCombo() == 1 || intersection.getCombo() == 2)
410                         {
411                             fraction1 = intersection.getFraction1();
412                             fraction2 = intersection.getFraction2();
413                             break; 
414                         }
415                     }
416                     
417                     Iterator<Intersection> iterator = intersections.iterator();
418                     while (iterator.hasNext())
419                     {
420                         if (iterator.next().getFraction1() <= fraction1)
421                         {
422                             iterator.remove();
423                         }
424                         else
425                         {
426                             
427                             break;
428                         }
429                     }
430                     if (Double.isNaN(fraction1))
431                     {
432                         SimLogger.always().warn("Fixing fractions of split conflict");
433                         fraction1 = 1;
434                         fraction2 = 1;
435                     }
436                     
437                     buildSplitConflict(lane1, dir1, fraction1, lane2, dir2, fraction2, gtuType, simulator, widthGenerator);
438                     
439                     split = true;
440                 }
441             }
442         }
443 
444         
445         if (!lane1.getParentLink().equals(lane2.getParentLink())) 
446         {
447             boolean[] crossed = new boolean[4];
448             Iterator<Intersection> iterator = intersections.iterator();
449             double f1Start = Double.NaN;
450             double f2Start = Double.NaN;
451             double f2End = Double.NaN;
452             while (iterator.hasNext())
453             {
454                 Intersection intersection = iterator.next();
455                 
456                 if (Double.isNaN(f1Start))
457                 {
458                     f1Start = intersection.getFraction1();
459                 }
460                 f2Start = Double.isNaN(f2Start) ? intersection.getFraction2() : Math.min(f2Start, intersection.getFraction2());
461                 f2End = Double.isNaN(f2End) ? intersection.getFraction2() : Math.max(f2End, intersection.getFraction2());
462                 
463                 crossed[intersection.getCombo()] = !crossed[intersection.getCombo()];
464                 
465                 if ((crossed[0] && crossed[1] && crossed[2] && crossed[3])
466                         || (!crossed[0] && !crossed[1] && !crossed[2] && !crossed[3]))
467                 {
468                     if (dir2.isMinus())
469                     {
470                         double f2Temp = f2Start;
471                         f2Start = f2End;
472                         f2End = f2Temp;
473                     }
474                     if (Double.isNaN(f1Start) || Double.isNaN(f2Start) || Double.isNaN(f2End))
475                     {
476                         SimLogger.always().warn("NOT YET Fixing fractions of crossing conflict");
477                     }
478                     buildCrossingConflict(lane1, dir1, f1Start, intersection.getFraction1(), lane2, dir2, f2Start, f2End,
479                             gtuType, simulator, widthGenerator, permitted);
480                     f1Start = Double.NaN;
481                     f2Start = Double.NaN;
482                     f2End = Double.NaN;
483                 }
484             }
485         }
486 
487     }
488 
489     
490 
491 
492 
493 
494 
495 
496 
497 
498 
499 
500 
501 
502 
503 
504     @SuppressWarnings("checkstyle:parameternumber")
505     private static void buildMergeConflict(final Lane lane1, final GTUDirectionality dir1, final double f1start,
506             final Lane lane2, final GTUDirectionality dir2, final double f2start, final GTUType gtuType,
507             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator, final boolean permitted)
508             throws NetworkException, OTSGeometryException
509     {
510 
511         
512         double f1end = dir1.isPlus() ? 1.0 : 0.0;
513         double f2end = dir2.isPlus() ? 1.0 : 0.0;
514 
515         
516         Length longitudinalPosition1 = lane1.getLength().times(f1start);
517         Length longitudinalPosition2 = lane2.getLength().times(f2start);
518         Length length1 = lane1.getLength().times(Math.abs(f1end - f1start));
519         Length length2 = lane2.getLength().times(Math.abs(f2end - f2start));
520 
521         
522         OTSLine3D geometry1 = getGeometry(lane1, f1start, f1end, widthGenerator);
523         OTSLine3D geometry2 = getGeometry(lane2, f2start, f2end, widthGenerator);
524 
525         
526         ConflictRule conflictRule;
527         if (lane1.getParentLink().getPriority().isBusStop() || lane2.getParentLink().getPriority().isBusStop())
528         {
529             Throw.when(lane1.getParentLink().getPriority().isBusStop() && lane2.getParentLink().getPriority().isBusStop(),
530                     IllegalArgumentException.class, "Merge conflict between two links with bus stop priority not supported.");
531             conflictRule = new BusStopConflictRule(simulator);
532         }
533         else
534         {
535             conflictRule = new DefaultConflictRule();
536         }
537 
538         
539         Conflict.generateConflictPair(ConflictType.MERGE, conflictRule, permitted, lane1, longitudinalPosition1, length1, dir1,
540                 geometry1, gtuType, lane2, longitudinalPosition2, length2, dir2, geometry2, gtuType, simulator);
541 
542         numberMergeConflicts.incrementAndGet();
543     }
544 
545     
546 
547 
548 
549 
550 
551 
552 
553 
554 
555 
556 
557 
558 
559     @SuppressWarnings("checkstyle:parameternumber")
560     private static void buildSplitConflict(final Lane lane1, final GTUDirectionality dir1, finalLanetrong class="jxr_keyword">double f1end, final Lane lane2,
561             final GTUDirectionality dir2, final double f2end, final GTUType gtuType,
562             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator)
563             throws NetworkException, OTSGeometryException
564     {
565 
566         
567         double f1start = dir1.isPlus() ? 0.0 : 1.0;
568         double f2start = dir2.isPlus() ? 0.0 : 1.0;
569 
570         
571         Length longitudinalPosition1 = lane1.getLength().times(f1start);
572         Length longitudinalPosition2 = lane2.getLength().times(f2start);
573         Length length1 = lane1.getLength().times(Math.abs(f1end - f1start));
574         Length length2 = lane2.getLength().times(Math.abs(f2end - f2start));
575 
576         
577         OTSLine3D geometry1 = getGeometry(lane1, f1start, f1end, widthGenerator);
578         OTSLine3D geometry2 = getGeometry(lane2, f2start, f2end, widthGenerator);
579 
580         
581         Conflict.generateConflictPair(ConflictType.SPLIT, new SplitConflictRule(), false, lane1, longitudinalPosition1, length1,
582                 dir1, geometry1, gtuType, lane2, longitudinalPosition2, length2, dir2, geometry2, gtuType, simulator);
583 
584         numberSplitConflicts.incrementAndGet();
585     }
586 
587     
588 
589 
590 
591 
592 
593 
594 
595 
596 
597 
598 
599 
600 
601 
602 
603 
604     @SuppressWarnings("checkstyle:parameternumber")
605     private static void buildCrossingConflict(final Lane lane1, final GTUDirectionality dir1, final double f1start,
606             final double f1end, final Lane lane2, final GTUDirectionality dir2, final double f2start, final double f2end,
607             final GTUType gtuType, final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
608             final boolean permitted) throws NetworkException, OTSGeometryException
609     {
610 
611         
612         
613         double f1startDirected;
614         double f2startDirected;
615         if ((dir1.isPlus() && f1end < f1start) || (dir1.isMinus() && f1end > f1start))
616         {
617             f1startDirected = f1end;
618         }
619         else
620         {
621             f1startDirected = f1start;
622         }
623         if ((dir2.isPlus() && f2end < f2start) || (dir2.isMinus() && f2end > f2start))
624         {
625             f2startDirected = f2end;
626         }
627         else
628         {
629             f2startDirected = f2start;
630         }
631 
632         
633         Length longitudinalPosition1 = lane1.getLength().times(f1startDirected);
634         Length longitudinalPosition2 = lane2.getLength().times(f2startDirected);
635         Length length1 = lane1.getLength().times(Math.abs(f1end - f1start));
636         Length length2 = lane2.getLength().times(Math.abs(f2end - f2start));
637 
638         
639         OTSLine3D geometry1 = getGeometry(lane1, f1start, f1end, widthGenerator);
640         OTSLine3D geometry2 = getGeometry(lane2, f2start, f2end, widthGenerator);
641 
642         
643         ConflictRule conflictRule;
644         if (lane1.getParentLink().getPriority().isBusStop() || lane2.getParentLink().getPriority().isBusStop())
645         {
646             Throw.when(lane1.getParentLink().getPriority().isBusStop() && lane2.getParentLink().getPriority().isBusStop(),
647                     IllegalArgumentException.class, "Merge conflict between two links with bus stop priority not supported.");
648             conflictRule = new BusStopConflictRule(simulator);
649         }
650         else
651         {
652             conflictRule = new DefaultConflictRule();
653         }
654 
655         
656         Conflict.generateConflictPair(ConflictType.CROSSING, conflictRule, permitted, lane1, longitudinalPosition1, length1,
657                 dir1, geometry1, gtuType, lane2, longitudinalPosition2, length2, dir2, geometry2, gtuType, simulator);
658 
659         numberCrossConflicts.incrementAndGet();
660     }
661 
662     
663 
664 
665 
666 
667 
668 
669 
670 
671     private static OTSLine3D getGeometry(final Lane lane, final double fStart, final double fEnd,
672             final WidthGenerator widthGenerator) throws OTSGeometryException
673     {
674         
675         double f1;
676         double f2;
677         if (fEnd > fStart)
678         {
679             f1 = fStart;
680             f2 = fEnd;
681         }
682         else
683         {
684             f1 = fEnd;
685             f2 = fStart;
686         }
687         if (f1 == f2)
688         {
689             SimLogger.always().debug("f1 (" + f1 + ") equals f2 (" + f2 + "); problematic lane is " + lane.toString());
690             
691             if (f1 > 0)
692             {
693                 f1 = f1 - f1 / 1000;
694             }
695             else
696             {
697                 f2 = f2 + f2 / 1000;
698             }
699         }
700         OTSLine3D centerLine = lane.getCenterLine().extractFractional(f1, f2);
701         OTSLine3D left = centerLine.offsetLine(widthGenerator.getWidth(lane, f1) / 2, widthGenerator.getWidth(lane, f2) / 2);
702         OTSLine3D right =
703                 centerLine.offsetLine(-widthGenerator.getWidth(lane, f1) / 2, -widthGenerator.getWidth(lane, f2) / 2).reverse();
704         OTSPoint3D[] points = new OTSPoint3D[left.size() + right.size()];
705         System.arraycopy(left.getPoints(), 0, points, 0, left.size());
706         System.arraycopy(right.getPoints(), 0, points, left.size(), right.size());
707         return new OTSLine3D(points);
708     }
709 
710     
711 
712 
713 
714 
715 
716 
717 
718 
719 
720 
721 
722 
723     private static class Intersection implements Comparable<Intersection>
724     {
725 
726         
727         private final double fraction1;
728 
729         
730         private final double fraction2;
731 
732         
733         private final int combo;
734 
735         
736 
737 
738 
739 
740         Intersection(final double fraction1, final double fraction2, final int combo)
741         {
742             this.fraction1 = fraction1;
743             this.fraction2 = fraction2;
744             this.combo = combo;
745         }
746 
747         
748 
749 
750         public final double getFraction1()
751         {
752             return this.fraction1;
753         }
754 
755         
756 
757 
758         public final double getFraction2()
759         {
760             return this.fraction2;
761         }
762 
763         
764 
765 
766         public final int getCombo()
767         {
768             return this.combo;
769         }
770 
771         
772         @Override
773         public int compareTo(final Intersection o)
774         {
775             int out = Double.compare(this.fraction1, o.fraction1);
776             if (out != 0)
777             {
778                 return out;
779             }
780             out = Double.compare(this.fraction2, o.fraction2);
781             if (out != 0)
782             {
783                 return out;
784             }
785             return Integer.compare(this.combo, o.combo);
786         }
787 
788         
789         @Override
790         public int hashCode()
791         {
792             final int prime = 31;
793             int result = 1;
794             result = prime * result + this.combo;
795             long temp;
796             temp = Double.doubleToLongBits(this.fraction1);
797             result = prime * result + (int) (temp ^ (temp >>> 32));
798             temp = Double.doubleToLongBits(this.fraction2);
799             result = prime * result + (int) (temp ^ (temp >>> 32));
800             return result;
801         }
802 
803         
804         @Override
805         public boolean equals(final Object obj)
806         {
807             if (this == obj)
808             {
809                 return true;
810             }
811             if (obj == null)
812             {
813                 return false;
814             }
815             if (getClass() != obj.getClass())
816             {
817                 return false;
818             }
819             Intersection other = (Intersection) obj;
820             if (this.combo != other.combo)
821             {
822                 return false;
823             }
824             if (Double.doubleToLongBits(this.fraction1) != Double.doubleToLongBits(other.fraction1))
825             {
826                 return false;
827             }
828             if (Double.doubleToLongBits(this.fraction2) != Double.doubleToLongBits(other.fraction2))
829             {
830                 return false;
831             }
832             return true;
833         }
834 
835         
836 
837 
838 
839 
840 
841 
842 
843         public static SortedSet<Intersection> getIntersectionList(final OTSLine3D line1, final OTSLine3D line2, final int combo)
844                 throws OTSGeometryException
845         {
846             SortedSet<Intersection> out = new TreeSet<>();
847             
848             
849             
850             
851             double cumul1 = 0.0;
852             OTSPoint3D start1 = null;
853             OTSPoint3D end1 = line1.get(0);
854             for (int i = 0; i < line1.size() - 1; i++)
855             {
856                 start1 = end1;
857                 end1 = line1.get(i + 1);
858 
859                 double cumul2 = 0.0;
860                 OTSPoint3D start2 = null;
861                 OTSPoint3D end2 = line2.get(0);
862 
863                 for (int j = 0; j < line2.size() - 1; j++)
864                 {
865                     start2 = end2;
866                     end2 = line2.get(j + 1);
867 
868                     OTSPoint3D p = OTSPoint3D.intersectionOfLineSegments(start1, end1, start2, end2);
869                     if (p != null)
870                     {
871                         
872                         double dx = p.x - start1.x;
873                         double dy = p.y - start1.y;
874                         double length1 = cumul1 + Math.sqrt(dx * dx + dy * dy);
875                         dx = p.x - start2.x;
876                         dy = p.y - start2.y;
877                         double length2 = cumul2 + Math.sqrt(dx * dx + dy * dy);
878                         out.add(new Intersection(length1 / line1.getLengthSI(), length2 / line2.getLengthSI(), combo));
879                     }
880 
881                     double dx = end2.x - start2.x;
882                     double dy = end2.y - start2.y;
883                     cumul2 += Math.sqrt(dx * dx + dy * dy);
884                 }
885 
886                 double dx = end1.x - start1.x;
887                 double dy = end1.y - start1.y;
888                 cumul1 += Math.sqrt(dx * dx + dy * dy);
889             }
890 
891             return out;
892         }
893 
894         
895         @Override
896         public String toString()
897         {
898             return "Intersection [fraction1=" + this.fraction1 + ", fraction2=" + this.fraction2 + ", combo=" + this.combo
899                     + "]";
900         }
901 
902     }
903 
904     
905 
906 
907 
908 
909 
910 
911 
912 
913 
914 
915 
916     public interface WidthGenerator
917     {
918 
919         
920 
921 
922 
923 
924 
925         double getWidth(Lane lane, double fraction);
926 
927     }
928 
929     
930 
931 
932 
933 
934 
935 
936 
937 
938 
939 
940 
941     public static class FixedWidthGenerator implements WidthGenerator
942     {
943 
944         
945         private final double width;
946 
947         
948 
949 
950 
951         public FixedWidthGenerator(final Length width)
952         {
953             this.width = width.si;
954         }
955 
956         
957         @Override
958         public final double getWidth(final Lane lane, final double fraction)
959         {
960             return this.width;
961         }
962 
963         
964         @Override
965         public final String toString()
966         {
967             return "FixedWidthGenerator [width=" + this.width + "]";
968         }
969 
970     }
971 
972     
973 
974 
975 
976 
977 
978 
979 
980 
981 
982 
983 
984     public static class RelativeWidthGenerator implements WidthGenerator
985     {
986 
987         
988         private final double factor;
989 
990         
991 
992 
993 
994         public RelativeWidthGenerator(final double factor)
995         {
996             this.factor = factor;
997         }
998 
999         
1000         @Override
1001         public final double getWidth(final Lane lane, final double fraction)
1002         {
1003             return lane.getWidth(fraction).si * this.factor;
1004         }
1005 
1006         
1007         @Override
1008         public final String toString()
1009         {
1010             return "RelativeWidthGenerator [factor=" + this.factor + "]";
1011         }
1012 
1013     }
1014 
1015     
1016     
1017     
1018     
1019     
1020     
1021     
1022 
1023     
1024 
1025 
1026 
1027 
1028 
1029 
1030 
1031     public static void buildConflictsParallel(final OTSRoadNetwork network, final GTUType gtuType,
1032             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator)
1033             throws OTSGeometryException
1034     {
1035         buildConflictsParallel(network, gtuType, simulator, widthGenerator, new LaneCombinationList(),
1036                 new LaneCombinationList());
1037     }
1038 
1039     
1040 
1041 
1042 
1043 
1044 
1045 
1046 
1047 
1048 
1049     public static void buildConflictsParallel(final OTSRoadNetwork network, final GTUType gtuType,
1050             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
1051             final LaneCombinationListflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList ignoreList, final LaneCombinationList permittedList) throws OTSGeometryException
1052     {
1053         
1054         ImmutableMap<String, Link> links = network.getLinkMap();
1055         List<Lane> lanes = new ArrayList<>();
1056         for (String linkId : links.keySet())
1057         {
1058             Link link = links.get(linkId);
1059             if (link instanceof CrossSectionLink)
1060             {
1061                 for (CrossSectionElement element : ((CrossSectionLink) link).getCrossSectionElementList())
1062                 {
1063                     if (element instanceof Lane)
1064                     {
1065                         lanes.add((Lane) element);
1066                     }
1067                 }
1068             }
1069         }
1070         buildConflictsParallelBig(lanes, gtuType, simulator, widthGenerator, ignoreList, permittedList);
1071     }
1072 
1073     
1074 
1075 
1076 
1077 
1078 
1079 
1080 
1081     public static void buildConflictsParallel(final List<Lane> lanes, final GTUType gtuType,
1082             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator)
1083             throws OTSGeometryException
1084     {
1085         buildConflictsParallelBig(lanes, gtuType, simulator, widthGenerator, new LaneCombinationList(),
1086                 new LaneCombinationList());
1087     }
1088 
1089     
1090 
1091 
1092 
1093 
1094 
1095 
1096 
1097 
1098 
1099     public static void buildConflictsParallelSmall(final List<Lane> lanes, final GTUType gtuType,
1100             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
1101             final LaneCombinationListflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList ignoreList, final LaneCombinationList permittedList) throws OTSGeometryException
1102     {
1103         
1104         long totalCombinations = ((long) lanes.size()) * ((long) lanes.size() - 1) / 2;
1105         System.out.println("PARALLEL GENERATING OF CONFLICTS (SMALL JOBS). " + totalCombinations + " COMBINATIONS");
1106         long lastReported = 0;
1107         Map<Lane, OTSLine3D> leftEdges = new LinkedHashMap<>();
1108         Map<Lane, OTSLine3D> rightEdges = new LinkedHashMap<>();
1109 
1110         
1111         for (Lane lane : lanes)
1112         {
1113             lane.getContour().getEnvelope();
1114         }
1115 
1116         
1117         int cores = Runtime.getRuntime().availableProcessors();
1118         System.out.println("USING " + cores + " CORES");
1119         ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(cores);
1120         AtomicInteger numberOfJobs = new AtomicInteger(0);
1121         final int maxqueue = 2 * cores;
1122 
1123         for (int i = 0; i < lanes.size(); i++)
1124         {
1125             long combinationsDone = totalCombinations - ((long) (lanes.size() - i)) * ((long) (lanes.size() - i)) / 2;
1126             if (combinationsDone / 100000000 > lastReported)
1127             {
1128                 SimLogger.always()
1129                         .debug(String.format(
1130                                 "generating conflicts at %.0f%% (generated %d merge conflicts, %d split "
1131                                         + "conflicts, %d crossing conflicts)",
1132                                 100.0 * combinationsDone / totalCombinations, numberMergeConflicts.get(),
1133                                 numberSplitConflicts.get(), numberCrossConflicts.get()));
1134                 lastReported = combinationsDone / 100000000;
1135             }
1136             Lane lane1 = lanes.get(i);
1137             for (GTUDirectionality dir1 : lane1.getLaneType().getDirectionality(gtuType).getDirectionalities())
1138             {
1139                 ImmutableMap<Lane, GTUDirectionality> down1 = lane1.downstreamLanes(dir1, gtuType);
1140                 ImmutableMap<Lane, GTUDirectionality> up1 = lane1.upstreamLanes(dir1, gtuType);
1141 
1142                 for (int j = i + 1; j < lanes.size(); j++)
1143                 {
1144                     Lane lane2 = lanes.get(j);
1145                     if (ignoreList.contains(lane1, lane2))
1146                     {
1147                         continue;
1148                     }
1149                     
1150                     try
1151                     {
1152                         if (!lane1.getContour().intersects(lane2.getContour()))
1153                         {
1154                             continue;
1155                         }
1156                     }
1157                     catch (Exception e)
1158                     {
1159                         System.err.println("Contour problem - lane1 = [" + lane1.getFullId() + "], lane2 = ["
1160                                 + lane2.getFullId() + "]; skipped");
1161                         continue;
1162                     }
1163 
1164                     boolean permitted = permittedList.contains(lane1, lane2);
1165 
1166                     for (GTUDirectionality dir2 : lane2.getLaneType().getDirectionality(gtuType).getDirectionalities())
1167                     {
1168                         while (numberOfJobs.get() > maxqueue) 
1169                         {
1170                             try
1171                             {
1172                                 Thread.sleep(1);
1173                             }
1174                             catch (InterruptedException exception)
1175                             {
1176                                 
1177                             }
1178                         }
1179                         numberOfJobs.incrementAndGet();
1180                         ImmutableMap<Lane, GTUDirectionality> down2 = lane2.downstreamLanes(dir2, gtuType);
1181                         ImmutableMap<Lane, GTUDirectionality> up2 = lane2.upstreamLanes(dir2, gtuType);
1182                         ConflictBuilderRecordSmall cbr = new ConflictBuilderRecordSmall(lane1, dir1, down1, up1, lane2, dir2,
1183                                 down2, up2, gtuType, permitted, simulator, widthGenerator, leftEdges, rightEdges);
1184                         executor.execute(new CbrTaskSmall(numberOfJobs, cbr));
1185                     }
1186                 }
1187             }
1188         }
1189 
1190         long time = System.currentTimeMillis();
1191         
1192         while (numberOfJobs.get() > 0 && System.currentTimeMillis() - time < 60000)
1193         {
1194             try
1195             {
1196                 Thread.sleep(10);
1197             }
1198             catch (InterruptedException exception)
1199             {
1200                 
1201             }
1202         }
1203 
1204         executor.shutdown();
1205         while (!executor.isTerminated())
1206         {
1207             try
1208             {
1209                 Thread.sleep(1);
1210             }
1211             catch (InterruptedException exception)
1212             {
1213                 
1214             }
1215         }
1216 
1217         SimLogger.always()
1218                 .debug(String.format(
1219                         "generating conflicts complete (generated %d merge conflicts, %d split "
1220                                 + "conflicts, %d crossing conflicts)",
1221                         numberMergeConflicts.get(), numberSplitConflicts.get(), numberCrossConflicts.get()));
1222     }
1223 
1224     
1225 
1226 
1227 
1228 
1229 
1230 
1231 
1232 
1233 
1234     public static void buildConflictsParallelBig(final List<Lane> lanes, final GTUType gtuType,
1235             final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
1236             final LaneCombinationListflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList ignoreList, final LaneCombinationList permittedList) throws OTSGeometryException
1237     {
1238         
1239         long totalCombinations = ((long) lanes.size()) * ((long) lanes.size() - 1) / 2;
1240         System.out.println("PARALLEL GENERATING OF CONFLICTS (BIG JOBS). " + totalCombinations + " COMBINATIONS");
1241         long lastReported = 0;
1242         Map<Lane, OTSLine3D> leftEdges = new LinkedHashMap<>();
1243         Map<Lane, OTSLine3D> rightEdges = new LinkedHashMap<>();
1244 
1245         
1246         for (Lane lane : lanes)
1247         {
1248             lane.getContour().getEnvelope();
1249         }
1250 
1251         
1252         int cores = Runtime.getRuntime().availableProcessors();
1253         System.out.println("USING " + cores + " CORES");
1254         ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(cores);
1255         AtomicInteger numberOfJobs = new AtomicInteger(0);
1256         final int maxqueue = 200;
1257 
1258         for (int i = 0; i < lanes.size(); i++)
1259         {
1260             long combinationsDone = totalCombinations - ((long) (lanes.size() - i)) * ((long) (lanes.size() - i)) / 2;
1261             if (combinationsDone / 100000000 > lastReported)
1262             {
1263                 SimLogger.always()
1264                         .debug(String.format(
1265                                 "generating conflicts at %.0f%% (generated %d merge conflicts, %d split "
1266                                         + "conflicts, %d crossing conflicts)",
1267                                 100.0 * combinationsDone / totalCombinations, numberMergeConflicts.get(),
1268                                 numberSplitConflicts.get(), numberCrossConflicts.get()));
1269                 lastReported = combinationsDone / 100000000;
1270             }
1271             Lane lane1 = lanes.get(i);
1272             for (GTUDirectionality dir1 : lane1.getLaneType().getDirectionality(gtuType).getDirectionalities())
1273             {
1274                 ImmutableMap<Lane, GTUDirectionality> down1 = lane1.downstreamLanes(dir1, gtuType);
1275                 ImmutableMap<Lane, GTUDirectionality> up1 = lane1.upstreamLanes(dir1, gtuType);
1276 
1277                 while (numberOfJobs.get() > maxqueue) 
1278                 {
1279                     try
1280                     {
1281                         Thread.sleep(0, 10);
1282                     }
1283                     catch (InterruptedException exception)
1284                     {
1285                         
1286                     }
1287                 }
1288                 numberOfJobs.incrementAndGet();
1289 
1290                 ConflictBuilderRecordBig cbr = new ConflictBuilderRecordBig(i, lanes, ignoreList, permittedList, lane1, dir1,
1291                         down1, up1, gtuType, simulator, widthGenerator, leftEdges, rightEdges);
1292                 executor.execute(new CbrTaskBig(numberOfJobs, cbr));
1293 
1294             }
1295         }
1296 
1297         long time = System.currentTimeMillis();
1298         
1299         while (numberOfJobs.get() > 0 && System.currentTimeMillis() - time < 60000)
1300         {
1301             try
1302             {
1303                 Thread.sleep(10);
1304             }
1305             catch (InterruptedException exception)
1306             {
1307                 
1308             }
1309         }
1310 
1311         executor.shutdown();
1312         while (!executor.isTerminated())
1313         {
1314             try
1315             {
1316                 Thread.sleep(1);
1317             }
1318             catch (InterruptedException exception)
1319             {
1320                 
1321             }
1322         }
1323 
1324         SimLogger.always()
1325                 .debug(String.format(
1326                         "generating conflicts complete (generated %d merge conflicts, %d split "
1327                                 + "conflicts, %d crossing conflicts)",
1328                         numberMergeConflicts.get(), numberSplitConflicts.get(), numberCrossConflicts.get()));
1329     }
1330 
1331     
1332 
1333 
1334 
1335 
1336 
1337 
1338 
1339 
1340 
1341     public static void buildConflictsParallel(final OTSRoadNetwork network, final Map<String, Set<Link>> conflictCandidateMap,
1342             final GTUType gtuType, final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator)
1343             throws OTSGeometryException
1344     {
1345         for (String conflictId : conflictCandidateMap.keySet())
1346         {
1347             
1348             List<Lane> lanes = new ArrayList<>();
1349             for (Link link : conflictCandidateMap.get(conflictId))
1350             {
1351                 if (link instanceof CrossSectionLink)
1352                 {
1353                     for (CrossSectionElement element : ((CrossSectionLink) link).getCrossSectionElementList())
1354                     {
1355                         if (element instanceof Lane)
1356                         {
1357                             lanes.add((Lane) element);
1358                         }
1359                     }
1360                 }
1361             }
1362             
1363             SimLogger.setAllLogLevel(Level.WARNING);
1364             buildConflicts(lanes, gtuType, simulator, widthGenerator, new LaneCombinationListrk/lane/conflict/LaneCombinationList.html#LaneCombinationList">LaneCombinationList(), new LaneCombinationList());
1365             SimLogger.setAllLogLevel(Level.DEBUG);
1366         }
1367     }
1368 
1369     
1370     static class CbrTaskSmall implements Runnable
1371     {
1372         
1373         final ConflictBuilderRecordSmall cbr;
1374 
1375         
1376         final AtomicInteger nrOfJobs;
1377 
1378         
1379 
1380 
1381 
1382         CbrTaskSmall(final AtomicInteger nrOfJobs, final ConflictBuilderRecordSmall cbr)
1383         {
1384             this.nrOfJobs = nrOfJobs;
1385             this.cbr = cbr;
1386         }
1387 
1388         @Override
1389         public void run()
1390         {
1391             
1392             try
1393             {
1394                 buildConflictsSmall(this.cbr);
1395             }
1396             catch (Exception e)
1397             {
1398                 e.printStackTrace();
1399             }
1400             this.nrOfJobs.decrementAndGet();
1401         }
1402 
1403     }
1404 
1405     
1406 
1407 
1408 
1409     static void buildConflictsSmall(final ConflictBuilderRecordSmall cbr)
1410     {
1411         
1412         try
1413         {
1414             buildConflicts(cbr.lane1, cbr.dir1, cbr.down1, cbr.up1, cbr.lane2, cbr.dir2, cbr.down2, cbr.up2, cbr.gtuType,
1415                     cbr.permitted, cbr.simulator, cbr.widthGenerator, cbr.leftEdges, cbr.rightEdges, false);
1416         }
1417         catch (NetworkException | OTSGeometryException ne)
1418         {
1419             throw new RuntimeException("Conflict build with bad combination of types / rules.", ne);
1420         }
1421     }
1422 
1423     
1424     @SuppressWarnings("checkstyle:visibilitymodifier")
1425     static class ConflictBuilderRecordSmall
1426     {
1427         
1428         final Lane lane1;
1429 
1430         
1431         final GTUDirectionality dir1;
1432 
1433         
1434         final ImmutableMap<Lane, GTUDirectionality> down1;
1435 
1436         
1437         final ImmutableMap<Lane, GTUDirectionality> up1;
1438 
1439         
1440         final Lane lane2;
1441 
1442         
1443         final GTUDirectionality dir2;
1444 
1445         
1446         final ImmutableMap<Lane, GTUDirectionality> down2;
1447 
1448         
1449         final ImmutableMap<Lane, GTUDirectionality> up2;
1450 
1451         
1452         final GTUType gtuType;
1453 
1454         
1455         final boolean permitted;
1456 
1457         
1458         final DEVSSimulatorInterface.TimeDoubleUnit simulator;
1459 
1460         
1461         final WidthGenerator widthGenerator;
1462 
1463         
1464         final Map<Lane, OTSLine3D> leftEdges;
1465 
1466         
1467         final Map<Lane, OTSLine3D> rightEdges;
1468 
1469         
1470 
1471 
1472 
1473 
1474 
1475 
1476 
1477 
1478 
1479 
1480 
1481 
1482 
1483 
1484 
1485 
1486         @SuppressWarnings("checkstyle:parameternumber")
1487         ConflictBuilderRecordSmall(final Lane lane1, final GTUDirectionality dir1,
1488                 final ImmutableMap<Lane, GTUDirectionality> down1, final ImmutableMap<Lane, GTUDirectionality> up1,
1489                 final Lane lane2, final GTUDirectionality dir2, final ImmutableMap<Lane, GTUDirectionality> down2,
1490                 final ImmutableMap<Lane, GTUDirectionality> up2, final GTUType gtuType, final boolean permitted,
1491                 final DEVSSimulatorInterface.TimeDoubleUnit simulator, final WidthGenerator widthGenerator,
1492                 final Map<Lane, OTSLine3D> leftEdges, final Map<Lane, OTSLine3D> rightEdges)
1493         {
1494             this.lane1 = lane1;
1495             this.dir1 = dir1;
1496             this.down1 = down1;
1497             this.up1 = up1;
1498             this.lane2 = lane2;
1499             this.dir2 = dir2;
1500             this.down2 = down2;
1501             this.up2 = up2;
1502             this.gtuType = gtuType;
1503             this.permitted = permitted;
1504             this.simulator = simulator;
1505             this.widthGenerator = widthGenerator;
1506             this.leftEdges = leftEdges;
1507             this.rightEdges = rightEdges;
1508         }
1509     }
1510 
1511     
1512     static class CbrTaskBig implements Runnable
1513     {
1514         
1515         final ConflictBuilderRecordBig cbr;
1516 
1517         
1518         final AtomicInteger nrOfJobs;
1519 
1520         
1521 
1522 
1523 
1524         CbrTaskBig(final AtomicInteger nrOfJobs, final ConflictBuilderRecordBig cbr)
1525         {
1526             this.nrOfJobs = nrOfJobs;
1527             this.cbr = cbr;
1528         }
1529 
1530         @Override
1531         public void run()
1532         {
1533             
1534             try
1535             {
1536                 for (int j = this.cbr.starti + 1; j < this.cbr.lanes.size(); j++)
1537                 {
1538                     Lane lane2 = this.cbr.lanes.get(j);
1539                     if (this.cbr.ignoreList.contains(this.cbr.lane1, lane2))
1540                     {
1541                         continue;
1542                     }
1543                     
1544                     try
1545                     {
1546                         if (!this.cbr.lane1.getContour().intersects(lane2.getContour()))
1547                         {
1548                             continue;
1549                         }
1550                     }
1551                     catch (Exception e)
1552                     {
1553                         System.err.println("Contour problem - lane1 = [" + this.cbr.lane1.getFullId() + "], lane2 = ["
1554                                 + lane2.getFullId() + "]; skipped");
1555                         continue;
1556                     }
1557 
1558                     boolean permitted = this.cbr.permittedList.contains(this.cbr.lane1, lane2);
1559 
1560                     for (GTUDirectionality dir2 : lane2.getLaneType().getDirectionality(this.cbr.gtuType).getDirectionalities())
1561                     {
1562                         ImmutableMap<Lane, GTUDirectionality> down2 = lane2.downstreamLanes(dir2, this.cbr.gtuType);
1563                         ImmutableMap<Lane, GTUDirectionality> up2 = lane2.upstreamLanes(dir2, this.cbr.gtuType);
1564 
1565                         try
1566                         {
1567                             buildConflicts(this.cbr.lane1, this.cbr.dir1, this.cbr.down1, this.cbr.up1, lane2, dir2, down2, up2,
1568                                     this.cbr.gtuType, permitted, this.cbr.simulator, this.cbr.widthGenerator,
1569                                     this.cbr.leftEdges, this.cbr.rightEdges, false);
1570                         }
1571                         catch (NetworkException | OTSGeometryException ne)
1572                         {
1573                             SimLogger.always().error(ne, "Conflict build with bad combination of types / rules.");
1574                         }
1575                     }
1576                 }
1577 
1578             }
1579             catch (Exception e)
1580             {
1581                 e.printStackTrace();
1582             }
1583             this.nrOfJobs.decrementAndGet();
1584         }
1585     }
1586 
1587     
1588     @SuppressWarnings("checkstyle:visibilitymodifier")
1589     static class ConflictBuilderRecordBig
1590     {
1591         
1592         final int starti;
1593 
1594         
1595         final List<Lane> lanes;
1596 
1597         
1598         final LaneCombinationList ignoreList;
1599 
1600         
1601         final LaneCombinationList permittedList;
1602 
1603         
1604         final Lane lane1;
1605 
1606         
1607         final GTUDirectionality dir1;
1608 
1609         
1610         final ImmutableMap<Lane, GTUDirectionality> down1;
1611 
1612         
1613         final ImmutableMap<Lane, GTUDirectionality> up1;
1614 
1615         
1616         final GTUType gtuType;
1617 
1618         
1619         final DEVSSimulatorInterface.TimeDoubleUnit simulator;
1620 
1621         
1622         final WidthGenerator widthGenerator;
1623 
1624         
1625         final Map<Lane, OTSLine3D> leftEdges;
1626 
1627         
1628         final Map<Lane, OTSLine3D> rightEdges;
1629 
1630         
1631 
1632 
1633 
1634 
1635 
1636 
1637 
1638 
1639 
1640 
1641 
1642 
1643 
1644 
1645 
1646         @SuppressWarnings("checkstyle:parameternumber")
1647         ConflictBuilderRecordBig(final int starti, final List<Lane> lanes, final LaneCombinationList ignoreList,
1648                 final LaneCombinationList permittedList, final Lane lane1, final GTUDirectionality dir1,
1649                 final ImmutableMap<Lane, GTUDirectionality> down1, final ImmutableMap<Lane, GTUDirectionality> up1,
1650                 final GTUType gtuType, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
1651                 final WidthGenerator widthGenerator, final Map<Lane, OTSLine3D> leftEdges,
1652                 final Map<Lane, OTSLine3D> rightEdges)
1653         {
1654             this.starti = starti;
1655             this.lanes = lanes;
1656             this.ignoreList = ignoreList;
1657             this.permittedList = permittedList;
1658             this.lane1 = lane1;
1659             this.dir1 = dir1;
1660             this.down1 = down1;
1661             this.up1 = up1;
1662             this.gtuType = gtuType;
1663             this.simulator = simulator;
1664             this.widthGenerator = widthGenerator;
1665             this.leftEdges = leftEdges;
1666             this.rightEdges = rightEdges;
1667         }
1668     }
1669 
1670 }