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