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