View Javadoc
1   package org.opentrafficsim.swing.graphs;
2   
3   import java.awt.event.ActionEvent;
4   import java.awt.event.ActionListener;
5   import java.util.LinkedHashMap;
6   import java.util.Map;
7   
8   import javax.swing.ButtonGroup;
9   import javax.swing.JCheckBoxMenuItem;
10  import javax.swing.JMenu;
11  import javax.swing.JPopupMenu;
12  import javax.swing.JRadioButtonMenuItem;
13  
14  import org.opentrafficsim.draw.graphs.AbstractContourPlot;
15  import org.opentrafficsim.draw.graphs.ContourDataSource.Dimension;
16  
17  /**
18   * Embed a ContourPlot in a Swing JPanel.
19   * <p>
20   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
21   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
22   * </p>
23   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
24   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
25   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
26   */
27  public class SwingContourPlot extends SwingSpaceTimePlot
28  {
29      /** */
30      private static final long serialVersionUID = 20190823L;
31  
32      /** Map to set time granularity. */
33      private Map<JRadioButtonMenuItem, Double> timeGranularityButtons;
34  
35      /** Map to set space granularity. */
36      private Map<JRadioButtonMenuItem, Double> spaceGranularityButtons;
37  
38      /** Check box for smoothing. */
39      private JCheckBoxMenuItem smoothCheckBox;
40  
41      /** Check box for interpolation. */
42      private JCheckBoxMenuItem interpolateCheckBox;
43  
44      /**
45       * Create a new SwingContourPlot with embedded plot.
46       * @param plot the plot to embed
47       */
48      public SwingContourPlot(final AbstractContourPlot<?> plot)
49      {
50          super(plot);
51      }
52  
53      @Override
54      protected void addPopUpMenuItems(final JPopupMenu popupMenu)
55      {
56          this.timeGranularityButtons = new LinkedHashMap<>();
57          this.spaceGranularityButtons = new LinkedHashMap<>();
58          super.addPopUpMenuItems(popupMenu);
59          JMenu spaceGranularityMenu = buildMenu("Distance granularity", "%.0f m", 1000, "%.0f km", "setSpaceGranularity",
60                  getPlot().getDataPool().getGranularities(Dimension.DISTANCE),
61                  getPlot().getDataPool().getGranularity(Dimension.DISTANCE), this.spaceGranularityButtons);
62          popupMenu.insert(spaceGranularityMenu, 0);
63          JMenu timeGranularityMenu = buildMenu("Time granularity", "%.0f s", 60.0, "%.0f min", "setTimeGranularity",
64                  getPlot().getDataPool().getGranularities(Dimension.TIME),
65                  getPlot().getDataPool().getGranularity(Dimension.TIME), this.timeGranularityButtons);
66          popupMenu.insert(timeGranularityMenu, 1);
67          this.smoothCheckBox = new JCheckBoxMenuItem("Adaptive smoothing method", false);
68          this.smoothCheckBox.addActionListener(new ActionListener()
69          {
70              @Override
71              public void actionPerformed(final ActionEvent e)
72              {
73                  getPlot().getDataPool().setSmooth(((JCheckBoxMenuItem) e.getSource()).isSelected());
74                  getPlot().notifyPlotChange();
75              }
76          });
77          popupMenu.insert(this.smoothCheckBox, 2);
78          this.interpolateCheckBox = new JCheckBoxMenuItem("Bilinear interpolation", true);
79          this.interpolateCheckBox.addActionListener(new ActionListener()
80          {
81              @Override
82              public void actionPerformed(final ActionEvent e)
83              {
84                  boolean interpolate = ((JCheckBoxMenuItem) e.getSource()).isSelected();
85                  getPlot().getBlockRenderer().setInterpolate(interpolate);
86                  getPlot().getDataPool().setInterpolate(interpolate);
87                  getPlot().notifyPlotChange();
88              }
89          });
90          popupMenu.insert(this.interpolateCheckBox, 3);
91      }
92  
93      /**
94       * Create a JMenu to let the user set the granularity.
95       * @param menuName caption for the new JMenu
96       * @param format1 format string for the values in the items under the new JMenu, below formatValue
97       * @param formatValue format value
98       * @param format2 format string for the values in the items under the new JMenu, above and equal to formatValue
99       * @param command prefix for the actionCommand of the items under the new JMenu
100      * @param values array of values to be formatted using the format strings to yield the items under the new JMenu
101      * @param initialValue the currently selected value (used to put the bullet on the correct item)
102      * @param granularityButtons map in to which buttons should be added
103      * @return JMenu with JRadioMenuItems for the values and a bullet on the currentValue item
104      */
105     private JMenu buildMenu(final String menuName, final String format1, final double formatValue, final String format2,
106             final String command, final double[] values, final double initialValue,
107             final Map<JRadioButtonMenuItem, Double> granularityButtons)
108     {
109         JMenu result = new JMenu(menuName);
110         ButtonGroup group = new ButtonGroup();
111         for (double value : values)
112         {
113             JRadioButtonMenuItem item = new JRadioButtonMenuItem(
114                     String.format(value < formatValue ? format1 : format2, value < formatValue ? value : value / formatValue));
115             granularityButtons.put(item, value);
116             item.setSelected(value == initialValue);
117             item.setActionCommand(command);
118             item.addActionListener(new ActionListener()
119             {
120                 @Override
121                 public void actionPerformed(final ActionEvent actionEvent)
122                 {
123                     if (command.equalsIgnoreCase("setSpaceGranularity"))
124                     {
125                         double granularity = SwingContourPlot.this.spaceGranularityButtons.get(actionEvent.getSource());
126                         getPlot().getDataPool().setGranularity(Dimension.DISTANCE, granularity);
127                     }
128                     else if (command.equalsIgnoreCase("setTimeGranularity"))
129                     {
130                         double granularity = SwingContourPlot.this.timeGranularityButtons.get(actionEvent.getSource());
131                         getPlot().getDataPool().setGranularity(Dimension.TIME, granularity);
132                     }
133                     else
134                     {
135                         throw new RuntimeException("Unknown ActionEvent");
136                     }
137                 }
138             });
139             result.add(item);
140             group.add(item);
141         }
142         return result;
143     }
144 
145     @Override
146     public AbstractContourPlot<?> getPlot()
147     {
148         return (AbstractContourPlot<?>) super.getPlot();
149     }
150 
151     /**
152      * Sets the correct space granularity radio button to selected. This is done from a {@code DataPool} to keep multiple plots
153      * consistent.
154      * @param granularity space granularity
155      */
156     protected final void setSpaceGranularityRadioButton(final double granularity)
157     {
158         getPlot().setSpaceGranularity(granularity);
159         for (JRadioButtonMenuItem button : this.spaceGranularityButtons.keySet())
160         {
161             button.setSelected(this.spaceGranularityButtons.get(button) == granularity);
162         }
163     }
164 
165     /**
166      * Sets the correct time granularity radio button to selected. This is done from a {@code DataPool} to keep multiple plots
167      * consistent.
168      * @param granularity time granularity
169      */
170     protected final void setTimeGranularityRadioButton(final double granularity)
171     {
172         getPlot().setTimeGranularity(granularity);
173         for (JRadioButtonMenuItem button : this.timeGranularityButtons.keySet())
174         {
175             button.setSelected(this.timeGranularityButtons.get(button) == granularity);
176         }
177     }
178 
179     /**
180      * Sets the check box for smooth rendering. This is done from a {@code DataPool} to keep multiple plots consistent.
181      * @param smooth selected or not
182      */
183     protected final void setSmoothing(final boolean smooth)
184     {
185         this.smoothCheckBox.setSelected(smooth);
186     }
187 
188     /**
189      * Sets the check box for interpolated rendering and block renderer setting. This is done from a {@code DataPool} to keep
190      * multiple plots consistent.
191      * @param interpolate selected or not
192      */
193     protected final void setInterpolation(final boolean interpolate)
194     {
195         getPlot().setInterpolation(interpolate);
196         this.interpolateCheckBox.setSelected(interpolate);
197     }
198 
199 }