1 package org.opentrafficsim.trafficcontrol.trafcod;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import java.awt.Component;
6 import java.awt.Dimension;
7 import java.awt.Graphics2D;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.awt.image.BufferedImage;
11 import java.util.ArrayList;
12 import java.util.Comparator;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18
19 import javax.swing.BoxLayout;
20 import javax.swing.ImageIcon;
21 import javax.swing.JCheckBox;
22 import javax.swing.JFrame;
23 import javax.swing.JLabel;
24 import javax.swing.JPanel;
25 import javax.swing.JScrollPane;
26 import javax.swing.SwingUtilities;
27
28 import org.djutils.exceptions.Throw;
29 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLightException;
30 import org.opentrafficsim.trafficcontrol.TrafficController;
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class Diagram
45 {
46
47
48 final static int DIVIDER_1 = 0;
49
50
51 final static int CAR_ROUNDABOUT_LEFT = 1;
52
53
54 final static int PT_DIV_L = 3;
55
56
57 final static int DIVIDER_2 = 4;
58
59
60 final static int CAR_LEFT = 5;
61
62
63 final static int CAR_CENTER = 7;
64
65
66 final static int CAR_RIGHT = 9;
67
68
69 final static int DIVIDER_3 = 10;
70
71
72 final static int PT_RIGHT_BICYCLE = 11;
73
74
75 final static int DIVIDER_4 = 12;
76
77
78 final static int BICYCLE = 13;
79
80
81 final static int DIVIDER_5 = 14;
82
83
84 final static int PT_BICYCLE_SIDEWALK = 15;
85
86
87 final static int DIVIDER_6 = 16;
88
89
90 final static int SIDEWALK = 17;
91
92
93 final static int DIVIDER_7 = 18;
94
95
96 final static int PT_SIDEWALK_SHOULDER = 19;
97
98
99 final static int SHOULDER = 20;
100
101
102 final static int BOUNDARY = 21;
103
104
105 final List<Short> streams;
106
107
108 final Map<Short, XYPair[]> routes = new HashMap<>();
109
110
111
112
113
114
115 public Diagram(final Set<Short> streams) throws TrafficLightException
116 {
117 this.streams = new ArrayList<Short>(streams);
118 this.streams.sort(new Comparator<Short>()
119 {
120
121 @Override
122 public int compare(Short o1, Short o2)
123 {
124 return o1 - o2;
125 }
126 });
127
128
129
130
131
132
133
134
135
136 for (short stream = 1; stream <= 12; stream += 3)
137 {
138 int quadrant = (stream - 1) / 3;
139 this.routes.put(stream, rotateRoute(quadrant, assembleRoute(
140 new RouteStep(-BOUNDARY, CAR_RIGHT),
141 new RouteStep(-SHOULDER, CAR_RIGHT,Command.STOP_LINE_AND_ICON),
142 new RouteStep(-CAR_CENTER, CAR_RIGHT),
143 new RouteStep(-CAR_CENTER, BOUNDARY))));
144 this.routes.put((short) (stream + 1), rotateRoute(quadrant, assembleRoute(
145 new RouteStep(-BOUNDARY, CAR_CENTER),
146 new RouteStep(-SHOULDER, CAR_CENTER, Command.STOP_LINE_AND_ICON),
147 new RouteStep(Command.IF, stream + 1 + 60),
148 new RouteStep(-CAR_ROUNDABOUT_LEFT, CAR_CENTER),
149 new RouteStep(Command.ELSE),
150 new RouteStep(BOUNDARY, CAR_CENTER),
151 new RouteStep(Command.END_IF))));
152 this.routes.put((short) (stream + 2), rotateRoute(quadrant, assembleRoute(
153 new RouteStep(-BOUNDARY, CAR_LEFT),
154 new RouteStep(-SHOULDER, CAR_LEFT, Command.STOP_LINE_AND_ICON),
155 new RouteStep(Command.IF, stream + 2 + 60),
156 new RouteStep(-CAR_ROUNDABOUT_LEFT, CAR_LEFT),
157 new RouteStep(Command.ELSE_IF, (stream + 10) % 12 + 60),
158 new RouteStep(CAR_CENTER, CAR_LEFT),
159 new RouteStep(CAR_CENTER, CAR_ROUNDABOUT_LEFT),
160 new RouteStep(Command.ELSE),
161 new RouteStep(-CAR_LEFT, CAR_LEFT),
162 new RouteStep(-CAR_LEFT, PT_DIV_L),
163 new RouteStep(-CAR_ROUNDABOUT_LEFT, PT_DIV_L),
164 new RouteStep(-CAR_ROUNDABOUT_LEFT, -CAR_LEFT),
165 new RouteStep(PT_DIV_L, -CAR_LEFT),
166 new RouteStep(PT_DIV_L, -CAR_CENTER),
167 new RouteStep(CAR_CENTER, -CAR_CENTER),
168 new RouteStep(CAR_CENTER, -BOUNDARY),
169 new RouteStep(Command.END_IF))));
170 }
171
172 for (short stream = 21; stream <= 28; stream += 2)
173 {
174 int quadrant = (stream - 19) / 2 % 4;
175 this.routes.put(stream, rotateRoute(quadrant, assembleRoute(
176 new RouteStep(DIVIDER_1, BICYCLE, Command.ICON),
177 new RouteStep(SHOULDER, BICYCLE),
178 new RouteStep(BOUNDARY, BICYCLE, Command.ICON))));
179 this.routes.put((short) (stream + 1), rotateRoute(quadrant, assembleRoute(
180 new RouteStep(-BOUNDARY, BICYCLE),
181 new RouteStep(-DIVIDER_3, BICYCLE, Command.ICON),
182 new RouteStep(Command.IF, stream),
183 new RouteStep(-DIVIDER_1, BICYCLE, Command.ICON),
184 new RouteStep(Command.ELSE),
185 new RouteStep(SHOULDER, BICYCLE),
186 new RouteStep(BOUNDARY, BICYCLE, Command.ICON),
187 new RouteStep(Command.END_IF))));
188 }
189
190 for (short stream = 31; stream <= 38; stream += 2)
191 {
192 int quadrant = (stream - 29) / 2 % 4;
193 this.routes.put(stream, rotateRoute(quadrant, assembleRoute(
194 new RouteStep(DIVIDER_1, SIDEWALK),
195 new RouteStep(BOUNDARY, SIDEWALK))));
196 this.routes.put((short) (stream + 1), rotateRoute(quadrant, assembleRoute(
197 new RouteStep(-BOUNDARY, SIDEWALK),
198 new RouteStep(Command.IF, stream),
199 new RouteStep(-DIVIDER_1, SIDEWALK),
200 new RouteStep(Command.ELSE),
201 new RouteStep(BOUNDARY, SIDEWALK),
202 new RouteStep(Command.END_IF))));
203 }
204
205 for (short stream = 41; stream <= 52; stream += 3)
206 {
207 int quadrant = (stream - 41) / 3;
208 this.routes.put(stream, rotateRoute(quadrant, assembleRoute(
209 new RouteStep(-BOUNDARY, PT_DIV_L),
210 new RouteStep(-SHOULDER, PT_DIV_L, Command.STOP_LINE),
211 new RouteStep(-PT_SIDEWALK_SHOULDER, PT_DIV_L, Command.ICON),
212 new RouteStep(-CAR_RIGHT, PT_DIV_L),
213 new RouteStep(-CAR_RIGHT, CAR_LEFT),
214 new RouteStep(-PT_DIV_L, CAR_LEFT),
215 new RouteStep(-PT_DIV_L, SHOULDER),
216 new RouteStep(-PT_DIV_L, BOUNDARY, Command.ICON))));
217 this.routes.put((short) (stream + 1), rotateRoute(quadrant, assembleRoute(
218 new RouteStep(-BOUNDARY, PT_DIV_L),
219 new RouteStep(-SHOULDER, PT_DIV_L, Command.STOP_LINE),
220 new RouteStep(-PT_SIDEWALK_SHOULDER, PT_DIV_L, Command.ICON),
221 new RouteStep(SHOULDER, PT_DIV_L),
222 new RouteStep(BOUNDARY, PT_DIV_L))));
223 this.routes.put((short) (stream + 2), rotateRoute(quadrant, assembleRoute(
224 new RouteStep(-BOUNDARY, PT_DIV_L),
225 new RouteStep(-SHOULDER, PT_DIV_L, Command.STOP_LINE),
226 new RouteStep(-PT_SIDEWALK_SHOULDER, PT_DIV_L, Command.ICON),
227 new RouteStep(-CAR_RIGHT, PT_DIV_L),
228 new RouteStep(-CAR_RIGHT, CAR_ROUNDABOUT_LEFT),
229 new RouteStep(-PT_DIV_L, CAR_ROUNDABOUT_LEFT),
230 new RouteStep(Command.IF, (stream + 2 - 40) % 12 + 60),
231 new RouteStep(-PT_DIV_L, -PT_DIV_L),
232 new RouteStep(PT_DIV_L, -PT_DIV_L),
233 new RouteStep(Command.ELSE),
234 new RouteStep(-PT_DIV_L, -CAR_CENTER),
235 new RouteStep(CAR_ROUNDABOUT_LEFT, -CAR_CENTER),
236 new RouteStep(CAR_ROUNDABOUT_LEFT, -CAR_RIGHT),
237 new RouteStep(PT_DIV_L, -CAR_RIGHT),
238 new RouteStep(Command.END_IF),
239 new RouteStep(PT_DIV_L, -SHOULDER),
240 new RouteStep(PT_DIV_L, -BOUNDARY, Command.ICON))));
241 }
242
243 for (short stream = 62; stream <= 72; stream += 3)
244 {
245 int quadrant = (stream - 61) / 3;
246 this.routes.put(stream, rotateRoute(quadrant, assembleRoute(
247 new RouteStep(-CAR_ROUNDABOUT_LEFT, CAR_CENTER),
248 new RouteStep(CAR_ROUNDABOUT_LEFT, CAR_CENTER, Command.STOP_LINE_AND_ICON),
249 new RouteStep(BOUNDARY, CAR_CENTER))));
250 this.routes.put((short) (stream + 1), rotateRoute(quadrant, assembleRoute(
251 new RouteStep(-CAR_ROUNDABOUT_LEFT, CAR_LEFT),
252 new RouteStep(CAR_ROUNDABOUT_LEFT, CAR_LEFT, Command.STOP_LINE_AND_ICON),
253 new RouteStep(CAR_CENTER, CAR_LEFT),
254 new RouteStep(Command.IF, ((stream - 61) + 11) % 12 + 60),
255 new RouteStep(CAR_CENTER, CAR_ROUNDABOUT_LEFT),
256 new RouteStep(Command.ELSE),
257 new RouteStep(CAR_CENTER, -BOUNDARY),
258 new RouteStep(Command.END_IF))));
259 }
260
261 }
262
263
264
265
266
267
268 private boolean streamExists(final short stream)
269 {
270 return this.streams.contains(stream);
271 }
272
273
274
275
276
277
278 public final static boolean isGrass(final int i)
279 {
280 return i == DIVIDER_1 || i == DIVIDER_2 || i == DIVIDER_3 || i == DIVIDER_4 || i == DIVIDER_5 || i == DIVIDER_6
281 || i == DIVIDER_7 || i == SHOULDER;
282 }
283
284
285
286
287
288
289 final LaneType laneType(final int streamNumber)
290 {
291 if (streamNumber < 20 || streamNumber > 60 && streamNumber <= 80)
292 {
293 return LaneType.CAR_LANE;
294 }
295 if (streamNumber >= 20 && streamNumber < 30)
296 {
297 return LaneType.BICYCLE_LANE;
298 }
299 if (streamNumber >= 30 && streamNumber < 40)
300 {
301 return LaneType.PEDESTRIAN_LANE;
302 }
303 if (streamNumber > 40 && streamNumber <= 52 || streamNumber >= 81 && streamNumber <= 92)
304 {
305 return LaneType.PUBLIC_TRANSIT_LANE;
306 }
307 return null;
308 }
309
310
311
312
313 enum LaneType
314 {
315
316 CAR_LANE,
317
318 BICYCLE_LANE,
319
320 PUBLIC_TRANSIT_LANE,
321
322 PEDESTRIAN_LANE,
323 }
324
325
326
327
328
329
330
331 final int rotatedX(final XYPair xyPair, final int rotation)
332 {
333 switch (rotation % 4)
334 {
335 case 0:
336 return xyPair.getX();
337 case 1:
338 return -xyPair.getY();
339 case 2:
340 return -xyPair.getX();
341 case 3:
342 return xyPair.getY();
343 }
344 return 0;
345 }
346
347
348
349
350
351
352
353 final int rotatedY(final XYPair xyPair, final int rotation)
354 {
355 switch (rotation % 4)
356 {
357 case 0:
358 return xyPair.getY();
359 case 1:
360 return xyPair.getX();
361 case 2:
362 return -xyPair.getY();
363 case 3:
364 return -xyPair.getX();
365 }
366 return 0;
367 }
368
369
370
371
372 enum Command
373 {
374
375 NO_OP,
376
377 IF,
378
379 ELSE,
380
381 ELSE_IF,
382
383 END_IF,
384
385 STOP_LINE,
386
387 ICON,
388
389 STOP_LINE_AND_ICON,
390 }
391
392
393
394
395 class RouteStep
396 {
397
398 final private int x;
399
400
401 final private int y;
402
403
404 final private Command command;
405
406
407 final private int streamCondition;
408
409
410
411
412
413
414 public RouteStep(final int x, final int y)
415 {
416 this.x = x;
417 this.y = y;
418 this.command = Command.NO_OP;
419 this.streamCondition = TrafficController.NO_STREAM;
420 }
421
422
423
424
425
426
427
428
429
430 public RouteStep(final int x, final int y, final Command command) throws TrafficLightException
431 {
432 Throw.when(
433 Command.STOP_LINE != command && Command.NO_OP != command && Command.ICON != command
434 && Command.STOP_LINE_AND_ICON != command,
435 TrafficLightException.class,
436 "X and Y should only be provided with a NO_OP, STOP_LINE, ICON, or STOP_LINE_AND_ICON command; not with "
437 + command);
438 this.x = x;
439 this.y = y;
440 this.command = command;
441 this.streamCondition = TrafficController.NO_STREAM;
442 }
443
444
445
446
447
448
449
450
451 public RouteStep(final Command command, final int streamCondition) throws TrafficLightException
452 {
453 Throw.when(Command.IF != command && Command.ELSE_IF != command, TrafficLightException.class,
454 "RouteStep constructor with stream condition must use command IF or ELSE_IF");
455 this.x = TrafficController.NO_STREAM;
456 this.y = TrafficController.NO_STREAM;
457 this.command = command;
458 Throw.when(streamCondition == TrafficController.NO_STREAM, TrafficLightException.class,
459 "IF or ELSE_IF need a valid traffic stream number");
460 this.streamCondition = streamCondition;
461 }
462
463
464
465
466
467
468 public RouteStep(final Command command) throws TrafficLightException
469 {
470 Throw.when(Command.ELSE != command && Command.END_IF != command, TrafficLightException.class,
471 "RouteStep constructor with single command parameter requires ELSE or END_IF command");
472 this.x = TrafficController.NO_STREAM;
473 this.y = TrafficController.NO_STREAM;
474 this.command = command;
475 this.streamCondition = TrafficController.NO_STREAM;
476 }
477
478
479
480
481
482 public int getX()
483 {
484 return this.x;
485 }
486
487
488
489
490
491 public int getY()
492 {
493 return this.y;
494 }
495
496
497
498
499
500 public Command getCommand()
501 {
502 return this.command;
503 }
504
505
506
507
508
509 public int getStreamCondition()
510 {
511 return this.streamCondition;
512 }
513
514
515 @Override
516 public String toString()
517 {
518 return "RouteStep [x=" + this.x + ", y=" + this.y + ", command=" + this.command + ", streamCondition="
519 + this.streamCondition + "]";
520 }
521
522 }
523
524
525
526
527 class XYPair
528 {
529
530 private final int x;
531
532
533 private final int y;
534
535
536
537
538
539
540 public XYPair(final int x, final int y)
541 {
542 this.x = x;
543 this.y = y;
544 }
545
546
547
548
549
550 public XYPair(final RouteStep routeStep)
551 {
552 this.x = routeStep.getX();
553 this.y = routeStep.getY();
554 }
555
556
557
558
559
560
561 public XYPair(final XYPair in, final int quadrant)
562 {
563 this.x = rotatedX(in, quadrant);
564 this.y = rotatedY(in, quadrant);
565 }
566
567
568
569
570
571 public int getX()
572 {
573 return this.x;
574 }
575
576
577
578
579
580 public int getY()
581 {
582 return this.y;
583 }
584
585
586 @Override
587 public String toString()
588 {
589 return "XYPair [x=" + this.x + ", y=" + this.y + "]";
590 }
591
592 }
593
594
595
596
597
598
599
600
601 private XYPair[] rotateRoute(final int quadrant, final RouteStep... steps) throws TrafficLightException
602 {
603 List<XYPair> route = new ArrayList<>();
604 boolean on = true;
605
606 for (RouteStep step : steps)
607 {
608 switch (step.getCommand())
609 {
610 case NO_OP:
611 case STOP_LINE:
612 case ICON:
613 case STOP_LINE_AND_ICON:
614 if (on)
615 {
616 route.add(new XYPair(new XYPair(step), quadrant));
617 }
618 break;
619
620 default:
621 throw new TrafficLightException("Bad command in rotateRoute: " + step.getCommand());
622
623 }
624 }
625 return route.toArray(new XYPair[route.size()]);
626 }
627
628
629
630
631
632
633
634 private RouteStep[] assembleRoute(RouteStep... steps) throws TrafficLightException
635 {
636 List<RouteStep> result = new ArrayList<>();
637 RouteStep step;
638 for (int pointNo = 0; null != (step = routePoint(pointNo, steps)); pointNo++)
639 {
640 result.add(step);
641 }
642 return result.toArray(new RouteStep[result.size()]);
643 }
644
645
646
647
648
649
650
651
652 private RouteStep routePoint(final int pointNo, final RouteStep... steps) throws TrafficLightException
653 {
654 boolean active = true;
655 boolean beenActive = false;
656 int index = 0;
657
658 for (RouteStep routeStep : steps)
659 {
660 switch (routeStep.getCommand())
661 {
662 case NO_OP:
663 case STOP_LINE:
664 case ICON:
665 case STOP_LINE_AND_ICON:
666 if (active)
667 {
668 if (index++ == pointNo)
669 {
670 return routeStep;
671 }
672 }
673 break;
674
675 case IF:
676 active = streamExists((short) routeStep.getStreamCondition());
677 beenActive = active;
678 break;
679
680 case ELSE_IF:
681 if (active)
682 {
683 active = false;
684 }
685 else if (!beenActive)
686 {
687 active = this.streams.contains(routeStep.getStreamCondition());
688 }
689 if (active)
690 {
691 beenActive = true;
692 }
693 break;
694
695 case ELSE:
696 active = !beenActive;
697 break;
698
699 case END_IF:
700 active = true;
701 break;
702
703 default:
704 throw new TrafficLightException("Bad switch: " + routeStep);
705
706 }
707 }
708 return null;
709 }
710
711
712
713
714
715 public BufferedImage render()
716 {
717 int range = 2 * BOUNDARY + 1;
718 int cellSize = 10;
719 BufferedImage result = new BufferedImage(range * cellSize, range * cellSize, BufferedImage.TYPE_INT_RGB);
720 Graphics2D graphics = (Graphics2D) result.getGraphics();
721 graphics.setColor(Color.GREEN);
722 graphics.fillRect(0, 0, result.getWidth(), result.getHeight());
723 for (Short stream : this.streams)
724 {
725 switch (laneType(stream))
726 {
727 case BICYCLE_LANE:
728 graphics.setColor(Color.RED);
729 break;
730
731 case CAR_LANE:
732 graphics.setColor(Color.BLACK);
733 break;
734
735 case PEDESTRIAN_LANE:
736 graphics.setColor(Color.BLUE);
737 break;
738
739 case PUBLIC_TRANSIT_LANE:
740 graphics.setColor(Color.BLACK);
741 break;
742
743 default:
744 graphics.setColor(Color.WHITE);
745 break;
746
747 }
748 XYPair[] path = this.routes.get(stream);
749 if (null == path)
750 {
751 System.err.println("Cannot find path for stream " + stream);
752 continue;
753 }
754 XYPair prevPair = null;
755 for (XYPair xyPair : path)
756 {
757 if (null != prevPair)
758 {
759 int dx = (int) Math.signum(xyPair.getX() - prevPair.getX());
760 int dy = (int) Math.signum(xyPair.getY() - prevPair.getY());
761 int x = prevPair.getX() + dx;
762 int y = prevPair.getY() + dy;
763 while (x != xyPair.getX() || y != xyPair.getY())
764 {
765 fillXYPair(graphics, new XYPair(x, y));
766 if (x != xyPair.getX())
767 {
768 x += dx;
769 }
770 if (y != xyPair.getY())
771 {
772 y += dy;
773 }
774 }
775
776 }
777 fillXYPair(graphics, xyPair);
778 prevPair = xyPair;
779 }
780 }
781 return result;
782 }
783
784
785
786
787
788
789 private void fillXYPair(final Graphics2D graphics, final XYPair xyPair)
790 {
791 int cellSize = 10;
792 graphics.fillRect(cellSize * (BOUNDARY - xyPair.getX()), cellSize * (BOUNDARY - xyPair.getY()), cellSize, cellSize);
793 }
794
795
796
797
798
799 public static void main(final String[] args)
800 {
801 SwingUtilities.invokeLater(new Runnable()
802 {
803 @Override
804 public void run()
805 {
806 JFrame frame = new JFrame("Diagram test");
807 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
808 frame.setMinimumSize(new Dimension(1000, 1000));
809 JPanel mainPanel = new JPanel(new BorderLayout());
810 frame.add(mainPanel);
811 checkBoxPanel = new JPanel();
812 checkBoxPanel.setLayout(new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS));
813 JScrollPane scrollPane = new JScrollPane(checkBoxPanel);
814 scrollPane.setPreferredSize(new Dimension(150, 1000));
815 mainPanel.add(scrollPane, BorderLayout.LINE_START);
816 for (int stream = 1; stream <= 12; stream++)
817 {
818 checkBoxPanel.add(makeCheckBox(stream, stream % 3 == 2));
819 }
820 for (int stream = 21; stream <= 28; stream++)
821 {
822 checkBoxPanel.add(makeCheckBox(stream, false));
823 }
824 for (int stream = 31; stream <= 38; stream++)
825 {
826 checkBoxPanel.add(makeCheckBox(stream, false));
827 }
828 for (int stream = 41; stream <= 52; stream++)
829 {
830 checkBoxPanel.add(makeCheckBox(stream, false));
831 }
832 for (int stream = 61; stream <= 72; stream++)
833 {
834 if (stream % 3 == 1)
835 {
836 continue;
837 }
838 checkBoxPanel.add(makeCheckBox(stream, false));
839 }
840 testPanel = new JPanel();
841 rebuildTestPanel();
842 mainPanel.add(testPanel, BorderLayout.CENTER);
843 frame.setVisible(true);
844 }
845 });
846
847 }
848
849
850
851
852
853
854
855 public static JCheckBox makeCheckBox(final int stream, final boolean initialState)
856 {
857 JCheckBox result = new JCheckBox(String.format("Stream %02d", stream));
858 result.setSelected(initialState);
859 result.addActionListener(new ActionListener()
860 {
861
862 @Override
863 public void actionPerformed(ActionEvent e)
864 {
865 rebuildTestPanel();
866 }
867 });
868 return result;
869 }
870
871
872 static JPanel testPanel = null;
873
874
875 static JPanel checkBoxPanel = null;
876
877
878
879
880 static void rebuildTestPanel()
881 {
882 testPanel.removeAll();
883 Set<Short> streamList = new HashSet<>();
884 for (Component c : checkBoxPanel.getComponents())
885 {
886 if (c instanceof JCheckBox)
887 {
888 JCheckBox checkBox = (JCheckBox) c;
889 if (checkBox.isSelected())
890 {
891 String caption = checkBox.getText();
892 String streamText = caption.substring(caption.length() - 2);
893 Short stream = Short.parseShort(streamText);
894 streamList.add(stream);
895 }
896 }
897 }
898 try
899 {
900 Diagram diagram = new Diagram(streamList);
901 testPanel.add(new JLabel(new ImageIcon(diagram.render())));
902 }
903 catch (TrafficLightException exception)
904 {
905 exception.printStackTrace();
906 }
907 testPanel.repaint();
908 testPanel.revalidate();
909 }
910
911 }