1 package org.opentrafficsim.swing.gui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Container;
6 import java.awt.Dimension;
7 import java.awt.Graphics;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.awt.event.ContainerEvent;
11 import java.awt.event.ContainerListener;
12 import java.awt.event.MouseAdapter;
13 import java.awt.event.MouseEvent;
14 import java.awt.event.MouseListener;
15 import java.awt.event.MouseWheelEvent;
16 import java.awt.event.MouseWheelListener;
17 import java.awt.event.WindowEvent;
18 import java.awt.event.WindowListener;
19 import java.awt.geom.Point2D;
20 import java.awt.geom.Rectangle2D;
21 import java.rmi.RemoteException;
22 import java.text.NumberFormat;
23 import java.util.ArrayList;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.swing.BoxLayout;
29 import javax.swing.Icon;
30 import javax.swing.JButton;
31 import javax.swing.JCheckBox;
32 import javax.swing.JFrame;
33 import javax.swing.JLabel;
34 import javax.swing.JPanel;
35 import javax.swing.JToggleButton;
36 import javax.swing.border.EmptyBorder;
37
38 import org.djutils.event.EventInterface;
39 import org.djutils.event.EventListenerInterface;
40 import org.djutils.event.TimedEvent;
41 import org.djutils.exceptions.Throw;
42 import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
43 import org.opentrafficsim.core.dsol.OTSAnimator;
44 import org.opentrafficsim.core.dsol.OTSModelInterface;
45 import org.opentrafficsim.core.gtu.GTU;
46 import org.opentrafficsim.core.network.Network;
47 import org.opentrafficsim.core.network.OTSNetwork;
48
49 import nl.javel.gisbeans.map.MapInterface;
50 import nl.tudelft.simulation.dsol.animation.Locatable;
51 import nl.tudelft.simulation.dsol.animation.D2.GisRenderable2D;
52 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
53 import nl.tudelft.simulation.dsol.experiment.Replication;
54 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
55 import nl.tudelft.simulation.dsol.swing.animation.D2.AnimationPanel;
56 import nl.tudelft.simulation.dsol.swing.animation.D2.GridPanel;
57 import nl.tudelft.simulation.dsol.swing.animation.D2.mouse.InputListener;
58 import nl.tudelft.simulation.language.DSOLException;
59 import nl.tudelft.simulation.language.d3.DirectedPoint;
60
61
62
63
64
65
66
67
68
69
70
71
72 public class OTSAnimationPanel extends OTSSimulationPanel implements ActionListener, WindowListener, EventListenerInterface
73 {
74
75 private static final long serialVersionUID = 20150617L;
76
77
78 private final AutoAnimationPanel animationPanel;
79
80
81 private final JPanel borderPanel;
82
83
84 private final JPanel togglePanel;
85
86
87 private JPanel demoPanel = null;
88
89
90 private Map<String, Class<? extends Locatable>> toggleLocatableMap = new LinkedHashMap<>();
91
92
93 private Map<Class<? extends Locatable>, JToggleButton> toggleButtons = new LinkedHashMap<>();
94
95
96 private Map<String, MapInterface> toggleGISMap = new LinkedHashMap<>();
97
98
99 private Map<String, JToggleButton> toggleGISButtons = new LinkedHashMap<>();
100
101
102 private GTUColorer gtuColorer = null;
103
104
105 private ColorControlPanel colorControlPanel = null;
106
107
108 private final JLabel coordinateField;
109
110
111 private final JLabel gtuCountField;
112
113
114 private int gtuCount = 0;
115
116
117 private final ArrayList<JButton> buttons = new ArrayList<>();
118
119
120 private static final NumberFormat FORMATTER = NumberFormat.getInstance();
121
122
123 @SuppressWarnings("checkstyle:visibilitymodifier")
124 protected boolean closeHandlerRegistered = false;
125
126
127 @SuppressWarnings("checkstyle:visibilitymodifier")
128 protected boolean windowExited = false;
129
130
131 private String autoPanId = null;
132
133
134 private OTSSearchPanel.ObjectKind<?> autoPanKind = null;
135
136
137 private boolean autoPanTrack = false;
138
139
140 private boolean autoPanOnNextPaintComponent = false;
141
142
143 static
144 {
145 FORMATTER.setMaximumFractionDigits(3);
146 }
147
148
149
150
151
152
153
154
155
156
157
158
159 public OTSAnimationPanel(final Rectangle2D extent, final Dimension size, final OTSAnimator simulator,
160 final OTSModelInterface otsModel, final GTUColorer gtuColorer, final OTSNetwork network) throws RemoteException,
161 DSOLException
162 {
163 super(simulator, otsModel);
164
165
166
167 this.animationPanel = new AutoAnimationPanel(extent, size, simulator, network);
168 this.animationPanel.showGrid(false);
169 this.borderPanel = new JPanel(new BorderLayout());
170 this.borderPanel.add(this.animationPanel, BorderLayout.CENTER);
171 getTabbedPane().addTab(0, "animation", this.borderPanel);
172 getTabbedPane().setSelectedIndex(0);
173
174
175 this.gtuColorer = gtuColorer;
176 this.colorControlPanel = new ColorControlPanel(this.gtuColorer);
177 JPanel buttonPanel = new JPanel();
178 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
179 this.borderPanel.add(buttonPanel, BorderLayout.NORTH);
180 buttonPanel.add(this.colorControlPanel);
181
182
183 this.togglePanel = new JPanel();
184 this.togglePanel.setLayout(new BoxLayout(this.togglePanel, BoxLayout.Y_AXIS));
185 this.borderPanel.add(this.togglePanel, BorderLayout.WEST);
186
187
188 buttonPanel.add(new JLabel(" "));
189 buttonPanel.add(makeButton("allButton", "/Expand.png", "ZoomAll", "Zoom whole network", true));
190 buttonPanel.add(makeButton("homeButton", "/Home.png", "Home", "Zoom to original extent", true));
191 buttonPanel.add(makeButton("gridButton", "/Grid.png", "Grid", "Toggle grid on/off", true));
192 buttonPanel.add(new JLabel(" "));
193
194
195 JPanel infoTextPanel = new JPanel();
196 buttonPanel.add(infoTextPanel);
197 infoTextPanel.setMinimumSize(new Dimension(250, 20));
198 infoTextPanel.setPreferredSize(new Dimension(250, 20));
199 infoTextPanel.setLayout(new BoxLayout(infoTextPanel, BoxLayout.Y_AXIS));
200 this.coordinateField = new JLabel("Mouse: ");
201 this.coordinateField.setMinimumSize(new Dimension(250, 10));
202 this.coordinateField.setPreferredSize(new Dimension(250, 10));
203 infoTextPanel.add(this.coordinateField);
204
205 JPanel gtuPanel = new JPanel();
206 gtuPanel.setAlignmentX(0.0f);
207 gtuPanel.setLayout(new BoxLayout(gtuPanel, BoxLayout.X_AXIS));
208 gtuPanel.setMinimumSize(new Dimension(250, 10));
209 gtuPanel.setPreferredSize(new Dimension(250, 10));
210 infoTextPanel.add(gtuPanel);
211 if (null != network)
212 {
213 network.addListener(this, Network.GTU_ADD_EVENT);
214 network.addListener(this, Network.GTU_REMOVE_EVENT);
215 }
216
217 this.gtuCountField = new JLabel("0 GTU's");
218 this.gtuCount = null == network ? 0 : network.getGTUs().size();
219 gtuPanel.add(this.gtuCountField);
220 setGtuCountText();
221
222
223 this.animationPanel.notify(new TimedEvent(Replication.START_REPLICATION_EVENT, simulator.getSourceId(), null,
224 getSimulator().getSimulatorTime()));
225
226
227 this.animationPanel.setShowToolTip(false);
228
229
230 new UpdateTimer().start();
231
232
233 installWindowCloseHandler();
234
235 }
236
237
238
239
240
241
242
243 public void setAutoPan(final String newAutoPanId, final OTSSearchPanel.ObjectKind<?> newAutoPanKind,
244 final boolean newAutoPanTrack)
245 {
246 this.autoPanId = newAutoPanId;
247 this.autoPanKind = newAutoPanKind;
248 this.autoPanTrack = newAutoPanTrack;
249 this.autoPanOnNextPaintComponent = true;
250
251 if (null != this.autoPanId && this.autoPanId.length() > 0 && null != this.autoPanKind)
252 {
253 OTSAnimationPanel.this.animationPanel.repaint();
254 }
255 }
256
257
258
259
260
261
262
263
264
265
266 private JButton makeButton(final String name, final String iconPath, final String actionCommand, final String toolTipText,
267 final boolean enabled)
268 {
269
270 JButton result = new JButton(OTSControlPanel.loadIcon(iconPath));
271 result.setPreferredSize(new Dimension(34, 32));
272 result.setName(name);
273 result.setEnabled(enabled);
274 result.setActionCommand(actionCommand);
275 result.setToolTipText(toolTipText);
276 result.addActionListener(this);
277 this.buttons.add(result);
278 return result;
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292 public final void addToggleAnimationButtonIcon(final String name, final Class<? extends Locatable> locatableClass,
293 final String iconPath, final String toolTipText, final boolean initiallyVisible, final boolean idButton)
294 {
295 JToggleButton button;
296 Icon icon = OTSControlPanel.loadIcon(iconPath);
297 Icon unIcon = OTSControlPanel.loadGrayscaleIcon(iconPath);
298 button = new JCheckBox();
299 button.setSelectedIcon(icon);
300 button.setIcon(unIcon);
301 button.setPreferredSize(new Dimension(32, 28));
302 button.setName(name);
303 button.setEnabled(true);
304 button.setSelected(initiallyVisible);
305 button.setActionCommand(name);
306 button.setToolTipText(toolTipText);
307 button.addActionListener(this);
308
309
310 if (idButton && this.togglePanel.getComponentCount() > 0)
311 {
312 JPanel lastToggleBox = (JPanel) this.togglePanel.getComponent(this.togglePanel.getComponentCount() - 1);
313 lastToggleBox.add(button);
314 }
315 else
316 {
317 JPanel toggleBox = new JPanel();
318 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
319 toggleBox.add(button);
320 this.togglePanel.add(toggleBox);
321 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
322 }
323
324 if (initiallyVisible)
325 {
326 this.animationPanel.showClass(locatableClass);
327 }
328 else
329 {
330 this.animationPanel.hideClass(locatableClass);
331 }
332 this.toggleLocatableMap.put(name, locatableClass);
333 this.toggleButtons.put(locatableClass, button);
334 }
335
336
337
338
339
340
341
342
343 public final void addToggleAnimationButtonText(final String name, final Class<? extends Locatable> locatableClass,
344 final String toolTipText, final boolean initiallyVisible)
345 {
346 JToggleButton button;
347 button = new JCheckBox(name);
348 button.setName(name);
349 button.setEnabled(true);
350 button.setSelected(initiallyVisible);
351 button.setActionCommand(name);
352 button.setToolTipText(toolTipText);
353 button.addActionListener(this);
354
355 JPanel toggleBox = new JPanel();
356 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
357 toggleBox.add(button);
358 this.togglePanel.add(toggleBox);
359 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
360
361 if (initiallyVisible)
362 {
363 this.animationPanel.showClass(locatableClass);
364 }
365 else
366 {
367 this.animationPanel.hideClass(locatableClass);
368 }
369 this.toggleLocatableMap.put(name, locatableClass);
370 this.toggleButtons.put(locatableClass, button);
371 }
372
373
374
375
376
377 public final void addToggleText(final String text)
378 {
379 JPanel textBox = new JPanel();
380 textBox.setLayout(new BoxLayout(textBox, BoxLayout.X_AXIS));
381 textBox.add(new JLabel(text));
382 this.togglePanel.add(textBox);
383 textBox.setAlignmentX(Component.LEFT_ALIGNMENT);
384 }
385
386
387
388
389
390
391
392 public final void addAllToggleGISButtonText(final String header, final GisRenderable2D gisMap, final String toolTipText)
393 {
394 addToggleText(" ");
395 addToggleText(header);
396 try
397 {
398 for (String layerName : gisMap.getMap().getLayerMap().keySet())
399 {
400 addToggleGISButtonText(layerName, layerName, gisMap, toolTipText);
401 }
402 }
403 catch (RemoteException exception)
404 {
405 exception.printStackTrace();
406 }
407 }
408
409
410
411
412
413
414
415
416 public final void addToggleGISButtonText(final String layerName, final String displayName, final GisRenderable2D gisMap,
417 final String toolTipText)
418 {
419 JToggleButton button;
420 button = new JCheckBox(displayName);
421 button.setName(layerName);
422 button.setEnabled(true);
423 button.setSelected(true);
424 button.setActionCommand(layerName);
425 button.setToolTipText(toolTipText);
426 button.addActionListener(this);
427
428 JPanel toggleBox = new JPanel();
429 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
430 toggleBox.add(button);
431 this.togglePanel.add(toggleBox);
432 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
433
434 this.toggleGISMap.put(layerName, gisMap.getMap());
435 this.toggleGISButtons.put(layerName, button);
436 }
437
438
439
440
441
442 public final void showGISLayer(final String layerName)
443 {
444 MapInterface gisMap = this.toggleGISMap.get(layerName);
445 if (gisMap != null)
446 {
447 try
448 {
449 gisMap.showLayer(layerName);
450 this.toggleGISButtons.get(layerName).setSelected(true);
451 this.animationPanel.repaint();
452 }
453 catch (RemoteException exception)
454 {
455 exception.printStackTrace();
456 }
457 }
458 }
459
460
461
462
463
464 public final void hideGISLayer(final String layerName)
465 {
466 MapInterface gisMap = this.toggleGISMap.get(layerName);
467 if (gisMap != null)
468 {
469 try
470 {
471 gisMap.hideLayer(layerName);
472 this.toggleGISButtons.get(layerName).setSelected(false);
473 this.animationPanel.repaint();
474 }
475 catch (RemoteException exception)
476 {
477 exception.printStackTrace();
478 }
479 }
480 }
481
482
483
484
485
486 public final void toggleGISLayer(final String layerName)
487 {
488 MapInterface gisMap = this.toggleGISMap.get(layerName);
489 if (gisMap != null)
490 {
491 try
492 {
493 if (gisMap.getVisibleLayers().contains(gisMap.getLayerMap().get(layerName)))
494 {
495 gisMap.hideLayer(layerName);
496 this.toggleGISButtons.get(layerName).setSelected(false);
497 }
498 else
499 {
500 gisMap.showLayer(layerName);
501 this.toggleGISButtons.get(layerName).setSelected(true);
502 }
503 this.animationPanel.repaint();
504 }
505 catch (RemoteException exception)
506 {
507 exception.printStackTrace();
508 }
509 }
510 }
511
512
513 @Override
514 public final void actionPerformed(final ActionEvent actionEvent)
515 {
516 String actionCommand = actionEvent.getActionCommand();
517
518 try
519 {
520 if (actionCommand.equals("Home"))
521 {
522 this.animationPanel.home();
523 }
524 if (actionCommand.equals("ZoomAll"))
525 {
526 this.animationPanel.zoomAll();
527 }
528 if (actionCommand.equals("Grid"))
529 {
530 this.animationPanel.showGrid(!this.animationPanel.isShowGrid());
531 }
532
533 if (this.toggleLocatableMap.containsKey(actionCommand))
534 {
535 Class<? extends Locatable> locatableClass = this.toggleLocatableMap.get(actionCommand);
536 this.animationPanel.toggleClass(locatableClass);
537 this.togglePanel.repaint();
538 }
539
540 if (this.toggleGISMap.containsKey(actionCommand))
541 {
542 this.toggleGISLayer(actionCommand);
543 this.togglePanel.repaint();
544 }
545 }
546 catch (Exception exception)
547 {
548 exception.printStackTrace();
549 }
550 }
551
552
553
554
555
556 public final AnimationPanel getAnimationPanel()
557 {
558 return this.animationPanel;
559 }
560
561
562
563
564
565
566 public void createDemoPanel(final DemoPanelPosition position)
567 {
568 Throw.when(this.demoPanel != null, IllegalStateException.class,
569 "Attempt to create demo panel, but it's already created");
570 Throw.whenNull(position, "Position may not be null.");
571 Container parent = this.animationPanel.getParent();
572 parent.remove(this.animationPanel);
573
574 JPanel splitPanel = new JPanel(new BorderLayout());
575 parent.add(splitPanel);
576 splitPanel.add(this.animationPanel, BorderLayout.CENTER);
577
578 this.demoPanel = new JPanel();
579 this.demoPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
580 splitPanel.add(this.demoPanel, position.getBorderLayoutPosition());
581 }
582
583
584
585
586
587 public JPanel getDemoPanel()
588 {
589 if (this.demoPanel == null)
590 {
591 createDemoPanel(DemoPanelPosition.RIGHT);
592
593
594
595
596
597 this.demoPanel.addContainerListener(new ContainerListener()
598 {
599 @Override
600 public void componentAdded(final ContainerEvent e)
601 {
602 try
603 {
604
605 }
606 catch (NullPointerException exception)
607 {
608
609 }
610 }
611
612 @Override
613 public void componentRemoved(final ContainerEvent e)
614 {
615
616 }
617 });
618 }
619 return this.demoPanel;
620 }
621
622
623
624
625
626 public final void updateAnimationClassCheckBox(final Class<? extends Locatable> locatableClass)
627 {
628 JToggleButton button = this.toggleButtons.get(locatableClass);
629 if (button == null)
630 {
631 return;
632 }
633 button.setSelected(getAnimationPanel().isShowClass(locatableClass));
634 }
635
636
637
638
639 protected final void updateWorldCoordinate()
640 {
641 String worldPoint = "(x=" + FORMATTER.format(this.animationPanel.getWorldCoordinate().getX()) + " ; y=" + FORMATTER
642 .format(this.animationPanel.getWorldCoordinate().getY()) + ")";
643 this.coordinateField.setText("Mouse: " + worldPoint);
644 int requiredWidth = this.coordinateField.getGraphics().getFontMetrics().stringWidth(this.coordinateField.getText());
645 if (this.coordinateField.getPreferredSize().width < requiredWidth)
646 {
647 Dimension requiredSize = new Dimension(requiredWidth, this.coordinateField.getPreferredSize().height);
648 this.coordinateField.setPreferredSize(requiredSize);
649 this.coordinateField.setMinimumSize(requiredSize);
650 Container parent = this.coordinateField.getParent();
651 parent.setPreferredSize(requiredSize);
652 parent.setMinimumSize(requiredSize);
653
654 parent.revalidate();
655 }
656 this.coordinateField.repaint();
657 }
658
659
660
661
662
663
664 public final GTUColorer getGTUColorer()
665 {
666 return this.gtuColorer;
667 }
668
669
670
671
672
673
674 public final ColorControlPanel getColorControlPanel()
675 {
676 return this.colorControlPanel;
677 }
678
679
680
681
682 public final void installWindowCloseHandler()
683 {
684 if (this.closeHandlerRegistered)
685 {
686 return;
687 }
688
689
690 new DisposeOnCloseThread(this).start();
691 }
692
693
694 protected class DisposeOnCloseThread extends Thread
695 {
696
697 private OTSAnimationPanel panel;
698
699
700
701
702 public DisposeOnCloseThread(final OTSAnimationPanel panel)
703 {
704 this.panel = panel;
705 }
706
707
708 @Override
709 public final void run()
710 {
711 Container root = this.panel;
712 while (!(root instanceof JFrame))
713 {
714 try
715 {
716 Thread.sleep(10);
717 }
718 catch (InterruptedException exception)
719 {
720
721 }
722
723
724 root = this.panel;
725 while (null != root.getParent() && !(root instanceof JFrame))
726 {
727 root = root.getParent();
728 }
729 }
730 JFrame frame = (JFrame) root;
731 frame.addWindowListener(this.panel);
732 this.panel.closeHandlerRegistered = true;
733 }
734
735
736 @Override
737 public final String toString()
738 {
739 return "DisposeOnCloseThread of OTSAnimationPanel [panel=" + this.panel + "]";
740 }
741 }
742
743
744 @Override
745 public void windowOpened(final WindowEvent e)
746 {
747
748 }
749
750
751 @Override
752 public final void windowClosing(final WindowEvent e)
753 {
754
755 }
756
757
758 @Override
759 public final void windowClosed(final WindowEvent e)
760 {
761 this.windowExited = true;
762 }
763
764
765 @Override
766 public final void windowIconified(final WindowEvent e)
767 {
768
769 }
770
771
772 @Override
773 public final void windowDeiconified(final WindowEvent e)
774 {
775
776 }
777
778
779 @Override
780 public final void windowActivated(final WindowEvent e)
781 {
782
783 }
784
785
786 @Override
787 public final void windowDeactivated(final WindowEvent e)
788 {
789
790 }
791
792
793 @Override
794 public void notify(final EventInterface event) throws RemoteException
795 {
796 if (event.getType().equals(Network.GTU_ADD_EVENT))
797 {
798 this.gtuCount++;
799 setGtuCountText();
800 }
801 else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
802 {
803 this.gtuCount--;
804 setGtuCountText();
805 }
806 }
807
808
809
810
811 private void setGtuCountText()
812 {
813 this.gtuCountField.setText(this.gtuCount + " GTU's");
814 }
815
816
817
818
819 protected class UpdateTimer extends Thread
820 {
821
822 @Override
823 public final void run()
824 {
825 while (!OTSAnimationPanel.this.windowExited)
826 {
827 if (OTSAnimationPanel.this.isShowing())
828 {
829 OTSAnimationPanel.this.updateWorldCoordinate();
830 }
831 try
832 {
833 Thread.sleep(50);
834 }
835 catch (InterruptedException exception)
836 {
837
838 }
839 }
840 }
841
842
843 @Override
844 public final String toString()
845 {
846 return "UpdateTimer thread for OTSAnimationPanel";
847 }
848
849 }
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864 private class AutoAnimationPanel extends AnimationPanel
865 {
866
867
868 private static final long serialVersionUID = 20180430L;
869
870
871 private final OTSNetwork network;
872
873
874 private GTU lastGtu;
875
876
877
878
879
880
881
882
883
884
885 AutoAnimationPanel(final Rectangle2D extent, final Dimension size, final SimulatorInterface<?, ?, ?> simulator,
886 final OTSNetwork network) throws RemoteException, DSOLException
887 {
888 super(extent, size, simulator);
889 this.network = network;
890 MouseListener[] listeners = getMouseListeners();
891 for (MouseListener listener : listeners)
892 {
893 removeMouseListener(listener);
894 }
895 this.addMouseListener(new MouseAdapter()
896 {
897
898 @SuppressWarnings("synthetic-access")
899 @Override
900 public void mouseClicked(final MouseEvent e)
901 {
902 if (e.isControlDown())
903 {
904 GTU gtu = getSelectedGTU(e.getPoint());
905 if (gtu != null)
906 {
907 getOtsControlPanel().getOtsSearchPanel().selectAndTrackObject("GTU", gtu.getId(), true);
908 e.consume();
909 }
910 }
911 e.consume();
912 }
913 });
914 for (MouseListener listener : listeners)
915 {
916 addMouseListener(listener);
917 }
918
919 MouseWheelListener[] wheelListeners = getMouseWheelListeners();
920 for (MouseWheelListener wheelListener : wheelListeners)
921 {
922 removeMouseWheelListener(wheelListener);
923 }
924 this.addMouseWheelListener(new InputListener(this)
925 {
926
927 @Override
928 public void mouseWheelMoved(final MouseWheelEvent e)
929 {
930 if (e.isShiftDown())
931 {
932 int amount = e.getUnitsToScroll();
933 if (amount > 0)
934 {
935 zoomVertical(GridPanel.ZOOMFACTOR, e.getX(), e.getY());
936 }
937 else
938 {
939 zoomVertical(1.0 / GridPanel.ZOOMFACTOR, e.getX(), e.getY());
940 }
941 }
942 else if (e.isAltDown())
943 {
944 int amount = e.getUnitsToScroll();
945 if (amount > 0)
946 {
947 zoomHorizontal(GridPanel.ZOOMFACTOR, e.getX(), e.getY());
948 }
949 else
950 {
951 zoomHorizontal(1.0 / GridPanel.ZOOMFACTOR, e.getX(), e.getY());
952 }
953 }
954 else
955 {
956 super.mouseWheelMoved(e);
957 }
958 }
959 });
960 }
961
962
963
964
965
966
967
968 final synchronized void zoomVertical(final double factor, final int mouseX, final int mouseY)
969 {
970
971 this.zoom(factor, mouseX, mouseY);
972
973
974
975
976
977
978
979
980
981 }
982
983
984
985
986
987
988
989 final synchronized void zoomHorizontal(final double factor, final int mouseX, final int mouseY)
990 {
991 this.zoom(factor, mouseX, mouseY);
992
993
994
995
996
997
998
999
1000
1001 }
1002
1003
1004
1005
1006
1007
1008 @SuppressWarnings("synthetic-access")
1009 protected GTU getSelectedGTU(final Point2D mousePoint)
1010 {
1011 List<GTU> targets = new ArrayList<>();
1012 Point2D point = Renderable2DInterface.Util.getWorldCoordinates(mousePoint, OTSAnimationPanel.this.animationPanel
1013 .getExtent(), OTSAnimationPanel.this.animationPanel.getSize());
1014 for (Renderable2DInterface<?> renderable : OTSAnimationPanel.this.animationPanel.getElements())
1015 {
1016 if (OTSAnimationPanel.this.animationPanel.isShowElement(renderable) && renderable.contains(point,
1017 OTSAnimationPanel.this.animationPanel.getExtent(), OTSAnimationPanel.this.animationPanel.getSize()))
1018 {
1019 if (renderable.getSource() instanceof GTU)
1020 {
1021 targets.add((GTU) renderable.getSource());
1022 }
1023 }
1024 }
1025 if (targets.size() == 1)
1026 {
1027 return targets.get(0);
1028 }
1029 return null;
1030 }
1031
1032
1033 @SuppressWarnings("synthetic-access")
1034 @Override
1035 public void paintComponent(final Graphics g)
1036 {
1037 final OTSSearchPanel.ObjectKind<?> panKind = OTSAnimationPanel.this.autoPanKind;
1038 final String panId = OTSAnimationPanel.this.autoPanId;
1039 final boolean doPan = OTSAnimationPanel.this.autoPanOnNextPaintComponent;
1040 OTSAnimationPanel.this.autoPanOnNextPaintComponent = OTSAnimationPanel.this.autoPanTrack;
1041 if (doPan && panKind != null && panId != null)
1042 {
1043 Locatable locatable = panKind.searchNetwork(this.network, panId);
1044 if (null != locatable)
1045 {
1046 try
1047 {
1048 DirectedPoint point = locatable.getLocation();
1049 if (point != null)
1050 {
1051 double w = this.extent.getWidth();
1052 double h = this.extent.getHeight();
1053 this.extent = new Rectangle2D.Double(point.getX() - w / 2, point.getY() - h / 2, w, h);
1054 }
1055 }
1056 catch (RemoteException exception)
1057 {
1058 getSimulator().getLogger().always().warn(
1059 "Caught RemoteException trying to locate {} with id {} in network {}.", panKind, panId, network
1060 .getId());
1061 return;
1062 }
1063 }
1064 }
1065 super.paintComponent(g);
1066 }
1067
1068
1069 @Override
1070 public String toString()
1071 {
1072 return "AutoAnimationPanel [network=" + this.network + ", lastGtu=" + this.lastGtu + "]";
1073 }
1074 }
1075
1076
1077
1078
1079
1080 public enum DemoPanelPosition
1081 {
1082
1083 TOP("First"),
1084
1085
1086 BOTTOM("Last"),
1087
1088
1089 LEFT("Before"),
1090
1091
1092 RIGHT("After");
1093
1094
1095 private final String direction;
1096
1097
1098
1099
1100 DemoPanelPosition(final String direction)
1101 {
1102 this.direction = direction;
1103 }
1104
1105
1106
1107
1108 public String getBorderLayoutPosition()
1109 {
1110 return this.direction;
1111 }
1112 }
1113
1114 }