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