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