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://tudelft.nl/staff/p.knoppers-1">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 AbstractContourPlot&lt;?&gt;; the plot to embed
47       */
48      public SwingContourPlot(final AbstractContourPlot<?> plot)
49      {
50          super(plot);
51      }
52  
53      /** {@inheritDoc} */
54      @Override
55      protected void addPopUpMenuItems(final JPopupMenu popupMenu)
56      {
57          this.timeGranularityButtons = new LinkedHashMap<>();
58          this.spaceGranularityButtons = new LinkedHashMap<>();
59          super.addPopUpMenuItems(popupMenu);
60          JMenu spaceGranularityMenu = buildMenu("Distance granularity", "%.0f m", 1000, "%.0f km", "setSpaceGranularity",
61                  getPlot().getDataPool().getGranularities(Dimension.DISTANCE),
62                  getPlot().getDataPool().getGranularity(Dimension.DISTANCE), this.spaceGranularityButtons);
63          popupMenu.insert(spaceGranularityMenu, 0);
64          JMenu timeGranularityMenu = buildMenu("Time granularity", "%.0f s", 60.0, "%.0f min", "setTimeGranularity",
65                  getPlot().getDataPool().getGranularities(Dimension.TIME),
66                  getPlot().getDataPool().getGranularity(Dimension.TIME), this.timeGranularityButtons);
67          popupMenu.insert(timeGranularityMenu, 1);
68          this.smoothCheckBox = new JCheckBoxMenuItem("Adaptive smoothing method", false);
69          this.smoothCheckBox.addActionListener(new ActionListener()
70          {
71              /** {@inheritDoc} */
72              @Override
73              public void actionPerformed(final ActionEvent e)
74              {
75                  getPlot().getDataPool().setSmooth(((JCheckBoxMenuItem) e.getSource()).isSelected());
76                  getPlot().notifyPlotChange();
77              }
78          });
79          popupMenu.insert(this.smoothCheckBox, 2);
80          this.interpolateCheckBox = new JCheckBoxMenuItem("Bilinear interpolation", true);
81          this.interpolateCheckBox.addActionListener(new ActionListener()
82          {
83              /** {@inheritDoc} */
84              @Override
85              public void actionPerformed(final ActionEvent e)
86              {
87                  boolean interpolate = ((JCheckBoxMenuItem) e.getSource()).isSelected();
88                  getPlot().getBlockRenderer().setInterpolate(interpolate);
89                  getPlot().getDataPool().setInterpolate(interpolate);
90                  getPlot().notifyPlotChange();
91              }
92          });
93          popupMenu.insert(this.interpolateCheckBox, 3);
94      }
95  
96      /**
97       * Create a JMenu to let the user set the granularity.
98       * @param menuName String; caption for the new JMenu
99       * @param format1 String; format string for the values in the items under the new JMenu, below formatValue
100      * @param formatValue double; format value
101      * @param format2 String; format string for the values in the items under the new JMenu, above and equal to formatValue
102      * @param command String; prefix for the actionCommand of the items under the new JMenu
103      * @param values double[]; array of values to be formatted using the format strings to yield the items under the new JMenu
104      * @param initialValue double; the currently selected value (used to put the bullet on the correct item)
105      * @param granularityButtons Map&lt;JRadioButtonMenuItem, Double&gt;; map in to which buttons should be added
106      * @return JMenu with JRadioMenuItems for the values and a bullet on the currentValue item
107      */
108     private JMenu buildMenu(final String menuName, final String format1, final double formatValue, final String format2,
109             final String command, final double[] values, final double initialValue,
110             final Map<JRadioButtonMenuItem, Double> granularityButtons)
111     {
112         JMenu result = new JMenu(menuName);
113         ButtonGroup group = new ButtonGroup();
114         for (double value : values)
115         {
116             JRadioButtonMenuItem item = new JRadioButtonMenuItem(
117                     String.format(value < formatValue ? format1 : format2, value < formatValue ? value : value / formatValue));
118             granularityButtons.put(item, value);
119             item.setSelected(value == initialValue);
120             item.setActionCommand(command);
121             item.addActionListener(new ActionListener()
122             {
123                 /** {@inheritDoc} */
124                 @Override
125                 public void actionPerformed(final ActionEvent actionEvent)
126                 {
127                     if (command.equalsIgnoreCase("setSpaceGranularity"))
128                     {
129                         double granularity = SwingContourPlot.this.spaceGranularityButtons.get(actionEvent.getSource());
130                         getPlot().getDataPool().setGranularity(Dimension.DISTANCE, granularity);
131                     }
132                     else if (command.equalsIgnoreCase("setTimeGranularity"))
133                     {
134                         double granularity = SwingContourPlot.this.timeGranularityButtons.get(actionEvent.getSource());
135                         getPlot().getDataPool().setGranularity(Dimension.TIME, granularity);
136                     }
137                     else
138                     {
139                         throw new RuntimeException("Unknown ActionEvent");
140                     }
141                 }
142             });
143             result.add(item);
144             group.add(item);
145         }
146         return result;
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public AbstractContourPlot<?> getPlot()
152     {
153         return (AbstractContourPlot<?>) super.getPlot();
154     }
155 
156     /**
157      * Sets the correct space granularity radio button to selected. This is done from a {@code DataPool} to keep multiple plots
158      * consistent.
159      * @param granularity double; space granularity
160      */
161     protected final void setSpaceGranularityRadioButton(final double granularity)
162     {
163         getPlot().setSpaceGranularity(granularity);
164         for (JRadioButtonMenuItem button : this.spaceGranularityButtons.keySet())
165         {
166             button.setSelected(this.spaceGranularityButtons.get(button) == granularity);
167         }
168     }
169 
170     /**
171      * Sets the correct time granularity radio button to selected. This is done from a {@code DataPool} to keep multiple plots
172      * consistent.
173      * @param granularity double; time granularity
174      */
175     protected final void setTimeGranularityRadioButton(final double granularity)
176     {
177         getPlot().setTimeGranularity(granularity);
178         for (JRadioButtonMenuItem button : this.timeGranularityButtons.keySet())
179         {
180             button.setSelected(this.timeGranularityButtons.get(button) == granularity);
181         }
182     }
183 
184     /**
185      * Sets the check box for smooth rendering. This is done from a {@code DataPool} to keep multiple plots consistent.
186      * @param smooth boolean; selected or not
187      */
188     protected final void setSmoothing(final boolean smooth)
189     {
190         this.smoothCheckBox.setSelected(smooth);
191     }
192 
193     /**
194      * Sets the check box for interpolated rendering and block renderer setting. This is done from a {@code DataPool} to keep
195      * multiple plots consistent.
196      * @param interpolate boolean; selected or not
197      */
198     protected final void setInterpolation(final boolean interpolate)
199     {
200         getPlot().setInterpolation(interpolate);
201         this.interpolateCheckBox.setSelected(interpolate);
202     }
203 
204 }