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.base.OtsRuntimeException;
15 import org.opentrafficsim.draw.graphs.AbstractContourPlot;
16 import org.opentrafficsim.draw.graphs.ContourDataSource;
17 import org.opentrafficsim.draw.graphs.ContourDataSource.Dimension;
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.getDataPool().addListener(this, ContourDataSource.GRANULARITY);
57 plot.getDataPool().addListener(this, ContourDataSource.INTERPOLATE);
58 plot.getDataPool().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().getDataPool().getGranularities(Dimension.DISTANCE),
69 getPlot().getDataPool().getGranularity(Dimension.DISTANCE), this.spaceGranularityButtons);
70 popupMenu.insert(spaceGranularityMenu, 0);
71 JMenu timeGranularityMenu = buildMenu("Time granularity", "%.0f s", 60.0, "%.0f min", "setTimeGranularity",
72 getPlot().getDataPool().getGranularities(Dimension.TIME),
73 getPlot().getDataPool().getGranularity(Dimension.TIME), 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().getDataPool().setSmooth(((JCheckBoxMenuItem) e.getSource()).isSelected());
80 getPlot().notifyPlotChange();
81 SwingContourPlot.this.ignoreEvent = false;
82 });
83 popupMenu.insert(this.smoothCheckBox, 2);
84 this.interpolateCheckBox = new JCheckBoxMenuItem("Bilinear interpolation", true);
85 this.interpolateCheckBox.addActionListener((e) ->
86 {
87 SwingContourPlot.this.ignoreEvent = true;
88 boolean interpolate = ((JCheckBoxMenuItem) e.getSource()).isSelected();
89 getPlot().getBlockRenderer().setInterpolate(interpolate);
90 getPlot().getDataPool().setInterpolate(interpolate);
91 getPlot().notifyPlotChange();
92 SwingContourPlot.this.ignoreEvent = false;
93 });
94 popupMenu.insert(this.interpolateCheckBox, 3);
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108
109 private JMenu buildMenu(final String menuName, final String format1, final double formatValue, final String format2,
110 final String command, final double[] values, final double initialValue,
111 final Map<JRadioButtonMenuItem, Double> granularityButtons)
112 {
113 JMenu result = new JMenu(menuName);
114 ButtonGroup group = new ButtonGroup();
115 for (double value : values)
116 {
117 JRadioButtonMenuItem item = new JRadioButtonMenuItem(
118 String.format(value < formatValue ? format1 : format2, value < formatValue ? value : value / formatValue));
119 granularityButtons.put(item, value);
120 item.setSelected(value == initialValue);
121 item.setActionCommand(command);
122 item.addActionListener((actionEvent) ->
123 {
124 SwingContourPlot.this.ignoreEvent = true;
125 if (command.equalsIgnoreCase("setSpaceGranularity"))
126 {
127 double granularity = SwingContourPlot.this.spaceGranularityButtons.get(actionEvent.getSource());
128
129 getPlot().getDataPool().offerGranularity(Dimension.DISTANCE, granularity);
130 }
131 else if (command.equalsIgnoreCase("setTimeGranularity"))
132 {
133 double granularity = SwingContourPlot.this.timeGranularityButtons.get(actionEvent.getSource());
134
135 getPlot().getDataPool().offerGranularity(Dimension.TIME, granularity);
136 }
137 else
138 {
139 throw new OtsRuntimeException("Unknown ActionEvent");
140 }
141 SwingContourPlot.this.ignoreEvent = false;
142 });
143 result.add(item);
144 group.add(item);
145 }
146 return result;
147 }
148
149 @Override
150 public AbstractContourPlot<?> getPlot()
151 {
152 return (AbstractContourPlot<?>) super.getPlot();
153 }
154
155 @Override
156 public void notify(final Event event)
157 {
158 if (this.ignoreEvent)
159 {
160 return;
161 }
162 if (event.getType().equals(ContourDataSource.GRANULARITY))
163 {
164 Object[] payload = (Object[]) event.getContent();
165 Dimension dimension = (Dimension) payload[0];
166 double granularity = (double) payload[1];
167 Map<JRadioButtonMenuItem, Double> buttonMap =
168 Dimension.DISTANCE.equals(dimension) ? this.spaceGranularityButtons : this.timeGranularityButtons;
169 for (JRadioButtonMenuItem button : buttonMap.keySet())
170 {
171 button.setSelected(Math.abs(buttonMap.get(button) - granularity) < 0.001);
172 }
173 }
174 else if (event.getType().equals(ContourDataSource.INTERPOLATE))
175 {
176 this.interpolateCheckBox.setSelected((boolean) event.getContent());
177 }
178 else if (event.getType().equals(ContourDataSource.SMOOTH))
179 {
180 this.smoothCheckBox.setSelected((boolean) event.getContent());
181 }
182 }
183
184 }