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