1 package org.opentrafficsim.swing.graphs;
2
3 import java.util.LinkedHashMap;
4 import java.util.Map;
5
6 import javax.swing.ButtonGroup;
7 import javax.swing.JCheckBoxMenuItem;
8 import javax.swing.JMenu;
9 import javax.swing.JPopupMenu;
10 import javax.swing.JRadioButtonMenuItem;
11
12 import org.djutils.event.Event;
13 import org.djutils.event.EventListener;
14 import org.opentrafficsim.animation.graphs.AbstractContourPlot;
15 import org.opentrafficsim.animation.graphs.ContourDataSource;
16 import org.opentrafficsim.animation.graphs.ContourDataSource.Dimension;
17 import org.opentrafficsim.base.OtsRuntimeException;
18
19
20
21
22
23
24
25
26
27
28
29 public class SwingContourPlot extends SwingSpaceTimePlot implements EventListener
30 {
31
32 private static final long serialVersionUID = 20190823L;
33
34
35 private Map<JRadioButtonMenuItem, Double> timeGranularityButtons;
36
37
38 private Map<JRadioButtonMenuItem, Double> spaceGranularityButtons;
39
40
41 private JCheckBoxMenuItem smoothCheckBox;
42
43
44 private JCheckBoxMenuItem interpolateCheckBox;
45
46
47 private boolean ignoreEvent = false;
48
49
50
51
52
53 public SwingContourPlot(final AbstractContourPlot<?> plot)
54 {
55 super(plot);
56 plot.addListener(this, ContourDataSource.GRANULARITY);
57 plot.addListener(this, ContourDataSource.INTERPOLATE);
58 plot.addListener(this, ContourDataSource.SMOOTH);
59 }
60
61 @Override
62 protected void addPopUpMenuItems(final JPopupMenu popupMenu)
63 {
64 this.timeGranularityButtons = new LinkedHashMap<>();
65 this.spaceGranularityButtons = new LinkedHashMap<>();
66 super.addPopUpMenuItems(popupMenu);
67 JMenu spaceGranularityMenu = buildMenu("Distance granularity", "%.0f m", 1000, "%.0f km", "setSpaceGranularity",
68 getPlot().getGranularities(Dimension.DISTANCE), getPlot().getGranularity(Dimension.DISTANCE),
69 this.spaceGranularityButtons);
70 popupMenu.insert(spaceGranularityMenu, 0);
71 JMenu timeGranularityMenu = buildMenu("Time granularity", "%.0f s", 60.0, "%.0f min", "setTimeGranularity",
72 getPlot().getGranularities(Dimension.TIME), getPlot().getGranularity(Dimension.TIME),
73 this.timeGranularityButtons);
74 popupMenu.insert(timeGranularityMenu, 1);
75 this.smoothCheckBox = new JCheckBoxMenuItem("Adaptive smoothing method", false);
76 this.smoothCheckBox.addActionListener((e) ->
77 {
78 SwingContourPlot.this.ignoreEvent = true;
79 getPlot().setSmooth(((JCheckBoxMenuItem) e.getSource()).isSelected());
80 SwingContourPlot.this.ignoreEvent = false;
81 });
82 popupMenu.insert(this.smoothCheckBox, 2);
83 this.interpolateCheckBox = new JCheckBoxMenuItem("Bilinear interpolation", true);
84 this.interpolateCheckBox.addActionListener((e) ->
85 {
86 SwingContourPlot.this.ignoreEvent = true;
87 boolean interpolate = ((JCheckBoxMenuItem) e.getSource()).isSelected();
88 getPlot().setInterpolate(interpolate);
89 SwingContourPlot.this.ignoreEvent = false;
90 });
91 popupMenu.insert(this.interpolateCheckBox, 3);
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106 private JMenu buildMenu(final String menuName, final String format1, final double formatValue, final String format2,
107 final String command, final double[] values, final double initialValue,
108 final Map<JRadioButtonMenuItem, Double> granularityButtons)
109 {
110 JMenu result = new JMenu(menuName);
111 ButtonGroup group = new ButtonGroup();
112 for (double value : values)
113 {
114 JRadioButtonMenuItem item = new JRadioButtonMenuItem(
115 String.format(value < formatValue ? format1 : format2, value < formatValue ? value : value / formatValue));
116 granularityButtons.put(item, value);
117 item.setSelected(value == initialValue);
118 item.setActionCommand(command);
119 item.addActionListener((actionEvent) ->
120 {
121 SwingContourPlot.this.ignoreEvent = true;
122 if (command.equalsIgnoreCase("setSpaceGranularity"))
123 {
124 double granularity = SwingContourPlot.this.spaceGranularityButtons.get(actionEvent.getSource());
125
126 getPlot().setGranularity(Dimension.DISTANCE, granularity);
127 }
128 else if (command.equalsIgnoreCase("setTimeGranularity"))
129 {
130 double granularity = SwingContourPlot.this.timeGranularityButtons.get(actionEvent.getSource());
131
132 getPlot().setGranularity(Dimension.TIME, granularity);
133 }
134 else
135 {
136 throw new OtsRuntimeException("Unknown ActionEvent");
137 }
138 SwingContourPlot.this.ignoreEvent = false;
139 });
140 result.add(item);
141 group.add(item);
142 }
143 return result;
144 }
145
146 @Override
147 public AbstractContourPlot<?> getPlot()
148 {
149 return (AbstractContourPlot<?>) super.getPlot();
150 }
151
152 @Override
153 public void notify(final Event event)
154 {
155 if (this.ignoreEvent)
156 {
157 return;
158 }
159 if (event.getType().equals(ContourDataSource.GRANULARITY))
160 {
161 Object[] payload = (Object[]) event.getContent();
162 Dimension dimension = (Dimension) payload[0];
163 double granularity = (double) payload[1];
164 Map<JRadioButtonMenuItem, Double> buttonMap =
165 Dimension.DISTANCE.equals(dimension) ? this.spaceGranularityButtons : this.timeGranularityButtons;
166 for (JRadioButtonMenuItem button : buttonMap.keySet())
167 {
168 button.setSelected(Math.abs(buttonMap.get(button) - granularity) < 0.001);
169 }
170 }
171 else if (event.getType().equals(ContourDataSource.INTERPOLATE))
172 {
173 this.interpolateCheckBox.setSelected((boolean) event.getContent());
174 }
175 else if (event.getType().equals(ContourDataSource.SMOOTH))
176 {
177 this.smoothCheckBox.setSelected((boolean) event.getContent());
178 }
179 }
180
181 }